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>
13 #include "utils/common.h"
14 #include "utils/base64.h"
15 #include "utils/json.h"
16 #include "common/ieee802_11_common.h"
17 #include "common/ieee802_11_defs.h"
18 #include "common/wpa_ctrl.h"
19 #include "crypto/crypto.h"
20 #include "crypto/random.h"
21 #include "crypto/aes.h"
22 #include "crypto/aes_siv.h"
23 #include "crypto/sha384.h"
24 #include "crypto/sha512.h"
25 #include "drivers/driver.h"
29 #ifdef CONFIG_TESTING_OPTIONS
30 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
31 #endif /* CONFIG_TESTING_OPTIONS */
33 #if OPENSSL_VERSION_NUMBER < 0x10100000L
34 /* Compatibility wrappers for older versions. */
36 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
44 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
56 static const struct dpp_curve_params dpp_curves
[] = {
57 /* The mandatory to support and the default NIST P-256 curve needs to
58 * be the first entry on this list. */
59 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
60 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
61 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
62 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
63 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
64 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
65 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
69 /* Role-specific elements for PKEX */
72 static const u8 pkex_init_x_p256
[32] = {
73 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
74 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
75 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
76 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
78 static const u8 pkex_init_y_p256
[32] = {
79 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
80 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
81 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
82 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
84 static const u8 pkex_resp_x_p256
[32] = {
85 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
86 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
87 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
88 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
90 static const u8 pkex_resp_y_p256
[32] = {
91 0x26, 0x04, 0x09, 0x45, 0x0a, 0x05, 0x20, 0xe7,
92 0xa7, 0x27, 0xc1, 0x36, 0x76, 0x85, 0xca, 0x3e,
93 0x42, 0x16, 0xf4, 0x89, 0x85, 0x34, 0x6e, 0xd5,
94 0x17, 0xde, 0xc0, 0xb8, 0xad, 0xfd, 0xb2, 0x98
98 static const u8 pkex_init_x_p384
[48] = {
99 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
100 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
101 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
102 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
103 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
104 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
106 static const u8 pkex_init_y_p384
[48] = {
107 0x89, 0xd0, 0x97, 0x7b, 0x59, 0x4f, 0xa6, 0xd6,
108 0x7c, 0x5d, 0x93, 0x5b, 0x93, 0xc4, 0x07, 0xa9,
109 0x89, 0xee, 0xd5, 0xcd, 0x6f, 0x42, 0xf8, 0x38,
110 0xc8, 0xc6, 0x62, 0x24, 0x69, 0x0c, 0xd4, 0x48,
111 0xd8, 0x44, 0xd6, 0xc2, 0xe8, 0xcc, 0x62, 0x6b,
112 0x3c, 0x25, 0x53, 0xba, 0x4f, 0x71, 0xf8, 0xe7
114 static const u8 pkex_resp_x_p384
[48] = {
115 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
116 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
117 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
118 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
119 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
120 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
122 static const u8 pkex_resp_y_p384
[48] = {
123 0x54, 0x58, 0x20, 0xad, 0x55, 0x1d, 0xca, 0xf3,
124 0x1c, 0x8a, 0xcd, 0x19, 0x40, 0xf9, 0x37, 0x83,
125 0xc7, 0xd6, 0xb3, 0x13, 0x7d, 0x53, 0x28, 0x5c,
126 0xf6, 0x2d, 0xf1, 0xdd, 0xa5, 0x8b, 0xad, 0x5d,
127 0x81, 0xab, 0xb1, 0x00, 0x39, 0xd6, 0xcc, 0x9c,
128 0xea, 0x1e, 0x84, 0x1d, 0xbf, 0xe3, 0x35, 0xf9
132 static const u8 pkex_init_x_p521
[66] = {
133 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
134 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
135 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
136 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
137 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
138 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
139 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
140 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
143 static const u8 pkex_init_y_p521
[66] = {
144 0x01, 0x4c, 0x71, 0xfd, 0x1b, 0xd5, 0x9c, 0xa6,
145 0xed, 0x39, 0xef, 0x45, 0xc5, 0x06, 0xfd, 0x66,
146 0xc0, 0xeb, 0x0f, 0xbf, 0x21, 0xa3, 0x36, 0x74,
147 0xfd, 0xaa, 0x05, 0x6e, 0x4e, 0x33, 0x95, 0x42,
148 0x1a, 0x9d, 0x3f, 0x3a, 0x1c, 0x5e, 0xa8, 0x60,
149 0xf7, 0xe5, 0x59, 0x1d, 0x07, 0xaa, 0x6f, 0x40,
150 0x0a, 0x59, 0x3c, 0x27, 0xad, 0xe0, 0x48, 0xfd,
151 0xd1, 0x83, 0x37, 0x4c, 0xdf, 0xe1, 0x86, 0x72,
154 static const u8 pkex_resp_x_p521
[66] = {
155 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
156 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
157 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
158 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
159 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
160 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
161 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
162 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
165 static const u8 pkex_resp_y_p521
[66] = {
166 0x01, 0xb9, 0x9c, 0xc6, 0x41, 0x32, 0x5b, 0xd2,
167 0x35, 0xd8, 0x8b, 0x2b, 0xe4, 0x6e, 0xcc, 0xdf,
168 0x7c, 0x38, 0xc4, 0x5b, 0xf6, 0x74, 0x71, 0x5c,
169 0x77, 0x16, 0x8a, 0x80, 0xa9, 0x84, 0xc7, 0x7b,
170 0x9d, 0xfd, 0x83, 0x6f, 0xae, 0xf8, 0x24, 0x16,
171 0x2f, 0x21, 0x25, 0x65, 0xa2, 0x1a, 0x6b, 0x2d,
172 0x30, 0x62, 0xb3, 0xcc, 0x6e, 0x59, 0x3c, 0x7f,
173 0x58, 0x91, 0x81, 0x72, 0x07, 0x8c, 0x91, 0xac,
177 /* Brainpool P-256r1 */
178 static const u8 pkex_init_x_bp_p256r1
[32] = {
179 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
180 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
181 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
182 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
184 static const u8 pkex_init_y_bp_p256r1
[32] = {
185 0x16, 0x30, 0x68, 0x32, 0x3b, 0xb0, 0x21, 0xee,
186 0xeb, 0xf7, 0xb6, 0x7c, 0xae, 0x52, 0x26, 0x42,
187 0x59, 0x28, 0x58, 0xb6, 0x14, 0x90, 0xed, 0x69,
188 0xd0, 0x67, 0xea, 0x25, 0x60, 0x0f, 0xa9, 0x6c
190 static const u8 pkex_resp_x_bp_p256r1
[32] = {
191 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
192 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
193 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
194 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
196 static const u8 pkex_resp_y_bp_p256r1
[32] = {
197 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
198 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
199 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
200 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
203 /* Brainpool P-384r1 */
204 static const u8 pkex_init_x_bp_p384r1
[48] = {
205 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
206 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
207 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
208 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
209 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
210 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
212 static const u8 pkex_init_y_bp_p384r1
[48] = {
213 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
214 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
215 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
216 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
217 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
218 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
220 static const u8 pkex_resp_x_bp_p384r1
[48] = {
221 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
222 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
223 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
224 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
225 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
226 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
228 static const u8 pkex_resp_y_bp_p384r1
[48] = {
229 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
230 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
231 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
232 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
233 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
234 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
237 /* Brainpool P-512r1 */
238 static const u8 pkex_init_x_bp_p512r1
[64] = {
239 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
240 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
241 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
242 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
243 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
244 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
245 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
246 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
248 static const u8 pkex_init_y_bp_p512r1
[64] = {
249 0x5a, 0x28, 0x01, 0xbe, 0x96, 0x82, 0x4e, 0xf6,
250 0xfa, 0xed, 0x7d, 0xfd, 0x48, 0x8b, 0x48, 0x4e,
251 0xd1, 0x97, 0x87, 0xc4, 0x05, 0x5d, 0x15, 0x2a,
252 0xf4, 0x91, 0x4b, 0x75, 0x90, 0xd9, 0x34, 0x2c,
253 0x3c, 0x12, 0xf2, 0xf5, 0x25, 0x94, 0x24, 0x34,
254 0xa7, 0x6d, 0x66, 0xbc, 0x27, 0xa4, 0xa0, 0x8d,
255 0xd5, 0xe1, 0x54, 0xa3, 0x55, 0x26, 0xd4, 0x14,
256 0x17, 0x0f, 0xc1, 0xc7, 0x3d, 0x68, 0x7f, 0x5a
258 static const u8 pkex_resp_x_bp_p512r1
[64] = {
259 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
260 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
261 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
262 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
263 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
264 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
265 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
266 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
268 static const u8 pkex_resp_y_bp_p512r1
[64] = {
269 0x2a, 0xbe, 0x59, 0xe6, 0xc4, 0xb3, 0xd8, 0x09,
270 0x66, 0x89, 0x0a, 0x2d, 0x19, 0xf0, 0x9c, 0x9f,
271 0xb4, 0xab, 0x8f, 0x50, 0x68, 0x3c, 0x74, 0x64,
272 0x4e, 0x19, 0x55, 0x81, 0x9b, 0x48, 0x5c, 0xf4,
273 0x12, 0x8d, 0xb9, 0xd8, 0x02, 0x5b, 0xe1, 0x26,
274 0x7e, 0x19, 0x5c, 0xfd, 0x70, 0xf7, 0x4b, 0xdc,
275 0xb5, 0x5d, 0xc1, 0x7a, 0xe9, 0xd1, 0x05, 0x2e,
276 0xd1, 0xfd, 0x2f, 0xce, 0x63, 0x77, 0x48, 0x2c
280 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
281 size_t num_elem
, const u8
*addr
[], const size_t *len
,
284 if (curve
->hash_len
== 32)
285 return sha256_vector(num_elem
, addr
, len
, mac
);
286 if (curve
->hash_len
== 48)
287 return sha384_vector(num_elem
, addr
, len
, mac
);
288 if (curve
->hash_len
== 64)
289 return sha512_vector(num_elem
, addr
, len
, mac
);
294 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
295 const char *label
, u8
*out
, size_t outlen
)
298 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
299 (const u8
*) label
, os_strlen(label
),
302 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
303 (const u8
*) label
, os_strlen(label
),
306 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
307 (const u8
*) label
, os_strlen(label
),
313 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
314 size_t num_elem
, const u8
*addr
[],
315 const size_t *len
, u8
*mac
)
318 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
321 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
324 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
330 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
331 const u8
*data
, size_t data_len
, u8
*mac
)
334 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
336 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
338 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
343 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
345 int num_bytes
, offset
;
347 num_bytes
= BN_num_bytes(bn
);
348 if ((size_t) num_bytes
> len
)
350 offset
= len
- num_bytes
;
351 os_memset(pos
, 0, offset
);
352 BN_bn2bin(bn
, pos
+ offset
);
357 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
364 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
367 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
368 len
= i2o_ECPublicKey(eckey
, NULL
);
370 wpa_printf(MSG_ERROR
,
371 "DDP: Failed to determine public key encoding length");
376 buf
= wpabuf_alloc(len
);
382 pos
= wpabuf_put(buf
, len
);
383 res
= i2o_ECPublicKey(eckey
, &pos
);
386 wpa_printf(MSG_ERROR
,
387 "DDP: Failed to encode public key (res=%d/%d)",
394 /* Remove 0x04 prefix to match DPP definition */
395 pos
= wpabuf_mhead(buf
);
396 os_memmove(pos
, pos
+ 1, len
- 1);
404 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
405 const u8
*buf_x
, const u8
*buf_y
,
408 EC_KEY
*eckey
= NULL
;
410 EC_POINT
*point
= NULL
;
411 BIGNUM
*x
= NULL
, *y
= NULL
;
412 EVP_PKEY
*pkey
= NULL
;
416 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
420 point
= EC_POINT_new(group
);
421 x
= BN_bin2bn(buf_x
, len
, NULL
);
422 y
= BN_bin2bn(buf_y
, len
, NULL
);
423 if (!point
|| !x
|| !y
) {
424 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
428 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
429 wpa_printf(MSG_ERROR
,
430 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
431 ERR_error_string(ERR_get_error(), NULL
));
435 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
436 EC_POINT_is_at_infinity(group
, point
)) {
437 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
441 eckey
= EC_KEY_new();
443 EC_KEY_set_group(eckey
, group
) != 1 ||
444 EC_KEY_set_public_key(eckey
, point
) != 1) {
445 wpa_printf(MSG_ERROR
,
446 "DPP: Failed to set EC_KEY: %s",
447 ERR_error_string(ERR_get_error(), NULL
));
450 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
452 pkey
= EVP_PKEY_new();
453 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
454 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
462 EC_POINT_free(point
);
472 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
473 const u8
*buf
, size_t len
)
476 const EC_GROUP
*group
;
477 EVP_PKEY
*pkey
= NULL
;
482 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
484 wpa_printf(MSG_ERROR
,
485 "DPP: Could not get EC_KEY from group_key");
489 group
= EC_KEY_get0_group(eckey
);
491 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
494 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
501 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
503 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
507 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
512 msg
= wpabuf_alloc(8 + len
);
515 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
516 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
517 wpabuf_put_be24(msg
, OUI_WFA
);
518 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
519 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
520 wpabuf_put_u8(msg
, type
);
525 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
528 const u8
*pos
= buf
, *end
= buf
+ len
;
530 while (end
- pos
>= 4) {
531 id
= WPA_GET_LE16(pos
);
533 alen
= WPA_GET_LE16(pos
);
535 if (alen
> end
- pos
)
548 int dpp_check_attrs(const u8
*buf
, size_t len
)
551 int wrapped_data
= 0;
555 while (end
- pos
>= 4) {
558 id
= WPA_GET_LE16(pos
);
560 alen
= WPA_GET_LE16(pos
);
562 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
564 if (alen
> end
- pos
) {
565 wpa_printf(MSG_DEBUG
,
566 "DPP: Truncated message - not enough room for the attribute - dropped");
570 wpa_printf(MSG_DEBUG
,
571 "DPP: An unexpected attribute included after the Wrapped Data attribute");
574 if (id
== DPP_ATTR_WRAPPED_DATA
)
580 wpa_printf(MSG_DEBUG
,
581 "DPP: Unexpected octets (%d) after the last attribute",
590 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
596 EVP_PKEY_free(info
->pubkey
);
601 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
604 case DPP_BOOTSTRAP_QR_CODE
:
606 case DPP_BOOTSTRAP_PKEX
:
613 static int dpp_uri_valid_info(const char *info
)
616 unsigned char val
= *info
++;
618 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
626 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
628 bi
->uri
= os_strdup(uri
);
629 return bi
->uri
? 0 : -1;
633 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
634 const char *chan_list
)
636 const char *pos
= chan_list
;
637 int opclass
, channel
, freq
;
639 while (pos
&& *pos
&& *pos
!= ';') {
643 pos
= os_strchr(pos
, '/');
650 while (*pos
>= '0' && *pos
<= '9')
652 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
653 wpa_printf(MSG_DEBUG
,
654 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
655 opclass
, channel
, freq
);
657 wpa_printf(MSG_DEBUG
,
658 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
660 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
661 wpa_printf(MSG_DEBUG
,
662 "DPP: Too many channels in URI channel-list - ignore list");
666 bi
->freq
[bi
->num_freq
++] = freq
;
669 if (*pos
== ';' || *pos
== '\0')
678 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
683 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
688 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
689 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
693 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
699 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
706 end
= os_strchr(info
, ';');
708 end
= info
+ os_strlen(info
);
709 bi
->info
= os_malloc(end
- info
+ 1);
712 os_memcpy(bi
->info
, info
, end
- info
);
713 bi
->info
[end
- info
] = '\0';
714 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
715 if (!dpp_uri_valid_info(bi
->info
)) {
716 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
724 static const struct dpp_curve_params
*
725 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
730 for (i
= 0; dpp_curves
[i
].name
; i
++) {
731 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
732 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
733 return &dpp_curves
[i
];
739 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
745 for (i
= 0; dpp_curves
[i
].name
; i
++) {
746 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
748 return &dpp_curves
[i
];
754 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
760 const unsigned char *p
;
762 X509_PUBKEY
*pub
= NULL
;
764 const unsigned char *pk
;
767 #if OPENSSL_VERSION_NUMBER < 0x10100000L
770 const ASN1_OBJECT
*pa_oid
;
774 const ASN1_OBJECT
*poid
;
777 end
= os_strchr(info
, ';');
781 data
= base64_decode((const unsigned char *) info
, end
- info
,
784 wpa_printf(MSG_DEBUG
,
785 "DPP: Invalid base64 encoding on URI public-key");
788 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
791 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
792 bi
->pubkey_hash
) < 0) {
793 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
796 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
797 bi
->pubkey_hash
, SHA256_MAC_LEN
);
799 /* DER encoded ASN.1 SubjectPublicKeyInfo
801 * SubjectPublicKeyInfo ::= SEQUENCE {
802 * algorithm AlgorithmIdentifier,
803 * subjectPublicKey BIT STRING }
805 * AlgorithmIdentifier ::= SEQUENCE {
806 * algorithm OBJECT IDENTIFIER,
807 * parameters ANY DEFINED BY algorithm OPTIONAL }
809 * subjectPublicKey = compressed format public key per ANSI X9.63
810 * algorithm = ecPublicKey (1.2.840.10045.2.1)
811 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
812 * prime256v1 (1.2.840.10045.3.1.7)
816 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
820 wpa_printf(MSG_DEBUG
,
821 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
825 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
826 wpa_printf(MSG_DEBUG
,
827 "DPP: SubjectPublicKeyInfo does not describe an EC key");
832 res
= X509_PUBKEY_set(&pub
, pkey
);
834 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
838 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
840 wpa_printf(MSG_DEBUG
,
841 "DPP: Could not extract SubjectPublicKeyInfo parameters");
844 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
845 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
846 wpa_printf(MSG_DEBUG
,
847 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
850 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
851 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
852 wpa_printf(MSG_DEBUG
,
853 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
857 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
858 if (ptype
!= V_ASN1_OBJECT
) {
859 wpa_printf(MSG_DEBUG
,
860 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
864 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
865 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
866 wpa_printf(MSG_DEBUG
,
867 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
870 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
871 bi
->curve
= dpp_get_curve_oid(poid
);
873 wpa_printf(MSG_DEBUG
,
874 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
879 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
881 X509_PUBKEY_free(pub
);
885 X509_PUBKEY_free(pub
);
891 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
893 const char *pos
= uri
;
895 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
896 struct dpp_bootstrap_info
*bi
;
898 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
900 if (os_strncmp(pos
, "DPP:", 4) != 0) {
901 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
907 end
= os_strchr(pos
, ';');
912 /* Handle terminating ";;" and ignore unexpected ";"
913 * for parsing robustness. */
918 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
920 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
922 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
924 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
927 wpa_hexdump_ascii(MSG_DEBUG
,
928 "DPP: Ignore unrecognized URI parameter",
934 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
938 bi
= os_zalloc(sizeof(*bi
));
942 if (dpp_clone_uri(bi
, uri
) < 0 ||
943 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
944 dpp_parse_uri_mac(bi
, mac
) < 0 ||
945 dpp_parse_uri_info(bi
, info
) < 0 ||
946 dpp_parse_uri_pk(bi
, pk
) < 0) {
947 dpp_bootstrap_info_free(bi
);
955 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
957 struct dpp_bootstrap_info
*bi
;
959 bi
= dpp_parse_uri(uri
);
961 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
966 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
973 unsigned char *der
= NULL
;
976 out
= BIO_new(BIO_s_mem());
980 EVP_PKEY_print_private(out
, key
, 0, NULL
);
981 rlen
= BIO_ctrl_pending(out
);
982 txt
= os_malloc(rlen
+ 1);
984 res
= BIO_read(out
, txt
, rlen
);
987 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
993 eckey
= EVP_PKEY_get1_EC_KEY(key
);
997 der_len
= i2d_ECPrivateKey(eckey
, &der
);
999 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1003 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1005 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1013 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1015 #ifdef OPENSSL_IS_BORINGSSL
1016 EVP_PKEY_CTX
*kctx
= NULL
;
1017 const EC_GROUP
*group
;
1020 EVP_PKEY_CTX
*pctx
, *kctx
= NULL
;
1022 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1025 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1027 nid
= OBJ_txt2nid(curve
->name
);
1028 if (nid
== NID_undef
) {
1029 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1032 #ifdef OPENSSL_IS_BORINGSSL
1033 group
= EC_GROUP_new_by_curve_name(nid
);
1034 ec_params
= EC_KEY_new();
1035 if (!ec_params
|| EC_KEY_set_group(ec_params
, group
) != 1) {
1036 wpa_printf(MSG_ERROR
,
1037 "DPP: Failed to generate EC_KEY parameters");
1040 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1041 params
= EVP_PKEY_new();
1042 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1043 wpa_printf(MSG_ERROR
,
1044 "DPP: Failed to generate EVP_PKEY parameters");
1048 pctx
= EVP_PKEY_CTX_new_id(EVP_PKEY_EC
, NULL
);
1050 EVP_PKEY_paramgen_init(pctx
) != 1 ||
1051 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx
, nid
) != 1 ||
1052 EVP_PKEY_CTX_set_ec_param_enc(pctx
, OPENSSL_EC_NAMED_CURVE
) != 1 ||
1053 EVP_PKEY_paramgen(pctx
, ¶ms
) != 1) {
1054 wpa_printf(MSG_ERROR
,
1055 "DPP: Failed to generate EVP_PKEY parameters");
1056 EVP_PKEY_CTX_free(pctx
);
1059 EVP_PKEY_CTX_free(pctx
);
1062 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1064 EVP_PKEY_keygen_init(kctx
) != 1 ||
1065 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1066 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1070 if (wpa_debug_show_keys
)
1071 dpp_debug_print_key("Own generated key", key
);
1073 EVP_PKEY_free(params
);
1074 EVP_PKEY_CTX_free(kctx
);
1077 EVP_PKEY_CTX_free(kctx
);
1078 EVP_PKEY_free(params
);
1083 static const struct dpp_curve_params
*
1084 dpp_get_curve_name(const char *name
)
1088 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1089 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1090 (dpp_curves
[i
].jwk_crv
&&
1091 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1092 return &dpp_curves
[i
];
1098 static const struct dpp_curve_params
*
1099 dpp_get_curve_jwk_crv(const char *name
)
1103 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1104 if (dpp_curves
[i
].jwk_crv
&&
1105 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1106 return &dpp_curves
[i
];
1112 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1113 const u8
*privkey
, size_t privkey_len
)
1117 const EC_GROUP
*group
;
1120 pkey
= EVP_PKEY_new();
1123 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1125 wpa_printf(MSG_INFO
,
1126 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1127 ERR_error_string(ERR_get_error(), NULL
));
1128 EVP_PKEY_free(pkey
);
1131 group
= EC_KEY_get0_group(eckey
);
1134 EVP_PKEY_free(pkey
);
1137 nid
= EC_GROUP_get_curve_name(group
);
1138 *curve
= dpp_get_curve_nid(nid
);
1140 wpa_printf(MSG_INFO
,
1141 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1144 EVP_PKEY_free(pkey
);
1148 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1150 EVP_PKEY_free(pkey
);
1157 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1159 unsigned char *der
= NULL
;
1165 /* Need to get the compressed form of the public key through EC_KEY, so
1166 * cannot use the simpler i2d_PUBKEY() here. */
1167 eckey
= EVP_PKEY_get1_EC_KEY(bi
->pubkey
);
1170 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_COMPRESSED
);
1171 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1174 wpa_printf(MSG_ERROR
,
1175 "DDP: Failed to build DER encoded public key");
1181 res
= sha256_vector(1, (const u8
**) &der
, &len
, bi
->pubkey_hash
);
1184 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1189 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1190 const u8
*privkey
, size_t privkey_len
)
1192 unsigned char *base64
= NULL
;
1195 unsigned char *der
= NULL
;
1200 bi
->curve
= &dpp_curves
[0];
1202 bi
->curve
= dpp_get_curve_name(curve
);
1204 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1210 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1212 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1217 /* Need to get the compressed form of the public key through EC_KEY, so
1218 * cannot use the simpler i2d_PUBKEY() here. */
1219 eckey
= EVP_PKEY_get1_EC_KEY(bi
->pubkey
);
1222 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_COMPRESSED
);
1223 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1226 wpa_printf(MSG_ERROR
,
1227 "DDP: Failed to build DER encoded public key");
1232 if (sha256_vector(1, (const u8
**) &der
, &len
, bi
->pubkey_hash
) < 0) {
1233 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1237 base64
= base64_encode(der
, der_len
, &len
);
1242 pos
= (char *) base64
;
1245 pos
= os_strchr(pos
, '\n');
1248 os_memmove(pos
, pos
+ 1, end
- pos
);
1250 return (char *) base64
;
1258 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1259 unsigned int hash_len
)
1261 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1262 const char *info
= "first intermediate key";
1265 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1267 /* HKDF-Extract(<>, M.x) */
1268 os_memset(salt
, 0, hash_len
);
1269 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1271 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1274 /* HKDF-Expand(PRK, info, L) */
1275 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1276 os_memset(prk
, 0, hash_len
);
1280 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1286 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1287 unsigned int hash_len
)
1289 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1290 const char *info
= "second intermediate key";
1293 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1295 /* HKDF-Extract(<>, N.x) */
1296 os_memset(salt
, 0, hash_len
);
1297 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1300 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1303 /* HKDF-Expand(PRK, info, L) */
1304 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1305 os_memset(prk
, 0, hash_len
);
1309 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1315 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1316 unsigned int hash_len
)
1319 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1320 const char *info_ke
= "DPP Key";
1321 u8 prk
[DPP_MAX_HASH_LEN
];
1325 size_t num_elem
= 0;
1327 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1329 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1330 nonce_len
= auth
->curve
->nonce_len
;
1331 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1332 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1333 addr
[num_elem
] = auth
->Mx
;
1334 len
[num_elem
] = auth
->secret_len
;
1336 addr
[num_elem
] = auth
->Nx
;
1337 len
[num_elem
] = auth
->secret_len
;
1339 if (auth
->peer_bi
&& auth
->own_bi
) {
1340 addr
[num_elem
] = auth
->Lx
;
1341 len
[num_elem
] = auth
->secret_len
;
1344 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1345 num_elem
, addr
, len
, prk
);
1348 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1351 /* HKDF-Expand(PRK, info, L) */
1352 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1353 os_memset(prk
, 0, hash_len
);
1357 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1363 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1364 const struct wpabuf
*pi
,
1366 const u8
*r_pubkey_hash
,
1367 const u8
*i_pubkey_hash
,
1368 unsigned int neg_freq
)
1371 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1372 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1375 size_t len
[2], siv_len
, attr_len
;
1376 u8
*attr_start
, *attr_end
;
1378 /* Build DPP Authentication Request frame attributes */
1379 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1380 4 + sizeof(wrapped_data
);
1383 #ifdef CONFIG_TESTING_OPTIONS
1384 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1386 #endif /* CONFIG_TESTING_OPTIONS */
1387 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1391 attr_start
= wpabuf_put(msg
, 0);
1393 /* Responder Bootstrapping Key Hash */
1394 if (r_pubkey_hash
) {
1395 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1396 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1397 wpabuf_put_data(msg
, r_pubkey_hash
, SHA256_MAC_LEN
);
1400 /* Initiator Bootstrapping Key Hash */
1401 if (i_pubkey_hash
) {
1402 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1403 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1404 wpabuf_put_data(msg
, i_pubkey_hash
, SHA256_MAC_LEN
);
1407 /* Initiator Protocol Key */
1409 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1410 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1411 wpabuf_put_buf(msg
, pi
);
1416 u8 op_class
, channel
;
1418 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1420 NUM_HOSTAPD_MODES
) {
1421 wpa_printf(MSG_INFO
,
1422 "DPP: Unsupported negotiation frequency request: %d",
1427 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1428 wpabuf_put_le16(msg
, 2);
1429 wpabuf_put_u8(msg
, op_class
);
1430 wpabuf_put_u8(msg
, channel
);
1433 #ifdef CONFIG_TESTING_OPTIONS
1434 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1435 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1436 goto skip_wrapped_data
;
1438 #endif /* CONFIG_TESTING_OPTIONS */
1440 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1443 #ifdef CONFIG_TESTING_OPTIONS
1444 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1445 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1448 #endif /* CONFIG_TESTING_OPTIONS */
1451 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1453 WPA_PUT_LE16(pos
, nonce_len
);
1455 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1458 #ifdef CONFIG_TESTING_OPTIONS
1460 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1461 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1464 #endif /* CONFIG_TESTING_OPTIONS */
1466 /* I-capabilities */
1467 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1469 WPA_PUT_LE16(pos
, 1);
1471 auth
->i_capab
= auth
->allowed_roles
;
1472 *pos
++ = auth
->i_capab
;
1473 #ifdef CONFIG_TESTING_OPTIONS
1474 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1475 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1479 #endif /* CONFIG_TESTING_OPTIONS */
1481 attr_end
= wpabuf_put(msg
, 0);
1483 /* OUI, OUI type, Crypto Suite, DPP frame type */
1484 addr
[0] = wpabuf_head_u8(msg
) + 2;
1485 len
[0] = 3 + 1 + 1 + 1;
1486 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1488 /* Attributes before Wrapped Data */
1489 addr
[1] = attr_start
;
1490 len
[1] = attr_end
- attr_start
;
1491 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1493 siv_len
= pos
- clear
;
1494 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1495 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1496 2, addr
, len
, wrapped_data
) < 0) {
1500 siv_len
+= AES_BLOCK_SIZE
;
1501 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1502 wrapped_data
, siv_len
);
1504 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1505 wpabuf_put_le16(msg
, siv_len
);
1506 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1508 #ifdef CONFIG_TESTING_OPTIONS
1509 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1510 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1511 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
1512 wpabuf_put_le16(msg
, 0);
1515 #endif /* CONFIG_TESTING_OPTIONS */
1517 wpa_hexdump_buf(MSG_DEBUG
,
1518 "DPP: Authentication Request frame attributes", msg
);
1524 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1525 enum dpp_status_error status
,
1526 const struct wpabuf
*pr
,
1528 const u8
*r_pubkey_hash
,
1529 const u8
*i_pubkey_hash
,
1530 const u8
*r_nonce
, const u8
*i_nonce
,
1531 const u8
*wrapped_r_auth
,
1532 size_t wrapped_r_auth_len
,
1536 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1537 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1538 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1539 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1541 size_t len
[2], siv_len
, attr_len
;
1542 u8
*attr_start
, *attr_end
, *pos
;
1544 /* Build DPP Authentication Response frame attributes */
1545 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1546 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1547 #ifdef CONFIG_TESTING_OPTIONS
1548 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1550 #endif /* CONFIG_TESTING_OPTIONS */
1551 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1554 wpabuf_free(auth
->resp_msg
);
1556 attr_start
= wpabuf_put(msg
, 0);
1559 if (status
!= 255) {
1560 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1561 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1562 wpabuf_put_le16(msg
, 1);
1563 wpabuf_put_u8(msg
, status
);
1566 /* Responder Bootstrapping Key Hash */
1567 if (r_pubkey_hash
) {
1568 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1569 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1570 wpabuf_put_data(msg
, r_pubkey_hash
, SHA256_MAC_LEN
);
1573 /* Initiator Bootstrapping Key Hash */
1574 if (i_pubkey_hash
) {
1575 /* Mutual authentication */
1576 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1577 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1578 wpabuf_put_data(msg
, i_pubkey_hash
, SHA256_MAC_LEN
);
1581 /* Responder Protocol Key */
1583 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1584 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1585 wpabuf_put_buf(msg
, pr
);
1588 attr_end
= wpabuf_put(msg
, 0);
1590 #ifdef CONFIG_TESTING_OPTIONS
1591 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1592 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1593 goto skip_wrapped_data
;
1595 #endif /* CONFIG_TESTING_OPTIONS */
1597 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1602 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1604 WPA_PUT_LE16(pos
, nonce_len
);
1606 os_memcpy(pos
, r_nonce
, nonce_len
);
1612 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1614 WPA_PUT_LE16(pos
, nonce_len
);
1616 os_memcpy(pos
, i_nonce
, nonce_len
);
1617 #ifdef CONFIG_TESTING_OPTIONS
1618 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1619 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1620 pos
[nonce_len
/ 2] ^= 0x01;
1622 #endif /* CONFIG_TESTING_OPTIONS */
1626 #ifdef CONFIG_TESTING_OPTIONS
1627 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1628 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1631 #endif /* CONFIG_TESTING_OPTIONS */
1633 /* R-capabilities */
1634 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1636 WPA_PUT_LE16(pos
, 1);
1638 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1640 *pos
++ = auth
->r_capab
;
1641 #ifdef CONFIG_TESTING_OPTIONS
1642 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1643 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1645 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1646 wpa_printf(MSG_INFO
,
1647 "DPP: TESTING - incompatible R-capabilities");
1648 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1649 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1652 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1653 DPP_CAPAB_CONFIGURATOR
;
1656 #endif /* CONFIG_TESTING_OPTIONS */
1658 if (wrapped_r_auth
) {
1660 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1662 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1664 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1665 pos
+= wrapped_r_auth_len
;
1668 /* OUI, OUI type, Crypto Suite, DPP frame type */
1669 addr
[0] = wpabuf_head_u8(msg
) + 2;
1670 len
[0] = 3 + 1 + 1 + 1;
1671 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1673 /* Attributes before Wrapped Data */
1674 addr
[1] = attr_start
;
1675 len
[1] = attr_end
- attr_start
;
1676 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1678 siv_len
= pos
- clear
;
1679 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1680 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1681 2, addr
, len
, wrapped_data
) < 0) {
1685 siv_len
+= AES_BLOCK_SIZE
;
1686 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1687 wrapped_data
, siv_len
);
1689 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1690 wpabuf_put_le16(msg
, siv_len
);
1691 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1693 #ifdef CONFIG_TESTING_OPTIONS
1694 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1695 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1696 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
1697 wpabuf_put_le16(msg
, 0);
1700 #endif /* CONFIG_TESTING_OPTIONS */
1702 wpa_hexdump_buf(MSG_DEBUG
,
1703 "DPP: Authentication Response frame attributes", msg
);
1708 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1709 u16 num_modes
, unsigned int freq
)
1714 if (!own_modes
|| !num_modes
)
1717 for (m
= 0; m
< num_modes
; m
++) {
1718 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1719 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1722 flag
= own_modes
[m
].channels
[c
].flag
;
1723 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1724 HOSTAPD_CHAN_NO_IR
|
1725 HOSTAPD_CHAN_RADAR
)))
1730 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1735 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1739 if (freqs
[--num
] == freq
)
1746 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1751 for (i
= 0; i
< num
; i
++) {
1752 if (freqs
[i
] == freq
)
1755 if (i
== 0 || i
>= num
)
1757 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1762 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1763 struct hostapd_hw_modes
*own_modes
,
1766 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1767 unsigned int i
, freq
;
1769 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
1770 freq
= peer_bi
->freq
[i
];
1771 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1773 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
1774 auth
->freq
[auth
->num_freq
++] = freq
;
1776 if (!auth
->num_freq
) {
1777 wpa_printf(MSG_INFO
,
1778 "DPP: No available channels for initiating DPP Authentication");
1781 auth
->curr_freq
= auth
->freq
[0];
1786 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
1787 struct hostapd_hw_modes
*own_modes
,
1796 if (!own_modes
|| !num_modes
) {
1797 auth
->freq
[0] = 2412;
1798 auth
->freq
[1] = 2437;
1799 auth
->freq
[2] = 2462;
1804 for (m
= 0; m
< num_modes
; m
++) {
1805 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1806 freq
= own_modes
[m
].channels
[c
].freq
;
1807 flag
= own_modes
[m
].channels
[c
].flag
;
1808 if (flag
& (HOSTAPD_CHAN_DISABLED
|
1809 HOSTAPD_CHAN_NO_IR
|
1810 HOSTAPD_CHAN_RADAR
))
1812 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1814 auth
->freq
[auth
->num_freq
++] = freq
;
1815 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
1822 return auth
->num_freq
== 0 ? -1 : 0;
1826 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
1827 struct hostapd_hw_modes
*own_modes
,
1831 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
1834 if (auth
->peer_bi
->num_freq
> 0)
1835 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
1837 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
1841 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1842 * likely channels first. */
1843 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
1844 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
1845 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
1848 auth
->curr_freq
= auth
->freq
[0];
1851 end
= pos
+ sizeof(freqs
);
1852 for (i
= 0; i
< auth
->num_freq
; i
++) {
1853 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
1854 if (os_snprintf_error(end
- pos
, res
))
1859 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
1866 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
1867 struct dpp_bootstrap_info
*peer_bi
,
1868 struct dpp_bootstrap_info
*own_bi
,
1869 u8 dpp_allowed_roles
,
1870 unsigned int neg_freq
,
1871 struct hostapd_hw_modes
*own_modes
,
1874 struct dpp_authentication
*auth
;
1876 EVP_PKEY_CTX
*ctx
= NULL
;
1878 struct wpabuf
*pi
= NULL
;
1879 u8 zero
[SHA256_MAC_LEN
];
1880 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
1882 auth
= os_zalloc(sizeof(*auth
));
1885 auth
->msg_ctx
= msg_ctx
;
1886 auth
->initiator
= 1;
1887 auth
->waiting_auth_resp
= 1;
1888 auth
->allowed_roles
= dpp_allowed_roles
;
1889 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
1890 auth
->peer_bi
= peer_bi
;
1891 auth
->own_bi
= own_bi
;
1892 auth
->curve
= peer_bi
->curve
;
1894 if (dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
1897 nonce_len
= auth
->curve
->nonce_len
;
1898 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
1899 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
1902 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
1904 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
1905 if (!auth
->own_protocol_key
)
1908 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1912 /* ECDH: M = pI * BR */
1913 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
1915 EVP_PKEY_derive_init(ctx
) != 1 ||
1916 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
1917 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
1918 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
1919 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
1920 wpa_printf(MSG_ERROR
,
1921 "DPP: Failed to derive ECDH shared secret: %s",
1922 ERR_error_string(ERR_get_error(), NULL
));
1925 auth
->secret_len
= secret_len
;
1926 EVP_PKEY_CTX_free(ctx
);
1929 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
1930 auth
->Mx
, auth
->secret_len
);
1932 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
1933 auth
->curve
->hash_len
) < 0)
1936 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
1939 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
1941 os_memset(zero
, 0, SHA256_MAC_LEN
);
1942 i_pubkey_hash
= zero
;
1945 #ifdef CONFIG_TESTING_OPTIONS
1946 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
1947 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
1948 r_pubkey_hash
= NULL
;
1949 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
1950 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
1951 i_pubkey_hash
= NULL
;
1952 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
1953 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
1957 #endif /* CONFIG_TESTING_OPTIONS */
1959 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
1960 i_pubkey_hash
, neg_freq
);
1966 EVP_PKEY_CTX_free(ctx
);
1969 dpp_auth_deinit(auth
);
1975 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
1979 size_t json_len
, clear_len
;
1980 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
1984 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
1986 nonce_len
= auth
->curve
->nonce_len
;
1987 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
1988 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
1991 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
1992 json_len
= os_strlen(json
);
1993 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
1995 /* { E-nonce, configAttrib }ke */
1996 clear_len
= 4 + nonce_len
+ 4 + json_len
;
1997 clear
= wpabuf_alloc(clear_len
);
1998 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
1999 #ifdef CONFIG_TESTING_OPTIONS
2000 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2002 #endif /* CONFIG_TESTING_OPTIONS */
2003 msg
= wpabuf_alloc(attr_len
);
2007 #ifdef CONFIG_TESTING_OPTIONS
2008 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2009 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2012 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2013 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2014 goto skip_wrapped_data
;
2016 #endif /* CONFIG_TESTING_OPTIONS */
2019 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2020 wpabuf_put_le16(clear
, nonce_len
);
2021 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2023 #ifdef CONFIG_TESTING_OPTIONS
2025 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2026 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2027 goto skip_conf_attr_obj
;
2029 #endif /* CONFIG_TESTING_OPTIONS */
2032 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2033 wpabuf_put_le16(clear
, json_len
);
2034 wpabuf_put_data(clear
, json
, json_len
);
2036 #ifdef CONFIG_TESTING_OPTIONS
2038 #endif /* CONFIG_TESTING_OPTIONS */
2040 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2041 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2042 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2045 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2046 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2047 wpabuf_head(clear
), wpabuf_len(clear
),
2048 0, NULL
, NULL
, wrapped
) < 0)
2050 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2051 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2053 #ifdef CONFIG_TESTING_OPTIONS
2054 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2055 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2056 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
2057 wpabuf_put_le16(msg
, 0);
2060 #endif /* CONFIG_TESTING_OPTIONS */
2062 wpa_hexdump_buf(MSG_DEBUG
,
2063 "DPP: Configuration Request frame attributes", msg
);
2074 static void dpp_auth_success(struct dpp_authentication
*auth
)
2076 wpa_printf(MSG_DEBUG
,
2077 "DPP: Authentication success - clear temporary keys");
2078 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2079 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2080 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2081 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2082 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2084 auth
->auth_success
= 1;
2088 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2090 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2093 size_t i
, num_elem
= 0;
2098 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2099 nonce_len
= auth
->curve
->nonce_len
;
2101 if (auth
->initiator
) {
2102 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2103 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2105 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2108 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2110 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2111 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2113 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2116 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2118 if (!pix
|| !prx
|| !brx
)
2121 addr
[num_elem
] = auth
->i_nonce
;
2122 len
[num_elem
] = nonce_len
;
2125 addr
[num_elem
] = auth
->r_nonce
;
2126 len
[num_elem
] = nonce_len
;
2129 addr
[num_elem
] = wpabuf_head(pix
);
2130 len
[num_elem
] = wpabuf_len(pix
) / 2;
2133 addr
[num_elem
] = wpabuf_head(prx
);
2134 len
[num_elem
] = wpabuf_len(prx
) / 2;
2138 addr
[num_elem
] = wpabuf_head(bix
);
2139 len
[num_elem
] = wpabuf_len(bix
) / 2;
2143 addr
[num_elem
] = wpabuf_head(brx
);
2144 len
[num_elem
] = wpabuf_len(brx
) / 2;
2147 addr
[num_elem
] = &zero
;
2151 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2152 for (i
= 0; i
< num_elem
; i
++)
2153 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2154 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2156 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2157 auth
->curve
->hash_len
);
2167 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2169 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2172 size_t i
, num_elem
= 0;
2177 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2178 nonce_len
= auth
->curve
->nonce_len
;
2180 if (auth
->initiator
) {
2181 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2182 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2184 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2189 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2191 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2192 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2194 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2199 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2201 if (!pix
|| !prx
|| !brx
)
2204 addr
[num_elem
] = auth
->r_nonce
;
2205 len
[num_elem
] = nonce_len
;
2208 addr
[num_elem
] = auth
->i_nonce
;
2209 len
[num_elem
] = nonce_len
;
2212 addr
[num_elem
] = wpabuf_head(prx
);
2213 len
[num_elem
] = wpabuf_len(prx
) / 2;
2216 addr
[num_elem
] = wpabuf_head(pix
);
2217 len
[num_elem
] = wpabuf_len(pix
) / 2;
2220 addr
[num_elem
] = wpabuf_head(brx
);
2221 len
[num_elem
] = wpabuf_len(brx
) / 2;
2225 addr
[num_elem
] = wpabuf_head(bix
);
2226 len
[num_elem
] = wpabuf_len(bix
) / 2;
2230 addr
[num_elem
] = &one
;
2234 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2235 for (i
= 0; i
< num_elem
; i
++)
2236 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2237 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2239 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2240 auth
->curve
->hash_len
);
2250 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2252 const EC_GROUP
*group
;
2254 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2255 const EC_POINT
*BI_point
;
2257 BIGNUM
*lx
, *sum
, *q
;
2258 const BIGNUM
*bR_bn
, *pR_bn
;
2261 /* L = ((bR + pR) modulo q) * BI */
2263 bnctx
= BN_CTX_new();
2267 if (!bnctx
|| !sum
|| !q
|| !lx
)
2269 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2272 BI_point
= EC_KEY_get0_public_key(BI
);
2273 group
= EC_KEY_get0_group(BI
);
2277 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2278 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2281 bR_bn
= EC_KEY_get0_private_key(bR
);
2282 pR_bn
= EC_KEY_get0_private_key(pR
);
2283 if (!bR_bn
|| !pR_bn
)
2285 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2286 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2288 l
= EC_POINT_new(group
);
2290 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2291 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2293 wpa_printf(MSG_ERROR
,
2294 "OpenSSL: failed: %s",
2295 ERR_error_string(ERR_get_error(), NULL
));
2299 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2301 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2304 EC_POINT_clear_free(l
);
2316 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2318 const EC_GROUP
*group
;
2319 EC_POINT
*l
= NULL
, *sum
= NULL
;
2320 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2321 const EC_POINT
*BR_point
, *PR_point
;
2324 const BIGNUM
*bI_bn
;
2327 /* L = bI * (BR + PR) */
2329 bnctx
= BN_CTX_new();
2333 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2334 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2337 BR_point
= EC_KEY_get0_public_key(BR
);
2338 PR_point
= EC_KEY_get0_public_key(PR
);
2340 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2343 group
= EC_KEY_get0_group(bI
);
2344 bI_bn
= EC_KEY_get0_private_key(bI
);
2345 if (!group
|| !bI_bn
)
2347 sum
= EC_POINT_new(group
);
2348 l
= EC_POINT_new(group
);
2350 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2351 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2352 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2354 wpa_printf(MSG_ERROR
,
2355 "OpenSSL: failed: %s",
2356 ERR_error_string(ERR_get_error(), NULL
));
2360 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2362 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2365 EC_POINT_clear_free(l
);
2375 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2378 EVP_PKEY_CTX
*ctx
= NULL
;
2380 struct wpabuf
*msg
, *pr
= NULL
;
2381 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2382 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2383 size_t wrapped_r_auth_len
;
2385 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2386 enum dpp_status_error status
= DPP_STATUS_OK
;
2388 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2390 nonce_len
= auth
->curve
->nonce_len
;
2391 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2392 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2395 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2397 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2398 if (!auth
->own_protocol_key
)
2401 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2405 /* ECDH: N = pR * PI */
2406 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2408 EVP_PKEY_derive_init(ctx
) != 1 ||
2409 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2410 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2411 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2412 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2413 wpa_printf(MSG_ERROR
,
2414 "DPP: Failed to derive ECDH shared secret: %s",
2415 ERR_error_string(ERR_get_error(), NULL
));
2418 EVP_PKEY_CTX_free(ctx
);
2421 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2422 auth
->Nx
, auth
->secret_len
);
2424 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2425 auth
->curve
->hash_len
) < 0)
2428 if (auth
->own_bi
&& auth
->peer_bi
) {
2429 /* Mutual authentication */
2430 if (dpp_auth_derive_l_responder(auth
) < 0)
2434 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2437 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2438 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2439 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2440 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2442 #ifdef CONFIG_TESTING_OPTIONS
2443 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2444 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2445 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2447 #endif /* CONFIG_TESTING_OPTIONS */
2448 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2449 r_auth
, 4 + auth
->curve
->hash_len
,
2450 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2452 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2453 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2454 wrapped_r_auth
, wrapped_r_auth_len
);
2455 w_r_auth
= wrapped_r_auth
;
2457 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2459 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2461 i_pubkey_hash
= NULL
;
2463 i_nonce
= auth
->i_nonce
;
2464 r_nonce
= auth
->r_nonce
;
2466 #ifdef CONFIG_TESTING_OPTIONS
2467 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2468 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2469 r_pubkey_hash
= NULL
;
2470 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2471 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2472 i_pubkey_hash
= NULL
;
2473 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2474 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2477 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2478 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2480 wrapped_r_auth_len
= 0;
2481 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2482 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2484 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2485 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2487 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2488 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2491 #endif /* CONFIG_TESTING_OPTIONS */
2493 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2494 r_pubkey_hash
, i_pubkey_hash
,
2496 w_r_auth
, wrapped_r_auth_len
,
2500 auth
->resp_msg
= msg
;
2508 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2509 enum dpp_status_error status
)
2512 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2514 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2516 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2518 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2520 i_pubkey_hash
= NULL
;
2522 i_nonce
= auth
->i_nonce
;
2524 #ifdef CONFIG_TESTING_OPTIONS
2525 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2526 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2527 r_pubkey_hash
= NULL
;
2528 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2529 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2530 i_pubkey_hash
= NULL
;
2531 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2532 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2534 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2535 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2538 #endif /* CONFIG_TESTING_OPTIONS */
2540 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
2541 r_pubkey_hash
, i_pubkey_hash
,
2542 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
2545 auth
->resp_msg
= msg
;
2550 struct dpp_authentication
*
2551 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
2552 struct dpp_bootstrap_info
*peer_bi
,
2553 struct dpp_bootstrap_info
*own_bi
,
2554 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
2557 EVP_PKEY
*pi
= NULL
;
2558 EVP_PKEY_CTX
*ctx
= NULL
;
2562 u8
*unwrapped
= NULL
;
2563 size_t unwrapped_len
= 0;
2564 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
2566 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
2567 i_bootstrap_len
, channel_len
;
2568 struct dpp_authentication
*auth
= NULL
;
2570 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2572 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
2573 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
2574 "Missing or invalid required Wrapped Data attribute");
2577 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
2578 wrapped_data
, wrapped_data_len
);
2579 attr_len
= wrapped_data
- 4 - attr_start
;
2581 auth
= os_zalloc(sizeof(*auth
));
2584 auth
->msg_ctx
= msg_ctx
;
2585 auth
->peer_bi
= peer_bi
;
2586 auth
->own_bi
= own_bi
;
2587 auth
->curve
= own_bi
->curve
;
2588 auth
->curr_freq
= freq
;
2590 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
2595 if (channel_len
< 2) {
2596 dpp_auth_fail(auth
, "Too short Channel attribute");
2600 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
2601 wpa_printf(MSG_DEBUG
,
2602 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2603 channel
[0], channel
[1], neg_freq
);
2606 "Unsupported Channel attribute value");
2610 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
2611 wpa_printf(MSG_DEBUG
,
2612 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2614 auth
->curr_freq
= neg_freq
;
2618 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
2622 "Missing required Initiator Protocol Key attribute");
2625 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
2626 i_proto
, i_proto_len
);
2629 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
2631 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
2634 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
2636 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
2638 EVP_PKEY_derive_init(ctx
) != 1 ||
2639 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
2640 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2641 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2642 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2643 wpa_printf(MSG_ERROR
,
2644 "DPP: Failed to derive ECDH shared secret: %s",
2645 ERR_error_string(ERR_get_error(), NULL
));
2646 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
2649 auth
->secret_len
= secret_len
;
2650 EVP_PKEY_CTX_free(ctx
);
2653 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2654 auth
->Mx
, auth
->secret_len
);
2656 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2657 auth
->curve
->hash_len
) < 0)
2661 len
[0] = DPP_HDR_LEN
;
2662 addr
[1] = attr_start
;
2664 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2665 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2666 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2667 wrapped_data
, wrapped_data_len
);
2668 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2669 unwrapped
= os_malloc(unwrapped_len
);
2672 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
2673 wrapped_data
, wrapped_data_len
,
2674 2, addr
, len
, unwrapped
) < 0) {
2675 dpp_auth_fail(auth
, "AES-SIV decryption failed");
2678 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2679 unwrapped
, unwrapped_len
);
2681 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
2682 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
2686 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
2688 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
2689 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
2692 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
2693 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
2695 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
2696 DPP_ATTR_I_CAPABILITIES
,
2698 if (!i_capab
|| i_capab_len
< 1) {
2699 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
2702 auth
->i_capab
= i_capab
[0];
2703 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
2705 bin_clear_free(unwrapped
, unwrapped_len
);
2708 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
2709 case DPP_CAPAB_ENROLLEE
:
2710 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
2711 wpa_printf(MSG_DEBUG
,
2712 "DPP: Local policy does not allow Configurator role");
2713 goto not_compatible
;
2715 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
2716 auth
->configurator
= 1;
2718 case DPP_CAPAB_CONFIGURATOR
:
2719 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
2720 wpa_printf(MSG_DEBUG
,
2721 "DPP: Local policy does not allow Enrollee role");
2722 goto not_compatible
;
2724 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
2725 auth
->configurator
= 0;
2727 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
2728 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
2729 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
2730 auth
->configurator
= 0;
2731 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
2732 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
2733 auth
->configurator
= 1;
2735 wpa_printf(MSG_DEBUG
,
2736 "DPP: Local policy does not allow Configurator/Enrollee role");
2737 goto not_compatible
;
2741 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
2742 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
2743 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
2744 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
2748 auth
->peer_protocol_key
= pi
;
2750 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
2751 char hex
[SHA256_MAC_LEN
* 2 + 1];
2753 wpa_printf(MSG_DEBUG
,
2754 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2755 if (dpp_auth_build_resp_status(auth
,
2756 DPP_STATUS_RESPONSE_PENDING
) < 0)
2758 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2759 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
2761 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
2762 auth
->response_pending
= 1;
2763 os_memcpy(auth
->waiting_pubkey_hash
,
2764 i_bootstrap
, i_bootstrap_len
);
2765 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
2771 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
2775 if (dpp_auth_build_resp_ok(auth
) < 0)
2781 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
2782 "i-capab=0x%02x", auth
->i_capab
);
2783 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
2784 auth
->configurator
= 1;
2786 auth
->configurator
= 0;
2787 auth
->peer_protocol_key
= pi
;
2789 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
2792 auth
->remove_on_tx_status
= 1;
2795 bin_clear_free(unwrapped
, unwrapped_len
);
2797 EVP_PKEY_CTX_free(ctx
);
2798 dpp_auth_deinit(auth
);
2803 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
2804 struct dpp_bootstrap_info
*peer_bi
)
2806 if (!auth
|| !auth
->response_pending
||
2807 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
2808 SHA256_MAC_LEN
) != 0)
2811 wpa_printf(MSG_DEBUG
,
2812 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2813 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
2814 auth
->peer_bi
= peer_bi
;
2816 if (dpp_auth_build_resp_ok(auth
) < 0)
2823 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
2824 enum dpp_status_error status
)
2827 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
2829 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
2832 size_t len
[2], attr_len
;
2834 u8
*wrapped_r_nonce
;
2835 u8
*attr_start
, *attr_end
;
2837 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
2839 i_auth_len
= 4 + auth
->curve
->hash_len
;
2840 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
2841 /* Build DPP Authentication Confirmation frame attributes */
2842 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
2843 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
2844 #ifdef CONFIG_TESTING_OPTIONS
2845 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
2847 #endif /* CONFIG_TESTING_OPTIONS */
2848 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
2852 attr_start
= wpabuf_put(msg
, 0);
2854 #ifdef CONFIG_TESTING_OPTIONS
2855 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
)
2857 #endif /* CONFIG_TESTING_OPTIONS */
2860 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
2861 wpabuf_put_le16(msg
, 1);
2862 wpabuf_put_u8(msg
, status
);
2864 #ifdef CONFIG_TESTING_OPTIONS
2866 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
)
2867 goto skip_r_bootstrap_key
;
2868 #endif /* CONFIG_TESTING_OPTIONS */
2870 /* Responder Bootstrapping Key Hash */
2871 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
2872 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2873 wpabuf_put_data(msg
, auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2875 #ifdef CONFIG_TESTING_OPTIONS
2876 skip_r_bootstrap_key
:
2877 if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
)
2878 goto skip_i_bootstrap_key
;
2879 #endif /* CONFIG_TESTING_OPTIONS */
2882 /* Mutual authentication */
2883 /* Initiator Bootstrapping Key Hash */
2884 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
2885 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2886 wpabuf_put_data(msg
, auth
->own_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2889 #ifdef CONFIG_TESTING_OPTIONS
2890 skip_i_bootstrap_key
:
2891 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
2892 goto skip_wrapped_data
;
2893 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
2895 #endif /* CONFIG_TESTING_OPTIONS */
2897 attr_end
= wpabuf_put(msg
, 0);
2899 /* OUI, OUI type, Crypto Suite, DPP frame type */
2900 addr
[0] = wpabuf_head_u8(msg
) + 2;
2901 len
[0] = 3 + 1 + 1 + 1;
2902 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2904 /* Attributes before Wrapped Data */
2905 addr
[1] = attr_start
;
2906 len
[1] = attr_end
- attr_start
;
2907 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2909 if (status
== DPP_STATUS_OK
) {
2910 /* I-auth wrapped with ke */
2911 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2912 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
2913 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
2915 #ifdef CONFIG_TESTING_OPTIONS
2916 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
2918 #endif /* CONFIG_TESTING_OPTIONS */
2920 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
2922 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
2923 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
2924 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
2927 #ifdef CONFIG_TESTING_OPTIONS
2928 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
2929 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
2930 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2933 #endif /* CONFIG_TESTING_OPTIONS */
2934 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2936 2, addr
, len
, wrapped_i_auth
) < 0)
2938 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
2939 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
2941 /* R-nonce wrapped with k2 */
2942 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2943 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
2944 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
2946 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
2947 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
2948 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
2950 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
2951 r_nonce
, r_nonce_len
,
2952 2, addr
, len
, wrapped_r_nonce
) < 0)
2954 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
2955 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
2958 #ifdef CONFIG_TESTING_OPTIONS
2959 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
2960 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2961 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
2962 wpabuf_put_le16(msg
, 0);
2965 #endif /* CONFIG_TESTING_OPTIONS */
2967 wpa_hexdump_buf(MSG_DEBUG
,
2968 "DPP: Authentication Confirmation frame attributes",
2970 if (status
== DPP_STATUS_OK
)
2971 dpp_auth_success(auth
);
2981 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
2982 const u8
*attr_start
, size_t attr_len
,
2983 const u8
*wrapped_data
, u16 wrapped_data_len
,
2984 enum dpp_status_error status
)
2988 u8
*unwrapped
= NULL
;
2989 size_t unwrapped_len
= 0;
2990 const u8
*i_nonce
, *r_capab
;
2991 u16 i_nonce_len
, r_capab_len
;
2993 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
2994 wpa_printf(MSG_DEBUG
,
2995 "DPP: Responder reported incompatible roles");
2996 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
2997 wpa_printf(MSG_DEBUG
,
2998 "DPP: Responder reported more time needed");
3000 wpa_printf(MSG_DEBUG
,
3001 "DPP: Responder reported failure (status %d)",
3003 dpp_auth_fail(auth
, "Responder reported failure");
3008 len
[0] = DPP_HDR_LEN
;
3009 addr
[1] = attr_start
;
3011 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3012 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3013 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3014 wrapped_data
, wrapped_data_len
);
3015 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3016 unwrapped
= os_malloc(unwrapped_len
);
3019 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3020 wrapped_data
, wrapped_data_len
,
3021 2, addr
, len
, unwrapped
) < 0) {
3022 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3025 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3026 unwrapped
, unwrapped_len
);
3028 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3029 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3033 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3035 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3036 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3039 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3040 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3041 dpp_auth_fail(auth
, "I-nonce mismatch");
3045 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3046 DPP_ATTR_R_CAPABILITIES
,
3048 if (!r_capab
|| r_capab_len
< 1) {
3049 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3052 auth
->r_capab
= r_capab
[0];
3053 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3054 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3055 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3056 "r-capab=0x%02x", auth
->r_capab
);
3057 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3058 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3060 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3061 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3062 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3063 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3066 wpa_printf(MSG_DEBUG
,
3067 "DPP: Continue waiting for full DPP Authentication Response");
3068 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_RESPONSE_PENDING
);
3072 bin_clear_free(unwrapped
, unwrapped_len
);
3077 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3078 const u8
*attr_start
, size_t attr_len
)
3081 EVP_PKEY_CTX
*ctx
= NULL
;
3085 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3086 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3087 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3088 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3089 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3090 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3091 wrapped2_len
, r_auth_len
;
3092 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3095 auth
->waiting_auth_resp
= 0;
3097 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3099 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3101 "Missing or invalid required Wrapped Data attribute");
3104 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3105 wrapped_data
, wrapped_data_len
);
3107 attr_len
= wrapped_data
- 4 - attr_start
;
3109 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3110 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3112 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3114 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3117 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3118 r_bootstrap
, r_bootstrap_len
);
3119 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3120 SHA256_MAC_LEN
) != 0) {
3122 "Unexpected Responder Bootstrapping Key Hash value");
3123 wpa_hexdump(MSG_DEBUG
,
3124 "DPP: Expected Responder Bootstrapping Key Hash",
3125 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3129 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3130 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3133 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3135 "Invalid Initiator Bootstrapping Key Hash attribute");
3138 wpa_hexdump(MSG_MSGDUMP
,
3139 "DPP: Initiator Bootstrapping Key Hash",
3140 i_bootstrap
, i_bootstrap_len
);
3141 if (!auth
->own_bi
||
3142 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3143 SHA256_MAC_LEN
) != 0) {
3145 "Initiator Bootstrapping Key Hash attribute did not match");
3148 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3149 /* PKEX bootstrapping mandates use of mutual authentication */
3151 "Missing Initiator Bootstrapping Key Hash attribute");
3155 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3157 if (!status
|| status_len
< 1) {
3159 "Missing or invalid required DPP Status attribute");
3162 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3163 auth
->auth_resp_status
= status
[0];
3164 if (status
[0] != DPP_STATUS_OK
) {
3165 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3166 attr_len
, wrapped_data
,
3167 wrapped_data_len
, status
[0]);
3171 if (!i_bootstrap
&& auth
->own_bi
) {
3172 wpa_printf(MSG_DEBUG
,
3173 "DPP: Responder decided not to use mutual authentication");
3174 auth
->own_bi
= NULL
;
3177 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3181 "Missing required Responder Protocol Key attribute");
3184 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3185 r_proto
, r_proto_len
);
3188 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3190 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3193 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3195 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3197 EVP_PKEY_derive_init(ctx
) != 1 ||
3198 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3199 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3200 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3201 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3202 wpa_printf(MSG_ERROR
,
3203 "DPP: Failed to derive ECDH shared secret: %s",
3204 ERR_error_string(ERR_get_error(), NULL
));
3205 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3208 EVP_PKEY_CTX_free(ctx
);
3210 auth
->peer_protocol_key
= pr
;
3213 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3214 auth
->Nx
, auth
->secret_len
);
3216 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3217 auth
->curve
->hash_len
) < 0)
3221 len
[0] = DPP_HDR_LEN
;
3222 addr
[1] = attr_start
;
3224 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3225 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3226 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3227 wrapped_data
, wrapped_data_len
);
3228 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3229 unwrapped
= os_malloc(unwrapped_len
);
3232 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3233 wrapped_data
, wrapped_data_len
,
3234 2, addr
, len
, unwrapped
) < 0) {
3235 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3238 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3239 unwrapped
, unwrapped_len
);
3241 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3242 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3246 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3248 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3249 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3252 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3253 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3255 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3257 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3258 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3261 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3262 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3263 dpp_auth_fail(auth
, "I-nonce mismatch");
3267 if (auth
->own_bi
&& auth
->peer_bi
) {
3268 /* Mutual authentication */
3269 if (dpp_auth_derive_l_initiator(auth
) < 0)
3273 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3274 DPP_ATTR_R_CAPABILITIES
,
3276 if (!r_capab
|| r_capab_len
< 1) {
3277 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3280 auth
->r_capab
= r_capab
[0];
3281 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3282 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3283 if ((auth
->allowed_roles
==
3284 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3285 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3286 /* Peer selected its role, so move from "either role" to the
3287 * role that is compatible with peer's selection. */
3288 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3289 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3290 auth
->configurator
? "Configurator" : "Enrollee");
3291 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3292 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3293 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3294 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3295 "Unexpected role in R-capabilities 0x%02x",
3297 if (role
!= DPP_CAPAB_ENROLLEE
&&
3298 role
!= DPP_CAPAB_CONFIGURATOR
)
3300 bin_clear_free(unwrapped
, unwrapped_len
);
3301 auth
->remove_on_tx_status
= 1;
3302 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3305 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3306 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3307 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3309 "Missing or invalid Secondary Wrapped Data");
3313 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3314 wrapped2
, wrapped2_len
);
3316 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3319 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3320 unwrapped2
= os_malloc(unwrapped2_len
);
3323 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3324 wrapped2
, wrapped2_len
,
3325 0, NULL
, NULL
, unwrapped2
) < 0) {
3326 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3329 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3330 unwrapped2
, unwrapped2_len
);
3332 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3334 "Invalid attribute in secondary unwrapped data");
3338 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3340 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3342 "Missing or invalid Responder Authenticating Tag");
3345 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3346 r_auth
, r_auth_len
);
3347 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3348 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3350 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3351 r_auth2
, r_auth_len
);
3352 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3353 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3354 bin_clear_free(unwrapped
, unwrapped_len
);
3355 bin_clear_free(unwrapped2
, unwrapped2_len
);
3356 auth
->remove_on_tx_status
= 1;
3357 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3360 bin_clear_free(unwrapped
, unwrapped_len
);
3361 bin_clear_free(unwrapped2
, unwrapped2_len
);
3363 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3366 bin_clear_free(unwrapped
, unwrapped_len
);
3367 bin_clear_free(unwrapped2
, unwrapped2_len
);
3369 EVP_PKEY_CTX_free(ctx
);
3374 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3376 const u8
*attr_start
, size_t attr_len
,
3377 const u8
*wrapped_data
,
3378 u16 wrapped_data_len
,
3379 enum dpp_status_error status
)
3383 u8
*unwrapped
= NULL
;
3384 size_t unwrapped_len
= 0;
3388 /* Authentication Confirm failure cases are expected to include
3389 * {R-nonce}k2 in the Wrapped Data attribute. */
3392 len
[0] = DPP_HDR_LEN
;
3393 addr
[1] = attr_start
;
3395 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3396 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3397 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3398 wrapped_data
, wrapped_data_len
);
3399 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3400 unwrapped
= os_malloc(unwrapped_len
);
3402 dpp_auth_fail(auth
, "Authentication failed");
3405 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3406 wrapped_data
, wrapped_data_len
,
3407 2, addr
, len
, unwrapped
) < 0) {
3408 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3411 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3412 unwrapped
, unwrapped_len
);
3414 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3415 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3419 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3421 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3422 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3425 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3426 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3427 r_nonce
, r_nonce_len
);
3428 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3429 auth
->r_nonce
, r_nonce_len
);
3430 dpp_auth_fail(auth
, "R-nonce mismatch");
3434 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3435 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3436 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3437 dpp_auth_fail(auth
, "Peer reported authentication failure)");
3440 bin_clear_free(unwrapped
, unwrapped_len
);
3445 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3446 const u8
*attr_start
, size_t attr_len
)
3448 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
3449 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3453 u8
*unwrapped
= NULL
;
3454 size_t unwrapped_len
= 0;
3455 u8 i_auth2
[DPP_MAX_HASH_LEN
];
3457 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3459 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3461 "Missing or invalid required Wrapped Data attribute");
3464 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3465 wrapped_data
, wrapped_data_len
);
3467 attr_len
= wrapped_data
- 4 - attr_start
;
3469 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3470 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3472 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3474 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3477 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3478 r_bootstrap
, r_bootstrap_len
);
3479 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
3480 SHA256_MAC_LEN
) != 0) {
3481 wpa_hexdump(MSG_DEBUG
,
3482 "DPP: Expected Responder Bootstrapping Key Hash",
3483 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3485 "Responder Bootstrapping Key Hash mismatch");
3489 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3490 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3493 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3495 "Invalid Initiator Bootstrapping Key Hash attribute");
3498 wpa_hexdump(MSG_MSGDUMP
,
3499 "DPP: Initiator Bootstrapping Key Hash",
3500 i_bootstrap
, i_bootstrap_len
);
3501 if (!auth
->peer_bi
||
3502 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3503 SHA256_MAC_LEN
) != 0) {
3505 "Initiator Bootstrapping Key Hash mismatch");
3508 } else if (auth
->own_bi
&& auth
->peer_bi
) {
3509 /* Mutual authentication and peer did not include its
3510 * Bootstrapping Key Hash attribute. */
3512 "Missing Initiator Bootstrapping Key Hash attribute");
3516 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3518 if (!status
|| status_len
< 1) {
3520 "Missing or invalid required DPP Status attribute");
3523 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3524 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
3525 status
[0] == DPP_STATUS_AUTH_FAILURE
)
3526 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
3527 attr_len
, wrapped_data
,
3528 wrapped_data_len
, status
[0]);
3530 if (status
[0] != DPP_STATUS_OK
) {
3531 dpp_auth_fail(auth
, "Authentication failed");
3536 len
[0] = DPP_HDR_LEN
;
3537 addr
[1] = attr_start
;
3539 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3540 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3541 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3542 wrapped_data
, wrapped_data_len
);
3543 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3544 unwrapped
= os_malloc(unwrapped_len
);
3547 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3548 wrapped_data
, wrapped_data_len
,
3549 2, addr
, len
, unwrapped
) < 0) {
3550 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3553 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3554 unwrapped
, unwrapped_len
);
3556 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3557 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3561 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
3563 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
3565 "Missing or invalid Initiator Authenticating Tag");
3568 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
3569 i_auth
, i_auth_len
);
3570 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3571 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
3573 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
3574 i_auth2
, i_auth_len
);
3575 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
3576 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
3580 bin_clear_free(unwrapped
, unwrapped_len
);
3581 dpp_auth_success(auth
);
3584 bin_clear_free(unwrapped
, unwrapped_len
);
3589 void dpp_configuration_free(struct dpp_configuration
*conf
)
3593 str_clear_free(conf
->passphrase
);
3594 bin_clear_free(conf
, sizeof(*conf
));
3598 void dpp_auth_deinit(struct dpp_authentication
*auth
)
3602 dpp_configuration_free(auth
->conf_ap
);
3603 dpp_configuration_free(auth
->conf_sta
);
3604 EVP_PKEY_free(auth
->own_protocol_key
);
3605 EVP_PKEY_free(auth
->peer_protocol_key
);
3606 wpabuf_free(auth
->req_msg
);
3607 wpabuf_free(auth
->resp_msg
);
3608 wpabuf_free(auth
->conf_req
);
3609 os_free(auth
->connector
);
3610 wpabuf_free(auth
->net_access_key
);
3611 wpabuf_free(auth
->c_sign_key
);
3612 #ifdef CONFIG_TESTING_OPTIONS
3613 os_free(auth
->config_obj_override
);
3614 os_free(auth
->discovery_override
);
3615 os_free(auth
->groups_override
);
3616 #endif /* CONFIG_TESTING_OPTIONS */
3617 bin_clear_free(auth
, sizeof(*auth
));
3621 static struct wpabuf
*
3622 dpp_build_conf_start(struct dpp_authentication
*auth
,
3623 struct dpp_configuration
*conf
, size_t tailroom
)
3626 char ssid
[6 * sizeof(conf
->ssid
) + 1];
3628 #ifdef CONFIG_TESTING_OPTIONS
3629 if (auth
->discovery_override
)
3630 tailroom
+= os_strlen(auth
->discovery_override
);
3631 #endif /* CONFIG_TESTING_OPTIONS */
3633 buf
= wpabuf_alloc(200 + tailroom
);
3636 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
3637 #ifdef CONFIG_TESTING_OPTIONS
3638 if (auth
->discovery_override
) {
3639 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
3640 auth
->discovery_override
);
3641 wpabuf_put_str(buf
, auth
->discovery_override
);
3642 wpabuf_put_u8(buf
, ',');
3645 #endif /* CONFIG_TESTING_OPTIONS */
3646 wpabuf_put_str(buf
, "{\"ssid\":\"");
3647 json_escape_string(ssid
, sizeof(ssid
),
3648 (const char *) conf
->ssid
, conf
->ssid_len
);
3649 wpabuf_put_str(buf
, ssid
);
3650 wpabuf_put_str(buf
, "\"},");
3656 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
3657 const char *kid
, const struct dpp_curve_params
*curve
)
3661 char *x
= NULL
, *y
= NULL
;
3664 pub
= dpp_get_pubkey_point(key
, 0);
3667 pos
= wpabuf_head(pub
);
3668 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
3669 pos
+= curve
->prime_len
;
3670 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
3674 wpabuf_put_str(buf
, "\"");
3675 wpabuf_put_str(buf
, name
);
3676 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
3677 wpabuf_put_str(buf
, curve
->jwk_crv
);
3678 wpabuf_put_str(buf
, "\",\"x\":\"");
3679 wpabuf_put_str(buf
, x
);
3680 wpabuf_put_str(buf
, "\",\"y\":\"");
3681 wpabuf_put_str(buf
, y
);
3683 wpabuf_put_str(buf
, "\",\"kid\":\"");
3684 wpabuf_put_str(buf
, kid
);
3686 wpabuf_put_str(buf
, "\"}");
3696 static struct wpabuf
*
3697 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
3698 struct dpp_configuration
*conf
)
3700 struct wpabuf
*buf
= NULL
;
3701 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
3703 const struct dpp_curve_params
*curve
;
3704 char jws_prot_hdr
[100];
3705 size_t signed1_len
, signed2_len
, signed3_len
;
3706 struct wpabuf
*dppcon
= NULL
;
3707 unsigned char *signature
= NULL
;
3708 const unsigned char *p
;
3709 size_t signature_len
;
3710 EVP_MD_CTX
*md_ctx
= NULL
;
3711 ECDSA_SIG
*sig
= NULL
;
3713 const EVP_MD
*sign_md
;
3714 const BIGNUM
*r
, *s
;
3715 size_t extra_len
= 1000;
3718 wpa_printf(MSG_INFO
,
3719 "DPP: No configurator specified - cannot generate DPP config object");
3722 curve
= auth
->conf
->curve
;
3723 if (curve
->hash_len
== SHA256_MAC_LEN
) {
3724 sign_md
= EVP_sha256();
3725 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
3726 sign_md
= EVP_sha384();
3727 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
3728 sign_md
= EVP_sha512();
3730 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
3734 #ifdef CONFIG_TESTING_OPTIONS
3735 if (auth
->groups_override
)
3736 extra_len
+= os_strlen(auth
->groups_override
);
3737 #endif /* CONFIG_TESTING_OPTIONS */
3739 /* Connector (JSON dppCon object) */
3740 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
3743 #ifdef CONFIG_TESTING_OPTIONS
3744 if (auth
->groups_override
) {
3745 wpabuf_put_u8(dppcon
, '{');
3746 if (auth
->groups_override
) {
3747 wpa_printf(MSG_DEBUG
,
3748 "DPP: TESTING - groups override: '%s'",
3749 auth
->groups_override
);
3750 wpabuf_put_str(dppcon
, "\"groups\":");
3751 wpabuf_put_str(dppcon
, auth
->groups_override
);
3752 wpabuf_put_u8(dppcon
, ',');
3756 #endif /* CONFIG_TESTING_OPTIONS */
3757 wpabuf_put_str(dppcon
, "{\"groups\":[{\"groupId\":\"*\",");
3758 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
3759 #ifdef CONFIG_TESTING_OPTIONS
3761 #endif /* CONFIG_TESTING_OPTIONS */
3762 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
3764 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
3767 if (conf
->netaccesskey_expiry
) {
3770 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
3771 wpa_printf(MSG_DEBUG
,
3772 "DPP: Failed to generate expiry string");
3775 wpabuf_printf(dppcon
,
3776 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3777 tm
.year
, tm
.month
, tm
.day
,
3778 tm
.hour
, tm
.min
, tm
.sec
);
3780 wpabuf_put_u8(dppcon
, '}');
3781 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
3782 (const char *) wpabuf_head(dppcon
));
3784 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
3785 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
3786 auth
->conf
->kid
, curve
->jws_alg
);
3787 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
3788 os_strlen(jws_prot_hdr
),
3790 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
3793 if (!signed1
|| !signed2
)
3796 md_ctx
= EVP_MD_CTX_create();
3801 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
3802 auth
->conf
->csign
) != 1) {
3803 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
3804 ERR_error_string(ERR_get_error(), NULL
));
3807 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
3808 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
3809 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
3810 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
3811 ERR_error_string(ERR_get_error(), NULL
));
3814 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
3815 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
3816 ERR_error_string(ERR_get_error(), NULL
));
3819 signature
= os_malloc(signature_len
);
3822 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
3823 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
3824 ERR_error_string(ERR_get_error(), NULL
));
3827 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
3828 signature
, signature_len
);
3829 /* Convert to raw coordinates r,s */
3831 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
3834 ECDSA_SIG_get0(sig
, &r
, &s
);
3835 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
3836 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
3837 curve
->prime_len
) < 0)
3839 signature_len
= 2 * curve
->prime_len
;
3840 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
3841 signature
, signature_len
);
3842 signed3
= (char *) base64_url_encode(signature
, signature_len
,
3848 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
3849 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
3850 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
3854 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
3855 wpabuf_put_str(buf
, signed1
);
3856 wpabuf_put_u8(buf
, '.');
3857 wpabuf_put_str(buf
, signed2
);
3858 wpabuf_put_u8(buf
, '.');
3859 wpabuf_put_str(buf
, signed3
);
3860 wpabuf_put_str(buf
, "\",");
3861 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
3863 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
3867 wpabuf_put_str(buf
, "}}");
3869 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
3870 wpabuf_head(buf
), wpabuf_len(buf
));
3873 EVP_MD_CTX_destroy(md_ctx
);
3874 ECDSA_SIG_free(sig
);
3879 wpabuf_free(dppcon
);
3882 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
3889 static struct wpabuf
*
3890 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
3891 struct dpp_configuration
*conf
)
3895 buf
= dpp_build_conf_start(auth
, conf
, 1000);
3899 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"psk\",");
3900 if (conf
->passphrase
) {
3901 char pass
[63 * 6 + 1];
3903 if (os_strlen(conf
->passphrase
) > 63) {
3908 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
3909 os_strlen(conf
->passphrase
));
3910 wpabuf_put_str(buf
, "\"pass\":\"");
3911 wpabuf_put_str(buf
, pass
);
3912 wpabuf_put_str(buf
, "\"");
3914 char psk
[2 * sizeof(conf
->psk
) + 1];
3916 wpa_snprintf_hex(psk
, sizeof(psk
),
3917 conf
->psk
, sizeof(conf
->psk
));
3918 wpabuf_put_str(buf
, "\"psk_hex\":\"");
3919 wpabuf_put_str(buf
, psk
);
3920 wpabuf_put_str(buf
, "\"");
3922 wpabuf_put_str(buf
, "}}");
3924 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
3925 wpabuf_head(buf
), wpabuf_len(buf
));
3931 static struct wpabuf
*
3932 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
3934 struct dpp_configuration
*conf
;
3936 #ifdef CONFIG_TESTING_OPTIONS
3937 if (auth
->config_obj_override
) {
3938 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
3939 return wpabuf_alloc_copy(auth
->config_obj_override
,
3940 os_strlen(auth
->config_obj_override
));
3942 #endif /* CONFIG_TESTING_OPTIONS */
3944 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
3946 wpa_printf(MSG_DEBUG
,
3947 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
3953 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
3954 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
3958 static struct wpabuf
*
3959 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
3960 u16 e_nonce_len
, int ap
)
3962 struct wpabuf
*conf
;
3963 size_t clear_len
, attr_len
;
3964 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
3968 enum dpp_status_error status
;
3970 conf
= dpp_build_conf_obj(auth
, ap
);
3972 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
3973 wpabuf_head(conf
), wpabuf_len(conf
));
3975 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
3977 /* { E-nonce, configurationObject}ke */
3978 clear_len
= 4 + e_nonce_len
;
3980 clear_len
+= 4 + wpabuf_len(conf
);
3981 clear
= wpabuf_alloc(clear_len
);
3982 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
3983 #ifdef CONFIG_TESTING_OPTIONS
3984 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
3986 #endif /* CONFIG_TESTING_OPTIONS */
3987 msg
= wpabuf_alloc(attr_len
);
3991 #ifdef CONFIG_TESTING_OPTIONS
3992 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
3993 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
3996 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
3997 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
3998 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
3999 wpabuf_put_le16(clear
, e_nonce_len
);
4000 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4001 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4004 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4005 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4006 goto skip_wrapped_data
;
4008 #endif /* CONFIG_TESTING_OPTIONS */
4011 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4012 wpabuf_put_le16(clear
, e_nonce_len
);
4013 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4015 #ifdef CONFIG_TESTING_OPTIONS
4017 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4018 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4019 goto skip_config_obj
;
4021 #endif /* CONFIG_TESTING_OPTIONS */
4024 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4025 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4026 wpabuf_put_buf(clear
, conf
);
4029 #ifdef CONFIG_TESTING_OPTIONS
4031 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4032 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4035 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4036 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4039 #endif /* CONFIG_TESTING_OPTIONS */
4042 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
4043 wpabuf_put_le16(msg
, 1);
4044 wpabuf_put_u8(msg
, status
);
4046 #ifdef CONFIG_TESTING_OPTIONS
4048 #endif /* CONFIG_TESTING_OPTIONS */
4050 addr
[0] = wpabuf_head(msg
);
4051 len
[0] = wpabuf_len(msg
);
4052 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4054 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4055 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4056 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4058 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4059 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4060 wpabuf_head(clear
), wpabuf_len(clear
),
4061 1, addr
, len
, wrapped
) < 0)
4063 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4064 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4066 #ifdef CONFIG_TESTING_OPTIONS
4067 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4068 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4069 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
4070 wpabuf_put_le16(msg
, 0);
4073 #endif /* CONFIG_TESTING_OPTIONS */
4075 wpa_hexdump_buf(MSG_DEBUG
,
4076 "DPP: Configuration Response attributes", msg
);
4090 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4093 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4094 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4095 u8
*unwrapped
= NULL
;
4096 size_t unwrapped_len
= 0;
4097 struct wpabuf
*resp
= NULL
;
4098 struct json_token
*root
= NULL
, *token
;
4101 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4102 dpp_auth_fail(auth
, "Invalid attribute in config request");
4106 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4108 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4110 "Missing or invalid required Wrapped Data attribute");
4114 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4115 wrapped_data
, wrapped_data_len
);
4116 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4117 unwrapped
= os_malloc(unwrapped_len
);
4120 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4121 wrapped_data
, wrapped_data_len
,
4122 0, NULL
, NULL
, unwrapped
) < 0) {
4123 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4126 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4127 unwrapped
, unwrapped_len
);
4129 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4130 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4134 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4135 DPP_ATTR_ENROLLEE_NONCE
,
4137 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4139 "Missing or invalid Enrollee Nonce attribute");
4142 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4144 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
4145 DPP_ATTR_CONFIG_ATTR_OBJ
,
4149 "Missing or invalid Config Attributes attribute");
4152 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
4153 config_attr
, config_attr_len
);
4155 root
= json_parse((const char *) config_attr
, config_attr_len
);
4157 dpp_auth_fail(auth
, "Could not parse Config Attributes");
4161 token
= json_get_member(root
, "name");
4162 if (!token
|| token
->type
!= JSON_STRING
) {
4163 dpp_auth_fail(auth
, "No Config Attributes - name");
4166 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
4168 token
= json_get_member(root
, "wi-fi_tech");
4169 if (!token
|| token
->type
!= JSON_STRING
) {
4170 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
4173 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
4174 if (os_strcmp(token
->string
, "infra") != 0) {
4175 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
4177 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
4181 token
= json_get_member(root
, "netRole");
4182 if (!token
|| token
->type
!= JSON_STRING
) {
4183 dpp_auth_fail(auth
, "No Config Attributes - netRole");
4186 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
4187 if (os_strcmp(token
->string
, "sta") == 0) {
4189 } else if (os_strcmp(token
->string
, "ap") == 0) {
4192 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
4194 dpp_auth_fail(auth
, "Unsupported netRole");
4198 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
4207 static struct wpabuf
*
4208 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
4209 const u8
*prot_hdr
, u16 prot_hdr_len
,
4210 const EVP_MD
**ret_md
)
4212 struct json_token
*root
, *token
;
4213 struct wpabuf
*kid
= NULL
;
4215 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
4217 wpa_printf(MSG_DEBUG
,
4218 "DPP: JSON parsing failed for JWS Protected Header");
4222 if (root
->type
!= JSON_OBJECT
) {
4223 wpa_printf(MSG_DEBUG
,
4224 "DPP: JWS Protected Header root is not an object");
4228 token
= json_get_member(root
, "typ");
4229 if (!token
|| token
->type
!= JSON_STRING
) {
4230 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
4233 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
4235 if (os_strcmp(token
->string
, "dppCon") != 0) {
4236 wpa_printf(MSG_DEBUG
,
4237 "DPP: Unsupported JWS Protected Header typ=%s",
4242 token
= json_get_member(root
, "alg");
4243 if (!token
|| token
->type
!= JSON_STRING
) {
4244 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
4247 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
4249 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
4250 wpa_printf(MSG_DEBUG
,
4251 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4252 token
->string
, curve
->jws_alg
);
4255 if (os_strcmp(token
->string
, "ES256") == 0 ||
4256 os_strcmp(token
->string
, "BS256") == 0)
4257 *ret_md
= EVP_sha256();
4258 else if (os_strcmp(token
->string
, "ES384") == 0 ||
4259 os_strcmp(token
->string
, "BS384") == 0)
4260 *ret_md
= EVP_sha384();
4261 else if (os_strcmp(token
->string
, "ES512") == 0 ||
4262 os_strcmp(token
->string
, "BS512") == 0)
4263 *ret_md
= EVP_sha512();
4267 wpa_printf(MSG_DEBUG
,
4268 "DPP: Unsupported JWS Protected Header alg=%s",
4273 kid
= json_get_member_base64url(root
, "kid");
4275 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
4278 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
4287 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
4288 struct json_token
*cred
)
4290 struct json_token
*pass
, *psk_hex
;
4292 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
4294 pass
= json_get_member(cred
, "pass");
4295 psk_hex
= json_get_member(cred
, "psk_hex");
4297 if (pass
&& pass
->type
== JSON_STRING
) {
4298 size_t len
= os_strlen(pass
->string
);
4300 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
4302 if (len
< 8 || len
> 63)
4304 os_strlcpy(auth
->passphrase
, pass
->string
,
4305 sizeof(auth
->passphrase
));
4306 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
4307 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
4308 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
4309 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
4312 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
4313 auth
->psk
, PMK_LEN
);
4316 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
4324 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
4325 const struct dpp_curve_params
**key_curve
)
4327 struct json_token
*token
;
4328 const struct dpp_curve_params
*curve
;
4329 struct wpabuf
*x
= NULL
, *y
= NULL
;
4331 EVP_PKEY
*pkey
= NULL
;
4333 token
= json_get_member(jwk
, "kty");
4334 if (!token
|| token
->type
!= JSON_STRING
) {
4335 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
4338 if (os_strcmp(token
->string
, "EC") != 0) {
4339 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s",
4344 token
= json_get_member(jwk
, "crv");
4345 if (!token
|| token
->type
!= JSON_STRING
) {
4346 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
4349 curve
= dpp_get_curve_jwk_crv(token
->string
);
4351 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
4356 x
= json_get_member_base64url(jwk
, "x");
4358 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
4361 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
4362 if (wpabuf_len(x
) != curve
->prime_len
) {
4363 wpa_printf(MSG_DEBUG
,
4364 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4365 (unsigned int) wpabuf_len(x
),
4366 (unsigned int) curve
->prime_len
, curve
->name
);
4370 y
= json_get_member_base64url(jwk
, "y");
4372 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
4375 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
4376 if (wpabuf_len(y
) != curve
->prime_len
) {
4377 wpa_printf(MSG_DEBUG
,
4378 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4379 (unsigned int) wpabuf_len(y
),
4380 (unsigned int) curve
->prime_len
, curve
->name
);
4384 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
4386 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
4390 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
4402 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
4405 unsigned int year
, month
, day
, hour
, min
, sec
;
4409 /* ISO 8601 date and time:
4411 * YYYY-MM-DDTHH:MM:SSZ
4412 * YYYY-MM-DDTHH:MM:SS+03:00
4414 if (os_strlen(timestamp
) < 19) {
4415 wpa_printf(MSG_DEBUG
,
4416 "DPP: Too short timestamp - assume expired key");
4419 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
4420 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
4421 wpa_printf(MSG_DEBUG
,
4422 "DPP: Failed to parse expiration day - assume expired key");
4426 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
4427 wpa_printf(MSG_DEBUG
,
4428 "DPP: Invalid date/time information - assume expired key");
4432 pos
= timestamp
+ 19;
4433 if (*pos
== 'Z' || *pos
== '\0') {
4434 /* In UTC - no need to adjust */
4435 } else if (*pos
== '-' || *pos
== '+') {
4438 /* Adjust local time to UTC */
4439 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
4441 wpa_printf(MSG_DEBUG
,
4442 "DPP: Invalid time zone designator (%s) - assume expired key",
4447 utime
+= 3600 * hour
;
4449 utime
-= 3600 * hour
;
4457 wpa_printf(MSG_DEBUG
,
4458 "DPP: Invalid time zone designator (%s) - assume expired key",
4465 if (os_get_time(&now
) < 0) {
4466 wpa_printf(MSG_DEBUG
,
4467 "DPP: Cannot get current time - assume expired key");
4471 if (now
.sec
> utime
) {
4472 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
4481 static int dpp_parse_connector(struct dpp_authentication
*auth
,
4482 const unsigned char *payload
,
4485 struct json_token
*root
, *groups
, *netkey
, *token
;
4487 EVP_PKEY
*key
= NULL
;
4488 const struct dpp_curve_params
*curve
;
4489 unsigned int rules
= 0;
4491 root
= json_parse((const char *) payload
, payload_len
);
4493 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
4497 groups
= json_get_member(root
, "groups");
4498 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
4499 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
4502 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4503 struct json_token
*id
, *role
;
4505 id
= json_get_member(token
, "groupId");
4506 if (!id
|| id
->type
!= JSON_STRING
) {
4507 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
4511 role
= json_get_member(token
, "netRole");
4512 if (!role
|| role
->type
!= JSON_STRING
) {
4513 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
4516 wpa_printf(MSG_DEBUG
,
4517 "DPP: connector group: groupId='%s' netRole='%s'",
4518 id
->string
, role
->string
);
4524 wpa_printf(MSG_DEBUG
,
4525 "DPP: Connector includes no groups");
4529 token
= json_get_member(root
, "expiry");
4530 if (!token
|| token
->type
!= JSON_STRING
) {
4531 wpa_printf(MSG_DEBUG
,
4532 "DPP: No expiry string found - connector does not expire");
4534 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
4535 if (dpp_key_expired(token
->string
,
4536 &auth
->net_access_key_expiry
)) {
4537 wpa_printf(MSG_DEBUG
,
4538 "DPP: Connector (netAccessKey) has expired");
4543 netkey
= json_get_member(root
, "netAccessKey");
4544 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
4545 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
4549 key
= dpp_parse_jwk(netkey
, &curve
);
4552 dpp_debug_print_key("DPP: Received netAccessKey", key
);
4554 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
4555 wpa_printf(MSG_DEBUG
,
4556 "DPP: netAccessKey in connector does not match own protocol key");
4557 #ifdef CONFIG_TESTING_OPTIONS
4558 if (auth
->ignore_netaccesskey_mismatch
) {
4559 wpa_printf(MSG_DEBUG
,
4560 "DPP: TESTING - skip netAccessKey mismatch");
4564 #else /* CONFIG_TESTING_OPTIONS */
4566 #endif /* CONFIG_TESTING_OPTIONS */
4577 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
4579 struct wpabuf
*uncomp
;
4581 u8 hash
[SHA256_MAC_LEN
];
4585 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
4587 uncomp
= dpp_get_pubkey_point(pub
, 1);
4590 addr
[0] = wpabuf_head(uncomp
);
4591 len
[0] = wpabuf_len(uncomp
);
4592 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
4594 res
= sha256_vector(1, addr
, len
, hash
);
4595 wpabuf_free(uncomp
);
4598 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
4599 wpa_printf(MSG_DEBUG
,
4600 "DPP: Received hash value does not match calculated public key hash value");
4601 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
4602 hash
, SHA256_MAC_LEN
);
4609 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
4611 unsigned char *der
= NULL
;
4614 der_len
= i2d_PUBKEY(csign
, &der
);
4617 wpabuf_free(auth
->c_sign_key
);
4618 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
4623 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
4625 unsigned char *der
= NULL
;
4629 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
4633 der_len
= i2d_ECPrivateKey(eckey
, &der
);
4638 wpabuf_free(auth
->net_access_key
);
4639 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
4645 struct dpp_signed_connector_info
{
4646 unsigned char *payload
;
4650 static enum dpp_status_error
4651 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
4652 EVP_PKEY
*csign_pub
, const char *connector
)
4654 enum dpp_status_error ret
= 255;
4655 const char *pos
, *end
, *signed_start
, *signed_end
;
4656 struct wpabuf
*kid
= NULL
;
4657 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
4658 size_t prot_hdr_len
= 0, signature_len
= 0;
4659 const EVP_MD
*sign_md
= NULL
;
4660 unsigned char *der
= NULL
;
4663 EVP_MD_CTX
*md_ctx
= NULL
;
4664 ECDSA_SIG
*sig
= NULL
;
4665 BIGNUM
*r
= NULL
, *s
= NULL
;
4666 const struct dpp_curve_params
*curve
;
4668 const EC_GROUP
*group
;
4671 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
4674 group
= EC_KEY_get0_group(eckey
);
4677 nid
= EC_GROUP_get_curve_name(group
);
4678 curve
= dpp_get_curve_nid(nid
);
4681 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
4682 os_memset(info
, 0, sizeof(*info
));
4684 signed_start
= pos
= connector
;
4685 end
= os_strchr(pos
, '.');
4687 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
4688 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4691 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
4692 end
- pos
, &prot_hdr_len
);
4694 wpa_printf(MSG_DEBUG
,
4695 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
4696 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4699 wpa_hexdump_ascii(MSG_DEBUG
,
4700 "DPP: signedConnector - JWS Protected Header",
4701 prot_hdr
, prot_hdr_len
);
4702 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
4704 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4707 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
4708 wpa_printf(MSG_DEBUG
,
4709 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
4710 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
4711 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4716 end
= os_strchr(pos
, '.');
4718 wpa_printf(MSG_DEBUG
,
4719 "DPP: Missing dot(2) in signedConnector");
4720 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4723 signed_end
= end
- 1;
4724 info
->payload
= base64_url_decode((const unsigned char *) pos
,
4725 end
- pos
, &info
->payload_len
);
4726 if (!info
->payload
) {
4727 wpa_printf(MSG_DEBUG
,
4728 "DPP: Failed to base64url decode signedConnector JWS Payload");
4729 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4732 wpa_hexdump_ascii(MSG_DEBUG
,
4733 "DPP: signedConnector - JWS Payload",
4734 info
->payload
, info
->payload_len
);
4736 signature
= base64_url_decode((const unsigned char *) pos
,
4737 os_strlen(pos
), &signature_len
);
4739 wpa_printf(MSG_DEBUG
,
4740 "DPP: Failed to base64url decode signedConnector signature");
4741 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4744 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
4745 signature
, signature_len
);
4747 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
4748 ret
= DPP_STATUS_NO_MATCH
;
4752 if (signature_len
& 0x01) {
4753 wpa_printf(MSG_DEBUG
,
4754 "DPP: Unexpected signedConnector signature length (%d)",
4755 (int) signature_len
);
4756 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4760 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
4761 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
4762 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
4763 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
4764 sig
= ECDSA_SIG_new();
4765 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
4770 der_len
= i2d_ECDSA_SIG(sig
, &der
);
4772 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
4775 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
4776 md_ctx
= EVP_MD_CTX_create();
4781 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
4782 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
4783 ERR_error_string(ERR_get_error(), NULL
));
4786 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
4787 signed_end
- signed_start
+ 1) != 1) {
4788 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
4789 ERR_error_string(ERR_get_error(), NULL
));
4792 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
4794 wpa_printf(MSG_DEBUG
,
4795 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
4796 res
, ERR_error_string(ERR_get_error(), NULL
));
4797 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4801 ret
= DPP_STATUS_OK
;
4804 EVP_MD_CTX_destroy(md_ctx
);
4808 ECDSA_SIG_free(sig
);
4816 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
4817 struct json_token
*cred
)
4819 struct dpp_signed_connector_info info
;
4820 struct json_token
*token
, *csign
;
4822 EVP_PKEY
*csign_pub
= NULL
;
4823 const struct dpp_curve_params
*key_curve
= NULL
;
4824 const char *signed_connector
;
4826 os_memset(&info
, 0, sizeof(info
));
4828 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
4830 csign
= json_get_member(cred
, "csign");
4831 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
4832 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
4836 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
4838 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
4841 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
4843 token
= json_get_member(cred
, "signedConnector");
4844 if (!token
|| token
->type
!= JSON_STRING
) {
4845 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
4848 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
4849 token
->string
, os_strlen(token
->string
));
4850 signed_connector
= token
->string
;
4852 if (os_strchr(signed_connector
, '"') ||
4853 os_strchr(signed_connector
, '\n')) {
4854 wpa_printf(MSG_DEBUG
,
4855 "DPP: Unexpected character in signedConnector");
4859 if (dpp_process_signed_connector(&info
, csign_pub
,
4860 signed_connector
) != DPP_STATUS_OK
)
4863 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
4864 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
4868 os_free(auth
->connector
);
4869 auth
->connector
= os_strdup(signed_connector
);
4871 dpp_copy_csign(auth
, csign_pub
);
4872 dpp_copy_netaccesskey(auth
);
4876 EVP_PKEY_free(csign_pub
);
4877 os_free(info
.payload
);
4882 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
4883 const u8
*conf_obj
, u16 conf_obj_len
)
4886 struct json_token
*root
, *token
, *discovery
, *cred
;
4888 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
4891 if (root
->type
!= JSON_OBJECT
) {
4892 dpp_auth_fail(auth
, "JSON root is not an object");
4896 token
= json_get_member(root
, "wi-fi_tech");
4897 if (!token
|| token
->type
!= JSON_STRING
) {
4898 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
4901 if (os_strcmp(token
->string
, "infra") != 0) {
4902 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
4904 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
4908 discovery
= json_get_member(root
, "discovery");
4909 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
4910 dpp_auth_fail(auth
, "No discovery object in JSON");
4914 token
= json_get_member(discovery
, "ssid");
4915 if (!token
|| token
->type
!= JSON_STRING
) {
4916 dpp_auth_fail(auth
, "No discovery::ssid string value found");
4919 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
4920 token
->string
, os_strlen(token
->string
));
4921 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
4922 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
4925 auth
->ssid_len
= os_strlen(token
->string
);
4926 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
4928 cred
= json_get_member(root
, "cred");
4929 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
4930 dpp_auth_fail(auth
, "No cred object in JSON");
4934 token
= json_get_member(cred
, "akm");
4935 if (!token
|| token
->type
!= JSON_STRING
) {
4936 dpp_auth_fail(auth
, "No cred::akm string value found");
4939 if (os_strcmp(token
->string
, "psk") == 0) {
4940 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
4942 } else if (os_strcmp(token
->string
, "dpp") == 0) {
4943 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
4946 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
4948 dpp_auth_fail(auth
, "Unsupported akm");
4952 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
4960 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
4961 const struct wpabuf
*resp
)
4963 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
4964 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
4967 u8
*unwrapped
= NULL
;
4968 size_t unwrapped_len
= 0;
4971 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
4972 dpp_auth_fail(auth
, "Invalid attribute in config response");
4976 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
4977 DPP_ATTR_WRAPPED_DATA
,
4979 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4981 "Missing or invalid required Wrapped Data attribute");
4985 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4986 wrapped_data
, wrapped_data_len
);
4987 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4988 unwrapped
= os_malloc(unwrapped_len
);
4992 addr
[0] = wpabuf_head(resp
);
4993 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
4994 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4996 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4997 wrapped_data
, wrapped_data_len
,
4998 1, addr
, len
, unwrapped
) < 0) {
4999 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5002 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5003 unwrapped
, unwrapped_len
);
5005 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5006 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5010 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5011 DPP_ATTR_ENROLLEE_NONCE
,
5013 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5015 "Missing or invalid Enrollee Nonce attribute");
5018 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5019 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5020 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5024 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5025 DPP_ATTR_STATUS
, &status_len
);
5026 if (!status
|| status_len
< 1) {
5028 "Missing or invalid required DPP Status attribute");
5031 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5032 if (status
[0] != DPP_STATUS_OK
) {
5033 dpp_auth_fail(auth
, "Configurator rejected configuration");
5037 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5038 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5041 "Missing required Configuration Object attribute");
5044 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5045 conf_obj
, conf_obj_len
);
5046 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5057 void dpp_configurator_free(struct dpp_configurator
*conf
)
5061 EVP_PKEY_free(conf
->csign
);
5067 struct dpp_configurator
*
5068 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
5071 struct dpp_configurator
*conf
;
5072 struct wpabuf
*csign_pub
= NULL
;
5073 u8 kid_hash
[SHA256_MAC_LEN
];
5077 conf
= os_zalloc(sizeof(*conf
));
5082 conf
->curve
= &dpp_curves
[0];
5084 conf
->curve
= dpp_get_curve_name(curve
);
5086 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5092 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
5095 conf
->csign
= dpp_gen_keypair(conf
->curve
);
5100 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
5102 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
5106 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5107 addr
[0] = wpabuf_head(csign_pub
);
5108 len
[0] = wpabuf_len(csign_pub
);
5109 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
5110 wpa_printf(MSG_DEBUG
,
5111 "DPP: Failed to derive kid for C-sign-key");
5115 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
5120 wpabuf_free(csign_pub
);
5123 dpp_configurator_free(conf
);
5129 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
5132 struct wpabuf
*conf_obj
;
5136 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
5141 auth
->curve
= &dpp_curves
[0];
5143 auth
->curve
= dpp_get_curve_name(curve
);
5145 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5150 wpa_printf(MSG_DEBUG
,
5151 "DPP: Building own configuration/connector with curve %s",
5154 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
5155 if (!auth
->own_protocol_key
)
5157 dpp_copy_netaccesskey(auth
);
5158 auth
->peer_protocol_key
= auth
->own_protocol_key
;
5159 dpp_copy_csign(auth
, auth
->conf
->csign
);
5161 conf_obj
= dpp_build_conf_obj(auth
, 0);
5164 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
5165 wpabuf_len(conf_obj
));
5167 wpabuf_free(conf_obj
);
5168 auth
->peer_protocol_key
= NULL
;
5173 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
5175 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
5176 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
5180 static int dpp_connector_compatible_group(struct json_token
*root
,
5181 const char *group_id
,
5182 const char *net_role
)
5184 struct json_token
*groups
, *token
;
5186 groups
= json_get_member(root
, "groups");
5187 if (!groups
|| groups
->type
!= JSON_ARRAY
)
5190 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5191 struct json_token
*id
, *role
;
5193 id
= json_get_member(token
, "groupId");
5194 if (!id
|| id
->type
!= JSON_STRING
)
5197 role
= json_get_member(token
, "netRole");
5198 if (!role
|| role
->type
!= JSON_STRING
)
5201 if (os_strcmp(id
->string
, "*") != 0 &&
5202 os_strcmp(group_id
, "*") != 0 &&
5203 os_strcmp(id
->string
, group_id
) != 0)
5206 if (dpp_compatible_netrole(role
->string
, net_role
))
5214 static int dpp_connector_match_groups(struct json_token
*own_root
,
5215 struct json_token
*peer_root
)
5217 struct json_token
*groups
, *token
;
5219 groups
= json_get_member(peer_root
, "groups");
5220 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5221 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
5225 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5226 struct json_token
*id
, *role
;
5228 id
= json_get_member(token
, "groupId");
5229 if (!id
|| id
->type
!= JSON_STRING
) {
5230 wpa_printf(MSG_DEBUG
,
5231 "DPP: Missing peer groupId string");
5235 role
= json_get_member(token
, "netRole");
5236 if (!role
|| role
->type
!= JSON_STRING
) {
5237 wpa_printf(MSG_DEBUG
,
5238 "DPP: Missing peer groups::netRole string");
5241 wpa_printf(MSG_DEBUG
,
5242 "DPP: peer connector group: groupId='%s' netRole='%s'",
5243 id
->string
, role
->string
);
5244 if (dpp_connector_compatible_group(own_root
, id
->string
,
5246 wpa_printf(MSG_DEBUG
,
5247 "DPP: Compatible group/netRole in own connector");
5256 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
5257 unsigned int hash_len
)
5259 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
5260 const char *info
= "DPP PMK";
5263 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5265 /* HKDF-Extract(<>, N.x) */
5266 os_memset(salt
, 0, hash_len
);
5267 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
5269 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5272 /* HKDF-Expand(PRK, info, L) */
5273 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
5274 os_memset(prk
, 0, hash_len
);
5278 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5284 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
5285 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
5287 struct wpabuf
*nkx
, *pkx
;
5291 u8 hash
[SHA256_MAC_LEN
];
5293 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5294 nkx
= dpp_get_pubkey_point(own_key
, 0);
5295 pkx
= dpp_get_pubkey_point(peer_key
, 0);
5298 addr
[0] = wpabuf_head(nkx
);
5299 len
[0] = wpabuf_len(nkx
) / 2;
5300 addr
[1] = wpabuf_head(pkx
);
5301 len
[1] = wpabuf_len(pkx
) / 2;
5302 if (len
[0] != len
[1])
5304 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
5305 addr
[0] = wpabuf_head(pkx
);
5306 addr
[1] = wpabuf_head(nkx
);
5308 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
5309 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
5310 res
= sha256_vector(2, addr
, len
, hash
);
5313 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
5314 os_memcpy(pmkid
, hash
, PMKID_LEN
);
5315 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
5324 enum dpp_status_error
5325 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
5326 const u8
*net_access_key
, size_t net_access_key_len
,
5327 const u8
*csign_key
, size_t csign_key_len
,
5328 const u8
*peer_connector
, size_t peer_connector_len
,
5331 struct json_token
*root
= NULL
, *netkey
, *token
;
5332 struct json_token
*own_root
= NULL
;
5333 enum dpp_status_error ret
= 255, res
;
5334 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
5335 struct wpabuf
*own_key_pub
= NULL
;
5336 const struct dpp_curve_params
*curve
, *own_curve
;
5337 struct dpp_signed_connector_info info
;
5338 const unsigned char *p
;
5339 EVP_PKEY
*csign
= NULL
;
5340 char *signed_connector
= NULL
;
5341 const char *pos
, *end
;
5342 unsigned char *own_conn
= NULL
;
5343 size_t own_conn_len
;
5344 EVP_PKEY_CTX
*ctx
= NULL
;
5346 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
5348 os_memset(intro
, 0, sizeof(*intro
));
5349 os_memset(&info
, 0, sizeof(info
));
5354 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
5356 wpa_printf(MSG_ERROR
,
5357 "DPP: Failed to parse local C-sign-key information");
5361 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
5362 net_access_key_len
);
5364 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
5368 pos
= os_strchr(own_connector
, '.');
5370 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
5374 end
= os_strchr(pos
, '.');
5376 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
5379 own_conn
= base64_url_decode((const unsigned char *) pos
,
5380 end
- pos
, &own_conn_len
);
5382 wpa_printf(MSG_DEBUG
,
5383 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5387 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
5389 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
5393 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
5394 peer_connector
, peer_connector_len
);
5395 signed_connector
= os_malloc(peer_connector_len
+ 1);
5396 if (!signed_connector
)
5398 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
5399 signed_connector
[peer_connector_len
] = '\0';
5401 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
5402 if (res
!= DPP_STATUS_OK
) {
5407 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
5409 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5410 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5414 if (!dpp_connector_match_groups(own_root
, root
)) {
5415 wpa_printf(MSG_DEBUG
,
5416 "DPP: Peer connector does not include compatible group netrole with own connector");
5417 ret
= DPP_STATUS_NO_MATCH
;
5421 token
= json_get_member(root
, "expiry");
5422 if (!token
|| token
->type
!= JSON_STRING
) {
5423 wpa_printf(MSG_DEBUG
,
5424 "DPP: No expiry string found - connector does not expire");
5426 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5427 if (dpp_key_expired(token
->string
, expiry
)) {
5428 wpa_printf(MSG_DEBUG
,
5429 "DPP: Connector (netAccessKey) has expired");
5430 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5435 netkey
= json_get_member(root
, "netAccessKey");
5436 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5437 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5438 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5442 peer_key
= dpp_parse_jwk(netkey
, &curve
);
5444 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5447 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
5449 if (own_curve
!= curve
) {
5450 wpa_printf(MSG_DEBUG
,
5451 "DPP: Mismatching netAccessKey curves (%s != %s)",
5452 own_curve
->name
, curve
->name
);
5453 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5457 /* ECDH: N = nk * PK */
5458 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
5460 EVP_PKEY_derive_init(ctx
) != 1 ||
5461 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
5462 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
5463 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5464 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
5465 wpa_printf(MSG_ERROR
,
5466 "DPP: Failed to derive ECDH shared secret: %s",
5467 ERR_error_string(ERR_get_error(), NULL
));
5471 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
5474 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5475 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
5476 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
5479 intro
->pmk_len
= curve
->hash_len
;
5481 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5482 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
5483 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
5487 ret
= DPP_STATUS_OK
;
5489 if (ret
!= DPP_STATUS_OK
)
5490 os_memset(intro
, 0, sizeof(*intro
));
5491 os_memset(Nx
, 0, sizeof(Nx
));
5492 EVP_PKEY_CTX_free(ctx
);
5494 os_free(signed_connector
);
5495 os_free(info
.payload
);
5496 EVP_PKEY_free(own_key
);
5497 wpabuf_free(own_key_pub
);
5498 EVP_PKEY_free(peer_key
);
5499 EVP_PKEY_free(csign
);
5501 json_free(own_root
);
5506 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
5510 size_t len
= curve
->prime_len
;
5513 switch (curve
->ike_group
) {
5515 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
5516 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
5519 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
5520 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
5523 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
5524 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
5527 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
5528 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
5531 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
5532 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
5535 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
5536 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
5542 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5545 return dpp_set_pubkey_point_group(group
, x
, y
, len
);
5549 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
5550 const u8
*mac_init
, const char *code
,
5551 const char *identifier
, BN_CTX
*bnctx
,
5552 const EC_GROUP
**ret_group
)
5554 u8 hash
[DPP_MAX_HASH_LEN
];
5557 unsigned int num_elem
= 0;
5558 EC_POINT
*Qi
= NULL
;
5559 EVP_PKEY
*Pi
= NULL
;
5560 EC_KEY
*Pi_ec
= NULL
;
5561 const EC_POINT
*Pi_point
;
5562 BIGNUM
*hash_bn
= NULL
;
5563 const EC_GROUP
*group
= NULL
;
5564 EC_GROUP
*group2
= NULL
;
5566 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5568 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
5569 addr
[num_elem
] = mac_init
;
5570 len
[num_elem
] = ETH_ALEN
;
5573 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5575 addr
[num_elem
] = (const u8
*) identifier
;
5576 len
[num_elem
] = os_strlen(identifier
);
5579 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5580 addr
[num_elem
] = (const u8
*) code
;
5581 len
[num_elem
] = os_strlen(code
);
5583 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5585 wpa_hexdump_key(MSG_DEBUG
,
5586 "DPP: H(MAC-Initiator | [identifier |] code)",
5587 hash
, curve
->hash_len
);
5588 Pi
= dpp_pkex_get_role_elem(curve
, 1);
5591 dpp_debug_print_key("DPP: Pi", Pi
);
5592 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
5595 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
5597 group
= EC_KEY_get0_group(Pi_ec
);
5600 group2
= EC_GROUP_dup(group
);
5603 Qi
= EC_POINT_new(group2
);
5605 EC_GROUP_free(group2
);
5608 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5610 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
5612 if (EC_POINT_is_at_infinity(group
, Qi
)) {
5613 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
5619 BN_clear_free(hash_bn
);
5621 *ret_group
= group2
;
5630 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
5631 const u8
*mac_resp
, const char *code
,
5632 const char *identifier
, BN_CTX
*bnctx
,
5633 const EC_GROUP
**ret_group
)
5635 u8 hash
[DPP_MAX_HASH_LEN
];
5638 unsigned int num_elem
= 0;
5639 EC_POINT
*Qr
= NULL
;
5640 EVP_PKEY
*Pr
= NULL
;
5641 EC_KEY
*Pr_ec
= NULL
;
5642 const EC_POINT
*Pr_point
;
5643 BIGNUM
*hash_bn
= NULL
;
5644 const EC_GROUP
*group
= NULL
;
5645 EC_GROUP
*group2
= NULL
;
5647 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5649 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
5650 addr
[num_elem
] = mac_resp
;
5651 len
[num_elem
] = ETH_ALEN
;
5654 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5656 addr
[num_elem
] = (const u8
*) identifier
;
5657 len
[num_elem
] = os_strlen(identifier
);
5660 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5661 addr
[num_elem
] = (const u8
*) code
;
5662 len
[num_elem
] = os_strlen(code
);
5664 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5666 wpa_hexdump_key(MSG_DEBUG
,
5667 "DPP: H(MAC-Responder | [identifier |] code)",
5668 hash
, curve
->hash_len
);
5669 Pr
= dpp_pkex_get_role_elem(curve
, 0);
5672 dpp_debug_print_key("DPP: Pr", Pr
);
5673 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
5676 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
5678 group
= EC_KEY_get0_group(Pr_ec
);
5681 group2
= EC_GROUP_dup(group
);
5684 Qr
= EC_POINT_new(group2
);
5686 EC_GROUP_free(group2
);
5689 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5691 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
5693 if (EC_POINT_is_at_infinity(group
, Qr
)) {
5694 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
5700 BN_clear_free(hash_bn
);
5702 *ret_group
= group2
;
5711 #ifdef CONFIG_TESTING_OPTIONS
5712 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
5713 const struct dpp_curve_params
*curve
)
5721 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5726 point
= EC_POINT_new(group
);
5729 if (!ctx
|| !point
|| !x
|| !y
)
5732 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
5735 /* Generate a random y coordinate that results in a point that is not
5738 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
5741 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
5745 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
5749 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
5750 curve
->prime_len
) < 0 ||
5751 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
5752 curve
->prime_len
) < 0)
5759 EC_POINT_free(point
);
5764 #endif /* CONFIG_TESTING_OPTIONS */
5767 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
5769 EC_KEY
*X_ec
= NULL
;
5770 const EC_POINT
*X_point
;
5771 BN_CTX
*bnctx
= NULL
;
5772 const EC_GROUP
*group
;
5773 EC_POINT
*Qi
= NULL
, *M
= NULL
;
5774 struct wpabuf
*M_buf
= NULL
;
5775 BIGNUM
*Mx
= NULL
, *My
= NULL
;
5776 struct wpabuf
*msg
= NULL
;
5778 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5780 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
5782 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5783 bnctx
= BN_CTX_new();
5786 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
5787 pkex
->identifier
, bnctx
, &group
);
5791 /* Generate a random ephemeral keypair x/X */
5792 pkex
->x
= dpp_gen_keypair(curve
);
5797 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
5800 X_point
= EC_KEY_get0_public_key(X_ec
);
5803 M
= EC_POINT_new(group
);
5806 if (!M
|| !Mx
|| !My
||
5807 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
5808 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
5811 /* Initiator -> Responder: group, [identifier,] M */
5813 if (pkex
->identifier
)
5814 attr_len
+= 4 + os_strlen(pkex
->identifier
);
5815 attr_len
+= 4 + 2 * curve
->prime_len
;
5816 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
5820 #ifdef CONFIG_TESTING_OPTIONS
5821 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
5822 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
5823 goto skip_finite_cyclic_group
;
5825 #endif /* CONFIG_TESTING_OPTIONS */
5827 /* Finite Cyclic Group attribute */
5828 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
5829 wpabuf_put_le16(msg
, 2);
5830 wpabuf_put_le16(msg
, curve
->ike_group
);
5832 #ifdef CONFIG_TESTING_OPTIONS
5833 skip_finite_cyclic_group
:
5834 #endif /* CONFIG_TESTING_OPTIONS */
5836 /* Code Identifier attribute */
5837 if (pkex
->identifier
) {
5838 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
5839 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
5840 wpabuf_put_str(msg
, pkex
->identifier
);
5843 #ifdef CONFIG_TESTING_OPTIONS
5844 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
5845 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
5848 #endif /* CONFIG_TESTING_OPTIONS */
5850 /* M in Encrypted Key attribute */
5851 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
5852 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
5854 #ifdef CONFIG_TESTING_OPTIONS
5855 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
5856 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
5857 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
5861 #endif /* CONFIG_TESTING_OPTIONS */
5863 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
5864 curve
->prime_len
) < 0 ||
5865 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
5866 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
5867 curve
->prime_len
) < 0)
5880 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
5887 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
5889 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
5893 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
5895 const char *identifier
,
5898 struct dpp_pkex
*pkex
;
5900 pkex
= os_zalloc(sizeof(*pkex
));
5903 pkex
->msg_ctx
= msg_ctx
;
5904 pkex
->initiator
= 1;
5906 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
5908 pkex
->identifier
= os_strdup(identifier
);
5909 if (!pkex
->identifier
)
5912 pkex
->code
= os_strdup(code
);
5915 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
5916 if (!pkex
->exchange_req
)
5920 dpp_pkex_free(pkex
);
5925 static struct wpabuf
*
5926 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
5927 enum dpp_status_error status
,
5928 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
5930 struct wpabuf
*msg
= NULL
;
5932 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5934 /* Initiator -> Responder: DPP Status, [identifier,] N */
5936 if (pkex
->identifier
)
5937 attr_len
+= 4 + os_strlen(pkex
->identifier
);
5938 attr_len
+= 4 + 2 * curve
->prime_len
;
5939 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
5943 #ifdef CONFIG_TESTING_OPTIONS
5944 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
5945 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
5949 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
5950 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
5953 #endif /* CONFIG_TESTING_OPTIONS */
5956 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
5957 wpabuf_put_le16(msg
, 1);
5958 wpabuf_put_u8(msg
, status
);
5960 #ifdef CONFIG_TESTING_OPTIONS
5962 #endif /* CONFIG_TESTING_OPTIONS */
5964 /* Code Identifier attribute */
5965 if (pkex
->identifier
) {
5966 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
5967 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
5968 wpabuf_put_str(msg
, pkex
->identifier
);
5971 if (status
!= DPP_STATUS_OK
)
5972 goto skip_encrypted_key
;
5974 #ifdef CONFIG_TESTING_OPTIONS
5975 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
5976 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
5977 goto skip_encrypted_key
;
5979 #endif /* CONFIG_TESTING_OPTIONS */
5981 /* N in Encrypted Key attribute */
5982 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
5983 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
5985 #ifdef CONFIG_TESTING_OPTIONS
5986 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
5987 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
5988 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
5990 goto skip_encrypted_key
;
5992 #endif /* CONFIG_TESTING_OPTIONS */
5994 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
5995 curve
->prime_len
) < 0 ||
5996 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
5997 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
5998 curve
->prime_len
) < 0)
6002 if (status
== DPP_STATUS_BAD_GROUP
) {
6003 /* Finite Cyclic Group attribute */
6004 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6005 wpabuf_put_le16(msg
, 2);
6006 wpabuf_put_le16(msg
, curve
->ike_group
);
6016 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
6017 const u8
*Mx
, size_t Mx_len
,
6018 const u8
*Nx
, size_t Nx_len
,
6020 const u8
*Kx
, size_t Kx_len
,
6021 u8
*z
, unsigned int hash_len
)
6023 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6028 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6031 /* HKDF-Extract(<>, IKM=K.x) */
6032 os_memset(salt
, 0, hash_len
);
6033 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
6035 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
6037 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
6038 info
= os_malloc(info_len
);
6042 os_memcpy(pos
, mac_init
, ETH_ALEN
);
6044 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
6046 os_memcpy(pos
, Mx
, Mx_len
);
6048 os_memcpy(pos
, Nx
, Nx_len
);
6050 os_memcpy(pos
, code
, os_strlen(code
));
6052 /* HKDF-Expand(PRK, info, L) */
6054 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6056 else if (hash_len
== 48)
6057 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6059 else if (hash_len
== 64)
6060 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6065 os_memset(prk
, 0, hash_len
);
6069 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
6075 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
6076 struct dpp_bootstrap_info
*bi
,
6079 const char *identifier
,
6081 const u8
*buf
, size_t len
)
6083 const u8
*attr_group
, *attr_id
, *attr_key
;
6084 u16 attr_group_len
, attr_id_len
, attr_key_len
;
6085 const struct dpp_curve_params
*curve
= bi
->curve
;
6087 struct dpp_pkex
*pkex
= NULL
;
6088 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
6089 BN_CTX
*bnctx
= NULL
;
6090 const EC_GROUP
*group
;
6091 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6092 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
6093 const EC_POINT
*Y_point
;
6094 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6095 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6098 EVP_PKEY_CTX
*ctx
= NULL
;
6100 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
6101 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6102 "PKEX counter t limit reached - ignore message");
6106 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
6108 if (!attr_id
&& identifier
) {
6109 wpa_printf(MSG_DEBUG
,
6110 "DPP: No PKEX code identifier received, but expected one");
6113 if (attr_id
&& identifier
&&
6114 (os_strlen(identifier
) != attr_id_len
||
6115 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
6116 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
6120 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
6122 if (!attr_group
|| attr_group_len
!= 2) {
6123 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6124 "Missing or invalid Finite Cyclic Group attribute");
6127 ike_group
= WPA_GET_LE16(attr_group
);
6128 if (ike_group
!= curve
->ike_group
) {
6129 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6130 "Mismatching PKEX curve: peer=%u own=%u",
6131 ike_group
, curve
->ike_group
);
6132 pkex
= os_zalloc(sizeof(*pkex
));
6137 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
6138 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
6139 if (!pkex
->exchange_resp
)
6144 /* M in Encrypted Key attribute */
6145 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
6147 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
6148 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
6149 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6150 "Missing Encrypted Key attribute");
6154 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6155 bnctx
= BN_CTX_new();
6158 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
6164 X
= EC_POINT_new(group
);
6165 M
= EC_POINT_new(group
);
6166 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6167 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6168 if (!X
|| !M
|| !Mx
|| !My
||
6169 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
6170 EC_POINT_is_at_infinity(group
, M
) ||
6171 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
6172 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
6173 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
6174 EC_POINT_is_at_infinity(group
, X
) ||
6175 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
6176 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6177 "Invalid Encrypted Key value");
6182 pkex
= os_zalloc(sizeof(*pkex
));
6185 pkex
->t
= bi
->pkex_t
;
6186 pkex
->msg_ctx
= msg_ctx
;
6188 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6189 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
6191 pkex
->identifier
= os_strdup(identifier
);
6192 if (!pkex
->identifier
)
6195 pkex
->code
= os_strdup(code
);
6199 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
6201 X_ec
= EC_KEY_new();
6203 EC_KEY_set_group(X_ec
, group
) != 1 ||
6204 EC_KEY_set_public_key(X_ec
, X
) != 1)
6206 pkex
->x
= EVP_PKEY_new();
6208 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
6211 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6212 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
6216 /* Generate a random ephemeral keypair y/Y */
6217 pkex
->y
= dpp_gen_keypair(curve
);
6222 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
6225 Y_point
= EC_KEY_get0_public_key(Y_ec
);
6228 N
= EC_POINT_new(group
);
6231 if (!N
|| !Nx
|| !Ny
||
6232 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
6233 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
6236 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
6238 if (!pkex
->exchange_resp
)
6242 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
6244 EVP_PKEY_derive_init(ctx
) != 1 ||
6245 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
6246 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6247 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6248 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6249 wpa_printf(MSG_ERROR
,
6250 "DPP: Failed to derive ECDH shared secret: %s",
6251 ERR_error_string(ERR_get_error(), NULL
));
6255 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6258 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6260 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
6261 pkex
->Mx
, curve
->prime_len
,
6262 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
6263 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
6264 os_memset(Kx
, 0, Kx_len
);
6268 pkex
->exchange_done
= 1;
6271 EVP_PKEY_CTX_free(ctx
);
6286 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
6287 dpp_pkex_free(pkex
);
6293 static struct wpabuf
*
6294 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
6295 const struct wpabuf
*A_pub
, const u8
*u
)
6297 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6298 struct wpabuf
*msg
= NULL
;
6299 size_t clear_len
, attr_len
;
6300 struct wpabuf
*clear
= NULL
;
6306 /* {A, u, [bootstrapping info]}z */
6307 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6308 clear
= wpabuf_alloc(clear_len
);
6309 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6310 #ifdef CONFIG_TESTING_OPTIONS
6311 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
6313 #endif /* CONFIG_TESTING_OPTIONS */
6314 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
6318 #ifdef CONFIG_TESTING_OPTIONS
6319 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6320 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6321 goto skip_bootstrap_key
;
6323 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6324 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6325 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6326 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6327 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6329 goto skip_bootstrap_key
;
6331 #endif /* CONFIG_TESTING_OPTIONS */
6333 /* A in Bootstrap Key attribute */
6334 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6335 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
6336 wpabuf_put_buf(clear
, A_pub
);
6338 #ifdef CONFIG_TESTING_OPTIONS
6340 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
6341 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
6342 goto skip_i_auth_tag
;
6344 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
6345 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
6346 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6347 wpabuf_put_le16(clear
, curve
->hash_len
);
6348 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
6349 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
6350 goto skip_i_auth_tag
;
6352 #endif /* CONFIG_TESTING_OPTIONS */
6354 /* u in I-Auth tag attribute */
6355 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6356 wpabuf_put_le16(clear
, curve
->hash_len
);
6357 wpabuf_put_data(clear
, u
, curve
->hash_len
);
6359 #ifdef CONFIG_TESTING_OPTIONS
6361 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
6362 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6363 goto skip_wrapped_data
;
6365 #endif /* CONFIG_TESTING_OPTIONS */
6367 addr
[0] = wpabuf_head_u8(msg
) + 2;
6368 len
[0] = DPP_HDR_LEN
;
6371 len
[1] = sizeof(octet
);
6372 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6373 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6375 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6376 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6377 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6379 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6380 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6381 wpabuf_head(clear
), wpabuf_len(clear
),
6382 2, addr
, len
, wrapped
) < 0)
6384 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6385 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6387 #ifdef CONFIG_TESTING_OPTIONS
6388 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
6389 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6390 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
6391 wpabuf_put_le16(msg
, 0);
6394 #endif /* CONFIG_TESTING_OPTIONS */
6407 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
6408 const u8
*buf
, size_t buflen
)
6410 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
6411 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
6412 const EC_GROUP
*group
;
6413 BN_CTX
*bnctx
= NULL
;
6414 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6415 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6416 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
6417 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6418 EVP_PKEY_CTX
*ctx
= NULL
;
6419 EC_KEY
*Y_ec
= NULL
;
6420 size_t Jx_len
, Kx_len
;
6421 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6424 u8 u
[DPP_MAX_HASH_LEN
];
6427 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
)
6430 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
6432 if (!attr_status
|| attr_status_len
!= 1) {
6433 dpp_pkex_fail(pkex
, "No DPP Status attribute");
6436 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
6438 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
6439 attr_group
= dpp_get_attr(buf
, buflen
,
6440 DPP_ATTR_FINITE_CYCLIC_GROUP
,
6442 if (attr_group
&& attr_group_len
== 2) {
6443 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6444 "Peer indicated mismatching PKEX group - proposed %u",
6445 WPA_GET_LE16(attr_group
));
6450 if (attr_status
[0] != DPP_STATUS_OK
) {
6451 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
6455 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
6457 if (!attr_id
&& pkex
->identifier
) {
6458 wpa_printf(MSG_DEBUG
,
6459 "DPP: No PKEX code identifier received, but expected one");
6462 if (attr_id
&& pkex
->identifier
&&
6463 (os_strlen(pkex
->identifier
) != attr_id_len
||
6464 os_memcmp(pkex
->identifier
, attr_id
, attr_id_len
) != 0)) {
6465 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
6469 /* N in Encrypted Key attribute */
6470 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
6472 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
6473 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
6477 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
6478 bnctx
= BN_CTX_new();
6481 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
6482 pkex
->identifier
, bnctx
, &group
);
6487 Y
= EC_POINT_new(group
);
6488 N
= EC_POINT_new(group
);
6489 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6490 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6491 if (!Y
|| !N
|| !Nx
|| !Ny
||
6492 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
6493 EC_POINT_is_at_infinity(group
, N
) ||
6494 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
6495 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
6496 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
6497 EC_POINT_is_at_infinity(group
, Y
) ||
6498 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
6499 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
6504 pkex
->exchange_done
= 1;
6506 /* ECDH: J = a * Y’ */
6507 Y_ec
= EC_KEY_new();
6509 EC_KEY_set_group(Y_ec
, group
) != 1 ||
6510 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
6512 pkex
->y
= EVP_PKEY_new();
6514 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
6516 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
6518 EVP_PKEY_derive_init(ctx
) != 1 ||
6519 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
6520 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
6521 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6522 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
6523 wpa_printf(MSG_ERROR
,
6524 "DPP: Failed to derive ECDH shared secret: %s",
6525 ERR_error_string(ERR_get_error(), NULL
));
6529 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
6532 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
6533 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
6534 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6535 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6536 if (!A_pub
|| !Y_pub
|| !X_pub
)
6538 addr
[0] = pkex
->own_mac
;
6540 addr
[1] = wpabuf_head(A_pub
);
6541 len
[1] = wpabuf_len(A_pub
) / 2;
6542 addr
[2] = wpabuf_head(Y_pub
);
6543 len
[2] = wpabuf_len(Y_pub
) / 2;
6544 addr
[3] = wpabuf_head(X_pub
);
6545 len
[3] = wpabuf_len(X_pub
) / 2;
6546 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
6548 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
6551 EVP_PKEY_CTX_free(ctx
);
6552 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
6554 EVP_PKEY_derive_init(ctx
) != 1 ||
6555 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
6556 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6557 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6558 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6559 wpa_printf(MSG_ERROR
,
6560 "DPP: Failed to derive ECDH shared secret: %s",
6561 ERR_error_string(ERR_get_error(), NULL
));
6565 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6568 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6570 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
6571 pkex
->Mx
, curve
->prime_len
,
6572 attr_key
/* N.x */, attr_key_len
/ 2,
6573 pkex
->code
, Kx
, Kx_len
,
6574 pkex
->z
, curve
->hash_len
);
6575 os_memset(Kx
, 0, Kx_len
);
6579 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
6593 EVP_PKEY_CTX_free(ctx
);
6597 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
6602 static struct wpabuf
*
6603 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
6604 const struct wpabuf
*B_pub
, const u8
*v
)
6606 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6607 struct wpabuf
*msg
= NULL
;
6612 struct wpabuf
*clear
= NULL
;
6613 size_t clear_len
, attr_len
;
6615 /* {B, v [bootstrapping info]}z */
6616 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6617 clear
= wpabuf_alloc(clear_len
);
6618 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6619 #ifdef CONFIG_TESTING_OPTIONS
6620 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
6622 #endif /* CONFIG_TESTING_OPTIONS */
6623 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
6627 #ifdef CONFIG_TESTING_OPTIONS
6628 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
6629 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6630 goto skip_bootstrap_key
;
6632 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
6633 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6634 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6635 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6636 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6638 goto skip_bootstrap_key
;
6640 #endif /* CONFIG_TESTING_OPTIONS */
6642 /* B in Bootstrap Key attribute */
6643 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6644 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
6645 wpabuf_put_buf(clear
, B_pub
);
6647 #ifdef CONFIG_TESTING_OPTIONS
6649 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
6650 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
6651 goto skip_r_auth_tag
;
6653 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
6654 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
6655 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
6656 wpabuf_put_le16(clear
, curve
->hash_len
);
6657 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
6658 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
6659 goto skip_r_auth_tag
;
6661 #endif /* CONFIG_TESTING_OPTIONS */
6663 /* v in R-Auth tag attribute */
6664 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
6665 wpabuf_put_le16(clear
, curve
->hash_len
);
6666 wpabuf_put_data(clear
, v
, curve
->hash_len
);
6668 #ifdef CONFIG_TESTING_OPTIONS
6670 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
6671 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6672 goto skip_wrapped_data
;
6674 #endif /* CONFIG_TESTING_OPTIONS */
6676 addr
[0] = wpabuf_head_u8(msg
) + 2;
6677 len
[0] = DPP_HDR_LEN
;
6680 len
[1] = sizeof(octet
);
6681 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6682 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6684 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6685 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6686 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6688 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6689 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6690 wpabuf_head(clear
), wpabuf_len(clear
),
6691 2, addr
, len
, wrapped
) < 0)
6693 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6694 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6696 #ifdef CONFIG_TESTING_OPTIONS
6697 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
6698 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6699 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
6700 wpabuf_put_le16(msg
, 0);
6703 #endif /* CONFIG_TESTING_OPTIONS */
6716 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
6718 const u8
*buf
, size_t buflen
)
6720 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6721 EVP_PKEY_CTX
*ctx
= NULL
;
6722 size_t Jx_len
, Lx_len
;
6723 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
6724 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
6725 const u8
*wrapped_data
, *b_key
, *peer_u
;
6726 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
6730 u8
*unwrapped
= NULL
;
6731 size_t unwrapped_len
= 0;
6732 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6733 struct wpabuf
*B_pub
= NULL
;
6734 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
6736 if (!pkex
->exchange_done
|| pkex
->failed
||
6737 pkex
->t
>= PKEX_COUNTER_T_LIMIT
)
6740 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
6742 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6744 "Missing or invalid required Wrapped Data attribute");
6748 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6749 wrapped_data
, wrapped_data_len
);
6750 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6751 unwrapped
= os_malloc(unwrapped_len
);
6756 len
[0] = DPP_HDR_LEN
;
6759 len
[1] = sizeof(octet
);
6760 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6761 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6763 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
6764 wrapped_data
, wrapped_data_len
,
6765 2, addr
, len
, unwrapped
) < 0) {
6767 "AES-SIV decryption failed - possible PKEX code mismatch");
6772 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6773 unwrapped
, unwrapped_len
);
6775 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6776 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
6780 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
6782 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
6783 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
6786 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
6788 if (!pkex
->peer_bootstrap_key
) {
6789 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
6792 dpp_debug_print_key("DPP: Peer bootstrap public key",
6793 pkex
->peer_bootstrap_key
);
6795 /* ECDH: J' = y * A' */
6796 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
6798 EVP_PKEY_derive_init(ctx
) != 1 ||
6799 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
6800 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
6801 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6802 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
6803 wpa_printf(MSG_ERROR
,
6804 "DPP: Failed to derive ECDH shared secret: %s",
6805 ERR_error_string(ERR_get_error(), NULL
));
6809 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
6812 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
6813 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
6814 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6815 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6816 if (!A_pub
|| !Y_pub
|| !X_pub
)
6818 addr
[0] = pkex
->peer_mac
;
6820 addr
[1] = wpabuf_head(A_pub
);
6821 len
[1] = wpabuf_len(A_pub
) / 2;
6822 addr
[2] = wpabuf_head(Y_pub
);
6823 len
[2] = wpabuf_len(Y_pub
) / 2;
6824 addr
[3] = wpabuf_head(X_pub
);
6825 len
[3] = wpabuf_len(X_pub
) / 2;
6826 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
6829 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
6831 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
6832 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
6833 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
6834 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
6835 u
, curve
->hash_len
);
6836 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
6840 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
6842 /* ECDH: L = b * X' */
6843 EVP_PKEY_CTX_free(ctx
);
6844 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
6846 EVP_PKEY_derive_init(ctx
) != 1 ||
6847 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
6848 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
6849 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6850 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
6851 wpa_printf(MSG_ERROR
,
6852 "DPP: Failed to derive ECDH shared secret: %s",
6853 ERR_error_string(ERR_get_error(), NULL
));
6857 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
6860 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
6861 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
6864 addr
[0] = pkex
->own_mac
;
6866 addr
[1] = wpabuf_head(B_pub
);
6867 len
[1] = wpabuf_len(B_pub
) / 2;
6868 addr
[2] = wpabuf_head(X_pub
);
6869 len
[2] = wpabuf_len(X_pub
) / 2;
6870 addr
[3] = wpabuf_head(Y_pub
);
6871 len
[3] = wpabuf_len(Y_pub
) / 2;
6872 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
6874 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
6876 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
6881 EVP_PKEY_CTX_free(ctx
);
6889 wpa_printf(MSG_DEBUG
,
6890 "DPP: PKEX Commit-Reveal Request processing failed");
6895 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
6896 const u8
*buf
, size_t buflen
)
6898 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6899 const u8
*wrapped_data
, *b_key
, *peer_v
;
6900 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
6904 u8
*unwrapped
= NULL
;
6905 size_t unwrapped_len
= 0;
6907 u8 v
[DPP_MAX_HASH_LEN
];
6909 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
6910 EVP_PKEY_CTX
*ctx
= NULL
;
6911 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6913 if (!pkex
->exchange_done
|| pkex
->failed
||
6914 pkex
->t
>= PKEX_COUNTER_T_LIMIT
)
6917 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
6919 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6921 "Missing or invalid required Wrapped Data attribute");
6925 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6926 wrapped_data
, wrapped_data_len
);
6927 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6928 unwrapped
= os_malloc(unwrapped_len
);
6933 len
[0] = DPP_HDR_LEN
;
6936 len
[1] = sizeof(octet
);
6937 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6938 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6940 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
6941 wrapped_data
, wrapped_data_len
,
6942 2, addr
, len
, unwrapped
) < 0) {
6944 "AES-SIV decryption failed - possible PKEX code mismatch");
6948 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6949 unwrapped
, unwrapped_len
);
6951 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6952 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
6956 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
6958 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
6959 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
6962 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
6964 if (!pkex
->peer_bootstrap_key
) {
6965 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
6968 dpp_debug_print_key("DPP: Peer bootstrap public key",
6969 pkex
->peer_bootstrap_key
);
6971 /* ECDH: L' = x * B' */
6972 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
6974 EVP_PKEY_derive_init(ctx
) != 1 ||
6975 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
6976 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
6977 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6978 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
6979 wpa_printf(MSG_ERROR
,
6980 "DPP: Failed to derive ECDH shared secret: %s",
6981 ERR_error_string(ERR_get_error(), NULL
));
6985 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
6988 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
6989 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
6990 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6991 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6992 if (!B_pub
|| !X_pub
|| !Y_pub
)
6994 addr
[0] = pkex
->peer_mac
;
6996 addr
[1] = wpabuf_head(B_pub
);
6997 len
[1] = wpabuf_len(B_pub
) / 2;
6998 addr
[2] = wpabuf_head(X_pub
);
6999 len
[2] = wpabuf_len(X_pub
) / 2;
7000 addr
[3] = wpabuf_head(Y_pub
);
7001 len
[3] = wpabuf_len(Y_pub
) / 2;
7002 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7005 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
7007 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
7008 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
7009 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
7010 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
7011 v
, curve
->hash_len
);
7012 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
7016 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
7023 EVP_PKEY_CTX_free(ctx
);
7031 void dpp_pkex_free(struct dpp_pkex
*pkex
)
7036 os_free(pkex
->identifier
);
7037 os_free(pkex
->code
);
7038 EVP_PKEY_free(pkex
->x
);
7039 EVP_PKEY_free(pkex
->y
);
7040 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
7041 wpabuf_free(pkex
->exchange_req
);
7042 wpabuf_free(pkex
->exchange_resp
);