2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2019, The Linux Foundation
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
10 #include "utils/includes.h"
11 #include <openssl/opensslv.h>
12 #include <openssl/err.h>
13 #include <openssl/asn1.h>
14 #include <openssl/asn1t.h>
16 #include "utils/common.h"
17 #include "utils/base64.h"
18 #include "utils/json.h"
19 #include "common/ieee802_11_common.h"
20 #include "common/ieee802_11_defs.h"
21 #include "common/wpa_ctrl.h"
22 #include "crypto/crypto.h"
23 #include "crypto/random.h"
24 #include "crypto/aes.h"
25 #include "crypto/aes_siv.h"
26 #include "crypto/sha384.h"
27 #include "crypto/sha512.h"
28 #include "drivers/driver.h"
32 #ifdef CONFIG_TESTING_OPTIONS
33 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
34 u8 dpp_pkex_own_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
35 u8 dpp_pkex_peer_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
36 u8 dpp_pkex_ephemeral_key_override
[600];
37 size_t dpp_pkex_ephemeral_key_override_len
= 0;
38 u8 dpp_protocol_key_override
[600];
39 size_t dpp_protocol_key_override_len
= 0;
40 u8 dpp_nonce_override
[DPP_MAX_NONCE_LEN
];
41 size_t dpp_nonce_override_len
= 0;
43 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
44 const struct dpp_curve_params
*curve
);
45 #endif /* CONFIG_TESTING_OPTIONS */
47 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
48 (defined(LIBRESSL_VERSION_NUMBER) && \
49 LIBRESSL_VERSION_NUMBER < 0x20700000L)
50 /* Compatibility wrappers for older versions. */
52 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
60 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
73 struct dl_list bootstrap
; /* struct dpp_bootstrap_info */
74 struct dl_list configurator
; /* struct dpp_configurator */
77 static const struct dpp_curve_params dpp_curves
[] = {
78 /* The mandatory to support and the default NIST P-256 curve needs to
79 * be the first entry on this list. */
80 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
81 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
82 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
83 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
84 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
85 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
86 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
90 /* Role-specific elements for PKEX */
93 static const u8 pkex_init_x_p256
[32] = {
94 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
95 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
96 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
97 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
99 static const u8 pkex_init_y_p256
[32] = {
100 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
101 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
102 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
103 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
105 static const u8 pkex_resp_x_p256
[32] = {
106 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
107 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
108 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
109 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
111 static const u8 pkex_resp_y_p256
[32] = {
112 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
113 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
114 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
115 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
119 static const u8 pkex_init_x_p384
[48] = {
120 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
121 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
122 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
123 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
124 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
125 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
127 static const u8 pkex_init_y_p384
[48] = {
128 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
129 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
130 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
131 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
132 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
133 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
135 static const u8 pkex_resp_x_p384
[48] = {
136 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
137 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
138 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
139 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
140 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
141 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
143 static const u8 pkex_resp_y_p384
[48] = {
144 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
145 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
146 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
147 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
148 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
149 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
153 static const u8 pkex_init_x_p521
[66] = {
154 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
155 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
156 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
157 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
158 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
159 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
160 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
161 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
164 static const u8 pkex_init_y_p521
[66] = {
165 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
166 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
167 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
168 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
169 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
170 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
171 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
172 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
175 static const u8 pkex_resp_x_p521
[66] = {
176 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
177 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
178 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
179 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
180 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
181 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
182 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
183 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
186 static const u8 pkex_resp_y_p521
[66] = {
187 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
188 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
189 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
190 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
191 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
192 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
193 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
194 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
198 /* Brainpool P-256r1 */
199 static const u8 pkex_init_x_bp_p256r1
[32] = {
200 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
201 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
202 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
203 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
205 static const u8 pkex_init_y_bp_p256r1
[32] = {
206 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
207 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
208 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
209 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
211 static const u8 pkex_resp_x_bp_p256r1
[32] = {
212 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
213 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
214 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
215 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
217 static const u8 pkex_resp_y_bp_p256r1
[32] = {
218 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
219 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
220 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
221 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
224 /* Brainpool P-384r1 */
225 static const u8 pkex_init_x_bp_p384r1
[48] = {
226 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
227 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
228 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
229 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
230 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
231 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
233 static const u8 pkex_init_y_bp_p384r1
[48] = {
234 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
235 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
236 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
237 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
238 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
239 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
241 static const u8 pkex_resp_x_bp_p384r1
[48] = {
242 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
243 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
244 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
245 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
246 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
247 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
249 static const u8 pkex_resp_y_bp_p384r1
[48] = {
250 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
251 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
252 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
253 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
254 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
255 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
258 /* Brainpool P-512r1 */
259 static const u8 pkex_init_x_bp_p512r1
[64] = {
260 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
261 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
262 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
263 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
264 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
265 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
266 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
267 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
269 static const u8 pkex_init_y_bp_p512r1
[64] = {
270 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
271 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
272 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
273 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
274 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
275 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
276 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
277 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
279 static const u8 pkex_resp_x_bp_p512r1
[64] = {
280 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
281 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
282 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
283 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
284 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
285 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
286 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
287 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
289 static const u8 pkex_resp_y_bp_p512r1
[64] = {
290 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
291 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
292 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
293 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
294 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
295 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
296 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
297 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
301 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
302 const EC_POINT
*point
)
306 char *x_str
= NULL
, *y_str
= NULL
;
308 if (!wpa_debug_show_keys
)
314 if (!ctx
|| !x
|| !y
||
315 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
318 x_str
= BN_bn2hex(x
);
319 y_str
= BN_bn2hex(y
);
320 if (!x_str
|| !y_str
)
323 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
334 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
335 size_t num_elem
, const u8
*addr
[], const size_t *len
,
338 if (curve
->hash_len
== 32)
339 return sha256_vector(num_elem
, addr
, len
, mac
);
340 if (curve
->hash_len
== 48)
341 return sha384_vector(num_elem
, addr
, len
, mac
);
342 if (curve
->hash_len
== 64)
343 return sha512_vector(num_elem
, addr
, len
, mac
);
348 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
349 const char *label
, u8
*out
, size_t outlen
)
352 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
353 (const u8
*) label
, os_strlen(label
),
356 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
357 (const u8
*) label
, os_strlen(label
),
360 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
361 (const u8
*) label
, os_strlen(label
),
367 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
368 size_t num_elem
, const u8
*addr
[],
369 const size_t *len
, u8
*mac
)
372 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
375 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
378 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
384 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
385 const u8
*data
, size_t data_len
, u8
*mac
)
388 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
390 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
392 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
397 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
399 int num_bytes
, offset
;
401 num_bytes
= BN_num_bytes(bn
);
402 if ((size_t) num_bytes
> len
)
404 offset
= len
- num_bytes
;
405 os_memset(pos
, 0, offset
);
406 BN_bn2bin(bn
, pos
+ offset
);
411 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
418 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
421 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
422 len
= i2o_ECPublicKey(eckey
, NULL
);
424 wpa_printf(MSG_ERROR
,
425 "DDP: Failed to determine public key encoding length");
430 buf
= wpabuf_alloc(len
);
436 pos
= wpabuf_put(buf
, len
);
437 res
= i2o_ECPublicKey(eckey
, &pos
);
440 wpa_printf(MSG_ERROR
,
441 "DDP: Failed to encode public key (res=%d/%d)",
448 /* Remove 0x04 prefix to match DPP definition */
449 pos
= wpabuf_mhead(buf
);
450 os_memmove(pos
, pos
+ 1, len
- 1);
458 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
459 const u8
*buf_x
, const u8
*buf_y
,
462 EC_KEY
*eckey
= NULL
;
464 EC_POINT
*point
= NULL
;
465 BIGNUM
*x
= NULL
, *y
= NULL
;
466 EVP_PKEY
*pkey
= NULL
;
470 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
474 point
= EC_POINT_new(group
);
475 x
= BN_bin2bn(buf_x
, len
, NULL
);
476 y
= BN_bin2bn(buf_y
, len
, NULL
);
477 if (!point
|| !x
|| !y
) {
478 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
482 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
483 wpa_printf(MSG_ERROR
,
484 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
485 ERR_error_string(ERR_get_error(), NULL
));
489 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
490 EC_POINT_is_at_infinity(group
, point
)) {
491 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
494 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
496 eckey
= EC_KEY_new();
498 EC_KEY_set_group(eckey
, group
) != 1 ||
499 EC_KEY_set_public_key(eckey
, point
) != 1) {
500 wpa_printf(MSG_ERROR
,
501 "DPP: Failed to set EC_KEY: %s",
502 ERR_error_string(ERR_get_error(), NULL
));
505 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
507 pkey
= EVP_PKEY_new();
508 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
509 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
517 EC_POINT_free(point
);
527 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
528 const u8
*buf
, size_t len
)
531 const EC_GROUP
*group
;
532 EVP_PKEY
*pkey
= NULL
;
537 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
539 wpa_printf(MSG_ERROR
,
540 "DPP: Could not get EC_KEY from group_key");
544 group
= EC_KEY_get0_group(eckey
);
546 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
549 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
556 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
558 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
562 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
567 msg
= wpabuf_alloc(8 + len
);
570 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
571 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
572 wpabuf_put_be24(msg
, OUI_WFA
);
573 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
574 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
575 wpabuf_put_u8(msg
, type
);
580 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
583 const u8
*pos
= buf
, *end
= buf
+ len
;
585 while (end
- pos
>= 4) {
586 id
= WPA_GET_LE16(pos
);
588 alen
= WPA_GET_LE16(pos
);
590 if (alen
> end
- pos
)
603 int dpp_check_attrs(const u8
*buf
, size_t len
)
606 int wrapped_data
= 0;
610 while (end
- pos
>= 4) {
613 id
= WPA_GET_LE16(pos
);
615 alen
= WPA_GET_LE16(pos
);
617 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
619 if (alen
> end
- pos
) {
620 wpa_printf(MSG_DEBUG
,
621 "DPP: Truncated message - not enough room for the attribute - dropped");
625 wpa_printf(MSG_DEBUG
,
626 "DPP: An unexpected attribute included after the Wrapped Data attribute");
629 if (id
== DPP_ATTR_WRAPPED_DATA
)
635 wpa_printf(MSG_DEBUG
,
636 "DPP: Unexpected octets (%d) after the last attribute",
645 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
651 EVP_PKEY_free(info
->pubkey
);
656 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
659 case DPP_BOOTSTRAP_QR_CODE
:
661 case DPP_BOOTSTRAP_PKEX
:
668 static int dpp_uri_valid_info(const char *info
)
671 unsigned char val
= *info
++;
673 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
681 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
683 bi
->uri
= os_strdup(uri
);
684 return bi
->uri
? 0 : -1;
688 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
689 const char *chan_list
)
691 const char *pos
= chan_list
;
692 int opclass
, channel
, freq
;
694 while (pos
&& *pos
&& *pos
!= ';') {
698 pos
= os_strchr(pos
, '/');
705 while (*pos
>= '0' && *pos
<= '9')
707 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
708 wpa_printf(MSG_DEBUG
,
709 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
710 opclass
, channel
, freq
);
712 wpa_printf(MSG_DEBUG
,
713 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
715 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
716 wpa_printf(MSG_DEBUG
,
717 "DPP: Too many channels in URI channel-list - ignore list");
721 bi
->freq
[bi
->num_freq
++] = freq
;
724 if (*pos
== ';' || *pos
== '\0')
733 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
738 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
743 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
744 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
748 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
754 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
761 end
= os_strchr(info
, ';');
763 end
= info
+ os_strlen(info
);
764 bi
->info
= os_malloc(end
- info
+ 1);
767 os_memcpy(bi
->info
, info
, end
- info
);
768 bi
->info
[end
- info
] = '\0';
769 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
770 if (!dpp_uri_valid_info(bi
->info
)) {
771 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
779 static const struct dpp_curve_params
*
780 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
785 for (i
= 0; dpp_curves
[i
].name
; i
++) {
786 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
787 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
788 return &dpp_curves
[i
];
794 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
800 for (i
= 0; dpp_curves
[i
].name
; i
++) {
801 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
803 return &dpp_curves
[i
];
809 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
815 const unsigned char *p
;
817 X509_PUBKEY
*pub
= NULL
;
819 const unsigned char *pk
;
822 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
823 (defined(LIBRESSL_VERSION_NUMBER) && \
824 LIBRESSL_VERSION_NUMBER < 0x20800000L)
827 const ASN1_OBJECT
*pa_oid
;
831 const ASN1_OBJECT
*poid
;
834 end
= os_strchr(info
, ';');
838 data
= base64_decode((const unsigned char *) info
, end
- info
,
841 wpa_printf(MSG_DEBUG
,
842 "DPP: Invalid base64 encoding on URI public-key");
845 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
848 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
849 bi
->pubkey_hash
) < 0) {
850 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
854 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
855 bi
->pubkey_hash
, SHA256_MAC_LEN
);
857 /* DER encoded ASN.1 SubjectPublicKeyInfo
859 * SubjectPublicKeyInfo ::= SEQUENCE {
860 * algorithm AlgorithmIdentifier,
861 * subjectPublicKey BIT STRING }
863 * AlgorithmIdentifier ::= SEQUENCE {
864 * algorithm OBJECT IDENTIFIER,
865 * parameters ANY DEFINED BY algorithm OPTIONAL }
867 * subjectPublicKey = compressed format public key per ANSI X9.63
868 * algorithm = ecPublicKey (1.2.840.10045.2.1)
869 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
870 * prime256v1 (1.2.840.10045.3.1.7)
874 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
878 wpa_printf(MSG_DEBUG
,
879 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
883 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
884 wpa_printf(MSG_DEBUG
,
885 "DPP: SubjectPublicKeyInfo does not describe an EC key");
890 res
= X509_PUBKEY_set(&pub
, pkey
);
892 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
896 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
898 wpa_printf(MSG_DEBUG
,
899 "DPP: Could not extract SubjectPublicKeyInfo parameters");
902 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
903 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
904 wpa_printf(MSG_DEBUG
,
905 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
908 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
909 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
910 wpa_printf(MSG_DEBUG
,
911 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
915 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
916 if (ptype
!= V_ASN1_OBJECT
) {
917 wpa_printf(MSG_DEBUG
,
918 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
922 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
923 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
924 wpa_printf(MSG_DEBUG
,
925 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
928 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
929 bi
->curve
= dpp_get_curve_oid(poid
);
931 wpa_printf(MSG_DEBUG
,
932 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
937 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
939 X509_PUBKEY_free(pub
);
943 X509_PUBKEY_free(pub
);
949 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
951 const char *pos
= uri
;
953 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
954 struct dpp_bootstrap_info
*bi
;
956 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
958 if (os_strncmp(pos
, "DPP:", 4) != 0) {
959 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
965 end
= os_strchr(pos
, ';');
970 /* Handle terminating ";;" and ignore unexpected ";"
971 * for parsing robustness. */
976 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
978 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
980 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
982 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
985 wpa_hexdump_ascii(MSG_DEBUG
,
986 "DPP: Ignore unrecognized URI parameter",
992 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
996 bi
= os_zalloc(sizeof(*bi
));
1000 if (dpp_clone_uri(bi
, uri
) < 0 ||
1001 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1002 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1003 dpp_parse_uri_info(bi
, info
) < 0 ||
1004 dpp_parse_uri_pk(bi
, pk
) < 0) {
1005 dpp_bootstrap_info_free(bi
);
1013 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
1015 struct dpp_bootstrap_info
*bi
;
1017 bi
= dpp_parse_uri(uri
);
1019 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
1024 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1031 unsigned char *der
= NULL
;
1033 const EC_GROUP
*group
;
1034 const EC_POINT
*point
;
1036 out
= BIO_new(BIO_s_mem());
1040 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1041 rlen
= BIO_ctrl_pending(out
);
1042 txt
= os_malloc(rlen
+ 1);
1044 res
= BIO_read(out
, txt
, rlen
);
1047 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1053 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1057 group
= EC_KEY_get0_group(eckey
);
1058 point
= EC_KEY_get0_public_key(eckey
);
1060 dpp_debug_print_point(title
, group
, point
);
1062 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1064 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1068 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1070 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1078 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1080 EVP_PKEY_CTX
*kctx
= NULL
;
1082 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1085 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1087 nid
= OBJ_txt2nid(curve
->name
);
1088 if (nid
== NID_undef
) {
1089 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1093 ec_params
= EC_KEY_new_by_curve_name(nid
);
1095 wpa_printf(MSG_ERROR
,
1096 "DPP: Failed to generate EC_KEY parameters");
1099 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1100 params
= EVP_PKEY_new();
1101 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1102 wpa_printf(MSG_ERROR
,
1103 "DPP: Failed to generate EVP_PKEY parameters");
1107 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1109 EVP_PKEY_keygen_init(kctx
) != 1 ||
1110 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1111 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1115 if (wpa_debug_show_keys
)
1116 dpp_debug_print_key("Own generated key", key
);
1118 EVP_PKEY_free(params
);
1119 EVP_PKEY_CTX_free(kctx
);
1122 EVP_PKEY_CTX_free(kctx
);
1123 EVP_PKEY_free(params
);
1128 static const struct dpp_curve_params
*
1129 dpp_get_curve_name(const char *name
)
1133 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1134 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1135 (dpp_curves
[i
].jwk_crv
&&
1136 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1137 return &dpp_curves
[i
];
1143 static const struct dpp_curve_params
*
1144 dpp_get_curve_jwk_crv(const char *name
)
1148 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1149 if (dpp_curves
[i
].jwk_crv
&&
1150 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1151 return &dpp_curves
[i
];
1157 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1158 const u8
*privkey
, size_t privkey_len
)
1162 const EC_GROUP
*group
;
1165 pkey
= EVP_PKEY_new();
1168 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1170 wpa_printf(MSG_INFO
,
1171 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1172 ERR_error_string(ERR_get_error(), NULL
));
1173 EVP_PKEY_free(pkey
);
1176 group
= EC_KEY_get0_group(eckey
);
1179 EVP_PKEY_free(pkey
);
1182 nid
= EC_GROUP_get_curve_name(group
);
1183 *curve
= dpp_get_curve_nid(nid
);
1185 wpa_printf(MSG_INFO
,
1186 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1189 EVP_PKEY_free(pkey
);
1193 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1195 EVP_PKEY_free(pkey
);
1203 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1204 * as an OID identifying the curve */
1206 /* Compressed format public key per ANSI X9.63 */
1207 ASN1_BIT_STRING
*pub_key
;
1208 } DPP_BOOTSTRAPPING_KEY
;
1210 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1211 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1212 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1213 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1215 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1218 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1220 unsigned char *der
= NULL
;
1223 struct wpabuf
*ret
= NULL
;
1225 const EC_GROUP
*group
;
1226 const EC_POINT
*point
;
1228 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1232 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1236 group
= EC_KEY_get0_group(eckey
);
1237 point
= EC_KEY_get0_public_key(eckey
);
1238 if (!group
|| !point
)
1240 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1241 nid
= EC_GROUP_get_curve_name(group
);
1243 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1245 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1246 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1249 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1254 der
= OPENSSL_malloc(len
);
1257 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1260 OPENSSL_free(bootstrap
->pub_key
->data
);
1261 bootstrap
->pub_key
->data
= der
;
1263 bootstrap
->pub_key
->length
= len
;
1264 /* No unused bits */
1265 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1266 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1268 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1270 wpa_printf(MSG_ERROR
,
1271 "DDP: Failed to build DER encoded public key");
1275 ret
= wpabuf_alloc_copy(der
, der_len
);
1277 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1285 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1292 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1295 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1298 addr
[0] = wpabuf_head(der
);
1299 len
[0] = wpabuf_len(der
);
1300 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1302 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1304 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1311 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1312 const u8
*privkey
, size_t privkey_len
)
1314 unsigned char *base64
= NULL
;
1317 struct wpabuf
*der
= NULL
;
1322 bi
->curve
= &dpp_curves
[0];
1324 bi
->curve
= dpp_get_curve_name(curve
);
1326 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1332 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1334 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1339 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1342 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1345 addr
[0] = wpabuf_head(der
);
1346 len
= wpabuf_len(der
);
1347 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1349 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1352 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1355 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1360 pos
= (char *) base64
;
1363 pos
= os_strchr(pos
, '\n');
1366 os_memmove(pos
, pos
+ 1, end
- pos
);
1368 return (char *) base64
;
1376 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1377 unsigned int hash_len
)
1379 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1380 const char *info
= "first intermediate key";
1383 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1385 /* HKDF-Extract(<>, M.x) */
1386 os_memset(salt
, 0, hash_len
);
1387 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1389 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1392 /* HKDF-Expand(PRK, info, L) */
1393 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1394 os_memset(prk
, 0, hash_len
);
1398 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1404 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1405 unsigned int hash_len
)
1407 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1408 const char *info
= "second intermediate key";
1411 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1413 /* HKDF-Extract(<>, N.x) */
1414 os_memset(salt
, 0, hash_len
);
1415 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1418 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1421 /* HKDF-Expand(PRK, info, L) */
1422 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1423 os_memset(prk
, 0, hash_len
);
1427 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1433 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1434 unsigned int hash_len
)
1437 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1438 const char *info_ke
= "DPP Key";
1439 u8 prk
[DPP_MAX_HASH_LEN
];
1443 size_t num_elem
= 0;
1445 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1446 wpa_printf(MSG_DEBUG
,
1447 "DPP: Mx/Nx not available - cannot derive ke");
1451 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1453 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1454 nonce_len
= auth
->curve
->nonce_len
;
1455 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1456 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1457 addr
[num_elem
] = auth
->Mx
;
1458 len
[num_elem
] = auth
->Mx_len
;
1460 addr
[num_elem
] = auth
->Nx
;
1461 len
[num_elem
] = auth
->Nx_len
;
1463 if (auth
->peer_bi
&& auth
->own_bi
) {
1464 if (!auth
->Lx_len
) {
1465 wpa_printf(MSG_DEBUG
,
1466 "DPP: Lx not available - cannot derive ke");
1469 addr
[num_elem
] = auth
->Lx
;
1470 len
[num_elem
] = auth
->secret_len
;
1473 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1474 num_elem
, addr
, len
, prk
);
1477 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1480 /* HKDF-Expand(PRK, info, L) */
1481 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1482 os_memset(prk
, 0, hash_len
);
1486 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1492 static void dpp_build_attr_status(struct wpabuf
*msg
,
1493 enum dpp_status_error status
)
1495 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1496 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1497 wpabuf_put_le16(msg
, 1);
1498 wpabuf_put_u8(msg
, status
);
1502 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1506 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1507 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1508 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1509 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1514 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1518 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1519 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1520 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1521 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1526 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1527 const struct wpabuf
*pi
,
1529 const u8
*r_pubkey_hash
,
1530 const u8
*i_pubkey_hash
,
1531 unsigned int neg_freq
)
1534 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1535 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1538 size_t len
[2], siv_len
, attr_len
;
1539 u8
*attr_start
, *attr_end
;
1541 /* Build DPP Authentication Request frame attributes */
1542 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1543 4 + sizeof(wrapped_data
);
1548 #endif /* CONFIG_DPP2 */
1549 #ifdef CONFIG_TESTING_OPTIONS
1550 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1552 #endif /* CONFIG_TESTING_OPTIONS */
1553 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1557 attr_start
= wpabuf_put(msg
, 0);
1559 /* Responder Bootstrapping Key Hash */
1560 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1562 /* Initiator Bootstrapping Key Hash */
1563 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1565 /* Initiator Protocol Key */
1567 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1568 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1569 wpabuf_put_buf(msg
, pi
);
1574 u8 op_class
, channel
;
1576 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1578 NUM_HOSTAPD_MODES
) {
1579 wpa_printf(MSG_INFO
,
1580 "DPP: Unsupported negotiation frequency request: %d",
1585 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1586 wpabuf_put_le16(msg
, 2);
1587 wpabuf_put_u8(msg
, op_class
);
1588 wpabuf_put_u8(msg
, channel
);
1592 /* Protocol Version */
1593 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1594 wpabuf_put_le16(msg
, 1);
1595 wpabuf_put_u8(msg
, 2);
1596 #endif /* CONFIG_DPP2 */
1598 #ifdef CONFIG_TESTING_OPTIONS
1599 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1600 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1601 goto skip_wrapped_data
;
1603 #endif /* CONFIG_TESTING_OPTIONS */
1605 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1608 #ifdef CONFIG_TESTING_OPTIONS
1609 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1610 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1613 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1614 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1615 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1617 WPA_PUT_LE16(pos
, nonce_len
- 1);
1619 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1620 pos
+= nonce_len
- 1;
1623 #endif /* CONFIG_TESTING_OPTIONS */
1626 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1628 WPA_PUT_LE16(pos
, nonce_len
);
1630 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1633 #ifdef CONFIG_TESTING_OPTIONS
1635 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1636 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1639 #endif /* CONFIG_TESTING_OPTIONS */
1641 /* I-capabilities */
1642 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1644 WPA_PUT_LE16(pos
, 1);
1646 auth
->i_capab
= auth
->allowed_roles
;
1647 *pos
++ = auth
->i_capab
;
1648 #ifdef CONFIG_TESTING_OPTIONS
1649 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1650 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1654 #endif /* CONFIG_TESTING_OPTIONS */
1656 attr_end
= wpabuf_put(msg
, 0);
1658 /* OUI, OUI type, Crypto Suite, DPP frame type */
1659 addr
[0] = wpabuf_head_u8(msg
) + 2;
1660 len
[0] = 3 + 1 + 1 + 1;
1661 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1663 /* Attributes before Wrapped Data */
1664 addr
[1] = attr_start
;
1665 len
[1] = attr_end
- attr_start
;
1666 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1668 siv_len
= pos
- clear
;
1669 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1670 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1671 2, addr
, len
, wrapped_data
) < 0) {
1675 siv_len
+= AES_BLOCK_SIZE
;
1676 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1677 wrapped_data
, siv_len
);
1679 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1680 wpabuf_put_le16(msg
, siv_len
);
1681 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1683 #ifdef CONFIG_TESTING_OPTIONS
1684 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1685 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1686 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1689 #endif /* CONFIG_TESTING_OPTIONS */
1691 wpa_hexdump_buf(MSG_DEBUG
,
1692 "DPP: Authentication Request frame attributes", msg
);
1698 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1699 enum dpp_status_error status
,
1700 const struct wpabuf
*pr
,
1702 const u8
*r_pubkey_hash
,
1703 const u8
*i_pubkey_hash
,
1704 const u8
*r_nonce
, const u8
*i_nonce
,
1705 const u8
*wrapped_r_auth
,
1706 size_t wrapped_r_auth_len
,
1710 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1711 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1712 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1713 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1715 size_t len
[2], siv_len
, attr_len
;
1716 u8
*attr_start
, *attr_end
, *pos
;
1718 auth
->waiting_auth_conf
= 1;
1719 auth
->auth_resp_tries
= 0;
1721 /* Build DPP Authentication Response frame attributes */
1722 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1723 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1726 #endif /* CONFIG_DPP2 */
1727 #ifdef CONFIG_TESTING_OPTIONS
1728 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1730 #endif /* CONFIG_TESTING_OPTIONS */
1731 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1735 attr_start
= wpabuf_put(msg
, 0);
1739 dpp_build_attr_status(msg
, status
);
1741 /* Responder Bootstrapping Key Hash */
1742 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1744 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1745 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1747 /* Responder Protocol Key */
1749 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1750 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1751 wpabuf_put_buf(msg
, pr
);
1755 /* Protocol Version */
1756 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1757 wpabuf_put_le16(msg
, 1);
1758 wpabuf_put_u8(msg
, 2);
1759 #endif /* CONFIG_DPP2 */
1761 attr_end
= wpabuf_put(msg
, 0);
1763 #ifdef CONFIG_TESTING_OPTIONS
1764 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1765 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1766 goto skip_wrapped_data
;
1768 #endif /* CONFIG_TESTING_OPTIONS */
1770 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1775 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1777 WPA_PUT_LE16(pos
, nonce_len
);
1779 os_memcpy(pos
, r_nonce
, nonce_len
);
1785 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1787 WPA_PUT_LE16(pos
, nonce_len
);
1789 os_memcpy(pos
, i_nonce
, nonce_len
);
1790 #ifdef CONFIG_TESTING_OPTIONS
1791 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1792 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1793 pos
[nonce_len
/ 2] ^= 0x01;
1795 #endif /* CONFIG_TESTING_OPTIONS */
1799 #ifdef CONFIG_TESTING_OPTIONS
1800 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1801 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1804 #endif /* CONFIG_TESTING_OPTIONS */
1806 /* R-capabilities */
1807 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1809 WPA_PUT_LE16(pos
, 1);
1811 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1813 *pos
++ = auth
->r_capab
;
1814 #ifdef CONFIG_TESTING_OPTIONS
1815 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1816 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1818 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1819 wpa_printf(MSG_INFO
,
1820 "DPP: TESTING - incompatible R-capabilities");
1821 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1822 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1825 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1826 DPP_CAPAB_CONFIGURATOR
;
1829 #endif /* CONFIG_TESTING_OPTIONS */
1831 if (wrapped_r_auth
) {
1833 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1835 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1837 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1838 pos
+= wrapped_r_auth_len
;
1841 /* OUI, OUI type, Crypto Suite, DPP frame type */
1842 addr
[0] = wpabuf_head_u8(msg
) + 2;
1843 len
[0] = 3 + 1 + 1 + 1;
1844 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1846 /* Attributes before Wrapped Data */
1847 addr
[1] = attr_start
;
1848 len
[1] = attr_end
- attr_start
;
1849 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1851 siv_len
= pos
- clear
;
1852 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1853 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1854 2, addr
, len
, wrapped_data
) < 0) {
1858 siv_len
+= AES_BLOCK_SIZE
;
1859 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1860 wrapped_data
, siv_len
);
1862 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1863 wpabuf_put_le16(msg
, siv_len
);
1864 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1866 #ifdef CONFIG_TESTING_OPTIONS
1867 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1868 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1869 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1872 #endif /* CONFIG_TESTING_OPTIONS */
1874 wpa_hexdump_buf(MSG_DEBUG
,
1875 "DPP: Authentication Response frame attributes", msg
);
1880 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1881 u16 num_modes
, unsigned int freq
)
1886 if (!own_modes
|| !num_modes
)
1889 for (m
= 0; m
< num_modes
; m
++) {
1890 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1891 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1894 flag
= own_modes
[m
].channels
[c
].flag
;
1895 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1896 HOSTAPD_CHAN_NO_IR
|
1897 HOSTAPD_CHAN_RADAR
)))
1902 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1907 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1911 if (freqs
[--num
] == freq
)
1918 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1923 for (i
= 0; i
< num
; i
++) {
1924 if (freqs
[i
] == freq
)
1927 if (i
== 0 || i
>= num
)
1929 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1934 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1935 struct hostapd_hw_modes
*own_modes
,
1938 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1939 unsigned int i
, freq
;
1941 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
1942 freq
= peer_bi
->freq
[i
];
1943 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1945 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
1946 auth
->freq
[auth
->num_freq
++] = freq
;
1948 if (!auth
->num_freq
) {
1949 wpa_printf(MSG_INFO
,
1950 "DPP: No available channels for initiating DPP Authentication");
1953 auth
->curr_freq
= auth
->freq
[0];
1958 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
1959 struct hostapd_hw_modes
*own_modes
,
1968 if (!own_modes
|| !num_modes
) {
1969 auth
->freq
[0] = 2412;
1970 auth
->freq
[1] = 2437;
1971 auth
->freq
[2] = 2462;
1976 for (m
= 0; m
< num_modes
; m
++) {
1977 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1978 freq
= own_modes
[m
].channels
[c
].freq
;
1979 flag
= own_modes
[m
].channels
[c
].flag
;
1980 if (flag
& (HOSTAPD_CHAN_DISABLED
|
1981 HOSTAPD_CHAN_NO_IR
|
1982 HOSTAPD_CHAN_RADAR
))
1984 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1986 auth
->freq
[auth
->num_freq
++] = freq
;
1987 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
1994 return auth
->num_freq
== 0 ? -1 : 0;
1998 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
1999 struct hostapd_hw_modes
*own_modes
,
2003 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2006 if (auth
->peer_bi
->num_freq
> 0)
2007 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2009 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2013 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2014 * likely channels first. */
2015 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2016 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2017 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2020 auth
->curr_freq
= auth
->freq
[0];
2023 end
= pos
+ sizeof(freqs
);
2024 for (i
= 0; i
< auth
->num_freq
; i
++) {
2025 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2026 if (os_snprintf_error(end
- pos
, res
))
2031 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2038 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2040 struct dpp_bootstrap_info
*bi
;
2045 return 0; /* already generated */
2047 bi
= os_zalloc(sizeof(*bi
));
2050 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2051 pk
= dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0);
2055 len
= 4; /* "DPP:" */
2056 len
+= 4 + os_strlen(pk
);
2057 bi
->uri
= os_malloc(len
+ 1);
2060 os_snprintf(bi
->uri
, len
+ 1, "DPP:K:%s;;", pk
);
2061 wpa_printf(MSG_DEBUG
,
2062 "DPP: Auto-generated own bootstrapping key info: URI %s",
2065 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2072 dpp_bootstrap_info_free(bi
);
2077 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2078 struct dpp_bootstrap_info
*peer_bi
,
2079 struct dpp_bootstrap_info
*own_bi
,
2080 u8 dpp_allowed_roles
,
2081 unsigned int neg_freq
,
2082 struct hostapd_hw_modes
*own_modes
,
2085 struct dpp_authentication
*auth
;
2087 EVP_PKEY_CTX
*ctx
= NULL
;
2089 struct wpabuf
*pi
= NULL
;
2090 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2091 #ifdef CONFIG_TESTING_OPTIONS
2092 u8 test_hash
[SHA256_MAC_LEN
];
2093 #endif /* CONFIG_TESTING_OPTIONS */
2095 auth
= os_zalloc(sizeof(*auth
));
2098 auth
->msg_ctx
= msg_ctx
;
2099 auth
->initiator
= 1;
2100 auth
->waiting_auth_resp
= 1;
2101 auth
->allowed_roles
= dpp_allowed_roles
;
2102 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2103 auth
->peer_bi
= peer_bi
;
2104 auth
->own_bi
= own_bi
;
2105 auth
->curve
= peer_bi
->curve
;
2107 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2108 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2111 #ifdef CONFIG_TESTING_OPTIONS
2112 if (dpp_nonce_override_len
> 0) {
2113 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2114 nonce_len
= dpp_nonce_override_len
;
2115 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2117 nonce_len
= auth
->curve
->nonce_len
;
2118 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2119 wpa_printf(MSG_ERROR
,
2120 "DPP: Failed to generate I-nonce");
2124 #else /* CONFIG_TESTING_OPTIONS */
2125 nonce_len
= auth
->curve
->nonce_len
;
2126 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2127 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2130 #endif /* CONFIG_TESTING_OPTIONS */
2131 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2133 #ifdef CONFIG_TESTING_OPTIONS
2134 if (dpp_protocol_key_override_len
) {
2135 const struct dpp_curve_params
*tmp_curve
;
2137 wpa_printf(MSG_INFO
,
2138 "DPP: TESTING - override protocol key");
2139 auth
->own_protocol_key
= dpp_set_keypair(
2140 &tmp_curve
, dpp_protocol_key_override
,
2141 dpp_protocol_key_override_len
);
2143 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2145 #else /* CONFIG_TESTING_OPTIONS */
2146 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2147 #endif /* CONFIG_TESTING_OPTIONS */
2148 if (!auth
->own_protocol_key
)
2151 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2155 /* ECDH: M = pI * BR */
2156 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2158 EVP_PKEY_derive_init(ctx
) != 1 ||
2159 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
2160 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2161 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2162 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2163 wpa_printf(MSG_ERROR
,
2164 "DPP: Failed to derive ECDH shared secret: %s",
2165 ERR_error_string(ERR_get_error(), NULL
));
2168 auth
->secret_len
= secret_len
;
2169 EVP_PKEY_CTX_free(ctx
);
2172 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2173 auth
->Mx
, auth
->secret_len
);
2174 auth
->Mx_len
= auth
->secret_len
;
2176 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2177 auth
->curve
->hash_len
) < 0)
2180 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2181 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2183 #ifdef CONFIG_TESTING_OPTIONS
2184 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2185 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2186 r_pubkey_hash
= NULL
;
2187 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2188 wpa_printf(MSG_INFO
,
2189 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2190 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2191 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2192 r_pubkey_hash
= test_hash
;
2193 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2194 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2195 i_pubkey_hash
= NULL
;
2196 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2197 wpa_printf(MSG_INFO
,
2198 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2199 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2200 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2201 i_pubkey_hash
= test_hash
;
2202 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2203 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2206 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2207 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2209 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2210 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2213 #endif /* CONFIG_TESTING_OPTIONS */
2215 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2216 i_pubkey_hash
, neg_freq
);
2222 EVP_PKEY_CTX_free(ctx
);
2225 dpp_auth_deinit(auth
);
2231 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2235 size_t json_len
, clear_len
;
2236 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2240 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2242 nonce_len
= auth
->curve
->nonce_len
;
2243 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2244 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2247 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2248 json_len
= os_strlen(json
);
2249 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
2251 /* { E-nonce, configAttrib }ke */
2252 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2253 clear
= wpabuf_alloc(clear_len
);
2254 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2255 #ifdef CONFIG_TESTING_OPTIONS
2256 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2258 #endif /* CONFIG_TESTING_OPTIONS */
2259 msg
= wpabuf_alloc(attr_len
);
2263 #ifdef CONFIG_TESTING_OPTIONS
2264 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2265 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2268 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2269 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2270 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2271 wpabuf_put_le16(clear
, nonce_len
- 1);
2272 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2275 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2276 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2277 goto skip_wrapped_data
;
2279 #endif /* CONFIG_TESTING_OPTIONS */
2282 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2283 wpabuf_put_le16(clear
, nonce_len
);
2284 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2286 #ifdef CONFIG_TESTING_OPTIONS
2288 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2289 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2290 goto skip_conf_attr_obj
;
2292 #endif /* CONFIG_TESTING_OPTIONS */
2295 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2296 wpabuf_put_le16(clear
, json_len
);
2297 wpabuf_put_data(clear
, json
, json_len
);
2299 #ifdef CONFIG_TESTING_OPTIONS
2301 #endif /* CONFIG_TESTING_OPTIONS */
2303 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2304 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2305 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2308 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2309 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2310 wpabuf_head(clear
), wpabuf_len(clear
),
2311 0, NULL
, NULL
, wrapped
) < 0)
2313 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2314 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2316 #ifdef CONFIG_TESTING_OPTIONS
2317 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2318 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2319 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2322 #endif /* CONFIG_TESTING_OPTIONS */
2324 wpa_hexdump_buf(MSG_DEBUG
,
2325 "DPP: Configuration Request frame attributes", msg
);
2336 static void dpp_auth_success(struct dpp_authentication
*auth
)
2338 wpa_printf(MSG_DEBUG
,
2339 "DPP: Authentication success - clear temporary keys");
2340 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2342 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2344 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2346 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2347 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2349 auth
->auth_success
= 1;
2353 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2355 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2358 size_t i
, num_elem
= 0;
2363 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2364 nonce_len
= auth
->curve
->nonce_len
;
2366 if (auth
->initiator
) {
2367 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2368 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2370 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2373 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2375 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2376 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2378 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2381 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2383 if (!pix
|| !prx
|| !brx
)
2386 addr
[num_elem
] = auth
->i_nonce
;
2387 len
[num_elem
] = nonce_len
;
2390 addr
[num_elem
] = auth
->r_nonce
;
2391 len
[num_elem
] = nonce_len
;
2394 addr
[num_elem
] = wpabuf_head(pix
);
2395 len
[num_elem
] = wpabuf_len(pix
) / 2;
2398 addr
[num_elem
] = wpabuf_head(prx
);
2399 len
[num_elem
] = wpabuf_len(prx
) / 2;
2403 addr
[num_elem
] = wpabuf_head(bix
);
2404 len
[num_elem
] = wpabuf_len(bix
) / 2;
2408 addr
[num_elem
] = wpabuf_head(brx
);
2409 len
[num_elem
] = wpabuf_len(brx
) / 2;
2412 addr
[num_elem
] = &zero
;
2416 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2417 for (i
= 0; i
< num_elem
; i
++)
2418 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2419 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2421 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2422 auth
->curve
->hash_len
);
2432 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2434 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2437 size_t i
, num_elem
= 0;
2442 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2443 nonce_len
= auth
->curve
->nonce_len
;
2445 if (auth
->initiator
) {
2446 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2447 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2449 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2454 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2456 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2457 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2459 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2464 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2466 if (!pix
|| !prx
|| !brx
)
2469 addr
[num_elem
] = auth
->r_nonce
;
2470 len
[num_elem
] = nonce_len
;
2473 addr
[num_elem
] = auth
->i_nonce
;
2474 len
[num_elem
] = nonce_len
;
2477 addr
[num_elem
] = wpabuf_head(prx
);
2478 len
[num_elem
] = wpabuf_len(prx
) / 2;
2481 addr
[num_elem
] = wpabuf_head(pix
);
2482 len
[num_elem
] = wpabuf_len(pix
) / 2;
2485 addr
[num_elem
] = wpabuf_head(brx
);
2486 len
[num_elem
] = wpabuf_len(brx
) / 2;
2490 addr
[num_elem
] = wpabuf_head(bix
);
2491 len
[num_elem
] = wpabuf_len(bix
) / 2;
2495 addr
[num_elem
] = &one
;
2499 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2500 for (i
= 0; i
< num_elem
; i
++)
2501 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2502 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2504 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2505 auth
->curve
->hash_len
);
2515 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2517 const EC_GROUP
*group
;
2519 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2520 const EC_POINT
*BI_point
;
2522 BIGNUM
*lx
, *sum
, *q
;
2523 const BIGNUM
*bR_bn
, *pR_bn
;
2526 /* L = ((bR + pR) modulo q) * BI */
2528 bnctx
= BN_CTX_new();
2532 if (!bnctx
|| !sum
|| !q
|| !lx
)
2534 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2537 BI_point
= EC_KEY_get0_public_key(BI
);
2538 group
= EC_KEY_get0_group(BI
);
2542 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2543 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2546 bR_bn
= EC_KEY_get0_private_key(bR
);
2547 pR_bn
= EC_KEY_get0_private_key(pR
);
2548 if (!bR_bn
|| !pR_bn
)
2550 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2551 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2553 l
= EC_POINT_new(group
);
2555 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2556 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2558 wpa_printf(MSG_ERROR
,
2559 "OpenSSL: failed: %s",
2560 ERR_error_string(ERR_get_error(), NULL
));
2564 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2566 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2567 auth
->Lx_len
= auth
->secret_len
;
2570 EC_POINT_clear_free(l
);
2582 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2584 const EC_GROUP
*group
;
2585 EC_POINT
*l
= NULL
, *sum
= NULL
;
2586 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2587 const EC_POINT
*BR_point
, *PR_point
;
2590 const BIGNUM
*bI_bn
;
2593 /* L = bI * (BR + PR) */
2595 bnctx
= BN_CTX_new();
2599 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2600 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2603 BR_point
= EC_KEY_get0_public_key(BR
);
2604 PR_point
= EC_KEY_get0_public_key(PR
);
2606 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2609 group
= EC_KEY_get0_group(bI
);
2610 bI_bn
= EC_KEY_get0_private_key(bI
);
2611 if (!group
|| !bI_bn
)
2613 sum
= EC_POINT_new(group
);
2614 l
= EC_POINT_new(group
);
2616 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2617 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2618 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2620 wpa_printf(MSG_ERROR
,
2621 "OpenSSL: failed: %s",
2622 ERR_error_string(ERR_get_error(), NULL
));
2626 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2628 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2629 auth
->Lx_len
= auth
->secret_len
;
2632 EC_POINT_clear_free(l
);
2633 EC_POINT_clear_free(sum
);
2643 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2646 EVP_PKEY_CTX
*ctx
= NULL
;
2648 struct wpabuf
*msg
, *pr
= NULL
;
2649 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2650 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2651 size_t wrapped_r_auth_len
;
2653 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2654 enum dpp_status_error status
= DPP_STATUS_OK
;
2655 #ifdef CONFIG_TESTING_OPTIONS
2656 u8 test_hash
[SHA256_MAC_LEN
];
2657 #endif /* CONFIG_TESTING_OPTIONS */
2659 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2663 #ifdef CONFIG_TESTING_OPTIONS
2664 if (dpp_nonce_override_len
> 0) {
2665 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
2666 nonce_len
= dpp_nonce_override_len
;
2667 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
2669 nonce_len
= auth
->curve
->nonce_len
;
2670 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2671 wpa_printf(MSG_ERROR
,
2672 "DPP: Failed to generate R-nonce");
2676 #else /* CONFIG_TESTING_OPTIONS */
2677 nonce_len
= auth
->curve
->nonce_len
;
2678 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2679 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2682 #endif /* CONFIG_TESTING_OPTIONS */
2683 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2685 #ifdef CONFIG_TESTING_OPTIONS
2686 if (dpp_protocol_key_override_len
) {
2687 const struct dpp_curve_params
*tmp_curve
;
2689 wpa_printf(MSG_INFO
,
2690 "DPP: TESTING - override protocol key");
2691 auth
->own_protocol_key
= dpp_set_keypair(
2692 &tmp_curve
, dpp_protocol_key_override
,
2693 dpp_protocol_key_override_len
);
2695 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2697 #else /* CONFIG_TESTING_OPTIONS */
2698 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2699 #endif /* CONFIG_TESTING_OPTIONS */
2700 if (!auth
->own_protocol_key
)
2703 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2707 /* ECDH: N = pR * PI */
2708 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2710 EVP_PKEY_derive_init(ctx
) != 1 ||
2711 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2712 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2713 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2714 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2715 wpa_printf(MSG_ERROR
,
2716 "DPP: Failed to derive ECDH shared secret: %s",
2717 ERR_error_string(ERR_get_error(), NULL
));
2720 EVP_PKEY_CTX_free(ctx
);
2723 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2724 auth
->Nx
, auth
->secret_len
);
2725 auth
->Nx_len
= auth
->secret_len
;
2727 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2728 auth
->curve
->hash_len
) < 0)
2731 if (auth
->own_bi
&& auth
->peer_bi
) {
2732 /* Mutual authentication */
2733 if (dpp_auth_derive_l_responder(auth
) < 0)
2737 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2740 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2741 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2742 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2743 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2745 #ifdef CONFIG_TESTING_OPTIONS
2746 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2747 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2748 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2750 #endif /* CONFIG_TESTING_OPTIONS */
2751 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2752 r_auth
, 4 + auth
->curve
->hash_len
,
2753 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2755 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2756 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2757 wrapped_r_auth
, wrapped_r_auth_len
);
2758 w_r_auth
= wrapped_r_auth
;
2760 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2762 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2764 i_pubkey_hash
= NULL
;
2766 i_nonce
= auth
->i_nonce
;
2767 r_nonce
= auth
->r_nonce
;
2769 #ifdef CONFIG_TESTING_OPTIONS
2770 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2771 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2772 r_pubkey_hash
= NULL
;
2773 } else if (dpp_test
==
2774 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2775 wpa_printf(MSG_INFO
,
2776 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2777 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2778 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2779 r_pubkey_hash
= test_hash
;
2780 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2781 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2782 i_pubkey_hash
= NULL
;
2783 } else if (dpp_test
==
2784 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2785 wpa_printf(MSG_INFO
,
2786 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2788 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2790 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2791 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2792 i_pubkey_hash
= test_hash
;
2793 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2794 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2797 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
2798 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
2800 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2801 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
2803 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2804 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2806 wrapped_r_auth_len
= 0;
2807 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2808 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2810 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
2811 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
2813 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2814 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2816 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2817 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2820 #endif /* CONFIG_TESTING_OPTIONS */
2822 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2823 r_pubkey_hash
, i_pubkey_hash
,
2825 w_r_auth
, wrapped_r_auth_len
,
2829 wpabuf_free(auth
->resp_msg
);
2830 auth
->resp_msg
= msg
;
2838 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2839 enum dpp_status_error status
)
2842 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2843 #ifdef CONFIG_TESTING_OPTIONS
2844 u8 test_hash
[SHA256_MAC_LEN
];
2845 #endif /* CONFIG_TESTING_OPTIONS */
2849 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2851 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2853 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2855 i_pubkey_hash
= NULL
;
2857 i_nonce
= auth
->i_nonce
;
2859 #ifdef CONFIG_TESTING_OPTIONS
2860 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2861 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2862 r_pubkey_hash
= NULL
;
2863 } else if (dpp_test
==
2864 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2865 wpa_printf(MSG_INFO
,
2866 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2867 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2868 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2869 r_pubkey_hash
= test_hash
;
2870 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2871 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2872 i_pubkey_hash
= NULL
;
2873 } else if (dpp_test
==
2874 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2875 wpa_printf(MSG_INFO
,
2876 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2878 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2880 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2881 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2882 i_pubkey_hash
= test_hash
;
2883 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2884 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2886 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2887 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2890 #endif /* CONFIG_TESTING_OPTIONS */
2892 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
2893 r_pubkey_hash
, i_pubkey_hash
,
2894 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
2897 wpabuf_free(auth
->resp_msg
);
2898 auth
->resp_msg
= msg
;
2903 struct dpp_authentication
*
2904 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
2905 struct dpp_bootstrap_info
*peer_bi
,
2906 struct dpp_bootstrap_info
*own_bi
,
2907 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
2910 EVP_PKEY
*pi
= NULL
;
2911 EVP_PKEY_CTX
*ctx
= NULL
;
2915 u8
*unwrapped
= NULL
;
2916 size_t unwrapped_len
= 0;
2917 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
2919 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
2920 i_bootstrap_len
, channel_len
;
2921 struct dpp_authentication
*auth
= NULL
;
2925 #endif /* CONFIG_DPP2 */
2927 #ifdef CONFIG_TESTING_OPTIONS
2928 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
2929 wpa_printf(MSG_INFO
,
2930 "DPP: TESTING - stop at Authentication Request");
2933 #endif /* CONFIG_TESTING_OPTIONS */
2935 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2937 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
2938 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
2939 "Missing or invalid required Wrapped Data attribute");
2942 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
2943 wrapped_data
, wrapped_data_len
);
2944 attr_len
= wrapped_data
- 4 - attr_start
;
2946 auth
= os_zalloc(sizeof(*auth
));
2949 auth
->msg_ctx
= msg_ctx
;
2950 auth
->peer_bi
= peer_bi
;
2951 auth
->own_bi
= own_bi
;
2952 auth
->curve
= own_bi
->curve
;
2953 auth
->curr_freq
= freq
;
2955 auth
->peer_version
= 1; /* default to the first version */
2957 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
2960 if (version_len
< 1 || version
[0] == 0) {
2962 "Invalid Protocol Version attribute");
2965 auth
->peer_version
= version
[0];
2966 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
2967 auth
->peer_version
);
2969 #endif /* CONFIG_DPP2 */
2971 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
2976 if (channel_len
< 2) {
2977 dpp_auth_fail(auth
, "Too short Channel attribute");
2981 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
2982 wpa_printf(MSG_DEBUG
,
2983 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2984 channel
[0], channel
[1], neg_freq
);
2987 "Unsupported Channel attribute value");
2991 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
2992 wpa_printf(MSG_DEBUG
,
2993 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2995 auth
->curr_freq
= neg_freq
;
2999 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3003 "Missing required Initiator Protocol Key attribute");
3006 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3007 i_proto
, i_proto_len
);
3010 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3012 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3015 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3017 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
3019 EVP_PKEY_derive_init(ctx
) != 1 ||
3020 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
3021 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3022 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3023 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
3024 wpa_printf(MSG_ERROR
,
3025 "DPP: Failed to derive ECDH shared secret: %s",
3026 ERR_error_string(ERR_get_error(), NULL
));
3027 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3030 auth
->secret_len
= secret_len
;
3031 EVP_PKEY_CTX_free(ctx
);
3034 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3035 auth
->Mx
, auth
->secret_len
);
3036 auth
->Mx_len
= auth
->secret_len
;
3038 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3039 auth
->curve
->hash_len
) < 0)
3043 len
[0] = DPP_HDR_LEN
;
3044 addr
[1] = attr_start
;
3046 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3047 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3048 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3049 wrapped_data
, wrapped_data_len
);
3050 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3051 unwrapped
= os_malloc(unwrapped_len
);
3054 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3055 wrapped_data
, wrapped_data_len
,
3056 2, addr
, len
, unwrapped
) < 0) {
3057 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3060 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3061 unwrapped
, unwrapped_len
);
3063 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3064 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3068 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3070 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3071 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3074 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3075 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3077 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3078 DPP_ATTR_I_CAPABILITIES
,
3080 if (!i_capab
|| i_capab_len
< 1) {
3081 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3084 auth
->i_capab
= i_capab
[0];
3085 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3087 bin_clear_free(unwrapped
, unwrapped_len
);
3090 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3091 case DPP_CAPAB_ENROLLEE
:
3092 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3093 wpa_printf(MSG_DEBUG
,
3094 "DPP: Local policy does not allow Configurator role");
3095 goto not_compatible
;
3097 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3098 auth
->configurator
= 1;
3100 case DPP_CAPAB_CONFIGURATOR
:
3101 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3102 wpa_printf(MSG_DEBUG
,
3103 "DPP: Local policy does not allow Enrollee role");
3104 goto not_compatible
;
3106 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3107 auth
->configurator
= 0;
3109 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3110 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3111 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3112 auth
->configurator
= 0;
3113 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3114 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3115 auth
->configurator
= 1;
3117 wpa_printf(MSG_DEBUG
,
3118 "DPP: Local policy does not allow Configurator/Enrollee role");
3119 goto not_compatible
;
3123 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3124 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3125 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3126 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3130 auth
->peer_protocol_key
= pi
;
3132 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3133 char hex
[SHA256_MAC_LEN
* 2 + 1];
3135 wpa_printf(MSG_DEBUG
,
3136 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3137 if (dpp_auth_build_resp_status(auth
,
3138 DPP_STATUS_RESPONSE_PENDING
) < 0)
3140 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3141 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3143 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3144 auth
->response_pending
= 1;
3145 os_memcpy(auth
->waiting_pubkey_hash
,
3146 i_bootstrap
, i_bootstrap_len
);
3147 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3153 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3157 if (dpp_auth_build_resp_ok(auth
) < 0)
3163 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3164 "i-capab=0x%02x", auth
->i_capab
);
3165 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3166 auth
->configurator
= 1;
3168 auth
->configurator
= 0;
3169 auth
->peer_protocol_key
= pi
;
3171 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3174 auth
->remove_on_tx_status
= 1;
3177 bin_clear_free(unwrapped
, unwrapped_len
);
3179 EVP_PKEY_CTX_free(ctx
);
3180 dpp_auth_deinit(auth
);
3185 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3186 struct dpp_bootstrap_info
*peer_bi
)
3188 if (!auth
|| !auth
->response_pending
||
3189 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3190 SHA256_MAC_LEN
) != 0)
3193 wpa_printf(MSG_DEBUG
,
3194 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3195 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3196 auth
->peer_bi
= peer_bi
;
3198 if (dpp_auth_build_resp_ok(auth
) < 0)
3205 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3206 enum dpp_status_error status
)
3209 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3211 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3214 size_t len
[2], attr_len
;
3216 u8
*wrapped_r_nonce
;
3217 u8
*attr_start
, *attr_end
;
3218 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3219 #ifdef CONFIG_TESTING_OPTIONS
3220 u8 test_hash
[SHA256_MAC_LEN
];
3221 #endif /* CONFIG_TESTING_OPTIONS */
3223 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3225 i_auth_len
= 4 + auth
->curve
->hash_len
;
3226 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3227 /* Build DPP Authentication Confirmation frame attributes */
3228 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3229 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3230 #ifdef CONFIG_TESTING_OPTIONS
3231 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3233 #endif /* CONFIG_TESTING_OPTIONS */
3234 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3238 attr_start
= wpabuf_put(msg
, 0);
3240 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3242 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3244 i_pubkey_hash
= NULL
;
3246 #ifdef CONFIG_TESTING_OPTIONS
3247 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3248 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3250 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3251 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3254 #endif /* CONFIG_TESTING_OPTIONS */
3257 dpp_build_attr_status(msg
, status
);
3259 #ifdef CONFIG_TESTING_OPTIONS
3261 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3262 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3263 r_pubkey_hash
= NULL
;
3264 } else if (dpp_test
==
3265 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3266 wpa_printf(MSG_INFO
,
3267 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3268 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3269 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3270 r_pubkey_hash
= test_hash
;
3271 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3272 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3273 i_pubkey_hash
= NULL
;
3274 } else if (dpp_test
==
3275 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3276 wpa_printf(MSG_INFO
,
3277 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3279 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3281 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3282 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3283 i_pubkey_hash
= test_hash
;
3285 #endif /* CONFIG_TESTING_OPTIONS */
3287 /* Responder Bootstrapping Key Hash */
3288 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3290 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3291 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3293 #ifdef CONFIG_TESTING_OPTIONS
3294 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3295 goto skip_wrapped_data
;
3296 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3298 #endif /* CONFIG_TESTING_OPTIONS */
3300 attr_end
= wpabuf_put(msg
, 0);
3302 /* OUI, OUI type, Crypto Suite, DPP frame type */
3303 addr
[0] = wpabuf_head_u8(msg
) + 2;
3304 len
[0] = 3 + 1 + 1 + 1;
3305 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3307 /* Attributes before Wrapped Data */
3308 addr
[1] = attr_start
;
3309 len
[1] = attr_end
- attr_start
;
3310 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3312 if (status
== DPP_STATUS_OK
) {
3313 /* I-auth wrapped with ke */
3314 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3315 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3316 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3318 #ifdef CONFIG_TESTING_OPTIONS
3319 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3321 #endif /* CONFIG_TESTING_OPTIONS */
3323 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3325 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3326 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3327 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3330 #ifdef CONFIG_TESTING_OPTIONS
3331 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3332 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3333 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3336 #endif /* CONFIG_TESTING_OPTIONS */
3337 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3339 2, addr
, len
, wrapped_i_auth
) < 0)
3341 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3342 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3344 /* R-nonce wrapped with k2 */
3345 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3346 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3347 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3349 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3350 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3351 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3353 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3354 r_nonce
, r_nonce_len
,
3355 2, addr
, len
, wrapped_r_nonce
) < 0)
3357 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3358 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3361 #ifdef CONFIG_TESTING_OPTIONS
3362 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3363 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3364 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3367 #endif /* CONFIG_TESTING_OPTIONS */
3369 wpa_hexdump_buf(MSG_DEBUG
,
3370 "DPP: Authentication Confirmation frame attributes",
3372 if (status
== DPP_STATUS_OK
)
3373 dpp_auth_success(auth
);
3384 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3385 const u8
*attr_start
, size_t attr_len
,
3386 const u8
*wrapped_data
, u16 wrapped_data_len
,
3387 enum dpp_status_error status
)
3391 u8
*unwrapped
= NULL
;
3392 size_t unwrapped_len
= 0;
3393 const u8
*i_nonce
, *r_capab
;
3394 u16 i_nonce_len
, r_capab_len
;
3396 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3397 wpa_printf(MSG_DEBUG
,
3398 "DPP: Responder reported incompatible roles");
3399 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3400 wpa_printf(MSG_DEBUG
,
3401 "DPP: Responder reported more time needed");
3403 wpa_printf(MSG_DEBUG
,
3404 "DPP: Responder reported failure (status %d)",
3406 dpp_auth_fail(auth
, "Responder reported failure");
3411 len
[0] = DPP_HDR_LEN
;
3412 addr
[1] = attr_start
;
3414 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3415 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3416 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3417 wrapped_data
, wrapped_data_len
);
3418 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3419 unwrapped
= os_malloc(unwrapped_len
);
3422 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3423 wrapped_data
, wrapped_data_len
,
3424 2, addr
, len
, unwrapped
) < 0) {
3425 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3428 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3429 unwrapped
, unwrapped_len
);
3431 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3432 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3436 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3438 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3439 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3442 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3443 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3444 dpp_auth_fail(auth
, "I-nonce mismatch");
3448 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3449 DPP_ATTR_R_CAPABILITIES
,
3451 if (!r_capab
|| r_capab_len
< 1) {
3452 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3455 auth
->r_capab
= r_capab
[0];
3456 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3457 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3458 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3459 "r-capab=0x%02x", auth
->r_capab
);
3460 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3461 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3463 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3464 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3465 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3466 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3469 wpa_printf(MSG_DEBUG
,
3470 "DPP: Continue waiting for full DPP Authentication Response");
3471 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3472 DPP_EVENT_RESPONSE_PENDING
"%s",
3473 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3477 bin_clear_free(unwrapped
, unwrapped_len
);
3482 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3483 const u8
*attr_start
, size_t attr_len
)
3486 EVP_PKEY_CTX
*ctx
= NULL
;
3490 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3491 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3492 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3493 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3494 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3495 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3496 wrapped2_len
, r_auth_len
;
3497 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3502 #endif /* CONFIG_DPP2 */
3504 #ifdef CONFIG_TESTING_OPTIONS
3505 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3506 wpa_printf(MSG_INFO
,
3507 "DPP: TESTING - stop at Authentication Response");
3510 #endif /* CONFIG_TESTING_OPTIONS */
3512 if (!auth
->initiator
|| !auth
->peer_bi
) {
3513 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3517 auth
->waiting_auth_resp
= 0;
3519 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3521 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3523 "Missing or invalid required Wrapped Data attribute");
3526 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3527 wrapped_data
, wrapped_data_len
);
3529 attr_len
= wrapped_data
- 4 - attr_start
;
3531 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3532 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3534 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3536 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3539 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3540 r_bootstrap
, r_bootstrap_len
);
3541 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3542 SHA256_MAC_LEN
) != 0) {
3544 "Unexpected Responder Bootstrapping Key Hash value");
3545 wpa_hexdump(MSG_DEBUG
,
3546 "DPP: Expected Responder Bootstrapping Key Hash",
3547 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3551 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3552 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3555 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3557 "Invalid Initiator Bootstrapping Key Hash attribute");
3560 wpa_hexdump(MSG_MSGDUMP
,
3561 "DPP: Initiator Bootstrapping Key Hash",
3562 i_bootstrap
, i_bootstrap_len
);
3563 if (!auth
->own_bi
||
3564 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3565 SHA256_MAC_LEN
) != 0) {
3567 "Initiator Bootstrapping Key Hash attribute did not match");
3570 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3571 /* PKEX bootstrapping mandates use of mutual authentication */
3573 "Missing Initiator Bootstrapping Key Hash attribute");
3577 auth
->peer_version
= 1; /* default to the first version */
3579 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3582 if (version_len
< 1 || version
[0] == 0) {
3584 "Invalid Protocol Version attribute");
3587 auth
->peer_version
= version
[0];
3588 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3589 auth
->peer_version
);
3591 #endif /* CONFIG_DPP2 */
3593 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3595 if (!status
|| status_len
< 1) {
3597 "Missing or invalid required DPP Status attribute");
3600 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3601 auth
->auth_resp_status
= status
[0];
3602 if (status
[0] != DPP_STATUS_OK
) {
3603 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3604 attr_len
, wrapped_data
,
3605 wrapped_data_len
, status
[0]);
3609 if (!i_bootstrap
&& auth
->own_bi
) {
3610 wpa_printf(MSG_DEBUG
,
3611 "DPP: Responder decided not to use mutual authentication");
3612 auth
->own_bi
= NULL
;
3615 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3616 auth
->own_bi
!= NULL
);
3618 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3622 "Missing required Responder Protocol Key attribute");
3625 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3626 r_proto
, r_proto_len
);
3629 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3631 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3634 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3636 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3638 EVP_PKEY_derive_init(ctx
) != 1 ||
3639 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3640 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3641 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3642 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3643 wpa_printf(MSG_ERROR
,
3644 "DPP: Failed to derive ECDH shared secret: %s",
3645 ERR_error_string(ERR_get_error(), NULL
));
3646 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3649 EVP_PKEY_CTX_free(ctx
);
3651 auth
->peer_protocol_key
= pr
;
3654 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3655 auth
->Nx
, auth
->secret_len
);
3656 auth
->Nx_len
= auth
->secret_len
;
3658 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3659 auth
->curve
->hash_len
) < 0)
3663 len
[0] = DPP_HDR_LEN
;
3664 addr
[1] = attr_start
;
3666 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3667 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3668 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3669 wrapped_data
, wrapped_data_len
);
3670 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3671 unwrapped
= os_malloc(unwrapped_len
);
3674 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3675 wrapped_data
, wrapped_data_len
,
3676 2, addr
, len
, unwrapped
) < 0) {
3677 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3680 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3681 unwrapped
, unwrapped_len
);
3683 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3684 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3688 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3690 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3691 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3694 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3695 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3697 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3699 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3700 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3703 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3704 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3705 dpp_auth_fail(auth
, "I-nonce mismatch");
3710 /* Mutual authentication */
3711 if (dpp_auth_derive_l_initiator(auth
) < 0)
3715 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3716 DPP_ATTR_R_CAPABILITIES
,
3718 if (!r_capab
|| r_capab_len
< 1) {
3719 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3722 auth
->r_capab
= r_capab
[0];
3723 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3724 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3725 if ((auth
->allowed_roles
==
3726 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3727 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3728 /* Peer selected its role, so move from "either role" to the
3729 * role that is compatible with peer's selection. */
3730 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3731 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3732 auth
->configurator
? "Configurator" : "Enrollee");
3733 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3734 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3735 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3736 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3737 "Unexpected role in R-capabilities 0x%02x",
3739 if (role
!= DPP_CAPAB_ENROLLEE
&&
3740 role
!= DPP_CAPAB_CONFIGURATOR
)
3742 bin_clear_free(unwrapped
, unwrapped_len
);
3743 auth
->remove_on_tx_status
= 1;
3744 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3747 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3748 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3749 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3751 "Missing or invalid Secondary Wrapped Data");
3755 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3756 wrapped2
, wrapped2_len
);
3758 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3761 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3762 unwrapped2
= os_malloc(unwrapped2_len
);
3765 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3766 wrapped2
, wrapped2_len
,
3767 0, NULL
, NULL
, unwrapped2
) < 0) {
3768 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3771 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3772 unwrapped2
, unwrapped2_len
);
3774 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3776 "Invalid attribute in secondary unwrapped data");
3780 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3782 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3784 "Missing or invalid Responder Authenticating Tag");
3787 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3788 r_auth
, r_auth_len
);
3789 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3790 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3792 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3793 r_auth2
, r_auth_len
);
3794 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3795 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3796 bin_clear_free(unwrapped
, unwrapped_len
);
3797 bin_clear_free(unwrapped2
, unwrapped2_len
);
3798 auth
->remove_on_tx_status
= 1;
3799 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3802 bin_clear_free(unwrapped
, unwrapped_len
);
3803 bin_clear_free(unwrapped2
, unwrapped2_len
);
3805 #ifdef CONFIG_TESTING_OPTIONS
3806 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
3807 wpa_printf(MSG_INFO
,
3808 "DPP: TESTING - Authentication Response in place of Confirm");
3809 if (dpp_auth_build_resp_ok(auth
) < 0)
3811 return wpabuf_dup(auth
->resp_msg
);
3813 #endif /* CONFIG_TESTING_OPTIONS */
3815 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3818 bin_clear_free(unwrapped
, unwrapped_len
);
3819 bin_clear_free(unwrapped2
, unwrapped2_len
);
3821 EVP_PKEY_CTX_free(ctx
);
3826 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3828 const u8
*attr_start
, size_t attr_len
,
3829 const u8
*wrapped_data
,
3830 u16 wrapped_data_len
,
3831 enum dpp_status_error status
)
3835 u8
*unwrapped
= NULL
;
3836 size_t unwrapped_len
= 0;
3840 /* Authentication Confirm failure cases are expected to include
3841 * {R-nonce}k2 in the Wrapped Data attribute. */
3844 len
[0] = DPP_HDR_LEN
;
3845 addr
[1] = attr_start
;
3847 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3848 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3849 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3850 wrapped_data
, wrapped_data_len
);
3851 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3852 unwrapped
= os_malloc(unwrapped_len
);
3854 dpp_auth_fail(auth
, "Authentication failed");
3857 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3858 wrapped_data
, wrapped_data_len
,
3859 2, addr
, len
, unwrapped
) < 0) {
3860 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3863 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3864 unwrapped
, unwrapped_len
);
3866 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3867 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3871 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3873 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3874 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3877 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3878 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3879 r_nonce
, r_nonce_len
);
3880 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3881 auth
->r_nonce
, r_nonce_len
);
3882 dpp_auth_fail(auth
, "R-nonce mismatch");
3886 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3887 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3888 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3889 dpp_auth_fail(auth
, "Peer reported authentication failure)");
3892 bin_clear_free(unwrapped
, unwrapped_len
);
3897 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3898 const u8
*attr_start
, size_t attr_len
)
3900 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
3901 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3905 u8
*unwrapped
= NULL
;
3906 size_t unwrapped_len
= 0;
3907 u8 i_auth2
[DPP_MAX_HASH_LEN
];
3909 #ifdef CONFIG_TESTING_OPTIONS
3910 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
3911 wpa_printf(MSG_INFO
,
3912 "DPP: TESTING - stop at Authentication Confirm");
3915 #endif /* CONFIG_TESTING_OPTIONS */
3917 if (auth
->initiator
|| !auth
->own_bi
) {
3918 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
3922 auth
->waiting_auth_conf
= 0;
3924 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3926 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3928 "Missing or invalid required Wrapped Data attribute");
3931 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3932 wrapped_data
, wrapped_data_len
);
3934 attr_len
= wrapped_data
- 4 - attr_start
;
3936 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3937 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3939 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3941 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3944 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3945 r_bootstrap
, r_bootstrap_len
);
3946 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
3947 SHA256_MAC_LEN
) != 0) {
3948 wpa_hexdump(MSG_DEBUG
,
3949 "DPP: Expected Responder Bootstrapping Key Hash",
3950 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3952 "Responder Bootstrapping Key Hash mismatch");
3956 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3957 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3960 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3962 "Invalid Initiator Bootstrapping Key Hash attribute");
3965 wpa_hexdump(MSG_MSGDUMP
,
3966 "DPP: Initiator Bootstrapping Key Hash",
3967 i_bootstrap
, i_bootstrap_len
);
3968 if (!auth
->peer_bi
||
3969 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3970 SHA256_MAC_LEN
) != 0) {
3972 "Initiator Bootstrapping Key Hash mismatch");
3975 } else if (auth
->peer_bi
) {
3976 /* Mutual authentication and peer did not include its
3977 * Bootstrapping Key Hash attribute. */
3979 "Missing Initiator Bootstrapping Key Hash attribute");
3983 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3985 if (!status
|| status_len
< 1) {
3987 "Missing or invalid required DPP Status attribute");
3990 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3991 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
3992 status
[0] == DPP_STATUS_AUTH_FAILURE
)
3993 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
3994 attr_len
, wrapped_data
,
3995 wrapped_data_len
, status
[0]);
3997 if (status
[0] != DPP_STATUS_OK
) {
3998 dpp_auth_fail(auth
, "Authentication failed");
4003 len
[0] = DPP_HDR_LEN
;
4004 addr
[1] = attr_start
;
4006 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4007 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4008 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4009 wrapped_data
, wrapped_data_len
);
4010 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4011 unwrapped
= os_malloc(unwrapped_len
);
4014 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4015 wrapped_data
, wrapped_data_len
,
4016 2, addr
, len
, unwrapped
) < 0) {
4017 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4020 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4021 unwrapped
, unwrapped_len
);
4023 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4024 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4028 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4030 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4032 "Missing or invalid Initiator Authenticating Tag");
4035 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4036 i_auth
, i_auth_len
);
4037 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4038 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4040 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4041 i_auth2
, i_auth_len
);
4042 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4043 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4047 bin_clear_free(unwrapped
, unwrapped_len
);
4048 dpp_auth_success(auth
);
4051 bin_clear_free(unwrapped
, unwrapped_len
);
4056 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4058 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4062 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4064 struct dpp_configuration
*conf
;
4068 conf
= os_zalloc(sizeof(*conf
));
4072 end
= os_strchr(type
, ' ');
4076 len
= os_strlen(type
);
4078 if (bin_str_eq(type
, len
, "psk"))
4079 conf
->akm
= DPP_AKM_PSK
;
4080 else if (bin_str_eq(type
, len
, "sae"))
4081 conf
->akm
= DPP_AKM_SAE
;
4082 else if (bin_str_eq(type
, len
, "psk-sae") ||
4083 bin_str_eq(type
, len
, "psk+sae"))
4084 conf
->akm
= DPP_AKM_PSK_SAE
;
4085 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4086 bin_str_eq(type
, len
, "dpp+sae"))
4087 conf
->akm
= DPP_AKM_SAE_DPP
;
4088 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4089 bin_str_eq(type
, len
, "dpp+psk+sae"))
4090 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4091 else if (bin_str_eq(type
, len
, "dpp"))
4092 conf
->akm
= DPP_AKM_DPP
;
4098 dpp_configuration_free(conf
);
4103 int dpp_akm_psk(enum dpp_akm akm
)
4105 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4106 akm
== DPP_AKM_PSK_SAE_DPP
;
4110 int dpp_akm_sae(enum dpp_akm akm
)
4112 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4113 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4117 int dpp_akm_legacy(enum dpp_akm akm
)
4119 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4124 int dpp_akm_dpp(enum dpp_akm akm
)
4126 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4127 akm
== DPP_AKM_PSK_SAE_DPP
;
4131 int dpp_akm_ver2(enum dpp_akm akm
)
4133 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4137 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4139 if (conf
->ssid_len
== 0)
4141 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4143 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4149 void dpp_configuration_free(struct dpp_configuration
*conf
)
4153 str_clear_free(conf
->passphrase
);
4154 os_free(conf
->group_id
);
4155 bin_clear_free(conf
, sizeof(*conf
));
4159 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4162 const char *pos
, *end
;
4163 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4164 struct dpp_configuration
*conf
= NULL
;
4166 pos
= os_strstr(cmd
, " conf=sta-");
4168 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4174 pos
= os_strstr(cmd
, " conf=ap-");
4176 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4185 pos
= os_strstr(cmd
, " ssid=");
4188 end
= os_strchr(pos
, ' ');
4189 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4190 conf
->ssid_len
/= 2;
4191 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4192 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4195 #ifdef CONFIG_TESTING_OPTIONS
4196 /* use a default SSID for legacy testing reasons */
4197 os_memcpy(conf
->ssid
, "test", 4);
4199 #else /* CONFIG_TESTING_OPTIONS */
4201 #endif /* CONFIG_TESTING_OPTIONS */
4204 pos
= os_strstr(cmd
, " pass=");
4209 end
= os_strchr(pos
, ' ');
4210 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4212 if (pass_len
> 63 || pass_len
< 8)
4214 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4215 if (!conf
->passphrase
||
4216 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4220 pos
= os_strstr(cmd
, " psk=");
4223 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4228 pos
= os_strstr(cmd
, " group_id=");
4230 size_t group_id_len
;
4233 end
= os_strchr(pos
, ' ');
4234 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4235 conf
->group_id
= os_malloc(group_id_len
+ 1);
4236 if (!conf
->group_id
)
4238 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4239 conf
->group_id
[group_id_len
] = '\0';
4242 pos
= os_strstr(cmd
, " expiry=");
4247 val
= strtol(pos
, NULL
, 0);
4250 conf
->netaccesskey_expiry
= val
;
4253 if (!dpp_configuration_valid(conf
))
4256 auth
->conf_sta
= conf_sta
;
4257 auth
->conf_ap
= conf_ap
;
4261 dpp_configuration_free(conf_sta
);
4262 dpp_configuration_free(conf_ap
);
4267 static struct dpp_configurator
*
4268 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4270 struct dpp_configurator
*conf
;
4275 dl_list_for_each(conf
, &dpp
->configurator
,
4276 struct dpp_configurator
, list
) {
4284 int dpp_set_configurator(struct dpp_global
*dpp
, void *msg_ctx
,
4285 struct dpp_authentication
*auth
,
4293 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4295 pos
= os_strstr(cmd
, " configurator=");
4298 auth
->conf
= dpp_configurator_get_id(dpp
, atoi(pos
));
4300 wpa_printf(MSG_INFO
,
4301 "DPP: Could not find the specified configurator");
4306 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4307 wpa_msg(msg_ctx
, MSG_INFO
,
4308 "DPP: Failed to set configurator parameters");
4315 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4319 dpp_configuration_free(auth
->conf_ap
);
4320 dpp_configuration_free(auth
->conf_sta
);
4321 EVP_PKEY_free(auth
->own_protocol_key
);
4322 EVP_PKEY_free(auth
->peer_protocol_key
);
4323 wpabuf_free(auth
->req_msg
);
4324 wpabuf_free(auth
->resp_msg
);
4325 wpabuf_free(auth
->conf_req
);
4326 os_free(auth
->connector
);
4327 wpabuf_free(auth
->net_access_key
);
4328 wpabuf_free(auth
->c_sign_key
);
4329 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4330 #ifdef CONFIG_TESTING_OPTIONS
4331 os_free(auth
->config_obj_override
);
4332 os_free(auth
->discovery_override
);
4333 os_free(auth
->groups_override
);
4334 #endif /* CONFIG_TESTING_OPTIONS */
4335 bin_clear_free(auth
, sizeof(*auth
));
4339 static struct wpabuf
*
4340 dpp_build_conf_start(struct dpp_authentication
*auth
,
4341 struct dpp_configuration
*conf
, size_t tailroom
)
4344 char ssid
[6 * sizeof(conf
->ssid
) + 1];
4346 #ifdef CONFIG_TESTING_OPTIONS
4347 if (auth
->discovery_override
)
4348 tailroom
+= os_strlen(auth
->discovery_override
);
4349 #endif /* CONFIG_TESTING_OPTIONS */
4351 buf
= wpabuf_alloc(200 + tailroom
);
4354 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4355 #ifdef CONFIG_TESTING_OPTIONS
4356 if (auth
->discovery_override
) {
4357 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4358 auth
->discovery_override
);
4359 wpabuf_put_str(buf
, auth
->discovery_override
);
4360 wpabuf_put_u8(buf
, ',');
4363 #endif /* CONFIG_TESTING_OPTIONS */
4364 wpabuf_put_str(buf
, "{\"ssid\":\"");
4365 json_escape_string(ssid
, sizeof(ssid
),
4366 (const char *) conf
->ssid
, conf
->ssid_len
);
4367 wpabuf_put_str(buf
, ssid
);
4368 wpabuf_put_str(buf
, "\"},");
4374 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4375 const char *kid
, const struct dpp_curve_params
*curve
)
4379 char *x
= NULL
, *y
= NULL
;
4382 pub
= dpp_get_pubkey_point(key
, 0);
4385 pos
= wpabuf_head(pub
);
4386 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4387 pos
+= curve
->prime_len
;
4388 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4392 wpabuf_put_str(buf
, "\"");
4393 wpabuf_put_str(buf
, name
);
4394 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
4395 wpabuf_put_str(buf
, curve
->jwk_crv
);
4396 wpabuf_put_str(buf
, "\",\"x\":\"");
4397 wpabuf_put_str(buf
, x
);
4398 wpabuf_put_str(buf
, "\",\"y\":\"");
4399 wpabuf_put_str(buf
, y
);
4401 wpabuf_put_str(buf
, "\",\"kid\":\"");
4402 wpabuf_put_str(buf
, kid
);
4404 wpabuf_put_str(buf
, "\"}");
4414 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4415 struct dpp_configuration
*conf
)
4417 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4418 char pass
[63 * 6 + 1];
4420 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
4421 os_strlen(conf
->passphrase
));
4422 wpabuf_put_str(buf
, "\"pass\":\"");
4423 wpabuf_put_str(buf
, pass
);
4424 wpabuf_put_str(buf
, "\"");
4425 os_memset(pass
, 0, sizeof(pass
));
4426 } else if (conf
->psk_set
) {
4427 char psk
[2 * sizeof(conf
->psk
) + 1];
4429 wpa_snprintf_hex(psk
, sizeof(psk
),
4430 conf
->psk
, sizeof(conf
->psk
));
4431 wpabuf_put_str(buf
, "\"psk_hex\":\"");
4432 wpabuf_put_str(buf
, psk
);
4433 wpabuf_put_str(buf
, "\"");
4434 os_memset(psk
, 0, sizeof(psk
));
4439 static struct wpabuf
*
4440 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
4441 struct dpp_configuration
*conf
)
4443 struct wpabuf
*buf
= NULL
;
4444 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4446 const struct dpp_curve_params
*curve
;
4447 char jws_prot_hdr
[100];
4448 size_t signed1_len
, signed2_len
, signed3_len
;
4449 struct wpabuf
*dppcon
= NULL
;
4450 unsigned char *signature
= NULL
;
4451 const unsigned char *p
;
4452 size_t signature_len
;
4453 EVP_MD_CTX
*md_ctx
= NULL
;
4454 ECDSA_SIG
*sig
= NULL
;
4456 const EVP_MD
*sign_md
;
4457 const BIGNUM
*r
, *s
;
4458 size_t extra_len
= 1000;
4463 wpa_printf(MSG_INFO
,
4464 "DPP: No configurator specified - cannot generate DPP config object");
4467 curve
= auth
->conf
->curve
;
4468 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4469 sign_md
= EVP_sha256();
4470 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4471 sign_md
= EVP_sha384();
4472 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4473 sign_md
= EVP_sha512();
4475 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4480 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4481 wpa_printf(MSG_DEBUG
,
4482 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4486 #ifdef CONFIG_TESTING_OPTIONS
4487 if (auth
->groups_override
)
4488 extra_len
+= os_strlen(auth
->groups_override
);
4489 #endif /* CONFIG_TESTING_OPTIONS */
4492 extra_len
+= os_strlen(conf
->group_id
);
4494 /* Connector (JSON dppCon object) */
4495 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4498 #ifdef CONFIG_TESTING_OPTIONS
4499 if (auth
->groups_override
) {
4500 wpabuf_put_u8(dppcon
, '{');
4501 if (auth
->groups_override
) {
4502 wpa_printf(MSG_DEBUG
,
4503 "DPP: TESTING - groups override: '%s'",
4504 auth
->groups_override
);
4505 wpabuf_put_str(dppcon
, "\"groups\":");
4506 wpabuf_put_str(dppcon
, auth
->groups_override
);
4507 wpabuf_put_u8(dppcon
, ',');
4511 #endif /* CONFIG_TESTING_OPTIONS */
4512 wpabuf_printf(dppcon
, "{\"groups\":[{\"groupId\":\"%s\",",
4513 conf
->group_id
? conf
->group_id
: "*");
4514 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
4515 #ifdef CONFIG_TESTING_OPTIONS
4517 #endif /* CONFIG_TESTING_OPTIONS */
4518 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4520 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4523 if (conf
->netaccesskey_expiry
) {
4526 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4527 wpa_printf(MSG_DEBUG
,
4528 "DPP: Failed to generate expiry string");
4531 wpabuf_printf(dppcon
,
4532 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4533 tm
.year
, tm
.month
, tm
.day
,
4534 tm
.hour
, tm
.min
, tm
.sec
);
4536 wpabuf_put_u8(dppcon
, '}');
4537 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4538 (const char *) wpabuf_head(dppcon
));
4540 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
4541 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4542 auth
->conf
->kid
, curve
->jws_alg
);
4543 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
4544 os_strlen(jws_prot_hdr
),
4546 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
4549 if (!signed1
|| !signed2
)
4552 md_ctx
= EVP_MD_CTX_create();
4557 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4558 auth
->conf
->csign
) != 1) {
4559 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4560 ERR_error_string(ERR_get_error(), NULL
));
4563 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4564 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4565 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4566 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4567 ERR_error_string(ERR_get_error(), NULL
));
4570 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4571 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4572 ERR_error_string(ERR_get_error(), NULL
));
4575 signature
= os_malloc(signature_len
);
4578 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4579 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4580 ERR_error_string(ERR_get_error(), NULL
));
4583 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4584 signature
, signature_len
);
4585 /* Convert to raw coordinates r,s */
4587 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4590 ECDSA_SIG_get0(sig
, &r
, &s
);
4591 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4592 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4593 curve
->prime_len
) < 0)
4595 signature_len
= 2 * curve
->prime_len
;
4596 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4597 signature
, signature_len
);
4598 signed3
= (char *) base64_url_encode(signature
, signature_len
,
4603 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
4605 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4606 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4609 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4613 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm
));
4615 dpp_build_legacy_cred_params(buf
, conf
);
4616 wpabuf_put_str(buf
, ",");
4618 wpabuf_put_str(buf
, "\"signedConnector\":\"");
4619 wpabuf_put_str(buf
, signed1
);
4620 wpabuf_put_u8(buf
, '.');
4621 wpabuf_put_str(buf
, signed2
);
4622 wpabuf_put_u8(buf
, '.');
4623 wpabuf_put_str(buf
, signed3
);
4624 wpabuf_put_str(buf
, "\",");
4625 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4627 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4631 wpabuf_put_str(buf
, "}}");
4633 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4634 wpabuf_head(buf
), wpabuf_len(buf
));
4637 EVP_MD_CTX_destroy(md_ctx
);
4638 ECDSA_SIG_free(sig
);
4643 wpabuf_free(dppcon
);
4646 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4653 static struct wpabuf
*
4654 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
4655 struct dpp_configuration
*conf
)
4659 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4663 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf
->akm
));
4664 dpp_build_legacy_cred_params(buf
, conf
);
4665 wpabuf_put_str(buf
, "}}");
4667 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4668 wpabuf_head(buf
), wpabuf_len(buf
));
4674 static struct wpabuf
*
4675 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
4677 struct dpp_configuration
*conf
;
4679 #ifdef CONFIG_TESTING_OPTIONS
4680 if (auth
->config_obj_override
) {
4681 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
4682 return wpabuf_alloc_copy(auth
->config_obj_override
,
4683 os_strlen(auth
->config_obj_override
));
4685 #endif /* CONFIG_TESTING_OPTIONS */
4687 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
4689 wpa_printf(MSG_DEBUG
,
4690 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4695 if (dpp_akm_dpp(conf
->akm
))
4696 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
4697 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
4701 static struct wpabuf
*
4702 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
4703 u16 e_nonce_len
, int ap
)
4705 struct wpabuf
*conf
;
4706 size_t clear_len
, attr_len
;
4707 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
4711 enum dpp_status_error status
;
4713 conf
= dpp_build_conf_obj(auth
, ap
);
4715 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4716 wpabuf_head(conf
), wpabuf_len(conf
));
4718 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
4719 auth
->conf_resp_status
= status
;
4721 /* { E-nonce, configurationObject}ke */
4722 clear_len
= 4 + e_nonce_len
;
4724 clear_len
+= 4 + wpabuf_len(conf
);
4725 clear
= wpabuf_alloc(clear_len
);
4726 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
4727 #ifdef CONFIG_TESTING_OPTIONS
4728 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
4730 #endif /* CONFIG_TESTING_OPTIONS */
4731 msg
= wpabuf_alloc(attr_len
);
4735 #ifdef CONFIG_TESTING_OPTIONS
4736 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
4737 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
4740 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
4741 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
4742 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4743 wpabuf_put_le16(clear
, e_nonce_len
);
4744 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4745 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4748 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4749 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4750 goto skip_wrapped_data
;
4752 #endif /* CONFIG_TESTING_OPTIONS */
4755 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4756 wpabuf_put_le16(clear
, e_nonce_len
);
4757 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4759 #ifdef CONFIG_TESTING_OPTIONS
4761 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4762 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4763 goto skip_config_obj
;
4765 #endif /* CONFIG_TESTING_OPTIONS */
4768 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4769 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4770 wpabuf_put_buf(clear
, conf
);
4773 #ifdef CONFIG_TESTING_OPTIONS
4775 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4776 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4779 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4780 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4783 #endif /* CONFIG_TESTING_OPTIONS */
4786 dpp_build_attr_status(msg
, status
);
4788 #ifdef CONFIG_TESTING_OPTIONS
4790 #endif /* CONFIG_TESTING_OPTIONS */
4792 addr
[0] = wpabuf_head(msg
);
4793 len
[0] = wpabuf_len(msg
);
4794 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4796 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4797 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4798 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4800 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4801 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4802 wpabuf_head(clear
), wpabuf_len(clear
),
4803 1, addr
, len
, wrapped
) < 0)
4805 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4806 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4808 #ifdef CONFIG_TESTING_OPTIONS
4809 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4810 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4811 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
4814 #endif /* CONFIG_TESTING_OPTIONS */
4816 wpa_hexdump_buf(MSG_DEBUG
,
4817 "DPP: Configuration Response attributes", msg
);
4831 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4834 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4835 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4836 u8
*unwrapped
= NULL
;
4837 size_t unwrapped_len
= 0;
4838 struct wpabuf
*resp
= NULL
;
4839 struct json_token
*root
= NULL
, *token
;
4842 #ifdef CONFIG_TESTING_OPTIONS
4843 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
4844 wpa_printf(MSG_INFO
,
4845 "DPP: TESTING - stop at Config Request");
4848 #endif /* CONFIG_TESTING_OPTIONS */
4850 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4851 dpp_auth_fail(auth
, "Invalid attribute in config request");
4855 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4857 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4859 "Missing or invalid required Wrapped Data attribute");
4863 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4864 wrapped_data
, wrapped_data_len
);
4865 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4866 unwrapped
= os_malloc(unwrapped_len
);
4869 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4870 wrapped_data
, wrapped_data_len
,
4871 0, NULL
, NULL
, unwrapped
) < 0) {
4872 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4875 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4876 unwrapped
, unwrapped_len
);
4878 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4879 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4883 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4884 DPP_ATTR_ENROLLEE_NONCE
,
4886 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4888 "Missing or invalid Enrollee Nonce attribute");
4891 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4892 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
4894 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
4895 DPP_ATTR_CONFIG_ATTR_OBJ
,
4899 "Missing or invalid Config Attributes attribute");
4902 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
4903 config_attr
, config_attr_len
);
4905 root
= json_parse((const char *) config_attr
, config_attr_len
);
4907 dpp_auth_fail(auth
, "Could not parse Config Attributes");
4911 token
= json_get_member(root
, "name");
4912 if (!token
|| token
->type
!= JSON_STRING
) {
4913 dpp_auth_fail(auth
, "No Config Attributes - name");
4916 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
4918 token
= json_get_member(root
, "wi-fi_tech");
4919 if (!token
|| token
->type
!= JSON_STRING
) {
4920 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
4923 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
4924 if (os_strcmp(token
->string
, "infra") != 0) {
4925 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
4927 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
4931 token
= json_get_member(root
, "netRole");
4932 if (!token
|| token
->type
!= JSON_STRING
) {
4933 dpp_auth_fail(auth
, "No Config Attributes - netRole");
4936 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
4937 if (os_strcmp(token
->string
, "sta") == 0) {
4939 } else if (os_strcmp(token
->string
, "ap") == 0) {
4942 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
4944 dpp_auth_fail(auth
, "Unsupported netRole");
4948 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
4957 static struct wpabuf
*
4958 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
4959 const u8
*prot_hdr
, u16 prot_hdr_len
,
4960 const EVP_MD
**ret_md
)
4962 struct json_token
*root
, *token
;
4963 struct wpabuf
*kid
= NULL
;
4965 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
4967 wpa_printf(MSG_DEBUG
,
4968 "DPP: JSON parsing failed for JWS Protected Header");
4972 if (root
->type
!= JSON_OBJECT
) {
4973 wpa_printf(MSG_DEBUG
,
4974 "DPP: JWS Protected Header root is not an object");
4978 token
= json_get_member(root
, "typ");
4979 if (!token
|| token
->type
!= JSON_STRING
) {
4980 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
4983 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
4985 if (os_strcmp(token
->string
, "dppCon") != 0) {
4986 wpa_printf(MSG_DEBUG
,
4987 "DPP: Unsupported JWS Protected Header typ=%s",
4992 token
= json_get_member(root
, "alg");
4993 if (!token
|| token
->type
!= JSON_STRING
) {
4994 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
4997 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
4999 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
5000 wpa_printf(MSG_DEBUG
,
5001 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5002 token
->string
, curve
->jws_alg
);
5005 if (os_strcmp(token
->string
, "ES256") == 0 ||
5006 os_strcmp(token
->string
, "BS256") == 0)
5007 *ret_md
= EVP_sha256();
5008 else if (os_strcmp(token
->string
, "ES384") == 0 ||
5009 os_strcmp(token
->string
, "BS384") == 0)
5010 *ret_md
= EVP_sha384();
5011 else if (os_strcmp(token
->string
, "ES512") == 0 ||
5012 os_strcmp(token
->string
, "BS512") == 0)
5013 *ret_md
= EVP_sha512();
5017 wpa_printf(MSG_DEBUG
,
5018 "DPP: Unsupported JWS Protected Header alg=%s",
5023 kid
= json_get_member_base64url(root
, "kid");
5025 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
5028 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
5037 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
5038 struct json_token
*cred
)
5040 struct json_token
*pass
, *psk_hex
;
5042 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
5044 pass
= json_get_member(cred
, "pass");
5045 psk_hex
= json_get_member(cred
, "psk_hex");
5047 if (pass
&& pass
->type
== JSON_STRING
) {
5048 size_t len
= os_strlen(pass
->string
);
5050 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
5052 if (len
< 8 || len
> 63)
5054 os_strlcpy(auth
->passphrase
, pass
->string
,
5055 sizeof(auth
->passphrase
));
5056 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
5057 if (dpp_akm_sae(auth
->akm
) && !dpp_akm_psk(auth
->akm
)) {
5058 wpa_printf(MSG_DEBUG
,
5059 "DPP: Unexpected psk_hex with akm=sae");
5062 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
5063 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
5064 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
5067 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
5068 auth
->psk
, PMK_LEN
);
5071 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
5075 if (dpp_akm_sae(auth
->akm
) && !auth
->passphrase
[0]) {
5076 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
5084 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
5085 const struct dpp_curve_params
**key_curve
)
5087 struct json_token
*token
;
5088 const struct dpp_curve_params
*curve
;
5089 struct wpabuf
*x
= NULL
, *y
= NULL
;
5091 EVP_PKEY
*pkey
= NULL
;
5093 token
= json_get_member(jwk
, "kty");
5094 if (!token
|| token
->type
!= JSON_STRING
) {
5095 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
5098 if (os_strcmp(token
->string
, "EC") != 0) {
5099 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
5104 token
= json_get_member(jwk
, "crv");
5105 if (!token
|| token
->type
!= JSON_STRING
) {
5106 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
5109 curve
= dpp_get_curve_jwk_crv(token
->string
);
5111 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
5116 x
= json_get_member_base64url(jwk
, "x");
5118 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
5121 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
5122 if (wpabuf_len(x
) != curve
->prime_len
) {
5123 wpa_printf(MSG_DEBUG
,
5124 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5125 (unsigned int) wpabuf_len(x
),
5126 (unsigned int) curve
->prime_len
, curve
->name
);
5130 y
= json_get_member_base64url(jwk
, "y");
5132 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
5135 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
5136 if (wpabuf_len(y
) != curve
->prime_len
) {
5137 wpa_printf(MSG_DEBUG
,
5138 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5139 (unsigned int) wpabuf_len(y
),
5140 (unsigned int) curve
->prime_len
, curve
->name
);
5144 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5146 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
5150 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
5162 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
5165 unsigned int year
, month
, day
, hour
, min
, sec
;
5169 /* ISO 8601 date and time:
5171 * YYYY-MM-DDTHH:MM:SSZ
5172 * YYYY-MM-DDTHH:MM:SS+03:00
5174 if (os_strlen(timestamp
) < 19) {
5175 wpa_printf(MSG_DEBUG
,
5176 "DPP: Too short timestamp - assume expired key");
5179 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
5180 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
5181 wpa_printf(MSG_DEBUG
,
5182 "DPP: Failed to parse expiration day - assume expired key");
5186 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
5187 wpa_printf(MSG_DEBUG
,
5188 "DPP: Invalid date/time information - assume expired key");
5192 pos
= timestamp
+ 19;
5193 if (*pos
== 'Z' || *pos
== '\0') {
5194 /* In UTC - no need to adjust */
5195 } else if (*pos
== '-' || *pos
== '+') {
5198 /* Adjust local time to UTC */
5199 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
5201 wpa_printf(MSG_DEBUG
,
5202 "DPP: Invalid time zone designator (%s) - assume expired key",
5207 utime
+= 3600 * hour
;
5209 utime
-= 3600 * hour
;
5217 wpa_printf(MSG_DEBUG
,
5218 "DPP: Invalid time zone designator (%s) - assume expired key",
5225 if (os_get_time(&now
) < 0) {
5226 wpa_printf(MSG_DEBUG
,
5227 "DPP: Cannot get current time - assume expired key");
5231 if (now
.sec
> utime
) {
5232 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
5241 static int dpp_parse_connector(struct dpp_authentication
*auth
,
5242 const unsigned char *payload
,
5245 struct json_token
*root
, *groups
, *netkey
, *token
;
5247 EVP_PKEY
*key
= NULL
;
5248 const struct dpp_curve_params
*curve
;
5249 unsigned int rules
= 0;
5251 root
= json_parse((const char *) payload
, payload_len
);
5253 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5257 groups
= json_get_member(root
, "groups");
5258 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5259 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
5262 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5263 struct json_token
*id
, *role
;
5265 id
= json_get_member(token
, "groupId");
5266 if (!id
|| id
->type
!= JSON_STRING
) {
5267 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
5271 role
= json_get_member(token
, "netRole");
5272 if (!role
|| role
->type
!= JSON_STRING
) {
5273 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
5276 wpa_printf(MSG_DEBUG
,
5277 "DPP: connector group: groupId='%s' netRole='%s'",
5278 id
->string
, role
->string
);
5284 wpa_printf(MSG_DEBUG
,
5285 "DPP: Connector includes no groups");
5289 token
= json_get_member(root
, "expiry");
5290 if (!token
|| token
->type
!= JSON_STRING
) {
5291 wpa_printf(MSG_DEBUG
,
5292 "DPP: No expiry string found - connector does not expire");
5294 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5295 if (dpp_key_expired(token
->string
,
5296 &auth
->net_access_key_expiry
)) {
5297 wpa_printf(MSG_DEBUG
,
5298 "DPP: Connector (netAccessKey) has expired");
5303 netkey
= json_get_member(root
, "netAccessKey");
5304 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5305 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5309 key
= dpp_parse_jwk(netkey
, &curve
);
5312 dpp_debug_print_key("DPP: Received netAccessKey", key
);
5314 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
5315 wpa_printf(MSG_DEBUG
,
5316 "DPP: netAccessKey in connector does not match own protocol key");
5317 #ifdef CONFIG_TESTING_OPTIONS
5318 if (auth
->ignore_netaccesskey_mismatch
) {
5319 wpa_printf(MSG_DEBUG
,
5320 "DPP: TESTING - skip netAccessKey mismatch");
5324 #else /* CONFIG_TESTING_OPTIONS */
5326 #endif /* CONFIG_TESTING_OPTIONS */
5337 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
5339 struct wpabuf
*uncomp
;
5341 u8 hash
[SHA256_MAC_LEN
];
5345 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
5347 uncomp
= dpp_get_pubkey_point(pub
, 1);
5350 addr
[0] = wpabuf_head(uncomp
);
5351 len
[0] = wpabuf_len(uncomp
);
5352 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5354 res
= sha256_vector(1, addr
, len
, hash
);
5355 wpabuf_free(uncomp
);
5358 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5359 wpa_printf(MSG_DEBUG
,
5360 "DPP: Received hash value does not match calculated public key hash value");
5361 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5362 hash
, SHA256_MAC_LEN
);
5369 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
5371 unsigned char *der
= NULL
;
5374 der_len
= i2d_PUBKEY(csign
, &der
);
5377 wpabuf_free(auth
->c_sign_key
);
5378 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5383 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
5385 unsigned char *der
= NULL
;
5389 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5393 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5398 wpabuf_free(auth
->net_access_key
);
5399 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5405 struct dpp_signed_connector_info
{
5406 unsigned char *payload
;
5410 static enum dpp_status_error
5411 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5412 EVP_PKEY
*csign_pub
, const char *connector
)
5414 enum dpp_status_error ret
= 255;
5415 const char *pos
, *end
, *signed_start
, *signed_end
;
5416 struct wpabuf
*kid
= NULL
;
5417 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5418 size_t prot_hdr_len
= 0, signature_len
= 0;
5419 const EVP_MD
*sign_md
= NULL
;
5420 unsigned char *der
= NULL
;
5423 EVP_MD_CTX
*md_ctx
= NULL
;
5424 ECDSA_SIG
*sig
= NULL
;
5425 BIGNUM
*r
= NULL
, *s
= NULL
;
5426 const struct dpp_curve_params
*curve
;
5428 const EC_GROUP
*group
;
5431 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5434 group
= EC_KEY_get0_group(eckey
);
5437 nid
= EC_GROUP_get_curve_name(group
);
5438 curve
= dpp_get_curve_nid(nid
);
5441 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5442 os_memset(info
, 0, sizeof(*info
));
5444 signed_start
= pos
= connector
;
5445 end
= os_strchr(pos
, '.');
5447 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5448 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5451 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
5452 end
- pos
, &prot_hdr_len
);
5454 wpa_printf(MSG_DEBUG
,
5455 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5456 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5459 wpa_hexdump_ascii(MSG_DEBUG
,
5460 "DPP: signedConnector - JWS Protected Header",
5461 prot_hdr
, prot_hdr_len
);
5462 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5464 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5467 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5468 wpa_printf(MSG_DEBUG
,
5469 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5470 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5471 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5476 end
= os_strchr(pos
, '.');
5478 wpa_printf(MSG_DEBUG
,
5479 "DPP: Missing dot(2) in signedConnector");
5480 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5483 signed_end
= end
- 1;
5484 info
->payload
= base64_url_decode((const unsigned char *) pos
,
5485 end
- pos
, &info
->payload_len
);
5486 if (!info
->payload
) {
5487 wpa_printf(MSG_DEBUG
,
5488 "DPP: Failed to base64url decode signedConnector JWS Payload");
5489 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5492 wpa_hexdump_ascii(MSG_DEBUG
,
5493 "DPP: signedConnector - JWS Payload",
5494 info
->payload
, info
->payload_len
);
5496 signature
= base64_url_decode((const unsigned char *) pos
,
5497 os_strlen(pos
), &signature_len
);
5499 wpa_printf(MSG_DEBUG
,
5500 "DPP: Failed to base64url decode signedConnector signature");
5501 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5504 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
5505 signature
, signature_len
);
5507 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
5508 ret
= DPP_STATUS_NO_MATCH
;
5512 if (signature_len
& 0x01) {
5513 wpa_printf(MSG_DEBUG
,
5514 "DPP: Unexpected signedConnector signature length (%d)",
5515 (int) signature_len
);
5516 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5520 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5521 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5522 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
5523 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
5524 sig
= ECDSA_SIG_new();
5525 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
5530 der_len
= i2d_ECDSA_SIG(sig
, &der
);
5532 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
5535 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
5536 md_ctx
= EVP_MD_CTX_create();
5541 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
5542 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
5543 ERR_error_string(ERR_get_error(), NULL
));
5546 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
5547 signed_end
- signed_start
+ 1) != 1) {
5548 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
5549 ERR_error_string(ERR_get_error(), NULL
));
5552 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
5554 wpa_printf(MSG_DEBUG
,
5555 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5556 res
, ERR_error_string(ERR_get_error(), NULL
));
5557 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5561 ret
= DPP_STATUS_OK
;
5564 EVP_MD_CTX_destroy(md_ctx
);
5568 ECDSA_SIG_free(sig
);
5576 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5577 struct json_token
*cred
)
5579 struct dpp_signed_connector_info info
;
5580 struct json_token
*token
, *csign
;
5582 EVP_PKEY
*csign_pub
= NULL
;
5583 const struct dpp_curve_params
*key_curve
= NULL
;
5584 const char *signed_connector
;
5586 os_memset(&info
, 0, sizeof(info
));
5588 if (dpp_akm_psk(auth
->akm
) || dpp_akm_sae(auth
->akm
)) {
5589 wpa_printf(MSG_DEBUG
,
5590 "DPP: Legacy credential included in Connector credential");
5591 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5595 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5597 csign
= json_get_member(cred
, "csign");
5598 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5599 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5603 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5605 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5608 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5610 token
= json_get_member(cred
, "signedConnector");
5611 if (!token
|| token
->type
!= JSON_STRING
) {
5612 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5615 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5616 token
->string
, os_strlen(token
->string
));
5617 signed_connector
= token
->string
;
5619 if (os_strchr(signed_connector
, '"') ||
5620 os_strchr(signed_connector
, '\n')) {
5621 wpa_printf(MSG_DEBUG
,
5622 "DPP: Unexpected character in signedConnector");
5626 if (dpp_process_signed_connector(&info
, csign_pub
,
5627 signed_connector
) != DPP_STATUS_OK
)
5630 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
5631 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
5635 os_free(auth
->connector
);
5636 auth
->connector
= os_strdup(signed_connector
);
5638 dpp_copy_csign(auth
, csign_pub
);
5639 dpp_copy_netaccesskey(auth
);
5643 EVP_PKEY_free(csign_pub
);
5644 os_free(info
.payload
);
5649 const char * dpp_akm_str(enum dpp_akm akm
)
5658 case DPP_AKM_PSK_SAE
:
5660 case DPP_AKM_SAE_DPP
:
5662 case DPP_AKM_PSK_SAE_DPP
:
5663 return "dpp+psk+sae";
5670 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
5672 if (os_strcmp(akm
, "psk") == 0)
5674 if (os_strcmp(akm
, "sae") == 0)
5676 if (os_strcmp(akm
, "psk+sae") == 0)
5677 return DPP_AKM_PSK_SAE
;
5678 if (os_strcmp(akm
, "dpp") == 0)
5680 if (os_strcmp(akm
, "dpp+sae") == 0)
5681 return DPP_AKM_SAE_DPP
;
5682 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
5683 return DPP_AKM_PSK_SAE_DPP
;
5684 return DPP_AKM_UNKNOWN
;
5688 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
5689 const u8
*conf_obj
, u16 conf_obj_len
)
5692 struct json_token
*root
, *token
, *discovery
, *cred
;
5694 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
5697 if (root
->type
!= JSON_OBJECT
) {
5698 dpp_auth_fail(auth
, "JSON root is not an object");
5702 token
= json_get_member(root
, "wi-fi_tech");
5703 if (!token
|| token
->type
!= JSON_STRING
) {
5704 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
5707 if (os_strcmp(token
->string
, "infra") != 0) {
5708 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
5710 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
5714 discovery
= json_get_member(root
, "discovery");
5715 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
5716 dpp_auth_fail(auth
, "No discovery object in JSON");
5720 token
= json_get_member(discovery
, "ssid");
5721 if (!token
|| token
->type
!= JSON_STRING
) {
5722 dpp_auth_fail(auth
, "No discovery::ssid string value found");
5725 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
5726 token
->string
, os_strlen(token
->string
));
5727 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
5728 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
5731 auth
->ssid_len
= os_strlen(token
->string
);
5732 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
5734 cred
= json_get_member(root
, "cred");
5735 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
5736 dpp_auth_fail(auth
, "No cred object in JSON");
5740 token
= json_get_member(cred
, "akm");
5741 if (!token
|| token
->type
!= JSON_STRING
) {
5742 dpp_auth_fail(auth
, "No cred::akm string value found");
5745 auth
->akm
= dpp_akm_from_str(token
->string
);
5747 if (dpp_akm_legacy(auth
->akm
)) {
5748 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5750 } else if (dpp_akm_dpp(auth
->akm
)) {
5751 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
5754 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
5756 dpp_auth_fail(auth
, "Unsupported akm");
5760 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
5768 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
5769 const struct wpabuf
*resp
)
5771 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
5772 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
5775 u8
*unwrapped
= NULL
;
5776 size_t unwrapped_len
= 0;
5779 auth
->conf_resp_status
= 255;
5781 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
5782 dpp_auth_fail(auth
, "Invalid attribute in config response");
5786 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5787 DPP_ATTR_WRAPPED_DATA
,
5789 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5791 "Missing or invalid required Wrapped Data attribute");
5795 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5796 wrapped_data
, wrapped_data_len
);
5797 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5798 unwrapped
= os_malloc(unwrapped_len
);
5802 addr
[0] = wpabuf_head(resp
);
5803 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
5804 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5806 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5807 wrapped_data
, wrapped_data_len
,
5808 1, addr
, len
, unwrapped
) < 0) {
5809 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5812 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5813 unwrapped
, unwrapped_len
);
5815 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5816 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5820 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5821 DPP_ATTR_ENROLLEE_NONCE
,
5823 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5825 "Missing or invalid Enrollee Nonce attribute");
5828 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5829 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5830 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5834 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5835 DPP_ATTR_STATUS
, &status_len
);
5836 if (!status
|| status_len
< 1) {
5838 "Missing or invalid required DPP Status attribute");
5841 auth
->conf_resp_status
= status
[0];
5842 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5843 if (status
[0] != DPP_STATUS_OK
) {
5844 dpp_auth_fail(auth
, "Configurator rejected configuration");
5848 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5849 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5852 "Missing required Configuration Object attribute");
5855 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5856 conf_obj
, conf_obj_len
);
5857 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5869 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
5871 const u8
*attr_start
, size_t attr_len
)
5873 const u8
*wrapped_data
, *status
, *e_nonce
;
5874 u16 wrapped_data_len
, status_len
, e_nonce_len
;
5877 u8
*unwrapped
= NULL
;
5878 size_t unwrapped_len
= 0;
5879 enum dpp_status_error ret
= 256;
5881 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5883 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5885 "Missing or invalid required Wrapped Data attribute");
5888 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
5889 wrapped_data
, wrapped_data_len
);
5891 attr_len
= wrapped_data
- 4 - attr_start
;
5894 len
[0] = DPP_HDR_LEN
;
5895 addr
[1] = attr_start
;
5897 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
5898 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
5899 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5900 wrapped_data
, wrapped_data_len
);
5901 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5902 unwrapped
= os_malloc(unwrapped_len
);
5905 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5906 wrapped_data
, wrapped_data_len
,
5907 2, addr
, len
, unwrapped
) < 0) {
5908 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5911 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5912 unwrapped
, unwrapped_len
);
5914 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5915 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5919 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5920 DPP_ATTR_ENROLLEE_NONCE
,
5922 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5924 "Missing or invalid Enrollee Nonce attribute");
5927 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5928 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5929 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5930 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
5931 auth
->e_nonce
, e_nonce_len
);
5935 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
5937 if (!status
|| status_len
< 1) {
5939 "Missing or invalid required DPP Status attribute");
5942 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5946 bin_clear_free(unwrapped
, unwrapped_len
);
5949 #endif /* CONFIG_DPP2 */
5952 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
5953 enum dpp_status_error status
)
5955 struct wpabuf
*msg
, *clear
;
5956 size_t nonce_len
, clear_len
, attr_len
;
5961 nonce_len
= auth
->curve
->nonce_len
;
5962 clear_len
= 5 + 4 + nonce_len
;
5963 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
5964 clear
= wpabuf_alloc(clear_len
);
5965 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
5970 dpp_build_attr_status(clear
, status
);
5973 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5974 wpabuf_put_le16(clear
, nonce_len
);
5975 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
5977 /* OUI, OUI type, Crypto Suite, DPP frame type */
5978 addr
[0] = wpabuf_head_u8(msg
) + 2;
5979 len
[0] = 3 + 1 + 1 + 1;
5980 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
5982 /* Attributes before Wrapped Data (none) */
5983 addr
[1] = wpabuf_put(msg
, 0);
5985 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
5988 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5989 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5990 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5992 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5993 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
5994 wpabuf_head(clear
), wpabuf_len(clear
),
5995 2, addr
, len
, wrapped
) < 0)
5998 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
6008 void dpp_configurator_free(struct dpp_configurator
*conf
)
6012 EVP_PKEY_free(conf
->csign
);
6018 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
6022 int key_len
, ret
= -1;
6023 unsigned char *key
= NULL
;
6028 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
6032 key_len
= i2d_ECPrivateKey(eckey
, &key
);
6034 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
6042 struct dpp_configurator
*
6043 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
6046 struct dpp_configurator
*conf
;
6047 struct wpabuf
*csign_pub
= NULL
;
6048 u8 kid_hash
[SHA256_MAC_LEN
];
6052 conf
= os_zalloc(sizeof(*conf
));
6057 conf
->curve
= &dpp_curves
[0];
6059 conf
->curve
= dpp_get_curve_name(curve
);
6061 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6068 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
6071 conf
->csign
= dpp_gen_keypair(conf
->curve
);
6076 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
6078 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
6082 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6083 addr
[0] = wpabuf_head(csign_pub
);
6084 len
[0] = wpabuf_len(csign_pub
);
6085 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
6086 wpa_printf(MSG_DEBUG
,
6087 "DPP: Failed to derive kid for C-sign-key");
6091 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
6096 wpabuf_free(csign_pub
);
6099 dpp_configurator_free(conf
);
6105 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
6106 const char *curve
, int ap
)
6108 struct wpabuf
*conf_obj
;
6112 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
6117 auth
->curve
= &dpp_curves
[0];
6119 auth
->curve
= dpp_get_curve_name(curve
);
6121 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6126 wpa_printf(MSG_DEBUG
,
6127 "DPP: Building own configuration/connector with curve %s",
6130 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
6131 if (!auth
->own_protocol_key
)
6133 dpp_copy_netaccesskey(auth
);
6134 auth
->peer_protocol_key
= auth
->own_protocol_key
;
6135 dpp_copy_csign(auth
, auth
->conf
->csign
);
6137 conf_obj
= dpp_build_conf_obj(auth
, ap
);
6140 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
6141 wpabuf_len(conf_obj
));
6143 wpabuf_free(conf_obj
);
6144 auth
->peer_protocol_key
= NULL
;
6149 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
6151 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
6152 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
6156 static int dpp_connector_compatible_group(struct json_token
*root
,
6157 const char *group_id
,
6158 const char *net_role
)
6160 struct json_token
*groups
, *token
;
6162 groups
= json_get_member(root
, "groups");
6163 if (!groups
|| groups
->type
!= JSON_ARRAY
)
6166 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6167 struct json_token
*id
, *role
;
6169 id
= json_get_member(token
, "groupId");
6170 if (!id
|| id
->type
!= JSON_STRING
)
6173 role
= json_get_member(token
, "netRole");
6174 if (!role
|| role
->type
!= JSON_STRING
)
6177 if (os_strcmp(id
->string
, "*") != 0 &&
6178 os_strcmp(group_id
, "*") != 0 &&
6179 os_strcmp(id
->string
, group_id
) != 0)
6182 if (dpp_compatible_netrole(role
->string
, net_role
))
6190 static int dpp_connector_match_groups(struct json_token
*own_root
,
6191 struct json_token
*peer_root
)
6193 struct json_token
*groups
, *token
;
6195 groups
= json_get_member(peer_root
, "groups");
6196 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6197 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
6201 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6202 struct json_token
*id
, *role
;
6204 id
= json_get_member(token
, "groupId");
6205 if (!id
|| id
->type
!= JSON_STRING
) {
6206 wpa_printf(MSG_DEBUG
,
6207 "DPP: Missing peer groupId string");
6211 role
= json_get_member(token
, "netRole");
6212 if (!role
|| role
->type
!= JSON_STRING
) {
6213 wpa_printf(MSG_DEBUG
,
6214 "DPP: Missing peer groups::netRole string");
6217 wpa_printf(MSG_DEBUG
,
6218 "DPP: peer connector group: groupId='%s' netRole='%s'",
6219 id
->string
, role
->string
);
6220 if (dpp_connector_compatible_group(own_root
, id
->string
,
6222 wpa_printf(MSG_DEBUG
,
6223 "DPP: Compatible group/netRole in own connector");
6232 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
6233 unsigned int hash_len
)
6235 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6236 const char *info
= "DPP PMK";
6239 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6241 /* HKDF-Extract(<>, N.x) */
6242 os_memset(salt
, 0, hash_len
);
6243 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
6245 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6248 /* HKDF-Expand(PRK, info, L) */
6249 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
6250 os_memset(prk
, 0, hash_len
);
6254 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6260 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
6261 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
6263 struct wpabuf
*nkx
, *pkx
;
6267 u8 hash
[SHA256_MAC_LEN
];
6269 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6270 nkx
= dpp_get_pubkey_point(own_key
, 0);
6271 pkx
= dpp_get_pubkey_point(peer_key
, 0);
6274 addr
[0] = wpabuf_head(nkx
);
6275 len
[0] = wpabuf_len(nkx
) / 2;
6276 addr
[1] = wpabuf_head(pkx
);
6277 len
[1] = wpabuf_len(pkx
) / 2;
6278 if (len
[0] != len
[1])
6280 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
6281 addr
[0] = wpabuf_head(pkx
);
6282 addr
[1] = wpabuf_head(nkx
);
6284 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
6285 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
6286 res
= sha256_vector(2, addr
, len
, hash
);
6289 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
6290 os_memcpy(pmkid
, hash
, PMKID_LEN
);
6291 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
6300 enum dpp_status_error
6301 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
6302 const u8
*net_access_key
, size_t net_access_key_len
,
6303 const u8
*csign_key
, size_t csign_key_len
,
6304 const u8
*peer_connector
, size_t peer_connector_len
,
6307 struct json_token
*root
= NULL
, *netkey
, *token
;
6308 struct json_token
*own_root
= NULL
;
6309 enum dpp_status_error ret
= 255, res
;
6310 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
6311 struct wpabuf
*own_key_pub
= NULL
;
6312 const struct dpp_curve_params
*curve
, *own_curve
;
6313 struct dpp_signed_connector_info info
;
6314 const unsigned char *p
;
6315 EVP_PKEY
*csign
= NULL
;
6316 char *signed_connector
= NULL
;
6317 const char *pos
, *end
;
6318 unsigned char *own_conn
= NULL
;
6319 size_t own_conn_len
;
6320 EVP_PKEY_CTX
*ctx
= NULL
;
6322 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
6324 os_memset(intro
, 0, sizeof(*intro
));
6325 os_memset(&info
, 0, sizeof(info
));
6330 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
6332 wpa_printf(MSG_ERROR
,
6333 "DPP: Failed to parse local C-sign-key information");
6337 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
6338 net_access_key_len
);
6340 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
6344 pos
= os_strchr(own_connector
, '.');
6346 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
6350 end
= os_strchr(pos
, '.');
6352 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
6355 own_conn
= base64_url_decode((const unsigned char *) pos
,
6356 end
- pos
, &own_conn_len
);
6358 wpa_printf(MSG_DEBUG
,
6359 "DPP: Failed to base64url decode own signedConnector JWS Payload");
6363 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
6365 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
6369 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
6370 peer_connector
, peer_connector_len
);
6371 signed_connector
= os_malloc(peer_connector_len
+ 1);
6372 if (!signed_connector
)
6374 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
6375 signed_connector
[peer_connector_len
] = '\0';
6377 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
6378 if (res
!= DPP_STATUS_OK
) {
6383 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
6385 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
6386 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6390 if (!dpp_connector_match_groups(own_root
, root
)) {
6391 wpa_printf(MSG_DEBUG
,
6392 "DPP: Peer connector does not include compatible group netrole with own connector");
6393 ret
= DPP_STATUS_NO_MATCH
;
6397 token
= json_get_member(root
, "expiry");
6398 if (!token
|| token
->type
!= JSON_STRING
) {
6399 wpa_printf(MSG_DEBUG
,
6400 "DPP: No expiry string found - connector does not expire");
6402 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
6403 if (dpp_key_expired(token
->string
, expiry
)) {
6404 wpa_printf(MSG_DEBUG
,
6405 "DPP: Connector (netAccessKey) has expired");
6406 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6411 netkey
= json_get_member(root
, "netAccessKey");
6412 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
6413 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
6414 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6418 peer_key
= dpp_parse_jwk(netkey
, &curve
);
6420 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6423 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
6425 if (own_curve
!= curve
) {
6426 wpa_printf(MSG_DEBUG
,
6427 "DPP: Mismatching netAccessKey curves (%s != %s)",
6428 own_curve
->name
, curve
->name
);
6429 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6433 /* ECDH: N = nk * PK */
6434 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
6436 EVP_PKEY_derive_init(ctx
) != 1 ||
6437 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
6438 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
6439 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6440 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
6441 wpa_printf(MSG_ERROR
,
6442 "DPP: Failed to derive ECDH shared secret: %s",
6443 ERR_error_string(ERR_get_error(), NULL
));
6447 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
6450 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6451 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
6452 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
6455 intro
->pmk_len
= curve
->hash_len
;
6457 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6458 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
6459 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
6463 ret
= DPP_STATUS_OK
;
6465 if (ret
!= DPP_STATUS_OK
)
6466 os_memset(intro
, 0, sizeof(*intro
));
6467 os_memset(Nx
, 0, sizeof(Nx
));
6468 EVP_PKEY_CTX_free(ctx
);
6470 os_free(signed_connector
);
6471 os_free(info
.payload
);
6472 EVP_PKEY_free(own_key
);
6473 wpabuf_free(own_key_pub
);
6474 EVP_PKEY_free(peer_key
);
6475 EVP_PKEY_free(csign
);
6477 json_free(own_root
);
6482 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
6486 size_t len
= curve
->prime_len
;
6489 switch (curve
->ike_group
) {
6491 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
6492 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
6495 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
6496 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
6499 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
6500 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
6503 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
6504 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
6507 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
6508 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
6511 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
6512 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
6518 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6521 return dpp_set_pubkey_point_group(group
, x
, y
, len
);
6525 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
6526 const u8
*mac_init
, const char *code
,
6527 const char *identifier
, BN_CTX
*bnctx
,
6528 const EC_GROUP
**ret_group
)
6530 u8 hash
[DPP_MAX_HASH_LEN
];
6533 unsigned int num_elem
= 0;
6534 EC_POINT
*Qi
= NULL
;
6535 EVP_PKEY
*Pi
= NULL
;
6536 EC_KEY
*Pi_ec
= NULL
;
6537 const EC_POINT
*Pi_point
;
6538 BIGNUM
*hash_bn
= NULL
;
6539 const EC_GROUP
*group
= NULL
;
6540 EC_GROUP
*group2
= NULL
;
6542 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6544 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
6545 addr
[num_elem
] = mac_init
;
6546 len
[num_elem
] = ETH_ALEN
;
6549 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6551 addr
[num_elem
] = (const u8
*) identifier
;
6552 len
[num_elem
] = os_strlen(identifier
);
6555 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6556 addr
[num_elem
] = (const u8
*) code
;
6557 len
[num_elem
] = os_strlen(code
);
6559 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6561 wpa_hexdump_key(MSG_DEBUG
,
6562 "DPP: H(MAC-Initiator | [identifier |] code)",
6563 hash
, curve
->hash_len
);
6564 Pi
= dpp_pkex_get_role_elem(curve
, 1);
6567 dpp_debug_print_key("DPP: Pi", Pi
);
6568 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
6571 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
6573 group
= EC_KEY_get0_group(Pi_ec
);
6576 group2
= EC_GROUP_dup(group
);
6579 Qi
= EC_POINT_new(group2
);
6581 EC_GROUP_free(group2
);
6584 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6586 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
6588 if (EC_POINT_is_at_infinity(group
, Qi
)) {
6589 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
6592 dpp_debug_print_point("DPP: Qi", group
, Qi
);
6596 BN_clear_free(hash_bn
);
6598 *ret_group
= group2
;
6607 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
6608 const u8
*mac_resp
, const char *code
,
6609 const char *identifier
, BN_CTX
*bnctx
,
6610 const EC_GROUP
**ret_group
)
6612 u8 hash
[DPP_MAX_HASH_LEN
];
6615 unsigned int num_elem
= 0;
6616 EC_POINT
*Qr
= NULL
;
6617 EVP_PKEY
*Pr
= NULL
;
6618 EC_KEY
*Pr_ec
= NULL
;
6619 const EC_POINT
*Pr_point
;
6620 BIGNUM
*hash_bn
= NULL
;
6621 const EC_GROUP
*group
= NULL
;
6622 EC_GROUP
*group2
= NULL
;
6624 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6626 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
6627 addr
[num_elem
] = mac_resp
;
6628 len
[num_elem
] = ETH_ALEN
;
6631 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6633 addr
[num_elem
] = (const u8
*) identifier
;
6634 len
[num_elem
] = os_strlen(identifier
);
6637 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6638 addr
[num_elem
] = (const u8
*) code
;
6639 len
[num_elem
] = os_strlen(code
);
6641 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6643 wpa_hexdump_key(MSG_DEBUG
,
6644 "DPP: H(MAC-Responder | [identifier |] code)",
6645 hash
, curve
->hash_len
);
6646 Pr
= dpp_pkex_get_role_elem(curve
, 0);
6649 dpp_debug_print_key("DPP: Pr", Pr
);
6650 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
6653 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
6655 group
= EC_KEY_get0_group(Pr_ec
);
6658 group2
= EC_GROUP_dup(group
);
6661 Qr
= EC_POINT_new(group2
);
6663 EC_GROUP_free(group2
);
6666 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6668 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
6670 if (EC_POINT_is_at_infinity(group
, Qr
)) {
6671 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
6674 dpp_debug_print_point("DPP: Qr", group
, Qr
);
6678 BN_clear_free(hash_bn
);
6680 *ret_group
= group2
;
6689 #ifdef CONFIG_TESTING_OPTIONS
6690 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
6691 const struct dpp_curve_params
*curve
)
6699 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6704 point
= EC_POINT_new(group
);
6707 if (!ctx
|| !point
|| !x
|| !y
)
6710 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
6713 /* Generate a random y coordinate that results in a point that is not
6716 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
6719 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
6721 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
6722 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6723 * return an error from EC_POINT_set_affine_coordinates_GFp()
6724 * when the point is not on the curve. */
6726 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
6728 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
6731 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
6735 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
6736 curve
->prime_len
) < 0 ||
6737 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
6738 curve
->prime_len
) < 0)
6744 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
6747 EC_POINT_free(point
);
6752 #endif /* CONFIG_TESTING_OPTIONS */
6755 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
6757 EC_KEY
*X_ec
= NULL
;
6758 const EC_POINT
*X_point
;
6759 BN_CTX
*bnctx
= NULL
;
6760 const EC_GROUP
*group
;
6761 EC_POINT
*Qi
= NULL
, *M
= NULL
;
6762 struct wpabuf
*M_buf
= NULL
;
6763 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6764 struct wpabuf
*msg
= NULL
;
6766 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6768 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
6770 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6771 bnctx
= BN_CTX_new();
6774 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
6775 pkex
->identifier
, bnctx
, &group
);
6779 /* Generate a random ephemeral keypair x/X */
6780 #ifdef CONFIG_TESTING_OPTIONS
6781 if (dpp_pkex_ephemeral_key_override_len
) {
6782 const struct dpp_curve_params
*tmp_curve
;
6784 wpa_printf(MSG_INFO
,
6785 "DPP: TESTING - override ephemeral key x/X");
6786 pkex
->x
= dpp_set_keypair(&tmp_curve
,
6787 dpp_pkex_ephemeral_key_override
,
6788 dpp_pkex_ephemeral_key_override_len
);
6790 pkex
->x
= dpp_gen_keypair(curve
);
6792 #else /* CONFIG_TESTING_OPTIONS */
6793 pkex
->x
= dpp_gen_keypair(curve
);
6794 #endif /* CONFIG_TESTING_OPTIONS */
6799 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
6802 X_point
= EC_KEY_get0_public_key(X_ec
);
6805 dpp_debug_print_point("DPP: X", group
, X_point
);
6806 M
= EC_POINT_new(group
);
6809 if (!M
|| !Mx
|| !My
||
6810 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
6811 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
6813 dpp_debug_print_point("DPP: M", group
, M
);
6815 /* Initiator -> Responder: group, [identifier,] M */
6817 if (pkex
->identifier
)
6818 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6819 attr_len
+= 4 + 2 * curve
->prime_len
;
6820 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
6824 #ifdef CONFIG_TESTING_OPTIONS
6825 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
6826 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
6827 goto skip_finite_cyclic_group
;
6829 #endif /* CONFIG_TESTING_OPTIONS */
6831 /* Finite Cyclic Group attribute */
6832 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6833 wpabuf_put_le16(msg
, 2);
6834 wpabuf_put_le16(msg
, curve
->ike_group
);
6836 #ifdef CONFIG_TESTING_OPTIONS
6837 skip_finite_cyclic_group
:
6838 #endif /* CONFIG_TESTING_OPTIONS */
6840 /* Code Identifier attribute */
6841 if (pkex
->identifier
) {
6842 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6843 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6844 wpabuf_put_str(msg
, pkex
->identifier
);
6847 #ifdef CONFIG_TESTING_OPTIONS
6848 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6849 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6852 #endif /* CONFIG_TESTING_OPTIONS */
6854 /* M in Encrypted Key attribute */
6855 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6856 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6858 #ifdef CONFIG_TESTING_OPTIONS
6859 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6860 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6861 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6865 #endif /* CONFIG_TESTING_OPTIONS */
6867 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
6868 curve
->prime_len
) < 0 ||
6869 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
6870 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
6871 curve
->prime_len
) < 0)
6884 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
6891 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
6893 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
6897 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
6899 const char *identifier
,
6902 struct dpp_pkex
*pkex
;
6904 #ifdef CONFIG_TESTING_OPTIONS
6905 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
6906 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
6907 MAC2STR(dpp_pkex_own_mac_override
));
6908 own_mac
= dpp_pkex_own_mac_override
;
6910 #endif /* CONFIG_TESTING_OPTIONS */
6912 pkex
= os_zalloc(sizeof(*pkex
));
6915 pkex
->msg_ctx
= msg_ctx
;
6916 pkex
->initiator
= 1;
6918 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6920 pkex
->identifier
= os_strdup(identifier
);
6921 if (!pkex
->identifier
)
6924 pkex
->code
= os_strdup(code
);
6927 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
6928 if (!pkex
->exchange_req
)
6932 dpp_pkex_free(pkex
);
6937 static struct wpabuf
*
6938 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
6939 enum dpp_status_error status
,
6940 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
6942 struct wpabuf
*msg
= NULL
;
6944 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6946 /* Initiator -> Responder: DPP Status, [identifier,] N */
6948 if (pkex
->identifier
)
6949 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6950 attr_len
+= 4 + 2 * curve
->prime_len
;
6951 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
6955 #ifdef CONFIG_TESTING_OPTIONS
6956 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
6957 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
6961 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
6962 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
6965 #endif /* CONFIG_TESTING_OPTIONS */
6968 dpp_build_attr_status(msg
, status
);
6970 #ifdef CONFIG_TESTING_OPTIONS
6972 #endif /* CONFIG_TESTING_OPTIONS */
6974 /* Code Identifier attribute */
6975 if (pkex
->identifier
) {
6976 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6977 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6978 wpabuf_put_str(msg
, pkex
->identifier
);
6981 if (status
!= DPP_STATUS_OK
)
6982 goto skip_encrypted_key
;
6984 #ifdef CONFIG_TESTING_OPTIONS
6985 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6986 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6987 goto skip_encrypted_key
;
6989 #endif /* CONFIG_TESTING_OPTIONS */
6991 /* N in Encrypted Key attribute */
6992 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6993 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6995 #ifdef CONFIG_TESTING_OPTIONS
6996 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6997 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6998 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
7000 goto skip_encrypted_key
;
7002 #endif /* CONFIG_TESTING_OPTIONS */
7004 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
7005 curve
->prime_len
) < 0 ||
7006 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
7007 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
7008 curve
->prime_len
) < 0)
7012 if (status
== DPP_STATUS_BAD_GROUP
) {
7013 /* Finite Cyclic Group attribute */
7014 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
7015 wpabuf_put_le16(msg
, 2);
7016 wpabuf_put_le16(msg
, curve
->ike_group
);
7026 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
7027 const u8
*Mx
, size_t Mx_len
,
7028 const u8
*Nx
, size_t Nx_len
,
7030 const u8
*Kx
, size_t Kx_len
,
7031 u8
*z
, unsigned int hash_len
)
7033 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
7038 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7041 /* HKDF-Extract(<>, IKM=K.x) */
7042 os_memset(salt
, 0, hash_len
);
7043 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
7045 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
7047 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
7048 info
= os_malloc(info_len
);
7052 os_memcpy(pos
, mac_init
, ETH_ALEN
);
7054 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
7056 os_memcpy(pos
, Mx
, Mx_len
);
7058 os_memcpy(pos
, Nx
, Nx_len
);
7060 os_memcpy(pos
, code
, os_strlen(code
));
7062 /* HKDF-Expand(PRK, info, L) */
7064 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7066 else if (hash_len
== 48)
7067 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7069 else if (hash_len
== 64)
7070 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7075 os_memset(prk
, 0, hash_len
);
7079 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
7085 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
7086 const char *identifier
)
7088 if (!attr_id
&& identifier
) {
7089 wpa_printf(MSG_DEBUG
,
7090 "DPP: No PKEX code identifier received, but expected one");
7094 if (attr_id
&& !identifier
) {
7095 wpa_printf(MSG_DEBUG
,
7096 "DPP: PKEX code identifier received, but not expecting one");
7100 if (attr_id
&& identifier
&&
7101 (os_strlen(identifier
) != attr_id_len
||
7102 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
7103 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
7111 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
7112 struct dpp_bootstrap_info
*bi
,
7115 const char *identifier
,
7117 const u8
*buf
, size_t len
)
7119 const u8
*attr_group
, *attr_id
, *attr_key
;
7120 u16 attr_group_len
, attr_id_len
, attr_key_len
;
7121 const struct dpp_curve_params
*curve
= bi
->curve
;
7123 struct dpp_pkex
*pkex
= NULL
;
7124 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
7125 BN_CTX
*bnctx
= NULL
;
7126 const EC_GROUP
*group
;
7127 BIGNUM
*Mx
= NULL
, *My
= NULL
;
7128 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
7129 const EC_POINT
*Y_point
;
7130 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7131 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7134 EVP_PKEY_CTX
*ctx
= NULL
;
7136 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
7137 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7138 "PKEX counter t limit reached - ignore message");
7142 #ifdef CONFIG_TESTING_OPTIONS
7143 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7144 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7145 MAC2STR(dpp_pkex_peer_mac_override
));
7146 peer_mac
= dpp_pkex_peer_mac_override
;
7148 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7149 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7150 MAC2STR(dpp_pkex_own_mac_override
));
7151 own_mac
= dpp_pkex_own_mac_override
;
7153 #endif /* CONFIG_TESTING_OPTIONS */
7156 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
7158 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
7161 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
7163 if (!attr_group
|| attr_group_len
!= 2) {
7164 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7165 "Missing or invalid Finite Cyclic Group attribute");
7168 ike_group
= WPA_GET_LE16(attr_group
);
7169 if (ike_group
!= curve
->ike_group
) {
7170 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7171 "Mismatching PKEX curve: peer=%u own=%u",
7172 ike_group
, curve
->ike_group
);
7173 pkex
= os_zalloc(sizeof(*pkex
));
7178 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
7179 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
7180 if (!pkex
->exchange_resp
)
7185 /* M in Encrypted Key attribute */
7186 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
7188 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
7189 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
7190 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7191 "Missing Encrypted Key attribute");
7195 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7196 bnctx
= BN_CTX_new();
7199 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
7205 X
= EC_POINT_new(group
);
7206 M
= EC_POINT_new(group
);
7207 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7208 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7209 if (!X
|| !M
|| !Mx
|| !My
||
7210 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
7211 EC_POINT_is_at_infinity(group
, M
) ||
7212 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
7213 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
7214 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
7215 EC_POINT_is_at_infinity(group
, X
) ||
7216 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
7217 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7218 "Invalid Encrypted Key value");
7222 dpp_debug_print_point("DPP: M", group
, M
);
7223 dpp_debug_print_point("DPP: X'", group
, X
);
7225 pkex
= os_zalloc(sizeof(*pkex
));
7228 pkex
->t
= bi
->pkex_t
;
7229 pkex
->msg_ctx
= msg_ctx
;
7231 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7232 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7234 pkex
->identifier
= os_strdup(identifier
);
7235 if (!pkex
->identifier
)
7238 pkex
->code
= os_strdup(code
);
7242 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
7244 X_ec
= EC_KEY_new();
7246 EC_KEY_set_group(X_ec
, group
) != 1 ||
7247 EC_KEY_set_public_key(X_ec
, X
) != 1)
7249 pkex
->x
= EVP_PKEY_new();
7251 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
7254 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7255 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
7259 /* Generate a random ephemeral keypair y/Y */
7260 #ifdef CONFIG_TESTING_OPTIONS
7261 if (dpp_pkex_ephemeral_key_override_len
) {
7262 const struct dpp_curve_params
*tmp_curve
;
7264 wpa_printf(MSG_INFO
,
7265 "DPP: TESTING - override ephemeral key y/Y");
7266 pkex
->y
= dpp_set_keypair(&tmp_curve
,
7267 dpp_pkex_ephemeral_key_override
,
7268 dpp_pkex_ephemeral_key_override_len
);
7270 pkex
->y
= dpp_gen_keypair(curve
);
7272 #else /* CONFIG_TESTING_OPTIONS */
7273 pkex
->y
= dpp_gen_keypair(curve
);
7274 #endif /* CONFIG_TESTING_OPTIONS */
7279 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
7282 Y_point
= EC_KEY_get0_public_key(Y_ec
);
7285 dpp_debug_print_point("DPP: Y", group
, Y_point
);
7286 N
= EC_POINT_new(group
);
7289 if (!N
|| !Nx
|| !Ny
||
7290 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
7291 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
7293 dpp_debug_print_point("DPP: N", group
, N
);
7295 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
7297 if (!pkex
->exchange_resp
)
7301 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7303 EVP_PKEY_derive_init(ctx
) != 1 ||
7304 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
7305 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7306 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7307 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7308 wpa_printf(MSG_ERROR
,
7309 "DPP: Failed to derive ECDH shared secret: %s",
7310 ERR_error_string(ERR_get_error(), NULL
));
7314 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7317 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7319 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
7320 pkex
->Mx
, curve
->prime_len
,
7321 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
7322 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
7323 os_memset(Kx
, 0, Kx_len
);
7327 pkex
->exchange_done
= 1;
7330 EVP_PKEY_CTX_free(ctx
);
7345 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
7346 dpp_pkex_free(pkex
);
7352 static struct wpabuf
*
7353 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
7354 const struct wpabuf
*A_pub
, const u8
*u
)
7356 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7357 struct wpabuf
*msg
= NULL
;
7358 size_t clear_len
, attr_len
;
7359 struct wpabuf
*clear
= NULL
;
7365 /* {A, u, [bootstrapping info]}z */
7366 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7367 clear
= wpabuf_alloc(clear_len
);
7368 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7369 #ifdef CONFIG_TESTING_OPTIONS
7370 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
7372 #endif /* CONFIG_TESTING_OPTIONS */
7373 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
7377 #ifdef CONFIG_TESTING_OPTIONS
7378 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7379 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7380 goto skip_bootstrap_key
;
7382 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7383 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7384 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7385 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7386 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7388 goto skip_bootstrap_key
;
7390 #endif /* CONFIG_TESTING_OPTIONS */
7392 /* A in Bootstrap Key attribute */
7393 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7394 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
7395 wpabuf_put_buf(clear
, A_pub
);
7397 #ifdef CONFIG_TESTING_OPTIONS
7399 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
7400 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
7401 goto skip_i_auth_tag
;
7403 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
7404 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
7405 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7406 wpabuf_put_le16(clear
, curve
->hash_len
);
7407 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
7408 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
7409 goto skip_i_auth_tag
;
7411 #endif /* CONFIG_TESTING_OPTIONS */
7413 /* u in I-Auth tag attribute */
7414 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7415 wpabuf_put_le16(clear
, curve
->hash_len
);
7416 wpabuf_put_data(clear
, u
, curve
->hash_len
);
7418 #ifdef CONFIG_TESTING_OPTIONS
7420 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
7421 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7422 goto skip_wrapped_data
;
7424 #endif /* CONFIG_TESTING_OPTIONS */
7426 addr
[0] = wpabuf_head_u8(msg
) + 2;
7427 len
[0] = DPP_HDR_LEN
;
7430 len
[1] = sizeof(octet
);
7431 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7432 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7434 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7435 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7436 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7438 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7439 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7440 wpabuf_head(clear
), wpabuf_len(clear
),
7441 2, addr
, len
, wrapped
) < 0)
7443 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7444 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7446 #ifdef CONFIG_TESTING_OPTIONS
7447 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
7448 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7449 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7452 #endif /* CONFIG_TESTING_OPTIONS */
7465 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
7467 const u8
*buf
, size_t buflen
)
7469 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
7470 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
7471 const EC_GROUP
*group
;
7472 BN_CTX
*bnctx
= NULL
;
7473 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7474 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7475 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
7476 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7477 EVP_PKEY_CTX
*ctx
= NULL
;
7478 EC_KEY
*Y_ec
= NULL
;
7479 size_t Jx_len
, Kx_len
;
7480 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7483 u8 u
[DPP_MAX_HASH_LEN
];
7486 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
7489 #ifdef CONFIG_TESTING_OPTIONS
7490 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
7491 wpa_printf(MSG_INFO
,
7492 "DPP: TESTING - stop at PKEX Exchange Response");
7497 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7498 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7499 MAC2STR(dpp_pkex_peer_mac_override
));
7500 peer_mac
= dpp_pkex_peer_mac_override
;
7502 #endif /* CONFIG_TESTING_OPTIONS */
7504 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7506 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
7508 if (!attr_status
|| attr_status_len
!= 1) {
7509 dpp_pkex_fail(pkex
, "No DPP Status attribute");
7512 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
7514 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
7515 attr_group
= dpp_get_attr(buf
, buflen
,
7516 DPP_ATTR_FINITE_CYCLIC_GROUP
,
7518 if (attr_group
&& attr_group_len
== 2) {
7519 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7520 "Peer indicated mismatching PKEX group - proposed %u",
7521 WPA_GET_LE16(attr_group
));
7526 if (attr_status
[0] != DPP_STATUS_OK
) {
7527 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
7532 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
7534 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
7535 pkex
->identifier
)) {
7536 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
7540 /* N in Encrypted Key attribute */
7541 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
7543 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
7544 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
7548 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7549 bnctx
= BN_CTX_new();
7552 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
7553 pkex
->identifier
, bnctx
, &group
);
7558 Y
= EC_POINT_new(group
);
7559 N
= EC_POINT_new(group
);
7560 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7561 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7562 if (!Y
|| !N
|| !Nx
|| !Ny
||
7563 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
7564 EC_POINT_is_at_infinity(group
, N
) ||
7565 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
7566 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
7567 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
7568 EC_POINT_is_at_infinity(group
, Y
) ||
7569 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
7570 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
7574 dpp_debug_print_point("DPP: N", group
, N
);
7575 dpp_debug_print_point("DPP: Y'", group
, Y
);
7577 pkex
->exchange_done
= 1;
7579 /* ECDH: J = a * Y’ */
7580 Y_ec
= EC_KEY_new();
7582 EC_KEY_set_group(Y_ec
, group
) != 1 ||
7583 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
7585 pkex
->y
= EVP_PKEY_new();
7587 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
7589 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7591 EVP_PKEY_derive_init(ctx
) != 1 ||
7592 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7593 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7594 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7595 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7596 wpa_printf(MSG_ERROR
,
7597 "DPP: Failed to derive ECDH shared secret: %s",
7598 ERR_error_string(ERR_get_error(), NULL
));
7602 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7605 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7606 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7607 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7608 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7609 if (!A_pub
|| !Y_pub
|| !X_pub
)
7611 addr
[0] = pkex
->own_mac
;
7613 addr
[1] = wpabuf_head(A_pub
);
7614 len
[1] = wpabuf_len(A_pub
) / 2;
7615 addr
[2] = wpabuf_head(Y_pub
);
7616 len
[2] = wpabuf_len(Y_pub
) / 2;
7617 addr
[3] = wpabuf_head(X_pub
);
7618 len
[3] = wpabuf_len(X_pub
) / 2;
7619 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7621 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
7624 EVP_PKEY_CTX_free(ctx
);
7625 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7627 EVP_PKEY_derive_init(ctx
) != 1 ||
7628 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7629 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7630 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7631 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7632 wpa_printf(MSG_ERROR
,
7633 "DPP: Failed to derive ECDH shared secret: %s",
7634 ERR_error_string(ERR_get_error(), NULL
));
7638 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7641 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7643 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
7644 pkex
->Mx
, curve
->prime_len
,
7645 attr_key
/* N.x */, attr_key_len
/ 2,
7646 pkex
->code
, Kx
, Kx_len
,
7647 pkex
->z
, curve
->hash_len
);
7648 os_memset(Kx
, 0, Kx_len
);
7652 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
7666 EVP_PKEY_CTX_free(ctx
);
7670 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
7675 static struct wpabuf
*
7676 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
7677 const struct wpabuf
*B_pub
, const u8
*v
)
7679 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7680 struct wpabuf
*msg
= NULL
;
7685 struct wpabuf
*clear
= NULL
;
7686 size_t clear_len
, attr_len
;
7688 /* {B, v [bootstrapping info]}z */
7689 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7690 clear
= wpabuf_alloc(clear_len
);
7691 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7692 #ifdef CONFIG_TESTING_OPTIONS
7693 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
7695 #endif /* CONFIG_TESTING_OPTIONS */
7696 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
7700 #ifdef CONFIG_TESTING_OPTIONS
7701 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7702 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7703 goto skip_bootstrap_key
;
7705 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7706 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7707 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7708 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7709 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7711 goto skip_bootstrap_key
;
7713 #endif /* CONFIG_TESTING_OPTIONS */
7715 /* B in Bootstrap Key attribute */
7716 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7717 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
7718 wpabuf_put_buf(clear
, B_pub
);
7720 #ifdef CONFIG_TESTING_OPTIONS
7722 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
7723 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
7724 goto skip_r_auth_tag
;
7726 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
7727 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
7728 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7729 wpabuf_put_le16(clear
, curve
->hash_len
);
7730 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
7731 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
7732 goto skip_r_auth_tag
;
7734 #endif /* CONFIG_TESTING_OPTIONS */
7736 /* v in R-Auth tag attribute */
7737 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7738 wpabuf_put_le16(clear
, curve
->hash_len
);
7739 wpabuf_put_data(clear
, v
, curve
->hash_len
);
7741 #ifdef CONFIG_TESTING_OPTIONS
7743 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
7744 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7745 goto skip_wrapped_data
;
7747 #endif /* CONFIG_TESTING_OPTIONS */
7749 addr
[0] = wpabuf_head_u8(msg
) + 2;
7750 len
[0] = DPP_HDR_LEN
;
7753 len
[1] = sizeof(octet
);
7754 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7755 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7757 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7758 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7759 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7761 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7762 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7763 wpabuf_head(clear
), wpabuf_len(clear
),
7764 2, addr
, len
, wrapped
) < 0)
7766 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7767 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7769 #ifdef CONFIG_TESTING_OPTIONS
7770 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
7771 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7772 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7775 #endif /* CONFIG_TESTING_OPTIONS */
7788 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
7790 const u8
*buf
, size_t buflen
)
7792 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7793 EVP_PKEY_CTX
*ctx
= NULL
;
7794 size_t Jx_len
, Lx_len
;
7795 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
7796 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7797 const u8
*wrapped_data
, *b_key
, *peer_u
;
7798 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
7802 u8
*unwrapped
= NULL
;
7803 size_t unwrapped_len
= 0;
7804 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7805 struct wpabuf
*B_pub
= NULL
;
7806 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
7808 #ifdef CONFIG_TESTING_OPTIONS
7809 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
7810 wpa_printf(MSG_INFO
,
7811 "DPP: TESTING - stop at PKEX CR Request");
7815 #endif /* CONFIG_TESTING_OPTIONS */
7817 if (!pkex
->exchange_done
|| pkex
->failed
||
7818 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
7821 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7823 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7825 "Missing or invalid required Wrapped Data attribute");
7829 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7830 wrapped_data
, wrapped_data_len
);
7831 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7832 unwrapped
= os_malloc(unwrapped_len
);
7837 len
[0] = DPP_HDR_LEN
;
7840 len
[1] = sizeof(octet
);
7841 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7842 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7844 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7845 wrapped_data
, wrapped_data_len
,
7846 2, addr
, len
, unwrapped
) < 0) {
7848 "AES-SIV decryption failed - possible PKEX code mismatch");
7853 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7854 unwrapped
, unwrapped_len
);
7856 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7857 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7861 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7863 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7864 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7867 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7869 if (!pkex
->peer_bootstrap_key
) {
7870 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7873 dpp_debug_print_key("DPP: Peer bootstrap public key",
7874 pkex
->peer_bootstrap_key
);
7876 /* ECDH: J' = y * A' */
7877 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7879 EVP_PKEY_derive_init(ctx
) != 1 ||
7880 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7881 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7882 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7883 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7884 wpa_printf(MSG_ERROR
,
7885 "DPP: Failed to derive ECDH shared secret: %s",
7886 ERR_error_string(ERR_get_error(), NULL
));
7890 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7893 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7894 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7895 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7896 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7897 if (!A_pub
|| !Y_pub
|| !X_pub
)
7899 addr
[0] = pkex
->peer_mac
;
7901 addr
[1] = wpabuf_head(A_pub
);
7902 len
[1] = wpabuf_len(A_pub
) / 2;
7903 addr
[2] = wpabuf_head(Y_pub
);
7904 len
[2] = wpabuf_len(Y_pub
) / 2;
7905 addr
[3] = wpabuf_head(X_pub
);
7906 len
[3] = wpabuf_len(X_pub
) / 2;
7907 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7910 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
7912 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
7913 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
7914 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
7915 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
7916 u
, curve
->hash_len
);
7917 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
7921 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
7923 /* ECDH: L = b * X' */
7924 EVP_PKEY_CTX_free(ctx
);
7925 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7927 EVP_PKEY_derive_init(ctx
) != 1 ||
7928 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
7929 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
7930 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7931 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
7932 wpa_printf(MSG_ERROR
,
7933 "DPP: Failed to derive ECDH shared secret: %s",
7934 ERR_error_string(ERR_get_error(), NULL
));
7938 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
7941 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7942 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7945 addr
[0] = pkex
->own_mac
;
7947 addr
[1] = wpabuf_head(B_pub
);
7948 len
[1] = wpabuf_len(B_pub
) / 2;
7949 addr
[2] = wpabuf_head(X_pub
);
7950 len
[2] = wpabuf_len(X_pub
) / 2;
7951 addr
[3] = wpabuf_head(Y_pub
);
7952 len
[3] = wpabuf_len(Y_pub
) / 2;
7953 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7955 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
7957 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
7962 EVP_PKEY_CTX_free(ctx
);
7970 wpa_printf(MSG_DEBUG
,
7971 "DPP: PKEX Commit-Reveal Request processing failed");
7976 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
7977 const u8
*buf
, size_t buflen
)
7979 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7980 const u8
*wrapped_data
, *b_key
, *peer_v
;
7981 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
7985 u8
*unwrapped
= NULL
;
7986 size_t unwrapped_len
= 0;
7988 u8 v
[DPP_MAX_HASH_LEN
];
7990 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7991 EVP_PKEY_CTX
*ctx
= NULL
;
7992 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7994 #ifdef CONFIG_TESTING_OPTIONS
7995 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
7996 wpa_printf(MSG_INFO
,
7997 "DPP: TESTING - stop at PKEX CR Response");
8001 #endif /* CONFIG_TESTING_OPTIONS */
8003 if (!pkex
->exchange_done
|| pkex
->failed
||
8004 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
8007 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
8009 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
8011 "Missing or invalid required Wrapped Data attribute");
8015 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8016 wrapped_data
, wrapped_data_len
);
8017 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
8018 unwrapped
= os_malloc(unwrapped_len
);
8023 len
[0] = DPP_HDR_LEN
;
8026 len
[1] = sizeof(octet
);
8027 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8028 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8030 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
8031 wrapped_data
, wrapped_data_len
,
8032 2, addr
, len
, unwrapped
) < 0) {
8034 "AES-SIV decryption failed - possible PKEX code mismatch");
8038 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
8039 unwrapped
, unwrapped_len
);
8041 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
8042 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
8046 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
8048 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
8049 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
8052 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
8054 if (!pkex
->peer_bootstrap_key
) {
8055 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
8058 dpp_debug_print_key("DPP: Peer bootstrap public key",
8059 pkex
->peer_bootstrap_key
);
8061 /* ECDH: L' = x * B' */
8062 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
8064 EVP_PKEY_derive_init(ctx
) != 1 ||
8065 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
8066 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
8067 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
8068 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
8069 wpa_printf(MSG_ERROR
,
8070 "DPP: Failed to derive ECDH shared secret: %s",
8071 ERR_error_string(ERR_get_error(), NULL
));
8075 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8078 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8079 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8080 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8081 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8082 if (!B_pub
|| !X_pub
|| !Y_pub
)
8084 addr
[0] = pkex
->peer_mac
;
8086 addr
[1] = wpabuf_head(B_pub
);
8087 len
[1] = wpabuf_len(B_pub
) / 2;
8088 addr
[2] = wpabuf_head(X_pub
);
8089 len
[2] = wpabuf_len(X_pub
) / 2;
8090 addr
[3] = wpabuf_head(Y_pub
);
8091 len
[3] = wpabuf_len(Y_pub
) / 2;
8092 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8095 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
8097 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
8098 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
8099 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
8100 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
8101 v
, curve
->hash_len
);
8102 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
8106 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
8113 EVP_PKEY_CTX_free(ctx
);
8121 void dpp_pkex_free(struct dpp_pkex
*pkex
)
8126 os_free(pkex
->identifier
);
8127 os_free(pkex
->code
);
8128 EVP_PKEY_free(pkex
->x
);
8129 EVP_PKEY_free(pkex
->y
);
8130 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
8131 wpabuf_free(pkex
->exchange_req
);
8132 wpabuf_free(pkex
->exchange_resp
);
8137 #ifdef CONFIG_TESTING_OPTIONS
8138 char * dpp_corrupt_connector_signature(const char *connector
)
8140 char *tmp
, *pos
, *signed3
= NULL
;
8141 unsigned char *signature
= NULL
;
8142 size_t signature_len
= 0, signed3_len
;
8144 tmp
= os_zalloc(os_strlen(connector
) + 5);
8147 os_memcpy(tmp
, connector
, os_strlen(connector
));
8149 pos
= os_strchr(tmp
, '.');
8153 pos
= os_strchr(pos
+ 1, '.');
8158 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
8160 signature
= base64_url_decode((const unsigned char *) pos
,
8161 os_strlen(pos
), &signature_len
);
8162 if (!signature
|| signature_len
== 0)
8164 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
8165 signature
, signature_len
);
8166 signature
[signature_len
- 1] ^= 0x01;
8167 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
8168 signature
, signature_len
);
8169 signed3
= (char *) base64_url_encode(signature
, signature_len
,
8173 os_memcpy(pos
, signed3
, signed3_len
);
8174 pos
[signed3_len
] = '\0';
8175 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
8187 #endif /* CONFIG_TESTING_OPTIONS */
8192 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
8193 size_t net_access_key_len
)
8195 struct wpabuf
*pub
= NULL
;
8197 struct dpp_pfs
*pfs
;
8199 pfs
= os_zalloc(sizeof(*pfs
));
8203 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
8204 net_access_key_len
);
8206 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8209 EVP_PKEY_free(own_key
);
8211 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
8215 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
8216 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
8220 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
8223 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
8224 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
8225 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
8226 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
8227 wpabuf_put_buf(pfs
->ie
, pub
);
8229 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
8240 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
8242 if (peer_ie_len
< 2)
8244 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
8245 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
8249 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
8251 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
8253 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
8256 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
8261 void dpp_pfs_free(struct dpp_pfs
*pfs
)
8265 crypto_ecdh_deinit(pfs
->ecdh
);
8266 wpabuf_free(pfs
->ie
);
8267 wpabuf_clear_free(pfs
->secret
);
8271 #endif /* CONFIG_DPP2 */
8274 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
8276 struct dpp_bootstrap_info
*bi
;
8277 unsigned int max_id
= 0;
8279 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8280 if (bi
->id
> max_id
)
8287 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
8289 struct dpp_bootstrap_info
*bi
, *tmp
;
8295 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
8296 struct dpp_bootstrap_info
, list
) {
8297 if (id
&& bi
->id
!= id
)
8300 dl_list_del(&bi
->list
);
8301 dpp_bootstrap_info_free(bi
);
8305 return 0; /* flush succeeds regardless of entries found */
8306 return found
? 0 : -1;
8310 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
8313 struct dpp_bootstrap_info
*bi
;
8318 bi
= dpp_parse_qr_code(uri
);
8322 bi
->id
= dpp_next_id(dpp
);
8323 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8328 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
8330 char *chan
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
, *curve
= NULL
;
8333 size_t privkey_len
= 0;
8336 struct dpp_bootstrap_info
*bi
;
8341 bi
= os_zalloc(sizeof(*bi
));
8345 if (os_strstr(cmd
, "type=qrcode"))
8346 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
8347 else if (os_strstr(cmd
, "type=pkex"))
8348 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8352 chan
= get_param(cmd
, " chan=");
8353 mac
= get_param(cmd
, " mac=");
8354 info
= get_param(cmd
, " info=");
8355 curve
= get_param(cmd
, " curve=");
8356 key
= get_param(cmd
, " key=");
8359 privkey_len
= os_strlen(key
) / 2;
8360 privkey
= os_malloc(privkey_len
);
8362 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8366 pk
= dpp_keygen(bi
, curve
, privkey
, privkey_len
);
8370 len
= 4; /* "DPP:" */
8372 if (dpp_parse_uri_chan_list(bi
, chan
) < 0)
8374 len
+= 3 + os_strlen(chan
); /* C:...; */
8377 if (dpp_parse_uri_mac(bi
, mac
) < 0)
8379 len
+= 3 + os_strlen(mac
); /* M:...; */
8382 if (dpp_parse_uri_info(bi
, info
) < 0)
8384 len
+= 3 + os_strlen(info
); /* I:...; */
8386 len
+= 4 + os_strlen(pk
);
8387 bi
->uri
= os_malloc(len
+ 1);
8390 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8391 chan
? "C:" : "", chan
? chan
: "", chan
? ";" : "",
8392 mac
? "M:" : "", mac
? mac
: "", mac
? ";" : "",
8393 info
? "I:" : "", info
? info
: "", info
? ";" : "",
8395 bi
->id
= dpp_next_id(dpp
);
8396 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8405 str_clear_free(key
);
8406 bin_clear_free(privkey
, privkey_len
);
8407 dpp_bootstrap_info_free(bi
);
8412 struct dpp_bootstrap_info
*
8413 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
8415 struct dpp_bootstrap_info
*bi
;
8420 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8428 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
8430 unsigned int id_val
;
8432 if (os_strcmp(id
, "*") == 0) {
8440 return dpp_bootstrap_del(dpp
, id_val
);
8444 struct dpp_bootstrap_info
*
8445 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
8448 struct dpp_bootstrap_info
*bi
;
8450 bi
= os_zalloc(sizeof(*bi
));
8453 bi
->id
= dpp_next_id(dpp
);
8454 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8455 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
8458 bi
->curve
= pkex
->own_bi
->curve
;
8459 bi
->pubkey
= pkex
->peer_bootstrap_key
;
8460 pkex
->peer_bootstrap_key
= NULL
;
8461 if (dpp_bootstrap_key_hash(bi
) < 0) {
8462 dpp_bootstrap_info_free(bi
);
8465 dpp_pkex_free(pkex
);
8466 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8471 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
8473 struct dpp_bootstrap_info
*bi
;
8475 bi
= dpp_bootstrap_get_id(dpp
, id
);
8482 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
8483 char *reply
, int reply_size
)
8485 struct dpp_bootstrap_info
*bi
;
8487 bi
= dpp_bootstrap_get_id(dpp
, id
);
8490 return os_snprintf(reply
, reply_size
, "type=%s\n"
8491 "mac_addr=" MACSTR
"\n"
8495 dpp_bootstrap_type_txt(bi
->type
),
8496 MAC2STR(bi
->mac_addr
),
8497 bi
->info
? bi
->info
: "",
8503 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
8504 const u8
*r_bootstrap
,
8505 struct dpp_bootstrap_info
**own_bi
,
8506 struct dpp_bootstrap_info
**peer_bi
)
8508 struct dpp_bootstrap_info
*bi
;
8515 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8516 if (!*own_bi
&& bi
->own
&&
8517 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
8518 SHA256_MAC_LEN
) == 0) {
8519 wpa_printf(MSG_DEBUG
,
8520 "DPP: Found matching own bootstrapping information");
8524 if (!*peer_bi
&& !bi
->own
&&
8525 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
8526 SHA256_MAC_LEN
) == 0) {
8527 wpa_printf(MSG_DEBUG
,
8528 "DPP: Found matching peer bootstrapping information");
8532 if (*own_bi
&& *peer_bi
)
8539 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
8541 struct dpp_configurator
*conf
;
8542 unsigned int max_id
= 0;
8544 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
8546 if (conf
->id
> max_id
)
8553 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
8558 size_t privkey_len
= 0;
8560 struct dpp_configurator
*conf
= NULL
;
8562 curve
= get_param(cmd
, " curve=");
8563 key
= get_param(cmd
, " key=");
8566 privkey_len
= os_strlen(key
) / 2;
8567 privkey
= os_malloc(privkey_len
);
8569 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8573 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
8577 conf
->id
= dpp_next_configurator_id(dpp
);
8578 dl_list_add(&dpp
->configurator
, &conf
->list
);
8583 str_clear_free(key
);
8584 bin_clear_free(privkey
, privkey_len
);
8585 dpp_configurator_free(conf
);
8590 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
8592 struct dpp_configurator
*conf
, *tmp
;
8598 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
8599 struct dpp_configurator
, list
) {
8600 if (id
&& conf
->id
!= id
)
8603 dl_list_del(&conf
->list
);
8604 dpp_configurator_free(conf
);
8608 return 0; /* flush succeeds regardless of entries found */
8609 return found
? 0 : -1;
8613 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
8615 unsigned int id_val
;
8617 if (os_strcmp(id
, "*") == 0) {
8625 return dpp_configurator_del(dpp
, id_val
);
8629 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
8630 char *buf
, size_t buflen
)
8632 struct dpp_configurator
*conf
;
8634 conf
= dpp_configurator_get_id(dpp
, id
);
8638 return dpp_configurator_get_key(conf
, buf
, buflen
);
8642 struct dpp_global
* dpp_global_init(void)
8644 struct dpp_global
*dpp
;
8646 dpp
= os_zalloc(sizeof(*dpp
));
8650 dl_list_init(&dpp
->bootstrap
);
8651 dl_list_init(&dpp
->configurator
);
8657 void dpp_global_clear(struct dpp_global
*dpp
)
8662 dpp_bootstrap_del(dpp
, 0);
8663 dpp_configurator_del(dpp
, 0);
8667 void dpp_global_deinit(struct dpp_global
*dpp
)
8669 dpp_global_clear(dpp
);