2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
10 #include <openssl/opensslv.h>
11 #include <openssl/err.h>
12 #include <openssl/asn1.h>
13 #include <openssl/asn1t.h>
15 #include "utils/common.h"
16 #include "utils/base64.h"
17 #include "utils/json.h"
18 #include "common/ieee802_11_common.h"
19 #include "common/ieee802_11_defs.h"
20 #include "common/wpa_ctrl.h"
21 #include "crypto/crypto.h"
22 #include "crypto/random.h"
23 #include "crypto/aes.h"
24 #include "crypto/aes_siv.h"
25 #include "crypto/sha384.h"
26 #include "crypto/sha512.h"
27 #include "drivers/driver.h"
31 #ifdef CONFIG_TESTING_OPTIONS
32 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
34 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
35 const struct dpp_curve_params
*curve
);
36 #endif /* CONFIG_TESTING_OPTIONS */
38 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
39 /* Compatibility wrappers for older versions. */
41 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
49 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
61 static const struct dpp_curve_params dpp_curves
[] = {
62 /* The mandatory to support and the default NIST P-256 curve needs to
63 * be the first entry on this list. */
64 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
65 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
66 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
67 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
68 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
69 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
70 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
74 /* Role-specific elements for PKEX */
77 static const u8 pkex_init_x_p256
[32] = {
78 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
79 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
80 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
81 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
83 static const u8 pkex_init_y_p256
[32] = {
84 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
85 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
86 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
87 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
89 static const u8 pkex_resp_x_p256
[32] = {
90 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
91 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
92 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
93 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
95 static const u8 pkex_resp_y_p256
[32] = {
96 0x26, 0x04, 0x09, 0x45, 0x0a, 0x05, 0x20, 0xe7,
97 0xa7, 0x27, 0xc1, 0x36, 0x76, 0x85, 0xca, 0x3e,
98 0x42, 0x16, 0xf4, 0x89, 0x85, 0x34, 0x6e, 0xd5,
99 0x17, 0xde, 0xc0, 0xb8, 0xad, 0xfd, 0xb2, 0x98
103 static const u8 pkex_init_x_p384
[48] = {
104 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
105 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
106 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
107 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
108 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
109 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
111 static const u8 pkex_init_y_p384
[48] = {
112 0x89, 0xd0, 0x97, 0x7b, 0x59, 0x4f, 0xa6, 0xd6,
113 0x7c, 0x5d, 0x93, 0x5b, 0x93, 0xc4, 0x07, 0xa9,
114 0x89, 0xee, 0xd5, 0xcd, 0x6f, 0x42, 0xf8, 0x38,
115 0xc8, 0xc6, 0x62, 0x24, 0x69, 0x0c, 0xd4, 0x48,
116 0xd8, 0x44, 0xd6, 0xc2, 0xe8, 0xcc, 0x62, 0x6b,
117 0x3c, 0x25, 0x53, 0xba, 0x4f, 0x71, 0xf8, 0xe7
119 static const u8 pkex_resp_x_p384
[48] = {
120 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
121 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
122 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
123 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
124 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
125 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
127 static const u8 pkex_resp_y_p384
[48] = {
128 0x54, 0x58, 0x20, 0xad, 0x55, 0x1d, 0xca, 0xf3,
129 0x1c, 0x8a, 0xcd, 0x19, 0x40, 0xf9, 0x37, 0x83,
130 0xc7, 0xd6, 0xb3, 0x13, 0x7d, 0x53, 0x28, 0x5c,
131 0xf6, 0x2d, 0xf1, 0xdd, 0xa5, 0x8b, 0xad, 0x5d,
132 0x81, 0xab, 0xb1, 0x00, 0x39, 0xd6, 0xcc, 0x9c,
133 0xea, 0x1e, 0x84, 0x1d, 0xbf, 0xe3, 0x35, 0xf9
137 static const u8 pkex_init_x_p521
[66] = {
138 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
139 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
140 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
141 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
142 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
143 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
144 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
145 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
148 static const u8 pkex_init_y_p521
[66] = {
149 0x01, 0x4c, 0x71, 0xfd, 0x1b, 0xd5, 0x9c, 0xa6,
150 0xed, 0x39, 0xef, 0x45, 0xc5, 0x06, 0xfd, 0x66,
151 0xc0, 0xeb, 0x0f, 0xbf, 0x21, 0xa3, 0x36, 0x74,
152 0xfd, 0xaa, 0x05, 0x6e, 0x4e, 0x33, 0x95, 0x42,
153 0x1a, 0x9d, 0x3f, 0x3a, 0x1c, 0x5e, 0xa8, 0x60,
154 0xf7, 0xe5, 0x59, 0x1d, 0x07, 0xaa, 0x6f, 0x40,
155 0x0a, 0x59, 0x3c, 0x27, 0xad, 0xe0, 0x48, 0xfd,
156 0xd1, 0x83, 0x37, 0x4c, 0xdf, 0xe1, 0x86, 0x72,
159 static const u8 pkex_resp_x_p521
[66] = {
160 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
161 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
162 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
163 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
164 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
165 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
166 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
167 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
170 static const u8 pkex_resp_y_p521
[66] = {
171 0x01, 0xb9, 0x9c, 0xc6, 0x41, 0x32, 0x5b, 0xd2,
172 0x35, 0xd8, 0x8b, 0x2b, 0xe4, 0x6e, 0xcc, 0xdf,
173 0x7c, 0x38, 0xc4, 0x5b, 0xf6, 0x74, 0x71, 0x5c,
174 0x77, 0x16, 0x8a, 0x80, 0xa9, 0x84, 0xc7, 0x7b,
175 0x9d, 0xfd, 0x83, 0x6f, 0xae, 0xf8, 0x24, 0x16,
176 0x2f, 0x21, 0x25, 0x65, 0xa2, 0x1a, 0x6b, 0x2d,
177 0x30, 0x62, 0xb3, 0xcc, 0x6e, 0x59, 0x3c, 0x7f,
178 0x58, 0x91, 0x81, 0x72, 0x07, 0x8c, 0x91, 0xac,
182 /* Brainpool P-256r1 */
183 static const u8 pkex_init_x_bp_p256r1
[32] = {
184 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
185 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
186 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
187 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
189 static const u8 pkex_init_y_bp_p256r1
[32] = {
190 0x16, 0x30, 0x68, 0x32, 0x3b, 0xb0, 0x21, 0xee,
191 0xeb, 0xf7, 0xb6, 0x7c, 0xae, 0x52, 0x26, 0x42,
192 0x59, 0x28, 0x58, 0xb6, 0x14, 0x90, 0xed, 0x69,
193 0xd0, 0x67, 0xea, 0x25, 0x60, 0x0f, 0xa9, 0x6c
195 static const u8 pkex_resp_x_bp_p256r1
[32] = {
196 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
197 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
198 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
199 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
201 static const u8 pkex_resp_y_bp_p256r1
[32] = {
202 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
203 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
204 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
205 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
208 /* Brainpool P-384r1 */
209 static const u8 pkex_init_x_bp_p384r1
[48] = {
210 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
211 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
212 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
213 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
214 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
215 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
217 static const u8 pkex_init_y_bp_p384r1
[48] = {
218 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
219 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
220 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
221 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
222 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
223 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
225 static const u8 pkex_resp_x_bp_p384r1
[48] = {
226 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
227 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
228 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
229 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
230 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
231 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
233 static const u8 pkex_resp_y_bp_p384r1
[48] = {
234 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
235 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
236 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
237 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
238 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
239 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
242 /* Brainpool P-512r1 */
243 static const u8 pkex_init_x_bp_p512r1
[64] = {
244 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
245 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
246 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
247 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
248 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
249 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
250 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
251 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
253 static const u8 pkex_init_y_bp_p512r1
[64] = {
254 0x5a, 0x28, 0x01, 0xbe, 0x96, 0x82, 0x4e, 0xf6,
255 0xfa, 0xed, 0x7d, 0xfd, 0x48, 0x8b, 0x48, 0x4e,
256 0xd1, 0x97, 0x87, 0xc4, 0x05, 0x5d, 0x15, 0x2a,
257 0xf4, 0x91, 0x4b, 0x75, 0x90, 0xd9, 0x34, 0x2c,
258 0x3c, 0x12, 0xf2, 0xf5, 0x25, 0x94, 0x24, 0x34,
259 0xa7, 0x6d, 0x66, 0xbc, 0x27, 0xa4, 0xa0, 0x8d,
260 0xd5, 0xe1, 0x54, 0xa3, 0x55, 0x26, 0xd4, 0x14,
261 0x17, 0x0f, 0xc1, 0xc7, 0x3d, 0x68, 0x7f, 0x5a
263 static const u8 pkex_resp_x_bp_p512r1
[64] = {
264 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
265 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
266 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
267 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
268 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
269 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
270 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
271 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
273 static const u8 pkex_resp_y_bp_p512r1
[64] = {
274 0x2a, 0xbe, 0x59, 0xe6, 0xc4, 0xb3, 0xd8, 0x09,
275 0x66, 0x89, 0x0a, 0x2d, 0x19, 0xf0, 0x9c, 0x9f,
276 0xb4, 0xab, 0x8f, 0x50, 0x68, 0x3c, 0x74, 0x64,
277 0x4e, 0x19, 0x55, 0x81, 0x9b, 0x48, 0x5c, 0xf4,
278 0x12, 0x8d, 0xb9, 0xd8, 0x02, 0x5b, 0xe1, 0x26,
279 0x7e, 0x19, 0x5c, 0xfd, 0x70, 0xf7, 0x4b, 0xdc,
280 0xb5, 0x5d, 0xc1, 0x7a, 0xe9, 0xd1, 0x05, 0x2e,
281 0xd1, 0xfd, 0x2f, 0xce, 0x63, 0x77, 0x48, 0x2c
285 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
286 size_t num_elem
, const u8
*addr
[], const size_t *len
,
289 if (curve
->hash_len
== 32)
290 return sha256_vector(num_elem
, addr
, len
, mac
);
291 if (curve
->hash_len
== 48)
292 return sha384_vector(num_elem
, addr
, len
, mac
);
293 if (curve
->hash_len
== 64)
294 return sha512_vector(num_elem
, addr
, len
, mac
);
299 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
300 const char *label
, u8
*out
, size_t outlen
)
303 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
304 (const u8
*) label
, os_strlen(label
),
307 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
308 (const u8
*) label
, os_strlen(label
),
311 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
312 (const u8
*) label
, os_strlen(label
),
318 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
319 size_t num_elem
, const u8
*addr
[],
320 const size_t *len
, u8
*mac
)
323 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
326 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
329 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
335 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
336 const u8
*data
, size_t data_len
, u8
*mac
)
339 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
341 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
343 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
348 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
350 int num_bytes
, offset
;
352 num_bytes
= BN_num_bytes(bn
);
353 if ((size_t) num_bytes
> len
)
355 offset
= len
- num_bytes
;
356 os_memset(pos
, 0, offset
);
357 BN_bn2bin(bn
, pos
+ offset
);
362 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
369 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
372 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
373 len
= i2o_ECPublicKey(eckey
, NULL
);
375 wpa_printf(MSG_ERROR
,
376 "DDP: Failed to determine public key encoding length");
381 buf
= wpabuf_alloc(len
);
387 pos
= wpabuf_put(buf
, len
);
388 res
= i2o_ECPublicKey(eckey
, &pos
);
391 wpa_printf(MSG_ERROR
,
392 "DDP: Failed to encode public key (res=%d/%d)",
399 /* Remove 0x04 prefix to match DPP definition */
400 pos
= wpabuf_mhead(buf
);
401 os_memmove(pos
, pos
+ 1, len
- 1);
409 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
410 const u8
*buf_x
, const u8
*buf_y
,
413 EC_KEY
*eckey
= NULL
;
415 EC_POINT
*point
= NULL
;
416 BIGNUM
*x
= NULL
, *y
= NULL
;
417 EVP_PKEY
*pkey
= NULL
;
421 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
425 point
= EC_POINT_new(group
);
426 x
= BN_bin2bn(buf_x
, len
, NULL
);
427 y
= BN_bin2bn(buf_y
, len
, NULL
);
428 if (!point
|| !x
|| !y
) {
429 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
433 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
434 wpa_printf(MSG_ERROR
,
435 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
436 ERR_error_string(ERR_get_error(), NULL
));
440 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
441 EC_POINT_is_at_infinity(group
, point
)) {
442 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
446 eckey
= EC_KEY_new();
448 EC_KEY_set_group(eckey
, group
) != 1 ||
449 EC_KEY_set_public_key(eckey
, point
) != 1) {
450 wpa_printf(MSG_ERROR
,
451 "DPP: Failed to set EC_KEY: %s",
452 ERR_error_string(ERR_get_error(), NULL
));
455 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
457 pkey
= EVP_PKEY_new();
458 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
459 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
467 EC_POINT_free(point
);
477 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
478 const u8
*buf
, size_t len
)
481 const EC_GROUP
*group
;
482 EVP_PKEY
*pkey
= NULL
;
487 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
489 wpa_printf(MSG_ERROR
,
490 "DPP: Could not get EC_KEY from group_key");
494 group
= EC_KEY_get0_group(eckey
);
496 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
499 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
506 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
508 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
512 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
517 msg
= wpabuf_alloc(8 + len
);
520 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
521 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
522 wpabuf_put_be24(msg
, OUI_WFA
);
523 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
524 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
525 wpabuf_put_u8(msg
, type
);
530 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
533 const u8
*pos
= buf
, *end
= buf
+ len
;
535 while (end
- pos
>= 4) {
536 id
= WPA_GET_LE16(pos
);
538 alen
= WPA_GET_LE16(pos
);
540 if (alen
> end
- pos
)
553 int dpp_check_attrs(const u8
*buf
, size_t len
)
556 int wrapped_data
= 0;
560 while (end
- pos
>= 4) {
563 id
= WPA_GET_LE16(pos
);
565 alen
= WPA_GET_LE16(pos
);
567 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
569 if (alen
> end
- pos
) {
570 wpa_printf(MSG_DEBUG
,
571 "DPP: Truncated message - not enough room for the attribute - dropped");
575 wpa_printf(MSG_DEBUG
,
576 "DPP: An unexpected attribute included after the Wrapped Data attribute");
579 if (id
== DPP_ATTR_WRAPPED_DATA
)
585 wpa_printf(MSG_DEBUG
,
586 "DPP: Unexpected octets (%d) after the last attribute",
595 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
601 EVP_PKEY_free(info
->pubkey
);
606 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
609 case DPP_BOOTSTRAP_QR_CODE
:
611 case DPP_BOOTSTRAP_PKEX
:
618 static int dpp_uri_valid_info(const char *info
)
621 unsigned char val
= *info
++;
623 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
631 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
633 bi
->uri
= os_strdup(uri
);
634 return bi
->uri
? 0 : -1;
638 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
639 const char *chan_list
)
641 const char *pos
= chan_list
;
642 int opclass
, channel
, freq
;
644 while (pos
&& *pos
&& *pos
!= ';') {
648 pos
= os_strchr(pos
, '/');
655 while (*pos
>= '0' && *pos
<= '9')
657 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
658 wpa_printf(MSG_DEBUG
,
659 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
660 opclass
, channel
, freq
);
662 wpa_printf(MSG_DEBUG
,
663 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
665 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
666 wpa_printf(MSG_DEBUG
,
667 "DPP: Too many channels in URI channel-list - ignore list");
671 bi
->freq
[bi
->num_freq
++] = freq
;
674 if (*pos
== ';' || *pos
== '\0')
683 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
688 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
693 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
694 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
698 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
704 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
711 end
= os_strchr(info
, ';');
713 end
= info
+ os_strlen(info
);
714 bi
->info
= os_malloc(end
- info
+ 1);
717 os_memcpy(bi
->info
, info
, end
- info
);
718 bi
->info
[end
- info
] = '\0';
719 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
720 if (!dpp_uri_valid_info(bi
->info
)) {
721 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
729 static const struct dpp_curve_params
*
730 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
735 for (i
= 0; dpp_curves
[i
].name
; i
++) {
736 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
737 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
738 return &dpp_curves
[i
];
744 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
750 for (i
= 0; dpp_curves
[i
].name
; i
++) {
751 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
753 return &dpp_curves
[i
];
759 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
765 const unsigned char *p
;
767 X509_PUBKEY
*pub
= NULL
;
769 const unsigned char *pk
;
772 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
775 const ASN1_OBJECT
*pa_oid
;
779 const ASN1_OBJECT
*poid
;
782 end
= os_strchr(info
, ';');
786 data
= base64_decode((const unsigned char *) info
, end
- info
,
789 wpa_printf(MSG_DEBUG
,
790 "DPP: Invalid base64 encoding on URI public-key");
793 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
796 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
797 bi
->pubkey_hash
) < 0) {
798 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
801 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
802 bi
->pubkey_hash
, SHA256_MAC_LEN
);
804 /* DER encoded ASN.1 SubjectPublicKeyInfo
806 * SubjectPublicKeyInfo ::= SEQUENCE {
807 * algorithm AlgorithmIdentifier,
808 * subjectPublicKey BIT STRING }
810 * AlgorithmIdentifier ::= SEQUENCE {
811 * algorithm OBJECT IDENTIFIER,
812 * parameters ANY DEFINED BY algorithm OPTIONAL }
814 * subjectPublicKey = compressed format public key per ANSI X9.63
815 * algorithm = ecPublicKey (1.2.840.10045.2.1)
816 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
817 * prime256v1 (1.2.840.10045.3.1.7)
821 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
825 wpa_printf(MSG_DEBUG
,
826 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
830 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
831 wpa_printf(MSG_DEBUG
,
832 "DPP: SubjectPublicKeyInfo does not describe an EC key");
837 res
= X509_PUBKEY_set(&pub
, pkey
);
839 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
843 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
845 wpa_printf(MSG_DEBUG
,
846 "DPP: Could not extract SubjectPublicKeyInfo parameters");
849 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
850 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
851 wpa_printf(MSG_DEBUG
,
852 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
855 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
856 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
857 wpa_printf(MSG_DEBUG
,
858 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
862 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
863 if (ptype
!= V_ASN1_OBJECT
) {
864 wpa_printf(MSG_DEBUG
,
865 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
869 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
870 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
871 wpa_printf(MSG_DEBUG
,
872 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
875 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
876 bi
->curve
= dpp_get_curve_oid(poid
);
878 wpa_printf(MSG_DEBUG
,
879 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
884 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
886 X509_PUBKEY_free(pub
);
890 X509_PUBKEY_free(pub
);
896 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
898 const char *pos
= uri
;
900 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
901 struct dpp_bootstrap_info
*bi
;
903 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
905 if (os_strncmp(pos
, "DPP:", 4) != 0) {
906 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
912 end
= os_strchr(pos
, ';');
917 /* Handle terminating ";;" and ignore unexpected ";"
918 * for parsing robustness. */
923 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
925 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
927 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
929 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
932 wpa_hexdump_ascii(MSG_DEBUG
,
933 "DPP: Ignore unrecognized URI parameter",
939 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
943 bi
= os_zalloc(sizeof(*bi
));
947 if (dpp_clone_uri(bi
, uri
) < 0 ||
948 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
949 dpp_parse_uri_mac(bi
, mac
) < 0 ||
950 dpp_parse_uri_info(bi
, info
) < 0 ||
951 dpp_parse_uri_pk(bi
, pk
) < 0) {
952 dpp_bootstrap_info_free(bi
);
960 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
962 struct dpp_bootstrap_info
*bi
;
964 bi
= dpp_parse_uri(uri
);
966 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
971 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
978 unsigned char *der
= NULL
;
981 out
= BIO_new(BIO_s_mem());
985 EVP_PKEY_print_private(out
, key
, 0, NULL
);
986 rlen
= BIO_ctrl_pending(out
);
987 txt
= os_malloc(rlen
+ 1);
989 res
= BIO_read(out
, txt
, rlen
);
992 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
998 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1002 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1004 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1008 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1010 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1018 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1020 #ifdef OPENSSL_IS_BORINGSSL
1021 EVP_PKEY_CTX
*kctx
= NULL
;
1022 const EC_GROUP
*group
;
1025 EVP_PKEY_CTX
*pctx
, *kctx
= NULL
;
1027 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1030 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1032 nid
= OBJ_txt2nid(curve
->name
);
1033 if (nid
== NID_undef
) {
1034 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1037 #ifdef OPENSSL_IS_BORINGSSL
1038 group
= EC_GROUP_new_by_curve_name(nid
);
1039 ec_params
= EC_KEY_new();
1040 if (!ec_params
|| EC_KEY_set_group(ec_params
, group
) != 1) {
1041 wpa_printf(MSG_ERROR
,
1042 "DPP: Failed to generate EC_KEY parameters");
1045 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1046 params
= EVP_PKEY_new();
1047 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1048 wpa_printf(MSG_ERROR
,
1049 "DPP: Failed to generate EVP_PKEY parameters");
1053 pctx
= EVP_PKEY_CTX_new_id(EVP_PKEY_EC
, NULL
);
1055 EVP_PKEY_paramgen_init(pctx
) != 1 ||
1056 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx
, nid
) != 1 ||
1057 EVP_PKEY_CTX_set_ec_param_enc(pctx
, OPENSSL_EC_NAMED_CURVE
) != 1 ||
1058 EVP_PKEY_paramgen(pctx
, ¶ms
) != 1) {
1059 wpa_printf(MSG_ERROR
,
1060 "DPP: Failed to generate EVP_PKEY parameters");
1061 EVP_PKEY_CTX_free(pctx
);
1064 EVP_PKEY_CTX_free(pctx
);
1067 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1069 EVP_PKEY_keygen_init(kctx
) != 1 ||
1070 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1071 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1075 if (wpa_debug_show_keys
)
1076 dpp_debug_print_key("Own generated key", key
);
1078 EVP_PKEY_free(params
);
1079 EVP_PKEY_CTX_free(kctx
);
1082 EVP_PKEY_CTX_free(kctx
);
1083 EVP_PKEY_free(params
);
1088 static const struct dpp_curve_params
*
1089 dpp_get_curve_name(const char *name
)
1093 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1094 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1095 (dpp_curves
[i
].jwk_crv
&&
1096 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1097 return &dpp_curves
[i
];
1103 static const struct dpp_curve_params
*
1104 dpp_get_curve_jwk_crv(const char *name
)
1108 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1109 if (dpp_curves
[i
].jwk_crv
&&
1110 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1111 return &dpp_curves
[i
];
1117 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1118 const u8
*privkey
, size_t privkey_len
)
1122 const EC_GROUP
*group
;
1125 pkey
= EVP_PKEY_new();
1128 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1130 wpa_printf(MSG_INFO
,
1131 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1132 ERR_error_string(ERR_get_error(), NULL
));
1133 EVP_PKEY_free(pkey
);
1136 group
= EC_KEY_get0_group(eckey
);
1139 EVP_PKEY_free(pkey
);
1142 nid
= EC_GROUP_get_curve_name(group
);
1143 *curve
= dpp_get_curve_nid(nid
);
1145 wpa_printf(MSG_INFO
,
1146 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1149 EVP_PKEY_free(pkey
);
1153 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1155 EVP_PKEY_free(pkey
);
1163 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1164 * as an OID identifying the curve */
1166 /* Compressed format public key per ANSI X9.63 */
1167 ASN1_BIT_STRING
*pub_key
;
1168 } DPP_BOOTSTRAPPING_KEY
;
1170 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1171 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1172 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1173 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1175 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1178 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1180 unsigned char *der
= NULL
;
1183 struct wpabuf
*ret
= NULL
;
1185 const EC_GROUP
*group
;
1186 const EC_POINT
*point
;
1188 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1192 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1196 group
= EC_KEY_get0_group(eckey
);
1197 point
= EC_KEY_get0_public_key(eckey
);
1198 if (!group
|| !point
)
1200 nid
= EC_GROUP_get_curve_name(group
);
1202 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1204 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1205 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1208 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1213 der
= OPENSSL_malloc(len
);
1216 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1219 OPENSSL_free(bootstrap
->pub_key
->data
);
1220 bootstrap
->pub_key
->data
= der
;
1222 bootstrap
->pub_key
->length
= len
;
1223 /* No unused bits */
1224 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1225 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1227 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1229 wpa_printf(MSG_ERROR
,
1230 "DDP: Failed to build DER encoded public key");
1234 ret
= wpabuf_alloc_copy(der
, der_len
);
1236 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1244 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1251 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1254 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1257 addr
[0] = wpabuf_head(der
);
1258 len
[0] = wpabuf_len(der
);
1259 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1261 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1263 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1270 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1271 const u8
*privkey
, size_t privkey_len
)
1273 unsigned char *base64
= NULL
;
1276 struct wpabuf
*der
= NULL
;
1281 bi
->curve
= &dpp_curves
[0];
1283 bi
->curve
= dpp_get_curve_name(curve
);
1285 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1291 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1293 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1298 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1301 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1304 addr
[0] = wpabuf_head(der
);
1305 len
= wpabuf_len(der
);
1306 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1308 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1310 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1313 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1318 pos
= (char *) base64
;
1321 pos
= os_strchr(pos
, '\n');
1324 os_memmove(pos
, pos
+ 1, end
- pos
);
1326 return (char *) base64
;
1334 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1335 unsigned int hash_len
)
1337 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1338 const char *info
= "first intermediate key";
1341 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1343 /* HKDF-Extract(<>, M.x) */
1344 os_memset(salt
, 0, hash_len
);
1345 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1347 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1350 /* HKDF-Expand(PRK, info, L) */
1351 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1352 os_memset(prk
, 0, hash_len
);
1356 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1362 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1363 unsigned int hash_len
)
1365 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1366 const char *info
= "second intermediate key";
1369 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1371 /* HKDF-Extract(<>, N.x) */
1372 os_memset(salt
, 0, hash_len
);
1373 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1376 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1379 /* HKDF-Expand(PRK, info, L) */
1380 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1381 os_memset(prk
, 0, hash_len
);
1385 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1391 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1392 unsigned int hash_len
)
1395 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1396 const char *info_ke
= "DPP Key";
1397 u8 prk
[DPP_MAX_HASH_LEN
];
1401 size_t num_elem
= 0;
1403 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1405 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1406 nonce_len
= auth
->curve
->nonce_len
;
1407 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1408 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1409 addr
[num_elem
] = auth
->Mx
;
1410 len
[num_elem
] = auth
->secret_len
;
1412 addr
[num_elem
] = auth
->Nx
;
1413 len
[num_elem
] = auth
->secret_len
;
1415 if (auth
->peer_bi
&& auth
->own_bi
) {
1416 addr
[num_elem
] = auth
->Lx
;
1417 len
[num_elem
] = auth
->secret_len
;
1420 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1421 num_elem
, addr
, len
, prk
);
1424 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1427 /* HKDF-Expand(PRK, info, L) */
1428 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1429 os_memset(prk
, 0, hash_len
);
1433 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1439 static void dpp_build_attr_status(struct wpabuf
*msg
,
1440 enum dpp_status_error status
)
1442 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1443 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1444 wpabuf_put_le16(msg
, 1);
1445 wpabuf_put_u8(msg
, status
);
1449 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1453 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1454 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1455 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1456 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1461 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1465 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1466 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1467 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1468 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1473 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1474 const struct wpabuf
*pi
,
1476 const u8
*r_pubkey_hash
,
1477 const u8
*i_pubkey_hash
,
1478 unsigned int neg_freq
)
1481 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1482 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1485 size_t len
[2], siv_len
, attr_len
;
1486 u8
*attr_start
, *attr_end
;
1488 /* Build DPP Authentication Request frame attributes */
1489 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1490 4 + sizeof(wrapped_data
);
1493 #ifdef CONFIG_TESTING_OPTIONS
1494 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1496 #endif /* CONFIG_TESTING_OPTIONS */
1497 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1501 attr_start
= wpabuf_put(msg
, 0);
1503 /* Responder Bootstrapping Key Hash */
1504 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1506 /* Initiator Bootstrapping Key Hash */
1507 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1509 /* Initiator Protocol Key */
1511 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1512 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1513 wpabuf_put_buf(msg
, pi
);
1518 u8 op_class
, channel
;
1520 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1522 NUM_HOSTAPD_MODES
) {
1523 wpa_printf(MSG_INFO
,
1524 "DPP: Unsupported negotiation frequency request: %d",
1529 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1530 wpabuf_put_le16(msg
, 2);
1531 wpabuf_put_u8(msg
, op_class
);
1532 wpabuf_put_u8(msg
, channel
);
1535 #ifdef CONFIG_TESTING_OPTIONS
1536 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1537 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1538 goto skip_wrapped_data
;
1540 #endif /* CONFIG_TESTING_OPTIONS */
1542 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1545 #ifdef CONFIG_TESTING_OPTIONS
1546 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1547 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1550 #endif /* CONFIG_TESTING_OPTIONS */
1553 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1555 WPA_PUT_LE16(pos
, nonce_len
);
1557 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1560 #ifdef CONFIG_TESTING_OPTIONS
1562 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1563 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1566 #endif /* CONFIG_TESTING_OPTIONS */
1568 /* I-capabilities */
1569 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1571 WPA_PUT_LE16(pos
, 1);
1573 auth
->i_capab
= auth
->allowed_roles
;
1574 *pos
++ = auth
->i_capab
;
1575 #ifdef CONFIG_TESTING_OPTIONS
1576 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1577 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1581 #endif /* CONFIG_TESTING_OPTIONS */
1583 attr_end
= wpabuf_put(msg
, 0);
1585 /* OUI, OUI type, Crypto Suite, DPP frame type */
1586 addr
[0] = wpabuf_head_u8(msg
) + 2;
1587 len
[0] = 3 + 1 + 1 + 1;
1588 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1590 /* Attributes before Wrapped Data */
1591 addr
[1] = attr_start
;
1592 len
[1] = attr_end
- attr_start
;
1593 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1595 siv_len
= pos
- clear
;
1596 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1597 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1598 2, addr
, len
, wrapped_data
) < 0) {
1602 siv_len
+= AES_BLOCK_SIZE
;
1603 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1604 wrapped_data
, siv_len
);
1606 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1607 wpabuf_put_le16(msg
, siv_len
);
1608 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1610 #ifdef CONFIG_TESTING_OPTIONS
1611 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1612 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1613 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1616 #endif /* CONFIG_TESTING_OPTIONS */
1618 wpa_hexdump_buf(MSG_DEBUG
,
1619 "DPP: Authentication Request frame attributes", msg
);
1625 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1626 enum dpp_status_error status
,
1627 const struct wpabuf
*pr
,
1629 const u8
*r_pubkey_hash
,
1630 const u8
*i_pubkey_hash
,
1631 const u8
*r_nonce
, const u8
*i_nonce
,
1632 const u8
*wrapped_r_auth
,
1633 size_t wrapped_r_auth_len
,
1637 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1638 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1639 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1640 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1642 size_t len
[2], siv_len
, attr_len
;
1643 u8
*attr_start
, *attr_end
, *pos
;
1645 auth
->waiting_auth_conf
= 1;
1646 auth
->auth_resp_tries
= 0;
1648 /* Build DPP Authentication Response frame attributes */
1649 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1650 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1651 #ifdef CONFIG_TESTING_OPTIONS
1652 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1654 #endif /* CONFIG_TESTING_OPTIONS */
1655 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1659 attr_start
= wpabuf_put(msg
, 0);
1663 dpp_build_attr_status(msg
, status
);
1665 /* Responder Bootstrapping Key Hash */
1666 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1668 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1669 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1671 /* Responder Protocol Key */
1673 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1674 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1675 wpabuf_put_buf(msg
, pr
);
1678 attr_end
= wpabuf_put(msg
, 0);
1680 #ifdef CONFIG_TESTING_OPTIONS
1681 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1682 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1683 goto skip_wrapped_data
;
1685 #endif /* CONFIG_TESTING_OPTIONS */
1687 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1692 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1694 WPA_PUT_LE16(pos
, nonce_len
);
1696 os_memcpy(pos
, r_nonce
, nonce_len
);
1702 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1704 WPA_PUT_LE16(pos
, nonce_len
);
1706 os_memcpy(pos
, i_nonce
, nonce_len
);
1707 #ifdef CONFIG_TESTING_OPTIONS
1708 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1709 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1710 pos
[nonce_len
/ 2] ^= 0x01;
1712 #endif /* CONFIG_TESTING_OPTIONS */
1716 #ifdef CONFIG_TESTING_OPTIONS
1717 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1718 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1721 #endif /* CONFIG_TESTING_OPTIONS */
1723 /* R-capabilities */
1724 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1726 WPA_PUT_LE16(pos
, 1);
1728 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1730 *pos
++ = auth
->r_capab
;
1731 #ifdef CONFIG_TESTING_OPTIONS
1732 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1733 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1735 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1736 wpa_printf(MSG_INFO
,
1737 "DPP: TESTING - incompatible R-capabilities");
1738 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1739 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1742 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1743 DPP_CAPAB_CONFIGURATOR
;
1746 #endif /* CONFIG_TESTING_OPTIONS */
1748 if (wrapped_r_auth
) {
1750 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1752 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1754 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1755 pos
+= wrapped_r_auth_len
;
1758 /* OUI, OUI type, Crypto Suite, DPP frame type */
1759 addr
[0] = wpabuf_head_u8(msg
) + 2;
1760 len
[0] = 3 + 1 + 1 + 1;
1761 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1763 /* Attributes before Wrapped Data */
1764 addr
[1] = attr_start
;
1765 len
[1] = attr_end
- attr_start
;
1766 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1768 siv_len
= pos
- clear
;
1769 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1770 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1771 2, addr
, len
, wrapped_data
) < 0) {
1775 siv_len
+= AES_BLOCK_SIZE
;
1776 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1777 wrapped_data
, siv_len
);
1779 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1780 wpabuf_put_le16(msg
, siv_len
);
1781 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1783 #ifdef CONFIG_TESTING_OPTIONS
1784 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1785 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1786 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1789 #endif /* CONFIG_TESTING_OPTIONS */
1791 wpa_hexdump_buf(MSG_DEBUG
,
1792 "DPP: Authentication Response frame attributes", msg
);
1797 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1798 u16 num_modes
, unsigned int freq
)
1803 if (!own_modes
|| !num_modes
)
1806 for (m
= 0; m
< num_modes
; m
++) {
1807 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1808 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1811 flag
= own_modes
[m
].channels
[c
].flag
;
1812 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1813 HOSTAPD_CHAN_NO_IR
|
1814 HOSTAPD_CHAN_RADAR
)))
1819 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1824 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1828 if (freqs
[--num
] == freq
)
1835 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1840 for (i
= 0; i
< num
; i
++) {
1841 if (freqs
[i
] == freq
)
1844 if (i
== 0 || i
>= num
)
1846 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1851 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1852 struct hostapd_hw_modes
*own_modes
,
1855 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1856 unsigned int i
, freq
;
1858 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
1859 freq
= peer_bi
->freq
[i
];
1860 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1862 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
1863 auth
->freq
[auth
->num_freq
++] = freq
;
1865 if (!auth
->num_freq
) {
1866 wpa_printf(MSG_INFO
,
1867 "DPP: No available channels for initiating DPP Authentication");
1870 auth
->curr_freq
= auth
->freq
[0];
1875 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
1876 struct hostapd_hw_modes
*own_modes
,
1885 if (!own_modes
|| !num_modes
) {
1886 auth
->freq
[0] = 2412;
1887 auth
->freq
[1] = 2437;
1888 auth
->freq
[2] = 2462;
1893 for (m
= 0; m
< num_modes
; m
++) {
1894 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1895 freq
= own_modes
[m
].channels
[c
].freq
;
1896 flag
= own_modes
[m
].channels
[c
].flag
;
1897 if (flag
& (HOSTAPD_CHAN_DISABLED
|
1898 HOSTAPD_CHAN_NO_IR
|
1899 HOSTAPD_CHAN_RADAR
))
1901 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1903 auth
->freq
[auth
->num_freq
++] = freq
;
1904 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
1911 return auth
->num_freq
== 0 ? -1 : 0;
1915 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
1916 struct hostapd_hw_modes
*own_modes
,
1920 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
1923 if (auth
->peer_bi
->num_freq
> 0)
1924 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
1926 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
1930 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1931 * likely channels first. */
1932 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
1933 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
1934 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
1937 auth
->curr_freq
= auth
->freq
[0];
1940 end
= pos
+ sizeof(freqs
);
1941 for (i
= 0; i
< auth
->num_freq
; i
++) {
1942 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
1943 if (os_snprintf_error(end
- pos
, res
))
1948 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
1955 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
1956 struct dpp_bootstrap_info
*peer_bi
,
1957 struct dpp_bootstrap_info
*own_bi
,
1958 u8 dpp_allowed_roles
,
1959 unsigned int neg_freq
,
1960 struct hostapd_hw_modes
*own_modes
,
1963 struct dpp_authentication
*auth
;
1965 EVP_PKEY_CTX
*ctx
= NULL
;
1967 struct wpabuf
*pi
= NULL
;
1968 u8 zero
[SHA256_MAC_LEN
];
1969 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
1970 #ifdef CONFIG_TESTING_OPTIONS
1971 u8 test_hash
[SHA256_MAC_LEN
];
1972 #endif /* CONFIG_TESTING_OPTIONS */
1974 auth
= os_zalloc(sizeof(*auth
));
1977 auth
->msg_ctx
= msg_ctx
;
1978 auth
->initiator
= 1;
1979 auth
->waiting_auth_resp
= 1;
1980 auth
->allowed_roles
= dpp_allowed_roles
;
1981 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
1982 auth
->peer_bi
= peer_bi
;
1983 auth
->own_bi
= own_bi
;
1984 auth
->curve
= peer_bi
->curve
;
1986 if (dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
1989 nonce_len
= auth
->curve
->nonce_len
;
1990 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
1991 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
1994 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
1996 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
1997 if (!auth
->own_protocol_key
)
2000 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2004 /* ECDH: M = pI * BR */
2005 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2007 EVP_PKEY_derive_init(ctx
) != 1 ||
2008 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
2009 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2010 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2011 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2012 wpa_printf(MSG_ERROR
,
2013 "DPP: Failed to derive ECDH shared secret: %s",
2014 ERR_error_string(ERR_get_error(), NULL
));
2017 auth
->secret_len
= secret_len
;
2018 EVP_PKEY_CTX_free(ctx
);
2021 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2022 auth
->Mx
, auth
->secret_len
);
2024 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2025 auth
->curve
->hash_len
) < 0)
2028 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2031 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2033 os_memset(zero
, 0, SHA256_MAC_LEN
);
2034 i_pubkey_hash
= zero
;
2037 #ifdef CONFIG_TESTING_OPTIONS
2038 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2039 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2040 r_pubkey_hash
= NULL
;
2041 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2042 wpa_printf(MSG_INFO
,
2043 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2044 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2045 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2046 r_pubkey_hash
= test_hash
;
2047 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2048 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2049 i_pubkey_hash
= NULL
;
2050 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2051 wpa_printf(MSG_INFO
,
2052 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2053 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2054 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2055 i_pubkey_hash
= test_hash
;
2056 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2057 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2060 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2061 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2063 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2064 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2067 #endif /* CONFIG_TESTING_OPTIONS */
2069 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2070 i_pubkey_hash
, neg_freq
);
2076 EVP_PKEY_CTX_free(ctx
);
2079 dpp_auth_deinit(auth
);
2085 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2089 size_t json_len
, clear_len
;
2090 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2094 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2096 nonce_len
= auth
->curve
->nonce_len
;
2097 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2098 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2101 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2102 json_len
= os_strlen(json
);
2103 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
2105 /* { E-nonce, configAttrib }ke */
2106 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2107 clear
= wpabuf_alloc(clear_len
);
2108 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2109 #ifdef CONFIG_TESTING_OPTIONS
2110 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2112 #endif /* CONFIG_TESTING_OPTIONS */
2113 msg
= wpabuf_alloc(attr_len
);
2117 #ifdef CONFIG_TESTING_OPTIONS
2118 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2119 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2122 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2123 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2124 goto skip_wrapped_data
;
2126 #endif /* CONFIG_TESTING_OPTIONS */
2129 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2130 wpabuf_put_le16(clear
, nonce_len
);
2131 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2133 #ifdef CONFIG_TESTING_OPTIONS
2135 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2136 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2137 goto skip_conf_attr_obj
;
2139 #endif /* CONFIG_TESTING_OPTIONS */
2142 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2143 wpabuf_put_le16(clear
, json_len
);
2144 wpabuf_put_data(clear
, json
, json_len
);
2146 #ifdef CONFIG_TESTING_OPTIONS
2148 #endif /* CONFIG_TESTING_OPTIONS */
2150 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2151 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2152 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2155 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2156 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2157 wpabuf_head(clear
), wpabuf_len(clear
),
2158 0, NULL
, NULL
, wrapped
) < 0)
2160 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2161 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2163 #ifdef CONFIG_TESTING_OPTIONS
2164 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2165 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2166 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2169 #endif /* CONFIG_TESTING_OPTIONS */
2171 wpa_hexdump_buf(MSG_DEBUG
,
2172 "DPP: Configuration Request frame attributes", msg
);
2183 static void dpp_auth_success(struct dpp_authentication
*auth
)
2185 wpa_printf(MSG_DEBUG
,
2186 "DPP: Authentication success - clear temporary keys");
2187 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2188 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2189 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2190 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2191 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2193 auth
->auth_success
= 1;
2197 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2199 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2202 size_t i
, num_elem
= 0;
2207 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2208 nonce_len
= auth
->curve
->nonce_len
;
2210 if (auth
->initiator
) {
2211 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2212 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2214 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2217 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2219 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2220 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2222 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2225 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2227 if (!pix
|| !prx
|| !brx
)
2230 addr
[num_elem
] = auth
->i_nonce
;
2231 len
[num_elem
] = nonce_len
;
2234 addr
[num_elem
] = auth
->r_nonce
;
2235 len
[num_elem
] = nonce_len
;
2238 addr
[num_elem
] = wpabuf_head(pix
);
2239 len
[num_elem
] = wpabuf_len(pix
) / 2;
2242 addr
[num_elem
] = wpabuf_head(prx
);
2243 len
[num_elem
] = wpabuf_len(prx
) / 2;
2247 addr
[num_elem
] = wpabuf_head(bix
);
2248 len
[num_elem
] = wpabuf_len(bix
) / 2;
2252 addr
[num_elem
] = wpabuf_head(brx
);
2253 len
[num_elem
] = wpabuf_len(brx
) / 2;
2256 addr
[num_elem
] = &zero
;
2260 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2261 for (i
= 0; i
< num_elem
; i
++)
2262 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2263 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2265 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2266 auth
->curve
->hash_len
);
2276 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2278 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2281 size_t i
, num_elem
= 0;
2286 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2287 nonce_len
= auth
->curve
->nonce_len
;
2289 if (auth
->initiator
) {
2290 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2291 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2293 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2298 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2300 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2301 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2303 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2308 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2310 if (!pix
|| !prx
|| !brx
)
2313 addr
[num_elem
] = auth
->r_nonce
;
2314 len
[num_elem
] = nonce_len
;
2317 addr
[num_elem
] = auth
->i_nonce
;
2318 len
[num_elem
] = nonce_len
;
2321 addr
[num_elem
] = wpabuf_head(prx
);
2322 len
[num_elem
] = wpabuf_len(prx
) / 2;
2325 addr
[num_elem
] = wpabuf_head(pix
);
2326 len
[num_elem
] = wpabuf_len(pix
) / 2;
2329 addr
[num_elem
] = wpabuf_head(brx
);
2330 len
[num_elem
] = wpabuf_len(brx
) / 2;
2334 addr
[num_elem
] = wpabuf_head(bix
);
2335 len
[num_elem
] = wpabuf_len(bix
) / 2;
2339 addr
[num_elem
] = &one
;
2343 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2344 for (i
= 0; i
< num_elem
; i
++)
2345 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2346 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2348 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2349 auth
->curve
->hash_len
);
2359 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2361 const EC_GROUP
*group
;
2363 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2364 const EC_POINT
*BI_point
;
2366 BIGNUM
*lx
, *sum
, *q
;
2367 const BIGNUM
*bR_bn
, *pR_bn
;
2370 /* L = ((bR + pR) modulo q) * BI */
2372 bnctx
= BN_CTX_new();
2376 if (!bnctx
|| !sum
|| !q
|| !lx
)
2378 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2381 BI_point
= EC_KEY_get0_public_key(BI
);
2382 group
= EC_KEY_get0_group(BI
);
2386 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2387 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2390 bR_bn
= EC_KEY_get0_private_key(bR
);
2391 pR_bn
= EC_KEY_get0_private_key(pR
);
2392 if (!bR_bn
|| !pR_bn
)
2394 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2395 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2397 l
= EC_POINT_new(group
);
2399 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2400 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2402 wpa_printf(MSG_ERROR
,
2403 "OpenSSL: failed: %s",
2404 ERR_error_string(ERR_get_error(), NULL
));
2408 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2410 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2413 EC_POINT_clear_free(l
);
2425 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2427 const EC_GROUP
*group
;
2428 EC_POINT
*l
= NULL
, *sum
= NULL
;
2429 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2430 const EC_POINT
*BR_point
, *PR_point
;
2433 const BIGNUM
*bI_bn
;
2436 /* L = bI * (BR + PR) */
2438 bnctx
= BN_CTX_new();
2442 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2443 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2446 BR_point
= EC_KEY_get0_public_key(BR
);
2447 PR_point
= EC_KEY_get0_public_key(PR
);
2449 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2452 group
= EC_KEY_get0_group(bI
);
2453 bI_bn
= EC_KEY_get0_private_key(bI
);
2454 if (!group
|| !bI_bn
)
2456 sum
= EC_POINT_new(group
);
2457 l
= EC_POINT_new(group
);
2459 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2460 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2461 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2463 wpa_printf(MSG_ERROR
,
2464 "OpenSSL: failed: %s",
2465 ERR_error_string(ERR_get_error(), NULL
));
2469 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2471 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2474 EC_POINT_clear_free(l
);
2484 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2487 EVP_PKEY_CTX
*ctx
= NULL
;
2489 struct wpabuf
*msg
, *pr
= NULL
;
2490 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2491 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2492 size_t wrapped_r_auth_len
;
2494 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2495 enum dpp_status_error status
= DPP_STATUS_OK
;
2496 #ifdef CONFIG_TESTING_OPTIONS
2497 u8 test_hash
[SHA256_MAC_LEN
];
2498 #endif /* CONFIG_TESTING_OPTIONS */
2500 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2504 nonce_len
= auth
->curve
->nonce_len
;
2505 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2506 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2509 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2511 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2512 if (!auth
->own_protocol_key
)
2515 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2519 /* ECDH: N = pR * PI */
2520 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2522 EVP_PKEY_derive_init(ctx
) != 1 ||
2523 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2524 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2525 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2526 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2527 wpa_printf(MSG_ERROR
,
2528 "DPP: Failed to derive ECDH shared secret: %s",
2529 ERR_error_string(ERR_get_error(), NULL
));
2532 EVP_PKEY_CTX_free(ctx
);
2535 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2536 auth
->Nx
, auth
->secret_len
);
2538 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2539 auth
->curve
->hash_len
) < 0)
2542 if (auth
->own_bi
&& auth
->peer_bi
) {
2543 /* Mutual authentication */
2544 if (dpp_auth_derive_l_responder(auth
) < 0)
2548 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2551 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2552 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2553 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2554 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2556 #ifdef CONFIG_TESTING_OPTIONS
2557 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2558 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2559 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2561 #endif /* CONFIG_TESTING_OPTIONS */
2562 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2563 r_auth
, 4 + auth
->curve
->hash_len
,
2564 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2566 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2567 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2568 wrapped_r_auth
, wrapped_r_auth_len
);
2569 w_r_auth
= wrapped_r_auth
;
2571 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2573 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2575 i_pubkey_hash
= NULL
;
2577 i_nonce
= auth
->i_nonce
;
2578 r_nonce
= auth
->r_nonce
;
2580 #ifdef CONFIG_TESTING_OPTIONS
2581 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2582 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2583 r_pubkey_hash
= NULL
;
2584 } else if (dpp_test
==
2585 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2586 wpa_printf(MSG_INFO
,
2587 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2588 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2589 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2590 r_pubkey_hash
= test_hash
;
2591 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2592 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2593 i_pubkey_hash
= NULL
;
2594 } else if (dpp_test
==
2595 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2596 wpa_printf(MSG_INFO
,
2597 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2599 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2601 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2602 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2603 i_pubkey_hash
= test_hash
;
2604 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2605 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2608 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
2609 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
2611 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2612 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
2614 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2615 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2617 wrapped_r_auth_len
= 0;
2618 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2619 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2621 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
2622 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
2624 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2625 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2627 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2628 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2631 #endif /* CONFIG_TESTING_OPTIONS */
2633 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2634 r_pubkey_hash
, i_pubkey_hash
,
2636 w_r_auth
, wrapped_r_auth_len
,
2640 wpabuf_free(auth
->resp_msg
);
2641 auth
->resp_msg
= msg
;
2649 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2650 enum dpp_status_error status
)
2653 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2654 #ifdef CONFIG_TESTING_OPTIONS
2655 u8 test_hash
[SHA256_MAC_LEN
];
2656 #endif /* CONFIG_TESTING_OPTIONS */
2660 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2662 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2664 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2666 i_pubkey_hash
= NULL
;
2668 i_nonce
= auth
->i_nonce
;
2670 #ifdef CONFIG_TESTING_OPTIONS
2671 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2672 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2673 r_pubkey_hash
= NULL
;
2674 } else if (dpp_test
==
2675 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2676 wpa_printf(MSG_INFO
,
2677 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2678 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2679 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2680 r_pubkey_hash
= test_hash
;
2681 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2682 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2683 i_pubkey_hash
= NULL
;
2684 } else if (dpp_test
==
2685 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2686 wpa_printf(MSG_INFO
,
2687 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2689 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2691 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2692 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2693 i_pubkey_hash
= test_hash
;
2694 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2695 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2697 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2698 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2701 #endif /* CONFIG_TESTING_OPTIONS */
2703 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
2704 r_pubkey_hash
, i_pubkey_hash
,
2705 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
2708 wpabuf_free(auth
->resp_msg
);
2709 auth
->resp_msg
= msg
;
2714 struct dpp_authentication
*
2715 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
2716 struct dpp_bootstrap_info
*peer_bi
,
2717 struct dpp_bootstrap_info
*own_bi
,
2718 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
2721 EVP_PKEY
*pi
= NULL
;
2722 EVP_PKEY_CTX
*ctx
= NULL
;
2726 u8
*unwrapped
= NULL
;
2727 size_t unwrapped_len
= 0;
2728 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
2730 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
2731 i_bootstrap_len
, channel_len
;
2732 struct dpp_authentication
*auth
= NULL
;
2734 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2736 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
2737 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
2738 "Missing or invalid required Wrapped Data attribute");
2741 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
2742 wrapped_data
, wrapped_data_len
);
2743 attr_len
= wrapped_data
- 4 - attr_start
;
2745 auth
= os_zalloc(sizeof(*auth
));
2748 auth
->msg_ctx
= msg_ctx
;
2749 auth
->peer_bi
= peer_bi
;
2750 auth
->own_bi
= own_bi
;
2751 auth
->curve
= own_bi
->curve
;
2752 auth
->curr_freq
= freq
;
2754 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
2759 if (channel_len
< 2) {
2760 dpp_auth_fail(auth
, "Too short Channel attribute");
2764 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
2765 wpa_printf(MSG_DEBUG
,
2766 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2767 channel
[0], channel
[1], neg_freq
);
2770 "Unsupported Channel attribute value");
2774 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
2775 wpa_printf(MSG_DEBUG
,
2776 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2778 auth
->curr_freq
= neg_freq
;
2782 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
2786 "Missing required Initiator Protocol Key attribute");
2789 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
2790 i_proto
, i_proto_len
);
2793 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
2795 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
2798 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
2800 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
2802 EVP_PKEY_derive_init(ctx
) != 1 ||
2803 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
2804 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2805 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2806 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2807 wpa_printf(MSG_ERROR
,
2808 "DPP: Failed to derive ECDH shared secret: %s",
2809 ERR_error_string(ERR_get_error(), NULL
));
2810 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
2813 auth
->secret_len
= secret_len
;
2814 EVP_PKEY_CTX_free(ctx
);
2817 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2818 auth
->Mx
, auth
->secret_len
);
2820 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2821 auth
->curve
->hash_len
) < 0)
2825 len
[0] = DPP_HDR_LEN
;
2826 addr
[1] = attr_start
;
2828 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2829 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2830 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2831 wrapped_data
, wrapped_data_len
);
2832 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2833 unwrapped
= os_malloc(unwrapped_len
);
2836 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
2837 wrapped_data
, wrapped_data_len
,
2838 2, addr
, len
, unwrapped
) < 0) {
2839 dpp_auth_fail(auth
, "AES-SIV decryption failed");
2842 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2843 unwrapped
, unwrapped_len
);
2845 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
2846 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
2850 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
2852 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
2853 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
2856 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
2857 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
2859 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
2860 DPP_ATTR_I_CAPABILITIES
,
2862 if (!i_capab
|| i_capab_len
< 1) {
2863 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
2866 auth
->i_capab
= i_capab
[0];
2867 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
2869 bin_clear_free(unwrapped
, unwrapped_len
);
2872 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
2873 case DPP_CAPAB_ENROLLEE
:
2874 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
2875 wpa_printf(MSG_DEBUG
,
2876 "DPP: Local policy does not allow Configurator role");
2877 goto not_compatible
;
2879 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
2880 auth
->configurator
= 1;
2882 case DPP_CAPAB_CONFIGURATOR
:
2883 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
2884 wpa_printf(MSG_DEBUG
,
2885 "DPP: Local policy does not allow Enrollee role");
2886 goto not_compatible
;
2888 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
2889 auth
->configurator
= 0;
2891 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
2892 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
2893 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
2894 auth
->configurator
= 0;
2895 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
2896 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
2897 auth
->configurator
= 1;
2899 wpa_printf(MSG_DEBUG
,
2900 "DPP: Local policy does not allow Configurator/Enrollee role");
2901 goto not_compatible
;
2905 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
2906 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
2907 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
2908 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
2912 auth
->peer_protocol_key
= pi
;
2914 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
2915 char hex
[SHA256_MAC_LEN
* 2 + 1];
2917 wpa_printf(MSG_DEBUG
,
2918 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2919 if (dpp_auth_build_resp_status(auth
,
2920 DPP_STATUS_RESPONSE_PENDING
) < 0)
2922 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2923 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
2925 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
2926 auth
->response_pending
= 1;
2927 os_memcpy(auth
->waiting_pubkey_hash
,
2928 i_bootstrap
, i_bootstrap_len
);
2929 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
2935 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
2939 if (dpp_auth_build_resp_ok(auth
) < 0)
2945 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
2946 "i-capab=0x%02x", auth
->i_capab
);
2947 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
2948 auth
->configurator
= 1;
2950 auth
->configurator
= 0;
2951 auth
->peer_protocol_key
= pi
;
2953 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
2956 auth
->remove_on_tx_status
= 1;
2959 bin_clear_free(unwrapped
, unwrapped_len
);
2961 EVP_PKEY_CTX_free(ctx
);
2962 dpp_auth_deinit(auth
);
2967 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
2968 struct dpp_bootstrap_info
*peer_bi
)
2970 if (!auth
|| !auth
->response_pending
||
2971 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
2972 SHA256_MAC_LEN
) != 0)
2975 wpa_printf(MSG_DEBUG
,
2976 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2977 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
2978 auth
->peer_bi
= peer_bi
;
2980 if (dpp_auth_build_resp_ok(auth
) < 0)
2987 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
2988 enum dpp_status_error status
)
2991 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
2993 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
2996 size_t len
[2], attr_len
;
2998 u8
*wrapped_r_nonce
;
2999 u8
*attr_start
, *attr_end
;
3000 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3001 #ifdef CONFIG_TESTING_OPTIONS
3002 u8 test_hash
[SHA256_MAC_LEN
];
3003 #endif /* CONFIG_TESTING_OPTIONS */
3005 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3007 i_auth_len
= 4 + auth
->curve
->hash_len
;
3008 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3009 /* Build DPP Authentication Confirmation frame attributes */
3010 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3011 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3012 #ifdef CONFIG_TESTING_OPTIONS
3013 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3015 #endif /* CONFIG_TESTING_OPTIONS */
3016 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3020 attr_start
= wpabuf_put(msg
, 0);
3022 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3024 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3026 i_pubkey_hash
= NULL
;
3028 #ifdef CONFIG_TESTING_OPTIONS
3029 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3030 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3032 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3033 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3036 #endif /* CONFIG_TESTING_OPTIONS */
3039 dpp_build_attr_status(msg
, status
);
3041 #ifdef CONFIG_TESTING_OPTIONS
3043 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3044 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3045 r_pubkey_hash
= NULL
;
3046 } else if (dpp_test
==
3047 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3048 wpa_printf(MSG_INFO
,
3049 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3050 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3051 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3052 r_pubkey_hash
= test_hash
;
3053 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3054 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3055 i_pubkey_hash
= NULL
;
3056 } else if (dpp_test
==
3057 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3058 wpa_printf(MSG_INFO
,
3059 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3061 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3063 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3064 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3065 i_pubkey_hash
= test_hash
;
3067 #endif /* CONFIG_TESTING_OPTIONS */
3069 /* Responder Bootstrapping Key Hash */
3070 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3072 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3073 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3075 #ifdef CONFIG_TESTING_OPTIONS
3076 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3077 goto skip_wrapped_data
;
3078 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3080 #endif /* CONFIG_TESTING_OPTIONS */
3082 attr_end
= wpabuf_put(msg
, 0);
3084 /* OUI, OUI type, Crypto Suite, DPP frame type */
3085 addr
[0] = wpabuf_head_u8(msg
) + 2;
3086 len
[0] = 3 + 1 + 1 + 1;
3087 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3089 /* Attributes before Wrapped Data */
3090 addr
[1] = attr_start
;
3091 len
[1] = attr_end
- attr_start
;
3092 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3094 if (status
== DPP_STATUS_OK
) {
3095 /* I-auth wrapped with ke */
3096 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3097 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3098 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3100 #ifdef CONFIG_TESTING_OPTIONS
3101 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3103 #endif /* CONFIG_TESTING_OPTIONS */
3105 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3107 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3108 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3109 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3112 #ifdef CONFIG_TESTING_OPTIONS
3113 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3114 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3115 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3118 #endif /* CONFIG_TESTING_OPTIONS */
3119 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3121 2, addr
, len
, wrapped_i_auth
) < 0)
3123 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3124 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3126 /* R-nonce wrapped with k2 */
3127 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3128 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3129 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3131 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3132 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3133 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3135 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3136 r_nonce
, r_nonce_len
,
3137 2, addr
, len
, wrapped_r_nonce
) < 0)
3139 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3140 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3143 #ifdef CONFIG_TESTING_OPTIONS
3144 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3145 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3146 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3149 #endif /* CONFIG_TESTING_OPTIONS */
3151 wpa_hexdump_buf(MSG_DEBUG
,
3152 "DPP: Authentication Confirmation frame attributes",
3154 if (status
== DPP_STATUS_OK
)
3155 dpp_auth_success(auth
);
3165 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3166 const u8
*attr_start
, size_t attr_len
,
3167 const u8
*wrapped_data
, u16 wrapped_data_len
,
3168 enum dpp_status_error status
)
3172 u8
*unwrapped
= NULL
;
3173 size_t unwrapped_len
= 0;
3174 const u8
*i_nonce
, *r_capab
;
3175 u16 i_nonce_len
, r_capab_len
;
3177 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3178 wpa_printf(MSG_DEBUG
,
3179 "DPP: Responder reported incompatible roles");
3180 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3181 wpa_printf(MSG_DEBUG
,
3182 "DPP: Responder reported more time needed");
3184 wpa_printf(MSG_DEBUG
,
3185 "DPP: Responder reported failure (status %d)",
3187 dpp_auth_fail(auth
, "Responder reported failure");
3192 len
[0] = DPP_HDR_LEN
;
3193 addr
[1] = attr_start
;
3195 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3196 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3197 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3198 wrapped_data
, wrapped_data_len
);
3199 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3200 unwrapped
= os_malloc(unwrapped_len
);
3203 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3204 wrapped_data
, wrapped_data_len
,
3205 2, addr
, len
, unwrapped
) < 0) {
3206 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3209 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3210 unwrapped
, unwrapped_len
);
3212 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3213 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3217 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3219 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3220 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3223 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3224 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3225 dpp_auth_fail(auth
, "I-nonce mismatch");
3229 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3230 DPP_ATTR_R_CAPABILITIES
,
3232 if (!r_capab
|| r_capab_len
< 1) {
3233 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3236 auth
->r_capab
= r_capab
[0];
3237 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3238 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3239 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3240 "r-capab=0x%02x", auth
->r_capab
);
3241 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3242 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3244 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3245 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3246 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3247 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3250 wpa_printf(MSG_DEBUG
,
3251 "DPP: Continue waiting for full DPP Authentication Response");
3252 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_RESPONSE_PENDING
);
3256 bin_clear_free(unwrapped
, unwrapped_len
);
3261 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3262 const u8
*attr_start
, size_t attr_len
)
3265 EVP_PKEY_CTX
*ctx
= NULL
;
3269 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3270 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3271 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3272 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3273 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3274 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3275 wrapped2_len
, r_auth_len
;
3276 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3279 if (!auth
->initiator
) {
3280 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3284 auth
->waiting_auth_resp
= 0;
3286 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3288 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3290 "Missing or invalid required Wrapped Data attribute");
3293 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3294 wrapped_data
, wrapped_data_len
);
3296 attr_len
= wrapped_data
- 4 - attr_start
;
3298 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3299 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3301 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3303 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3306 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3307 r_bootstrap
, r_bootstrap_len
);
3308 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3309 SHA256_MAC_LEN
) != 0) {
3311 "Unexpected Responder Bootstrapping Key Hash value");
3312 wpa_hexdump(MSG_DEBUG
,
3313 "DPP: Expected Responder Bootstrapping Key Hash",
3314 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3318 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3319 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3322 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3324 "Invalid Initiator Bootstrapping Key Hash attribute");
3327 wpa_hexdump(MSG_MSGDUMP
,
3328 "DPP: Initiator Bootstrapping Key Hash",
3329 i_bootstrap
, i_bootstrap_len
);
3330 if (!auth
->own_bi
||
3331 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3332 SHA256_MAC_LEN
) != 0) {
3334 "Initiator Bootstrapping Key Hash attribute did not match");
3337 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3338 /* PKEX bootstrapping mandates use of mutual authentication */
3340 "Missing Initiator Bootstrapping Key Hash attribute");
3344 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3346 if (!status
|| status_len
< 1) {
3348 "Missing or invalid required DPP Status attribute");
3351 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3352 auth
->auth_resp_status
= status
[0];
3353 if (status
[0] != DPP_STATUS_OK
) {
3354 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3355 attr_len
, wrapped_data
,
3356 wrapped_data_len
, status
[0]);
3360 if (!i_bootstrap
&& auth
->own_bi
) {
3361 wpa_printf(MSG_DEBUG
,
3362 "DPP: Responder decided not to use mutual authentication");
3363 auth
->own_bi
= NULL
;
3366 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3370 "Missing required Responder Protocol Key attribute");
3373 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3374 r_proto
, r_proto_len
);
3377 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3379 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3382 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3384 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3386 EVP_PKEY_derive_init(ctx
) != 1 ||
3387 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3388 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3389 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3390 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3391 wpa_printf(MSG_ERROR
,
3392 "DPP: Failed to derive ECDH shared secret: %s",
3393 ERR_error_string(ERR_get_error(), NULL
));
3394 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3397 EVP_PKEY_CTX_free(ctx
);
3399 auth
->peer_protocol_key
= pr
;
3402 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3403 auth
->Nx
, auth
->secret_len
);
3405 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3406 auth
->curve
->hash_len
) < 0)
3410 len
[0] = DPP_HDR_LEN
;
3411 addr
[1] = attr_start
;
3413 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3414 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3415 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3416 wrapped_data
, wrapped_data_len
);
3417 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3418 unwrapped
= os_malloc(unwrapped_len
);
3421 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3422 wrapped_data
, wrapped_data_len
,
3423 2, addr
, len
, unwrapped
) < 0) {
3424 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3427 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3428 unwrapped
, unwrapped_len
);
3430 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3431 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3435 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3437 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3438 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3441 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3442 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3444 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3446 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3447 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3450 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3451 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3452 dpp_auth_fail(auth
, "I-nonce mismatch");
3456 if (auth
->own_bi
&& auth
->peer_bi
) {
3457 /* Mutual authentication */
3458 if (dpp_auth_derive_l_initiator(auth
) < 0)
3462 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3463 DPP_ATTR_R_CAPABILITIES
,
3465 if (!r_capab
|| r_capab_len
< 1) {
3466 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3469 auth
->r_capab
= r_capab
[0];
3470 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3471 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3472 if ((auth
->allowed_roles
==
3473 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3474 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3475 /* Peer selected its role, so move from "either role" to the
3476 * role that is compatible with peer's selection. */
3477 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3478 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3479 auth
->configurator
? "Configurator" : "Enrollee");
3480 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3481 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3482 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3483 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3484 "Unexpected role in R-capabilities 0x%02x",
3486 if (role
!= DPP_CAPAB_ENROLLEE
&&
3487 role
!= DPP_CAPAB_CONFIGURATOR
)
3489 bin_clear_free(unwrapped
, unwrapped_len
);
3490 auth
->remove_on_tx_status
= 1;
3491 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3494 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3495 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3496 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3498 "Missing or invalid Secondary Wrapped Data");
3502 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3503 wrapped2
, wrapped2_len
);
3505 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3508 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3509 unwrapped2
= os_malloc(unwrapped2_len
);
3512 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3513 wrapped2
, wrapped2_len
,
3514 0, NULL
, NULL
, unwrapped2
) < 0) {
3515 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3518 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3519 unwrapped2
, unwrapped2_len
);
3521 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3523 "Invalid attribute in secondary unwrapped data");
3527 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3529 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3531 "Missing or invalid Responder Authenticating Tag");
3534 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3535 r_auth
, r_auth_len
);
3536 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3537 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3539 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3540 r_auth2
, r_auth_len
);
3541 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3542 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3543 bin_clear_free(unwrapped
, unwrapped_len
);
3544 bin_clear_free(unwrapped2
, unwrapped2_len
);
3545 auth
->remove_on_tx_status
= 1;
3546 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3549 bin_clear_free(unwrapped
, unwrapped_len
);
3550 bin_clear_free(unwrapped2
, unwrapped2_len
);
3552 #ifdef CONFIG_TESTING_OPTIONS
3553 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
3554 wpa_printf(MSG_INFO
,
3555 "DPP: TESTING - Authentication Response in place of Confirm");
3556 if (dpp_auth_build_resp_ok(auth
) < 0)
3558 return wpabuf_dup(auth
->resp_msg
);
3560 #endif /* CONFIG_TESTING_OPTIONS */
3562 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3565 bin_clear_free(unwrapped
, unwrapped_len
);
3566 bin_clear_free(unwrapped2
, unwrapped2_len
);
3568 EVP_PKEY_CTX_free(ctx
);
3573 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3575 const u8
*attr_start
, size_t attr_len
,
3576 const u8
*wrapped_data
,
3577 u16 wrapped_data_len
,
3578 enum dpp_status_error status
)
3582 u8
*unwrapped
= NULL
;
3583 size_t unwrapped_len
= 0;
3587 /* Authentication Confirm failure cases are expected to include
3588 * {R-nonce}k2 in the Wrapped Data attribute. */
3591 len
[0] = DPP_HDR_LEN
;
3592 addr
[1] = attr_start
;
3594 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3595 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3596 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3597 wrapped_data
, wrapped_data_len
);
3598 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3599 unwrapped
= os_malloc(unwrapped_len
);
3601 dpp_auth_fail(auth
, "Authentication failed");
3604 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3605 wrapped_data
, wrapped_data_len
,
3606 2, addr
, len
, unwrapped
) < 0) {
3607 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3610 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3611 unwrapped
, unwrapped_len
);
3613 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3614 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3618 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3620 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3621 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3624 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3625 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3626 r_nonce
, r_nonce_len
);
3627 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3628 auth
->r_nonce
, r_nonce_len
);
3629 dpp_auth_fail(auth
, "R-nonce mismatch");
3633 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3634 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3635 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3636 dpp_auth_fail(auth
, "Peer reported authentication failure)");
3639 bin_clear_free(unwrapped
, unwrapped_len
);
3644 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3645 const u8
*attr_start
, size_t attr_len
)
3647 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
3648 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3652 u8
*unwrapped
= NULL
;
3653 size_t unwrapped_len
= 0;
3654 u8 i_auth2
[DPP_MAX_HASH_LEN
];
3656 if (auth
->initiator
) {
3657 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
3661 auth
->waiting_auth_conf
= 0;
3663 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3665 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3667 "Missing or invalid required Wrapped Data attribute");
3670 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3671 wrapped_data
, wrapped_data_len
);
3673 attr_len
= wrapped_data
- 4 - attr_start
;
3675 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3676 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3678 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3680 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3683 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3684 r_bootstrap
, r_bootstrap_len
);
3685 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
3686 SHA256_MAC_LEN
) != 0) {
3687 wpa_hexdump(MSG_DEBUG
,
3688 "DPP: Expected Responder Bootstrapping Key Hash",
3689 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3691 "Responder Bootstrapping Key Hash mismatch");
3695 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3696 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3699 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3701 "Invalid Initiator Bootstrapping Key Hash attribute");
3704 wpa_hexdump(MSG_MSGDUMP
,
3705 "DPP: Initiator Bootstrapping Key Hash",
3706 i_bootstrap
, i_bootstrap_len
);
3707 if (!auth
->peer_bi
||
3708 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3709 SHA256_MAC_LEN
) != 0) {
3711 "Initiator Bootstrapping Key Hash mismatch");
3714 } else if (auth
->own_bi
&& auth
->peer_bi
) {
3715 /* Mutual authentication and peer did not include its
3716 * Bootstrapping Key Hash attribute. */
3718 "Missing Initiator Bootstrapping Key Hash attribute");
3722 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3724 if (!status
|| status_len
< 1) {
3726 "Missing or invalid required DPP Status attribute");
3729 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3730 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
3731 status
[0] == DPP_STATUS_AUTH_FAILURE
)
3732 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
3733 attr_len
, wrapped_data
,
3734 wrapped_data_len
, status
[0]);
3736 if (status
[0] != DPP_STATUS_OK
) {
3737 dpp_auth_fail(auth
, "Authentication failed");
3742 len
[0] = DPP_HDR_LEN
;
3743 addr
[1] = attr_start
;
3745 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3746 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3747 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3748 wrapped_data
, wrapped_data_len
);
3749 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3750 unwrapped
= os_malloc(unwrapped_len
);
3753 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3754 wrapped_data
, wrapped_data_len
,
3755 2, addr
, len
, unwrapped
) < 0) {
3756 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3759 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3760 unwrapped
, unwrapped_len
);
3762 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3763 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3767 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
3769 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
3771 "Missing or invalid Initiator Authenticating Tag");
3774 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
3775 i_auth
, i_auth_len
);
3776 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3777 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
3779 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
3780 i_auth2
, i_auth_len
);
3781 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
3782 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
3786 bin_clear_free(unwrapped
, unwrapped_len
);
3787 dpp_auth_success(auth
);
3790 bin_clear_free(unwrapped
, unwrapped_len
);
3795 void dpp_configuration_free(struct dpp_configuration
*conf
)
3799 str_clear_free(conf
->passphrase
);
3800 bin_clear_free(conf
, sizeof(*conf
));
3804 void dpp_auth_deinit(struct dpp_authentication
*auth
)
3808 dpp_configuration_free(auth
->conf_ap
);
3809 dpp_configuration_free(auth
->conf_sta
);
3810 EVP_PKEY_free(auth
->own_protocol_key
);
3811 EVP_PKEY_free(auth
->peer_protocol_key
);
3812 wpabuf_free(auth
->req_msg
);
3813 wpabuf_free(auth
->resp_msg
);
3814 wpabuf_free(auth
->conf_req
);
3815 os_free(auth
->connector
);
3816 wpabuf_free(auth
->net_access_key
);
3817 wpabuf_free(auth
->c_sign_key
);
3818 #ifdef CONFIG_TESTING_OPTIONS
3819 os_free(auth
->config_obj_override
);
3820 os_free(auth
->discovery_override
);
3821 os_free(auth
->groups_override
);
3822 #endif /* CONFIG_TESTING_OPTIONS */
3823 bin_clear_free(auth
, sizeof(*auth
));
3827 static struct wpabuf
*
3828 dpp_build_conf_start(struct dpp_authentication
*auth
,
3829 struct dpp_configuration
*conf
, size_t tailroom
)
3832 char ssid
[6 * sizeof(conf
->ssid
) + 1];
3834 #ifdef CONFIG_TESTING_OPTIONS
3835 if (auth
->discovery_override
)
3836 tailroom
+= os_strlen(auth
->discovery_override
);
3837 #endif /* CONFIG_TESTING_OPTIONS */
3839 buf
= wpabuf_alloc(200 + tailroom
);
3842 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
3843 #ifdef CONFIG_TESTING_OPTIONS
3844 if (auth
->discovery_override
) {
3845 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
3846 auth
->discovery_override
);
3847 wpabuf_put_str(buf
, auth
->discovery_override
);
3848 wpabuf_put_u8(buf
, ',');
3851 #endif /* CONFIG_TESTING_OPTIONS */
3852 wpabuf_put_str(buf
, "{\"ssid\":\"");
3853 json_escape_string(ssid
, sizeof(ssid
),
3854 (const char *) conf
->ssid
, conf
->ssid_len
);
3855 wpabuf_put_str(buf
, ssid
);
3856 wpabuf_put_str(buf
, "\"},");
3862 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
3863 const char *kid
, const struct dpp_curve_params
*curve
)
3867 char *x
= NULL
, *y
= NULL
;
3870 pub
= dpp_get_pubkey_point(key
, 0);
3873 pos
= wpabuf_head(pub
);
3874 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
3875 pos
+= curve
->prime_len
;
3876 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
3880 wpabuf_put_str(buf
, "\"");
3881 wpabuf_put_str(buf
, name
);
3882 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
3883 wpabuf_put_str(buf
, curve
->jwk_crv
);
3884 wpabuf_put_str(buf
, "\",\"x\":\"");
3885 wpabuf_put_str(buf
, x
);
3886 wpabuf_put_str(buf
, "\",\"y\":\"");
3887 wpabuf_put_str(buf
, y
);
3889 wpabuf_put_str(buf
, "\",\"kid\":\"");
3890 wpabuf_put_str(buf
, kid
);
3892 wpabuf_put_str(buf
, "\"}");
3902 static struct wpabuf
*
3903 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
3904 struct dpp_configuration
*conf
)
3906 struct wpabuf
*buf
= NULL
;
3907 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
3909 const struct dpp_curve_params
*curve
;
3910 char jws_prot_hdr
[100];
3911 size_t signed1_len
, signed2_len
, signed3_len
;
3912 struct wpabuf
*dppcon
= NULL
;
3913 unsigned char *signature
= NULL
;
3914 const unsigned char *p
;
3915 size_t signature_len
;
3916 EVP_MD_CTX
*md_ctx
= NULL
;
3917 ECDSA_SIG
*sig
= NULL
;
3919 const EVP_MD
*sign_md
;
3920 const BIGNUM
*r
, *s
;
3921 size_t extra_len
= 1000;
3924 wpa_printf(MSG_INFO
,
3925 "DPP: No configurator specified - cannot generate DPP config object");
3928 curve
= auth
->conf
->curve
;
3929 if (curve
->hash_len
== SHA256_MAC_LEN
) {
3930 sign_md
= EVP_sha256();
3931 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
3932 sign_md
= EVP_sha384();
3933 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
3934 sign_md
= EVP_sha512();
3936 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
3940 #ifdef CONFIG_TESTING_OPTIONS
3941 if (auth
->groups_override
)
3942 extra_len
+= os_strlen(auth
->groups_override
);
3943 #endif /* CONFIG_TESTING_OPTIONS */
3945 /* Connector (JSON dppCon object) */
3946 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
3949 #ifdef CONFIG_TESTING_OPTIONS
3950 if (auth
->groups_override
) {
3951 wpabuf_put_u8(dppcon
, '{');
3952 if (auth
->groups_override
) {
3953 wpa_printf(MSG_DEBUG
,
3954 "DPP: TESTING - groups override: '%s'",
3955 auth
->groups_override
);
3956 wpabuf_put_str(dppcon
, "\"groups\":");
3957 wpabuf_put_str(dppcon
, auth
->groups_override
);
3958 wpabuf_put_u8(dppcon
, ',');
3962 #endif /* CONFIG_TESTING_OPTIONS */
3963 wpabuf_put_str(dppcon
, "{\"groups\":[{\"groupId\":\"*\",");
3964 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
3965 #ifdef CONFIG_TESTING_OPTIONS
3967 #endif /* CONFIG_TESTING_OPTIONS */
3968 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
3970 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
3973 if (conf
->netaccesskey_expiry
) {
3976 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
3977 wpa_printf(MSG_DEBUG
,
3978 "DPP: Failed to generate expiry string");
3981 wpabuf_printf(dppcon
,
3982 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3983 tm
.year
, tm
.month
, tm
.day
,
3984 tm
.hour
, tm
.min
, tm
.sec
);
3986 wpabuf_put_u8(dppcon
, '}');
3987 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
3988 (const char *) wpabuf_head(dppcon
));
3990 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
3991 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
3992 auth
->conf
->kid
, curve
->jws_alg
);
3993 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
3994 os_strlen(jws_prot_hdr
),
3996 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
3999 if (!signed1
|| !signed2
)
4002 md_ctx
= EVP_MD_CTX_create();
4007 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4008 auth
->conf
->csign
) != 1) {
4009 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4010 ERR_error_string(ERR_get_error(), NULL
));
4013 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4014 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4015 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4016 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4017 ERR_error_string(ERR_get_error(), NULL
));
4020 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4021 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4022 ERR_error_string(ERR_get_error(), NULL
));
4025 signature
= os_malloc(signature_len
);
4028 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4029 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4030 ERR_error_string(ERR_get_error(), NULL
));
4033 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4034 signature
, signature_len
);
4035 /* Convert to raw coordinates r,s */
4037 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4040 ECDSA_SIG_get0(sig
, &r
, &s
);
4041 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4042 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4043 curve
->prime_len
) < 0)
4045 signature_len
= 2 * curve
->prime_len
;
4046 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4047 signature
, signature_len
);
4048 signed3
= (char *) base64_url_encode(signature
, signature_len
,
4054 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4055 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4056 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4060 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
4061 wpabuf_put_str(buf
, signed1
);
4062 wpabuf_put_u8(buf
, '.');
4063 wpabuf_put_str(buf
, signed2
);
4064 wpabuf_put_u8(buf
, '.');
4065 wpabuf_put_str(buf
, signed3
);
4066 wpabuf_put_str(buf
, "\",");
4067 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4069 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4073 wpabuf_put_str(buf
, "}}");
4075 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4076 wpabuf_head(buf
), wpabuf_len(buf
));
4079 EVP_MD_CTX_destroy(md_ctx
);
4080 ECDSA_SIG_free(sig
);
4085 wpabuf_free(dppcon
);
4088 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4095 static struct wpabuf
*
4096 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
4097 struct dpp_configuration
*conf
)
4101 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4105 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"psk\",");
4106 if (conf
->passphrase
) {
4107 char pass
[63 * 6 + 1];
4109 if (os_strlen(conf
->passphrase
) > 63) {
4114 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
4115 os_strlen(conf
->passphrase
));
4116 wpabuf_put_str(buf
, "\"pass\":\"");
4117 wpabuf_put_str(buf
, pass
);
4118 wpabuf_put_str(buf
, "\"");
4120 char psk
[2 * sizeof(conf
->psk
) + 1];
4122 wpa_snprintf_hex(psk
, sizeof(psk
),
4123 conf
->psk
, sizeof(conf
->psk
));
4124 wpabuf_put_str(buf
, "\"psk_hex\":\"");
4125 wpabuf_put_str(buf
, psk
);
4126 wpabuf_put_str(buf
, "\"");
4128 wpabuf_put_str(buf
, "}}");
4130 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4131 wpabuf_head(buf
), wpabuf_len(buf
));
4137 static struct wpabuf
*
4138 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
4140 struct dpp_configuration
*conf
;
4142 #ifdef CONFIG_TESTING_OPTIONS
4143 if (auth
->config_obj_override
) {
4144 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
4145 return wpabuf_alloc_copy(auth
->config_obj_override
,
4146 os_strlen(auth
->config_obj_override
));
4148 #endif /* CONFIG_TESTING_OPTIONS */
4150 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
4152 wpa_printf(MSG_DEBUG
,
4153 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4159 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
4160 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
4164 static struct wpabuf
*
4165 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
4166 u16 e_nonce_len
, int ap
)
4168 struct wpabuf
*conf
;
4169 size_t clear_len
, attr_len
;
4170 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
4174 enum dpp_status_error status
;
4176 conf
= dpp_build_conf_obj(auth
, ap
);
4178 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4179 wpabuf_head(conf
), wpabuf_len(conf
));
4181 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
4183 /* { E-nonce, configurationObject}ke */
4184 clear_len
= 4 + e_nonce_len
;
4186 clear_len
+= 4 + wpabuf_len(conf
);
4187 clear
= wpabuf_alloc(clear_len
);
4188 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
4189 #ifdef CONFIG_TESTING_OPTIONS
4190 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
4192 #endif /* CONFIG_TESTING_OPTIONS */
4193 msg
= wpabuf_alloc(attr_len
);
4197 #ifdef CONFIG_TESTING_OPTIONS
4198 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
4199 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
4202 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
4203 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
4204 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4205 wpabuf_put_le16(clear
, e_nonce_len
);
4206 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4207 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4210 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4211 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4212 goto skip_wrapped_data
;
4214 #endif /* CONFIG_TESTING_OPTIONS */
4217 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4218 wpabuf_put_le16(clear
, e_nonce_len
);
4219 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4221 #ifdef CONFIG_TESTING_OPTIONS
4223 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4224 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4225 goto skip_config_obj
;
4227 #endif /* CONFIG_TESTING_OPTIONS */
4230 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4231 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4232 wpabuf_put_buf(clear
, conf
);
4235 #ifdef CONFIG_TESTING_OPTIONS
4237 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4238 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4241 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4242 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4245 #endif /* CONFIG_TESTING_OPTIONS */
4248 dpp_build_attr_status(msg
, status
);
4250 #ifdef CONFIG_TESTING_OPTIONS
4252 #endif /* CONFIG_TESTING_OPTIONS */
4254 addr
[0] = wpabuf_head(msg
);
4255 len
[0] = wpabuf_len(msg
);
4256 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4258 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4259 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4260 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4262 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4263 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4264 wpabuf_head(clear
), wpabuf_len(clear
),
4265 1, addr
, len
, wrapped
) < 0)
4267 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4268 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4270 #ifdef CONFIG_TESTING_OPTIONS
4271 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4272 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4273 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
4276 #endif /* CONFIG_TESTING_OPTIONS */
4278 wpa_hexdump_buf(MSG_DEBUG
,
4279 "DPP: Configuration Response attributes", msg
);
4293 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4296 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4297 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4298 u8
*unwrapped
= NULL
;
4299 size_t unwrapped_len
= 0;
4300 struct wpabuf
*resp
= NULL
;
4301 struct json_token
*root
= NULL
, *token
;
4304 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4305 dpp_auth_fail(auth
, "Invalid attribute in config request");
4309 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4311 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4313 "Missing or invalid required Wrapped Data attribute");
4317 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4318 wrapped_data
, wrapped_data_len
);
4319 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4320 unwrapped
= os_malloc(unwrapped_len
);
4323 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4324 wrapped_data
, wrapped_data_len
,
4325 0, NULL
, NULL
, unwrapped
) < 0) {
4326 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4329 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4330 unwrapped
, unwrapped_len
);
4332 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4333 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4337 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4338 DPP_ATTR_ENROLLEE_NONCE
,
4340 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4342 "Missing or invalid Enrollee Nonce attribute");
4345 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4347 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
4348 DPP_ATTR_CONFIG_ATTR_OBJ
,
4352 "Missing or invalid Config Attributes attribute");
4355 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
4356 config_attr
, config_attr_len
);
4358 root
= json_parse((const char *) config_attr
, config_attr_len
);
4360 dpp_auth_fail(auth
, "Could not parse Config Attributes");
4364 token
= json_get_member(root
, "name");
4365 if (!token
|| token
->type
!= JSON_STRING
) {
4366 dpp_auth_fail(auth
, "No Config Attributes - name");
4369 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
4371 token
= json_get_member(root
, "wi-fi_tech");
4372 if (!token
|| token
->type
!= JSON_STRING
) {
4373 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
4376 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
4377 if (os_strcmp(token
->string
, "infra") != 0) {
4378 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
4380 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
4384 token
= json_get_member(root
, "netRole");
4385 if (!token
|| token
->type
!= JSON_STRING
) {
4386 dpp_auth_fail(auth
, "No Config Attributes - netRole");
4389 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
4390 if (os_strcmp(token
->string
, "sta") == 0) {
4392 } else if (os_strcmp(token
->string
, "ap") == 0) {
4395 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
4397 dpp_auth_fail(auth
, "Unsupported netRole");
4401 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
4410 static struct wpabuf
*
4411 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
4412 const u8
*prot_hdr
, u16 prot_hdr_len
,
4413 const EVP_MD
**ret_md
)
4415 struct json_token
*root
, *token
;
4416 struct wpabuf
*kid
= NULL
;
4418 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
4420 wpa_printf(MSG_DEBUG
,
4421 "DPP: JSON parsing failed for JWS Protected Header");
4425 if (root
->type
!= JSON_OBJECT
) {
4426 wpa_printf(MSG_DEBUG
,
4427 "DPP: JWS Protected Header root is not an object");
4431 token
= json_get_member(root
, "typ");
4432 if (!token
|| token
->type
!= JSON_STRING
) {
4433 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
4436 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
4438 if (os_strcmp(token
->string
, "dppCon") != 0) {
4439 wpa_printf(MSG_DEBUG
,
4440 "DPP: Unsupported JWS Protected Header typ=%s",
4445 token
= json_get_member(root
, "alg");
4446 if (!token
|| token
->type
!= JSON_STRING
) {
4447 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
4450 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
4452 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
4453 wpa_printf(MSG_DEBUG
,
4454 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4455 token
->string
, curve
->jws_alg
);
4458 if (os_strcmp(token
->string
, "ES256") == 0 ||
4459 os_strcmp(token
->string
, "BS256") == 0)
4460 *ret_md
= EVP_sha256();
4461 else if (os_strcmp(token
->string
, "ES384") == 0 ||
4462 os_strcmp(token
->string
, "BS384") == 0)
4463 *ret_md
= EVP_sha384();
4464 else if (os_strcmp(token
->string
, "ES512") == 0 ||
4465 os_strcmp(token
->string
, "BS512") == 0)
4466 *ret_md
= EVP_sha512();
4470 wpa_printf(MSG_DEBUG
,
4471 "DPP: Unsupported JWS Protected Header alg=%s",
4476 kid
= json_get_member_base64url(root
, "kid");
4478 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
4481 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
4490 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
4491 struct json_token
*cred
)
4493 struct json_token
*pass
, *psk_hex
;
4495 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
4497 pass
= json_get_member(cred
, "pass");
4498 psk_hex
= json_get_member(cred
, "psk_hex");
4500 if (pass
&& pass
->type
== JSON_STRING
) {
4501 size_t len
= os_strlen(pass
->string
);
4503 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
4505 if (len
< 8 || len
> 63)
4507 os_strlcpy(auth
->passphrase
, pass
->string
,
4508 sizeof(auth
->passphrase
));
4509 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
4510 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
4511 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
4512 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
4515 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
4516 auth
->psk
, PMK_LEN
);
4519 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
4527 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
4528 const struct dpp_curve_params
**key_curve
)
4530 struct json_token
*token
;
4531 const struct dpp_curve_params
*curve
;
4532 struct wpabuf
*x
= NULL
, *y
= NULL
;
4534 EVP_PKEY
*pkey
= NULL
;
4536 token
= json_get_member(jwk
, "kty");
4537 if (!token
|| token
->type
!= JSON_STRING
) {
4538 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
4541 if (os_strcmp(token
->string
, "EC") != 0) {
4542 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s",
4547 token
= json_get_member(jwk
, "crv");
4548 if (!token
|| token
->type
!= JSON_STRING
) {
4549 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
4552 curve
= dpp_get_curve_jwk_crv(token
->string
);
4554 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
4559 x
= json_get_member_base64url(jwk
, "x");
4561 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
4564 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
4565 if (wpabuf_len(x
) != curve
->prime_len
) {
4566 wpa_printf(MSG_DEBUG
,
4567 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4568 (unsigned int) wpabuf_len(x
),
4569 (unsigned int) curve
->prime_len
, curve
->name
);
4573 y
= json_get_member_base64url(jwk
, "y");
4575 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
4578 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
4579 if (wpabuf_len(y
) != curve
->prime_len
) {
4580 wpa_printf(MSG_DEBUG
,
4581 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4582 (unsigned int) wpabuf_len(y
),
4583 (unsigned int) curve
->prime_len
, curve
->name
);
4587 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
4589 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
4593 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
4605 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
4608 unsigned int year
, month
, day
, hour
, min
, sec
;
4612 /* ISO 8601 date and time:
4614 * YYYY-MM-DDTHH:MM:SSZ
4615 * YYYY-MM-DDTHH:MM:SS+03:00
4617 if (os_strlen(timestamp
) < 19) {
4618 wpa_printf(MSG_DEBUG
,
4619 "DPP: Too short timestamp - assume expired key");
4622 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
4623 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
4624 wpa_printf(MSG_DEBUG
,
4625 "DPP: Failed to parse expiration day - assume expired key");
4629 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
4630 wpa_printf(MSG_DEBUG
,
4631 "DPP: Invalid date/time information - assume expired key");
4635 pos
= timestamp
+ 19;
4636 if (*pos
== 'Z' || *pos
== '\0') {
4637 /* In UTC - no need to adjust */
4638 } else if (*pos
== '-' || *pos
== '+') {
4641 /* Adjust local time to UTC */
4642 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
4644 wpa_printf(MSG_DEBUG
,
4645 "DPP: Invalid time zone designator (%s) - assume expired key",
4650 utime
+= 3600 * hour
;
4652 utime
-= 3600 * hour
;
4660 wpa_printf(MSG_DEBUG
,
4661 "DPP: Invalid time zone designator (%s) - assume expired key",
4668 if (os_get_time(&now
) < 0) {
4669 wpa_printf(MSG_DEBUG
,
4670 "DPP: Cannot get current time - assume expired key");
4674 if (now
.sec
> utime
) {
4675 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
4684 static int dpp_parse_connector(struct dpp_authentication
*auth
,
4685 const unsigned char *payload
,
4688 struct json_token
*root
, *groups
, *netkey
, *token
;
4690 EVP_PKEY
*key
= NULL
;
4691 const struct dpp_curve_params
*curve
;
4692 unsigned int rules
= 0;
4694 root
= json_parse((const char *) payload
, payload_len
);
4696 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
4700 groups
= json_get_member(root
, "groups");
4701 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
4702 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
4705 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4706 struct json_token
*id
, *role
;
4708 id
= json_get_member(token
, "groupId");
4709 if (!id
|| id
->type
!= JSON_STRING
) {
4710 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
4714 role
= json_get_member(token
, "netRole");
4715 if (!role
|| role
->type
!= JSON_STRING
) {
4716 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
4719 wpa_printf(MSG_DEBUG
,
4720 "DPP: connector group: groupId='%s' netRole='%s'",
4721 id
->string
, role
->string
);
4727 wpa_printf(MSG_DEBUG
,
4728 "DPP: Connector includes no groups");
4732 token
= json_get_member(root
, "expiry");
4733 if (!token
|| token
->type
!= JSON_STRING
) {
4734 wpa_printf(MSG_DEBUG
,
4735 "DPP: No expiry string found - connector does not expire");
4737 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
4738 if (dpp_key_expired(token
->string
,
4739 &auth
->net_access_key_expiry
)) {
4740 wpa_printf(MSG_DEBUG
,
4741 "DPP: Connector (netAccessKey) has expired");
4746 netkey
= json_get_member(root
, "netAccessKey");
4747 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
4748 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
4752 key
= dpp_parse_jwk(netkey
, &curve
);
4755 dpp_debug_print_key("DPP: Received netAccessKey", key
);
4757 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
4758 wpa_printf(MSG_DEBUG
,
4759 "DPP: netAccessKey in connector does not match own protocol key");
4760 #ifdef CONFIG_TESTING_OPTIONS
4761 if (auth
->ignore_netaccesskey_mismatch
) {
4762 wpa_printf(MSG_DEBUG
,
4763 "DPP: TESTING - skip netAccessKey mismatch");
4767 #else /* CONFIG_TESTING_OPTIONS */
4769 #endif /* CONFIG_TESTING_OPTIONS */
4780 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
4782 struct wpabuf
*uncomp
;
4784 u8 hash
[SHA256_MAC_LEN
];
4788 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
4790 uncomp
= dpp_get_pubkey_point(pub
, 1);
4793 addr
[0] = wpabuf_head(uncomp
);
4794 len
[0] = wpabuf_len(uncomp
);
4795 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
4797 res
= sha256_vector(1, addr
, len
, hash
);
4798 wpabuf_free(uncomp
);
4801 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
4802 wpa_printf(MSG_DEBUG
,
4803 "DPP: Received hash value does not match calculated public key hash value");
4804 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
4805 hash
, SHA256_MAC_LEN
);
4812 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
4814 unsigned char *der
= NULL
;
4817 der_len
= i2d_PUBKEY(csign
, &der
);
4820 wpabuf_free(auth
->c_sign_key
);
4821 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
4826 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
4828 unsigned char *der
= NULL
;
4832 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
4836 der_len
= i2d_ECPrivateKey(eckey
, &der
);
4841 wpabuf_free(auth
->net_access_key
);
4842 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
4848 struct dpp_signed_connector_info
{
4849 unsigned char *payload
;
4853 static enum dpp_status_error
4854 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
4855 EVP_PKEY
*csign_pub
, const char *connector
)
4857 enum dpp_status_error ret
= 255;
4858 const char *pos
, *end
, *signed_start
, *signed_end
;
4859 struct wpabuf
*kid
= NULL
;
4860 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
4861 size_t prot_hdr_len
= 0, signature_len
= 0;
4862 const EVP_MD
*sign_md
= NULL
;
4863 unsigned char *der
= NULL
;
4866 EVP_MD_CTX
*md_ctx
= NULL
;
4867 ECDSA_SIG
*sig
= NULL
;
4868 BIGNUM
*r
= NULL
, *s
= NULL
;
4869 const struct dpp_curve_params
*curve
;
4871 const EC_GROUP
*group
;
4874 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
4877 group
= EC_KEY_get0_group(eckey
);
4880 nid
= EC_GROUP_get_curve_name(group
);
4881 curve
= dpp_get_curve_nid(nid
);
4884 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
4885 os_memset(info
, 0, sizeof(*info
));
4887 signed_start
= pos
= connector
;
4888 end
= os_strchr(pos
, '.');
4890 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
4891 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4894 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
4895 end
- pos
, &prot_hdr_len
);
4897 wpa_printf(MSG_DEBUG
,
4898 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
4899 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4902 wpa_hexdump_ascii(MSG_DEBUG
,
4903 "DPP: signedConnector - JWS Protected Header",
4904 prot_hdr
, prot_hdr_len
);
4905 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
4907 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4910 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
4911 wpa_printf(MSG_DEBUG
,
4912 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
4913 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
4914 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4919 end
= os_strchr(pos
, '.');
4921 wpa_printf(MSG_DEBUG
,
4922 "DPP: Missing dot(2) in signedConnector");
4923 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4926 signed_end
= end
- 1;
4927 info
->payload
= base64_url_decode((const unsigned char *) pos
,
4928 end
- pos
, &info
->payload_len
);
4929 if (!info
->payload
) {
4930 wpa_printf(MSG_DEBUG
,
4931 "DPP: Failed to base64url decode signedConnector JWS Payload");
4932 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4935 wpa_hexdump_ascii(MSG_DEBUG
,
4936 "DPP: signedConnector - JWS Payload",
4937 info
->payload
, info
->payload_len
);
4939 signature
= base64_url_decode((const unsigned char *) pos
,
4940 os_strlen(pos
), &signature_len
);
4942 wpa_printf(MSG_DEBUG
,
4943 "DPP: Failed to base64url decode signedConnector signature");
4944 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4947 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
4948 signature
, signature_len
);
4950 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
4951 ret
= DPP_STATUS_NO_MATCH
;
4955 if (signature_len
& 0x01) {
4956 wpa_printf(MSG_DEBUG
,
4957 "DPP: Unexpected signedConnector signature length (%d)",
4958 (int) signature_len
);
4959 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4963 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
4964 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
4965 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
4966 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
4967 sig
= ECDSA_SIG_new();
4968 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
4973 der_len
= i2d_ECDSA_SIG(sig
, &der
);
4975 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
4978 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
4979 md_ctx
= EVP_MD_CTX_create();
4984 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
4985 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
4986 ERR_error_string(ERR_get_error(), NULL
));
4989 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
4990 signed_end
- signed_start
+ 1) != 1) {
4991 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
4992 ERR_error_string(ERR_get_error(), NULL
));
4995 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
4997 wpa_printf(MSG_DEBUG
,
4998 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
4999 res
, ERR_error_string(ERR_get_error(), NULL
));
5000 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5004 ret
= DPP_STATUS_OK
;
5007 EVP_MD_CTX_destroy(md_ctx
);
5011 ECDSA_SIG_free(sig
);
5019 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5020 struct json_token
*cred
)
5022 struct dpp_signed_connector_info info
;
5023 struct json_token
*token
, *csign
;
5025 EVP_PKEY
*csign_pub
= NULL
;
5026 const struct dpp_curve_params
*key_curve
= NULL
;
5027 const char *signed_connector
;
5029 os_memset(&info
, 0, sizeof(info
));
5031 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5033 csign
= json_get_member(cred
, "csign");
5034 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5035 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5039 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5041 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5044 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5046 token
= json_get_member(cred
, "signedConnector");
5047 if (!token
|| token
->type
!= JSON_STRING
) {
5048 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5051 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5052 token
->string
, os_strlen(token
->string
));
5053 signed_connector
= token
->string
;
5055 if (os_strchr(signed_connector
, '"') ||
5056 os_strchr(signed_connector
, '\n')) {
5057 wpa_printf(MSG_DEBUG
,
5058 "DPP: Unexpected character in signedConnector");
5062 if (dpp_process_signed_connector(&info
, csign_pub
,
5063 signed_connector
) != DPP_STATUS_OK
)
5066 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
5067 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
5071 os_free(auth
->connector
);
5072 auth
->connector
= os_strdup(signed_connector
);
5074 dpp_copy_csign(auth
, csign_pub
);
5075 dpp_copy_netaccesskey(auth
);
5079 EVP_PKEY_free(csign_pub
);
5080 os_free(info
.payload
);
5085 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
5086 const u8
*conf_obj
, u16 conf_obj_len
)
5089 struct json_token
*root
, *token
, *discovery
, *cred
;
5091 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
5094 if (root
->type
!= JSON_OBJECT
) {
5095 dpp_auth_fail(auth
, "JSON root is not an object");
5099 token
= json_get_member(root
, "wi-fi_tech");
5100 if (!token
|| token
->type
!= JSON_STRING
) {
5101 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
5104 if (os_strcmp(token
->string
, "infra") != 0) {
5105 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
5107 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
5111 discovery
= json_get_member(root
, "discovery");
5112 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
5113 dpp_auth_fail(auth
, "No discovery object in JSON");
5117 token
= json_get_member(discovery
, "ssid");
5118 if (!token
|| token
->type
!= JSON_STRING
) {
5119 dpp_auth_fail(auth
, "No discovery::ssid string value found");
5122 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
5123 token
->string
, os_strlen(token
->string
));
5124 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
5125 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
5128 auth
->ssid_len
= os_strlen(token
->string
);
5129 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
5131 cred
= json_get_member(root
, "cred");
5132 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
5133 dpp_auth_fail(auth
, "No cred object in JSON");
5137 token
= json_get_member(cred
, "akm");
5138 if (!token
|| token
->type
!= JSON_STRING
) {
5139 dpp_auth_fail(auth
, "No cred::akm string value found");
5142 if (os_strcmp(token
->string
, "psk") == 0) {
5143 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5145 } else if (os_strcmp(token
->string
, "dpp") == 0) {
5146 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
5149 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
5151 dpp_auth_fail(auth
, "Unsupported akm");
5155 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
5163 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
5164 const struct wpabuf
*resp
)
5166 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
5167 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
5170 u8
*unwrapped
= NULL
;
5171 size_t unwrapped_len
= 0;
5174 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
5175 dpp_auth_fail(auth
, "Invalid attribute in config response");
5179 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5180 DPP_ATTR_WRAPPED_DATA
,
5182 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5184 "Missing or invalid required Wrapped Data attribute");
5188 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5189 wrapped_data
, wrapped_data_len
);
5190 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5191 unwrapped
= os_malloc(unwrapped_len
);
5195 addr
[0] = wpabuf_head(resp
);
5196 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
5197 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5199 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5200 wrapped_data
, wrapped_data_len
,
5201 1, addr
, len
, unwrapped
) < 0) {
5202 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5205 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5206 unwrapped
, unwrapped_len
);
5208 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5209 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5213 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5214 DPP_ATTR_ENROLLEE_NONCE
,
5216 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5218 "Missing or invalid Enrollee Nonce attribute");
5221 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5222 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5223 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5227 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5228 DPP_ATTR_STATUS
, &status_len
);
5229 if (!status
|| status_len
< 1) {
5231 "Missing or invalid required DPP Status attribute");
5234 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5235 if (status
[0] != DPP_STATUS_OK
) {
5236 dpp_auth_fail(auth
, "Configurator rejected configuration");
5240 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5241 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5244 "Missing required Configuration Object attribute");
5247 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5248 conf_obj
, conf_obj_len
);
5249 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5260 void dpp_configurator_free(struct dpp_configurator
*conf
)
5264 EVP_PKEY_free(conf
->csign
);
5270 struct dpp_configurator
*
5271 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
5274 struct dpp_configurator
*conf
;
5275 struct wpabuf
*csign_pub
= NULL
;
5276 u8 kid_hash
[SHA256_MAC_LEN
];
5280 conf
= os_zalloc(sizeof(*conf
));
5285 conf
->curve
= &dpp_curves
[0];
5287 conf
->curve
= dpp_get_curve_name(curve
);
5289 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5295 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
5298 conf
->csign
= dpp_gen_keypair(conf
->curve
);
5303 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
5305 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
5309 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5310 addr
[0] = wpabuf_head(csign_pub
);
5311 len
[0] = wpabuf_len(csign_pub
);
5312 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
5313 wpa_printf(MSG_DEBUG
,
5314 "DPP: Failed to derive kid for C-sign-key");
5318 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
5323 wpabuf_free(csign_pub
);
5326 dpp_configurator_free(conf
);
5332 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
5335 struct wpabuf
*conf_obj
;
5339 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
5344 auth
->curve
= &dpp_curves
[0];
5346 auth
->curve
= dpp_get_curve_name(curve
);
5348 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5353 wpa_printf(MSG_DEBUG
,
5354 "DPP: Building own configuration/connector with curve %s",
5357 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
5358 if (!auth
->own_protocol_key
)
5360 dpp_copy_netaccesskey(auth
);
5361 auth
->peer_protocol_key
= auth
->own_protocol_key
;
5362 dpp_copy_csign(auth
, auth
->conf
->csign
);
5364 conf_obj
= dpp_build_conf_obj(auth
, 0);
5367 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
5368 wpabuf_len(conf_obj
));
5370 wpabuf_free(conf_obj
);
5371 auth
->peer_protocol_key
= NULL
;
5376 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
5378 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
5379 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
5383 static int dpp_connector_compatible_group(struct json_token
*root
,
5384 const char *group_id
,
5385 const char *net_role
)
5387 struct json_token
*groups
, *token
;
5389 groups
= json_get_member(root
, "groups");
5390 if (!groups
|| groups
->type
!= JSON_ARRAY
)
5393 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5394 struct json_token
*id
, *role
;
5396 id
= json_get_member(token
, "groupId");
5397 if (!id
|| id
->type
!= JSON_STRING
)
5400 role
= json_get_member(token
, "netRole");
5401 if (!role
|| role
->type
!= JSON_STRING
)
5404 if (os_strcmp(id
->string
, "*") != 0 &&
5405 os_strcmp(group_id
, "*") != 0 &&
5406 os_strcmp(id
->string
, group_id
) != 0)
5409 if (dpp_compatible_netrole(role
->string
, net_role
))
5417 static int dpp_connector_match_groups(struct json_token
*own_root
,
5418 struct json_token
*peer_root
)
5420 struct json_token
*groups
, *token
;
5422 groups
= json_get_member(peer_root
, "groups");
5423 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5424 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
5428 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5429 struct json_token
*id
, *role
;
5431 id
= json_get_member(token
, "groupId");
5432 if (!id
|| id
->type
!= JSON_STRING
) {
5433 wpa_printf(MSG_DEBUG
,
5434 "DPP: Missing peer groupId string");
5438 role
= json_get_member(token
, "netRole");
5439 if (!role
|| role
->type
!= JSON_STRING
) {
5440 wpa_printf(MSG_DEBUG
,
5441 "DPP: Missing peer groups::netRole string");
5444 wpa_printf(MSG_DEBUG
,
5445 "DPP: peer connector group: groupId='%s' netRole='%s'",
5446 id
->string
, role
->string
);
5447 if (dpp_connector_compatible_group(own_root
, id
->string
,
5449 wpa_printf(MSG_DEBUG
,
5450 "DPP: Compatible group/netRole in own connector");
5459 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
5460 unsigned int hash_len
)
5462 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
5463 const char *info
= "DPP PMK";
5466 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5468 /* HKDF-Extract(<>, N.x) */
5469 os_memset(salt
, 0, hash_len
);
5470 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
5472 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5475 /* HKDF-Expand(PRK, info, L) */
5476 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
5477 os_memset(prk
, 0, hash_len
);
5481 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5487 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
5488 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
5490 struct wpabuf
*nkx
, *pkx
;
5494 u8 hash
[SHA256_MAC_LEN
];
5496 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5497 nkx
= dpp_get_pubkey_point(own_key
, 0);
5498 pkx
= dpp_get_pubkey_point(peer_key
, 0);
5501 addr
[0] = wpabuf_head(nkx
);
5502 len
[0] = wpabuf_len(nkx
) / 2;
5503 addr
[1] = wpabuf_head(pkx
);
5504 len
[1] = wpabuf_len(pkx
) / 2;
5505 if (len
[0] != len
[1])
5507 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
5508 addr
[0] = wpabuf_head(pkx
);
5509 addr
[1] = wpabuf_head(nkx
);
5511 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
5512 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
5513 res
= sha256_vector(2, addr
, len
, hash
);
5516 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
5517 os_memcpy(pmkid
, hash
, PMKID_LEN
);
5518 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
5527 enum dpp_status_error
5528 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
5529 const u8
*net_access_key
, size_t net_access_key_len
,
5530 const u8
*csign_key
, size_t csign_key_len
,
5531 const u8
*peer_connector
, size_t peer_connector_len
,
5534 struct json_token
*root
= NULL
, *netkey
, *token
;
5535 struct json_token
*own_root
= NULL
;
5536 enum dpp_status_error ret
= 255, res
;
5537 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
5538 struct wpabuf
*own_key_pub
= NULL
;
5539 const struct dpp_curve_params
*curve
, *own_curve
;
5540 struct dpp_signed_connector_info info
;
5541 const unsigned char *p
;
5542 EVP_PKEY
*csign
= NULL
;
5543 char *signed_connector
= NULL
;
5544 const char *pos
, *end
;
5545 unsigned char *own_conn
= NULL
;
5546 size_t own_conn_len
;
5547 EVP_PKEY_CTX
*ctx
= NULL
;
5549 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
5551 os_memset(intro
, 0, sizeof(*intro
));
5552 os_memset(&info
, 0, sizeof(info
));
5557 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
5559 wpa_printf(MSG_ERROR
,
5560 "DPP: Failed to parse local C-sign-key information");
5564 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
5565 net_access_key_len
);
5567 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
5571 pos
= os_strchr(own_connector
, '.');
5573 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
5577 end
= os_strchr(pos
, '.');
5579 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
5582 own_conn
= base64_url_decode((const unsigned char *) pos
,
5583 end
- pos
, &own_conn_len
);
5585 wpa_printf(MSG_DEBUG
,
5586 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5590 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
5592 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
5596 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
5597 peer_connector
, peer_connector_len
);
5598 signed_connector
= os_malloc(peer_connector_len
+ 1);
5599 if (!signed_connector
)
5601 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
5602 signed_connector
[peer_connector_len
] = '\0';
5604 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
5605 if (res
!= DPP_STATUS_OK
) {
5610 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
5612 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5613 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5617 if (!dpp_connector_match_groups(own_root
, root
)) {
5618 wpa_printf(MSG_DEBUG
,
5619 "DPP: Peer connector does not include compatible group netrole with own connector");
5620 ret
= DPP_STATUS_NO_MATCH
;
5624 token
= json_get_member(root
, "expiry");
5625 if (!token
|| token
->type
!= JSON_STRING
) {
5626 wpa_printf(MSG_DEBUG
,
5627 "DPP: No expiry string found - connector does not expire");
5629 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5630 if (dpp_key_expired(token
->string
, expiry
)) {
5631 wpa_printf(MSG_DEBUG
,
5632 "DPP: Connector (netAccessKey) has expired");
5633 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5638 netkey
= json_get_member(root
, "netAccessKey");
5639 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5640 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5641 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5645 peer_key
= dpp_parse_jwk(netkey
, &curve
);
5647 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5650 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
5652 if (own_curve
!= curve
) {
5653 wpa_printf(MSG_DEBUG
,
5654 "DPP: Mismatching netAccessKey curves (%s != %s)",
5655 own_curve
->name
, curve
->name
);
5656 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5660 /* ECDH: N = nk * PK */
5661 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
5663 EVP_PKEY_derive_init(ctx
) != 1 ||
5664 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
5665 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
5666 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5667 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
5668 wpa_printf(MSG_ERROR
,
5669 "DPP: Failed to derive ECDH shared secret: %s",
5670 ERR_error_string(ERR_get_error(), NULL
));
5674 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
5677 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5678 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
5679 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
5682 intro
->pmk_len
= curve
->hash_len
;
5684 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5685 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
5686 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
5690 ret
= DPP_STATUS_OK
;
5692 if (ret
!= DPP_STATUS_OK
)
5693 os_memset(intro
, 0, sizeof(*intro
));
5694 os_memset(Nx
, 0, sizeof(Nx
));
5695 EVP_PKEY_CTX_free(ctx
);
5697 os_free(signed_connector
);
5698 os_free(info
.payload
);
5699 EVP_PKEY_free(own_key
);
5700 wpabuf_free(own_key_pub
);
5701 EVP_PKEY_free(peer_key
);
5702 EVP_PKEY_free(csign
);
5704 json_free(own_root
);
5709 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
5713 size_t len
= curve
->prime_len
;
5716 switch (curve
->ike_group
) {
5718 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
5719 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
5722 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
5723 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
5726 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
5727 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
5730 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
5731 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
5734 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
5735 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
5738 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
5739 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
5745 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5748 return dpp_set_pubkey_point_group(group
, x
, y
, len
);
5752 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
5753 const u8
*mac_init
, const char *code
,
5754 const char *identifier
, BN_CTX
*bnctx
,
5755 const EC_GROUP
**ret_group
)
5757 u8 hash
[DPP_MAX_HASH_LEN
];
5760 unsigned int num_elem
= 0;
5761 EC_POINT
*Qi
= NULL
;
5762 EVP_PKEY
*Pi
= NULL
;
5763 EC_KEY
*Pi_ec
= NULL
;
5764 const EC_POINT
*Pi_point
;
5765 BIGNUM
*hash_bn
= NULL
;
5766 const EC_GROUP
*group
= NULL
;
5767 EC_GROUP
*group2
= NULL
;
5769 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5771 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
5772 addr
[num_elem
] = mac_init
;
5773 len
[num_elem
] = ETH_ALEN
;
5776 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5778 addr
[num_elem
] = (const u8
*) identifier
;
5779 len
[num_elem
] = os_strlen(identifier
);
5782 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5783 addr
[num_elem
] = (const u8
*) code
;
5784 len
[num_elem
] = os_strlen(code
);
5786 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5788 wpa_hexdump_key(MSG_DEBUG
,
5789 "DPP: H(MAC-Initiator | [identifier |] code)",
5790 hash
, curve
->hash_len
);
5791 Pi
= dpp_pkex_get_role_elem(curve
, 1);
5794 dpp_debug_print_key("DPP: Pi", Pi
);
5795 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
5798 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
5800 group
= EC_KEY_get0_group(Pi_ec
);
5803 group2
= EC_GROUP_dup(group
);
5806 Qi
= EC_POINT_new(group2
);
5808 EC_GROUP_free(group2
);
5811 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5813 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
5815 if (EC_POINT_is_at_infinity(group
, Qi
)) {
5816 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
5822 BN_clear_free(hash_bn
);
5824 *ret_group
= group2
;
5833 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
5834 const u8
*mac_resp
, const char *code
,
5835 const char *identifier
, BN_CTX
*bnctx
,
5836 const EC_GROUP
**ret_group
)
5838 u8 hash
[DPP_MAX_HASH_LEN
];
5841 unsigned int num_elem
= 0;
5842 EC_POINT
*Qr
= NULL
;
5843 EVP_PKEY
*Pr
= NULL
;
5844 EC_KEY
*Pr_ec
= NULL
;
5845 const EC_POINT
*Pr_point
;
5846 BIGNUM
*hash_bn
= NULL
;
5847 const EC_GROUP
*group
= NULL
;
5848 EC_GROUP
*group2
= NULL
;
5850 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5852 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
5853 addr
[num_elem
] = mac_resp
;
5854 len
[num_elem
] = ETH_ALEN
;
5857 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5859 addr
[num_elem
] = (const u8
*) identifier
;
5860 len
[num_elem
] = os_strlen(identifier
);
5863 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5864 addr
[num_elem
] = (const u8
*) code
;
5865 len
[num_elem
] = os_strlen(code
);
5867 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5869 wpa_hexdump_key(MSG_DEBUG
,
5870 "DPP: H(MAC-Responder | [identifier |] code)",
5871 hash
, curve
->hash_len
);
5872 Pr
= dpp_pkex_get_role_elem(curve
, 0);
5875 dpp_debug_print_key("DPP: Pr", Pr
);
5876 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
5879 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
5881 group
= EC_KEY_get0_group(Pr_ec
);
5884 group2
= EC_GROUP_dup(group
);
5887 Qr
= EC_POINT_new(group2
);
5889 EC_GROUP_free(group2
);
5892 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5894 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
5896 if (EC_POINT_is_at_infinity(group
, Qr
)) {
5897 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
5903 BN_clear_free(hash_bn
);
5905 *ret_group
= group2
;
5914 #ifdef CONFIG_TESTING_OPTIONS
5915 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
5916 const struct dpp_curve_params
*curve
)
5924 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5929 point
= EC_POINT_new(group
);
5932 if (!ctx
|| !point
|| !x
|| !y
)
5935 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
5938 /* Generate a random y coordinate that results in a point that is not
5941 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
5944 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
5946 #ifdef OPENSSL_IS_BORINGSSL
5947 /* Unlike OpenSSL, BoringSSL returns an error from
5948 * EC_POINT_set_affine_coordinates_GFp() is not on the curve. */
5950 #else /* OPENSSL_IS_BORINGSSL */
5952 #endif /* OPENSSL_IS_BORINGSSL */
5955 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
5959 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
5960 curve
->prime_len
) < 0 ||
5961 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
5962 curve
->prime_len
) < 0)
5968 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
5971 EC_POINT_free(point
);
5976 #endif /* CONFIG_TESTING_OPTIONS */
5979 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
5981 EC_KEY
*X_ec
= NULL
;
5982 const EC_POINT
*X_point
;
5983 BN_CTX
*bnctx
= NULL
;
5984 const EC_GROUP
*group
;
5985 EC_POINT
*Qi
= NULL
, *M
= NULL
;
5986 struct wpabuf
*M_buf
= NULL
;
5987 BIGNUM
*Mx
= NULL
, *My
= NULL
;
5988 struct wpabuf
*msg
= NULL
;
5990 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5992 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
5994 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5995 bnctx
= BN_CTX_new();
5998 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
5999 pkex
->identifier
, bnctx
, &group
);
6003 /* Generate a random ephemeral keypair x/X */
6004 pkex
->x
= dpp_gen_keypair(curve
);
6009 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
6012 X_point
= EC_KEY_get0_public_key(X_ec
);
6015 M
= EC_POINT_new(group
);
6018 if (!M
|| !Mx
|| !My
||
6019 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
6020 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
6023 /* Initiator -> Responder: group, [identifier,] M */
6025 if (pkex
->identifier
)
6026 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6027 attr_len
+= 4 + 2 * curve
->prime_len
;
6028 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
6032 #ifdef CONFIG_TESTING_OPTIONS
6033 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
6034 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
6035 goto skip_finite_cyclic_group
;
6037 #endif /* CONFIG_TESTING_OPTIONS */
6039 /* Finite Cyclic Group attribute */
6040 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6041 wpabuf_put_le16(msg
, 2);
6042 wpabuf_put_le16(msg
, curve
->ike_group
);
6044 #ifdef CONFIG_TESTING_OPTIONS
6045 skip_finite_cyclic_group
:
6046 #endif /* CONFIG_TESTING_OPTIONS */
6048 /* Code Identifier attribute */
6049 if (pkex
->identifier
) {
6050 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6051 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6052 wpabuf_put_str(msg
, pkex
->identifier
);
6055 #ifdef CONFIG_TESTING_OPTIONS
6056 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6057 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6060 #endif /* CONFIG_TESTING_OPTIONS */
6062 /* M in Encrypted Key attribute */
6063 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6064 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6066 #ifdef CONFIG_TESTING_OPTIONS
6067 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6068 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6069 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6073 #endif /* CONFIG_TESTING_OPTIONS */
6075 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
6076 curve
->prime_len
) < 0 ||
6077 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
6078 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
6079 curve
->prime_len
) < 0)
6092 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
6099 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
6101 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
6105 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
6107 const char *identifier
,
6110 struct dpp_pkex
*pkex
;
6112 pkex
= os_zalloc(sizeof(*pkex
));
6115 pkex
->msg_ctx
= msg_ctx
;
6116 pkex
->initiator
= 1;
6118 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6120 pkex
->identifier
= os_strdup(identifier
);
6121 if (!pkex
->identifier
)
6124 pkex
->code
= os_strdup(code
);
6127 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
6128 if (!pkex
->exchange_req
)
6132 dpp_pkex_free(pkex
);
6137 static struct wpabuf
*
6138 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
6139 enum dpp_status_error status
,
6140 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
6142 struct wpabuf
*msg
= NULL
;
6144 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6146 /* Initiator -> Responder: DPP Status, [identifier,] N */
6148 if (pkex
->identifier
)
6149 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6150 attr_len
+= 4 + 2 * curve
->prime_len
;
6151 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
6155 #ifdef CONFIG_TESTING_OPTIONS
6156 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
6157 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
6161 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
6162 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
6165 #endif /* CONFIG_TESTING_OPTIONS */
6168 dpp_build_attr_status(msg
, status
);
6170 #ifdef CONFIG_TESTING_OPTIONS
6172 #endif /* CONFIG_TESTING_OPTIONS */
6174 /* Code Identifier attribute */
6175 if (pkex
->identifier
) {
6176 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6177 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6178 wpabuf_put_str(msg
, pkex
->identifier
);
6181 if (status
!= DPP_STATUS_OK
)
6182 goto skip_encrypted_key
;
6184 #ifdef CONFIG_TESTING_OPTIONS
6185 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6186 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6187 goto skip_encrypted_key
;
6189 #endif /* CONFIG_TESTING_OPTIONS */
6191 /* N in Encrypted Key attribute */
6192 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6193 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6195 #ifdef CONFIG_TESTING_OPTIONS
6196 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6197 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6198 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6200 goto skip_encrypted_key
;
6202 #endif /* CONFIG_TESTING_OPTIONS */
6204 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
6205 curve
->prime_len
) < 0 ||
6206 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
6207 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
6208 curve
->prime_len
) < 0)
6212 if (status
== DPP_STATUS_BAD_GROUP
) {
6213 /* Finite Cyclic Group attribute */
6214 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6215 wpabuf_put_le16(msg
, 2);
6216 wpabuf_put_le16(msg
, curve
->ike_group
);
6226 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
6227 const u8
*Mx
, size_t Mx_len
,
6228 const u8
*Nx
, size_t Nx_len
,
6230 const u8
*Kx
, size_t Kx_len
,
6231 u8
*z
, unsigned int hash_len
)
6233 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6238 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6241 /* HKDF-Extract(<>, IKM=K.x) */
6242 os_memset(salt
, 0, hash_len
);
6243 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
6245 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
6247 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
6248 info
= os_malloc(info_len
);
6252 os_memcpy(pos
, mac_init
, ETH_ALEN
);
6254 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
6256 os_memcpy(pos
, Mx
, Mx_len
);
6258 os_memcpy(pos
, Nx
, Nx_len
);
6260 os_memcpy(pos
, code
, os_strlen(code
));
6262 /* HKDF-Expand(PRK, info, L) */
6264 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6266 else if (hash_len
== 48)
6267 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6269 else if (hash_len
== 64)
6270 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6275 os_memset(prk
, 0, hash_len
);
6279 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
6285 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
6286 struct dpp_bootstrap_info
*bi
,
6289 const char *identifier
,
6291 const u8
*buf
, size_t len
)
6293 const u8
*attr_group
, *attr_id
, *attr_key
;
6294 u16 attr_group_len
, attr_id_len
, attr_key_len
;
6295 const struct dpp_curve_params
*curve
= bi
->curve
;
6297 struct dpp_pkex
*pkex
= NULL
;
6298 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
6299 BN_CTX
*bnctx
= NULL
;
6300 const EC_GROUP
*group
;
6301 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6302 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
6303 const EC_POINT
*Y_point
;
6304 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6305 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6308 EVP_PKEY_CTX
*ctx
= NULL
;
6310 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
6311 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6312 "PKEX counter t limit reached - ignore message");
6316 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
6318 if (!attr_id
&& identifier
) {
6319 wpa_printf(MSG_DEBUG
,
6320 "DPP: No PKEX code identifier received, but expected one");
6323 if (attr_id
&& identifier
&&
6324 (os_strlen(identifier
) != attr_id_len
||
6325 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
6326 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
6330 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
6332 if (!attr_group
|| attr_group_len
!= 2) {
6333 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6334 "Missing or invalid Finite Cyclic Group attribute");
6337 ike_group
= WPA_GET_LE16(attr_group
);
6338 if (ike_group
!= curve
->ike_group
) {
6339 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6340 "Mismatching PKEX curve: peer=%u own=%u",
6341 ike_group
, curve
->ike_group
);
6342 pkex
= os_zalloc(sizeof(*pkex
));
6347 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
6348 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
6349 if (!pkex
->exchange_resp
)
6354 /* M in Encrypted Key attribute */
6355 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
6357 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
6358 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
6359 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6360 "Missing Encrypted Key attribute");
6364 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6365 bnctx
= BN_CTX_new();
6368 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
6374 X
= EC_POINT_new(group
);
6375 M
= EC_POINT_new(group
);
6376 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6377 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6378 if (!X
|| !M
|| !Mx
|| !My
||
6379 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
6380 EC_POINT_is_at_infinity(group
, M
) ||
6381 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
6382 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
6383 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
6384 EC_POINT_is_at_infinity(group
, X
) ||
6385 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
6386 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6387 "Invalid Encrypted Key value");
6392 pkex
= os_zalloc(sizeof(*pkex
));
6395 pkex
->t
= bi
->pkex_t
;
6396 pkex
->msg_ctx
= msg_ctx
;
6398 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6399 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
6401 pkex
->identifier
= os_strdup(identifier
);
6402 if (!pkex
->identifier
)
6405 pkex
->code
= os_strdup(code
);
6409 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
6411 X_ec
= EC_KEY_new();
6413 EC_KEY_set_group(X_ec
, group
) != 1 ||
6414 EC_KEY_set_public_key(X_ec
, X
) != 1)
6416 pkex
->x
= EVP_PKEY_new();
6418 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
6421 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6422 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
6426 /* Generate a random ephemeral keypair y/Y */
6427 pkex
->y
= dpp_gen_keypair(curve
);
6432 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
6435 Y_point
= EC_KEY_get0_public_key(Y_ec
);
6438 N
= EC_POINT_new(group
);
6441 if (!N
|| !Nx
|| !Ny
||
6442 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
6443 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
6446 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
6448 if (!pkex
->exchange_resp
)
6452 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
6454 EVP_PKEY_derive_init(ctx
) != 1 ||
6455 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
6456 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6457 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6458 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6459 wpa_printf(MSG_ERROR
,
6460 "DPP: Failed to derive ECDH shared secret: %s",
6461 ERR_error_string(ERR_get_error(), NULL
));
6465 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6468 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6470 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
6471 pkex
->Mx
, curve
->prime_len
,
6472 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
6473 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
6474 os_memset(Kx
, 0, Kx_len
);
6478 pkex
->exchange_done
= 1;
6481 EVP_PKEY_CTX_free(ctx
);
6496 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
6497 dpp_pkex_free(pkex
);
6503 static struct wpabuf
*
6504 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
6505 const struct wpabuf
*A_pub
, const u8
*u
)
6507 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6508 struct wpabuf
*msg
= NULL
;
6509 size_t clear_len
, attr_len
;
6510 struct wpabuf
*clear
= NULL
;
6516 /* {A, u, [bootstrapping info]}z */
6517 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6518 clear
= wpabuf_alloc(clear_len
);
6519 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6520 #ifdef CONFIG_TESTING_OPTIONS
6521 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
6523 #endif /* CONFIG_TESTING_OPTIONS */
6524 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
6528 #ifdef CONFIG_TESTING_OPTIONS
6529 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6530 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6531 goto skip_bootstrap_key
;
6533 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6534 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6535 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6536 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6537 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6539 goto skip_bootstrap_key
;
6541 #endif /* CONFIG_TESTING_OPTIONS */
6543 /* A in Bootstrap Key attribute */
6544 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6545 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
6546 wpabuf_put_buf(clear
, A_pub
);
6548 #ifdef CONFIG_TESTING_OPTIONS
6550 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
6551 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
6552 goto skip_i_auth_tag
;
6554 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
6555 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
6556 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6557 wpabuf_put_le16(clear
, curve
->hash_len
);
6558 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
6559 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
6560 goto skip_i_auth_tag
;
6562 #endif /* CONFIG_TESTING_OPTIONS */
6564 /* u in I-Auth tag attribute */
6565 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6566 wpabuf_put_le16(clear
, curve
->hash_len
);
6567 wpabuf_put_data(clear
, u
, curve
->hash_len
);
6569 #ifdef CONFIG_TESTING_OPTIONS
6571 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
6572 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6573 goto skip_wrapped_data
;
6575 #endif /* CONFIG_TESTING_OPTIONS */
6577 addr
[0] = wpabuf_head_u8(msg
) + 2;
6578 len
[0] = DPP_HDR_LEN
;
6581 len
[1] = sizeof(octet
);
6582 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6583 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6585 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6586 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6587 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6589 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6590 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6591 wpabuf_head(clear
), wpabuf_len(clear
),
6592 2, addr
, len
, wrapped
) < 0)
6594 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6595 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6597 #ifdef CONFIG_TESTING_OPTIONS
6598 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
6599 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6600 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
6603 #endif /* CONFIG_TESTING_OPTIONS */
6616 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
6617 const u8
*buf
, size_t buflen
)
6619 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
6620 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
6621 const EC_GROUP
*group
;
6622 BN_CTX
*bnctx
= NULL
;
6623 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6624 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6625 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
6626 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6627 EVP_PKEY_CTX
*ctx
= NULL
;
6628 EC_KEY
*Y_ec
= NULL
;
6629 size_t Jx_len
, Kx_len
;
6630 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6633 u8 u
[DPP_MAX_HASH_LEN
];
6636 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
6639 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
6641 if (!attr_status
|| attr_status_len
!= 1) {
6642 dpp_pkex_fail(pkex
, "No DPP Status attribute");
6645 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
6647 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
6648 attr_group
= dpp_get_attr(buf
, buflen
,
6649 DPP_ATTR_FINITE_CYCLIC_GROUP
,
6651 if (attr_group
&& attr_group_len
== 2) {
6652 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6653 "Peer indicated mismatching PKEX group - proposed %u",
6654 WPA_GET_LE16(attr_group
));
6659 if (attr_status
[0] != DPP_STATUS_OK
) {
6660 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
6664 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
6666 if (!attr_id
&& pkex
->identifier
) {
6667 wpa_printf(MSG_DEBUG
,
6668 "DPP: No PKEX code identifier received, but expected one");
6671 if (attr_id
&& pkex
->identifier
&&
6672 (os_strlen(pkex
->identifier
) != attr_id_len
||
6673 os_memcmp(pkex
->identifier
, attr_id
, attr_id_len
) != 0)) {
6674 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
6678 /* N in Encrypted Key attribute */
6679 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
6681 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
6682 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
6686 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
6687 bnctx
= BN_CTX_new();
6690 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
6691 pkex
->identifier
, bnctx
, &group
);
6696 Y
= EC_POINT_new(group
);
6697 N
= EC_POINT_new(group
);
6698 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6699 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6700 if (!Y
|| !N
|| !Nx
|| !Ny
||
6701 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
6702 EC_POINT_is_at_infinity(group
, N
) ||
6703 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
6704 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
6705 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
6706 EC_POINT_is_at_infinity(group
, Y
) ||
6707 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
6708 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
6713 pkex
->exchange_done
= 1;
6715 /* ECDH: J = a * Y’ */
6716 Y_ec
= EC_KEY_new();
6718 EC_KEY_set_group(Y_ec
, group
) != 1 ||
6719 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
6721 pkex
->y
= EVP_PKEY_new();
6723 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
6725 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
6727 EVP_PKEY_derive_init(ctx
) != 1 ||
6728 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
6729 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
6730 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6731 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
6732 wpa_printf(MSG_ERROR
,
6733 "DPP: Failed to derive ECDH shared secret: %s",
6734 ERR_error_string(ERR_get_error(), NULL
));
6738 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
6741 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
6742 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
6743 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6744 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6745 if (!A_pub
|| !Y_pub
|| !X_pub
)
6747 addr
[0] = pkex
->own_mac
;
6749 addr
[1] = wpabuf_head(A_pub
);
6750 len
[1] = wpabuf_len(A_pub
) / 2;
6751 addr
[2] = wpabuf_head(Y_pub
);
6752 len
[2] = wpabuf_len(Y_pub
) / 2;
6753 addr
[3] = wpabuf_head(X_pub
);
6754 len
[3] = wpabuf_len(X_pub
) / 2;
6755 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
6757 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
6760 EVP_PKEY_CTX_free(ctx
);
6761 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
6763 EVP_PKEY_derive_init(ctx
) != 1 ||
6764 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
6765 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6766 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6767 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6768 wpa_printf(MSG_ERROR
,
6769 "DPP: Failed to derive ECDH shared secret: %s",
6770 ERR_error_string(ERR_get_error(), NULL
));
6774 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6777 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6779 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
6780 pkex
->Mx
, curve
->prime_len
,
6781 attr_key
/* N.x */, attr_key_len
/ 2,
6782 pkex
->code
, Kx
, Kx_len
,
6783 pkex
->z
, curve
->hash_len
);
6784 os_memset(Kx
, 0, Kx_len
);
6788 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
6802 EVP_PKEY_CTX_free(ctx
);
6806 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
6811 static struct wpabuf
*
6812 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
6813 const struct wpabuf
*B_pub
, const u8
*v
)
6815 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6816 struct wpabuf
*msg
= NULL
;
6821 struct wpabuf
*clear
= NULL
;
6822 size_t clear_len
, attr_len
;
6824 /* {B, v [bootstrapping info]}z */
6825 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6826 clear
= wpabuf_alloc(clear_len
);
6827 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6828 #ifdef CONFIG_TESTING_OPTIONS
6829 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
6831 #endif /* CONFIG_TESTING_OPTIONS */
6832 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
6836 #ifdef CONFIG_TESTING_OPTIONS
6837 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
6838 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6839 goto skip_bootstrap_key
;
6841 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
6842 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6843 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6844 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6845 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6847 goto skip_bootstrap_key
;
6849 #endif /* CONFIG_TESTING_OPTIONS */
6851 /* B in Bootstrap Key attribute */
6852 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6853 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
6854 wpabuf_put_buf(clear
, B_pub
);
6856 #ifdef CONFIG_TESTING_OPTIONS
6858 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
6859 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
6860 goto skip_r_auth_tag
;
6862 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
6863 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
6864 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
6865 wpabuf_put_le16(clear
, curve
->hash_len
);
6866 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
6867 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
6868 goto skip_r_auth_tag
;
6870 #endif /* CONFIG_TESTING_OPTIONS */
6872 /* v in R-Auth tag attribute */
6873 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
6874 wpabuf_put_le16(clear
, curve
->hash_len
);
6875 wpabuf_put_data(clear
, v
, curve
->hash_len
);
6877 #ifdef CONFIG_TESTING_OPTIONS
6879 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
6880 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6881 goto skip_wrapped_data
;
6883 #endif /* CONFIG_TESTING_OPTIONS */
6885 addr
[0] = wpabuf_head_u8(msg
) + 2;
6886 len
[0] = DPP_HDR_LEN
;
6889 len
[1] = sizeof(octet
);
6890 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6891 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6893 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6894 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6895 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6897 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6898 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6899 wpabuf_head(clear
), wpabuf_len(clear
),
6900 2, addr
, len
, wrapped
) < 0)
6902 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6903 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6905 #ifdef CONFIG_TESTING_OPTIONS
6906 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
6907 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6908 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
6911 #endif /* CONFIG_TESTING_OPTIONS */
6924 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
6926 const u8
*buf
, size_t buflen
)
6928 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6929 EVP_PKEY_CTX
*ctx
= NULL
;
6930 size_t Jx_len
, Lx_len
;
6931 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
6932 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
6933 const u8
*wrapped_data
, *b_key
, *peer_u
;
6934 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
6938 u8
*unwrapped
= NULL
;
6939 size_t unwrapped_len
= 0;
6940 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6941 struct wpabuf
*B_pub
= NULL
;
6942 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
6944 if (!pkex
->exchange_done
|| pkex
->failed
||
6945 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
6948 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
6950 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6952 "Missing or invalid required Wrapped Data attribute");
6956 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6957 wrapped_data
, wrapped_data_len
);
6958 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6959 unwrapped
= os_malloc(unwrapped_len
);
6964 len
[0] = DPP_HDR_LEN
;
6967 len
[1] = sizeof(octet
);
6968 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6969 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6971 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
6972 wrapped_data
, wrapped_data_len
,
6973 2, addr
, len
, unwrapped
) < 0) {
6975 "AES-SIV decryption failed - possible PKEX code mismatch");
6980 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6981 unwrapped
, unwrapped_len
);
6983 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6984 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
6988 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
6990 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
6991 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
6994 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
6996 if (!pkex
->peer_bootstrap_key
) {
6997 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7000 dpp_debug_print_key("DPP: Peer bootstrap public key",
7001 pkex
->peer_bootstrap_key
);
7003 /* ECDH: J' = y * A' */
7004 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7006 EVP_PKEY_derive_init(ctx
) != 1 ||
7007 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7008 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7009 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7010 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7011 wpa_printf(MSG_ERROR
,
7012 "DPP: Failed to derive ECDH shared secret: %s",
7013 ERR_error_string(ERR_get_error(), NULL
));
7017 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7020 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7021 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7022 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7023 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7024 if (!A_pub
|| !Y_pub
|| !X_pub
)
7026 addr
[0] = pkex
->peer_mac
;
7028 addr
[1] = wpabuf_head(A_pub
);
7029 len
[1] = wpabuf_len(A_pub
) / 2;
7030 addr
[2] = wpabuf_head(Y_pub
);
7031 len
[2] = wpabuf_len(Y_pub
) / 2;
7032 addr
[3] = wpabuf_head(X_pub
);
7033 len
[3] = wpabuf_len(X_pub
) / 2;
7034 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7037 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
7039 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
7040 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
7041 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
7042 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
7043 u
, curve
->hash_len
);
7044 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
7048 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
7050 /* ECDH: L = b * X' */
7051 EVP_PKEY_CTX_free(ctx
);
7052 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7054 EVP_PKEY_derive_init(ctx
) != 1 ||
7055 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
7056 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
7057 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7058 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
7059 wpa_printf(MSG_ERROR
,
7060 "DPP: Failed to derive ECDH shared secret: %s",
7061 ERR_error_string(ERR_get_error(), NULL
));
7065 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
7068 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7069 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7072 addr
[0] = pkex
->own_mac
;
7074 addr
[1] = wpabuf_head(B_pub
);
7075 len
[1] = wpabuf_len(B_pub
) / 2;
7076 addr
[2] = wpabuf_head(X_pub
);
7077 len
[2] = wpabuf_len(X_pub
) / 2;
7078 addr
[3] = wpabuf_head(Y_pub
);
7079 len
[3] = wpabuf_len(Y_pub
) / 2;
7080 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7082 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
7084 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
7089 EVP_PKEY_CTX_free(ctx
);
7097 wpa_printf(MSG_DEBUG
,
7098 "DPP: PKEX Commit-Reveal Request processing failed");
7103 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
7104 const u8
*buf
, size_t buflen
)
7106 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7107 const u8
*wrapped_data
, *b_key
, *peer_v
;
7108 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
7112 u8
*unwrapped
= NULL
;
7113 size_t unwrapped_len
= 0;
7115 u8 v
[DPP_MAX_HASH_LEN
];
7117 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7118 EVP_PKEY_CTX
*ctx
= NULL
;
7119 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7121 if (!pkex
->exchange_done
|| pkex
->failed
||
7122 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
7125 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7127 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7129 "Missing or invalid required Wrapped Data attribute");
7133 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7134 wrapped_data
, wrapped_data_len
);
7135 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7136 unwrapped
= os_malloc(unwrapped_len
);
7141 len
[0] = DPP_HDR_LEN
;
7144 len
[1] = sizeof(octet
);
7145 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7146 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7148 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7149 wrapped_data
, wrapped_data_len
,
7150 2, addr
, len
, unwrapped
) < 0) {
7152 "AES-SIV decryption failed - possible PKEX code mismatch");
7156 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7157 unwrapped
, unwrapped_len
);
7159 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7160 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7164 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7166 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7167 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7170 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7172 if (!pkex
->peer_bootstrap_key
) {
7173 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7176 dpp_debug_print_key("DPP: Peer bootstrap public key",
7177 pkex
->peer_bootstrap_key
);
7179 /* ECDH: L' = x * B' */
7180 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7182 EVP_PKEY_derive_init(ctx
) != 1 ||
7183 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7184 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
7185 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7186 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
7187 wpa_printf(MSG_ERROR
,
7188 "DPP: Failed to derive ECDH shared secret: %s",
7189 ERR_error_string(ERR_get_error(), NULL
));
7193 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
7196 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
7197 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7198 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7199 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7200 if (!B_pub
|| !X_pub
|| !Y_pub
)
7202 addr
[0] = pkex
->peer_mac
;
7204 addr
[1] = wpabuf_head(B_pub
);
7205 len
[1] = wpabuf_len(B_pub
) / 2;
7206 addr
[2] = wpabuf_head(X_pub
);
7207 len
[2] = wpabuf_len(X_pub
) / 2;
7208 addr
[3] = wpabuf_head(Y_pub
);
7209 len
[3] = wpabuf_len(Y_pub
) / 2;
7210 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7213 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
7215 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
7216 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
7217 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
7218 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
7219 v
, curve
->hash_len
);
7220 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
7224 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
7231 EVP_PKEY_CTX_free(ctx
);
7239 void dpp_pkex_free(struct dpp_pkex
*pkex
)
7244 os_free(pkex
->identifier
);
7245 os_free(pkex
->code
);
7246 EVP_PKEY_free(pkex
->x
);
7247 EVP_PKEY_free(pkex
->y
);
7248 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
7249 wpabuf_free(pkex
->exchange_req
);
7250 wpabuf_free(pkex
->exchange_resp
);
7255 #ifdef CONFIG_TESTING_OPTIONS
7256 char * dpp_corrupt_connector_signature(const char *connector
)
7258 char *tmp
, *pos
, *signed3
= NULL
;
7259 unsigned char *signature
= NULL
;
7260 size_t signature_len
= 0, signed3_len
;
7262 tmp
= os_zalloc(os_strlen(connector
) + 5);
7265 os_memcpy(tmp
, connector
, os_strlen(connector
));
7267 pos
= os_strchr(tmp
, '.');
7271 pos
= os_strchr(pos
+ 1, '.');
7276 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
7278 signature
= base64_url_decode((const unsigned char *) pos
,
7279 os_strlen(pos
), &signature_len
);
7280 if (!signature
|| signature_len
== 0)
7282 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
7283 signature
, signature_len
);
7284 signature
[signature_len
- 1] ^= 0x01;
7285 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
7286 signature
, signature_len
);
7287 signed3
= (char *) base64_url_encode(signature
, signature_len
,
7291 os_memcpy(pos
, signed3
, signed3_len
);
7292 pos
[signed3_len
] = '\0';
7293 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
7305 #endif /* CONFIG_TESTING_OPTIONS */