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 void (*remove_bi
)(void *ctx
, struct dpp_bootstrap_info
*bi
);
135 #endif /* CONFIG_DPP2 */
138 static const struct dpp_curve_params dpp_curves
[] = {
139 /* The mandatory to support and the default NIST P-256 curve needs to
140 * be the first entry on this list. */
141 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
142 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
143 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
144 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
145 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
146 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
147 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
151 /* Role-specific elements for PKEX */
154 static const u8 pkex_init_x_p256
[32] = {
155 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
156 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
157 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
158 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
160 static const u8 pkex_init_y_p256
[32] = {
161 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
162 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
163 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
164 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
166 static const u8 pkex_resp_x_p256
[32] = {
167 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
168 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
169 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
170 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
172 static const u8 pkex_resp_y_p256
[32] = {
173 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
174 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
175 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
176 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
180 static const u8 pkex_init_x_p384
[48] = {
181 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
182 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
183 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
184 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
185 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
186 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
188 static const u8 pkex_init_y_p384
[48] = {
189 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
190 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
191 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
192 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
193 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
194 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
196 static const u8 pkex_resp_x_p384
[48] = {
197 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
198 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
199 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
200 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
201 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
202 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
204 static const u8 pkex_resp_y_p384
[48] = {
205 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
206 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
207 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
208 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
209 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
210 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
214 static const u8 pkex_init_x_p521
[66] = {
215 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
216 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
217 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
218 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
219 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
220 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
221 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
222 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
225 static const u8 pkex_init_y_p521
[66] = {
226 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
227 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
228 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
229 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
230 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
231 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
232 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
233 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
236 static const u8 pkex_resp_x_p521
[66] = {
237 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
238 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
239 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
240 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
241 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
242 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
243 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
244 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
247 static const u8 pkex_resp_y_p521
[66] = {
248 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
249 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
250 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
251 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
252 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
253 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
254 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
255 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
259 /* Brainpool P-256r1 */
260 static const u8 pkex_init_x_bp_p256r1
[32] = {
261 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
262 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
263 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
264 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
266 static const u8 pkex_init_y_bp_p256r1
[32] = {
267 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
268 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
269 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
270 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
272 static const u8 pkex_resp_x_bp_p256r1
[32] = {
273 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
274 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
275 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
276 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
278 static const u8 pkex_resp_y_bp_p256r1
[32] = {
279 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
280 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
281 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
282 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
285 /* Brainpool P-384r1 */
286 static const u8 pkex_init_x_bp_p384r1
[48] = {
287 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
288 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
289 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
290 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
291 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
292 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
294 static const u8 pkex_init_y_bp_p384r1
[48] = {
295 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
296 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
297 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
298 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
299 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
300 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
302 static const u8 pkex_resp_x_bp_p384r1
[48] = {
303 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
304 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
305 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
306 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
307 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
308 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
310 static const u8 pkex_resp_y_bp_p384r1
[48] = {
311 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
312 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
313 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
314 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
315 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
316 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
319 /* Brainpool P-512r1 */
320 static const u8 pkex_init_x_bp_p512r1
[64] = {
321 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
322 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
323 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
324 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
325 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
326 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
327 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
328 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
330 static const u8 pkex_init_y_bp_p512r1
[64] = {
331 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
332 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
333 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
334 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
335 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
336 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
337 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
338 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
340 static const u8 pkex_resp_x_bp_p512r1
[64] = {
341 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
342 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
343 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
344 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
345 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
346 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
347 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
348 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
350 static const u8 pkex_resp_y_bp_p512r1
[64] = {
351 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
352 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
353 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
354 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
355 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
356 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
357 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
358 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
362 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
363 const EC_POINT
*point
)
367 char *x_str
= NULL
, *y_str
= NULL
;
369 if (!wpa_debug_show_keys
)
375 if (!ctx
|| !x
|| !y
||
376 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
379 x_str
= BN_bn2hex(x
);
380 y_str
= BN_bn2hex(y
);
381 if (!x_str
|| !y_str
)
384 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
395 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
396 size_t num_elem
, const u8
*addr
[], const size_t *len
,
399 if (curve
->hash_len
== 32)
400 return sha256_vector(num_elem
, addr
, len
, mac
);
401 if (curve
->hash_len
== 48)
402 return sha384_vector(num_elem
, addr
, len
, mac
);
403 if (curve
->hash_len
== 64)
404 return sha512_vector(num_elem
, addr
, len
, mac
);
409 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
410 const char *label
, u8
*out
, size_t outlen
)
413 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
414 (const u8
*) label
, os_strlen(label
),
417 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
418 (const u8
*) label
, os_strlen(label
),
421 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
422 (const u8
*) label
, os_strlen(label
),
428 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
429 size_t num_elem
, const u8
*addr
[],
430 const size_t *len
, u8
*mac
)
433 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
436 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
439 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
445 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
446 const u8
*data
, size_t data_len
, u8
*mac
)
449 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
451 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
453 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
460 static int dpp_pbkdf2_f(size_t hash_len
,
461 const u8
*password
, size_t password_len
,
462 const u8
*salt
, size_t salt_len
,
463 unsigned int iterations
, unsigned int count
, u8
*digest
)
465 unsigned char tmp
[DPP_MAX_HASH_LEN
], tmp2
[DPP_MAX_HASH_LEN
];
477 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
478 * U1 = PRF(P, S || i)
483 WPA_PUT_BE32(count_buf
, count
);
484 if (dpp_hmac_vector(hash_len
, password
, password_len
, 2, addr
, len
,
487 os_memcpy(digest
, tmp
, hash_len
);
489 for (i
= 1; i
< iterations
; i
++) {
490 if (dpp_hmac(hash_len
, password
, password_len
, tmp
, hash_len
,
493 os_memcpy(tmp
, tmp2
, hash_len
);
494 for (j
= 0; j
< hash_len
; j
++)
495 digest
[j
] ^= tmp2
[j
];
502 static int dpp_pbkdf2(size_t hash_len
, const u8
*password
, size_t password_len
,
503 const u8
*salt
, size_t salt_len
, unsigned int iterations
,
504 u8
*buf
, size_t buflen
)
506 unsigned int count
= 0;
507 unsigned char *pos
= buf
;
508 size_t left
= buflen
, plen
;
509 unsigned char digest
[DPP_MAX_HASH_LEN
];
513 if (dpp_pbkdf2_f(hash_len
, password
, password_len
,
514 salt
, salt_len
, iterations
, count
, digest
))
516 plen
= left
> hash_len
? hash_len
: left
;
517 os_memcpy(pos
, digest
, plen
);
525 #endif /* CONFIG_DPP2 */
528 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
530 int num_bytes
, offset
;
532 num_bytes
= BN_num_bytes(bn
);
533 if ((size_t) num_bytes
> len
)
535 offset
= len
- num_bytes
;
536 os_memset(pos
, 0, offset
);
537 BN_bn2bin(bn
, pos
+ offset
);
542 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
549 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
552 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
553 len
= i2o_ECPublicKey(eckey
, NULL
);
555 wpa_printf(MSG_ERROR
,
556 "DDP: Failed to determine public key encoding length");
561 buf
= wpabuf_alloc(len
);
567 pos
= wpabuf_put(buf
, len
);
568 res
= i2o_ECPublicKey(eckey
, &pos
);
571 wpa_printf(MSG_ERROR
,
572 "DDP: Failed to encode public key (res=%d/%d)",
579 /* Remove 0x04 prefix to match DPP definition */
580 pos
= wpabuf_mhead(buf
);
581 os_memmove(pos
, pos
+ 1, len
- 1);
589 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
590 const u8
*buf_x
, const u8
*buf_y
,
593 EC_KEY
*eckey
= NULL
;
595 EC_POINT
*point
= NULL
;
596 BIGNUM
*x
= NULL
, *y
= NULL
;
597 EVP_PKEY
*pkey
= NULL
;
601 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
605 point
= EC_POINT_new(group
);
606 x
= BN_bin2bn(buf_x
, len
, NULL
);
607 y
= BN_bin2bn(buf_y
, len
, NULL
);
608 if (!point
|| !x
|| !y
) {
609 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
613 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
614 wpa_printf(MSG_ERROR
,
615 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
616 ERR_error_string(ERR_get_error(), NULL
));
620 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
621 EC_POINT_is_at_infinity(group
, point
)) {
622 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
625 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
627 eckey
= EC_KEY_new();
629 EC_KEY_set_group(eckey
, group
) != 1 ||
630 EC_KEY_set_public_key(eckey
, point
) != 1) {
631 wpa_printf(MSG_ERROR
,
632 "DPP: Failed to set EC_KEY: %s",
633 ERR_error_string(ERR_get_error(), NULL
));
636 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
638 pkey
= EVP_PKEY_new();
639 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
640 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
648 EC_POINT_free(point
);
658 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
659 const u8
*buf
, size_t len
)
662 const EC_GROUP
*group
;
663 EVP_PKEY
*pkey
= NULL
;
668 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
670 wpa_printf(MSG_ERROR
,
671 "DPP: Could not get EC_KEY from group_key");
675 group
= EC_KEY_get0_group(eckey
);
677 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
680 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
687 static int dpp_ecdh(EVP_PKEY
*own
, EVP_PKEY
*peer
,
688 u8
*secret
, size_t *secret_len
)
696 ctx
= EVP_PKEY_CTX_new(own
, NULL
);
698 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_CTX_new failed: %s",
699 ERR_error_string(ERR_get_error(), NULL
));
703 if (EVP_PKEY_derive_init(ctx
) != 1) {
704 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive_init failed: %s",
705 ERR_error_string(ERR_get_error(), NULL
));
709 if (EVP_PKEY_derive_set_peer(ctx
, peer
) != 1) {
710 wpa_printf(MSG_ERROR
,
711 "DPP: EVP_PKEY_derive_set_peet failed: %s",
712 ERR_error_string(ERR_get_error(), NULL
));
716 if (EVP_PKEY_derive(ctx
, NULL
, secret_len
) != 1) {
717 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive(NULL) failed: %s",
718 ERR_error_string(ERR_get_error(), NULL
));
722 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
724 int level
= *secret_len
> 200 ? MSG_ERROR
: MSG_DEBUG
;
726 /* It looks like OpenSSL can return unexpectedly large buffer
727 * need for shared secret from EVP_PKEY_derive(NULL) in some
728 * cases. For example, group 19 has shown cases where secret_len
729 * is set to 72 even though the actual length ends up being
730 * updated to 32 when EVP_PKEY_derive() is called with a buffer
731 * for the value. Work around this by trying to fetch the value
732 * and continue if it is within supported range even when the
733 * initial buffer need is claimed to be larger. */
735 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
737 if (*secret_len
> 200)
739 if (EVP_PKEY_derive(ctx
, buf
, secret_len
) != 1) {
740 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
741 ERR_error_string(ERR_get_error(), NULL
));
744 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
745 wpa_printf(MSG_ERROR
,
746 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
750 wpa_hexdump_key(MSG_DEBUG
, "DPP: Unexpected secret_len change",
752 os_memcpy(secret
, buf
, *secret_len
);
753 forced_memzero(buf
, sizeof(buf
));
757 if (EVP_PKEY_derive(ctx
, secret
, secret_len
) != 1) {
758 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
759 ERR_error_string(ERR_get_error(), NULL
));
767 EVP_PKEY_CTX_free(ctx
);
772 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
774 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
778 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
783 msg
= wpabuf_alloc(8 + len
);
786 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
787 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
788 wpabuf_put_be24(msg
, OUI_WFA
);
789 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
790 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
791 wpabuf_put_u8(msg
, type
);
796 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
799 const u8
*pos
= buf
, *end
= buf
+ len
;
801 while (end
- pos
>= 4) {
802 id
= WPA_GET_LE16(pos
);
804 alen
= WPA_GET_LE16(pos
);
806 if (alen
> end
- pos
)
819 static const u8
* dpp_get_attr_next(const u8
*prev
, const u8
*buf
, size_t len
,
820 u16 req_id
, u16
*ret_len
)
823 const u8
*pos
, *end
= buf
+ len
;
828 pos
= prev
+ WPA_GET_LE16(prev
- 2);
829 while (end
- pos
>= 4) {
830 id
= WPA_GET_LE16(pos
);
832 alen
= WPA_GET_LE16(pos
);
834 if (alen
> end
- pos
)
847 int dpp_check_attrs(const u8
*buf
, size_t len
)
850 int wrapped_data
= 0;
854 while (end
- pos
>= 4) {
857 id
= WPA_GET_LE16(pos
);
859 alen
= WPA_GET_LE16(pos
);
861 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
863 if (alen
> end
- pos
) {
864 wpa_printf(MSG_DEBUG
,
865 "DPP: Truncated message - not enough room for the attribute - dropped");
869 wpa_printf(MSG_DEBUG
,
870 "DPP: An unexpected attribute included after the Wrapped Data attribute");
873 if (id
== DPP_ATTR_WRAPPED_DATA
)
879 wpa_printf(MSG_DEBUG
,
880 "DPP: Unexpected octets (%d) after the last attribute",
889 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
897 EVP_PKEY_free(info
->pubkey
);
898 str_clear_free(info
->configurator_params
);
903 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
906 case DPP_BOOTSTRAP_QR_CODE
:
908 case DPP_BOOTSTRAP_PKEX
:
910 case DPP_BOOTSTRAP_NFC_URI
:
917 static int dpp_uri_valid_info(const char *info
)
920 unsigned char val
= *info
++;
922 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
930 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
932 bi
->uri
= os_strdup(uri
);
933 return bi
->uri
? 0 : -1;
937 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
938 const char *chan_list
)
940 const char *pos
= chan_list
, *pos2
;
941 int opclass
= -1, channel
, freq
;
943 while (pos
&& *pos
&& *pos
!= ';') {
945 while (*pos2
>= '0' && *pos2
<= '9')
956 while (*pos
>= '0' && *pos
<= '9')
958 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
959 wpa_printf(MSG_DEBUG
,
960 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
961 opclass
, channel
, freq
);
963 wpa_printf(MSG_DEBUG
,
964 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
966 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
967 wpa_printf(MSG_DEBUG
,
968 "DPP: Too many channels in URI channel-list - ignore list");
972 bi
->freq
[bi
->num_freq
++] = freq
;
975 if (*pos
== ';' || *pos
== '\0')
984 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
989 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
994 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
995 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
999 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
1005 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
1012 end
= os_strchr(info
, ';');
1014 end
= info
+ os_strlen(info
);
1015 bi
->info
= os_malloc(end
- info
+ 1);
1018 os_memcpy(bi
->info
, info
, end
- info
);
1019 bi
->info
[end
- info
] = '\0';
1020 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
1021 if (!dpp_uri_valid_info(bi
->info
)) {
1022 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
1030 static const struct dpp_curve_params
*
1031 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
1036 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1037 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
1038 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
1039 return &dpp_curves
[i
];
1045 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
1051 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1052 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
1054 return &dpp_curves
[i
];
1060 static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info
*bi
,
1061 const u8
*data
, size_t data_len
)
1068 if (sha256_vector(1, addr
, len
, bi
->pubkey_hash
) < 0)
1070 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
1071 bi
->pubkey_hash
, SHA256_MAC_LEN
);
1073 addr
[0] = (const u8
*) "chirp";
1077 if (sha256_vector(2, addr
, len
, bi
->pubkey_hash_chirp
) < 0)
1079 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash (chirp)",
1080 bi
->pubkey_hash_chirp
, SHA256_MAC_LEN
);
1086 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
1092 const unsigned char *p
;
1094 X509_PUBKEY
*pub
= NULL
;
1095 ASN1_OBJECT
*ppkalg
;
1096 const unsigned char *pk
;
1099 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1100 (defined(LIBRESSL_VERSION_NUMBER) && \
1101 LIBRESSL_VERSION_NUMBER < 0x20800000L)
1102 ASN1_OBJECT
*pa_oid
;
1104 const ASN1_OBJECT
*pa_oid
;
1108 const ASN1_OBJECT
*poid
;
1111 end
= os_strchr(info
, ';');
1115 data
= base64_decode(info
, end
- info
, &data_len
);
1117 wpa_printf(MSG_DEBUG
,
1118 "DPP: Invalid base64 encoding on URI public-key");
1121 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
1124 if (dpp_bi_pubkey_hash(bi
, data
, data_len
) < 0) {
1125 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1130 /* DER encoded ASN.1 SubjectPublicKeyInfo
1132 * SubjectPublicKeyInfo ::= SEQUENCE {
1133 * algorithm AlgorithmIdentifier,
1134 * subjectPublicKey BIT STRING }
1136 * AlgorithmIdentifier ::= SEQUENCE {
1137 * algorithm OBJECT IDENTIFIER,
1138 * parameters ANY DEFINED BY algorithm OPTIONAL }
1140 * subjectPublicKey = compressed format public key per ANSI X9.63
1141 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1142 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1143 * prime256v1 (1.2.840.10045.3.1.7)
1147 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
1151 wpa_printf(MSG_DEBUG
,
1152 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1156 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
1157 wpa_printf(MSG_DEBUG
,
1158 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1159 EVP_PKEY_free(pkey
);
1163 res
= X509_PUBKEY_set(&pub
, pkey
);
1165 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
1169 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
1171 wpa_printf(MSG_DEBUG
,
1172 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1175 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
1176 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1177 wpa_printf(MSG_DEBUG
,
1178 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1181 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
1182 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
1183 wpa_printf(MSG_DEBUG
,
1184 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1188 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
1189 if (ptype
!= V_ASN1_OBJECT
) {
1190 wpa_printf(MSG_DEBUG
,
1191 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1195 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
1196 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1197 wpa_printf(MSG_DEBUG
,
1198 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1201 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
1202 bi
->curve
= dpp_get_curve_oid(poid
);
1204 wpa_printf(MSG_DEBUG
,
1205 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1210 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
1212 X509_PUBKEY_free(pub
);
1216 X509_PUBKEY_free(pub
);
1217 EVP_PKEY_free(pkey
);
1222 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
1224 const char *pos
= uri
;
1226 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
1227 struct dpp_bootstrap_info
*bi
;
1229 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
1231 if (os_strncmp(pos
, "DPP:", 4) != 0) {
1232 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
1238 end
= os_strchr(pos
, ';');
1243 /* Handle terminating ";;" and ignore unexpected ";"
1244 * for parsing robustness. */
1249 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
1250 chan_list
= pos
+ 2;
1251 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
1253 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
1255 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
1258 wpa_hexdump_ascii(MSG_DEBUG
,
1259 "DPP: Ignore unrecognized URI parameter",
1265 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
1269 bi
= os_zalloc(sizeof(*bi
));
1273 if (dpp_clone_uri(bi
, uri
) < 0 ||
1274 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1275 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1276 dpp_parse_uri_info(bi
, info
) < 0 ||
1277 dpp_parse_uri_pk(bi
, pk
) < 0) {
1278 dpp_bootstrap_info_free(bi
);
1286 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1293 unsigned char *der
= NULL
;
1295 const EC_GROUP
*group
;
1296 const EC_POINT
*point
;
1298 out
= BIO_new(BIO_s_mem());
1302 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1303 rlen
= BIO_ctrl_pending(out
);
1304 txt
= os_malloc(rlen
+ 1);
1306 res
= BIO_read(out
, txt
, rlen
);
1309 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1315 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1319 group
= EC_KEY_get0_group(eckey
);
1320 point
= EC_KEY_get0_public_key(eckey
);
1322 dpp_debug_print_point(title
, group
, point
);
1324 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1326 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1330 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1332 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1340 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1342 EVP_PKEY_CTX
*kctx
= NULL
;
1343 EC_KEY
*ec_params
= NULL
;
1344 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1347 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1349 nid
= OBJ_txt2nid(curve
->name
);
1350 if (nid
== NID_undef
) {
1351 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1355 ec_params
= EC_KEY_new_by_curve_name(nid
);
1357 wpa_printf(MSG_ERROR
,
1358 "DPP: Failed to generate EC_KEY parameters");
1361 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1362 params
= EVP_PKEY_new();
1363 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1364 wpa_printf(MSG_ERROR
,
1365 "DPP: Failed to generate EVP_PKEY parameters");
1369 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1371 EVP_PKEY_keygen_init(kctx
) != 1 ||
1372 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1373 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1378 if (wpa_debug_show_keys
)
1379 dpp_debug_print_key("Own generated key", key
);
1382 EC_KEY_free(ec_params
);
1383 EVP_PKEY_free(params
);
1384 EVP_PKEY_CTX_free(kctx
);
1389 static const struct dpp_curve_params
*
1390 dpp_get_curve_name(const char *name
)
1394 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1395 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1396 (dpp_curves
[i
].jwk_crv
&&
1397 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1398 return &dpp_curves
[i
];
1404 static const struct dpp_curve_params
*
1405 dpp_get_curve_jwk_crv(const char *name
)
1409 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1410 if (dpp_curves
[i
].jwk_crv
&&
1411 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1412 return &dpp_curves
[i
];
1418 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1419 const u8
*privkey
, size_t privkey_len
)
1423 const EC_GROUP
*group
;
1426 pkey
= EVP_PKEY_new();
1429 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1431 wpa_printf(MSG_INFO
,
1432 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1433 ERR_error_string(ERR_get_error(), NULL
));
1434 EVP_PKEY_free(pkey
);
1437 group
= EC_KEY_get0_group(eckey
);
1440 EVP_PKEY_free(pkey
);
1443 nid
= EC_GROUP_get_curve_name(group
);
1444 *curve
= dpp_get_curve_nid(nid
);
1446 wpa_printf(MSG_INFO
,
1447 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1450 EVP_PKEY_free(pkey
);
1454 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1456 EVP_PKEY_free(pkey
);
1464 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1465 * as an OID identifying the curve */
1467 /* Compressed format public key per ANSI X9.63 */
1468 ASN1_BIT_STRING
*pub_key
;
1469 } DPP_BOOTSTRAPPING_KEY
;
1471 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1472 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1473 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1474 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1476 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1479 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1481 unsigned char *der
= NULL
;
1484 struct wpabuf
*ret
= NULL
;
1486 const EC_GROUP
*group
;
1487 const EC_POINT
*point
;
1489 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1493 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1497 group
= EC_KEY_get0_group(eckey
);
1498 point
= EC_KEY_get0_public_key(eckey
);
1499 if (!group
|| !point
)
1501 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1502 nid
= EC_GROUP_get_curve_name(group
);
1504 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1506 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1507 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1510 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1515 der
= OPENSSL_malloc(len
);
1518 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1521 OPENSSL_free(bootstrap
->pub_key
->data
);
1522 bootstrap
->pub_key
->data
= der
;
1524 bootstrap
->pub_key
->length
= len
;
1525 /* No unused bits */
1526 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1527 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1529 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1531 wpa_printf(MSG_ERROR
,
1532 "DDP: Failed to build DER encoded public key");
1536 ret
= wpabuf_alloc_copy(der
, der_len
);
1538 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1546 static int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1551 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1554 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1556 res
= dpp_bi_pubkey_hash(bi
, wpabuf_head(der
), wpabuf_len(der
));
1558 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1564 static int dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1565 const u8
*privkey
, size_t privkey_len
)
1567 char *base64
= NULL
;
1570 struct wpabuf
*der
= NULL
;
1573 bi
->curve
= &dpp_curves
[0];
1575 bi
->curve
= dpp_get_curve_name(curve
);
1577 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1583 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1585 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1590 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1593 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1596 if (dpp_bi_pubkey_hash(bi
, wpabuf_head(der
), wpabuf_len(der
)) < 0) {
1597 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1601 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1609 pos
= os_strchr(pos
, '\n');
1612 os_memmove(pos
, pos
+ 1, end
- pos
);
1624 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1625 unsigned int hash_len
)
1627 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1628 const char *info
= "first intermediate key";
1631 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1633 /* HKDF-Extract(<>, M.x) */
1634 os_memset(salt
, 0, hash_len
);
1635 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1637 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1640 /* HKDF-Expand(PRK, info, L) */
1641 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1642 os_memset(prk
, 0, hash_len
);
1646 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1652 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1653 unsigned int hash_len
)
1655 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1656 const char *info
= "second intermediate key";
1659 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1661 /* HKDF-Extract(<>, N.x) */
1662 os_memset(salt
, 0, hash_len
);
1663 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1666 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1669 /* HKDF-Expand(PRK, info, L) */
1670 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1671 os_memset(prk
, 0, hash_len
);
1675 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1681 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1682 unsigned int hash_len
)
1685 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1686 const char *info_ke
= "DPP Key";
1687 u8 prk
[DPP_MAX_HASH_LEN
];
1691 size_t num_elem
= 0;
1693 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1694 wpa_printf(MSG_DEBUG
,
1695 "DPP: Mx/Nx not available - cannot derive ke");
1699 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1701 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1702 nonce_len
= auth
->curve
->nonce_len
;
1703 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1704 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1705 addr
[num_elem
] = auth
->Mx
;
1706 len
[num_elem
] = auth
->Mx_len
;
1708 addr
[num_elem
] = auth
->Nx
;
1709 len
[num_elem
] = auth
->Nx_len
;
1711 if (auth
->peer_bi
&& auth
->own_bi
) {
1712 if (!auth
->Lx_len
) {
1713 wpa_printf(MSG_DEBUG
,
1714 "DPP: Lx not available - cannot derive ke");
1717 addr
[num_elem
] = auth
->Lx
;
1718 len
[num_elem
] = auth
->secret_len
;
1721 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1722 num_elem
, addr
, len
, prk
);
1725 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1728 /* HKDF-Expand(PRK, info, L) */
1729 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1730 os_memset(prk
, 0, hash_len
);
1734 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1740 static void dpp_build_attr_status(struct wpabuf
*msg
,
1741 enum dpp_status_error status
)
1743 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1744 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1745 wpabuf_put_le16(msg
, 1);
1746 wpabuf_put_u8(msg
, status
);
1750 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1754 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1755 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1756 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1757 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1762 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1766 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1767 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1768 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1769 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1774 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1775 const struct wpabuf
*pi
,
1777 const u8
*r_pubkey_hash
,
1778 const u8
*i_pubkey_hash
,
1779 unsigned int neg_freq
)
1782 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1783 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1786 size_t len
[2], siv_len
, attr_len
;
1787 u8
*attr_start
, *attr_end
;
1789 /* Build DPP Authentication Request frame attributes */
1790 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1791 4 + sizeof(wrapped_data
);
1796 #endif /* CONFIG_DPP2 */
1797 #ifdef CONFIG_TESTING_OPTIONS
1798 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1800 #endif /* CONFIG_TESTING_OPTIONS */
1801 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1805 attr_start
= wpabuf_put(msg
, 0);
1807 /* Responder Bootstrapping Key Hash */
1808 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1810 /* Initiator Bootstrapping Key Hash */
1811 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1813 /* Initiator Protocol Key */
1815 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1816 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1817 wpabuf_put_buf(msg
, pi
);
1822 u8 op_class
, channel
;
1824 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1826 NUM_HOSTAPD_MODES
) {
1827 wpa_printf(MSG_INFO
,
1828 "DPP: Unsupported negotiation frequency request: %d",
1833 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1834 wpabuf_put_le16(msg
, 2);
1835 wpabuf_put_u8(msg
, op_class
);
1836 wpabuf_put_u8(msg
, channel
);
1840 /* Protocol Version */
1841 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1842 wpabuf_put_le16(msg
, 1);
1843 wpabuf_put_u8(msg
, 2);
1844 #endif /* CONFIG_DPP2 */
1846 #ifdef CONFIG_TESTING_OPTIONS
1847 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1848 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1849 goto skip_wrapped_data
;
1851 #endif /* CONFIG_TESTING_OPTIONS */
1853 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1856 #ifdef CONFIG_TESTING_OPTIONS
1857 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1858 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1861 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1862 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1863 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1865 WPA_PUT_LE16(pos
, nonce_len
- 1);
1867 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1868 pos
+= nonce_len
- 1;
1871 #endif /* CONFIG_TESTING_OPTIONS */
1874 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1876 WPA_PUT_LE16(pos
, nonce_len
);
1878 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1881 #ifdef CONFIG_TESTING_OPTIONS
1883 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1884 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1887 #endif /* CONFIG_TESTING_OPTIONS */
1889 /* I-capabilities */
1890 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1892 WPA_PUT_LE16(pos
, 1);
1894 auth
->i_capab
= auth
->allowed_roles
;
1895 *pos
++ = auth
->i_capab
;
1896 #ifdef CONFIG_TESTING_OPTIONS
1897 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1898 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1902 #endif /* CONFIG_TESTING_OPTIONS */
1904 attr_end
= wpabuf_put(msg
, 0);
1906 /* OUI, OUI type, Crypto Suite, DPP frame type */
1907 addr
[0] = wpabuf_head_u8(msg
) + 2;
1908 len
[0] = 3 + 1 + 1 + 1;
1909 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1911 /* Attributes before Wrapped Data */
1912 addr
[1] = attr_start
;
1913 len
[1] = attr_end
- attr_start
;
1914 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1916 siv_len
= pos
- clear
;
1917 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1918 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1919 2, addr
, len
, wrapped_data
) < 0) {
1923 siv_len
+= AES_BLOCK_SIZE
;
1924 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1925 wrapped_data
, siv_len
);
1927 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1928 wpabuf_put_le16(msg
, siv_len
);
1929 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1931 #ifdef CONFIG_TESTING_OPTIONS
1932 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1933 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1934 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1937 #endif /* CONFIG_TESTING_OPTIONS */
1939 wpa_hexdump_buf(MSG_DEBUG
,
1940 "DPP: Authentication Request frame attributes", msg
);
1946 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1947 enum dpp_status_error status
,
1948 const struct wpabuf
*pr
,
1950 const u8
*r_pubkey_hash
,
1951 const u8
*i_pubkey_hash
,
1952 const u8
*r_nonce
, const u8
*i_nonce
,
1953 const u8
*wrapped_r_auth
,
1954 size_t wrapped_r_auth_len
,
1958 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1959 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1960 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1961 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1963 size_t len
[2], siv_len
, attr_len
;
1964 u8
*attr_start
, *attr_end
, *pos
;
1966 auth
->waiting_auth_conf
= 1;
1967 auth
->auth_resp_tries
= 0;
1969 /* Build DPP Authentication Response frame attributes */
1970 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1971 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1974 #endif /* CONFIG_DPP2 */
1975 #ifdef CONFIG_TESTING_OPTIONS
1976 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1978 #endif /* CONFIG_TESTING_OPTIONS */
1979 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1983 attr_start
= wpabuf_put(msg
, 0);
1987 dpp_build_attr_status(msg
, status
);
1989 /* Responder Bootstrapping Key Hash */
1990 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1992 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1993 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1995 /* Responder Protocol Key */
1997 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1998 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1999 wpabuf_put_buf(msg
, pr
);
2003 /* Protocol Version */
2004 if (auth
->peer_version
>= 2) {
2005 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
2006 wpabuf_put_le16(msg
, 1);
2007 wpabuf_put_u8(msg
, 2);
2009 #endif /* CONFIG_DPP2 */
2011 attr_end
= wpabuf_put(msg
, 0);
2013 #ifdef CONFIG_TESTING_OPTIONS
2014 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
2015 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2016 goto skip_wrapped_data
;
2018 #endif /* CONFIG_TESTING_OPTIONS */
2020 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
2025 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
2027 WPA_PUT_LE16(pos
, nonce_len
);
2029 os_memcpy(pos
, r_nonce
, nonce_len
);
2035 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
2037 WPA_PUT_LE16(pos
, nonce_len
);
2039 os_memcpy(pos
, i_nonce
, nonce_len
);
2040 #ifdef CONFIG_TESTING_OPTIONS
2041 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
2042 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
2043 pos
[nonce_len
/ 2] ^= 0x01;
2045 #endif /* CONFIG_TESTING_OPTIONS */
2049 #ifdef CONFIG_TESTING_OPTIONS
2050 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
2051 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
2054 #endif /* CONFIG_TESTING_OPTIONS */
2056 /* R-capabilities */
2057 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
2059 WPA_PUT_LE16(pos
, 1);
2061 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
2063 *pos
++ = auth
->r_capab
;
2064 #ifdef CONFIG_TESTING_OPTIONS
2065 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
2066 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
2068 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
2069 wpa_printf(MSG_INFO
,
2070 "DPP: TESTING - incompatible R-capabilities");
2071 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
2072 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
2075 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
2076 DPP_CAPAB_CONFIGURATOR
;
2079 #endif /* CONFIG_TESTING_OPTIONS */
2081 if (wrapped_r_auth
) {
2083 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
2085 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
2087 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
2088 pos
+= wrapped_r_auth_len
;
2091 /* OUI, OUI type, Crypto Suite, DPP frame type */
2092 addr
[0] = wpabuf_head_u8(msg
) + 2;
2093 len
[0] = 3 + 1 + 1 + 1;
2094 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2096 /* Attributes before Wrapped Data */
2097 addr
[1] = attr_start
;
2098 len
[1] = attr_end
- attr_start
;
2099 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2101 siv_len
= pos
- clear
;
2102 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
2103 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
2104 2, addr
, len
, wrapped_data
) < 0) {
2108 siv_len
+= AES_BLOCK_SIZE
;
2109 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2110 wrapped_data
, siv_len
);
2112 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2113 wpabuf_put_le16(msg
, siv_len
);
2114 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
2116 #ifdef CONFIG_TESTING_OPTIONS
2117 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
2118 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2119 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2122 #endif /* CONFIG_TESTING_OPTIONS */
2124 wpa_hexdump_buf(MSG_DEBUG
,
2125 "DPP: Authentication Response frame attributes", msg
);
2130 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
2131 u16 num_modes
, unsigned int freq
)
2136 if (!own_modes
|| !num_modes
)
2139 for (m
= 0; m
< num_modes
; m
++) {
2140 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2141 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
2144 flag
= own_modes
[m
].channels
[c
].flag
;
2145 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
2146 HOSTAPD_CHAN_NO_IR
|
2147 HOSTAPD_CHAN_RADAR
)))
2152 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
2157 static int freq_included(const unsigned int freqs
[], unsigned int num
,
2161 if (freqs
[--num
] == freq
)
2168 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
2173 for (i
= 0; i
< num
; i
++) {
2174 if (freqs
[i
] == freq
)
2177 if (i
== 0 || i
>= num
)
2179 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
2184 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
2185 struct hostapd_hw_modes
*own_modes
,
2188 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
2189 unsigned int i
, freq
;
2191 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
2192 freq
= peer_bi
->freq
[i
];
2193 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2195 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
2196 auth
->freq
[auth
->num_freq
++] = freq
;
2198 if (!auth
->num_freq
) {
2199 wpa_printf(MSG_INFO
,
2200 "DPP: No available channels for initiating DPP Authentication");
2203 auth
->curr_freq
= auth
->freq
[0];
2208 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
2209 struct hostapd_hw_modes
*own_modes
,
2218 if (!own_modes
|| !num_modes
) {
2219 auth
->freq
[0] = 2412;
2220 auth
->freq
[1] = 2437;
2221 auth
->freq
[2] = 2462;
2226 for (m
= 0; m
< num_modes
; m
++) {
2227 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2228 freq
= own_modes
[m
].channels
[c
].freq
;
2229 flag
= own_modes
[m
].channels
[c
].flag
;
2230 if (flag
& (HOSTAPD_CHAN_DISABLED
|
2231 HOSTAPD_CHAN_NO_IR
|
2232 HOSTAPD_CHAN_RADAR
))
2234 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2236 auth
->freq
[auth
->num_freq
++] = freq
;
2237 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
2244 return auth
->num_freq
== 0 ? -1 : 0;
2248 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
2249 unsigned int neg_freq
,
2250 struct hostapd_hw_modes
*own_modes
,
2254 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2261 auth
->freq
[0] = neg_freq
;
2265 if (auth
->peer_bi
->num_freq
> 0)
2266 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2268 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2272 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2273 * likely channels first. */
2274 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2275 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2276 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2279 auth
->curr_freq
= auth
->freq
[0];
2282 end
= pos
+ sizeof(freqs
);
2283 for (i
= 0; i
< auth
->num_freq
; i
++) {
2284 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2285 if (os_snprintf_error(end
- pos
, res
))
2290 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2297 static int dpp_gen_uri(struct dpp_bootstrap_info
*bi
)
2299 char macstr
[ETH_ALEN
* 2 + 10];
2302 len
= 4; /* "DPP:" */
2304 len
+= 3 + os_strlen(bi
->chan
); /* C:...; */
2305 if (is_zero_ether_addr(bi
->mac_addr
))
2308 os_snprintf(macstr
, sizeof(macstr
), "M:" COMPACT_MACSTR
";",
2309 MAC2STR(bi
->mac_addr
));
2310 len
+= os_strlen(macstr
); /* M:...; */
2312 len
+= 3 + os_strlen(bi
->info
); /* I:...; */
2313 len
+= 4 + os_strlen(bi
->pk
); /* K:...;; */
2316 bi
->uri
= os_malloc(len
+ 1);
2319 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
2320 bi
->chan
? "C:" : "", bi
->chan
? bi
->chan
: "",
2321 bi
->chan
? ";" : "",
2323 bi
->info
? "I:" : "", bi
->info
? bi
->info
: "",
2324 bi
->info
? ";" : "",
2330 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2332 struct dpp_bootstrap_info
*bi
;
2335 return 0; /* already generated */
2337 bi
= os_zalloc(sizeof(*bi
));
2340 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2341 if (dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0) < 0 ||
2342 dpp_gen_uri(bi
) < 0)
2344 wpa_printf(MSG_DEBUG
,
2345 "DPP: Auto-generated own bootstrapping key info: URI %s",
2348 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2352 dpp_bootstrap_info_free(bi
);
2357 struct dpp_authentication
*
2358 dpp_alloc_auth(struct dpp_global
*dpp
, void *msg_ctx
)
2360 struct dpp_authentication
*auth
;
2362 auth
= os_zalloc(sizeof(*auth
));
2366 auth
->msg_ctx
= msg_ctx
;
2367 auth
->conf_resp_status
= 255;
2372 struct dpp_authentication
* dpp_auth_init(struct dpp_global
*dpp
, void *msg_ctx
,
2373 struct dpp_bootstrap_info
*peer_bi
,
2374 struct dpp_bootstrap_info
*own_bi
,
2375 u8 dpp_allowed_roles
,
2376 unsigned int neg_freq
,
2377 struct hostapd_hw_modes
*own_modes
,
2380 struct dpp_authentication
*auth
;
2383 struct wpabuf
*pi
= NULL
;
2384 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2385 #ifdef CONFIG_TESTING_OPTIONS
2386 u8 test_hash
[SHA256_MAC_LEN
];
2387 #endif /* CONFIG_TESTING_OPTIONS */
2389 auth
= dpp_alloc_auth(dpp
, msg_ctx
);
2392 if (peer_bi
->configurator_params
&&
2393 dpp_set_configurator(auth
, peer_bi
->configurator_params
) < 0)
2395 auth
->initiator
= 1;
2396 auth
->waiting_auth_resp
= 1;
2397 auth
->allowed_roles
= dpp_allowed_roles
;
2398 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2399 auth
->peer_bi
= peer_bi
;
2400 auth
->own_bi
= own_bi
;
2401 auth
->curve
= peer_bi
->curve
;
2403 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2404 dpp_prepare_channel_list(auth
, neg_freq
, own_modes
, num_modes
) < 0)
2407 #ifdef CONFIG_TESTING_OPTIONS
2408 if (dpp_nonce_override_len
> 0) {
2409 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2410 nonce_len
= dpp_nonce_override_len
;
2411 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2413 nonce_len
= auth
->curve
->nonce_len
;
2414 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2415 wpa_printf(MSG_ERROR
,
2416 "DPP: Failed to generate I-nonce");
2420 #else /* CONFIG_TESTING_OPTIONS */
2421 nonce_len
= auth
->curve
->nonce_len
;
2422 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2423 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2426 #endif /* CONFIG_TESTING_OPTIONS */
2427 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2429 #ifdef CONFIG_TESTING_OPTIONS
2430 if (dpp_protocol_key_override_len
) {
2431 const struct dpp_curve_params
*tmp_curve
;
2433 wpa_printf(MSG_INFO
,
2434 "DPP: TESTING - override protocol key");
2435 auth
->own_protocol_key
= dpp_set_keypair(
2436 &tmp_curve
, dpp_protocol_key_override
,
2437 dpp_protocol_key_override_len
);
2439 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2441 #else /* CONFIG_TESTING_OPTIONS */
2442 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2443 #endif /* CONFIG_TESTING_OPTIONS */
2444 if (!auth
->own_protocol_key
)
2447 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2451 /* ECDH: M = pI * BR */
2452 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_bi
->pubkey
,
2453 auth
->Mx
, &secret_len
) < 0)
2455 auth
->secret_len
= secret_len
;
2457 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2458 auth
->Mx
, auth
->secret_len
);
2459 auth
->Mx_len
= auth
->secret_len
;
2461 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2462 auth
->curve
->hash_len
) < 0)
2465 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2466 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2468 #ifdef CONFIG_TESTING_OPTIONS
2469 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2470 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2471 r_pubkey_hash
= NULL
;
2472 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2473 wpa_printf(MSG_INFO
,
2474 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2475 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2476 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2477 r_pubkey_hash
= test_hash
;
2478 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2479 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2480 i_pubkey_hash
= NULL
;
2481 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2482 wpa_printf(MSG_INFO
,
2483 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2484 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2485 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2486 i_pubkey_hash
= test_hash
;
2487 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2488 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2491 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2492 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2494 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2495 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2498 #endif /* CONFIG_TESTING_OPTIONS */
2500 if (neg_freq
&& auth
->num_freq
== 1 && auth
->freq
[0] == neg_freq
)
2502 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2503 i_pubkey_hash
, neg_freq
);
2511 dpp_auth_deinit(auth
);
2517 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2521 size_t json_len
, clear_len
;
2522 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2526 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2528 nonce_len
= auth
->curve
->nonce_len
;
2529 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2530 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2533 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2534 json_len
= os_strlen(json
);
2535 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configRequest JSON", json
, json_len
);
2537 /* { E-nonce, configAttrib }ke */
2538 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2539 clear
= wpabuf_alloc(clear_len
);
2540 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2541 #ifdef CONFIG_TESTING_OPTIONS
2542 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2544 #endif /* CONFIG_TESTING_OPTIONS */
2545 msg
= wpabuf_alloc(attr_len
);
2549 #ifdef CONFIG_TESTING_OPTIONS
2550 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2551 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2554 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2555 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2556 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2557 wpabuf_put_le16(clear
, nonce_len
- 1);
2558 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2561 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2562 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2563 goto skip_wrapped_data
;
2565 #endif /* CONFIG_TESTING_OPTIONS */
2568 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2569 wpabuf_put_le16(clear
, nonce_len
);
2570 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2572 #ifdef CONFIG_TESTING_OPTIONS
2574 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2575 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2576 goto skip_conf_attr_obj
;
2578 #endif /* CONFIG_TESTING_OPTIONS */
2581 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2582 wpabuf_put_le16(clear
, json_len
);
2583 wpabuf_put_data(clear
, json
, json_len
);
2585 #ifdef CONFIG_TESTING_OPTIONS
2587 #endif /* CONFIG_TESTING_OPTIONS */
2589 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2590 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2591 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2594 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2595 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2596 wpabuf_head(clear
), wpabuf_len(clear
),
2597 0, NULL
, NULL
, wrapped
) < 0)
2599 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2600 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2602 #ifdef CONFIG_TESTING_OPTIONS
2603 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2604 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2605 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2608 #endif /* CONFIG_TESTING_OPTIONS */
2610 wpa_hexdump_buf(MSG_DEBUG
,
2611 "DPP: Configuration Request frame attributes", msg
);
2622 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2624 /* Advertisement Protocol IE */
2625 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2626 wpabuf_put_u8(buf
, 8); /* Length */
2627 wpabuf_put_u8(buf
, 0x7f);
2628 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2629 wpabuf_put_u8(buf
, 5);
2630 wpabuf_put_be24(buf
, OUI_WFA
);
2631 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2632 wpabuf_put_u8(buf
, 0x01);
2636 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2639 wpabuf_put_le16(buf
, wpabuf_len(query
));
2640 wpabuf_put_buf(buf
, query
);
2644 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2647 struct wpabuf
*buf
, *conf_req
;
2649 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2651 wpa_printf(MSG_DEBUG
,
2652 "DPP: No configuration request data available");
2656 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2658 wpabuf_free(conf_req
);
2662 dpp_write_adv_proto(buf
);
2663 dpp_write_gas_query(buf
, conf_req
);
2664 wpabuf_free(conf_req
);
2665 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2671 struct wpabuf
* dpp_build_conf_req_helper(struct dpp_authentication
*auth
,
2673 enum dpp_netrole netrole
,
2674 const char *mud_url
, int *opclasses
)
2676 size_t len
, name_len
;
2677 const char *tech
= "infra";
2678 const char *dpp_name
;
2679 struct wpabuf
*buf
, *json
;
2681 #ifdef CONFIG_TESTING_OPTIONS
2682 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
2683 static const char *bogus_tech
= "knfra";
2685 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
2688 #endif /* CONFIG_TESTING_OPTIONS */
2690 dpp_name
= name
? name
: "Test";
2691 name_len
= os_strlen(dpp_name
);
2693 len
= 100 + name_len
* 6 + 1 + int_array_len(opclasses
) * 4;
2694 if (mud_url
&& mud_url
[0])
2695 len
+= 10 + os_strlen(mud_url
);
2696 json
= wpabuf_alloc(len
);
2700 json_start_object(json
, NULL
);
2701 if (json_add_string_escape(json
, "name", dpp_name
, name_len
) < 0) {
2705 json_value_sep(json
);
2706 json_add_string(json
, "wi-fi_tech", tech
);
2707 json_value_sep(json
);
2708 json_add_string(json
, "netRole", dpp_netrole_str(netrole
));
2709 if (mud_url
&& mud_url
[0]) {
2710 json_value_sep(json
);
2711 json_add_string(json
, "mudurl", mud_url
);
2716 json_value_sep(json
);
2717 json_start_array(json
, "bandSupport");
2718 for (i
= 0; opclasses
[i
]; i
++)
2719 wpabuf_printf(json
, "%s%u", i
? "," : "", opclasses
[i
]);
2720 json_end_array(json
);
2722 json_end_object(json
);
2724 buf
= dpp_build_conf_req(auth
, wpabuf_head(json
));
2731 static void dpp_auth_success(struct dpp_authentication
*auth
)
2733 wpa_printf(MSG_DEBUG
,
2734 "DPP: Authentication success - clear temporary keys");
2735 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2737 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2739 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2741 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2742 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2744 auth
->auth_success
= 1;
2748 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2750 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2753 size_t i
, num_elem
= 0;
2758 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2759 nonce_len
= auth
->curve
->nonce_len
;
2761 if (auth
->initiator
) {
2762 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2763 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2765 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2768 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2770 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2771 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2773 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2776 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2778 if (!pix
|| !prx
|| !brx
)
2781 addr
[num_elem
] = auth
->i_nonce
;
2782 len
[num_elem
] = nonce_len
;
2785 addr
[num_elem
] = auth
->r_nonce
;
2786 len
[num_elem
] = nonce_len
;
2789 addr
[num_elem
] = wpabuf_head(pix
);
2790 len
[num_elem
] = wpabuf_len(pix
) / 2;
2793 addr
[num_elem
] = wpabuf_head(prx
);
2794 len
[num_elem
] = wpabuf_len(prx
) / 2;
2798 addr
[num_elem
] = wpabuf_head(bix
);
2799 len
[num_elem
] = wpabuf_len(bix
) / 2;
2803 addr
[num_elem
] = wpabuf_head(brx
);
2804 len
[num_elem
] = wpabuf_len(brx
) / 2;
2807 addr
[num_elem
] = &zero
;
2811 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2812 for (i
= 0; i
< num_elem
; i
++)
2813 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2814 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2816 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2817 auth
->curve
->hash_len
);
2827 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2829 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2832 size_t i
, num_elem
= 0;
2837 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2838 nonce_len
= auth
->curve
->nonce_len
;
2840 if (auth
->initiator
) {
2841 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2842 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2844 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2849 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2851 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2852 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2854 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2859 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2861 if (!pix
|| !prx
|| !brx
)
2864 addr
[num_elem
] = auth
->r_nonce
;
2865 len
[num_elem
] = nonce_len
;
2868 addr
[num_elem
] = auth
->i_nonce
;
2869 len
[num_elem
] = nonce_len
;
2872 addr
[num_elem
] = wpabuf_head(prx
);
2873 len
[num_elem
] = wpabuf_len(prx
) / 2;
2876 addr
[num_elem
] = wpabuf_head(pix
);
2877 len
[num_elem
] = wpabuf_len(pix
) / 2;
2880 addr
[num_elem
] = wpabuf_head(brx
);
2881 len
[num_elem
] = wpabuf_len(brx
) / 2;
2885 addr
[num_elem
] = wpabuf_head(bix
);
2886 len
[num_elem
] = wpabuf_len(bix
) / 2;
2890 addr
[num_elem
] = &one
;
2894 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2895 for (i
= 0; i
< num_elem
; i
++)
2896 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2897 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2899 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2900 auth
->curve
->hash_len
);
2910 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2912 const EC_GROUP
*group
;
2914 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2915 const EC_POINT
*BI_point
;
2917 BIGNUM
*lx
, *sum
, *q
;
2918 const BIGNUM
*bR_bn
, *pR_bn
;
2921 /* L = ((bR + pR) modulo q) * BI */
2923 bnctx
= BN_CTX_new();
2927 if (!bnctx
|| !sum
|| !q
|| !lx
)
2929 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2932 BI_point
= EC_KEY_get0_public_key(BI
);
2933 group
= EC_KEY_get0_group(BI
);
2937 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2938 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2941 bR_bn
= EC_KEY_get0_private_key(bR
);
2942 pR_bn
= EC_KEY_get0_private_key(pR
);
2943 if (!bR_bn
|| !pR_bn
)
2945 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2946 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2948 l
= EC_POINT_new(group
);
2950 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2951 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2953 wpa_printf(MSG_ERROR
,
2954 "OpenSSL: failed: %s",
2955 ERR_error_string(ERR_get_error(), NULL
));
2959 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2961 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2962 auth
->Lx_len
= auth
->secret_len
;
2965 EC_POINT_clear_free(l
);
2977 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2979 const EC_GROUP
*group
;
2980 EC_POINT
*l
= NULL
, *sum
= NULL
;
2981 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2982 const EC_POINT
*BR_point
, *PR_point
;
2985 const BIGNUM
*bI_bn
;
2988 /* L = bI * (BR + PR) */
2990 bnctx
= BN_CTX_new();
2994 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2995 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2998 BR_point
= EC_KEY_get0_public_key(BR
);
2999 PR_point
= EC_KEY_get0_public_key(PR
);
3001 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
3004 group
= EC_KEY_get0_group(bI
);
3005 bI_bn
= EC_KEY_get0_private_key(bI
);
3006 if (!group
|| !bI_bn
)
3008 sum
= EC_POINT_new(group
);
3009 l
= EC_POINT_new(group
);
3011 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
3012 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
3013 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
3015 wpa_printf(MSG_ERROR
,
3016 "OpenSSL: failed: %s",
3017 ERR_error_string(ERR_get_error(), NULL
));
3021 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
3023 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
3024 auth
->Lx_len
= auth
->secret_len
;
3027 EC_POINT_clear_free(l
);
3028 EC_POINT_clear_free(sum
);
3038 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
3042 struct wpabuf
*msg
, *pr
= NULL
;
3043 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
3044 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
3045 size_t wrapped_r_auth_len
;
3047 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
3048 enum dpp_status_error status
= DPP_STATUS_OK
;
3049 #ifdef CONFIG_TESTING_OPTIONS
3050 u8 test_hash
[SHA256_MAC_LEN
];
3051 #endif /* CONFIG_TESTING_OPTIONS */
3053 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3057 #ifdef CONFIG_TESTING_OPTIONS
3058 if (dpp_nonce_override_len
> 0) {
3059 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
3060 nonce_len
= dpp_nonce_override_len
;
3061 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
3063 nonce_len
= auth
->curve
->nonce_len
;
3064 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3065 wpa_printf(MSG_ERROR
,
3066 "DPP: Failed to generate R-nonce");
3070 #else /* CONFIG_TESTING_OPTIONS */
3071 nonce_len
= auth
->curve
->nonce_len
;
3072 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3073 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
3076 #endif /* CONFIG_TESTING_OPTIONS */
3077 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
3079 EVP_PKEY_free(auth
->own_protocol_key
);
3080 #ifdef CONFIG_TESTING_OPTIONS
3081 if (dpp_protocol_key_override_len
) {
3082 const struct dpp_curve_params
*tmp_curve
;
3084 wpa_printf(MSG_INFO
,
3085 "DPP: TESTING - override protocol key");
3086 auth
->own_protocol_key
= dpp_set_keypair(
3087 &tmp_curve
, dpp_protocol_key_override
,
3088 dpp_protocol_key_override_len
);
3090 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3092 #else /* CONFIG_TESTING_OPTIONS */
3093 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3094 #endif /* CONFIG_TESTING_OPTIONS */
3095 if (!auth
->own_protocol_key
)
3098 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
3102 /* ECDH: N = pR * PI */
3103 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_protocol_key
,
3104 auth
->Nx
, &secret_len
) < 0)
3107 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3108 auth
->Nx
, auth
->secret_len
);
3109 auth
->Nx_len
= auth
->secret_len
;
3111 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3112 auth
->curve
->hash_len
) < 0)
3115 if (auth
->own_bi
&& auth
->peer_bi
) {
3116 /* Mutual authentication */
3117 if (dpp_auth_derive_l_responder(auth
) < 0)
3121 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3124 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3125 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
3126 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
3127 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
3129 #ifdef CONFIG_TESTING_OPTIONS
3130 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
3131 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
3132 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3134 #endif /* CONFIG_TESTING_OPTIONS */
3135 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3136 r_auth
, 4 + auth
->curve
->hash_len
,
3137 0, NULL
, NULL
, wrapped_r_auth
) < 0)
3139 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
3140 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
3141 wrapped_r_auth
, wrapped_r_auth_len
);
3142 w_r_auth
= wrapped_r_auth
;
3144 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3146 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3148 i_pubkey_hash
= NULL
;
3150 i_nonce
= auth
->i_nonce
;
3151 r_nonce
= auth
->r_nonce
;
3153 #ifdef CONFIG_TESTING_OPTIONS
3154 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3155 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3156 r_pubkey_hash
= NULL
;
3157 } else if (dpp_test
==
3158 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3159 wpa_printf(MSG_INFO
,
3160 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3161 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3162 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3163 r_pubkey_hash
= test_hash
;
3164 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3165 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3166 i_pubkey_hash
= NULL
;
3167 } else if (dpp_test
==
3168 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3169 wpa_printf(MSG_INFO
,
3170 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3172 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3174 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3175 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3176 i_pubkey_hash
= test_hash
;
3177 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
3178 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
3181 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
3182 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
3184 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
3185 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
3187 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
3188 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
3190 wrapped_r_auth_len
= 0;
3191 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3192 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3194 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
3195 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3197 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
3198 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
3200 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3201 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3204 #endif /* CONFIG_TESTING_OPTIONS */
3206 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
3207 r_pubkey_hash
, i_pubkey_hash
,
3209 w_r_auth
, wrapped_r_auth_len
,
3213 wpabuf_free(auth
->resp_msg
);
3214 auth
->resp_msg
= msg
;
3222 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
3223 enum dpp_status_error status
)
3226 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
3227 #ifdef CONFIG_TESTING_OPTIONS
3228 u8 test_hash
[SHA256_MAC_LEN
];
3229 #endif /* CONFIG_TESTING_OPTIONS */
3233 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3235 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3237 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3239 i_pubkey_hash
= NULL
;
3241 i_nonce
= auth
->i_nonce
;
3243 #ifdef CONFIG_TESTING_OPTIONS
3244 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3245 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3246 r_pubkey_hash
= NULL
;
3247 } else if (dpp_test
==
3248 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3249 wpa_printf(MSG_INFO
,
3250 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3251 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3252 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3253 r_pubkey_hash
= test_hash
;
3254 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3255 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3256 i_pubkey_hash
= NULL
;
3257 } else if (dpp_test
==
3258 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3259 wpa_printf(MSG_INFO
,
3260 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3262 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3264 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3265 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3266 i_pubkey_hash
= test_hash
;
3267 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3268 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3270 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3271 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3274 #endif /* CONFIG_TESTING_OPTIONS */
3276 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
3277 r_pubkey_hash
, i_pubkey_hash
,
3278 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3281 wpabuf_free(auth
->resp_msg
);
3282 auth
->resp_msg
= msg
;
3287 struct dpp_authentication
*
3288 dpp_auth_req_rx(struct dpp_global
*dpp
, void *msg_ctx
, u8 dpp_allowed_roles
,
3289 int qr_mutual
, struct dpp_bootstrap_info
*peer_bi
,
3290 struct dpp_bootstrap_info
*own_bi
,
3291 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3294 EVP_PKEY
*pi
= NULL
;
3295 EVP_PKEY_CTX
*ctx
= NULL
;
3299 u8
*unwrapped
= NULL
;
3300 size_t unwrapped_len
= 0;
3301 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3303 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3304 i_bootstrap_len
, channel_len
;
3305 struct dpp_authentication
*auth
= NULL
;
3309 #endif /* CONFIG_DPP2 */
3311 #ifdef CONFIG_TESTING_OPTIONS
3312 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3313 wpa_printf(MSG_INFO
,
3314 "DPP: TESTING - stop at Authentication Request");
3317 #endif /* CONFIG_TESTING_OPTIONS */
3319 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3321 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3322 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3323 "Missing or invalid required Wrapped Data attribute");
3326 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3327 wrapped_data
, wrapped_data_len
);
3328 attr_len
= wrapped_data
- 4 - attr_start
;
3330 auth
= dpp_alloc_auth(dpp
, msg_ctx
);
3333 if (peer_bi
&& peer_bi
->configurator_params
&&
3334 dpp_set_configurator(auth
, peer_bi
->configurator_params
) < 0)
3336 auth
->peer_bi
= peer_bi
;
3337 auth
->own_bi
= own_bi
;
3338 auth
->curve
= own_bi
->curve
;
3339 auth
->curr_freq
= freq
;
3341 auth
->peer_version
= 1; /* default to the first version */
3343 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3346 if (version_len
< 1 || version
[0] == 0) {
3348 "Invalid Protocol Version attribute");
3351 auth
->peer_version
= version
[0];
3352 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3353 auth
->peer_version
);
3355 #endif /* CONFIG_DPP2 */
3357 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3362 if (channel_len
< 2) {
3363 dpp_auth_fail(auth
, "Too short Channel attribute");
3367 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3368 wpa_printf(MSG_DEBUG
,
3369 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3370 channel
[0], channel
[1], neg_freq
);
3373 "Unsupported Channel attribute value");
3377 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3378 wpa_printf(MSG_DEBUG
,
3379 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3381 auth
->curr_freq
= neg_freq
;
3385 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3389 "Missing required Initiator Protocol Key attribute");
3392 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3393 i_proto
, i_proto_len
);
3396 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3398 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3401 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3403 if (dpp_ecdh(own_bi
->pubkey
, pi
, auth
->Mx
, &secret_len
) < 0)
3405 auth
->secret_len
= secret_len
;
3407 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3408 auth
->Mx
, auth
->secret_len
);
3409 auth
->Mx_len
= auth
->secret_len
;
3411 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3412 auth
->curve
->hash_len
) < 0)
3416 len
[0] = DPP_HDR_LEN
;
3417 addr
[1] = attr_start
;
3419 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3420 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3421 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3422 wrapped_data
, wrapped_data_len
);
3423 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3424 unwrapped
= os_malloc(unwrapped_len
);
3427 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3428 wrapped_data
, wrapped_data_len
,
3429 2, addr
, len
, unwrapped
) < 0) {
3430 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3433 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3434 unwrapped
, unwrapped_len
);
3436 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3437 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3441 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3443 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3444 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3447 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3448 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3450 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3451 DPP_ATTR_I_CAPABILITIES
,
3453 if (!i_capab
|| i_capab_len
< 1) {
3454 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3457 auth
->i_capab
= i_capab
[0];
3458 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3460 bin_clear_free(unwrapped
, unwrapped_len
);
3463 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3464 case DPP_CAPAB_ENROLLEE
:
3465 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3466 wpa_printf(MSG_DEBUG
,
3467 "DPP: Local policy does not allow Configurator role");
3468 goto not_compatible
;
3470 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3471 auth
->configurator
= 1;
3473 case DPP_CAPAB_CONFIGURATOR
:
3474 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3475 wpa_printf(MSG_DEBUG
,
3476 "DPP: Local policy does not allow Enrollee role");
3477 goto not_compatible
;
3479 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3480 auth
->configurator
= 0;
3482 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3483 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3484 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3485 auth
->configurator
= 0;
3486 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3487 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3488 auth
->configurator
= 1;
3490 wpa_printf(MSG_DEBUG
,
3491 "DPP: Local policy does not allow Configurator/Enrollee role");
3492 goto not_compatible
;
3496 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3497 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3498 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3499 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3503 auth
->peer_protocol_key
= pi
;
3505 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3506 char hex
[SHA256_MAC_LEN
* 2 + 1];
3508 wpa_printf(MSG_DEBUG
,
3509 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3510 if (dpp_auth_build_resp_status(auth
,
3511 DPP_STATUS_RESPONSE_PENDING
) < 0)
3513 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3514 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3516 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3517 auth
->response_pending
= 1;
3518 os_memcpy(auth
->waiting_pubkey_hash
,
3519 i_bootstrap
, i_bootstrap_len
);
3520 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3526 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3530 if (dpp_auth_build_resp_ok(auth
) < 0)
3536 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3537 "i-capab=0x%02x", auth
->i_capab
);
3538 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3539 auth
->configurator
= 1;
3541 auth
->configurator
= 0;
3542 auth
->peer_protocol_key
= pi
;
3544 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3547 auth
->remove_on_tx_status
= 1;
3550 bin_clear_free(unwrapped
, unwrapped_len
);
3552 EVP_PKEY_CTX_free(ctx
);
3553 dpp_auth_deinit(auth
);
3558 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3559 struct dpp_bootstrap_info
*peer_bi
)
3561 if (!auth
|| !auth
->response_pending
||
3562 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3563 SHA256_MAC_LEN
) != 0)
3566 wpa_printf(MSG_DEBUG
,
3567 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3568 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3569 auth
->peer_bi
= peer_bi
;
3571 if (dpp_auth_build_resp_ok(auth
) < 0)
3578 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3579 enum dpp_status_error status
)
3582 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3584 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3587 size_t len
[2], attr_len
;
3589 u8
*wrapped_r_nonce
;
3590 u8
*attr_start
, *attr_end
;
3591 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3592 #ifdef CONFIG_TESTING_OPTIONS
3593 u8 test_hash
[SHA256_MAC_LEN
];
3594 #endif /* CONFIG_TESTING_OPTIONS */
3596 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3598 i_auth_len
= 4 + auth
->curve
->hash_len
;
3599 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3600 /* Build DPP Authentication Confirmation frame attributes */
3601 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3602 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3603 #ifdef CONFIG_TESTING_OPTIONS
3604 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3606 #endif /* CONFIG_TESTING_OPTIONS */
3607 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3611 attr_start
= wpabuf_put(msg
, 0);
3613 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3615 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3617 i_pubkey_hash
= NULL
;
3619 #ifdef CONFIG_TESTING_OPTIONS
3620 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3621 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3623 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3624 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3627 #endif /* CONFIG_TESTING_OPTIONS */
3630 dpp_build_attr_status(msg
, status
);
3632 #ifdef CONFIG_TESTING_OPTIONS
3634 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3635 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3636 r_pubkey_hash
= NULL
;
3637 } else if (dpp_test
==
3638 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3639 wpa_printf(MSG_INFO
,
3640 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3641 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3642 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3643 r_pubkey_hash
= test_hash
;
3644 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3645 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3646 i_pubkey_hash
= NULL
;
3647 } else if (dpp_test
==
3648 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3649 wpa_printf(MSG_INFO
,
3650 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3652 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3654 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3655 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3656 i_pubkey_hash
= test_hash
;
3658 #endif /* CONFIG_TESTING_OPTIONS */
3660 /* Responder Bootstrapping Key Hash */
3661 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3663 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3664 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3666 #ifdef CONFIG_TESTING_OPTIONS
3667 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3668 goto skip_wrapped_data
;
3669 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3671 #endif /* CONFIG_TESTING_OPTIONS */
3673 attr_end
= wpabuf_put(msg
, 0);
3675 /* OUI, OUI type, Crypto Suite, DPP frame type */
3676 addr
[0] = wpabuf_head_u8(msg
) + 2;
3677 len
[0] = 3 + 1 + 1 + 1;
3678 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3680 /* Attributes before Wrapped Data */
3681 addr
[1] = attr_start
;
3682 len
[1] = attr_end
- attr_start
;
3683 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3685 if (status
== DPP_STATUS_OK
) {
3686 /* I-auth wrapped with ke */
3687 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3688 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3689 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3691 #ifdef CONFIG_TESTING_OPTIONS
3692 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3694 #endif /* CONFIG_TESTING_OPTIONS */
3696 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3698 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3699 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3700 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3703 #ifdef CONFIG_TESTING_OPTIONS
3704 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3705 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3706 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3709 #endif /* CONFIG_TESTING_OPTIONS */
3710 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3712 2, addr
, len
, wrapped_i_auth
) < 0)
3714 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3715 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3717 /* R-nonce wrapped with k2 */
3718 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3719 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3720 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3722 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3723 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3724 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3726 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3727 r_nonce
, r_nonce_len
,
3728 2, addr
, len
, wrapped_r_nonce
) < 0)
3730 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3731 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3734 #ifdef CONFIG_TESTING_OPTIONS
3735 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3736 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3737 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3740 #endif /* CONFIG_TESTING_OPTIONS */
3742 wpa_hexdump_buf(MSG_DEBUG
,
3743 "DPP: Authentication Confirmation frame attributes",
3745 if (status
== DPP_STATUS_OK
)
3746 dpp_auth_success(auth
);
3757 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3758 const u8
*attr_start
, size_t attr_len
,
3759 const u8
*wrapped_data
, u16 wrapped_data_len
,
3760 enum dpp_status_error status
)
3764 u8
*unwrapped
= NULL
;
3765 size_t unwrapped_len
= 0;
3766 const u8
*i_nonce
, *r_capab
;
3767 u16 i_nonce_len
, r_capab_len
;
3769 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3770 wpa_printf(MSG_DEBUG
,
3771 "DPP: Responder reported incompatible roles");
3772 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3773 wpa_printf(MSG_DEBUG
,
3774 "DPP: Responder reported more time needed");
3776 wpa_printf(MSG_DEBUG
,
3777 "DPP: Responder reported failure (status %d)",
3779 dpp_auth_fail(auth
, "Responder reported failure");
3784 len
[0] = DPP_HDR_LEN
;
3785 addr
[1] = attr_start
;
3787 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3788 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3789 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3790 wrapped_data
, wrapped_data_len
);
3791 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3792 unwrapped
= os_malloc(unwrapped_len
);
3795 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3796 wrapped_data
, wrapped_data_len
,
3797 2, addr
, len
, unwrapped
) < 0) {
3798 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3801 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3802 unwrapped
, unwrapped_len
);
3804 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3805 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3809 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3811 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3812 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3815 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3816 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3817 dpp_auth_fail(auth
, "I-nonce mismatch");
3821 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3822 DPP_ATTR_R_CAPABILITIES
,
3824 if (!r_capab
|| r_capab_len
< 1) {
3825 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3828 auth
->r_capab
= r_capab
[0];
3829 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3830 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3831 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3832 "r-capab=0x%02x", auth
->r_capab
);
3833 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3834 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3836 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3837 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3838 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3839 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3842 wpa_printf(MSG_DEBUG
,
3843 "DPP: Continue waiting for full DPP Authentication Response");
3844 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3845 DPP_EVENT_RESPONSE_PENDING
"%s",
3846 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3850 bin_clear_free(unwrapped
, unwrapped_len
);
3855 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3856 const u8
*attr_start
, size_t attr_len
)
3862 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3863 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3864 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3865 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3866 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3867 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3868 wrapped2_len
, r_auth_len
;
3869 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3874 #endif /* CONFIG_DPP2 */
3876 #ifdef CONFIG_TESTING_OPTIONS
3877 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3878 wpa_printf(MSG_INFO
,
3879 "DPP: TESTING - stop at Authentication Response");
3882 #endif /* CONFIG_TESTING_OPTIONS */
3884 if (!auth
->initiator
|| !auth
->peer_bi
) {
3885 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3889 auth
->waiting_auth_resp
= 0;
3891 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3893 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3895 "Missing or invalid required Wrapped Data attribute");
3898 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3899 wrapped_data
, wrapped_data_len
);
3901 attr_len
= wrapped_data
- 4 - attr_start
;
3903 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3904 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3906 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3908 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3911 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3912 r_bootstrap
, r_bootstrap_len
);
3913 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3914 SHA256_MAC_LEN
) != 0) {
3916 "Unexpected Responder Bootstrapping Key Hash value");
3917 wpa_hexdump(MSG_DEBUG
,
3918 "DPP: Expected Responder Bootstrapping Key Hash",
3919 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3923 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3924 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3927 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3929 "Invalid Initiator Bootstrapping Key Hash attribute");
3932 wpa_hexdump(MSG_MSGDUMP
,
3933 "DPP: Initiator Bootstrapping Key Hash",
3934 i_bootstrap
, i_bootstrap_len
);
3935 if (!auth
->own_bi
||
3936 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3937 SHA256_MAC_LEN
) != 0) {
3939 "Initiator Bootstrapping Key Hash attribute did not match");
3942 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3943 /* PKEX bootstrapping mandates use of mutual authentication */
3945 "Missing Initiator Bootstrapping Key Hash attribute");
3949 auth
->peer_version
= 1; /* default to the first version */
3951 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3954 if (version_len
< 1 || version
[0] == 0) {
3956 "Invalid Protocol Version attribute");
3959 auth
->peer_version
= version
[0];
3960 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3961 auth
->peer_version
);
3963 #endif /* CONFIG_DPP2 */
3965 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3967 if (!status
|| status_len
< 1) {
3969 "Missing or invalid required DPP Status attribute");
3972 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3973 auth
->auth_resp_status
= status
[0];
3974 if (status
[0] != DPP_STATUS_OK
) {
3975 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3976 attr_len
, wrapped_data
,
3977 wrapped_data_len
, status
[0]);
3981 if (!i_bootstrap
&& auth
->own_bi
) {
3982 wpa_printf(MSG_DEBUG
,
3983 "DPP: Responder decided not to use mutual authentication");
3984 auth
->own_bi
= NULL
;
3987 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3988 auth
->own_bi
!= NULL
);
3990 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3994 "Missing required Responder Protocol Key attribute");
3997 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3998 r_proto
, r_proto_len
);
4001 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
4003 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
4006 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
4008 if (dpp_ecdh(auth
->own_protocol_key
, pr
, auth
->Nx
, &secret_len
) < 0) {
4009 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
4012 EVP_PKEY_free(auth
->peer_protocol_key
);
4013 auth
->peer_protocol_key
= pr
;
4016 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
4017 auth
->Nx
, auth
->secret_len
);
4018 auth
->Nx_len
= auth
->secret_len
;
4020 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
4021 auth
->curve
->hash_len
) < 0)
4025 len
[0] = DPP_HDR_LEN
;
4026 addr
[1] = attr_start
;
4028 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4029 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4030 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4031 wrapped_data
, wrapped_data_len
);
4032 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4033 unwrapped
= os_malloc(unwrapped_len
);
4036 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4037 wrapped_data
, wrapped_data_len
,
4038 2, addr
, len
, unwrapped
) < 0) {
4039 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4042 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4043 unwrapped
, unwrapped_len
);
4045 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4046 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4050 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4052 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4053 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4056 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
4057 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
4059 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
4061 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
4062 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
4065 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
4066 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
4067 dpp_auth_fail(auth
, "I-nonce mismatch");
4072 /* Mutual authentication */
4073 if (dpp_auth_derive_l_initiator(auth
) < 0)
4077 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
4078 DPP_ATTR_R_CAPABILITIES
,
4080 if (!r_capab
|| r_capab_len
< 1) {
4081 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
4084 auth
->r_capab
= r_capab
[0];
4085 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
4086 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
4087 if ((auth
->allowed_roles
==
4088 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
4089 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
4090 /* Peer selected its role, so move from "either role" to the
4091 * role that is compatible with peer's selection. */
4092 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
4093 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
4094 auth
->configurator
? "Configurator" : "Enrollee");
4095 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
4096 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
4097 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
4098 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
4099 "Unexpected role in R-capabilities 0x%02x",
4101 if (role
!= DPP_CAPAB_ENROLLEE
&&
4102 role
!= DPP_CAPAB_CONFIGURATOR
)
4104 bin_clear_free(unwrapped
, unwrapped_len
);
4105 auth
->remove_on_tx_status
= 1;
4106 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
4109 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
4110 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
4111 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
4113 "Missing or invalid Secondary Wrapped Data");
4117 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4118 wrapped2
, wrapped2_len
);
4120 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
4123 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
4124 unwrapped2
= os_malloc(unwrapped2_len
);
4127 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4128 wrapped2
, wrapped2_len
,
4129 0, NULL
, NULL
, unwrapped2
) < 0) {
4130 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4133 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4134 unwrapped2
, unwrapped2_len
);
4136 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
4138 "Invalid attribute in secondary unwrapped data");
4142 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
4144 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
4146 "Missing or invalid Responder Authenticating Tag");
4149 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
4150 r_auth
, r_auth_len
);
4151 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4152 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
4154 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
4155 r_auth2
, r_auth_len
);
4156 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
4157 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
4158 bin_clear_free(unwrapped
, unwrapped_len
);
4159 bin_clear_free(unwrapped2
, unwrapped2_len
);
4160 auth
->remove_on_tx_status
= 1;
4161 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
4164 bin_clear_free(unwrapped
, unwrapped_len
);
4165 bin_clear_free(unwrapped2
, unwrapped2_len
);
4167 #ifdef CONFIG_TESTING_OPTIONS
4168 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
4169 wpa_printf(MSG_INFO
,
4170 "DPP: TESTING - Authentication Response in place of Confirm");
4171 if (dpp_auth_build_resp_ok(auth
) < 0)
4173 return wpabuf_dup(auth
->resp_msg
);
4175 #endif /* CONFIG_TESTING_OPTIONS */
4177 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
4180 bin_clear_free(unwrapped
, unwrapped_len
);
4181 bin_clear_free(unwrapped2
, unwrapped2_len
);
4187 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
4189 const u8
*attr_start
, size_t attr_len
,
4190 const u8
*wrapped_data
,
4191 u16 wrapped_data_len
,
4192 enum dpp_status_error status
)
4196 u8
*unwrapped
= NULL
;
4197 size_t unwrapped_len
= 0;
4201 /* Authentication Confirm failure cases are expected to include
4202 * {R-nonce}k2 in the Wrapped Data attribute. */
4205 len
[0] = DPP_HDR_LEN
;
4206 addr
[1] = attr_start
;
4208 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4209 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4210 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4211 wrapped_data
, wrapped_data_len
);
4212 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4213 unwrapped
= os_malloc(unwrapped_len
);
4215 dpp_auth_fail(auth
, "Authentication failed");
4218 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4219 wrapped_data
, wrapped_data_len
,
4220 2, addr
, len
, unwrapped
) < 0) {
4221 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4224 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4225 unwrapped
, unwrapped_len
);
4227 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4228 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4232 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4234 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4235 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4238 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
4239 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
4240 r_nonce
, r_nonce_len
);
4241 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
4242 auth
->r_nonce
, r_nonce_len
);
4243 dpp_auth_fail(auth
, "R-nonce mismatch");
4247 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
4248 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
4249 else if (status
== DPP_STATUS_AUTH_FAILURE
)
4250 dpp_auth_fail(auth
, "Peer reported authentication failure)");
4253 bin_clear_free(unwrapped
, unwrapped_len
);
4258 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4259 const u8
*attr_start
, size_t attr_len
)
4261 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4262 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4266 u8
*unwrapped
= NULL
;
4267 size_t unwrapped_len
= 0;
4268 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4270 #ifdef CONFIG_TESTING_OPTIONS
4271 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4272 wpa_printf(MSG_INFO
,
4273 "DPP: TESTING - stop at Authentication Confirm");
4276 #endif /* CONFIG_TESTING_OPTIONS */
4278 if (auth
->initiator
|| !auth
->own_bi
|| !auth
->waiting_auth_conf
) {
4279 wpa_printf(MSG_DEBUG
,
4280 "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
4281 auth
->initiator
, !!auth
->own_bi
,
4282 auth
->waiting_auth_conf
);
4283 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4287 auth
->waiting_auth_conf
= 0;
4289 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4291 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4293 "Missing or invalid required Wrapped Data attribute");
4296 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4297 wrapped_data
, wrapped_data_len
);
4299 attr_len
= wrapped_data
- 4 - attr_start
;
4301 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4302 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4304 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4306 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4309 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4310 r_bootstrap
, r_bootstrap_len
);
4311 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4312 SHA256_MAC_LEN
) != 0) {
4313 wpa_hexdump(MSG_DEBUG
,
4314 "DPP: Expected Responder Bootstrapping Key Hash",
4315 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4317 "Responder Bootstrapping Key Hash mismatch");
4321 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4322 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4325 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4327 "Invalid Initiator Bootstrapping Key Hash attribute");
4330 wpa_hexdump(MSG_MSGDUMP
,
4331 "DPP: Initiator Bootstrapping Key Hash",
4332 i_bootstrap
, i_bootstrap_len
);
4333 if (!auth
->peer_bi
||
4334 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4335 SHA256_MAC_LEN
) != 0) {
4337 "Initiator Bootstrapping Key Hash mismatch");
4340 } else if (auth
->peer_bi
) {
4341 /* Mutual authentication and peer did not include its
4342 * Bootstrapping Key Hash attribute. */
4344 "Missing Initiator Bootstrapping Key Hash attribute");
4348 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4350 if (!status
|| status_len
< 1) {
4352 "Missing or invalid required DPP Status attribute");
4355 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4356 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4357 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4358 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4359 attr_len
, wrapped_data
,
4360 wrapped_data_len
, status
[0]);
4362 if (status
[0] != DPP_STATUS_OK
) {
4363 dpp_auth_fail(auth
, "Authentication failed");
4368 len
[0] = DPP_HDR_LEN
;
4369 addr
[1] = attr_start
;
4371 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4372 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4373 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4374 wrapped_data
, wrapped_data_len
);
4375 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4376 unwrapped
= os_malloc(unwrapped_len
);
4379 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4380 wrapped_data
, wrapped_data_len
,
4381 2, addr
, len
, unwrapped
) < 0) {
4382 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4385 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4386 unwrapped
, unwrapped_len
);
4388 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4389 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4393 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4395 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4397 "Missing or invalid Initiator Authenticating Tag");
4400 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4401 i_auth
, i_auth_len
);
4402 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4403 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4405 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4406 i_auth2
, i_auth_len
);
4407 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4408 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4412 bin_clear_free(unwrapped
, unwrapped_len
);
4413 dpp_auth_success(auth
);
4416 bin_clear_free(unwrapped
, unwrapped_len
);
4421 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4423 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4427 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4429 struct dpp_configuration
*conf
;
4433 conf
= os_zalloc(sizeof(*conf
));
4437 end
= os_strchr(type
, ' ');
4441 len
= os_strlen(type
);
4443 if (bin_str_eq(type
, len
, "psk"))
4444 conf
->akm
= DPP_AKM_PSK
;
4445 else if (bin_str_eq(type
, len
, "sae"))
4446 conf
->akm
= DPP_AKM_SAE
;
4447 else if (bin_str_eq(type
, len
, "psk-sae") ||
4448 bin_str_eq(type
, len
, "psk+sae"))
4449 conf
->akm
= DPP_AKM_PSK_SAE
;
4450 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4451 bin_str_eq(type
, len
, "dpp+sae"))
4452 conf
->akm
= DPP_AKM_SAE_DPP
;
4453 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4454 bin_str_eq(type
, len
, "dpp+psk+sae"))
4455 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4456 else if (bin_str_eq(type
, len
, "dpp"))
4457 conf
->akm
= DPP_AKM_DPP
;
4463 dpp_configuration_free(conf
);
4468 int dpp_akm_psk(enum dpp_akm akm
)
4470 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4471 akm
== DPP_AKM_PSK_SAE_DPP
;
4475 int dpp_akm_sae(enum dpp_akm akm
)
4477 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4478 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4482 int dpp_akm_legacy(enum dpp_akm akm
)
4484 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4489 int dpp_akm_dpp(enum dpp_akm akm
)
4491 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4492 akm
== DPP_AKM_PSK_SAE_DPP
;
4496 int dpp_akm_ver2(enum dpp_akm akm
)
4498 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4502 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4504 if (conf
->ssid_len
== 0)
4506 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4508 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4514 void dpp_configuration_free(struct dpp_configuration
*conf
)
4518 str_clear_free(conf
->passphrase
);
4519 os_free(conf
->group_id
);
4520 bin_clear_free(conf
, sizeof(*conf
));
4524 static int dpp_configuration_parse_helper(struct dpp_authentication
*auth
,
4525 const char *cmd
, int idx
)
4527 const char *pos
, *end
;
4528 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4529 struct dpp_configuration
*conf
= NULL
;
4531 pos
= os_strstr(cmd
, " conf=sta-");
4533 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4536 conf_sta
->netrole
= DPP_NETROLE_STA
;
4540 pos
= os_strstr(cmd
, " conf=ap-");
4542 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4545 conf_ap
->netrole
= DPP_NETROLE_AP
;
4549 pos
= os_strstr(cmd
, " conf=configurator");
4551 auth
->provision_configurator
= 1;
4556 pos
= os_strstr(cmd
, " ssid=");
4559 end
= os_strchr(pos
, ' ');
4560 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4561 conf
->ssid_len
/= 2;
4562 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4563 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4566 #ifdef CONFIG_TESTING_OPTIONS
4567 /* use a default SSID for legacy testing reasons */
4568 os_memcpy(conf
->ssid
, "test", 4);
4570 #else /* CONFIG_TESTING_OPTIONS */
4572 #endif /* CONFIG_TESTING_OPTIONS */
4575 pos
= os_strstr(cmd
, " ssid_charset=");
4578 wpa_printf(MSG_INFO
,
4579 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
4582 conf
->ssid_charset
= atoi(pos
+ 14);
4585 pos
= os_strstr(cmd
, " pass=");
4590 end
= os_strchr(pos
, ' ');
4591 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4593 if (pass_len
> 63 || pass_len
< 8)
4595 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4596 if (!conf
->passphrase
||
4597 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4601 pos
= os_strstr(cmd
, " psk=");
4604 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4609 pos
= os_strstr(cmd
, " group_id=");
4611 size_t group_id_len
;
4614 end
= os_strchr(pos
, ' ');
4615 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4616 conf
->group_id
= os_malloc(group_id_len
+ 1);
4617 if (!conf
->group_id
)
4619 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4620 conf
->group_id
[group_id_len
] = '\0';
4623 pos
= os_strstr(cmd
, " expiry=");
4628 val
= strtol(pos
, NULL
, 0);
4631 conf
->netaccesskey_expiry
= val
;
4634 if (!dpp_configuration_valid(conf
))
4638 auth
->conf_sta
= conf_sta
;
4639 auth
->conf_ap
= conf_ap
;
4640 } else if (idx
== 1) {
4641 auth
->conf2_sta
= conf_sta
;
4642 auth
->conf2_ap
= conf_ap
;
4649 dpp_configuration_free(conf_sta
);
4650 dpp_configuration_free(conf_ap
);
4655 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4663 pos
= os_strstr(cmd
, " @CONF-OBJ-SEP@ ");
4665 return dpp_configuration_parse_helper(auth
, cmd
, 0);
4668 tmp
= os_malloc(len
+ 1);
4671 os_memcpy(tmp
, cmd
, len
);
4673 res
= dpp_configuration_parse_helper(auth
, cmd
, 0);
4674 str_clear_free(tmp
);
4677 res
= dpp_configuration_parse_helper(auth
, cmd
+ len
, 1);
4682 dpp_configuration_free(auth
->conf_sta
);
4683 dpp_configuration_free(auth
->conf2_sta
);
4684 dpp_configuration_free(auth
->conf_ap
);
4685 dpp_configuration_free(auth
->conf2_ap
);
4690 static struct dpp_configurator
*
4691 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4693 struct dpp_configurator
*conf
;
4698 dl_list_for_each(conf
, &dpp
->configurator
,
4699 struct dpp_configurator
, list
) {
4707 int dpp_set_configurator(struct dpp_authentication
*auth
, const char *cmd
)
4713 if (!cmd
|| auth
->configurator_set
)
4715 auth
->configurator_set
= 1;
4717 if (cmd
[0] != ' ') {
4720 len
= os_strlen(cmd
);
4721 tmp
= os_malloc(len
+ 2);
4725 os_memcpy(tmp
+ 1, cmd
, len
+ 1);
4729 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4731 pos
= os_strstr(cmd
, " configurator=");
4734 auth
->conf
= dpp_configurator_get_id(auth
->global
, atoi(pos
));
4736 wpa_printf(MSG_INFO
,
4737 "DPP: Could not find the specified configurator");
4742 pos
= os_strstr(cmd
, " conn_status=");
4745 auth
->send_conn_status
= atoi(pos
);
4748 pos
= os_strstr(cmd
, " akm_use_selector=");
4751 auth
->akm_use_selector
= atoi(pos
);
4754 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4755 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
4756 "DPP: Failed to set configurator parameters");
4766 static void dpp_free_asymmetric_key(struct dpp_asymmetric_key
*key
)
4769 struct dpp_asymmetric_key
*next
= key
->next
;
4771 EVP_PKEY_free(key
->csign
);
4772 str_clear_free(key
->config_template
);
4773 str_clear_free(key
->connector_template
);
4780 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4786 dpp_configuration_free(auth
->conf_ap
);
4787 dpp_configuration_free(auth
->conf2_ap
);
4788 dpp_configuration_free(auth
->conf_sta
);
4789 dpp_configuration_free(auth
->conf2_sta
);
4790 EVP_PKEY_free(auth
->own_protocol_key
);
4791 EVP_PKEY_free(auth
->peer_protocol_key
);
4792 wpabuf_free(auth
->req_msg
);
4793 wpabuf_free(auth
->resp_msg
);
4794 wpabuf_free(auth
->conf_req
);
4795 for (i
= 0; i
< auth
->num_conf_obj
; i
++) {
4796 struct dpp_config_obj
*conf
= &auth
->conf_obj
[i
];
4798 os_free(conf
->connector
);
4799 wpabuf_free(conf
->c_sign_key
);
4801 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
4802 wpabuf_free(auth
->net_access_key
);
4803 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4804 #ifdef CONFIG_TESTING_OPTIONS
4805 os_free(auth
->config_obj_override
);
4806 os_free(auth
->discovery_override
);
4807 os_free(auth
->groups_override
);
4808 #endif /* CONFIG_TESTING_OPTIONS */
4809 bin_clear_free(auth
, sizeof(*auth
));
4813 static struct wpabuf
*
4814 dpp_build_conf_start(struct dpp_authentication
*auth
,
4815 struct dpp_configuration
*conf
, size_t tailroom
)
4819 #ifdef CONFIG_TESTING_OPTIONS
4820 if (auth
->discovery_override
)
4821 tailroom
+= os_strlen(auth
->discovery_override
);
4822 #endif /* CONFIG_TESTING_OPTIONS */
4824 buf
= wpabuf_alloc(200 + tailroom
);
4827 json_start_object(buf
, NULL
);
4828 json_add_string(buf
, "wi-fi_tech", "infra");
4829 json_value_sep(buf
);
4830 #ifdef CONFIG_TESTING_OPTIONS
4831 if (auth
->discovery_override
) {
4832 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4833 auth
->discovery_override
);
4834 wpabuf_put_str(buf
, "\"discovery\":");
4835 wpabuf_put_str(buf
, auth
->discovery_override
);
4836 json_value_sep(buf
);
4839 #endif /* CONFIG_TESTING_OPTIONS */
4840 json_start_object(buf
, "discovery");
4841 if (((!conf
->ssid_charset
|| auth
->peer_version
< 2) &&
4842 json_add_string_escape(buf
, "ssid", conf
->ssid
,
4843 conf
->ssid_len
) < 0) ||
4844 ((conf
->ssid_charset
&& auth
->peer_version
>= 2) &&
4845 json_add_base64url(buf
, "ssid64", conf
->ssid
,
4846 conf
->ssid_len
) < 0)) {
4850 if (conf
->ssid_charset
> 0) {
4851 json_value_sep(buf
);
4852 json_add_int(buf
, "ssid_charset", conf
->ssid_charset
);
4854 json_end_object(buf
);
4855 json_value_sep(buf
);
4861 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4862 const char *kid
, const struct dpp_curve_params
*curve
)
4868 pub
= dpp_get_pubkey_point(key
, 0);
4872 json_start_object(buf
, name
);
4873 json_add_string(buf
, "kty", "EC");
4874 json_value_sep(buf
);
4875 json_add_string(buf
, "crv", curve
->jwk_crv
);
4876 json_value_sep(buf
);
4877 pos
= wpabuf_head(pub
);
4878 if (json_add_base64url(buf
, "x", pos
, curve
->prime_len
) < 0)
4880 json_value_sep(buf
);
4881 pos
+= curve
->prime_len
;
4882 if (json_add_base64url(buf
, "y", pos
, curve
->prime_len
) < 0)
4885 json_value_sep(buf
);
4886 json_add_string(buf
, "kid", kid
);
4888 json_end_object(buf
);
4896 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4897 struct dpp_configuration
*conf
)
4899 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4900 json_add_string_escape(buf
, "pass", conf
->passphrase
,
4901 os_strlen(conf
->passphrase
));
4902 } else if (conf
->psk_set
) {
4903 char psk
[2 * sizeof(conf
->psk
) + 1];
4905 wpa_snprintf_hex(psk
, sizeof(psk
),
4906 conf
->psk
, sizeof(conf
->psk
));
4907 json_add_string(buf
, "psk_hex", psk
);
4908 forced_memzero(psk
, sizeof(psk
));
4913 static const char * dpp_netrole_str(enum dpp_netrole netrole
)
4916 case DPP_NETROLE_STA
:
4918 case DPP_NETROLE_AP
:
4920 case DPP_NETROLE_CONFIGURATOR
:
4921 return "configurator";
4928 static struct wpabuf
*
4929 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
,
4930 struct dpp_configuration
*conf
)
4932 struct wpabuf
*buf
= NULL
;
4933 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4935 const struct dpp_curve_params
*curve
;
4936 struct wpabuf
*jws_prot_hdr
;
4937 size_t signed1_len
, signed2_len
, signed3_len
;
4938 struct wpabuf
*dppcon
= NULL
;
4939 unsigned char *signature
= NULL
;
4940 const unsigned char *p
;
4941 size_t signature_len
;
4942 EVP_MD_CTX
*md_ctx
= NULL
;
4943 ECDSA_SIG
*sig
= NULL
;
4945 const EVP_MD
*sign_md
;
4946 const BIGNUM
*r
, *s
;
4947 size_t extra_len
= 1000;
4950 const char *akm_str
;
4953 wpa_printf(MSG_INFO
,
4954 "DPP: No configurator specified - cannot generate DPP config object");
4957 curve
= auth
->conf
->curve
;
4958 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4959 sign_md
= EVP_sha256();
4960 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4961 sign_md
= EVP_sha384();
4962 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4963 sign_md
= EVP_sha512();
4965 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4970 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4971 wpa_printf(MSG_DEBUG
,
4972 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4976 #ifdef CONFIG_TESTING_OPTIONS
4977 if (auth
->groups_override
)
4978 extra_len
+= os_strlen(auth
->groups_override
);
4979 #endif /* CONFIG_TESTING_OPTIONS */
4982 extra_len
+= os_strlen(conf
->group_id
);
4984 /* Connector (JSON dppCon object) */
4985 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4988 #ifdef CONFIG_TESTING_OPTIONS
4989 if (auth
->groups_override
) {
4990 wpabuf_put_u8(dppcon
, '{');
4991 if (auth
->groups_override
) {
4992 wpa_printf(MSG_DEBUG
,
4993 "DPP: TESTING - groups override: '%s'",
4994 auth
->groups_override
);
4995 wpabuf_put_str(dppcon
, "\"groups\":");
4996 wpabuf_put_str(dppcon
, auth
->groups_override
);
4997 json_value_sep(dppcon
);
5001 #endif /* CONFIG_TESTING_OPTIONS */
5002 json_start_object(dppcon
, NULL
);
5003 json_start_array(dppcon
, "groups");
5004 json_start_object(dppcon
, NULL
);
5005 json_add_string(dppcon
, "groupId",
5006 conf
->group_id
? conf
->group_id
: "*");
5007 json_value_sep(dppcon
);
5008 json_add_string(dppcon
, "netRole", dpp_netrole_str(conf
->netrole
));
5009 json_end_object(dppcon
);
5010 json_end_array(dppcon
);
5011 json_value_sep(dppcon
);
5012 #ifdef CONFIG_TESTING_OPTIONS
5014 #endif /* CONFIG_TESTING_OPTIONS */
5015 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
5017 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
5020 if (conf
->netaccesskey_expiry
) {
5024 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
5025 wpa_printf(MSG_DEBUG
,
5026 "DPP: Failed to generate expiry string");
5029 os_snprintf(expiry
, sizeof(expiry
),
5030 "%04u-%02u-%02uT%02u:%02u:%02uZ",
5031 tm
.year
, tm
.month
, tm
.day
,
5032 tm
.hour
, tm
.min
, tm
.sec
);
5033 json_value_sep(dppcon
);
5034 json_add_string(dppcon
, "expiry", expiry
);
5036 json_end_object(dppcon
);
5037 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
5038 (const char *) wpabuf_head(dppcon
));
5040 jws_prot_hdr
= wpabuf_alloc(100);
5043 json_start_object(jws_prot_hdr
, NULL
);
5044 json_add_string(jws_prot_hdr
, "typ", "dppCon");
5045 json_value_sep(jws_prot_hdr
);
5046 json_add_string(jws_prot_hdr
, "kid", auth
->conf
->kid
);
5047 json_value_sep(jws_prot_hdr
);
5048 json_add_string(jws_prot_hdr
, "alg", curve
->jws_alg
);
5049 json_end_object(jws_prot_hdr
);
5050 signed1
= base64_url_encode(wpabuf_head(jws_prot_hdr
),
5051 wpabuf_len(jws_prot_hdr
),
5053 wpabuf_free(jws_prot_hdr
);
5054 signed2
= base64_url_encode(wpabuf_head(dppcon
), wpabuf_len(dppcon
),
5056 if (!signed1
|| !signed2
)
5059 md_ctx
= EVP_MD_CTX_create();
5064 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
5065 auth
->conf
->csign
) != 1) {
5066 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
5067 ERR_error_string(ERR_get_error(), NULL
));
5070 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
5071 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
5072 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
5073 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
5074 ERR_error_string(ERR_get_error(), NULL
));
5077 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
5078 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5079 ERR_error_string(ERR_get_error(), NULL
));
5082 signature
= os_malloc(signature_len
);
5085 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
5086 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5087 ERR_error_string(ERR_get_error(), NULL
));
5090 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
5091 signature
, signature_len
);
5092 /* Convert to raw coordinates r,s */
5094 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
5097 ECDSA_SIG_get0(sig
, &r
, &s
);
5098 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
5099 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
5100 curve
->prime_len
) < 0)
5102 signature_len
= 2 * curve
->prime_len
;
5103 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
5104 signature
, signature_len
);
5105 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
5109 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
5111 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
5112 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
5115 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
5119 if (auth
->akm_use_selector
&& dpp_akm_ver2(akm
))
5120 akm_str
= dpp_akm_selector_str(akm
);
5122 akm_str
= dpp_akm_str(akm
);
5123 json_start_object(buf
, "cred");
5124 json_add_string(buf
, "akm", akm_str
);
5125 json_value_sep(buf
);
5127 dpp_build_legacy_cred_params(buf
, conf
);
5128 json_value_sep(buf
);
5130 wpabuf_put_str(buf
, "\"signedConnector\":\"");
5131 wpabuf_put_str(buf
, signed1
);
5132 wpabuf_put_u8(buf
, '.');
5133 wpabuf_put_str(buf
, signed2
);
5134 wpabuf_put_u8(buf
, '.');
5135 wpabuf_put_str(buf
, signed3
);
5136 wpabuf_put_str(buf
, "\"");
5137 json_value_sep(buf
);
5138 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
5140 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
5144 json_end_object(buf
);
5145 json_end_object(buf
);
5147 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
5148 wpabuf_head(buf
), wpabuf_len(buf
));
5151 EVP_MD_CTX_destroy(md_ctx
);
5152 ECDSA_SIG_free(sig
);
5157 wpabuf_free(dppcon
);
5160 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
5167 static struct wpabuf
*
5168 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
,
5169 struct dpp_configuration
*conf
)
5172 const char *akm_str
;
5174 buf
= dpp_build_conf_start(auth
, conf
, 1000);
5178 if (auth
->akm_use_selector
&& dpp_akm_ver2(conf
->akm
))
5179 akm_str
= dpp_akm_selector_str(conf
->akm
);
5181 akm_str
= dpp_akm_str(conf
->akm
);
5182 json_start_object(buf
, "cred");
5183 json_add_string(buf
, "akm", akm_str
);
5184 json_value_sep(buf
);
5185 dpp_build_legacy_cred_params(buf
, conf
);
5186 json_end_object(buf
);
5187 json_end_object(buf
);
5189 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
5190 wpabuf_head(buf
), wpabuf_len(buf
));
5196 static struct wpabuf
*
5197 dpp_build_conf_obj(struct dpp_authentication
*auth
, enum dpp_netrole netrole
,
5200 struct dpp_configuration
*conf
= NULL
;
5202 #ifdef CONFIG_TESTING_OPTIONS
5203 if (auth
->config_obj_override
) {
5206 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
5207 return wpabuf_alloc_copy(auth
->config_obj_override
,
5208 os_strlen(auth
->config_obj_override
));
5210 #endif /* CONFIG_TESTING_OPTIONS */
5213 if (netrole
== DPP_NETROLE_STA
)
5214 conf
= auth
->conf_sta
;
5215 else if (netrole
== DPP_NETROLE_AP
)
5216 conf
= auth
->conf_ap
;
5217 } else if (idx
== 1) {
5218 if (netrole
== DPP_NETROLE_STA
)
5219 conf
= auth
->conf2_sta
;
5220 else if (netrole
== DPP_NETROLE_AP
)
5221 conf
= auth
->conf2_ap
;
5225 wpa_printf(MSG_DEBUG
,
5226 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
5227 dpp_netrole_str(netrole
));
5231 if (dpp_akm_dpp(conf
->akm
))
5232 return dpp_build_conf_obj_dpp(auth
, conf
);
5233 return dpp_build_conf_obj_legacy(auth
, conf
);
5239 static struct wpabuf
* dpp_build_conf_params(void)
5243 /* TODO: proper template values */
5244 const char *conf_template
= "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
5245 const char *connector_template
= NULL
;
5247 len
= 100 + os_strlen(conf_template
);
5248 if (connector_template
)
5249 len
+= os_strlen(connector_template
);
5250 buf
= wpabuf_alloc(len
);
5255 * DPPConfigurationParameters ::= SEQUENCE {
5256 * configurationTemplate UTF8String,
5257 * connectorTemplate UTF8String OPTIONAL}
5260 asn1_put_utf8string(buf
, conf_template
);
5261 if (connector_template
)
5262 asn1_put_utf8string(buf
, connector_template
);
5263 return asn1_encaps(buf
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5267 static struct wpabuf
* dpp_build_attribute(void)
5269 struct wpabuf
*conf_params
, *attr
;
5272 * aa-DPPConfigurationParameters ATTRIBUTE ::=
5273 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
5275 * Attribute ::= SEQUENCE {
5276 * type OBJECT IDENTIFIER,
5277 * values SET SIZE(1..MAX) OF Type
5279 conf_params
= dpp_build_conf_params();
5280 conf_params
= asn1_encaps(conf_params
, ASN1_CLASS_UNIVERSAL
,
5285 attr
= wpabuf_alloc(100 + wpabuf_len(conf_params
));
5287 wpabuf_clear_free(conf_params
);
5291 asn1_put_oid(attr
, &asn1_dpp_config_params_oid
);
5292 wpabuf_put_buf(attr
, conf_params
);
5293 wpabuf_clear_free(conf_params
);
5295 return asn1_encaps(attr
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5299 static struct wpabuf
* dpp_build_key_alg(const struct dpp_curve_params
*curve
)
5301 const struct asn1_oid
*oid
;
5302 struct wpabuf
*params
, *res
;
5304 switch (curve
->ike_group
) {
5306 oid
= &asn1_prime256v1_oid
;
5309 oid
= &asn1_secp384r1_oid
;
5312 oid
= &asn1_secp521r1_oid
;
5315 oid
= &asn1_brainpoolP256r1_oid
;
5318 oid
= &asn1_brainpoolP384r1_oid
;
5321 oid
= &asn1_brainpoolP512r1_oid
;
5327 params
= wpabuf_alloc(20);
5330 asn1_put_oid(params
, oid
); /* namedCurve */
5332 res
= asn1_build_alg_id(&asn1_ec_public_key_oid
, params
);
5333 wpabuf_free(params
);
5338 static struct wpabuf
* dpp_build_key_pkg(struct dpp_authentication
*auth
)
5340 struct wpabuf
*key
= NULL
, *attr
, *alg
, *priv_key
= NULL
;
5342 unsigned char *der
= NULL
;
5345 eckey
= EVP_PKEY_get0_EC_KEY(auth
->conf
->csign
);
5349 EC_KEY_set_enc_flags(eckey
, EC_PKEY_NO_PUBKEY
);
5350 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5352 priv_key
= wpabuf_alloc_copy(der
, der_len
);
5355 alg
= dpp_build_key_alg(auth
->conf
->curve
);
5357 /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
5358 attr
= dpp_build_attribute();
5359 attr
= asn1_encaps(attr
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SET
);
5360 if (!priv_key
|| !attr
|| !alg
)
5364 * OneAsymmetricKey ::= SEQUENCE {
5366 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
5367 * privateKey PrivateKey,
5368 * attributes [0] Attributes OPTIONAL,
5370 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
5375 key
= wpabuf_alloc(100 + wpabuf_len(alg
) + wpabuf_len(priv_key
) +
5380 asn1_put_integer(key
, 1); /* version = v2(1) */
5382 /* PrivateKeyAlgorithmIdentifier */
5383 wpabuf_put_buf(key
, alg
);
5385 /* PrivateKey ::= OCTET STRING */
5386 asn1_put_octet_string(key
, priv_key
);
5388 /* [0] Attributes OPTIONAL */
5389 asn1_put_hdr(key
, ASN1_CLASS_CONTEXT_SPECIFIC
, 1, 0, wpabuf_len(attr
));
5390 wpabuf_put_buf(key
, attr
);
5393 wpabuf_clear_free(attr
);
5394 wpabuf_clear_free(priv_key
);
5398 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
5400 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
5402 * OneAsymmetricKey ::= SEQUENCE
5404 return asn1_encaps(asn1_encaps(key
,
5405 ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
),
5406 ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5410 static struct wpabuf
* dpp_build_pbkdf2_alg_id(const struct wpabuf
*salt
,
5413 struct wpabuf
*params
= NULL
, *buf
= NULL
, *prf
= NULL
;
5414 const struct asn1_oid
*oid
;
5417 * PBKDF2-params ::= SEQUENCE {
5419 * specified OCTET STRING,
5420 * otherSource AlgorithmIdentifier}
5421 * iterationCount INTEGER (1..MAX),
5422 * keyLength INTEGER (1..MAX),
5423 * prf AlgorithmIdentifier}
5425 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
5426 * on Configurator signing key length, prf is
5427 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
5431 oid
= &asn1_pbkdf2_hmac_sha256_oid
;
5432 else if (hash_len
== 48)
5433 oid
= &asn1_pbkdf2_hmac_sha384_oid
;
5434 else if (hash_len
== 64)
5435 oid
= &asn1_pbkdf2_hmac_sha512_oid
;
5438 prf
= asn1_build_alg_id(oid
, NULL
);
5441 params
= wpabuf_alloc(100 + wpabuf_len(salt
) + wpabuf_len(prf
));
5444 asn1_put_octet_string(params
, salt
); /* salt.specified */
5445 asn1_put_integer(params
, 1000); /* iterationCount */
5446 asn1_put_integer(params
, hash_len
); /* keyLength */
5447 wpabuf_put_buf(params
, prf
);
5448 params
= asn1_encaps(params
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5451 buf
= asn1_build_alg_id(&asn1_pbkdf2_oid
, params
);
5453 wpabuf_free(params
);
5459 static struct wpabuf
*
5460 dpp_build_pw_recipient_info(struct dpp_authentication
*auth
, size_t hash_len
,
5461 const struct wpabuf
*cont_enc_key
)
5463 struct wpabuf
*pwri
= NULL
, *enc_key
= NULL
, *key_der_alg
= NULL
,
5464 *key_enc_alg
= NULL
, *salt
;
5465 u8 kek
[DPP_MAX_HASH_LEN
];
5469 salt
= wpabuf_alloc(64);
5470 if (!salt
|| os_get_random(wpabuf_put(salt
, 64), 64) < 0)
5472 wpa_hexdump_buf(MSG_DEBUG
, "DPP: PBKDF2 salt", salt
);
5474 /* TODO: For initial testing, use ke as the key. Replace this with a
5475 * new key once that has been defined. */
5477 key_len
= auth
->curve
->hash_len
;
5478 wpa_hexdump_key(MSG_DEBUG
, "DPP: PBKDF2 key", key
, key_len
);
5480 if (dpp_pbkdf2(hash_len
, key
, key_len
, wpabuf_head(salt
), 64, 1000,
5482 wpa_printf(MSG_DEBUG
, "DPP: PBKDF2 failed");
5485 wpa_hexdump_key(MSG_DEBUG
, "DPP: key-encryption key from PBKDF2",
5488 enc_key
= wpabuf_alloc(hash_len
+ AES_BLOCK_SIZE
);
5490 aes_siv_encrypt(kek
, hash_len
, wpabuf_head(cont_enc_key
),
5491 wpabuf_len(cont_enc_key
), 0, NULL
, NULL
,
5492 wpabuf_put(enc_key
, hash_len
+ AES_BLOCK_SIZE
)) < 0)
5494 wpa_hexdump_buf(MSG_DEBUG
, "DPP: encryptedKey", enc_key
);
5497 * PasswordRecipientInfo ::= SEQUENCE {
5498 * version CMSVersion,
5499 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
5500 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
5501 * encryptedKey EncryptedKey}
5503 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
5504 * parameters contains PBKDF2-params SEQUENCE.
5507 key_der_alg
= dpp_build_pbkdf2_alg_id(salt
, hash_len
);
5508 key_enc_alg
= asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid
, NULL
);
5509 if (!key_der_alg
|| !key_enc_alg
)
5511 pwri
= wpabuf_alloc(100 + wpabuf_len(key_der_alg
) +
5512 wpabuf_len(key_enc_alg
) + wpabuf_len(enc_key
));
5517 asn1_put_integer(pwri
, 0);
5519 /* [0] KeyDerivationAlgorithmIdentifier */
5520 asn1_put_hdr(pwri
, ASN1_CLASS_CONTEXT_SPECIFIC
, 1, 0,
5521 wpabuf_len(key_der_alg
));
5522 wpabuf_put_buf(pwri
, key_der_alg
);
5524 /* KeyEncryptionAlgorithmIdentifier */
5525 wpabuf_put_buf(pwri
, key_enc_alg
);
5527 /* EncryptedKey ::= OCTET STRING */
5528 asn1_put_octet_string(pwri
, enc_key
);
5531 wpabuf_clear_free(key_der_alg
);
5532 wpabuf_free(key_enc_alg
);
5533 wpabuf_free(enc_key
);
5535 forced_memzero(kek
, sizeof(kek
));
5536 return asn1_encaps(pwri
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5540 static struct wpabuf
*
5541 dpp_build_recipient_info(struct dpp_authentication
*auth
, size_t hash_len
,
5542 const struct wpabuf
*cont_enc_key
)
5544 struct wpabuf
*pwri
;
5547 * RecipientInfo ::= CHOICE {
5548 * ktri KeyTransRecipientInfo,
5549 * kari [1] KeyAgreeRecipientInfo,
5550 * kekri [2] KEKRecipientInfo,
5551 * pwri [3] PasswordRecipientInfo,
5552 * ori [4] OtherRecipientInfo}
5554 * Shall always use the pwri CHOICE.
5557 pwri
= dpp_build_pw_recipient_info(auth
, hash_len
, cont_enc_key
);
5558 return asn1_encaps(pwri
, ASN1_CLASS_CONTEXT_SPECIFIC
, 3);
5562 static struct wpabuf
*
5563 dpp_build_enc_cont_info(struct dpp_authentication
*auth
, size_t hash_len
,
5564 const struct wpabuf
*cont_enc_key
)
5566 struct wpabuf
*key_pkg
, *enc_cont_info
= NULL
, *enc_cont
= NULL
,
5568 const struct asn1_oid
*oid
;
5569 size_t enc_cont_len
;
5572 * EncryptedContentInfo ::= SEQUENCE {
5573 * contentType ContentType,
5574 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
5575 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
5579 oid
= &asn1_aes_siv_cmac_aead_256_oid
;
5580 else if (hash_len
== 48)
5581 oid
= &asn1_aes_siv_cmac_aead_384_oid
;
5582 else if (hash_len
== 64)
5583 oid
= &asn1_aes_siv_cmac_aead_512_oid
;
5587 key_pkg
= dpp_build_key_pkg(auth
);
5588 enc_alg
= asn1_build_alg_id(oid
, NULL
);
5589 if (!key_pkg
|| !enc_alg
)
5592 wpa_hexdump_buf_key(MSG_MSGDUMP
, "DPP: DPPAsymmetricKeyPackage",
5595 enc_cont_len
= wpabuf_len(key_pkg
) + AES_BLOCK_SIZE
;
5596 enc_cont
= wpabuf_alloc(enc_cont_len
);
5598 aes_siv_encrypt(wpabuf_head(cont_enc_key
), wpabuf_len(cont_enc_key
),
5599 wpabuf_head(key_pkg
), wpabuf_len(key_pkg
),
5601 wpabuf_put(enc_cont
, enc_cont_len
)) < 0)
5604 enc_cont_info
= wpabuf_alloc(100 + wpabuf_len(enc_alg
) +
5605 wpabuf_len(enc_cont
));
5609 /* ContentType ::= OBJECT IDENTIFIER */
5610 asn1_put_oid(enc_cont_info
, &asn1_dpp_asymmetric_key_package_oid
);
5612 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
5613 wpabuf_put_buf(enc_cont_info
, enc_alg
);
5615 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
5616 * EncryptedContent ::= OCTET STRING */
5617 asn1_put_hdr(enc_cont_info
, ASN1_CLASS_CONTEXT_SPECIFIC
, 0, 0,
5618 wpabuf_len(enc_cont
));
5619 wpabuf_put_buf(enc_cont_info
, enc_cont
);
5622 wpabuf_clear_free(key_pkg
);
5623 wpabuf_free(enc_cont
);
5624 wpabuf_free(enc_alg
);
5625 return enc_cont_info
;
5629 static struct wpabuf
* dpp_gen_random(size_t len
)
5633 key
= wpabuf_alloc(len
);
5634 if (!key
|| os_get_random(wpabuf_put(key
, len
), len
) < 0) {
5638 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: content-encryption key", key
);
5643 static struct wpabuf
* dpp_build_enveloped_data(struct dpp_authentication
*auth
)
5645 struct wpabuf
*env
= NULL
;
5646 struct wpabuf
*recipient_info
= NULL
, *enc_cont_info
= NULL
;
5647 struct wpabuf
*cont_enc_key
= NULL
;
5651 wpa_printf(MSG_DEBUG
,
5652 "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
5656 if (!auth
->provision_configurator
) {
5657 wpa_printf(MSG_DEBUG
,
5658 "DPP: Configurator provisioning not allowed");
5662 wpa_printf(MSG_DEBUG
, "DPP: Building DPPEnvelopedData");
5664 hash_len
= auth
->conf
->curve
->hash_len
;
5665 cont_enc_key
= dpp_gen_random(hash_len
);
5668 recipient_info
= dpp_build_recipient_info(auth
, hash_len
, cont_enc_key
);
5669 enc_cont_info
= dpp_build_enc_cont_info(auth
, hash_len
, cont_enc_key
);
5670 if (!recipient_info
|| !enc_cont_info
)
5673 env
= wpabuf_alloc(wpabuf_len(recipient_info
) +
5674 wpabuf_len(enc_cont_info
) +
5680 * DPPEnvelopedData ::= EnvelopedData
5682 * EnvelopedData ::= SEQUENCE {
5683 * version CMSVersion,
5684 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
5685 * recipientInfos RecipientInfos,
5686 * encryptedContentInfo EncryptedContentInfo,
5687 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
5689 * For DPP, version is 3, both originatorInfo and
5690 * unprotectedAttrs are omitted, and recipientInfos contains a single
5694 /* EnvelopedData.version = 3 */
5695 asn1_put_integer(env
, 3);
5697 /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
5698 asn1_put_set(env
, recipient_info
);
5700 /* EncryptedContentInfo ::= SEQUENCE */
5701 asn1_put_sequence(env
, enc_cont_info
);
5703 env
= asn1_encaps(env
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5704 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: DPPEnvelopedData", env
);
5706 wpabuf_clear_free(cont_enc_key
);
5707 wpabuf_clear_free(recipient_info
);
5708 wpabuf_free(enc_cont_info
);
5716 #endif /* CONFIG_DPP2 */
5719 static struct wpabuf
*
5720 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
5721 u16 e_nonce_len
, enum dpp_netrole netrole
)
5723 struct wpabuf
*conf
= NULL
, *conf2
= NULL
, *env_data
= NULL
;
5724 size_t clear_len
, attr_len
;
5725 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
5729 enum dpp_status_error status
;
5731 if (netrole
== DPP_NETROLE_CONFIGURATOR
) {
5733 env_data
= dpp_build_enveloped_data(auth
);
5734 #endif /* CONFIG_DPP2 */
5736 conf
= dpp_build_conf_obj(auth
, netrole
, 0);
5738 wpa_hexdump_ascii(MSG_DEBUG
,
5739 "DPP: configurationObject JSON",
5740 wpabuf_head(conf
), wpabuf_len(conf
));
5741 conf2
= dpp_build_conf_obj(auth
, netrole
, 1);
5744 status
= (conf
|| env_data
) ? DPP_STATUS_OK
:
5745 DPP_STATUS_CONFIGURE_FAILURE
;
5746 auth
->conf_resp_status
= status
;
5748 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
5749 clear_len
= 4 + e_nonce_len
;
5751 clear_len
+= 4 + wpabuf_len(conf
);
5753 clear_len
+= 4 + wpabuf_len(conf2
);
5755 clear_len
+= 4 + wpabuf_len(env_data
);
5756 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5757 netrole
== DPP_NETROLE_STA
)
5759 clear
= wpabuf_alloc(clear_len
);
5760 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
5761 #ifdef CONFIG_TESTING_OPTIONS
5762 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
5764 #endif /* CONFIG_TESTING_OPTIONS */
5765 msg
= wpabuf_alloc(attr_len
);
5769 #ifdef CONFIG_TESTING_OPTIONS
5770 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
5771 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
5774 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
5775 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
5776 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5777 wpabuf_put_le16(clear
, e_nonce_len
);
5778 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
5779 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
5782 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
5783 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
5784 goto skip_wrapped_data
;
5786 #endif /* CONFIG_TESTING_OPTIONS */
5789 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5790 wpabuf_put_le16(clear
, e_nonce_len
);
5791 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
5793 #ifdef CONFIG_TESTING_OPTIONS
5795 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
5796 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
5797 goto skip_config_obj
;
5799 #endif /* CONFIG_TESTING_OPTIONS */
5802 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5803 wpabuf_put_le16(clear
, wpabuf_len(conf
));
5804 wpabuf_put_buf(clear
, conf
);
5806 if (auth
->peer_version
>= 2 && conf2
) {
5807 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5808 wpabuf_put_le16(clear
, wpabuf_len(conf2
));
5809 wpabuf_put_buf(clear
, conf2
);
5811 wpa_printf(MSG_DEBUG
,
5812 "DPP: Second Config Object available, but peer does not support more than one");
5815 wpabuf_put_le16(clear
, DPP_ATTR_ENVELOPED_DATA
);
5816 wpabuf_put_le16(clear
, wpabuf_len(env_data
));
5817 wpabuf_put_buf(clear
, env_data
);
5820 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5821 netrole
== DPP_NETROLE_STA
) {
5822 wpa_printf(MSG_DEBUG
, "DPP: sendConnStatus");
5823 wpabuf_put_le16(clear
, DPP_ATTR_SEND_CONN_STATUS
);
5824 wpabuf_put_le16(clear
, 0);
5827 #ifdef CONFIG_TESTING_OPTIONS
5829 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
5830 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
5833 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
5834 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
5837 #endif /* CONFIG_TESTING_OPTIONS */
5840 dpp_build_attr_status(msg
, status
);
5842 #ifdef CONFIG_TESTING_OPTIONS
5844 #endif /* CONFIG_TESTING_OPTIONS */
5846 addr
[0] = wpabuf_head(msg
);
5847 len
[0] = wpabuf_len(msg
);
5848 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5850 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5851 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5852 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5854 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5855 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
5856 wpabuf_head(clear
), wpabuf_len(clear
),
5857 1, addr
, len
, wrapped
) < 0)
5859 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5860 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5862 #ifdef CONFIG_TESTING_OPTIONS
5863 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
5864 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
5865 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
5868 #endif /* CONFIG_TESTING_OPTIONS */
5870 wpa_hexdump_buf(MSG_DEBUG
,
5871 "DPP: Configuration Response attributes", msg
);
5873 wpabuf_clear_free(conf
);
5874 wpabuf_clear_free(conf2
);
5875 wpabuf_clear_free(env_data
);
5876 wpabuf_clear_free(clear
);
5887 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
5890 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
5891 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
5892 u8
*unwrapped
= NULL
;
5893 size_t unwrapped_len
= 0;
5894 struct wpabuf
*resp
= NULL
;
5895 struct json_token
*root
= NULL
, *token
;
5896 enum dpp_netrole netrole
;
5898 #ifdef CONFIG_TESTING_OPTIONS
5899 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
5900 wpa_printf(MSG_INFO
,
5901 "DPP: TESTING - stop at Config Request");
5904 #endif /* CONFIG_TESTING_OPTIONS */
5906 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
5907 dpp_auth_fail(auth
, "Invalid attribute in config request");
5911 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5913 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5915 "Missing or invalid required Wrapped Data attribute");
5919 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5920 wrapped_data
, wrapped_data_len
);
5921 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5922 unwrapped
= os_malloc(unwrapped_len
);
5925 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5926 wrapped_data
, wrapped_data_len
,
5927 0, NULL
, NULL
, unwrapped
) < 0) {
5928 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5931 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5932 unwrapped
, unwrapped_len
);
5934 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5935 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5939 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5940 DPP_ATTR_ENROLLEE_NONCE
,
5942 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5944 "Missing or invalid Enrollee Nonce attribute");
5947 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5948 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
5950 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5951 DPP_ATTR_CONFIG_ATTR_OBJ
,
5955 "Missing or invalid Config Attributes attribute");
5958 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5959 config_attr
, config_attr_len
);
5961 root
= json_parse((const char *) config_attr
, config_attr_len
);
5963 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5967 token
= json_get_member(root
, "name");
5968 if (!token
|| token
->type
!= JSON_STRING
) {
5969 dpp_auth_fail(auth
, "No Config Attributes - name");
5972 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5974 token
= json_get_member(root
, "wi-fi_tech");
5975 if (!token
|| token
->type
!= JSON_STRING
) {
5976 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5979 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5980 if (os_strcmp(token
->string
, "infra") != 0) {
5981 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5983 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5987 token
= json_get_member(root
, "netRole");
5988 if (!token
|| token
->type
!= JSON_STRING
) {
5989 dpp_auth_fail(auth
, "No Config Attributes - netRole");
5992 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
5993 if (os_strcmp(token
->string
, "sta") == 0) {
5994 netrole
= DPP_NETROLE_STA
;
5995 } else if (os_strcmp(token
->string
, "ap") == 0) {
5996 netrole
= DPP_NETROLE_AP
;
5997 } else if (os_strcmp(token
->string
, "configurator") == 0) {
5998 netrole
= DPP_NETROLE_CONFIGURATOR
;
6000 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
6002 dpp_auth_fail(auth
, "Unsupported netRole");
6006 token
= json_get_member(root
, "mudurl");
6007 if (token
&& token
->type
== JSON_STRING
)
6008 wpa_printf(MSG_DEBUG
, "DPP: mudurl = '%s'", token
->string
);
6010 token
= json_get_member(root
, "bandSupport");
6011 if (token
&& token
->type
== JSON_ARRAY
) {
6012 wpa_printf(MSG_DEBUG
, "DPP: bandSupport");
6013 token
= token
->child
;
6015 if (token
->type
!= JSON_NUMBER
)
6016 wpa_printf(MSG_DEBUG
,
6017 "DPP: Invalid bandSupport array member type");
6019 wpa_printf(MSG_DEBUG
,
6020 "DPP: Supported global operating class: %d",
6022 token
= token
->sibling
;
6026 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, netrole
);
6035 static struct wpabuf
*
6036 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
6037 const u8
*prot_hdr
, u16 prot_hdr_len
,
6038 const EVP_MD
**ret_md
)
6040 struct json_token
*root
, *token
;
6041 struct wpabuf
*kid
= NULL
;
6043 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
6045 wpa_printf(MSG_DEBUG
,
6046 "DPP: JSON parsing failed for JWS Protected Header");
6050 if (root
->type
!= JSON_OBJECT
) {
6051 wpa_printf(MSG_DEBUG
,
6052 "DPP: JWS Protected Header root is not an object");
6056 token
= json_get_member(root
, "typ");
6057 if (!token
|| token
->type
!= JSON_STRING
) {
6058 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
6061 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
6063 if (os_strcmp(token
->string
, "dppCon") != 0) {
6064 wpa_printf(MSG_DEBUG
,
6065 "DPP: Unsupported JWS Protected Header typ=%s",
6070 token
= json_get_member(root
, "alg");
6071 if (!token
|| token
->type
!= JSON_STRING
) {
6072 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
6075 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
6077 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
6078 wpa_printf(MSG_DEBUG
,
6079 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
6080 token
->string
, curve
->jws_alg
);
6083 if (os_strcmp(token
->string
, "ES256") == 0 ||
6084 os_strcmp(token
->string
, "BS256") == 0)
6085 *ret_md
= EVP_sha256();
6086 else if (os_strcmp(token
->string
, "ES384") == 0 ||
6087 os_strcmp(token
->string
, "BS384") == 0)
6088 *ret_md
= EVP_sha384();
6089 else if (os_strcmp(token
->string
, "ES512") == 0 ||
6090 os_strcmp(token
->string
, "BS512") == 0)
6091 *ret_md
= EVP_sha512();
6095 wpa_printf(MSG_DEBUG
,
6096 "DPP: Unsupported JWS Protected Header alg=%s",
6101 kid
= json_get_member_base64url(root
, "kid");
6103 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
6106 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
6115 static int dpp_parse_cred_legacy(struct dpp_config_obj
*conf
,
6116 struct json_token
*cred
)
6118 struct json_token
*pass
, *psk_hex
;
6120 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
6122 pass
= json_get_member(cred
, "pass");
6123 psk_hex
= json_get_member(cred
, "psk_hex");
6125 if (pass
&& pass
->type
== JSON_STRING
) {
6126 size_t len
= os_strlen(pass
->string
);
6128 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
6130 if (len
< 8 || len
> 63)
6132 os_strlcpy(conf
->passphrase
, pass
->string
,
6133 sizeof(conf
->passphrase
));
6134 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
6135 if (dpp_akm_sae(conf
->akm
) && !dpp_akm_psk(conf
->akm
)) {
6136 wpa_printf(MSG_DEBUG
,
6137 "DPP: Unexpected psk_hex with akm=sae");
6140 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
6141 hexstr2bin(psk_hex
->string
, conf
->psk
, PMK_LEN
) < 0) {
6142 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
6145 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
6146 conf
->psk
, PMK_LEN
);
6149 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
6153 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
[0]) {
6154 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
6162 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
6163 const struct dpp_curve_params
**key_curve
)
6165 struct json_token
*token
;
6166 const struct dpp_curve_params
*curve
;
6167 struct wpabuf
*x
= NULL
, *y
= NULL
;
6169 EVP_PKEY
*pkey
= NULL
;
6171 token
= json_get_member(jwk
, "kty");
6172 if (!token
|| token
->type
!= JSON_STRING
) {
6173 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
6176 if (os_strcmp(token
->string
, "EC") != 0) {
6177 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
6182 token
= json_get_member(jwk
, "crv");
6183 if (!token
|| token
->type
!= JSON_STRING
) {
6184 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
6187 curve
= dpp_get_curve_jwk_crv(token
->string
);
6189 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
6194 x
= json_get_member_base64url(jwk
, "x");
6196 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
6199 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
6200 if (wpabuf_len(x
) != curve
->prime_len
) {
6201 wpa_printf(MSG_DEBUG
,
6202 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
6203 (unsigned int) wpabuf_len(x
),
6204 (unsigned int) curve
->prime_len
, curve
->name
);
6208 y
= json_get_member_base64url(jwk
, "y");
6210 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
6213 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
6214 if (wpabuf_len(y
) != curve
->prime_len
) {
6215 wpa_printf(MSG_DEBUG
,
6216 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
6217 (unsigned int) wpabuf_len(y
),
6218 (unsigned int) curve
->prime_len
, curve
->name
);
6222 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6224 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
6228 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
6230 EC_GROUP_free(group
);
6241 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
6244 unsigned int year
, month
, day
, hour
, min
, sec
;
6248 /* ISO 8601 date and time:
6250 * YYYY-MM-DDTHH:MM:SSZ
6251 * YYYY-MM-DDTHH:MM:SS+03:00
6253 if (os_strlen(timestamp
) < 19) {
6254 wpa_printf(MSG_DEBUG
,
6255 "DPP: Too short timestamp - assume expired key");
6258 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
6259 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
6260 wpa_printf(MSG_DEBUG
,
6261 "DPP: Failed to parse expiration day - assume expired key");
6265 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
6266 wpa_printf(MSG_DEBUG
,
6267 "DPP: Invalid date/time information - assume expired key");
6271 pos
= timestamp
+ 19;
6272 if (*pos
== 'Z' || *pos
== '\0') {
6273 /* In UTC - no need to adjust */
6274 } else if (*pos
== '-' || *pos
== '+') {
6277 /* Adjust local time to UTC */
6278 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
6280 wpa_printf(MSG_DEBUG
,
6281 "DPP: Invalid time zone designator (%s) - assume expired key",
6286 utime
+= 3600 * hour
;
6288 utime
-= 3600 * hour
;
6296 wpa_printf(MSG_DEBUG
,
6297 "DPP: Invalid time zone designator (%s) - assume expired key",
6304 if (os_get_time(&now
) < 0) {
6305 wpa_printf(MSG_DEBUG
,
6306 "DPP: Cannot get current time - assume expired key");
6310 if (now
.sec
> utime
) {
6311 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
6320 static int dpp_parse_connector(struct dpp_authentication
*auth
,
6321 struct dpp_config_obj
*conf
,
6322 const unsigned char *payload
,
6325 struct json_token
*root
, *groups
, *netkey
, *token
;
6327 EVP_PKEY
*key
= NULL
;
6328 const struct dpp_curve_params
*curve
;
6329 unsigned int rules
= 0;
6331 root
= json_parse((const char *) payload
, payload_len
);
6333 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
6337 groups
= json_get_member(root
, "groups");
6338 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6339 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
6342 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6343 struct json_token
*id
, *role
;
6345 id
= json_get_member(token
, "groupId");
6346 if (!id
|| id
->type
!= JSON_STRING
) {
6347 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
6351 role
= json_get_member(token
, "netRole");
6352 if (!role
|| role
->type
!= JSON_STRING
) {
6353 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
6356 wpa_printf(MSG_DEBUG
,
6357 "DPP: connector group: groupId='%s' netRole='%s'",
6358 id
->string
, role
->string
);
6364 wpa_printf(MSG_DEBUG
,
6365 "DPP: Connector includes no groups");
6369 token
= json_get_member(root
, "expiry");
6370 if (!token
|| token
->type
!= JSON_STRING
) {
6371 wpa_printf(MSG_DEBUG
,
6372 "DPP: No expiry string found - connector does not expire");
6374 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
6375 if (dpp_key_expired(token
->string
,
6376 &auth
->net_access_key_expiry
)) {
6377 wpa_printf(MSG_DEBUG
,
6378 "DPP: Connector (netAccessKey) has expired");
6383 netkey
= json_get_member(root
, "netAccessKey");
6384 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
6385 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
6389 key
= dpp_parse_jwk(netkey
, &curve
);
6392 dpp_debug_print_key("DPP: Received netAccessKey", key
);
6394 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
6395 wpa_printf(MSG_DEBUG
,
6396 "DPP: netAccessKey in connector does not match own protocol key");
6397 #ifdef CONFIG_TESTING_OPTIONS
6398 if (auth
->ignore_netaccesskey_mismatch
) {
6399 wpa_printf(MSG_DEBUG
,
6400 "DPP: TESTING - skip netAccessKey mismatch");
6404 #else /* CONFIG_TESTING_OPTIONS */
6406 #endif /* CONFIG_TESTING_OPTIONS */
6417 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
6419 struct wpabuf
*uncomp
;
6421 u8 hash
[SHA256_MAC_LEN
];
6425 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
6427 uncomp
= dpp_get_pubkey_point(pub
, 1);
6430 addr
[0] = wpabuf_head(uncomp
);
6431 len
[0] = wpabuf_len(uncomp
);
6432 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
6434 res
= sha256_vector(1, addr
, len
, hash
);
6435 wpabuf_free(uncomp
);
6438 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
6439 wpa_printf(MSG_DEBUG
,
6440 "DPP: Received hash value does not match calculated public key hash value");
6441 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
6442 hash
, SHA256_MAC_LEN
);
6449 static void dpp_copy_csign(struct dpp_config_obj
*conf
, EVP_PKEY
*csign
)
6451 unsigned char *der
= NULL
;
6454 der_len
= i2d_PUBKEY(csign
, &der
);
6457 wpabuf_free(conf
->c_sign_key
);
6458 conf
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
6463 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
,
6464 struct dpp_config_obj
*conf
)
6466 unsigned char *der
= NULL
;
6470 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
6474 der_len
= i2d_ECPrivateKey(eckey
, &der
);
6479 wpabuf_free(auth
->net_access_key
);
6480 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
6486 struct dpp_signed_connector_info
{
6487 unsigned char *payload
;
6491 static enum dpp_status_error
6492 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
6493 EVP_PKEY
*csign_pub
, const char *connector
)
6495 enum dpp_status_error ret
= 255;
6496 const char *pos
, *end
, *signed_start
, *signed_end
;
6497 struct wpabuf
*kid
= NULL
;
6498 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
6499 size_t prot_hdr_len
= 0, signature_len
= 0;
6500 const EVP_MD
*sign_md
= NULL
;
6501 unsigned char *der
= NULL
;
6504 EVP_MD_CTX
*md_ctx
= NULL
;
6505 ECDSA_SIG
*sig
= NULL
;
6506 BIGNUM
*r
= NULL
, *s
= NULL
;
6507 const struct dpp_curve_params
*curve
;
6509 const EC_GROUP
*group
;
6512 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
6515 group
= EC_KEY_get0_group(eckey
);
6518 nid
= EC_GROUP_get_curve_name(group
);
6519 curve
= dpp_get_curve_nid(nid
);
6522 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
6523 os_memset(info
, 0, sizeof(*info
));
6525 signed_start
= pos
= connector
;
6526 end
= os_strchr(pos
, '.');
6528 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
6529 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6532 prot_hdr
= base64_url_decode(pos
, end
- pos
, &prot_hdr_len
);
6534 wpa_printf(MSG_DEBUG
,
6535 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
6536 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6539 wpa_hexdump_ascii(MSG_DEBUG
,
6540 "DPP: signedConnector - JWS Protected Header",
6541 prot_hdr
, prot_hdr_len
);
6542 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
6544 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6547 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
6548 wpa_printf(MSG_DEBUG
,
6549 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
6550 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
6551 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6556 end
= os_strchr(pos
, '.');
6558 wpa_printf(MSG_DEBUG
,
6559 "DPP: Missing dot(2) in signedConnector");
6560 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6563 signed_end
= end
- 1;
6564 info
->payload
= base64_url_decode(pos
, end
- pos
, &info
->payload_len
);
6565 if (!info
->payload
) {
6566 wpa_printf(MSG_DEBUG
,
6567 "DPP: Failed to base64url decode signedConnector JWS Payload");
6568 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6571 wpa_hexdump_ascii(MSG_DEBUG
,
6572 "DPP: signedConnector - JWS Payload",
6573 info
->payload
, info
->payload_len
);
6575 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
6577 wpa_printf(MSG_DEBUG
,
6578 "DPP: Failed to base64url decode signedConnector signature");
6579 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6582 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
6583 signature
, signature_len
);
6585 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
6586 ret
= DPP_STATUS_NO_MATCH
;
6590 if (signature_len
& 0x01) {
6591 wpa_printf(MSG_DEBUG
,
6592 "DPP: Unexpected signedConnector signature length (%d)",
6593 (int) signature_len
);
6594 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6598 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
6599 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
6600 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
6601 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
6602 sig
= ECDSA_SIG_new();
6603 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
6608 der_len
= i2d_ECDSA_SIG(sig
, &der
);
6610 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
6613 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
6614 md_ctx
= EVP_MD_CTX_create();
6619 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
6620 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
6621 ERR_error_string(ERR_get_error(), NULL
));
6624 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
6625 signed_end
- signed_start
+ 1) != 1) {
6626 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
6627 ERR_error_string(ERR_get_error(), NULL
));
6630 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
6632 wpa_printf(MSG_DEBUG
,
6633 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
6634 res
, ERR_error_string(ERR_get_error(), NULL
));
6635 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6639 ret
= DPP_STATUS_OK
;
6642 EVP_MD_CTX_destroy(md_ctx
);
6646 ECDSA_SIG_free(sig
);
6654 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
6655 struct dpp_config_obj
*conf
,
6656 struct json_token
*cred
)
6658 struct dpp_signed_connector_info info
;
6659 struct json_token
*token
, *csign
;
6661 EVP_PKEY
*csign_pub
= NULL
;
6662 const struct dpp_curve_params
*key_curve
= NULL
;
6663 const char *signed_connector
;
6665 os_memset(&info
, 0, sizeof(info
));
6667 if (dpp_akm_psk(conf
->akm
) || dpp_akm_sae(conf
->akm
)) {
6668 wpa_printf(MSG_DEBUG
,
6669 "DPP: Legacy credential included in Connector credential");
6670 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6674 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
6676 csign
= json_get_member(cred
, "csign");
6677 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
6678 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
6682 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
6684 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
6687 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
6689 token
= json_get_member(cred
, "signedConnector");
6690 if (!token
|| token
->type
!= JSON_STRING
) {
6691 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
6694 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
6695 token
->string
, os_strlen(token
->string
));
6696 signed_connector
= token
->string
;
6698 if (os_strchr(signed_connector
, '"') ||
6699 os_strchr(signed_connector
, '\n')) {
6700 wpa_printf(MSG_DEBUG
,
6701 "DPP: Unexpected character in signedConnector");
6705 if (dpp_process_signed_connector(&info
, csign_pub
,
6706 signed_connector
) != DPP_STATUS_OK
)
6709 if (dpp_parse_connector(auth
, conf
,
6710 info
.payload
, info
.payload_len
) < 0) {
6711 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
6715 os_free(conf
->connector
);
6716 conf
->connector
= os_strdup(signed_connector
);
6718 dpp_copy_csign(conf
, csign_pub
);
6719 dpp_copy_netaccesskey(auth
, conf
);
6723 EVP_PKEY_free(csign_pub
);
6724 os_free(info
.payload
);
6729 const char * dpp_akm_str(enum dpp_akm akm
)
6738 case DPP_AKM_PSK_SAE
:
6740 case DPP_AKM_SAE_DPP
:
6742 case DPP_AKM_PSK_SAE_DPP
:
6743 return "dpp+psk+sae";
6750 const char * dpp_akm_selector_str(enum dpp_akm akm
)
6756 return "000FAC02+000FAC06";
6759 case DPP_AKM_PSK_SAE
:
6760 return "000FAC02+000FAC06+000FAC08";
6761 case DPP_AKM_SAE_DPP
:
6762 return "506F9A02+000FAC08";
6763 case DPP_AKM_PSK_SAE_DPP
:
6764 return "506F9A02+000FAC08+000FAC02+000FAC06";
6771 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
6774 int dpp
= 0, psk
= 0, sae
= 0;
6776 if (os_strcmp(akm
, "psk") == 0)
6778 if (os_strcmp(akm
, "sae") == 0)
6780 if (os_strcmp(akm
, "psk+sae") == 0)
6781 return DPP_AKM_PSK_SAE
;
6782 if (os_strcmp(akm
, "dpp") == 0)
6784 if (os_strcmp(akm
, "dpp+sae") == 0)
6785 return DPP_AKM_SAE_DPP
;
6786 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
6787 return DPP_AKM_PSK_SAE_DPP
;
6791 if (os_strlen(pos
) < 8)
6793 if (os_strncasecmp(pos
, "506F9A02", 8) == 0)
6795 else if (os_strncasecmp(pos
, "000FAC02", 8) == 0)
6797 else if (os_strncasecmp(pos
, "000FAC06", 8) == 0)
6799 else if (os_strncasecmp(pos
, "000FAC08", 8) == 0)
6807 if (dpp
&& psk
&& sae
)
6808 return DPP_AKM_PSK_SAE_DPP
;
6810 return DPP_AKM_SAE_DPP
;
6814 return DPP_AKM_PSK_SAE
;
6820 return DPP_AKM_UNKNOWN
;
6824 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
6825 const u8
*conf_obj
, u16 conf_obj_len
)
6828 struct json_token
*root
, *token
, *discovery
, *cred
;
6829 struct dpp_config_obj
*conf
;
6830 struct wpabuf
*ssid64
= NULL
;
6832 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
6835 if (root
->type
!= JSON_OBJECT
) {
6836 dpp_auth_fail(auth
, "JSON root is not an object");
6840 token
= json_get_member(root
, "wi-fi_tech");
6841 if (!token
|| token
->type
!= JSON_STRING
) {
6842 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
6845 if (os_strcmp(token
->string
, "infra") != 0) {
6846 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
6848 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
6852 discovery
= json_get_member(root
, "discovery");
6853 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
6854 dpp_auth_fail(auth
, "No discovery object in JSON");
6858 ssid64
= json_get_member_base64url(discovery
, "ssid64");
6860 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid64",
6861 wpabuf_head(ssid64
), wpabuf_len(ssid64
));
6862 if (wpabuf_len(ssid64
) > SSID_MAX_LEN
) {
6863 dpp_auth_fail(auth
, "Too long discovery::ssid64 value");
6867 token
= json_get_member(discovery
, "ssid");
6868 if (!token
|| token
->type
!= JSON_STRING
) {
6870 "No discovery::ssid string value found");
6873 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
6874 token
->string
, os_strlen(token
->string
));
6875 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
6877 "Too long discovery::ssid string value");
6882 if (auth
->num_conf_obj
== DPP_MAX_CONF_OBJ
) {
6883 wpa_printf(MSG_DEBUG
,
6884 "DPP: No room for this many Config Objects - ignore this one");
6888 conf
= &auth
->conf_obj
[auth
->num_conf_obj
++];
6891 conf
->ssid_len
= wpabuf_len(ssid64
);
6892 os_memcpy(conf
->ssid
, wpabuf_head(ssid64
), conf
->ssid_len
);
6894 conf
->ssid_len
= os_strlen(token
->string
);
6895 os_memcpy(conf
->ssid
, token
->string
, conf
->ssid_len
);
6898 token
= json_get_member(discovery
, "ssid_charset");
6899 if (token
&& token
->type
== JSON_NUMBER
) {
6900 conf
->ssid_charset
= token
->number
;
6901 wpa_printf(MSG_DEBUG
, "DPP: ssid_charset=%d",
6902 conf
->ssid_charset
);
6905 cred
= json_get_member(root
, "cred");
6906 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
6907 dpp_auth_fail(auth
, "No cred object in JSON");
6911 token
= json_get_member(cred
, "akm");
6912 if (!token
|| token
->type
!= JSON_STRING
) {
6913 dpp_auth_fail(auth
, "No cred::akm string value found");
6916 conf
->akm
= dpp_akm_from_str(token
->string
);
6918 if (dpp_akm_legacy(conf
->akm
)) {
6919 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6921 } else if (dpp_akm_dpp(conf
->akm
)) {
6922 if (dpp_parse_cred_dpp(auth
, conf
, cred
) < 0)
6925 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
6927 dpp_auth_fail(auth
, "Unsupported akm");
6931 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
6934 wpabuf_free(ssid64
);
6942 struct dpp_enveloped_data
{
6944 size_t enc_cont_len
;
6948 size_t pbkdf2_key_len
;
6949 size_t prf_hash_len
;
6953 static int dpp_parse_recipient_infos(const u8
*pos
, size_t len
,
6954 struct dpp_enveloped_data
*data
)
6956 struct asn1_hdr hdr
;
6957 const u8
*end
= pos
+ len
;
6958 const u8
*next
, *e_end
;
6959 struct asn1_oid oid
;
6964 wpa_hexdump(MSG_MSGDUMP
, "DPP: RecipientInfos", pos
, len
);
6967 * RecipientInfo ::= CHOICE {
6968 * ktri KeyTransRecipientInfo,
6969 * kari [1] KeyAgreeRecipientInfo,
6970 * kekri [2] KEKRecipientInfo,
6971 * pwri [3] PasswordRecipientInfo,
6972 * ori [4] OtherRecipientInfo}
6974 * Shall always use the pwri CHOICE.
6977 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6978 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 3) {
6979 wpa_printf(MSG_DEBUG
,
6980 "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
6981 hdr
.class, hdr
.tag
);
6984 wpa_hexdump(MSG_MSGDUMP
, "DPP: PasswordRecipientInfo",
6985 hdr
.payload
, hdr
.length
);
6987 end
= pos
+ hdr
.length
;
6990 * PasswordRecipientInfo ::= SEQUENCE {
6991 * version CMSVersion,
6992 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
6993 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
6994 * encryptedKey EncryptedKey}
6996 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
6997 * parameters contains PBKDF2-params SEQUENCE.
7000 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
7004 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7007 wpa_printf(MSG_DEBUG
, "DPP: pwri.version != 0");
7011 wpa_hexdump(MSG_MSGDUMP
, "DPP: Remaining PasswordRecipientInfo after version",
7014 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7015 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7016 wpa_printf(MSG_DEBUG
,
7017 "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
7018 hdr
.class, hdr
.tag
);
7022 e_end
= pos
+ hdr
.length
;
7024 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
7025 if (asn1_get_alg_id(pos
, e_end
- pos
, &oid
, ¶ms
, ¶ms_len
,
7028 if (!asn1_oid_equal(&oid
, &asn1_pbkdf2_oid
)) {
7031 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7032 wpa_printf(MSG_DEBUG
,
7033 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
7039 * PBKDF2-params ::= SEQUENCE {
7041 * specified OCTET STRING,
7042 * otherSource AlgorithmIdentifier}
7043 * iterationCount INTEGER (1..MAX),
7044 * keyLength INTEGER (1..MAX),
7045 * prf AlgorithmIdentifier}
7047 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
7048 * on Configurator signing key length, prf is
7049 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
7052 asn1_get_sequence(params
, params_len
, &hdr
, &e_end
) < 0)
7056 if (asn1_get_next(pos
, e_end
- pos
, &hdr
) < 0 ||
7057 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7058 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7059 wpa_printf(MSG_DEBUG
,
7060 "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
7061 hdr
.class, hdr
.tag
);
7064 wpa_hexdump(MSG_MSGDUMP
, "DPP: salt.specified",
7065 hdr
.payload
, hdr
.length
);
7066 if (hdr
.length
!= 64) {
7067 wpa_printf(MSG_DEBUG
, "DPP: Unexpected salt length %u",
7071 data
->salt
= hdr
.payload
;
7072 pos
= hdr
.payload
+ hdr
.length
;
7074 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
7077 wpa_printf(MSG_DEBUG
, "DPP: Unexpected iterationCount %d", val
);
7081 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
7083 if (val
!= 32 && val
!= 48 && val
!= 64) {
7084 wpa_printf(MSG_DEBUG
, "DPP: Unexpected keyLength %d", val
);
7087 data
->pbkdf2_key_len
= val
;
7089 if (asn1_get_sequence(pos
, e_end
- pos
, &hdr
, NULL
) < 0 ||
7090 asn1_get_oid(hdr
.payload
, hdr
.length
, &oid
, &pos
) < 0) {
7091 wpa_printf(MSG_DEBUG
, "DPP: Could not parse prf");
7094 if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha256_oid
)) {
7095 data
->prf_hash_len
= 32;
7096 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha384_oid
)) {
7097 data
->prf_hash_len
= 48;
7098 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha512_oid
)) {
7099 data
->prf_hash_len
= 64;
7103 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7104 wpa_printf(MSG_DEBUG
, "DPP: Unexpected PBKDF2-params.prf %s",
7111 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
7113 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
7115 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
7116 * id-alg-AES-SIV-CMAC-aed-512. */
7117 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
7119 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
7120 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
7121 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
7124 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7125 wpa_printf(MSG_DEBUG
,
7126 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
7132 * encryptedKey EncryptedKey
7134 * EncryptedKey ::= OCTET STRING
7136 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7137 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7138 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7139 wpa_printf(MSG_DEBUG
,
7140 "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
7141 hdr
.class, hdr
.tag
);
7144 wpa_hexdump(MSG_MSGDUMP
, "DPP: pwri.encryptedKey",
7145 hdr
.payload
, hdr
.length
);
7146 data
->enc_key
= hdr
.payload
;
7147 data
->enc_key_len
= hdr
.length
;
7153 static int dpp_parse_encrypted_content_info(const u8
*pos
, const u8
*end
,
7154 struct dpp_enveloped_data
*data
)
7156 struct asn1_hdr hdr
;
7157 struct asn1_oid oid
;
7160 * EncryptedContentInfo ::= SEQUENCE {
7161 * contentType ContentType,
7162 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
7163 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
7165 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7167 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContentInfo",
7168 hdr
.payload
, hdr
.length
);
7170 wpa_hexdump(MSG_DEBUG
,
7171 "DPP: Unexpected extra data after EncryptedContentInfo",
7179 /* ContentType ::= OBJECT IDENTIFIER */
7180 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0) {
7181 wpa_printf(MSG_DEBUG
, "DPP: Could not parse ContentType");
7184 if (!asn1_oid_equal(&oid
, &asn1_dpp_asymmetric_key_package_oid
)) {
7187 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7188 wpa_printf(MSG_DEBUG
, "DPP: Unexpected ContentType %s", buf
);
7192 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
7193 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
7195 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
7196 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
7197 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
7200 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7201 wpa_printf(MSG_DEBUG
,
7202 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
7206 /* ignore optional parameters */
7208 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
7209 * EncryptedContent ::= OCTET STRING */
7210 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7211 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7212 wpa_printf(MSG_DEBUG
,
7213 "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
7214 hdr
.class, hdr
.tag
);
7217 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContent",
7218 hdr
.payload
, hdr
.length
);
7219 data
->enc_cont
= hdr
.payload
;
7220 data
->enc_cont_len
= hdr
.length
;
7225 static int dpp_parse_enveloped_data(const u8
*env_data
, size_t env_data_len
,
7226 struct dpp_enveloped_data
*data
)
7228 struct asn1_hdr hdr
;
7229 const u8
*pos
, *end
;
7232 os_memset(data
, 0, sizeof(*data
));
7235 * DPPEnvelopedData ::= EnvelopedData
7237 * EnvelopedData ::= SEQUENCE {
7238 * version CMSVersion,
7239 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
7240 * recipientInfos RecipientInfos,
7241 * encryptedContentInfo EncryptedContentInfo,
7242 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
7244 * CMSVersion ::= INTEGER
7246 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
7248 * For DPP, version is 3, both originatorInfo and
7249 * unprotectedAttrs are omitted, and recipientInfos contains a single
7252 if (asn1_get_sequence(env_data
, env_data_len
, &hdr
, &end
) < 0)
7255 if (end
< env_data
+ env_data_len
) {
7256 wpa_hexdump(MSG_DEBUG
,
7257 "DPP: Unexpected extra data after DPPEnvelopedData",
7258 end
, env_data
+ env_data_len
- end
);
7262 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7265 wpa_printf(MSG_DEBUG
, "DPP: EnvelopedData.version != 3");
7269 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7270 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7271 wpa_printf(MSG_DEBUG
,
7272 "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
7273 hdr
.class, hdr
.tag
);
7277 if (dpp_parse_recipient_infos(hdr
.payload
, hdr
.length
, data
) < 0)
7279 return dpp_parse_encrypted_content_info(hdr
.payload
+ hdr
.length
, end
,
7284 static struct dpp_asymmetric_key
*
7285 dpp_parse_one_asymmetric_key(const u8
*buf
, size_t len
)
7287 struct asn1_hdr hdr
;
7288 const u8
*pos
= buf
, *end
= buf
+ len
, *next
;
7292 struct asn1_oid oid
;
7294 struct dpp_asymmetric_key
*key
;
7297 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: OneAsymmetricKey", buf
, len
);
7299 key
= os_zalloc(sizeof(*key
));
7304 * OneAsymmetricKey ::= SEQUENCE {
7306 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
7307 * privateKey PrivateKey,
7308 * attributes [0] Attributes OPTIONAL,
7310 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
7314 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
7318 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
7319 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7322 wpa_printf(MSG_DEBUG
,
7323 "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
7328 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
7329 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, ¶ms
, ¶ms_len
,
7332 if (!asn1_oid_equal(&oid
, &asn1_ec_public_key_oid
)) {
7333 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7334 wpa_printf(MSG_DEBUG
,
7335 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
7339 wpa_hexdump(MSG_MSGDUMP
, "DPP: PrivateKeyAlgorithmIdentifier params",
7340 params
, params_len
);
7342 * ECParameters ::= CHOICE {
7343 * namedCurve OBJECT IDENTIFIER
7344 * -- implicitCurve NULL
7345 * -- specifiedCurve SpecifiedECDomain}
7347 if (!params
|| asn1_get_oid(params
, params_len
, &oid
, &next
) < 0) {
7348 wpa_printf(MSG_DEBUG
,
7349 "DPP: Could not parse ECParameters.namedCurve");
7352 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7353 wpa_printf(MSG_MSGDUMP
, "DPP: namedCurve %s", txt
);
7354 /* Assume the curve is identified within ECPrivateKey, so that this
7355 * separate indication is not really needed. */
7358 * PrivateKey ::= OCTET STRING
7359 * (Contains DER encoding of ECPrivateKey)
7361 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7362 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7363 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7364 wpa_printf(MSG_DEBUG
,
7365 "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
7366 hdr
.class, hdr
.tag
);
7369 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: PrivateKey",
7370 hdr
.payload
, hdr
.length
);
7371 pos
= hdr
.payload
+ hdr
.length
;
7372 eckey
= d2i_ECPrivateKey(NULL
, &hdr
.payload
, hdr
.length
);
7374 wpa_printf(MSG_INFO
,
7375 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
7376 ERR_error_string(ERR_get_error(), NULL
));
7379 key
->csign
= EVP_PKEY_new();
7380 if (!key
->csign
|| EVP_PKEY_assign_EC_KEY(key
->csign
, eckey
) != 1) {
7384 if (wpa_debug_show_keys
)
7385 dpp_debug_print_key("DPP: Received c-sign-key", key
->csign
);
7388 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
7390 * Exactly one instance of type Attribute in OneAsymmetricKey.
7392 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7393 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7394 wpa_printf(MSG_DEBUG
,
7395 "DPP: Expected [0] Attributes - found class %d tag 0x%x",
7396 hdr
.class, hdr
.tag
);
7399 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: Attributes",
7400 hdr
.payload
, hdr
.length
);
7401 if (hdr
.payload
+ hdr
.length
< end
) {
7402 wpa_hexdump_key(MSG_MSGDUMP
,
7403 "DPP: Ignore additional data at the end of OneAsymmetricKey",
7404 hdr
.payload
+ hdr
.length
,
7405 end
- (hdr
.payload
+ hdr
.length
));
7408 end
= hdr
.payload
+ hdr
.length
;
7410 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7411 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7412 wpa_printf(MSG_DEBUG
,
7413 "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
7414 hdr
.class, hdr
.tag
);
7417 if (hdr
.payload
+ hdr
.length
< end
) {
7418 wpa_hexdump_key(MSG_MSGDUMP
,
7419 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
7420 hdr
.payload
+ hdr
.length
,
7421 end
- (hdr
.payload
+ hdr
.length
));
7424 end
= hdr
.payload
+ hdr
.length
;
7427 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
7428 * aa-DPPConfigurationParameters,
7429 * ... -- For local profiles
7432 * aa-DPPConfigurationParameters ATTRIBUTE ::=
7433 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
7435 * Attribute ::= SEQUENCE {
7436 * type OBJECT IDENTIFIER,
7437 * values SET SIZE(1..MAX) OF Type
7439 * Exactly one instance of ATTRIBUTE in attrValues.
7441 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7444 wpa_hexdump_key(MSG_MSGDUMP
,
7445 "DPP: Ignore additional data at the end of ATTRIBUTE",
7451 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0)
7453 if (!asn1_oid_equal(&oid
, &asn1_dpp_config_params_oid
)) {
7454 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7455 wpa_printf(MSG_DEBUG
,
7456 "DPP: Unexpected Attribute identifier %s", txt
);
7460 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7461 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7462 wpa_printf(MSG_DEBUG
,
7463 "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
7464 hdr
.class, hdr
.tag
);
7468 end
= hdr
.payload
+ hdr
.length
;
7471 * DPPConfigurationParameters ::= SEQUENCE {
7472 * configurationTemplate UTF8String,
7473 * connectorTemplate UTF8String OPTIONAL}
7476 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPConfigurationParameters",
7478 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7481 wpa_hexdump_key(MSG_MSGDUMP
,
7482 "DPP: Ignore additional data after DPPConfigurationParameters",
7488 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7489 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7490 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
7491 wpa_printf(MSG_DEBUG
,
7492 "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
7493 hdr
.class, hdr
.tag
);
7496 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: configurationTemplate",
7497 hdr
.payload
, hdr
.length
);
7498 key
->config_template
= os_zalloc(hdr
.length
+ 1);
7499 if (!key
->config_template
)
7501 os_memcpy(key
->config_template
, hdr
.payload
, hdr
.length
);
7503 pos
= hdr
.payload
+ hdr
.length
;
7506 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7507 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7508 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
7509 wpa_printf(MSG_DEBUG
,
7510 "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
7511 hdr
.class, hdr
.tag
);
7514 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: connectorTemplate",
7515 hdr
.payload
, hdr
.length
);
7516 key
->connector_template
= os_zalloc(hdr
.length
+ 1);
7517 if (!key
->connector_template
)
7519 os_memcpy(key
->connector_template
, hdr
.payload
, hdr
.length
);
7524 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse OneAsymmetricKey");
7525 dpp_free_asymmetric_key(key
);
7530 static struct dpp_asymmetric_key
*
7531 dpp_parse_dpp_asymmetric_key_package(const u8
*key_pkg
, size_t key_pkg_len
)
7533 struct asn1_hdr hdr
;
7534 const u8
*pos
= key_pkg
, *end
= key_pkg
+ key_pkg_len
;
7535 struct dpp_asymmetric_key
*first
= NULL
, *last
= NULL
, *key
;
7537 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPAsymmetricKeyPackage",
7538 key_pkg
, key_pkg_len
);
7541 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
7543 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
7546 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0 ||
7547 !(key
= dpp_parse_one_asymmetric_key(hdr
.payload
,
7549 dpp_free_asymmetric_key(first
);
7564 static int dpp_conf_resp_env_data(struct dpp_authentication
*auth
,
7565 const u8
*env_data
, size_t env_data_len
)
7569 u8 kek
[DPP_MAX_HASH_LEN
];
7570 u8 cont_encr_key
[DPP_MAX_HASH_LEN
];
7571 size_t cont_encr_key_len
;
7575 struct dpp_enveloped_data data
;
7576 struct dpp_asymmetric_key
*keys
;
7578 wpa_hexdump(MSG_DEBUG
, "DPP: DPPEnvelopedData", env_data
, env_data_len
);
7580 if (dpp_parse_enveloped_data(env_data
, env_data_len
, &data
) < 0)
7583 /* TODO: For initial testing, use ke as the key. Replace this with a
7584 * new key once that has been defined. */
7586 key_len
= auth
->curve
->hash_len
;
7587 wpa_hexdump_key(MSG_DEBUG
, "DPP: PBKDF2 key", key
, key_len
);
7589 if (dpp_pbkdf2(data
.prf_hash_len
, key
, key_len
, data
.salt
, 64, 1000,
7590 kek
, data
.pbkdf2_key_len
)) {
7591 wpa_printf(MSG_DEBUG
, "DPP: PBKDF2 failed");
7594 wpa_hexdump_key(MSG_DEBUG
, "DPP: key-encryption key from PBKDF2",
7595 kek
, data
.pbkdf2_key_len
);
7597 if (data
.enc_key_len
< AES_BLOCK_SIZE
||
7598 data
.enc_key_len
> sizeof(cont_encr_key
) + AES_BLOCK_SIZE
) {
7599 wpa_printf(MSG_DEBUG
, "DPP: Invalid encryptedKey length");
7602 res
= aes_siv_decrypt(kek
, data
.pbkdf2_key_len
,
7603 data
.enc_key
, data
.enc_key_len
,
7604 0, NULL
, NULL
, cont_encr_key
);
7605 forced_memzero(kek
, data
.pbkdf2_key_len
);
7607 wpa_printf(MSG_DEBUG
,
7608 "DPP: AES-SIV decryption of encryptedKey failed");
7611 cont_encr_key_len
= data
.enc_key_len
- AES_BLOCK_SIZE
;
7612 wpa_hexdump_key(MSG_DEBUG
, "DPP: content-encryption key",
7613 cont_encr_key
, cont_encr_key_len
);
7615 if (data
.enc_cont_len
< AES_BLOCK_SIZE
)
7617 key_pkg_len
= data
.enc_cont_len
- AES_BLOCK_SIZE
;
7618 key_pkg
= os_malloc(key_pkg_len
);
7621 res
= aes_siv_decrypt(cont_encr_key
, cont_encr_key_len
,
7622 data
.enc_cont
, data
.enc_cont_len
,
7623 0, NULL
, NULL
, key_pkg
);
7624 forced_memzero(cont_encr_key
, cont_encr_key_len
);
7626 bin_clear_free(key_pkg
, key_pkg_len
);
7627 wpa_printf(MSG_DEBUG
,
7628 "DPP: AES-SIV decryption of encryptedContent failed");
7632 keys
= dpp_parse_dpp_asymmetric_key_package(key_pkg
, key_pkg_len
);
7633 bin_clear_free(key_pkg
, key_pkg_len
);
7634 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
7635 auth
->conf_key_pkg
= keys
;
7637 return keys
!= NULL
;;
7640 #endif /* CONFIG_DPP2 */
7643 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
7644 const struct wpabuf
*resp
)
7646 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
7647 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
7652 u8
*unwrapped
= NULL
;
7653 size_t unwrapped_len
= 0;
7656 auth
->conf_resp_status
= 255;
7658 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
7659 dpp_auth_fail(auth
, "Invalid attribute in config response");
7663 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7664 DPP_ATTR_WRAPPED_DATA
,
7666 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7668 "Missing or invalid required Wrapped Data attribute");
7672 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7673 wrapped_data
, wrapped_data_len
);
7674 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7675 unwrapped
= os_malloc(unwrapped_len
);
7679 addr
[0] = wpabuf_head(resp
);
7680 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
7681 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
7683 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7684 wrapped_data
, wrapped_data_len
,
7685 1, addr
, len
, unwrapped
) < 0) {
7686 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7689 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7690 unwrapped
, unwrapped_len
);
7692 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7693 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7697 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7698 DPP_ATTR_ENROLLEE_NONCE
,
7700 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7702 "Missing or invalid Enrollee Nonce attribute");
7705 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7706 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7707 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7711 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7712 DPP_ATTR_STATUS
, &status_len
);
7713 if (!status
|| status_len
< 1) {
7715 "Missing or invalid required DPP Status attribute");
7718 auth
->conf_resp_status
= status
[0];
7719 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7720 if (status
[0] != DPP_STATUS_OK
) {
7721 dpp_auth_fail(auth
, "Configurator rejected configuration");
7725 env_data
= dpp_get_attr(unwrapped
, unwrapped_len
,
7726 DPP_ATTR_ENVELOPED_DATA
, &env_data_len
);
7729 dpp_conf_resp_env_data(auth
, env_data
, env_data_len
) < 0)
7731 #endif /* CONFIG_DPP2 */
7733 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONFIG_OBJ
,
7735 if (!conf_obj
&& !env_data
) {
7737 "Missing required Configuration Object attribute");
7741 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
7742 conf_obj
, conf_obj_len
);
7743 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
7745 conf_obj
= dpp_get_attr_next(conf_obj
, unwrapped
, unwrapped_len
,
7746 DPP_ATTR_CONFIG_OBJ
,
7751 status
= dpp_get_attr(unwrapped
, unwrapped_len
,
7752 DPP_ATTR_SEND_CONN_STATUS
, &status_len
);
7754 wpa_printf(MSG_DEBUG
,
7755 "DPP: Configurator requested connection status result");
7756 auth
->conn_status_requested
= 1;
7758 #endif /* CONFIG_DPP2 */
7770 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
7772 const u8
*attr_start
, size_t attr_len
)
7774 const u8
*wrapped_data
, *status
, *e_nonce
;
7775 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7778 u8
*unwrapped
= NULL
;
7779 size_t unwrapped_len
= 0;
7780 enum dpp_status_error ret
= 256;
7782 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7784 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7786 "Missing or invalid required Wrapped Data attribute");
7789 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7790 wrapped_data
, wrapped_data_len
);
7792 attr_len
= wrapped_data
- 4 - attr_start
;
7795 len
[0] = DPP_HDR_LEN
;
7796 addr
[1] = attr_start
;
7798 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7799 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7800 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7801 wrapped_data
, wrapped_data_len
);
7802 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7803 unwrapped
= os_malloc(unwrapped_len
);
7806 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7807 wrapped_data
, wrapped_data_len
,
7808 2, addr
, len
, unwrapped
) < 0) {
7809 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7812 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7813 unwrapped
, unwrapped_len
);
7815 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7816 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7820 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7821 DPP_ATTR_ENROLLEE_NONCE
,
7823 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7825 "Missing or invalid Enrollee Nonce attribute");
7828 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7829 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7830 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7831 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7832 auth
->e_nonce
, e_nonce_len
);
7836 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
7838 if (!status
|| status_len
< 1) {
7840 "Missing or invalid required DPP Status attribute");
7843 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7847 bin_clear_free(unwrapped
, unwrapped_len
);
7852 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
7853 enum dpp_status_error status
)
7855 struct wpabuf
*msg
, *clear
;
7856 size_t nonce_len
, clear_len
, attr_len
;
7861 nonce_len
= auth
->curve
->nonce_len
;
7862 clear_len
= 5 + 4 + nonce_len
;
7863 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7864 clear
= wpabuf_alloc(clear_len
);
7865 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
7870 dpp_build_attr_status(clear
, status
);
7873 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
7874 wpabuf_put_le16(clear
, nonce_len
);
7875 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
7877 /* OUI, OUI type, Crypto Suite, DPP frame type */
7878 addr
[0] = wpabuf_head_u8(msg
) + 2;
7879 len
[0] = 3 + 1 + 1 + 1;
7880 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7882 /* Attributes before Wrapped Data (none) */
7883 addr
[1] = wpabuf_put(msg
, 0);
7885 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7888 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7889 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7890 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7892 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7893 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
7894 wpabuf_head(clear
), wpabuf_len(clear
),
7895 2, addr
, len
, wrapped
) < 0)
7898 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
7908 static int valid_channel_list(const char *val
)
7911 if (!((*val
>= '0' && *val
<= '9') ||
7912 *val
== '/' || *val
== ','))
7921 enum dpp_status_error
dpp_conn_status_result_rx(struct dpp_authentication
*auth
,
7923 const u8
*attr_start
,
7925 u8
*ssid
, size_t *ssid_len
,
7926 char **channel_list
)
7928 const u8
*wrapped_data
, *status
, *e_nonce
;
7929 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7932 u8
*unwrapped
= NULL
;
7933 size_t unwrapped_len
= 0;
7934 enum dpp_status_error ret
= 256;
7935 struct json_token
*root
= NULL
, *token
;
7936 struct wpabuf
*ssid64
;
7939 *channel_list
= NULL
;
7941 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7943 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7945 "Missing or invalid required Wrapped Data attribute");
7948 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7949 wrapped_data
, wrapped_data_len
);
7951 attr_len
= wrapped_data
- 4 - attr_start
;
7954 len
[0] = DPP_HDR_LEN
;
7955 addr
[1] = attr_start
;
7957 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7958 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7959 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7960 wrapped_data
, wrapped_data_len
);
7961 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7962 unwrapped
= os_malloc(unwrapped_len
);
7965 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7966 wrapped_data
, wrapped_data_len
,
7967 2, addr
, len
, unwrapped
) < 0) {
7968 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7971 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7972 unwrapped
, unwrapped_len
);
7974 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7975 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7979 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7980 DPP_ATTR_ENROLLEE_NONCE
,
7982 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7984 "Missing or invalid Enrollee Nonce attribute");
7987 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7988 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7989 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7990 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7991 auth
->e_nonce
, e_nonce_len
);
7995 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONN_STATUS
,
7999 "Missing required DPP Connection Status attribute");
8002 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
8003 status
, status_len
);
8005 root
= json_parse((const char *) status
, status_len
);
8007 dpp_auth_fail(auth
, "Could not parse connStatus");
8011 ssid64
= json_get_member_base64url(root
, "ssid64");
8012 if (ssid64
&& wpabuf_len(ssid64
) <= SSID_MAX_LEN
) {
8013 *ssid_len
= wpabuf_len(ssid64
);
8014 os_memcpy(ssid
, wpabuf_head(ssid64
), *ssid_len
);
8016 wpabuf_free(ssid64
);
8018 token
= json_get_member(root
, "channelList");
8019 if (token
&& token
->type
== JSON_STRING
&&
8020 valid_channel_list(token
->string
))
8021 *channel_list
= os_strdup(token
->string
);
8023 token
= json_get_member(root
, "result");
8024 if (!token
|| token
->type
!= JSON_NUMBER
) {
8025 dpp_auth_fail(auth
, "No connStatus - result");
8028 wpa_printf(MSG_DEBUG
, "DPP: result %d", token
->number
);
8029 ret
= token
->number
;
8033 bin_clear_free(unwrapped
, unwrapped_len
);
8038 struct wpabuf
* dpp_build_conn_status_result(struct dpp_authentication
*auth
,
8039 enum dpp_status_error result
,
8040 const u8
*ssid
, size_t ssid_len
,
8041 const char *channel_list
)
8043 struct wpabuf
*msg
= NULL
, *clear
= NULL
, *json
;
8044 size_t nonce_len
, clear_len
, attr_len
;
8049 json
= wpabuf_alloc(1000);
8052 json_start_object(json
, NULL
);
8053 json_add_int(json
, "result", result
);
8055 json_value_sep(json
);
8056 if (json_add_base64url(json
, "ssid64", ssid
, ssid_len
) < 0)
8060 json_value_sep(json
);
8061 json_add_string(json
, "channelList", channel_list
);
8063 json_end_object(json
);
8064 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
8065 wpabuf_head(json
), wpabuf_len(json
));
8067 nonce_len
= auth
->curve
->nonce_len
;
8068 clear_len
= 5 + 4 + nonce_len
+ 4 + wpabuf_len(json
);
8069 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
8070 clear
= wpabuf_alloc(clear_len
);
8071 msg
= dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT
, attr_len
);
8076 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
8077 wpabuf_put_le16(clear
, nonce_len
);
8078 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
8080 /* DPP Connection Status */
8081 wpabuf_put_le16(clear
, DPP_ATTR_CONN_STATUS
);
8082 wpabuf_put_le16(clear
, wpabuf_len(json
));
8083 wpabuf_put_buf(clear
, json
);
8085 /* OUI, OUI type, Crypto Suite, DPP frame type */
8086 addr
[0] = wpabuf_head_u8(msg
) + 2;
8087 len
[0] = 3 + 1 + 1 + 1;
8088 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8090 /* Attributes before Wrapped Data (none) */
8091 addr
[1] = wpabuf_put(msg
, 0);
8093 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8096 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
8097 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8098 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8100 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
8101 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
8102 wpabuf_head(clear
), wpabuf_len(clear
),
8103 2, addr
, len
, wrapped
) < 0)
8106 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Connection Status Result attributes",
8118 #endif /* CONFIG_DPP2 */
8121 void dpp_configurator_free(struct dpp_configurator
*conf
)
8125 EVP_PKEY_free(conf
->csign
);
8131 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
8135 int key_len
, ret
= -1;
8136 unsigned char *key
= NULL
;
8141 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
8145 key_len
= i2d_ECPrivateKey(eckey
, &key
);
8147 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
8155 static int dpp_configurator_gen_kid(struct dpp_configurator
*conf
)
8157 struct wpabuf
*csign_pub
= NULL
;
8158 u8 kid_hash
[SHA256_MAC_LEN
];
8163 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
8165 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
8169 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
8170 addr
[0] = wpabuf_head(csign_pub
);
8171 len
[0] = wpabuf_len(csign_pub
);
8172 res
= sha256_vector(1, addr
, len
, kid_hash
);
8173 wpabuf_free(csign_pub
);
8175 wpa_printf(MSG_DEBUG
,
8176 "DPP: Failed to derive kid for C-sign-key");
8180 conf
->kid
= base64_url_encode(kid_hash
, sizeof(kid_hash
), NULL
);
8181 return conf
->kid
? 0 : -1;
8185 struct dpp_configurator
*
8186 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
8189 struct dpp_configurator
*conf
;
8191 conf
= os_zalloc(sizeof(*conf
));
8196 conf
->curve
= &dpp_curves
[0];
8198 conf
->curve
= dpp_get_curve_name(curve
);
8200 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
8207 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
8210 conf
->csign
= dpp_gen_keypair(conf
->curve
);
8215 if (dpp_configurator_gen_kid(conf
) < 0)
8219 dpp_configurator_free(conf
);
8224 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
8225 const char *curve
, int ap
)
8227 struct wpabuf
*conf_obj
;
8231 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
8236 auth
->curve
= &dpp_curves
[0];
8238 auth
->curve
= dpp_get_curve_name(curve
);
8240 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
8245 wpa_printf(MSG_DEBUG
,
8246 "DPP: Building own configuration/connector with curve %s",
8249 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
8250 if (!auth
->own_protocol_key
)
8252 dpp_copy_netaccesskey(auth
, &auth
->conf_obj
[0]);
8253 auth
->peer_protocol_key
= auth
->own_protocol_key
;
8254 dpp_copy_csign(&auth
->conf_obj
[0], auth
->conf
->csign
);
8256 conf_obj
= dpp_build_conf_obj(auth
, ap
, 0);
8258 wpabuf_free(auth
->conf_obj
[0].c_sign_key
);
8259 auth
->conf_obj
[0].c_sign_key
= NULL
;
8262 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
8263 wpabuf_len(conf_obj
));
8265 wpabuf_free(conf_obj
);
8266 auth
->peer_protocol_key
= NULL
;
8271 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
8273 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
8274 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
8278 static int dpp_connector_compatible_group(struct json_token
*root
,
8279 const char *group_id
,
8280 const char *net_role
)
8282 struct json_token
*groups
, *token
;
8284 groups
= json_get_member(root
, "groups");
8285 if (!groups
|| groups
->type
!= JSON_ARRAY
)
8288 for (token
= groups
->child
; token
; token
= token
->sibling
) {
8289 struct json_token
*id
, *role
;
8291 id
= json_get_member(token
, "groupId");
8292 if (!id
|| id
->type
!= JSON_STRING
)
8295 role
= json_get_member(token
, "netRole");
8296 if (!role
|| role
->type
!= JSON_STRING
)
8299 if (os_strcmp(id
->string
, "*") != 0 &&
8300 os_strcmp(group_id
, "*") != 0 &&
8301 os_strcmp(id
->string
, group_id
) != 0)
8304 if (dpp_compatible_netrole(role
->string
, net_role
))
8312 static int dpp_connector_match_groups(struct json_token
*own_root
,
8313 struct json_token
*peer_root
)
8315 struct json_token
*groups
, *token
;
8317 groups
= json_get_member(peer_root
, "groups");
8318 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
8319 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
8323 for (token
= groups
->child
; token
; token
= token
->sibling
) {
8324 struct json_token
*id
, *role
;
8326 id
= json_get_member(token
, "groupId");
8327 if (!id
|| id
->type
!= JSON_STRING
) {
8328 wpa_printf(MSG_DEBUG
,
8329 "DPP: Missing peer groupId string");
8333 role
= json_get_member(token
, "netRole");
8334 if (!role
|| role
->type
!= JSON_STRING
) {
8335 wpa_printf(MSG_DEBUG
,
8336 "DPP: Missing peer groups::netRole string");
8339 wpa_printf(MSG_DEBUG
,
8340 "DPP: peer connector group: groupId='%s' netRole='%s'",
8341 id
->string
, role
->string
);
8342 if (dpp_connector_compatible_group(own_root
, id
->string
,
8344 wpa_printf(MSG_DEBUG
,
8345 "DPP: Compatible group/netRole in own connector");
8354 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
8355 unsigned int hash_len
)
8357 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
8358 const char *info
= "DPP PMK";
8361 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8363 /* HKDF-Extract(<>, N.x) */
8364 os_memset(salt
, 0, hash_len
);
8365 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
8367 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
8370 /* HKDF-Expand(PRK, info, L) */
8371 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
8372 os_memset(prk
, 0, hash_len
);
8376 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
8382 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
8383 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
8385 struct wpabuf
*nkx
, *pkx
;
8389 u8 hash
[SHA256_MAC_LEN
];
8391 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8392 nkx
= dpp_get_pubkey_point(own_key
, 0);
8393 pkx
= dpp_get_pubkey_point(peer_key
, 0);
8396 addr
[0] = wpabuf_head(nkx
);
8397 len
[0] = wpabuf_len(nkx
) / 2;
8398 addr
[1] = wpabuf_head(pkx
);
8399 len
[1] = wpabuf_len(pkx
) / 2;
8400 if (len
[0] != len
[1])
8402 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
8403 addr
[0] = wpabuf_head(pkx
);
8404 addr
[1] = wpabuf_head(nkx
);
8406 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
8407 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
8408 res
= sha256_vector(2, addr
, len
, hash
);
8411 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
8412 os_memcpy(pmkid
, hash
, PMKID_LEN
);
8413 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
8422 enum dpp_status_error
8423 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
8424 const u8
*net_access_key
, size_t net_access_key_len
,
8425 const u8
*csign_key
, size_t csign_key_len
,
8426 const u8
*peer_connector
, size_t peer_connector_len
,
8429 struct json_token
*root
= NULL
, *netkey
, *token
;
8430 struct json_token
*own_root
= NULL
;
8431 enum dpp_status_error ret
= 255, res
;
8432 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
8433 struct wpabuf
*own_key_pub
= NULL
;
8434 const struct dpp_curve_params
*curve
, *own_curve
;
8435 struct dpp_signed_connector_info info
;
8436 const unsigned char *p
;
8437 EVP_PKEY
*csign
= NULL
;
8438 char *signed_connector
= NULL
;
8439 const char *pos
, *end
;
8440 unsigned char *own_conn
= NULL
;
8441 size_t own_conn_len
;
8443 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
8445 os_memset(intro
, 0, sizeof(*intro
));
8446 os_memset(&info
, 0, sizeof(info
));
8451 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
8453 wpa_printf(MSG_ERROR
,
8454 "DPP: Failed to parse local C-sign-key information");
8458 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
8459 net_access_key_len
);
8461 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8465 pos
= os_strchr(own_connector
, '.');
8467 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
8471 end
= os_strchr(pos
, '.');
8473 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
8476 own_conn
= base64_url_decode(pos
, end
- pos
, &own_conn_len
);
8478 wpa_printf(MSG_DEBUG
,
8479 "DPP: Failed to base64url decode own signedConnector JWS Payload");
8483 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
8485 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
8489 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
8490 peer_connector
, peer_connector_len
);
8491 signed_connector
= os_malloc(peer_connector_len
+ 1);
8492 if (!signed_connector
)
8494 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
8495 signed_connector
[peer_connector_len
] = '\0';
8497 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
8498 if (res
!= DPP_STATUS_OK
) {
8503 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
8505 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
8506 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8510 if (!dpp_connector_match_groups(own_root
, root
)) {
8511 wpa_printf(MSG_DEBUG
,
8512 "DPP: Peer connector does not include compatible group netrole with own connector");
8513 ret
= DPP_STATUS_NO_MATCH
;
8517 token
= json_get_member(root
, "expiry");
8518 if (!token
|| token
->type
!= JSON_STRING
) {
8519 wpa_printf(MSG_DEBUG
,
8520 "DPP: No expiry string found - connector does not expire");
8522 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
8523 if (dpp_key_expired(token
->string
, expiry
)) {
8524 wpa_printf(MSG_DEBUG
,
8525 "DPP: Connector (netAccessKey) has expired");
8526 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8531 netkey
= json_get_member(root
, "netAccessKey");
8532 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
8533 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
8534 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8538 peer_key
= dpp_parse_jwk(netkey
, &curve
);
8540 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8543 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
8545 if (own_curve
!= curve
) {
8546 wpa_printf(MSG_DEBUG
,
8547 "DPP: Mismatching netAccessKey curves (%s != %s)",
8548 own_curve
->name
, curve
->name
);
8549 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8553 /* ECDH: N = nk * PK */
8554 if (dpp_ecdh(own_key
, peer_key
, Nx
, &Nx_len
) < 0)
8557 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
8560 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8561 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
8562 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
8565 intro
->pmk_len
= curve
->hash_len
;
8567 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8568 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
8569 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
8573 ret
= DPP_STATUS_OK
;
8575 if (ret
!= DPP_STATUS_OK
)
8576 os_memset(intro
, 0, sizeof(*intro
));
8577 os_memset(Nx
, 0, sizeof(Nx
));
8579 os_free(signed_connector
);
8580 os_free(info
.payload
);
8581 EVP_PKEY_free(own_key
);
8582 wpabuf_free(own_key_pub
);
8583 EVP_PKEY_free(peer_key
);
8584 EVP_PKEY_free(csign
);
8586 json_free(own_root
);
8591 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
8595 size_t len
= curve
->prime_len
;
8599 switch (curve
->ike_group
) {
8601 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
8602 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
8605 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
8606 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
8609 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
8610 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
8613 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
8614 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
8617 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
8618 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
8621 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
8622 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
8628 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8631 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
8632 EC_GROUP_free(group
);
8637 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
8638 const u8
*mac_init
, const char *code
,
8639 const char *identifier
, BN_CTX
*bnctx
,
8640 EC_GROUP
**ret_group
)
8642 u8 hash
[DPP_MAX_HASH_LEN
];
8645 unsigned int num_elem
= 0;
8646 EC_POINT
*Qi
= NULL
;
8647 EVP_PKEY
*Pi
= NULL
;
8648 EC_KEY
*Pi_ec
= NULL
;
8649 const EC_POINT
*Pi_point
;
8650 BIGNUM
*hash_bn
= NULL
;
8651 const EC_GROUP
*group
= NULL
;
8652 EC_GROUP
*group2
= NULL
;
8654 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8656 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
8657 addr
[num_elem
] = mac_init
;
8658 len
[num_elem
] = ETH_ALEN
;
8661 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8663 addr
[num_elem
] = (const u8
*) identifier
;
8664 len
[num_elem
] = os_strlen(identifier
);
8667 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8668 addr
[num_elem
] = (const u8
*) code
;
8669 len
[num_elem
] = os_strlen(code
);
8671 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8673 wpa_hexdump_key(MSG_DEBUG
,
8674 "DPP: H(MAC-Initiator | [identifier |] code)",
8675 hash
, curve
->hash_len
);
8676 Pi
= dpp_pkex_get_role_elem(curve
, 1);
8679 dpp_debug_print_key("DPP: Pi", Pi
);
8680 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
8683 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
8685 group
= EC_KEY_get0_group(Pi_ec
);
8688 group2
= EC_GROUP_dup(group
);
8691 Qi
= EC_POINT_new(group2
);
8693 EC_GROUP_free(group2
);
8696 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8698 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
8700 if (EC_POINT_is_at_infinity(group
, Qi
)) {
8701 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
8704 dpp_debug_print_point("DPP: Qi", group
, Qi
);
8708 BN_clear_free(hash_bn
);
8709 if (ret_group
&& Qi
)
8710 *ret_group
= group2
;
8712 EC_GROUP_free(group2
);
8721 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
8722 const u8
*mac_resp
, const char *code
,
8723 const char *identifier
, BN_CTX
*bnctx
,
8724 EC_GROUP
**ret_group
)
8726 u8 hash
[DPP_MAX_HASH_LEN
];
8729 unsigned int num_elem
= 0;
8730 EC_POINT
*Qr
= NULL
;
8731 EVP_PKEY
*Pr
= NULL
;
8732 EC_KEY
*Pr_ec
= NULL
;
8733 const EC_POINT
*Pr_point
;
8734 BIGNUM
*hash_bn
= NULL
;
8735 const EC_GROUP
*group
= NULL
;
8736 EC_GROUP
*group2
= NULL
;
8738 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8740 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
8741 addr
[num_elem
] = mac_resp
;
8742 len
[num_elem
] = ETH_ALEN
;
8745 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8747 addr
[num_elem
] = (const u8
*) identifier
;
8748 len
[num_elem
] = os_strlen(identifier
);
8751 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8752 addr
[num_elem
] = (const u8
*) code
;
8753 len
[num_elem
] = os_strlen(code
);
8755 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8757 wpa_hexdump_key(MSG_DEBUG
,
8758 "DPP: H(MAC-Responder | [identifier |] code)",
8759 hash
, curve
->hash_len
);
8760 Pr
= dpp_pkex_get_role_elem(curve
, 0);
8763 dpp_debug_print_key("DPP: Pr", Pr
);
8764 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
8767 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
8769 group
= EC_KEY_get0_group(Pr_ec
);
8772 group2
= EC_GROUP_dup(group
);
8775 Qr
= EC_POINT_new(group2
);
8777 EC_GROUP_free(group2
);
8780 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8782 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
8784 if (EC_POINT_is_at_infinity(group
, Qr
)) {
8785 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
8788 dpp_debug_print_point("DPP: Qr", group
, Qr
);
8792 BN_clear_free(hash_bn
);
8793 if (ret_group
&& Qr
)
8794 *ret_group
= group2
;
8796 EC_GROUP_free(group2
);
8805 #ifdef CONFIG_TESTING_OPTIONS
8806 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
8807 const struct dpp_curve_params
*curve
)
8815 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8820 point
= EC_POINT_new(group
);
8823 if (!ctx
|| !point
|| !x
|| !y
)
8826 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
8829 /* Generate a random y coordinate that results in a point that is not
8832 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
8835 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
8837 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
8838 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
8839 * return an error from EC_POINT_set_affine_coordinates_GFp()
8840 * when the point is not on the curve. */
8842 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
8844 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
8847 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
8851 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
8852 curve
->prime_len
) < 0 ||
8853 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
8854 curve
->prime_len
) < 0)
8860 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
8863 EC_POINT_free(point
);
8865 EC_GROUP_free(group
);
8869 #endif /* CONFIG_TESTING_OPTIONS */
8872 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
8874 EC_KEY
*X_ec
= NULL
;
8875 const EC_POINT
*X_point
;
8876 BN_CTX
*bnctx
= NULL
;
8877 EC_GROUP
*group
= NULL
;
8878 EC_POINT
*Qi
= NULL
, *M
= NULL
;
8879 struct wpabuf
*M_buf
= NULL
;
8880 BIGNUM
*Mx
= NULL
, *My
= NULL
;
8881 struct wpabuf
*msg
= NULL
;
8883 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8885 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
8887 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8888 bnctx
= BN_CTX_new();
8891 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
8892 pkex
->identifier
, bnctx
, &group
);
8896 /* Generate a random ephemeral keypair x/X */
8897 #ifdef CONFIG_TESTING_OPTIONS
8898 if (dpp_pkex_ephemeral_key_override_len
) {
8899 const struct dpp_curve_params
*tmp_curve
;
8901 wpa_printf(MSG_INFO
,
8902 "DPP: TESTING - override ephemeral key x/X");
8903 pkex
->x
= dpp_set_keypair(&tmp_curve
,
8904 dpp_pkex_ephemeral_key_override
,
8905 dpp_pkex_ephemeral_key_override_len
);
8907 pkex
->x
= dpp_gen_keypair(curve
);
8909 #else /* CONFIG_TESTING_OPTIONS */
8910 pkex
->x
= dpp_gen_keypair(curve
);
8911 #endif /* CONFIG_TESTING_OPTIONS */
8916 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
8919 X_point
= EC_KEY_get0_public_key(X_ec
);
8922 dpp_debug_print_point("DPP: X", group
, X_point
);
8923 M
= EC_POINT_new(group
);
8926 if (!M
|| !Mx
|| !My
||
8927 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
8928 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
8930 dpp_debug_print_point("DPP: M", group
, M
);
8932 /* Initiator -> Responder: group, [identifier,] M */
8934 if (pkex
->identifier
)
8935 attr_len
+= 4 + os_strlen(pkex
->identifier
);
8936 attr_len
+= 4 + 2 * curve
->prime_len
;
8937 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
8941 #ifdef CONFIG_TESTING_OPTIONS
8942 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
8943 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
8944 goto skip_finite_cyclic_group
;
8946 #endif /* CONFIG_TESTING_OPTIONS */
8948 /* Finite Cyclic Group attribute */
8949 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
8950 wpabuf_put_le16(msg
, 2);
8951 wpabuf_put_le16(msg
, curve
->ike_group
);
8953 #ifdef CONFIG_TESTING_OPTIONS
8954 skip_finite_cyclic_group
:
8955 #endif /* CONFIG_TESTING_OPTIONS */
8957 /* Code Identifier attribute */
8958 if (pkex
->identifier
) {
8959 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
8960 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
8961 wpabuf_put_str(msg
, pkex
->identifier
);
8964 #ifdef CONFIG_TESTING_OPTIONS
8965 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8966 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
8969 #endif /* CONFIG_TESTING_OPTIONS */
8971 /* M in Encrypted Key attribute */
8972 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
8973 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
8975 #ifdef CONFIG_TESTING_OPTIONS
8976 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8977 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
8978 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
8982 #endif /* CONFIG_TESTING_OPTIONS */
8984 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
8985 curve
->prime_len
) < 0 ||
8986 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
8987 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
8988 curve
->prime_len
) < 0)
8999 EC_GROUP_free(group
);
9002 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
9009 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
9011 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
9015 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
9017 const char *identifier
,
9020 struct dpp_pkex
*pkex
;
9022 #ifdef CONFIG_TESTING_OPTIONS
9023 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
9024 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
9025 MAC2STR(dpp_pkex_own_mac_override
));
9026 own_mac
= dpp_pkex_own_mac_override
;
9028 #endif /* CONFIG_TESTING_OPTIONS */
9030 pkex
= os_zalloc(sizeof(*pkex
));
9033 pkex
->msg_ctx
= msg_ctx
;
9034 pkex
->initiator
= 1;
9036 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
9038 pkex
->identifier
= os_strdup(identifier
);
9039 if (!pkex
->identifier
)
9042 pkex
->code
= os_strdup(code
);
9045 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
9046 if (!pkex
->exchange_req
)
9050 dpp_pkex_free(pkex
);
9055 static struct wpabuf
*
9056 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
9057 enum dpp_status_error status
,
9058 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
9060 struct wpabuf
*msg
= NULL
;
9062 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9064 /* Initiator -> Responder: DPP Status, [identifier,] N */
9066 if (pkex
->identifier
)
9067 attr_len
+= 4 + os_strlen(pkex
->identifier
);
9068 attr_len
+= 4 + 2 * curve
->prime_len
;
9069 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
9073 #ifdef CONFIG_TESTING_OPTIONS
9074 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
9075 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
9079 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
9080 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
9083 #endif /* CONFIG_TESTING_OPTIONS */
9086 dpp_build_attr_status(msg
, status
);
9088 #ifdef CONFIG_TESTING_OPTIONS
9090 #endif /* CONFIG_TESTING_OPTIONS */
9092 /* Code Identifier attribute */
9093 if (pkex
->identifier
) {
9094 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
9095 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
9096 wpabuf_put_str(msg
, pkex
->identifier
);
9099 if (status
!= DPP_STATUS_OK
)
9100 goto skip_encrypted_key
;
9102 #ifdef CONFIG_TESTING_OPTIONS
9103 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
9104 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
9105 goto skip_encrypted_key
;
9107 #endif /* CONFIG_TESTING_OPTIONS */
9109 /* N in Encrypted Key attribute */
9110 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
9111 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
9113 #ifdef CONFIG_TESTING_OPTIONS
9114 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
9115 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
9116 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
9118 goto skip_encrypted_key
;
9120 #endif /* CONFIG_TESTING_OPTIONS */
9122 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
9123 curve
->prime_len
) < 0 ||
9124 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
9125 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
9126 curve
->prime_len
) < 0)
9130 if (status
== DPP_STATUS_BAD_GROUP
) {
9131 /* Finite Cyclic Group attribute */
9132 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
9133 wpabuf_put_le16(msg
, 2);
9134 wpabuf_put_le16(msg
, curve
->ike_group
);
9144 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
9145 const u8
*Mx
, size_t Mx_len
,
9146 const u8
*Nx
, size_t Nx_len
,
9148 const u8
*Kx
, size_t Kx_len
,
9149 u8
*z
, unsigned int hash_len
)
9151 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
9156 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9159 /* HKDF-Extract(<>, IKM=K.x) */
9160 os_memset(salt
, 0, hash_len
);
9161 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
9163 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
9165 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
9166 info
= os_malloc(info_len
);
9170 os_memcpy(pos
, mac_init
, ETH_ALEN
);
9172 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
9174 os_memcpy(pos
, Mx
, Mx_len
);
9176 os_memcpy(pos
, Nx
, Nx_len
);
9178 os_memcpy(pos
, code
, os_strlen(code
));
9180 /* HKDF-Expand(PRK, info, L) */
9182 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9184 else if (hash_len
== 48)
9185 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9187 else if (hash_len
== 64)
9188 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9193 os_memset(prk
, 0, hash_len
);
9197 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
9203 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
9204 const char *identifier
)
9206 if (!attr_id
&& identifier
) {
9207 wpa_printf(MSG_DEBUG
,
9208 "DPP: No PKEX code identifier received, but expected one");
9212 if (attr_id
&& !identifier
) {
9213 wpa_printf(MSG_DEBUG
,
9214 "DPP: PKEX code identifier received, but not expecting one");
9218 if (attr_id
&& identifier
&&
9219 (os_strlen(identifier
) != attr_id_len
||
9220 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
9221 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
9229 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
9230 struct dpp_bootstrap_info
*bi
,
9233 const char *identifier
,
9235 const u8
*buf
, size_t len
)
9237 const u8
*attr_group
, *attr_id
, *attr_key
;
9238 u16 attr_group_len
, attr_id_len
, attr_key_len
;
9239 const struct dpp_curve_params
*curve
= bi
->curve
;
9241 struct dpp_pkex
*pkex
= NULL
;
9242 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
9243 BN_CTX
*bnctx
= NULL
;
9244 EC_GROUP
*group
= NULL
;
9245 BIGNUM
*Mx
= NULL
, *My
= NULL
;
9246 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
9247 const EC_POINT
*Y_point
;
9248 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
9249 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
9253 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
9254 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9255 "PKEX counter t limit reached - ignore message");
9259 #ifdef CONFIG_TESTING_OPTIONS
9260 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
9261 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
9262 MAC2STR(dpp_pkex_peer_mac_override
));
9263 peer_mac
= dpp_pkex_peer_mac_override
;
9265 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
9266 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
9267 MAC2STR(dpp_pkex_own_mac_override
));
9268 own_mac
= dpp_pkex_own_mac_override
;
9270 #endif /* CONFIG_TESTING_OPTIONS */
9273 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
9275 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
9278 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
9280 if (!attr_group
|| attr_group_len
!= 2) {
9281 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9282 "Missing or invalid Finite Cyclic Group attribute");
9285 ike_group
= WPA_GET_LE16(attr_group
);
9286 if (ike_group
!= curve
->ike_group
) {
9287 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9288 "Mismatching PKEX curve: peer=%u own=%u",
9289 ike_group
, curve
->ike_group
);
9290 pkex
= os_zalloc(sizeof(*pkex
));
9295 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
9296 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
9297 if (!pkex
->exchange_resp
)
9302 /* M in Encrypted Key attribute */
9303 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
9305 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
9306 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
9307 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9308 "Missing Encrypted Key attribute");
9312 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
9313 bnctx
= BN_CTX_new();
9316 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
9322 X
= EC_POINT_new(group
);
9323 M
= EC_POINT_new(group
);
9324 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
9325 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
9326 if (!X
|| !M
|| !Mx
|| !My
||
9327 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
9328 EC_POINT_is_at_infinity(group
, M
) ||
9329 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
9330 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
9331 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
9332 EC_POINT_is_at_infinity(group
, X
) ||
9333 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
9334 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9335 "Invalid Encrypted Key value");
9339 dpp_debug_print_point("DPP: M", group
, M
);
9340 dpp_debug_print_point("DPP: X'", group
, X
);
9342 pkex
= os_zalloc(sizeof(*pkex
));
9345 pkex
->t
= bi
->pkex_t
;
9346 pkex
->msg_ctx
= msg_ctx
;
9348 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
9349 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
9351 pkex
->identifier
= os_strdup(identifier
);
9352 if (!pkex
->identifier
)
9355 pkex
->code
= os_strdup(code
);
9359 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
9361 X_ec
= EC_KEY_new();
9363 EC_KEY_set_group(X_ec
, group
) != 1 ||
9364 EC_KEY_set_public_key(X_ec
, X
) != 1)
9366 pkex
->x
= EVP_PKEY_new();
9368 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
9371 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
9372 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
9376 /* Generate a random ephemeral keypair y/Y */
9377 #ifdef CONFIG_TESTING_OPTIONS
9378 if (dpp_pkex_ephemeral_key_override_len
) {
9379 const struct dpp_curve_params
*tmp_curve
;
9381 wpa_printf(MSG_INFO
,
9382 "DPP: TESTING - override ephemeral key y/Y");
9383 pkex
->y
= dpp_set_keypair(&tmp_curve
,
9384 dpp_pkex_ephemeral_key_override
,
9385 dpp_pkex_ephemeral_key_override_len
);
9387 pkex
->y
= dpp_gen_keypair(curve
);
9389 #else /* CONFIG_TESTING_OPTIONS */
9390 pkex
->y
= dpp_gen_keypair(curve
);
9391 #endif /* CONFIG_TESTING_OPTIONS */
9396 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
9399 Y_point
= EC_KEY_get0_public_key(Y_ec
);
9402 dpp_debug_print_point("DPP: Y", group
, Y_point
);
9403 N
= EC_POINT_new(group
);
9406 if (!N
|| !Nx
|| !Ny
||
9407 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
9408 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
9410 dpp_debug_print_point("DPP: N", group
, N
);
9412 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
9414 if (!pkex
->exchange_resp
)
9418 if (dpp_ecdh(pkex
->y
, pkex
->x
, Kx
, &Kx_len
) < 0)
9421 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
9424 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9426 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
9427 pkex
->Mx
, curve
->prime_len
,
9428 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
9429 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
9430 os_memset(Kx
, 0, Kx_len
);
9434 pkex
->exchange_done
= 1;
9449 EC_GROUP_free(group
);
9452 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
9453 dpp_pkex_free(pkex
);
9459 static struct wpabuf
*
9460 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
9461 const struct wpabuf
*A_pub
, const u8
*u
)
9463 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9464 struct wpabuf
*msg
= NULL
;
9465 size_t clear_len
, attr_len
;
9466 struct wpabuf
*clear
= NULL
;
9472 /* {A, u, [bootstrapping info]}z */
9473 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
9474 clear
= wpabuf_alloc(clear_len
);
9475 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
9476 #ifdef CONFIG_TESTING_OPTIONS
9477 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
9479 #endif /* CONFIG_TESTING_OPTIONS */
9480 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
9484 #ifdef CONFIG_TESTING_OPTIONS
9485 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
9486 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
9487 goto skip_bootstrap_key
;
9489 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
9490 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
9491 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9492 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
9493 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
9495 goto skip_bootstrap_key
;
9497 #endif /* CONFIG_TESTING_OPTIONS */
9499 /* A in Bootstrap Key attribute */
9500 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9501 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
9502 wpabuf_put_buf(clear
, A_pub
);
9504 #ifdef CONFIG_TESTING_OPTIONS
9506 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
9507 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
9508 goto skip_i_auth_tag
;
9510 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
9511 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
9512 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
9513 wpabuf_put_le16(clear
, curve
->hash_len
);
9514 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
9515 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
9516 goto skip_i_auth_tag
;
9518 #endif /* CONFIG_TESTING_OPTIONS */
9520 /* u in I-Auth tag attribute */
9521 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
9522 wpabuf_put_le16(clear
, curve
->hash_len
);
9523 wpabuf_put_data(clear
, u
, curve
->hash_len
);
9525 #ifdef CONFIG_TESTING_OPTIONS
9527 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
9528 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
9529 goto skip_wrapped_data
;
9531 #endif /* CONFIG_TESTING_OPTIONS */
9533 addr
[0] = wpabuf_head_u8(msg
) + 2;
9534 len
[0] = DPP_HDR_LEN
;
9537 len
[1] = sizeof(octet
);
9538 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9539 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9541 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
9542 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9543 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9545 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
9546 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
9547 wpabuf_head(clear
), wpabuf_len(clear
),
9548 2, addr
, len
, wrapped
) < 0)
9550 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9551 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9553 #ifdef CONFIG_TESTING_OPTIONS
9554 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
9555 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
9556 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
9559 #endif /* CONFIG_TESTING_OPTIONS */
9572 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
9574 const u8
*buf
, size_t buflen
)
9576 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
9577 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
9578 EC_GROUP
*group
= NULL
;
9579 BN_CTX
*bnctx
= NULL
;
9580 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9581 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9582 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
9583 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
9584 EC_KEY
*Y_ec
= NULL
;
9585 size_t Jx_len
, Kx_len
;
9586 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
9589 u8 u
[DPP_MAX_HASH_LEN
];
9592 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
9595 #ifdef CONFIG_TESTING_OPTIONS
9596 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
9597 wpa_printf(MSG_INFO
,
9598 "DPP: TESTING - stop at PKEX Exchange Response");
9603 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
9604 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
9605 MAC2STR(dpp_pkex_peer_mac_override
));
9606 peer_mac
= dpp_pkex_peer_mac_override
;
9608 #endif /* CONFIG_TESTING_OPTIONS */
9610 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
9612 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
9614 if (!attr_status
|| attr_status_len
!= 1) {
9615 dpp_pkex_fail(pkex
, "No DPP Status attribute");
9618 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
9620 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
9621 attr_group
= dpp_get_attr(buf
, buflen
,
9622 DPP_ATTR_FINITE_CYCLIC_GROUP
,
9624 if (attr_group
&& attr_group_len
== 2) {
9625 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9626 "Peer indicated mismatching PKEX group - proposed %u",
9627 WPA_GET_LE16(attr_group
));
9632 if (attr_status
[0] != DPP_STATUS_OK
) {
9633 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
9638 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
9640 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
9641 pkex
->identifier
)) {
9642 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
9646 /* N in Encrypted Key attribute */
9647 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
9649 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
9650 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
9654 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
9655 bnctx
= BN_CTX_new();
9658 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
9659 pkex
->identifier
, bnctx
, &group
);
9664 Y
= EC_POINT_new(group
);
9665 N
= EC_POINT_new(group
);
9666 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
9667 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
9668 if (!Y
|| !N
|| !Nx
|| !Ny
||
9669 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
9670 EC_POINT_is_at_infinity(group
, N
) ||
9671 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
9672 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
9673 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
9674 EC_POINT_is_at_infinity(group
, Y
) ||
9675 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
9676 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
9680 dpp_debug_print_point("DPP: N", group
, N
);
9681 dpp_debug_print_point("DPP: Y'", group
, Y
);
9683 pkex
->exchange_done
= 1;
9685 /* ECDH: J = a * Y’ */
9686 Y_ec
= EC_KEY_new();
9688 EC_KEY_set_group(Y_ec
, group
) != 1 ||
9689 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
9691 pkex
->y
= EVP_PKEY_new();
9693 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
9695 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->y
, Jx
, &Jx_len
) < 0)
9698 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9701 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
9702 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
9703 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9704 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9705 if (!A_pub
|| !Y_pub
|| !X_pub
)
9707 addr
[0] = pkex
->own_mac
;
9709 addr
[1] = wpabuf_head(A_pub
);
9710 len
[1] = wpabuf_len(A_pub
) / 2;
9711 addr
[2] = wpabuf_head(Y_pub
);
9712 len
[2] = wpabuf_len(Y_pub
) / 2;
9713 addr
[3] = wpabuf_head(X_pub
);
9714 len
[3] = wpabuf_len(X_pub
) / 2;
9715 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9717 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
9720 if (dpp_ecdh(pkex
->x
, pkex
->y
, Kx
, &Kx_len
) < 0)
9723 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
9726 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9728 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
9729 pkex
->Mx
, curve
->prime_len
,
9730 attr_key
/* N.x */, attr_key_len
/ 2,
9731 pkex
->code
, Kx
, Kx_len
,
9732 pkex
->z
, curve
->hash_len
);
9733 os_memset(Kx
, 0, Kx_len
);
9737 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
9752 EC_GROUP_free(group
);
9755 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
9760 static struct wpabuf
*
9761 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
9762 const struct wpabuf
*B_pub
, const u8
*v
)
9764 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9765 struct wpabuf
*msg
= NULL
;
9770 struct wpabuf
*clear
= NULL
;
9771 size_t clear_len
, attr_len
;
9773 /* {B, v [bootstrapping info]}z */
9774 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
9775 clear
= wpabuf_alloc(clear_len
);
9776 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
9777 #ifdef CONFIG_TESTING_OPTIONS
9778 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
9780 #endif /* CONFIG_TESTING_OPTIONS */
9781 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
9785 #ifdef CONFIG_TESTING_OPTIONS
9786 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9787 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
9788 goto skip_bootstrap_key
;
9790 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9791 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
9792 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9793 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
9794 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
9796 goto skip_bootstrap_key
;
9798 #endif /* CONFIG_TESTING_OPTIONS */
9800 /* B in Bootstrap Key attribute */
9801 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9802 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
9803 wpabuf_put_buf(clear
, B_pub
);
9805 #ifdef CONFIG_TESTING_OPTIONS
9807 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
9808 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
9809 goto skip_r_auth_tag
;
9811 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
9812 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
9813 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9814 wpabuf_put_le16(clear
, curve
->hash_len
);
9815 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
9816 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
9817 goto skip_r_auth_tag
;
9819 #endif /* CONFIG_TESTING_OPTIONS */
9821 /* v in R-Auth tag attribute */
9822 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9823 wpabuf_put_le16(clear
, curve
->hash_len
);
9824 wpabuf_put_data(clear
, v
, curve
->hash_len
);
9826 #ifdef CONFIG_TESTING_OPTIONS
9828 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
9829 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
9830 goto skip_wrapped_data
;
9832 #endif /* CONFIG_TESTING_OPTIONS */
9834 addr
[0] = wpabuf_head_u8(msg
) + 2;
9835 len
[0] = DPP_HDR_LEN
;
9838 len
[1] = sizeof(octet
);
9839 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9840 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9842 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
9843 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9844 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9846 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
9847 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
9848 wpabuf_head(clear
), wpabuf_len(clear
),
9849 2, addr
, len
, wrapped
) < 0)
9851 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9852 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9854 #ifdef CONFIG_TESTING_OPTIONS
9855 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
9856 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
9857 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
9860 #endif /* CONFIG_TESTING_OPTIONS */
9873 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
9875 const u8
*buf
, size_t buflen
)
9877 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9878 size_t Jx_len
, Lx_len
;
9879 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
9880 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
9881 const u8
*wrapped_data
, *b_key
, *peer_u
;
9882 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
9886 u8
*unwrapped
= NULL
;
9887 size_t unwrapped_len
= 0;
9888 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9889 struct wpabuf
*B_pub
= NULL
;
9890 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
9892 #ifdef CONFIG_TESTING_OPTIONS
9893 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
9894 wpa_printf(MSG_INFO
,
9895 "DPP: TESTING - stop at PKEX CR Request");
9899 #endif /* CONFIG_TESTING_OPTIONS */
9901 if (!pkex
->exchange_done
|| pkex
->failed
||
9902 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
9905 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
9907 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
9909 "Missing or invalid required Wrapped Data attribute");
9913 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9914 wrapped_data
, wrapped_data_len
);
9915 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
9916 unwrapped
= os_malloc(unwrapped_len
);
9921 len
[0] = DPP_HDR_LEN
;
9924 len
[1] = sizeof(octet
);
9925 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9926 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9928 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
9929 wrapped_data
, wrapped_data_len
,
9930 2, addr
, len
, unwrapped
) < 0) {
9932 "AES-SIV decryption failed - possible PKEX code mismatch");
9937 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
9938 unwrapped
, unwrapped_len
);
9940 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
9941 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
9945 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
9947 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
9948 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
9951 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
9953 if (!pkex
->peer_bootstrap_key
) {
9954 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
9957 dpp_debug_print_key("DPP: Peer bootstrap public key",
9958 pkex
->peer_bootstrap_key
);
9960 /* ECDH: J' = y * A' */
9961 if (dpp_ecdh(pkex
->y
, pkex
->peer_bootstrap_key
, Jx
, &Jx_len
) < 0)
9964 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9967 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
9968 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
9969 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9970 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9971 if (!A_pub
|| !Y_pub
|| !X_pub
)
9973 addr
[0] = pkex
->peer_mac
;
9975 addr
[1] = wpabuf_head(A_pub
);
9976 len
[1] = wpabuf_len(A_pub
) / 2;
9977 addr
[2] = wpabuf_head(Y_pub
);
9978 len
[2] = wpabuf_len(Y_pub
) / 2;
9979 addr
[3] = wpabuf_head(X_pub
);
9980 len
[3] = wpabuf_len(X_pub
) / 2;
9981 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9984 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
9986 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
9987 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
9988 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
9989 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
9990 u
, curve
->hash_len
);
9991 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
9995 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
9997 /* ECDH: L = b * X' */
9998 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->x
, Lx
, &Lx_len
) < 0)
10001 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
10004 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
10005 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
10008 addr
[0] = pkex
->own_mac
;
10010 addr
[1] = wpabuf_head(B_pub
);
10011 len
[1] = wpabuf_len(B_pub
) / 2;
10012 addr
[2] = wpabuf_head(X_pub
);
10013 len
[2] = wpabuf_len(X_pub
) / 2;
10014 addr
[3] = wpabuf_head(Y_pub
);
10015 len
[3] = wpabuf_len(Y_pub
) / 2;
10016 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
10018 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
10020 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
10025 os_free(unwrapped
);
10026 wpabuf_free(A_pub
);
10027 wpabuf_free(B_pub
);
10028 wpabuf_free(X_pub
);
10029 wpabuf_free(Y_pub
);
10032 wpa_printf(MSG_DEBUG
,
10033 "DPP: PKEX Commit-Reveal Request processing failed");
10038 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
10039 const u8
*buf
, size_t buflen
)
10041 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
10042 const u8
*wrapped_data
, *b_key
, *peer_v
;
10043 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
10047 u8
*unwrapped
= NULL
;
10048 size_t unwrapped_len
= 0;
10050 u8 v
[DPP_MAX_HASH_LEN
];
10052 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
10053 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
10055 #ifdef CONFIG_TESTING_OPTIONS
10056 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
10057 wpa_printf(MSG_INFO
,
10058 "DPP: TESTING - stop at PKEX CR Response");
10062 #endif /* CONFIG_TESTING_OPTIONS */
10064 if (!pkex
->exchange_done
|| pkex
->failed
||
10065 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
10068 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
10069 &wrapped_data_len
);
10070 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
10071 dpp_pkex_fail(pkex
,
10072 "Missing or invalid required Wrapped Data attribute");
10076 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
10077 wrapped_data
, wrapped_data_len
);
10078 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
10079 unwrapped
= os_malloc(unwrapped_len
);
10084 len
[0] = DPP_HDR_LEN
;
10087 len
[1] = sizeof(octet
);
10088 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
10089 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
10091 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
10092 wrapped_data
, wrapped_data_len
,
10093 2, addr
, len
, unwrapped
) < 0) {
10094 dpp_pkex_fail(pkex
,
10095 "AES-SIV decryption failed - possible PKEX code mismatch");
10099 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
10100 unwrapped
, unwrapped_len
);
10102 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
10103 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
10107 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
10109 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
10110 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
10113 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
10115 if (!pkex
->peer_bootstrap_key
) {
10116 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
10119 dpp_debug_print_key("DPP: Peer bootstrap public key",
10120 pkex
->peer_bootstrap_key
);
10122 /* ECDH: L' = x * B' */
10123 if (dpp_ecdh(pkex
->x
, pkex
->peer_bootstrap_key
, Lx
, &Lx_len
) < 0)
10126 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
10129 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
10130 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
10131 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
10132 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
10133 if (!B_pub
|| !X_pub
|| !Y_pub
)
10135 addr
[0] = pkex
->peer_mac
;
10137 addr
[1] = wpabuf_head(B_pub
);
10138 len
[1] = wpabuf_len(B_pub
) / 2;
10139 addr
[2] = wpabuf_head(X_pub
);
10140 len
[2] = wpabuf_len(X_pub
) / 2;
10141 addr
[3] = wpabuf_head(Y_pub
);
10142 len
[3] = wpabuf_len(Y_pub
) / 2;
10143 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
10146 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
10148 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
10149 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
10150 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
10151 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
10152 v
, curve
->hash_len
);
10153 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
10157 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
10161 wpabuf_free(B_pub
);
10162 wpabuf_free(X_pub
);
10163 wpabuf_free(Y_pub
);
10164 os_free(unwrapped
);
10171 void dpp_pkex_free(struct dpp_pkex
*pkex
)
10176 os_free(pkex
->identifier
);
10177 os_free(pkex
->code
);
10178 EVP_PKEY_free(pkex
->x
);
10179 EVP_PKEY_free(pkex
->y
);
10180 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
10181 wpabuf_free(pkex
->exchange_req
);
10182 wpabuf_free(pkex
->exchange_resp
);
10187 #ifdef CONFIG_TESTING_OPTIONS
10188 char * dpp_corrupt_connector_signature(const char *connector
)
10190 char *tmp
, *pos
, *signed3
= NULL
;
10191 unsigned char *signature
= NULL
;
10192 size_t signature_len
= 0, signed3_len
;
10194 tmp
= os_zalloc(os_strlen(connector
) + 5);
10197 os_memcpy(tmp
, connector
, os_strlen(connector
));
10199 pos
= os_strchr(tmp
, '.');
10203 pos
= os_strchr(pos
+ 1, '.');
10208 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
10210 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
10211 if (!signature
|| signature_len
== 0)
10213 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
10214 signature
, signature_len
);
10215 signature
[signature_len
- 1] ^= 0x01;
10216 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
10217 signature
, signature_len
);
10218 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
10221 os_memcpy(pos
, signed3
, signed3_len
);
10222 pos
[signed3_len
] = '\0';
10223 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
10227 os_free(signature
);
10235 #endif /* CONFIG_TESTING_OPTIONS */
10240 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
10241 size_t net_access_key_len
)
10243 struct wpabuf
*pub
= NULL
;
10245 struct dpp_pfs
*pfs
;
10247 pfs
= os_zalloc(sizeof(*pfs
));
10251 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
10252 net_access_key_len
);
10254 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
10257 EVP_PKEY_free(own_key
);
10259 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
10263 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
10264 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
10268 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
10271 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
10272 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
10273 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
10274 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
10275 wpabuf_put_buf(pfs
->ie
, pub
);
10277 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
10288 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
10290 if (peer_ie_len
< 2)
10292 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
10293 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
10297 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
10299 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
10300 if (!pfs
->secret
) {
10301 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
10304 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
10309 void dpp_pfs_free(struct dpp_pfs
*pfs
)
10313 crypto_ecdh_deinit(pfs
->ecdh
);
10314 wpabuf_free(pfs
->ie
);
10315 wpabuf_clear_free(pfs
->secret
);
10319 #endif /* CONFIG_DPP2 */
10322 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
10324 struct dpp_bootstrap_info
*bi
;
10325 unsigned int max_id
= 0;
10327 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10328 if (bi
->id
> max_id
)
10335 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
10337 struct dpp_bootstrap_info
*bi
, *tmp
;
10343 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
10344 struct dpp_bootstrap_info
, list
) {
10345 if (id
&& bi
->id
!= id
)
10349 if (dpp
->remove_bi
)
10350 dpp
->remove_bi(dpp
->cb_ctx
, bi
);
10351 #endif /* CONFIG_DPP2 */
10352 dl_list_del(&bi
->list
);
10353 dpp_bootstrap_info_free(bi
);
10357 return 0; /* flush succeeds regardless of entries found */
10358 return found
? 0 : -1;
10362 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
10365 struct dpp_bootstrap_info
*bi
;
10370 bi
= dpp_parse_uri(uri
);
10374 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
10375 bi
->id
= dpp_next_id(dpp
);
10376 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10381 struct dpp_bootstrap_info
* dpp_add_nfc_uri(struct dpp_global
*dpp
,
10384 struct dpp_bootstrap_info
*bi
;
10389 bi
= dpp_parse_uri(uri
);
10393 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
10394 bi
->id
= dpp_next_id(dpp
);
10395 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10400 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
10402 char *mac
= NULL
, *info
= NULL
, *curve
= NULL
;
10404 u8
*privkey
= NULL
;
10405 size_t privkey_len
= 0;
10407 struct dpp_bootstrap_info
*bi
;
10412 bi
= os_zalloc(sizeof(*bi
));
10416 if (os_strstr(cmd
, "type=qrcode"))
10417 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
10418 else if (os_strstr(cmd
, "type=pkex"))
10419 bi
->type
= DPP_BOOTSTRAP_PKEX
;
10420 else if (os_strstr(cmd
, "type=nfc-uri"))
10421 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
10425 bi
->chan
= get_param(cmd
, " chan=");
10426 mac
= get_param(cmd
, " mac=");
10427 info
= get_param(cmd
, " info=");
10428 curve
= get_param(cmd
, " curve=");
10429 key
= get_param(cmd
, " key=");
10432 privkey_len
= os_strlen(key
) / 2;
10433 privkey
= os_malloc(privkey_len
);
10435 hexstr2bin(key
, privkey
, privkey_len
) < 0)
10439 if (dpp_keygen(bi
, curve
, privkey
, privkey_len
) < 0 ||
10440 dpp_parse_uri_chan_list(bi
, bi
->chan
) < 0 ||
10441 dpp_parse_uri_mac(bi
, mac
) < 0 ||
10442 dpp_parse_uri_info(bi
, info
) < 0 ||
10443 dpp_gen_uri(bi
) < 0)
10446 bi
->id
= dpp_next_id(dpp
);
10447 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10454 str_clear_free(key
);
10455 bin_clear_free(privkey
, privkey_len
);
10456 dpp_bootstrap_info_free(bi
);
10461 struct dpp_bootstrap_info
*
10462 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
10464 struct dpp_bootstrap_info
*bi
;
10469 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10477 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
10479 unsigned int id_val
;
10481 if (os_strcmp(id
, "*") == 0) {
10489 return dpp_bootstrap_del(dpp
, id_val
);
10493 struct dpp_bootstrap_info
*
10494 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
10497 struct dpp_bootstrap_info
*bi
;
10499 bi
= os_zalloc(sizeof(*bi
));
10502 bi
->id
= dpp_next_id(dpp
);
10503 bi
->type
= DPP_BOOTSTRAP_PKEX
;
10504 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
10506 bi
->freq
[0] = freq
;
10507 bi
->curve
= pkex
->own_bi
->curve
;
10508 bi
->pubkey
= pkex
->peer_bootstrap_key
;
10509 pkex
->peer_bootstrap_key
= NULL
;
10510 if (dpp_bootstrap_key_hash(bi
) < 0) {
10511 dpp_bootstrap_info_free(bi
);
10514 dpp_pkex_free(pkex
);
10515 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10520 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
10522 struct dpp_bootstrap_info
*bi
;
10524 bi
= dpp_bootstrap_get_id(dpp
, id
);
10531 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
10532 char *reply
, int reply_size
)
10534 struct dpp_bootstrap_info
*bi
;
10535 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
10537 bi
= dpp_bootstrap_get_id(dpp
, id
);
10540 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
10542 return os_snprintf(reply
, reply_size
, "type=%s\n"
10543 "mac_addr=" MACSTR
"\n"
10549 dpp_bootstrap_type_txt(bi
->type
),
10550 MAC2STR(bi
->mac_addr
),
10551 bi
->info
? bi
->info
: "",
10553 bi
->num_freq
== 1 ? bi
->freq
[0] : 0,
10559 int dpp_bootstrap_set(struct dpp_global
*dpp
, int id
, const char *params
)
10561 struct dpp_bootstrap_info
*bi
;
10563 bi
= dpp_bootstrap_get_id(dpp
, id
);
10567 str_clear_free(bi
->configurator_params
);
10570 bi
->configurator_params
= os_strdup(params
);
10571 return bi
->configurator_params
? 0 : -1;
10574 bi
->configurator_params
= NULL
;
10579 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
10580 const u8
*r_bootstrap
,
10581 struct dpp_bootstrap_info
**own_bi
,
10582 struct dpp_bootstrap_info
**peer_bi
)
10584 struct dpp_bootstrap_info
*bi
;
10591 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10592 if (!*own_bi
&& bi
->own
&&
10593 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
10594 SHA256_MAC_LEN
) == 0) {
10595 wpa_printf(MSG_DEBUG
,
10596 "DPP: Found matching own bootstrapping information");
10600 if (!*peer_bi
&& !bi
->own
&&
10601 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
10602 SHA256_MAC_LEN
) == 0) {
10603 wpa_printf(MSG_DEBUG
,
10604 "DPP: Found matching peer bootstrapping information");
10608 if (*own_bi
&& *peer_bi
)
10615 struct dpp_bootstrap_info
* dpp_bootstrap_find_chirp(struct dpp_global
*dpp
,
10618 struct dpp_bootstrap_info
*bi
;
10623 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10624 if (!bi
->own
&& os_memcmp(bi
->pubkey_hash_chirp
, hash
,
10625 SHA256_MAC_LEN
) == 0)
10631 #endif /* CONFIG_DPP2 */
10634 static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info
*own_bi
,
10635 struct dpp_bootstrap_info
*peer_bi
)
10637 unsigned int i
, freq
= 0;
10638 enum hostapd_hw_mode mode
;
10639 u8 op_class
, channel
;
10642 if (peer_bi
->num_freq
== 0)
10643 return 0; /* no channel preference/constraint */
10645 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
10646 if (own_bi
->num_freq
== 0 ||
10647 freq_included(own_bi
->freq
, own_bi
->num_freq
,
10648 peer_bi
->freq
[i
])) {
10649 freq
= peer_bi
->freq
[i
];
10654 wpa_printf(MSG_DEBUG
, "DPP: No common channel found");
10658 mode
= ieee80211_freq_to_channel_ext(freq
, 0, 0, &op_class
, &channel
);
10659 if (mode
== NUM_HOSTAPD_MODES
) {
10660 wpa_printf(MSG_DEBUG
,
10661 "DPP: Could not determine operating class or channel number for %u MHz",
10665 wpa_printf(MSG_DEBUG
,
10666 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
10667 freq
, op_class
, channel
);
10668 os_snprintf(chan
, sizeof(chan
), "%u/%u", op_class
, channel
);
10669 os_free(own_bi
->chan
);
10670 own_bi
->chan
= os_strdup(chan
);
10671 own_bi
->freq
[0] = freq
;
10672 own_bi
->num_freq
= 1;
10673 os_free(peer_bi
->chan
);
10674 peer_bi
->chan
= os_strdup(chan
);
10675 peer_bi
->freq
[0] = freq
;
10676 peer_bi
->num_freq
= 1;
10678 return dpp_gen_uri(own_bi
);
10682 static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info
*own_bi
,
10683 struct dpp_bootstrap_info
*peer_bi
)
10685 if (peer_bi
->curve
== own_bi
->curve
)
10688 wpa_printf(MSG_DEBUG
,
10689 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
10691 EVP_PKEY_free(own_bi
->pubkey
);
10692 own_bi
->pubkey
= NULL
;
10694 if (dpp_keygen(own_bi
, peer_bi
->curve
->name
, NULL
, 0) < 0 ||
10695 dpp_gen_uri(own_bi
) < 0)
10700 dl_list_del(&own_bi
->list
);
10701 dpp_bootstrap_info_free(own_bi
);
10706 int dpp_nfc_update_bi(struct dpp_bootstrap_info
*own_bi
,
10707 struct dpp_bootstrap_info
*peer_bi
)
10709 if (dpp_nfc_update_bi_channel(own_bi
, peer_bi
) < 0 ||
10710 dpp_nfc_update_bi_key(own_bi
, peer_bi
) < 0)
10716 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
10718 struct dpp_configurator
*conf
;
10719 unsigned int max_id
= 0;
10721 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
10723 if (conf
->id
> max_id
)
10730 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
10732 char *curve
= NULL
;
10734 u8
*privkey
= NULL
;
10735 size_t privkey_len
= 0;
10737 struct dpp_configurator
*conf
= NULL
;
10739 curve
= get_param(cmd
, " curve=");
10740 key
= get_param(cmd
, " key=");
10743 privkey_len
= os_strlen(key
) / 2;
10744 privkey
= os_malloc(privkey_len
);
10746 hexstr2bin(key
, privkey
, privkey_len
) < 0)
10750 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
10754 conf
->id
= dpp_next_configurator_id(dpp
);
10755 dl_list_add(&dpp
->configurator
, &conf
->list
);
10760 str_clear_free(key
);
10761 bin_clear_free(privkey
, privkey_len
);
10762 dpp_configurator_free(conf
);
10767 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
10769 struct dpp_configurator
*conf
, *tmp
;
10775 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
10776 struct dpp_configurator
, list
) {
10777 if (id
&& conf
->id
!= id
)
10780 dl_list_del(&conf
->list
);
10781 dpp_configurator_free(conf
);
10785 return 0; /* flush succeeds regardless of entries found */
10786 return found
? 0 : -1;
10790 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
10792 unsigned int id_val
;
10794 if (os_strcmp(id
, "*") == 0) {
10802 return dpp_configurator_del(dpp
, id_val
);
10806 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
10807 char *buf
, size_t buflen
)
10809 struct dpp_configurator
*conf
;
10811 conf
= dpp_configurator_get_id(dpp
, id
);
10815 return dpp_configurator_get_key(conf
, buf
, buflen
);
10821 int dpp_configurator_from_backup(struct dpp_global
*dpp
,
10822 struct dpp_asymmetric_key
*key
)
10824 struct dpp_configurator
*conf
;
10825 const EC_KEY
*eckey
;
10826 const EC_GROUP
*group
;
10828 const struct dpp_curve_params
*curve
;
10832 eckey
= EVP_PKEY_get0_EC_KEY(key
->csign
);
10835 group
= EC_KEY_get0_group(eckey
);
10838 nid
= EC_GROUP_get_curve_name(group
);
10839 curve
= dpp_get_curve_nid(nid
);
10841 wpa_printf(MSG_INFO
, "DPP: Unsupported group in c-sign-key");
10845 conf
= os_zalloc(sizeof(*conf
));
10848 conf
->curve
= curve
;
10849 conf
->csign
= key
->csign
;
10852 if (dpp_configurator_gen_kid(conf
) < 0) {
10853 dpp_configurator_free(conf
);
10857 conf
->id
= dpp_next_configurator_id(dpp
);
10858 dl_list_add(&dpp
->configurator
, &conf
->list
);
10863 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
10864 void *timeout_ctx
);
10867 static void dpp_connection_free(struct dpp_connection
*conn
)
10869 if (conn
->sock
>= 0) {
10870 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
10872 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
10873 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
10876 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout
,
10878 wpabuf_free(conn
->msg
);
10879 wpabuf_free(conn
->msg_out
);
10880 dpp_auth_deinit(conn
->auth
);
10885 static void dpp_connection_remove(struct dpp_connection
*conn
)
10887 dl_list_del(&conn
->list
);
10888 dpp_connection_free(conn
);
10892 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
10894 struct dpp_connection
*conn
, *tmp
;
10896 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
10898 dpp_connection_remove(conn
);
10902 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
10904 struct dpp_connection
*conn
, *tmp
;
10906 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
10908 dpp_connection_remove(conn
);
10913 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
10915 struct dpp_relay_controller
*ctrl
, *tmp
;
10920 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
10921 struct dpp_relay_controller
, list
) {
10922 dl_list_del(&ctrl
->list
);
10923 dpp_relay_controller_free(ctrl
);
10927 #endif /* CONFIG_DPP2 */
10930 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
10932 struct dpp_global
*dpp
;
10934 dpp
= os_zalloc(sizeof(*dpp
));
10937 dpp
->msg_ctx
= config
->msg_ctx
;
10939 dpp
->cb_ctx
= config
->cb_ctx
;
10940 dpp
->process_conf_obj
= config
->process_conf_obj
;
10941 dpp
->remove_bi
= config
->remove_bi
;
10942 #endif /* CONFIG_DPP2 */
10944 dl_list_init(&dpp
->bootstrap
);
10945 dl_list_init(&dpp
->configurator
);
10947 dl_list_init(&dpp
->controllers
);
10948 dl_list_init(&dpp
->tcp_init
);
10949 #endif /* CONFIG_DPP2 */
10955 void dpp_global_clear(struct dpp_global
*dpp
)
10960 dpp_bootstrap_del(dpp
, 0);
10961 dpp_configurator_del(dpp
, 0);
10963 dpp_tcp_init_flush(dpp
);
10964 dpp_relay_flush_controllers(dpp
);
10965 dpp_controller_stop(dpp
);
10966 #endif /* CONFIG_DPP2 */
10970 void dpp_global_deinit(struct dpp_global
*dpp
)
10972 dpp_global_clear(dpp
);
10979 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
10980 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
10981 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
10985 int dpp_relay_add_controller(struct dpp_global
*dpp
,
10986 struct dpp_relay_config
*config
)
10988 struct dpp_relay_controller
*ctrl
;
10993 ctrl
= os_zalloc(sizeof(*ctrl
));
10996 dl_list_init(&ctrl
->conn
);
10997 ctrl
->global
= dpp
;
10998 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
10999 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
11000 ctrl
->cb_ctx
= config
->cb_ctx
;
11001 ctrl
->tx
= config
->tx
;
11002 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
11003 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
11008 static struct dpp_relay_controller
*
11009 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
11011 struct dpp_relay_controller
*ctrl
;
11016 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
11018 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
11026 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
11028 struct dpp_authentication
*auth
= conn
->auth
;
11030 if (auth
->peer_version
>= 2 &&
11031 auth
->conf_resp_status
== DPP_STATUS_OK
) {
11032 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
11033 auth
->waiting_conf_result
= 1;
11037 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
11038 dpp_connection_remove(conn
);
11042 static int dpp_tcp_send(struct dpp_connection
*conn
)
11046 if (!conn
->msg_out
) {
11047 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
11048 conn
->write_eloop
= 0;
11051 res
= send(conn
->sock
,
11052 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
11053 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
11055 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
11057 dpp_connection_remove(conn
);
11061 conn
->msg_out_pos
+= res
;
11062 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
11063 wpa_printf(MSG_DEBUG
,
11064 "DPP: %u/%u bytes of message sent to Controller",
11065 (unsigned int) conn
->msg_out_pos
,
11066 (unsigned int) wpabuf_len(conn
->msg_out
));
11067 if (!conn
->write_eloop
&&
11068 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11069 dpp_conn_tx_ready
, conn
, NULL
) == 0)
11070 conn
->write_eloop
= 1;
11074 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
11075 wpabuf_free(conn
->msg_out
);
11076 conn
->msg_out
= NULL
;
11077 conn
->msg_out_pos
= 0;
11078 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
11079 conn
->write_eloop
= 0;
11080 if (!conn
->read_eloop
&&
11081 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
11082 dpp_controller_rx
, conn
, NULL
) == 0)
11083 conn
->read_eloop
= 1;
11084 if (conn
->on_tcp_tx_complete_remove
) {
11085 dpp_connection_remove(conn
);
11086 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
11088 dpp_controller_gas_done(conn
);
11089 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
11090 conn
->on_tcp_tx_complete_auth_ok
= 0;
11091 dpp_controller_auth_success(conn
, 1);
11098 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
11100 struct dpp_authentication
*auth
= conn
->auth
;
11101 struct wpabuf
*buf
;
11102 int netrole_ap
= 0; /* TODO: make this configurable */
11104 buf
= dpp_build_conf_req_helper(auth
, "Test", netrole_ap
, NULL
, NULL
);
11106 wpa_printf(MSG_DEBUG
,
11107 "DPP: No configuration request data available");
11111 wpabuf_free(conn
->msg_out
);
11112 conn
->msg_out_pos
= 0;
11113 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(buf
) - 1);
11114 if (!conn
->msg_out
) {
11118 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(buf
) - 1);
11119 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(buf
) + 1,
11120 wpabuf_len(buf
) - 1);
11123 if (dpp_tcp_send(conn
) == 1) {
11124 if (!conn
->write_eloop
) {
11125 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11129 conn
->write_eloop
= 1;
11135 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
11138 struct dpp_authentication
*auth
= conn
->auth
;
11143 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
11144 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
11145 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
11146 #ifdef CONFIG_TESTING_OPTIONS
11147 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
11148 wpa_printf(MSG_INFO
,
11149 "DPP: TESTING - stop at Authentication Confirm");
11150 if (auth
->configurator
) {
11151 /* Prevent GAS response */
11152 auth
->auth_success
= 0;
11156 #endif /* CONFIG_TESTING_OPTIONS */
11158 if (!auth
->configurator
)
11159 dpp_controller_start_gas_client(conn
);
11163 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
11165 struct dpp_connection
*conn
= eloop_ctx
;
11167 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
11168 dpp_tcp_send(conn
);
11172 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
11173 const struct hostapd_ip_addr
*ipaddr
,
11176 struct sockaddr_in
*dst
;
11178 struct sockaddr_in6
*dst6
;
11179 #endif /* CONFIG_IPV6 */
11181 switch (ipaddr
->af
) {
11183 dst
= (struct sockaddr_in
*) addr
;
11184 os_memset(dst
, 0, sizeof(*dst
));
11185 dst
->sin_family
= AF_INET
;
11186 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
11187 dst
->sin_port
= htons(port
);
11188 *addrlen
= sizeof(*dst
);
11192 dst6
= (struct sockaddr_in6
*) addr
;
11193 os_memset(dst6
, 0, sizeof(*dst6
));
11194 dst6
->sin6_family
= AF_INET6
;
11195 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
11196 sizeof(struct in6_addr
));
11197 dst6
->sin6_port
= htons(port
);
11198 *addrlen
= sizeof(*dst6
);
11200 #endif /* CONFIG_IPV6 */
11209 static struct dpp_connection
*
11210 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
11213 struct dpp_connection
*conn
;
11214 struct sockaddr_storage addr
;
11218 if (dl_list_len(&ctrl
->conn
) >= 15) {
11219 wpa_printf(MSG_DEBUG
,
11220 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
11224 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
11225 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
11228 conn
= os_zalloc(sizeof(*conn
));
11232 conn
->global
= ctrl
->global
;
11233 conn
->relay
= ctrl
;
11234 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
11237 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
11238 if (conn
->sock
< 0)
11240 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
11241 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
11243 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
11244 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
11249 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
11250 if (errno
!= EINPROGRESS
) {
11251 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
11257 * Continue connecting in the background; eloop will call us
11258 * once the connection is ready (or failed).
11262 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11263 dpp_conn_tx_ready
, conn
, NULL
) < 0)
11265 conn
->write_eloop
= 1;
11267 /* TODO: eloop timeout to clear a connection if it does not complete
11270 dl_list_add(&ctrl
->conn
, &conn
->list
);
11273 dpp_connection_free(conn
);
11278 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
11280 struct wpabuf
*msg
;
11282 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
11285 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
11286 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
11287 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
11288 wpabuf_put_data(msg
, buf
, len
);
11289 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
11294 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
11295 const u8
*buf
, size_t len
)
11297 u8 type
= hdr
[DPP_HDR_LEN
- 1];
11299 wpa_printf(MSG_DEBUG
,
11300 "DPP: Continue already established Relay/Controller connection for this session");
11301 wpabuf_free(conn
->msg_out
);
11302 conn
->msg_out_pos
= 0;
11303 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
11304 if (!conn
->msg_out
) {
11305 dpp_connection_remove(conn
);
11309 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
11311 if (type
== DPP_PA_CONFIGURATION_RESULT
)
11312 conn
->on_tcp_tx_complete_remove
= 1;
11313 dpp_tcp_send(conn
);
11318 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
11319 const u8
*buf
, size_t len
, unsigned int freq
,
11320 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
11322 struct dpp_relay_controller
*ctrl
;
11323 struct dpp_connection
*conn
;
11324 u8 type
= hdr
[DPP_HDR_LEN
- 1];
11326 /* Check if there is an already started session for this peer and if so,
11327 * continue that session (send this over TCP) and return 0.
11329 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
11330 type
!= DPP_PA_PEER_DISCOVERY_RESP
&&
11331 type
!= DPP_PA_PRESENCE_ANNOUNCEMENT
) {
11332 dl_list_for_each(ctrl
, &dpp
->controllers
,
11333 struct dpp_relay_controller
, list
) {
11334 dl_list_for_each(conn
, &ctrl
->conn
,
11335 struct dpp_connection
, list
) {
11336 if (os_memcmp(src
, conn
->mac_addr
,
11338 return dpp_relay_tx(conn
, hdr
, buf
, len
);
11346 if (type
== DPP_PA_PRESENCE_ANNOUNCEMENT
) {
11347 /* TODO: Could send this to all configured Controllers. For now,
11348 * only the first Controller is supported. */
11349 ctrl
= dl_list_first(&dpp
->controllers
,
11350 struct dpp_relay_controller
, list
);
11352 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
11357 wpa_printf(MSG_DEBUG
,
11358 "DPP: Authentication Request for a configured Controller");
11359 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
11363 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
11364 if (!conn
->msg_out
) {
11365 dpp_connection_remove(conn
);
11368 /* Message will be sent in dpp_conn_tx_ready() */
11374 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
11377 struct dpp_relay_controller
*ctrl
;
11378 struct dpp_connection
*conn
, *found
= NULL
;
11379 struct wpabuf
*msg
;
11381 /* Check if there is a successfully completed authentication for this
11382 * and if so, continue that session (send this over TCP) and return 0.
11384 dl_list_for_each(ctrl
, &dpp
->controllers
,
11385 struct dpp_relay_controller
, list
) {
11388 dl_list_for_each(conn
, &ctrl
->conn
,
11389 struct dpp_connection
, list
) {
11390 if (os_memcmp(src
, conn
->mac_addr
,
11401 msg
= wpabuf_alloc(4 + 1 + data_len
);
11404 wpabuf_put_be32(msg
, 1 + data_len
);
11405 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
11406 wpabuf_put_data(msg
, data
, data_len
);
11407 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
11409 wpabuf_free(conn
->msg_out
);
11410 conn
->msg_out_pos
= 0;
11411 conn
->msg_out
= msg
;
11412 dpp_tcp_send(conn
);
11417 static void dpp_controller_free(struct dpp_controller
*ctrl
)
11419 struct dpp_connection
*conn
, *tmp
;
11424 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
11426 dpp_connection_remove(conn
);
11428 if (ctrl
->sock
>= 0) {
11430 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
11432 os_free(ctrl
->configurator_params
);
11437 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
11438 const u8
*hdr
, const u8
*buf
, size_t len
)
11440 const u8
*r_bootstrap
, *i_bootstrap
;
11441 u16 r_bootstrap_len
, i_bootstrap_len
;
11442 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
11447 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
11449 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
11451 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
11452 wpa_printf(MSG_INFO
,
11453 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11456 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
11457 r_bootstrap
, r_bootstrap_len
);
11459 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
11461 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
11462 wpa_printf(MSG_INFO
,
11463 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
11466 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
11467 i_bootstrap
, i_bootstrap_len
);
11469 /* Try to find own and peer bootstrapping key matches based on the
11470 * received hash values */
11471 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
11472 &own_bi
, &peer_bi
);
11474 wpa_printf(MSG_INFO
,
11475 "No matching own bootstrapping key found - ignore message");
11480 wpa_printf(MSG_INFO
,
11481 "Already in DPP authentication exchange - ignore new one");
11485 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
,
11486 conn
->ctrl
->global
->msg_ctx
,
11487 conn
->ctrl
->allowed_roles
,
11488 conn
->ctrl
->qr_mutual
,
11489 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
11491 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
11495 if (dpp_set_configurator(conn
->auth
,
11496 conn
->ctrl
->configurator_params
) < 0) {
11497 dpp_connection_remove(conn
);
11501 wpabuf_free(conn
->msg_out
);
11502 conn
->msg_out_pos
= 0;
11503 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(conn
->auth
->resp_msg
) - 1);
11504 if (!conn
->msg_out
)
11506 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(conn
->auth
->resp_msg
) - 1);
11507 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(conn
->auth
->resp_msg
) + 1,
11508 wpabuf_len(conn
->auth
->resp_msg
) - 1);
11510 if (dpp_tcp_send(conn
) == 1) {
11511 if (!conn
->write_eloop
) {
11512 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11516 conn
->write_eloop
= 1;
11524 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
11525 const u8
*hdr
, const u8
*buf
, size_t len
)
11527 struct dpp_authentication
*auth
= conn
->auth
;
11528 struct wpabuf
*msg
;
11533 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
11535 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
11537 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
11538 wpa_printf(MSG_DEBUG
,
11539 "DPP: Start wait for full response");
11542 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
11543 dpp_connection_remove(conn
);
11547 wpabuf_free(conn
->msg_out
);
11548 conn
->msg_out_pos
= 0;
11549 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
11550 if (!conn
->msg_out
) {
11554 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
11555 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(msg
) + 1,
11556 wpabuf_len(msg
) - 1);
11559 conn
->on_tcp_tx_complete_auth_ok
= 1;
11560 if (dpp_tcp_send(conn
) == 1) {
11561 if (!conn
->write_eloop
) {
11562 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11566 conn
->write_eloop
= 1;
11574 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
11575 const u8
*hdr
, const u8
*buf
, size_t len
)
11577 struct dpp_authentication
*auth
= conn
->auth
;
11579 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
11582 wpa_printf(MSG_DEBUG
,
11583 "DPP: No DPP Authentication in progress - drop");
11587 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
11588 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
11592 dpp_controller_auth_success(conn
, 0);
11597 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
11600 struct dpp_connection
*conn
= eloop_ctx
;
11602 if (!conn
->auth
->waiting_conf_result
)
11605 wpa_printf(MSG_DEBUG
,
11606 "DPP: Timeout while waiting for Connection Status Result");
11607 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11608 DPP_EVENT_CONN_STATUS_RESULT
"timeout");
11609 dpp_connection_remove(conn
);
11613 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
11614 const u8
*hdr
, const u8
*buf
,
11617 struct dpp_authentication
*auth
= conn
->auth
;
11618 enum dpp_status_error status
;
11623 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
11625 if (!auth
|| !auth
->waiting_conf_result
) {
11626 wpa_printf(MSG_DEBUG
,
11627 "DPP: No DPP Configuration waiting for result - drop");
11631 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
11632 if (status
== DPP_STATUS_OK
&& auth
->send_conn_status
) {
11633 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11634 DPP_EVENT_CONF_SENT
"wait_conn_status=1");
11635 wpa_printf(MSG_DEBUG
, "DPP: Wait for Connection Status Result");
11636 eloop_cancel_timeout(
11637 dpp_controller_conn_status_result_wait_timeout
,
11639 eloop_register_timeout(
11640 16, 0, dpp_controller_conn_status_result_wait_timeout
,
11644 if (status
== DPP_STATUS_OK
)
11645 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11646 DPP_EVENT_CONF_SENT
);
11648 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11649 DPP_EVENT_CONF_FAILED
);
11650 return -1; /* to remove the completed connection */
11654 static int dpp_controller_rx_conn_status_result(struct dpp_connection
*conn
,
11655 const u8
*hdr
, const u8
*buf
,
11658 struct dpp_authentication
*auth
= conn
->auth
;
11659 enum dpp_status_error status
;
11660 u8 ssid
[SSID_MAX_LEN
];
11661 size_t ssid_len
= 0;
11662 char *channel_list
= NULL
;
11667 wpa_printf(MSG_DEBUG
, "DPP: Connection Status Result");
11669 if (!auth
|| !auth
->waiting_conn_status_result
) {
11670 wpa_printf(MSG_DEBUG
,
11671 "DPP: No DPP Configuration waiting for connection status result - drop");
11675 status
= dpp_conn_status_result_rx(auth
, hdr
, buf
, len
,
11676 ssid
, &ssid_len
, &channel_list
);
11677 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11678 DPP_EVENT_CONN_STATUS_RESULT
11679 "result=%d ssid=%s channel_list=%s",
11680 status
, wpa_ssid_txt(ssid
, ssid_len
),
11681 channel_list
? channel_list
: "N/A");
11682 os_free(channel_list
);
11683 return -1; /* to remove the completed connection */
11687 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
11690 const u8
*pos
, *end
;
11693 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
11697 if (end
- pos
< DPP_HDR_LEN
||
11698 WPA_GET_BE24(pos
) != OUI_WFA
||
11699 pos
[3] != DPP_OUI_TYPE
) {
11700 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
11705 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
11710 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
11711 pos
+= DPP_HDR_LEN
;
11713 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
11715 if (dpp_check_attrs(pos
, end
- pos
) < 0)
11719 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11720 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11721 conn
->freq
, msg
, len
);
11726 case DPP_PA_AUTHENTICATION_REQ
:
11727 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
11728 case DPP_PA_AUTHENTICATION_RESP
:
11729 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
11730 case DPP_PA_AUTHENTICATION_CONF
:
11731 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
11732 case DPP_PA_CONFIGURATION_RESULT
:
11733 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
11734 case DPP_PA_CONNECTION_STATUS_RESULT
:
11735 return dpp_controller_rx_conn_status_result(conn
, msg
, pos
,
11738 /* TODO: missing messages types */
11739 wpa_printf(MSG_DEBUG
,
11740 "DPP: Unsupported frame subtype %d", type
);
11746 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
11749 const u8
*pos
, *end
, *next
;
11751 const u8
*adv_proto
;
11753 struct wpabuf
*resp
, *buf
;
11754 struct dpp_authentication
*auth
= conn
->auth
;
11759 wpa_printf(MSG_DEBUG
,
11760 "DPP: Received DPP Configuration Request over TCP");
11762 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
11763 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11770 dialog_token
= *pos
++;
11773 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11774 slen
> end
- pos
|| slen
< 2)
11778 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11780 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11781 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11782 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11786 /* Query Request */
11789 slen
= WPA_GET_LE16(pos
);
11791 if (slen
> end
- pos
)
11794 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
11798 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
11804 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
11806 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
11807 wpabuf_put_u8(buf
, dialog_token
);
11808 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
11809 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
11811 dpp_write_adv_proto(buf
);
11812 dpp_write_gas_query(buf
, resp
);
11815 /* Send Config Response over TCP; GAS fragmentation is taken care of by
11817 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
11818 wpabuf_free(conn
->msg_out
);
11819 conn
->msg_out_pos
= 0;
11820 conn
->msg_out
= buf
;
11821 conn
->on_tcp_tx_complete_gas_done
= 1;
11822 dpp_tcp_send(conn
);
11827 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
11829 struct dpp_authentication
*auth
= conn
->auth
;
11831 struct wpabuf
*msg
, *encaps
;
11832 enum dpp_status_error status
;
11834 wpa_printf(MSG_DEBUG
,
11835 "DPP: Configuration Response for local stack from TCP");
11837 res
= dpp_conf_resp_rx(auth
, resp
);
11840 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
11844 if (conn
->global
->process_conf_obj
)
11845 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
11850 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
11854 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
11855 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
11856 msg
= dpp_build_conf_result(auth
, status
);
11860 encaps
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
11865 wpabuf_put_be32(encaps
, wpabuf_len(msg
) - 1);
11866 wpabuf_put_data(encaps
, wpabuf_head_u8(msg
) + 1, wpabuf_len(msg
) - 1);
11868 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", encaps
);
11870 wpabuf_free(conn
->msg_out
);
11871 conn
->msg_out_pos
= 0;
11872 conn
->msg_out
= encaps
;
11873 conn
->on_tcp_tx_complete_remove
= 1;
11874 dpp_tcp_send(conn
);
11876 /* This exchange will be terminated in the TX status handler */
11879 #else /* CONFIG_DPP2 */
11881 #endif /* CONFIG_DPP2 */
11885 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
11888 struct wpabuf
*buf
;
11890 const u8
*pos
, *end
, *next
, *adv_proto
;
11896 wpa_printf(MSG_DEBUG
,
11897 "DPP: Received DPP Configuration Response over TCP");
11902 dialog_token
= *pos
++;
11903 status
= WPA_GET_LE16(pos
);
11904 if (status
!= WLAN_STATUS_SUCCESS
) {
11905 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
11909 pos
+= 2; /* ignore GAS Comeback Delay */
11913 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11914 slen
> end
- pos
|| slen
< 2)
11918 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11920 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11921 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11922 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11926 /* Query Response */
11929 slen
= WPA_GET_LE16(pos
);
11931 if (slen
> end
- pos
)
11934 buf
= wpabuf_alloc(slen
);
11937 wpabuf_put_data(buf
, pos
, slen
);
11939 if (!conn
->relay
&& !conn
->ctrl
)
11940 return dpp_tcp_rx_gas_resp(conn
, buf
);
11942 if (!conn
->relay
) {
11943 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11947 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11948 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11949 dialog_token
, 0, buf
);
11955 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
11957 struct dpp_connection
*conn
= eloop_ctx
;
11961 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
11964 if (conn
->msg_len_octets
< 4) {
11967 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
11968 4 - conn
->msg_len_octets
, 0);
11970 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
11972 dpp_connection_remove(conn
);
11976 wpa_printf(MSG_DEBUG
,
11977 "DPP: No more data available over TCP");
11978 dpp_connection_remove(conn
);
11981 wpa_printf(MSG_DEBUG
,
11982 "DPP: Received %d/%d octet(s) of message length field",
11983 res
, (int) (4 - conn
->msg_len_octets
));
11984 conn
->msg_len_octets
+= res
;
11986 if (conn
->msg_len_octets
< 4) {
11987 wpa_printf(MSG_DEBUG
,
11988 "DPP: Need %d more octets of message length field",
11989 (int) (4 - conn
->msg_len_octets
));
11993 msglen
= WPA_GET_BE32(conn
->msg_len
);
11994 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
11995 if (msglen
> 65535) {
11996 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
11997 dpp_connection_remove(conn
);
12001 wpabuf_free(conn
->msg
);
12002 conn
->msg
= wpabuf_alloc(msglen
);
12006 wpa_printf(MSG_DEBUG
,
12007 "DPP: No buffer available for receiving the message");
12008 dpp_connection_remove(conn
);
12012 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
12013 (unsigned int) wpabuf_tailroom(conn
->msg
));
12015 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
12017 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
12018 dpp_connection_remove(conn
);
12022 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
12023 dpp_connection_remove(conn
);
12026 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
12027 wpabuf_put(conn
->msg
, res
);
12029 if (wpabuf_tailroom(conn
->msg
) > 0) {
12030 wpa_printf(MSG_DEBUG
,
12031 "DPP: Need %u more octets of message payload",
12032 (unsigned int) wpabuf_tailroom(conn
->msg
));
12036 conn
->msg_len_octets
= 0;
12037 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
12038 if (wpabuf_len(conn
->msg
) < 1) {
12039 dpp_connection_remove(conn
);
12043 pos
= wpabuf_head(conn
->msg
);
12045 case WLAN_PA_VENDOR_SPECIFIC
:
12046 if (dpp_controller_rx_action(conn
, pos
+ 1,
12047 wpabuf_len(conn
->msg
) - 1) < 0)
12048 dpp_connection_remove(conn
);
12050 case WLAN_PA_GAS_INITIAL_REQ
:
12051 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
12052 wpabuf_len(conn
->msg
) - 1) < 0)
12053 dpp_connection_remove(conn
);
12055 case WLAN_PA_GAS_INITIAL_RESP
:
12056 if (dpp_rx_gas_resp(conn
, pos
+ 1,
12057 wpabuf_len(conn
->msg
) - 1) < 0)
12058 dpp_connection_remove(conn
);
12061 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
12068 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
12070 struct dpp_controller
*ctrl
= eloop_ctx
;
12071 struct sockaddr_in addr
;
12072 socklen_t addr_len
= sizeof(addr
);
12074 struct dpp_connection
*conn
;
12076 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
12078 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
12080 wpa_printf(MSG_DEBUG
,
12081 "DPP: Failed to accept new connection: %s",
12085 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
12086 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
12088 conn
= os_zalloc(sizeof(*conn
));
12092 conn
->global
= ctrl
->global
;
12096 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
12097 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12102 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
12103 dpp_controller_rx
, conn
, NULL
) < 0)
12105 conn
->read_eloop
= 1;
12107 /* TODO: eloop timeout to expire connections that do not complete in
12108 * reasonable time */
12109 dl_list_add(&ctrl
->conn
, &conn
->list
);
12118 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
12119 const struct hostapd_ip_addr
*addr
, int port
)
12121 struct dpp_connection
*conn
;
12122 struct sockaddr_storage saddr
;
12124 const u8
*hdr
, *pos
, *end
;
12127 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
12128 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
12129 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
12131 dpp_auth_deinit(auth
);
12135 conn
= os_zalloc(sizeof(*conn
));
12137 dpp_auth_deinit(auth
);
12141 conn
->global
= dpp
;
12143 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
12144 if (conn
->sock
< 0)
12147 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
12148 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12153 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
12154 if (errno
!= EINPROGRESS
) {
12155 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
12161 * Continue connecting in the background; eloop will call us
12162 * once the connection is ready (or failed).
12166 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
12167 dpp_conn_tx_ready
, conn
, NULL
) < 0)
12169 conn
->write_eloop
= 1;
12171 hdr
= wpabuf_head(auth
->req_msg
);
12172 end
= hdr
+ wpabuf_len(auth
->req_msg
);
12173 hdr
+= 2; /* skip Category and Actiom */
12174 pos
= hdr
+ DPP_HDR_LEN
;
12175 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
12176 if (!conn
->msg_out
)
12178 /* Message will be sent in dpp_conn_tx_ready() */
12180 /* TODO: eloop timeout to clear a connection if it does not complete
12182 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
12185 dpp_connection_free(conn
);
12190 int dpp_controller_start(struct dpp_global
*dpp
,
12191 struct dpp_controller_config
*config
)
12193 struct dpp_controller
*ctrl
;
12195 struct sockaddr_in sin
;
12198 if (!dpp
|| dpp
->controller
)
12201 ctrl
= os_zalloc(sizeof(*ctrl
));
12204 ctrl
->global
= dpp
;
12205 if (config
->configurator_params
)
12206 ctrl
->configurator_params
=
12207 os_strdup(config
->configurator_params
);
12208 dl_list_init(&ctrl
->conn
);
12209 /* TODO: configure these somehow */
12210 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
12211 ctrl
->qr_mutual
= 0;
12213 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
12214 if (ctrl
->sock
< 0)
12217 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
12218 &on
, sizeof(on
)) < 0) {
12219 wpa_printf(MSG_DEBUG
,
12220 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
12222 /* try to continue anyway */
12225 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
12226 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12232 os_memset(&sin
, 0, sizeof(sin
));
12233 sin
.sin_family
= AF_INET
;
12234 sin
.sin_addr
.s_addr
= INADDR_ANY
;
12235 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
12236 sin
.sin_port
= htons(port
);
12237 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
12238 wpa_printf(MSG_INFO
,
12239 "DPP: Failed to bind Controller TCP port: %s",
12243 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
12244 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
12245 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
12246 dpp_controller_tcp_cb
, ctrl
, NULL
))
12249 dpp
->controller
= ctrl
;
12250 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
12253 dpp_controller_free(ctrl
);
12258 void dpp_controller_stop(struct dpp_global
*dpp
)
12261 dpp_controller_free(dpp
->controller
);
12262 dpp
->controller
= NULL
;
12267 struct wpabuf
* dpp_build_presence_announcement(struct dpp_bootstrap_info
*bi
)
12269 struct wpabuf
*msg
;
12271 wpa_printf(MSG_DEBUG
, "DPP: Build Presence Announcement frame");
12273 msg
= dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT
, 4 + SHA256_MAC_LEN
);
12277 /* Responder Bootstrapping Key Hash */
12278 dpp_build_attr_r_bootstrap_key_hash(msg
, bi
->pubkey_hash_chirp
);
12279 wpa_hexdump_buf(MSG_DEBUG
,
12280 "DPP: Presence Announcement frame attributes", msg
);
12284 #endif /* CONFIG_DPP2 */