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
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1473 *pos
++ = auth
->i_capab
;
1474 #ifdef CONFIG_TESTING_OPTIONS
1475 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1476 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1480 #endif /* CONFIG_TESTING_OPTIONS */
1482 attr_end
= wpabuf_put(msg
, 0);
1484 /* OUI, OUI type, Crypto Suite, DPP frame type */
1485 addr
[0] = wpabuf_head_u8(msg
) + 2;
1486 len
[0] = 3 + 1 + 1 + 1;
1487 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1489 /* Attributes before Wrapped Data */
1490 addr
[1] = attr_start
;
1491 len
[1] = attr_end
- attr_start
;
1492 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1494 siv_len
= pos
- clear
;
1495 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1496 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1497 2, addr
, len
, wrapped_data
) < 0) {
1501 siv_len
+= AES_BLOCK_SIZE
;
1502 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1503 wrapped_data
, siv_len
);
1505 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1506 wpabuf_put_le16(msg
, siv_len
);
1507 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1509 #ifdef CONFIG_TESTING_OPTIONS
1510 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1511 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1512 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
1513 wpabuf_put_le16(msg
, 0);
1516 #endif /* CONFIG_TESTING_OPTIONS */
1518 wpa_hexdump_buf(MSG_DEBUG
,
1519 "DPP: Authentication Request frame attributes", msg
);
1525 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1526 enum dpp_status_error status
,
1527 const struct wpabuf
*pr
,
1529 const u8
*r_pubkey_hash
,
1530 const u8
*i_pubkey_hash
,
1531 const u8
*r_nonce
, const u8
*i_nonce
,
1532 const u8
*wrapped_r_auth
,
1533 size_t wrapped_r_auth_len
,
1537 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1538 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1539 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1540 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1542 size_t len
[2], siv_len
, attr_len
;
1543 u8
*attr_start
, *attr_end
, *pos
;
1545 /* Build DPP Authentication Response frame attributes */
1546 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1547 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1548 #ifdef CONFIG_TESTING_OPTIONS
1549 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1551 #endif /* CONFIG_TESTING_OPTIONS */
1552 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1555 wpabuf_free(auth
->resp_msg
);
1557 attr_start
= wpabuf_put(msg
, 0);
1560 if (status
!= 255) {
1561 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1562 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1563 wpabuf_put_le16(msg
, 1);
1564 wpabuf_put_u8(msg
, status
);
1567 /* Responder Bootstrapping Key Hash */
1568 if (r_pubkey_hash
) {
1569 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1570 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1571 wpabuf_put_data(msg
, r_pubkey_hash
, SHA256_MAC_LEN
);
1574 /* Initiator Bootstrapping Key Hash */
1575 if (i_pubkey_hash
) {
1576 /* Mutual authentication */
1577 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1578 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1579 wpabuf_put_data(msg
, i_pubkey_hash
, SHA256_MAC_LEN
);
1582 /* Responder Protocol Key */
1584 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1585 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1586 wpabuf_put_buf(msg
, pr
);
1589 attr_end
= wpabuf_put(msg
, 0);
1591 #ifdef CONFIG_TESTING_OPTIONS
1592 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1593 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1594 goto skip_wrapped_data
;
1596 #endif /* CONFIG_TESTING_OPTIONS */
1598 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1603 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1605 WPA_PUT_LE16(pos
, nonce_len
);
1607 os_memcpy(pos
, r_nonce
, nonce_len
);
1613 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1615 WPA_PUT_LE16(pos
, nonce_len
);
1617 os_memcpy(pos
, i_nonce
, nonce_len
);
1618 #ifdef CONFIG_TESTING_OPTIONS
1619 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1620 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1621 pos
[nonce_len
/ 2] ^= 0x01;
1623 #endif /* CONFIG_TESTING_OPTIONS */
1627 #ifdef CONFIG_TESTING_OPTIONS
1628 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1629 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1632 #endif /* CONFIG_TESTING_OPTIONS */
1634 /* R-capabilities */
1635 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1637 WPA_PUT_LE16(pos
, 1);
1639 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1641 *pos
++ = auth
->r_capab
;
1642 #ifdef CONFIG_TESTING_OPTIONS
1643 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1644 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1646 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1647 wpa_printf(MSG_INFO
,
1648 "DPP: TESTING - incompatible R-capabilities");
1649 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1650 DPP_CAPAB_CONFIGURATOR
;
1653 #endif /* CONFIG_TESTING_OPTIONS */
1655 if (wrapped_r_auth
) {
1657 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1659 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1661 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1662 pos
+= wrapped_r_auth_len
;
1665 /* OUI, OUI type, Crypto Suite, DPP frame type */
1666 addr
[0] = wpabuf_head_u8(msg
) + 2;
1667 len
[0] = 3 + 1 + 1 + 1;
1668 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1670 /* Attributes before Wrapped Data */
1671 addr
[1] = attr_start
;
1672 len
[1] = attr_end
- attr_start
;
1673 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1675 siv_len
= pos
- clear
;
1676 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1677 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1678 2, addr
, len
, wrapped_data
) < 0) {
1682 siv_len
+= AES_BLOCK_SIZE
;
1683 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1684 wrapped_data
, siv_len
);
1686 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1687 wpabuf_put_le16(msg
, siv_len
);
1688 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1690 #ifdef CONFIG_TESTING_OPTIONS
1691 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1692 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1693 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
1694 wpabuf_put_le16(msg
, 0);
1697 #endif /* CONFIG_TESTING_OPTIONS */
1699 wpa_hexdump_buf(MSG_DEBUG
,
1700 "DPP: Authentication Response frame attributes", msg
);
1705 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1706 u16 num_modes
, unsigned int freq
)
1711 if (!own_modes
|| !num_modes
)
1714 for (m
= 0; m
< num_modes
; m
++) {
1715 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1716 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1719 flag
= own_modes
[m
].channels
[c
].flag
;
1720 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1721 HOSTAPD_CHAN_NO_IR
|
1722 HOSTAPD_CHAN_RADAR
)))
1727 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1732 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1736 if (freqs
[--num
] == freq
)
1743 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1748 for (i
= 0; i
< num
; i
++) {
1749 if (freqs
[i
] == freq
)
1752 if (i
== 0 || i
>= num
)
1754 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1759 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1760 struct hostapd_hw_modes
*own_modes
,
1763 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1764 unsigned int i
, freq
;
1766 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
1767 freq
= peer_bi
->freq
[i
];
1768 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1770 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
1771 auth
->freq
[auth
->num_freq
++] = freq
;
1773 if (!auth
->num_freq
) {
1774 wpa_printf(MSG_INFO
,
1775 "DPP: No available channels for initiating DPP Authentication");
1778 auth
->curr_freq
= auth
->freq
[0];
1783 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
1784 struct hostapd_hw_modes
*own_modes
,
1793 if (!own_modes
|| !num_modes
) {
1794 auth
->freq
[0] = 2412;
1795 auth
->freq
[1] = 2437;
1796 auth
->freq
[2] = 2462;
1801 for (m
= 0; m
< num_modes
; m
++) {
1802 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1803 freq
= own_modes
[m
].channels
[c
].freq
;
1804 flag
= own_modes
[m
].channels
[c
].flag
;
1805 if (flag
& (HOSTAPD_CHAN_DISABLED
|
1806 HOSTAPD_CHAN_NO_IR
|
1807 HOSTAPD_CHAN_RADAR
))
1809 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1811 auth
->freq
[auth
->num_freq
++] = freq
;
1812 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
1819 return auth
->num_freq
== 0 ? -1 : 0;
1823 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
1824 struct hostapd_hw_modes
*own_modes
,
1828 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
1831 if (auth
->peer_bi
->num_freq
> 0)
1832 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
1834 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
1838 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1839 * likely channels first. */
1840 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
1841 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
1842 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
1845 auth
->curr_freq
= auth
->freq
[0];
1848 end
= pos
+ sizeof(freqs
);
1849 for (i
= 0; i
< auth
->num_freq
; i
++) {
1850 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
1851 if (os_snprintf_error(end
- pos
, res
))
1856 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
1863 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
1864 struct dpp_bootstrap_info
*peer_bi
,
1865 struct dpp_bootstrap_info
*own_bi
,
1867 unsigned int neg_freq
,
1868 struct hostapd_hw_modes
*own_modes
,
1871 struct dpp_authentication
*auth
;
1873 EVP_PKEY_CTX
*ctx
= NULL
;
1875 struct wpabuf
*pi
= NULL
;
1876 u8 zero
[SHA256_MAC_LEN
];
1877 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
1879 auth
= os_zalloc(sizeof(*auth
));
1882 auth
->msg_ctx
= msg_ctx
;
1883 auth
->initiator
= 1;
1884 auth
->waiting_auth_resp
= 1;
1885 auth
->configurator
= configurator
;
1886 auth
->peer_bi
= peer_bi
;
1887 auth
->own_bi
= own_bi
;
1888 auth
->curve
= peer_bi
->curve
;
1890 if (dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
1893 nonce_len
= auth
->curve
->nonce_len
;
1894 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
1895 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
1898 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
1900 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
1901 if (!auth
->own_protocol_key
)
1904 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1908 /* ECDH: M = pI * BR */
1909 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
1911 EVP_PKEY_derive_init(ctx
) != 1 ||
1912 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
1913 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
1914 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
1915 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
1916 wpa_printf(MSG_ERROR
,
1917 "DPP: Failed to derive ECDH shared secret: %s",
1918 ERR_error_string(ERR_get_error(), NULL
));
1921 auth
->secret_len
= secret_len
;
1922 EVP_PKEY_CTX_free(ctx
);
1925 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
1926 auth
->Mx
, auth
->secret_len
);
1928 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
1929 auth
->curve
->hash_len
) < 0)
1932 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
1935 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
1937 os_memset(zero
, 0, SHA256_MAC_LEN
);
1938 i_pubkey_hash
= zero
;
1941 #ifdef CONFIG_TESTING_OPTIONS
1942 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
1943 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
1944 r_pubkey_hash
= NULL
;
1945 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
1946 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
1947 i_pubkey_hash
= NULL
;
1948 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
1949 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
1953 #endif /* CONFIG_TESTING_OPTIONS */
1955 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
1956 i_pubkey_hash
, neg_freq
);
1962 EVP_PKEY_CTX_free(ctx
);
1965 dpp_auth_deinit(auth
);
1971 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
1975 size_t json_len
, clear_len
;
1976 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
1980 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
1982 nonce_len
= auth
->curve
->nonce_len
;
1983 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
1984 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
1987 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
1988 json_len
= os_strlen(json
);
1989 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
1991 /* { E-nonce, configAttrib }ke */
1992 clear_len
= 4 + nonce_len
+ 4 + json_len
;
1993 clear
= wpabuf_alloc(clear_len
);
1994 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
1995 #ifdef CONFIG_TESTING_OPTIONS
1996 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
1998 #endif /* CONFIG_TESTING_OPTIONS */
1999 msg
= wpabuf_alloc(attr_len
);
2003 #ifdef CONFIG_TESTING_OPTIONS
2004 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2005 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2008 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2009 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2010 goto skip_wrapped_data
;
2012 #endif /* CONFIG_TESTING_OPTIONS */
2015 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2016 wpabuf_put_le16(clear
, nonce_len
);
2017 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2019 #ifdef CONFIG_TESTING_OPTIONS
2021 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2022 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2023 goto skip_conf_attr_obj
;
2025 #endif /* CONFIG_TESTING_OPTIONS */
2028 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2029 wpabuf_put_le16(clear
, json_len
);
2030 wpabuf_put_data(clear
, json
, json_len
);
2032 #ifdef CONFIG_TESTING_OPTIONS
2034 #endif /* CONFIG_TESTING_OPTIONS */
2036 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2037 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2038 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2041 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2042 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2043 wpabuf_head(clear
), wpabuf_len(clear
),
2044 0, NULL
, NULL
, wrapped
) < 0)
2046 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2047 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2049 #ifdef CONFIG_TESTING_OPTIONS
2050 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2051 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2052 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
2053 wpabuf_put_le16(msg
, 0);
2056 #endif /* CONFIG_TESTING_OPTIONS */
2058 wpa_hexdump_buf(MSG_DEBUG
,
2059 "DPP: Configuration Request frame attributes", msg
);
2070 static void dpp_auth_success(struct dpp_authentication
*auth
)
2072 wpa_printf(MSG_DEBUG
,
2073 "DPP: Authentication success - clear temporary keys");
2074 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2075 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2076 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2077 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2078 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2080 auth
->auth_success
= 1;
2084 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2086 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2089 size_t i
, num_elem
= 0;
2094 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2095 nonce_len
= auth
->curve
->nonce_len
;
2097 if (auth
->initiator
) {
2098 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2099 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2101 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2104 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2106 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2107 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2109 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2112 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2114 if (!pix
|| !prx
|| !brx
)
2117 addr
[num_elem
] = auth
->i_nonce
;
2118 len
[num_elem
] = nonce_len
;
2121 addr
[num_elem
] = auth
->r_nonce
;
2122 len
[num_elem
] = nonce_len
;
2125 addr
[num_elem
] = wpabuf_head(pix
);
2126 len
[num_elem
] = wpabuf_len(pix
) / 2;
2129 addr
[num_elem
] = wpabuf_head(prx
);
2130 len
[num_elem
] = wpabuf_len(prx
) / 2;
2134 addr
[num_elem
] = wpabuf_head(bix
);
2135 len
[num_elem
] = wpabuf_len(bix
) / 2;
2139 addr
[num_elem
] = wpabuf_head(brx
);
2140 len
[num_elem
] = wpabuf_len(brx
) / 2;
2143 addr
[num_elem
] = &zero
;
2147 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2148 for (i
= 0; i
< num_elem
; i
++)
2149 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2150 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2152 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2153 auth
->curve
->hash_len
);
2163 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2165 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2168 size_t i
, num_elem
= 0;
2173 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2174 nonce_len
= auth
->curve
->nonce_len
;
2176 if (auth
->initiator
) {
2177 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2178 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2180 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2185 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2187 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2188 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2190 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2195 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2197 if (!pix
|| !prx
|| !brx
)
2200 addr
[num_elem
] = auth
->r_nonce
;
2201 len
[num_elem
] = nonce_len
;
2204 addr
[num_elem
] = auth
->i_nonce
;
2205 len
[num_elem
] = nonce_len
;
2208 addr
[num_elem
] = wpabuf_head(prx
);
2209 len
[num_elem
] = wpabuf_len(prx
) / 2;
2212 addr
[num_elem
] = wpabuf_head(pix
);
2213 len
[num_elem
] = wpabuf_len(pix
) / 2;
2216 addr
[num_elem
] = wpabuf_head(brx
);
2217 len
[num_elem
] = wpabuf_len(brx
) / 2;
2221 addr
[num_elem
] = wpabuf_head(bix
);
2222 len
[num_elem
] = wpabuf_len(bix
) / 2;
2226 addr
[num_elem
] = &one
;
2230 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2231 for (i
= 0; i
< num_elem
; i
++)
2232 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2233 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2235 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2236 auth
->curve
->hash_len
);
2246 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2248 const EC_GROUP
*group
;
2250 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2251 const EC_POINT
*BI_point
;
2253 BIGNUM
*lx
, *sum
, *q
;
2254 const BIGNUM
*bR_bn
, *pR_bn
;
2257 /* L = ((bR + pR) modulo q) * BI */
2259 bnctx
= BN_CTX_new();
2263 if (!bnctx
|| !sum
|| !q
|| !lx
)
2265 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2268 BI_point
= EC_KEY_get0_public_key(BI
);
2269 group
= EC_KEY_get0_group(BI
);
2273 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2274 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2277 bR_bn
= EC_KEY_get0_private_key(bR
);
2278 pR_bn
= EC_KEY_get0_private_key(pR
);
2279 if (!bR_bn
|| !pR_bn
)
2281 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2282 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2284 l
= EC_POINT_new(group
);
2286 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2287 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2289 wpa_printf(MSG_ERROR
,
2290 "OpenSSL: failed: %s",
2291 ERR_error_string(ERR_get_error(), NULL
));
2295 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2297 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2300 EC_POINT_clear_free(l
);
2312 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2314 const EC_GROUP
*group
;
2315 EC_POINT
*l
= NULL
, *sum
= NULL
;
2316 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2317 const EC_POINT
*BR_point
, *PR_point
;
2320 const BIGNUM
*bI_bn
;
2323 /* L = bI * (BR + PR) */
2325 bnctx
= BN_CTX_new();
2329 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2330 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2333 BR_point
= EC_KEY_get0_public_key(BR
);
2334 PR_point
= EC_KEY_get0_public_key(PR
);
2336 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2339 group
= EC_KEY_get0_group(bI
);
2340 bI_bn
= EC_KEY_get0_private_key(bI
);
2341 if (!group
|| !bI_bn
)
2343 sum
= EC_POINT_new(group
);
2344 l
= EC_POINT_new(group
);
2346 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2347 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2348 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2350 wpa_printf(MSG_ERROR
,
2351 "OpenSSL: failed: %s",
2352 ERR_error_string(ERR_get_error(), NULL
));
2356 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2358 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2361 EC_POINT_clear_free(l
);
2371 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2374 EVP_PKEY_CTX
*ctx
= NULL
;
2376 struct wpabuf
*msg
, *pr
= NULL
;
2377 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2378 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2379 size_t wrapped_r_auth_len
;
2381 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2382 enum dpp_status_error status
= DPP_STATUS_OK
;
2384 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2386 nonce_len
= auth
->curve
->nonce_len
;
2387 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2388 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2391 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2393 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2394 if (!auth
->own_protocol_key
)
2397 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2401 /* ECDH: N = pR * PI */
2402 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2404 EVP_PKEY_derive_init(ctx
) != 1 ||
2405 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2406 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2407 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2408 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2409 wpa_printf(MSG_ERROR
,
2410 "DPP: Failed to derive ECDH shared secret: %s",
2411 ERR_error_string(ERR_get_error(), NULL
));
2414 EVP_PKEY_CTX_free(ctx
);
2417 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2418 auth
->Nx
, auth
->secret_len
);
2420 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2421 auth
->curve
->hash_len
) < 0)
2424 if (auth
->own_bi
&& auth
->peer_bi
) {
2425 /* Mutual authentication */
2426 if (dpp_auth_derive_l_responder(auth
) < 0)
2430 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2433 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2434 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2435 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2436 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2438 #ifdef CONFIG_TESTING_OPTIONS
2439 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2440 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2441 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2443 #endif /* CONFIG_TESTING_OPTIONS */
2444 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2445 r_auth
, 4 + auth
->curve
->hash_len
,
2446 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2448 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2449 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2450 wrapped_r_auth
, wrapped_r_auth_len
);
2451 w_r_auth
= wrapped_r_auth
;
2453 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2455 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2457 i_pubkey_hash
= NULL
;
2459 i_nonce
= auth
->i_nonce
;
2460 r_nonce
= auth
->r_nonce
;
2462 #ifdef CONFIG_TESTING_OPTIONS
2463 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2464 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2465 r_pubkey_hash
= NULL
;
2466 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2467 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2468 i_pubkey_hash
= NULL
;
2469 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2470 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2473 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2474 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2476 wrapped_r_auth_len
= 0;
2477 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2478 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2480 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2481 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2483 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2484 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2487 #endif /* CONFIG_TESTING_OPTIONS */
2489 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2490 r_pubkey_hash
, i_pubkey_hash
,
2492 w_r_auth
, wrapped_r_auth_len
,
2496 auth
->resp_msg
= msg
;
2504 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2505 enum dpp_status_error status
)
2508 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2510 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2512 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2514 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2516 i_pubkey_hash
= NULL
;
2518 i_nonce
= auth
->i_nonce
;
2520 #ifdef CONFIG_TESTING_OPTIONS
2521 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2522 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2523 r_pubkey_hash
= NULL
;
2524 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2525 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2526 i_pubkey_hash
= NULL
;
2527 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2528 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2530 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2531 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2534 #endif /* CONFIG_TESTING_OPTIONS */
2536 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
2537 r_pubkey_hash
, i_pubkey_hash
,
2538 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
2541 auth
->resp_msg
= msg
;
2546 struct dpp_authentication
*
2547 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
2548 struct dpp_bootstrap_info
*peer_bi
,
2549 struct dpp_bootstrap_info
*own_bi
,
2550 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
2553 EVP_PKEY
*pi
= NULL
;
2554 EVP_PKEY_CTX
*ctx
= NULL
;
2558 u8
*unwrapped
= NULL
;
2559 size_t unwrapped_len
= 0;
2560 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
2562 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
2563 i_bootstrap_len
, channel_len
;
2564 struct dpp_authentication
*auth
= NULL
;
2566 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2568 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
2569 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
2570 "Missing or invalid required Wrapped Data attribute");
2573 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
2574 wrapped_data
, wrapped_data_len
);
2575 attr_len
= wrapped_data
- 4 - attr_start
;
2577 auth
= os_zalloc(sizeof(*auth
));
2580 auth
->msg_ctx
= msg_ctx
;
2581 auth
->peer_bi
= peer_bi
;
2582 auth
->own_bi
= own_bi
;
2583 auth
->curve
= own_bi
->curve
;
2584 auth
->curr_freq
= freq
;
2586 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
2591 if (channel_len
< 2) {
2592 dpp_auth_fail(auth
, "Too short Channel attribute");
2596 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
2597 wpa_printf(MSG_DEBUG
,
2598 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2599 channel
[0], channel
[1], neg_freq
);
2602 "Unsupported Channel attribute value");
2606 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
2607 wpa_printf(MSG_DEBUG
,
2608 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2610 auth
->curr_freq
= neg_freq
;
2614 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
2618 "Missing required Initiator Protocol Key attribute");
2621 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
2622 i_proto
, i_proto_len
);
2625 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
2627 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
2630 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
2632 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
2634 EVP_PKEY_derive_init(ctx
) != 1 ||
2635 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
2636 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2637 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2638 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2639 wpa_printf(MSG_ERROR
,
2640 "DPP: Failed to derive ECDH shared secret: %s",
2641 ERR_error_string(ERR_get_error(), NULL
));
2642 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
2645 auth
->secret_len
= secret_len
;
2646 EVP_PKEY_CTX_free(ctx
);
2649 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2650 auth
->Mx
, auth
->secret_len
);
2652 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2653 auth
->curve
->hash_len
) < 0)
2657 len
[0] = DPP_HDR_LEN
;
2658 addr
[1] = attr_start
;
2660 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2661 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2662 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2663 wrapped_data
, wrapped_data_len
);
2664 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2665 unwrapped
= os_malloc(unwrapped_len
);
2668 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
2669 wrapped_data
, wrapped_data_len
,
2670 2, addr
, len
, unwrapped
) < 0) {
2671 dpp_auth_fail(auth
, "AES-SIV decryption failed");
2674 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2675 unwrapped
, unwrapped_len
);
2677 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
2678 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
2682 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
2684 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
2685 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
2688 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
2689 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
2691 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
2692 DPP_ATTR_I_CAPABILITIES
,
2694 if (!i_capab
|| i_capab_len
< 1) {
2695 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
2698 auth
->i_capab
= i_capab
[0];
2699 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
2701 bin_clear_free(unwrapped
, unwrapped_len
);
2704 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
2705 case DPP_CAPAB_ENROLLEE
:
2706 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
2707 wpa_printf(MSG_DEBUG
,
2708 "DPP: Local policy does not allow Configurator role");
2709 goto not_compatible
;
2711 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
2712 auth
->configurator
= 1;
2714 case DPP_CAPAB_CONFIGURATOR
:
2715 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
2716 wpa_printf(MSG_DEBUG
,
2717 "DPP: Local policy does not allow Enrollee role");
2718 goto not_compatible
;
2720 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
2721 auth
->configurator
= 0;
2724 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
2725 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
2726 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
2727 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
2731 auth
->peer_protocol_key
= pi
;
2733 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
2734 char hex
[SHA256_MAC_LEN
* 2 + 1];
2736 wpa_printf(MSG_DEBUG
,
2737 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2738 if (dpp_auth_build_resp_status(auth
,
2739 DPP_STATUS_RESPONSE_PENDING
) < 0)
2741 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2742 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
2744 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
2745 auth
->response_pending
= 1;
2746 os_memcpy(auth
->waiting_pubkey_hash
,
2747 i_bootstrap
, i_bootstrap_len
);
2748 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
2754 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
2758 if (dpp_auth_build_resp_ok(auth
) < 0)
2764 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
2765 "i-capab=0x%02x", auth
->i_capab
);
2766 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
2767 auth
->configurator
= 1;
2769 auth
->configurator
= 0;
2770 auth
->peer_protocol_key
= pi
;
2772 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
2775 auth
->remove_on_tx_status
= 1;
2778 bin_clear_free(unwrapped
, unwrapped_len
);
2780 EVP_PKEY_CTX_free(ctx
);
2781 dpp_auth_deinit(auth
);
2786 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
2787 struct dpp_bootstrap_info
*peer_bi
)
2789 if (!auth
|| !auth
->response_pending
||
2790 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
2791 SHA256_MAC_LEN
) != 0)
2794 wpa_printf(MSG_DEBUG
,
2795 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2796 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
2797 auth
->peer_bi
= peer_bi
;
2799 if (dpp_auth_build_resp_ok(auth
) < 0)
2806 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
2807 enum dpp_status_error status
)
2810 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
2812 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
2815 size_t len
[2], attr_len
;
2817 u8
*wrapped_r_nonce
;
2818 u8
*attr_start
, *attr_end
;
2820 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
2822 i_auth_len
= 4 + auth
->curve
->hash_len
;
2823 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
2824 /* Build DPP Authentication Confirmation frame attributes */
2825 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
2826 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
2827 #ifdef CONFIG_TESTING_OPTIONS
2828 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
2830 #endif /* CONFIG_TESTING_OPTIONS */
2831 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
2835 attr_start
= wpabuf_put(msg
, 0);
2837 #ifdef CONFIG_TESTING_OPTIONS
2838 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
)
2840 #endif /* CONFIG_TESTING_OPTIONS */
2843 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
2844 wpabuf_put_le16(msg
, 1);
2845 wpabuf_put_u8(msg
, status
);
2847 #ifdef CONFIG_TESTING_OPTIONS
2849 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
)
2850 goto skip_r_bootstrap_key
;
2851 #endif /* CONFIG_TESTING_OPTIONS */
2853 /* Responder Bootstrapping Key Hash */
2854 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
2855 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2856 wpabuf_put_data(msg
, auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2858 #ifdef CONFIG_TESTING_OPTIONS
2859 skip_r_bootstrap_key
:
2860 if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
)
2861 goto skip_i_bootstrap_key
;
2862 #endif /* CONFIG_TESTING_OPTIONS */
2865 /* Mutual authentication */
2866 /* Initiator Bootstrapping Key Hash */
2867 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
2868 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2869 wpabuf_put_data(msg
, auth
->own_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2872 #ifdef CONFIG_TESTING_OPTIONS
2873 skip_i_bootstrap_key
:
2874 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
2875 goto skip_wrapped_data
;
2876 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
2878 #endif /* CONFIG_TESTING_OPTIONS */
2880 attr_end
= wpabuf_put(msg
, 0);
2882 /* OUI, OUI type, Crypto Suite, DPP frame type */
2883 addr
[0] = wpabuf_head_u8(msg
) + 2;
2884 len
[0] = 3 + 1 + 1 + 1;
2885 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2887 /* Attributes before Wrapped Data */
2888 addr
[1] = attr_start
;
2889 len
[1] = attr_end
- attr_start
;
2890 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2892 if (status
== DPP_STATUS_OK
) {
2893 /* I-auth wrapped with ke */
2894 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2895 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
2896 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
2898 #ifdef CONFIG_TESTING_OPTIONS
2899 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
2901 #endif /* CONFIG_TESTING_OPTIONS */
2903 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
2905 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
2906 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
2907 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
2910 #ifdef CONFIG_TESTING_OPTIONS
2911 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
2912 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
2913 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2916 #endif /* CONFIG_TESTING_OPTIONS */
2917 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2919 2, addr
, len
, wrapped_i_auth
) < 0)
2921 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
2922 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
2924 /* R-nonce wrapped with k2 */
2925 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2926 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
2927 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
2929 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
2930 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
2931 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
2933 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
2934 r_nonce
, r_nonce_len
,
2935 2, addr
, len
, wrapped_r_nonce
) < 0)
2937 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
2938 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
2941 #ifdef CONFIG_TESTING_OPTIONS
2942 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
2943 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2944 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
2945 wpabuf_put_le16(msg
, 0);
2948 #endif /* CONFIG_TESTING_OPTIONS */
2950 wpa_hexdump_buf(MSG_DEBUG
,
2951 "DPP: Authentication Confirmation frame attributes",
2953 if (status
== DPP_STATUS_OK
)
2954 dpp_auth_success(auth
);
2964 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
2965 const u8
*attr_start
, size_t attr_len
,
2966 const u8
*wrapped_data
, u16 wrapped_data_len
,
2967 enum dpp_status_error status
)
2971 u8
*unwrapped
= NULL
;
2972 size_t unwrapped_len
= 0;
2973 const u8
*i_nonce
, *r_capab
;
2974 u16 i_nonce_len
, r_capab_len
;
2976 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
2977 wpa_printf(MSG_DEBUG
,
2978 "DPP: Responder reported incompatible roles");
2979 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
2980 wpa_printf(MSG_DEBUG
,
2981 "DPP: Responder reported more time needed");
2983 wpa_printf(MSG_DEBUG
,
2984 "DPP: Responder reported failure (status %d)",
2986 dpp_auth_fail(auth
, "Responder reported failure");
2991 len
[0] = DPP_HDR_LEN
;
2992 addr
[1] = attr_start
;
2994 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2995 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2996 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2997 wrapped_data
, wrapped_data_len
);
2998 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2999 unwrapped
= os_malloc(unwrapped_len
);
3002 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3003 wrapped_data
, wrapped_data_len
,
3004 2, addr
, len
, unwrapped
) < 0) {
3005 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3008 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3009 unwrapped
, unwrapped_len
);
3011 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3012 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3016 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3018 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3019 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3022 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3023 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3024 dpp_auth_fail(auth
, "I-nonce mismatch");
3028 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3029 DPP_ATTR_R_CAPABILITIES
,
3031 if (!r_capab
|| r_capab_len
< 1) {
3032 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3035 auth
->r_capab
= r_capab
[0];
3036 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3037 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3038 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3039 "r-capab=0x%02x", auth
->r_capab
);
3040 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3041 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3043 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3044 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3045 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3046 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3049 wpa_printf(MSG_DEBUG
,
3050 "DPP: Continue waiting for full DPP Authentication Response");
3051 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_RESPONSE_PENDING
);
3055 bin_clear_free(unwrapped
, unwrapped_len
);
3060 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3061 const u8
*attr_start
, size_t attr_len
)
3064 EVP_PKEY_CTX
*ctx
= NULL
;
3068 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3069 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3070 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3071 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3072 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3073 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3074 wrapped2_len
, r_auth_len
;
3075 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3078 auth
->waiting_auth_resp
= 0;
3080 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3082 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3084 "Missing or invalid required Wrapped Data attribute");
3087 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3088 wrapped_data
, wrapped_data_len
);
3090 attr_len
= wrapped_data
- 4 - attr_start
;
3092 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3093 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3095 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3097 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3100 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3101 r_bootstrap
, r_bootstrap_len
);
3102 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3103 SHA256_MAC_LEN
) != 0) {
3105 "Unexpected Responder Bootstrapping Key Hash value");
3106 wpa_hexdump(MSG_DEBUG
,
3107 "DPP: Expected Responder Bootstrapping Key Hash",
3108 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3112 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3113 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3116 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3118 "Invalid Initiator Bootstrapping Key Hash attribute");
3121 wpa_hexdump(MSG_MSGDUMP
,
3122 "DPP: Initiator Bootstrapping Key Hash",
3123 i_bootstrap
, i_bootstrap_len
);
3124 if (!auth
->own_bi
||
3125 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3126 SHA256_MAC_LEN
) != 0) {
3128 "Initiator Bootstrapping Key Hash attribute did not match");
3131 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3132 /* PKEX bootstrapping mandates use of mutual authentication */
3134 "Missing Initiator Bootstrapping Key Hash attribute");
3138 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3140 if (!status
|| status_len
< 1) {
3142 "Missing or invalid required DPP Status attribute");
3145 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3146 auth
->auth_resp_status
= status
[0];
3147 if (status
[0] != DPP_STATUS_OK
) {
3148 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3149 attr_len
, wrapped_data
,
3150 wrapped_data_len
, status
[0]);
3154 if (!i_bootstrap
&& auth
->own_bi
) {
3155 wpa_printf(MSG_DEBUG
,
3156 "DPP: Responder decided not to use mutual authentication");
3157 auth
->own_bi
= NULL
;
3160 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3164 "Missing required Responder Protocol Key attribute");
3167 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3168 r_proto
, r_proto_len
);
3171 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3173 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3176 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3178 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3180 EVP_PKEY_derive_init(ctx
) != 1 ||
3181 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3182 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3183 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3184 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3185 wpa_printf(MSG_ERROR
,
3186 "DPP: Failed to derive ECDH shared secret: %s",
3187 ERR_error_string(ERR_get_error(), NULL
));
3188 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3191 EVP_PKEY_CTX_free(ctx
);
3193 auth
->peer_protocol_key
= pr
;
3196 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3197 auth
->Nx
, auth
->secret_len
);
3199 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3200 auth
->curve
->hash_len
) < 0)
3204 len
[0] = DPP_HDR_LEN
;
3205 addr
[1] = attr_start
;
3207 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3208 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3209 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3210 wrapped_data
, wrapped_data_len
);
3211 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3212 unwrapped
= os_malloc(unwrapped_len
);
3215 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3216 wrapped_data
, wrapped_data_len
,
3217 2, addr
, len
, unwrapped
) < 0) {
3218 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3221 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3222 unwrapped
, unwrapped_len
);
3224 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3225 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3229 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3231 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3232 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3235 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3236 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3238 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3240 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3241 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3244 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3245 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3246 dpp_auth_fail(auth
, "I-nonce mismatch");
3250 if (auth
->own_bi
&& auth
->peer_bi
) {
3251 /* Mutual authentication */
3252 if (dpp_auth_derive_l_initiator(auth
) < 0)
3256 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3257 DPP_ATTR_R_CAPABILITIES
,
3259 if (!r_capab
|| r_capab_len
< 1) {
3260 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3263 auth
->r_capab
= r_capab
[0];
3264 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3265 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3266 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3267 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3268 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3269 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3270 "Unexpected role in R-capabilities 0x%02x",
3272 if (role
!= DPP_CAPAB_ENROLLEE
&&
3273 role
!= DPP_CAPAB_CONFIGURATOR
)
3275 bin_clear_free(unwrapped
, unwrapped_len
);
3276 auth
->remove_on_tx_status
= 1;
3277 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3280 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3281 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3282 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3284 "Missing or invalid Secondary Wrapped Data");
3288 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3289 wrapped2
, wrapped2_len
);
3291 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3294 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3295 unwrapped2
= os_malloc(unwrapped2_len
);
3298 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3299 wrapped2
, wrapped2_len
,
3300 0, NULL
, NULL
, unwrapped2
) < 0) {
3301 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3304 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3305 unwrapped2
, unwrapped2_len
);
3307 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3309 "Invalid attribute in secondary unwrapped data");
3313 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3315 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3317 "Missing or invalid Responder Authenticating Tag");
3320 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3321 r_auth
, r_auth_len
);
3322 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3323 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3325 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3326 r_auth2
, r_auth_len
);
3327 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3328 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3329 bin_clear_free(unwrapped
, unwrapped_len
);
3330 bin_clear_free(unwrapped2
, unwrapped2_len
);
3331 auth
->remove_on_tx_status
= 1;
3332 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3335 bin_clear_free(unwrapped
, unwrapped_len
);
3336 bin_clear_free(unwrapped2
, unwrapped2_len
);
3338 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3341 bin_clear_free(unwrapped
, unwrapped_len
);
3342 bin_clear_free(unwrapped2
, unwrapped2_len
);
3344 EVP_PKEY_CTX_free(ctx
);
3349 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3351 const u8
*attr_start
, size_t attr_len
,
3352 const u8
*wrapped_data
,
3353 u16 wrapped_data_len
,
3354 enum dpp_status_error status
)
3358 u8
*unwrapped
= NULL
;
3359 size_t unwrapped_len
= 0;
3363 /* Authentication Confirm failure cases are expected to include
3364 * {R-nonce}k2 in the Wrapped Data attribute. */
3367 len
[0] = DPP_HDR_LEN
;
3368 addr
[1] = attr_start
;
3370 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3371 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3372 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3373 wrapped_data
, wrapped_data_len
);
3374 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3375 unwrapped
= os_malloc(unwrapped_len
);
3377 dpp_auth_fail(auth
, "Authentication failed");
3380 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3381 wrapped_data
, wrapped_data_len
,
3382 2, addr
, len
, unwrapped
) < 0) {
3383 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3386 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3387 unwrapped
, unwrapped_len
);
3389 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3390 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3394 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3396 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3397 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3400 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3401 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3402 r_nonce
, r_nonce_len
);
3403 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3404 auth
->r_nonce
, r_nonce_len
);
3405 dpp_auth_fail(auth
, "R-nonce mismatch");
3409 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3410 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3411 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3412 dpp_auth_fail(auth
, "Peer reported authentication failure)");
3415 bin_clear_free(unwrapped
, unwrapped_len
);
3420 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3421 const u8
*attr_start
, size_t attr_len
)
3423 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
3424 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3428 u8
*unwrapped
= NULL
;
3429 size_t unwrapped_len
= 0;
3430 u8 i_auth2
[DPP_MAX_HASH_LEN
];
3432 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3434 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3436 "Missing or invalid required Wrapped Data attribute");
3439 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3440 wrapped_data
, wrapped_data_len
);
3442 attr_len
= wrapped_data
- 4 - attr_start
;
3444 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3445 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3447 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3449 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3452 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3453 r_bootstrap
, r_bootstrap_len
);
3454 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
3455 SHA256_MAC_LEN
) != 0) {
3456 wpa_hexdump(MSG_DEBUG
,
3457 "DPP: Expected Responder Bootstrapping Key Hash",
3458 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3460 "Responder Bootstrapping Key Hash mismatch");
3464 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3465 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3468 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3470 "Invalid Initiator Bootstrapping Key Hash attribute");
3473 wpa_hexdump(MSG_MSGDUMP
,
3474 "DPP: Initiator Bootstrapping Key Hash",
3475 i_bootstrap
, i_bootstrap_len
);
3476 if (!auth
->peer_bi
||
3477 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3478 SHA256_MAC_LEN
) != 0) {
3480 "Initiator Bootstrapping Key Hash mismatch");
3483 } else if (auth
->own_bi
&& auth
->peer_bi
) {
3484 /* Mutual authentication and peer did not include its
3485 * Bootstrapping Key Hash attribute. */
3487 "Missing Initiator Bootstrapping Key Hash attribute");
3491 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3493 if (!status
|| status_len
< 1) {
3495 "Missing or invalid required DPP Status attribute");
3498 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3499 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
3500 status
[0] == DPP_STATUS_AUTH_FAILURE
)
3501 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
3502 attr_len
, wrapped_data
,
3503 wrapped_data_len
, status
[0]);
3505 if (status
[0] != DPP_STATUS_OK
) {
3506 dpp_auth_fail(auth
, "Authentication failed");
3511 len
[0] = DPP_HDR_LEN
;
3512 addr
[1] = attr_start
;
3514 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3515 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3516 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3517 wrapped_data
, wrapped_data_len
);
3518 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3519 unwrapped
= os_malloc(unwrapped_len
);
3522 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3523 wrapped_data
, wrapped_data_len
,
3524 2, addr
, len
, unwrapped
) < 0) {
3525 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3528 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3529 unwrapped
, unwrapped_len
);
3531 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3532 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3536 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
3538 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
3540 "Missing or invalid Initiator Authenticating Tag");
3543 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
3544 i_auth
, i_auth_len
);
3545 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3546 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
3548 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
3549 i_auth2
, i_auth_len
);
3550 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
3551 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
3555 bin_clear_free(unwrapped
, unwrapped_len
);
3556 dpp_auth_success(auth
);
3559 bin_clear_free(unwrapped
, unwrapped_len
);
3564 void dpp_configuration_free(struct dpp_configuration
*conf
)
3568 str_clear_free(conf
->passphrase
);
3569 bin_clear_free(conf
, sizeof(*conf
));
3573 void dpp_auth_deinit(struct dpp_authentication
*auth
)
3577 dpp_configuration_free(auth
->conf_ap
);
3578 dpp_configuration_free(auth
->conf_sta
);
3579 EVP_PKEY_free(auth
->own_protocol_key
);
3580 EVP_PKEY_free(auth
->peer_protocol_key
);
3581 wpabuf_free(auth
->req_msg
);
3582 wpabuf_free(auth
->resp_msg
);
3583 wpabuf_free(auth
->conf_req
);
3584 os_free(auth
->connector
);
3585 wpabuf_free(auth
->net_access_key
);
3586 wpabuf_free(auth
->c_sign_key
);
3587 #ifdef CONFIG_TESTING_OPTIONS
3588 os_free(auth
->config_obj_override
);
3589 os_free(auth
->discovery_override
);
3590 os_free(auth
->groups_override
);
3591 #endif /* CONFIG_TESTING_OPTIONS */
3592 bin_clear_free(auth
, sizeof(*auth
));
3596 static struct wpabuf
*
3597 dpp_build_conf_start(struct dpp_authentication
*auth
,
3598 struct dpp_configuration
*conf
, size_t tailroom
)
3601 char ssid
[6 * sizeof(conf
->ssid
) + 1];
3603 #ifdef CONFIG_TESTING_OPTIONS
3604 if (auth
->discovery_override
)
3605 tailroom
+= os_strlen(auth
->discovery_override
);
3606 #endif /* CONFIG_TESTING_OPTIONS */
3608 buf
= wpabuf_alloc(200 + tailroom
);
3611 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
3612 #ifdef CONFIG_TESTING_OPTIONS
3613 if (auth
->discovery_override
) {
3614 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
3615 auth
->discovery_override
);
3616 wpabuf_put_str(buf
, auth
->discovery_override
);
3617 wpabuf_put_u8(buf
, ',');
3620 #endif /* CONFIG_TESTING_OPTIONS */
3621 wpabuf_put_str(buf
, "{\"ssid\":\"");
3622 json_escape_string(ssid
, sizeof(ssid
),
3623 (const char *) conf
->ssid
, conf
->ssid_len
);
3624 wpabuf_put_str(buf
, ssid
);
3625 wpabuf_put_str(buf
, "\"},");
3631 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
3632 const char *kid
, const struct dpp_curve_params
*curve
)
3636 char *x
= NULL
, *y
= NULL
;
3639 pub
= dpp_get_pubkey_point(key
, 0);
3642 pos
= wpabuf_head(pub
);
3643 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
3644 pos
+= curve
->prime_len
;
3645 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
3649 wpabuf_put_str(buf
, "\"");
3650 wpabuf_put_str(buf
, name
);
3651 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
3652 wpabuf_put_str(buf
, curve
->jwk_crv
);
3653 wpabuf_put_str(buf
, "\",\"x\":\"");
3654 wpabuf_put_str(buf
, x
);
3655 wpabuf_put_str(buf
, "\",\"y\":\"");
3656 wpabuf_put_str(buf
, y
);
3658 wpabuf_put_str(buf
, "\",\"kid\":\"");
3659 wpabuf_put_str(buf
, kid
);
3661 wpabuf_put_str(buf
, "\"}");
3671 static struct wpabuf
*
3672 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
3673 struct dpp_configuration
*conf
)
3675 struct wpabuf
*buf
= NULL
;
3676 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
3678 const struct dpp_curve_params
*curve
;
3679 char jws_prot_hdr
[100];
3680 size_t signed1_len
, signed2_len
, signed3_len
;
3681 struct wpabuf
*dppcon
= NULL
;
3682 unsigned char *signature
= NULL
;
3683 const unsigned char *p
;
3684 size_t signature_len
;
3685 EVP_MD_CTX
*md_ctx
= NULL
;
3686 ECDSA_SIG
*sig
= NULL
;
3688 const EVP_MD
*sign_md
;
3689 const BIGNUM
*r
, *s
;
3690 size_t extra_len
= 1000;
3693 wpa_printf(MSG_INFO
,
3694 "DPP: No configurator specified - cannot generate DPP config object");
3697 curve
= auth
->conf
->curve
;
3698 if (curve
->hash_len
== SHA256_MAC_LEN
) {
3699 sign_md
= EVP_sha256();
3700 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
3701 sign_md
= EVP_sha384();
3702 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
3703 sign_md
= EVP_sha512();
3705 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
3709 #ifdef CONFIG_TESTING_OPTIONS
3710 if (auth
->groups_override
)
3711 extra_len
+= os_strlen(auth
->groups_override
);
3712 #endif /* CONFIG_TESTING_OPTIONS */
3714 /* Connector (JSON dppCon object) */
3715 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
3718 #ifdef CONFIG_TESTING_OPTIONS
3719 if (auth
->groups_override
) {
3720 wpabuf_put_u8(dppcon
, '{');
3721 if (auth
->groups_override
) {
3722 wpa_printf(MSG_DEBUG
,
3723 "DPP: TESTING - groups override: '%s'",
3724 auth
->groups_override
);
3725 wpabuf_put_str(dppcon
, "\"groups\":");
3726 wpabuf_put_str(dppcon
, auth
->groups_override
);
3727 wpabuf_put_u8(dppcon
, ',');
3731 #endif /* CONFIG_TESTING_OPTIONS */
3732 wpabuf_put_str(dppcon
, "{\"groups\":[{\"groupId\":\"*\",");
3733 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
3734 #ifdef CONFIG_TESTING_OPTIONS
3736 #endif /* CONFIG_TESTING_OPTIONS */
3737 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
3739 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
3742 if (conf
->netaccesskey_expiry
) {
3745 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
3746 wpa_printf(MSG_DEBUG
,
3747 "DPP: Failed to generate expiry string");
3750 wpabuf_printf(dppcon
,
3751 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3752 tm
.year
, tm
.month
, tm
.day
,
3753 tm
.hour
, tm
.min
, tm
.sec
);
3755 wpabuf_put_u8(dppcon
, '}');
3756 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
3757 (const char *) wpabuf_head(dppcon
));
3759 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
3760 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
3761 auth
->conf
->kid
, curve
->jws_alg
);
3762 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
3763 os_strlen(jws_prot_hdr
),
3765 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
3768 if (!signed1
|| !signed2
)
3771 md_ctx
= EVP_MD_CTX_create();
3776 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
3777 auth
->conf
->csign
) != 1) {
3778 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
3779 ERR_error_string(ERR_get_error(), NULL
));
3782 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
3783 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
3784 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
3785 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
3786 ERR_error_string(ERR_get_error(), NULL
));
3789 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
3790 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
3791 ERR_error_string(ERR_get_error(), NULL
));
3794 signature
= os_malloc(signature_len
);
3797 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
3798 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
3799 ERR_error_string(ERR_get_error(), NULL
));
3802 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
3803 signature
, signature_len
);
3804 /* Convert to raw coordinates r,s */
3806 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
3809 ECDSA_SIG_get0(sig
, &r
, &s
);
3810 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
3811 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
3812 curve
->prime_len
) < 0)
3814 signature_len
= 2 * curve
->prime_len
;
3815 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
3816 signature
, signature_len
);
3817 signed3
= (char *) base64_url_encode(signature
, signature_len
,
3823 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
3824 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
3825 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
3829 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
3830 wpabuf_put_str(buf
, signed1
);
3831 wpabuf_put_u8(buf
, '.');
3832 wpabuf_put_str(buf
, signed2
);
3833 wpabuf_put_u8(buf
, '.');
3834 wpabuf_put_str(buf
, signed3
);
3835 wpabuf_put_str(buf
, "\",");
3836 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
3838 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
3842 wpabuf_put_str(buf
, "}}");
3844 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
3845 wpabuf_head(buf
), wpabuf_len(buf
));
3848 EVP_MD_CTX_destroy(md_ctx
);
3849 ECDSA_SIG_free(sig
);
3854 wpabuf_free(dppcon
);
3857 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
3864 static struct wpabuf
*
3865 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
3866 struct dpp_configuration
*conf
)
3870 buf
= dpp_build_conf_start(auth
, conf
, 1000);
3874 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"psk\",");
3875 if (conf
->passphrase
) {
3876 char pass
[63 * 6 + 1];
3878 if (os_strlen(conf
->passphrase
) > 63) {
3883 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
3884 os_strlen(conf
->passphrase
));
3885 wpabuf_put_str(buf
, "\"pass\":\"");
3886 wpabuf_put_str(buf
, pass
);
3887 wpabuf_put_str(buf
, "\"");
3889 char psk
[2 * sizeof(conf
->psk
) + 1];
3891 wpa_snprintf_hex(psk
, sizeof(psk
),
3892 conf
->psk
, sizeof(conf
->psk
));
3893 wpabuf_put_str(buf
, "\"psk_hex\":\"");
3894 wpabuf_put_str(buf
, psk
);
3895 wpabuf_put_str(buf
, "\"");
3897 wpabuf_put_str(buf
, "}}");
3899 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
3900 wpabuf_head(buf
), wpabuf_len(buf
));
3906 static struct wpabuf
*
3907 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
3909 struct dpp_configuration
*conf
;
3911 #ifdef CONFIG_TESTING_OPTIONS
3912 if (auth
->config_obj_override
) {
3913 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
3914 return wpabuf_alloc_copy(auth
->config_obj_override
,
3915 os_strlen(auth
->config_obj_override
));
3917 #endif /* CONFIG_TESTING_OPTIONS */
3919 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
3921 wpa_printf(MSG_DEBUG
,
3922 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
3928 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
3929 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
3933 static struct wpabuf
*
3934 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
3935 u16 e_nonce_len
, int ap
)
3937 struct wpabuf
*conf
;
3938 size_t clear_len
, attr_len
;
3939 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
3943 enum dpp_status_error status
;
3945 conf
= dpp_build_conf_obj(auth
, ap
);
3947 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
3948 wpabuf_head(conf
), wpabuf_len(conf
));
3950 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
3952 /* { E-nonce, configurationObject}ke */
3953 clear_len
= 4 + e_nonce_len
;
3955 clear_len
+= 4 + wpabuf_len(conf
);
3956 clear
= wpabuf_alloc(clear_len
);
3957 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
3958 #ifdef CONFIG_TESTING_OPTIONS
3959 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
3961 #endif /* CONFIG_TESTING_OPTIONS */
3962 msg
= wpabuf_alloc(attr_len
);
3966 #ifdef CONFIG_TESTING_OPTIONS
3967 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
3968 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
3971 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
3972 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
3973 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
3974 wpabuf_put_le16(clear
, e_nonce_len
);
3975 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
3976 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
3979 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
3980 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
3981 goto skip_wrapped_data
;
3983 #endif /* CONFIG_TESTING_OPTIONS */
3986 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
3987 wpabuf_put_le16(clear
, e_nonce_len
);
3988 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
3990 #ifdef CONFIG_TESTING_OPTIONS
3992 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
3993 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
3994 goto skip_config_obj
;
3996 #endif /* CONFIG_TESTING_OPTIONS */
3999 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4000 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4001 wpabuf_put_buf(clear
, conf
);
4004 #ifdef CONFIG_TESTING_OPTIONS
4006 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4007 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4010 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4011 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4014 #endif /* CONFIG_TESTING_OPTIONS */
4017 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
4018 wpabuf_put_le16(msg
, 1);
4019 wpabuf_put_u8(msg
, status
);
4021 #ifdef CONFIG_TESTING_OPTIONS
4023 #endif /* CONFIG_TESTING_OPTIONS */
4025 addr
[0] = wpabuf_head(msg
);
4026 len
[0] = wpabuf_len(msg
);
4027 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4029 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4030 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4031 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4033 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4034 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4035 wpabuf_head(clear
), wpabuf_len(clear
),
4036 1, addr
, len
, wrapped
) < 0)
4038 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4039 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4041 #ifdef CONFIG_TESTING_OPTIONS
4042 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4043 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4044 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
4045 wpabuf_put_le16(msg
, 0);
4048 #endif /* CONFIG_TESTING_OPTIONS */
4050 wpa_hexdump_buf(MSG_DEBUG
,
4051 "DPP: Configuration Response attributes", msg
);
4065 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4068 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4069 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4070 u8
*unwrapped
= NULL
;
4071 size_t unwrapped_len
= 0;
4072 struct wpabuf
*resp
= NULL
;
4073 struct json_token
*root
= NULL
, *token
;
4076 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4077 dpp_auth_fail(auth
, "Invalid attribute in config request");
4081 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4083 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4085 "Missing or invalid required Wrapped Data attribute");
4089 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4090 wrapped_data
, wrapped_data_len
);
4091 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4092 unwrapped
= os_malloc(unwrapped_len
);
4095 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4096 wrapped_data
, wrapped_data_len
,
4097 0, NULL
, NULL
, unwrapped
) < 0) {
4098 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4101 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4102 unwrapped
, unwrapped_len
);
4104 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4105 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4109 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4110 DPP_ATTR_ENROLLEE_NONCE
,
4112 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4114 "Missing or invalid Enrollee Nonce attribute");
4117 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4119 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
4120 DPP_ATTR_CONFIG_ATTR_OBJ
,
4124 "Missing or invalid Config Attributes attribute");
4127 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
4128 config_attr
, config_attr_len
);
4130 root
= json_parse((const char *) config_attr
, config_attr_len
);
4132 dpp_auth_fail(auth
, "Could not parse Config Attributes");
4136 token
= json_get_member(root
, "name");
4137 if (!token
|| token
->type
!= JSON_STRING
) {
4138 dpp_auth_fail(auth
, "No Config Attributes - name");
4141 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
4143 token
= json_get_member(root
, "wi-fi_tech");
4144 if (!token
|| token
->type
!= JSON_STRING
) {
4145 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
4148 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
4149 if (os_strcmp(token
->string
, "infra") != 0) {
4150 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
4152 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
4156 token
= json_get_member(root
, "netRole");
4157 if (!token
|| token
->type
!= JSON_STRING
) {
4158 dpp_auth_fail(auth
, "No Config Attributes - netRole");
4161 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
4162 if (os_strcmp(token
->string
, "sta") == 0) {
4164 } else if (os_strcmp(token
->string
, "ap") == 0) {
4167 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
4169 dpp_auth_fail(auth
, "Unsupported netRole");
4173 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
4182 static struct wpabuf
*
4183 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
4184 const u8
*prot_hdr
, u16 prot_hdr_len
,
4185 const EVP_MD
**ret_md
)
4187 struct json_token
*root
, *token
;
4188 struct wpabuf
*kid
= NULL
;
4190 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
4192 wpa_printf(MSG_DEBUG
,
4193 "DPP: JSON parsing failed for JWS Protected Header");
4197 if (root
->type
!= JSON_OBJECT
) {
4198 wpa_printf(MSG_DEBUG
,
4199 "DPP: JWS Protected Header root is not an object");
4203 token
= json_get_member(root
, "typ");
4204 if (!token
|| token
->type
!= JSON_STRING
) {
4205 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
4208 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
4210 if (os_strcmp(token
->string
, "dppCon") != 0) {
4211 wpa_printf(MSG_DEBUG
,
4212 "DPP: Unsupported JWS Protected Header typ=%s",
4217 token
= json_get_member(root
, "alg");
4218 if (!token
|| token
->type
!= JSON_STRING
) {
4219 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
4222 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
4224 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
4225 wpa_printf(MSG_DEBUG
,
4226 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4227 token
->string
, curve
->jws_alg
);
4230 if (os_strcmp(token
->string
, "ES256") == 0 ||
4231 os_strcmp(token
->string
, "BS256") == 0)
4232 *ret_md
= EVP_sha256();
4233 else if (os_strcmp(token
->string
, "ES384") == 0 ||
4234 os_strcmp(token
->string
, "BS384") == 0)
4235 *ret_md
= EVP_sha384();
4236 else if (os_strcmp(token
->string
, "ES512") == 0 ||
4237 os_strcmp(token
->string
, "BS512") == 0)
4238 *ret_md
= EVP_sha512();
4242 wpa_printf(MSG_DEBUG
,
4243 "DPP: Unsupported JWS Protected Header alg=%s",
4248 kid
= json_get_member_base64url(root
, "kid");
4250 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
4253 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
4262 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
4263 struct json_token
*cred
)
4265 struct json_token
*pass
, *psk_hex
;
4267 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
4269 pass
= json_get_member(cred
, "pass");
4270 psk_hex
= json_get_member(cred
, "psk_hex");
4272 if (pass
&& pass
->type
== JSON_STRING
) {
4273 size_t len
= os_strlen(pass
->string
);
4275 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
4277 if (len
< 8 || len
> 63)
4279 os_strlcpy(auth
->passphrase
, pass
->string
,
4280 sizeof(auth
->passphrase
));
4281 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
4282 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
4283 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
4284 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
4287 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
4288 auth
->psk
, PMK_LEN
);
4291 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
4299 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
4300 const struct dpp_curve_params
**key_curve
)
4302 struct json_token
*token
;
4303 const struct dpp_curve_params
*curve
;
4304 struct wpabuf
*x
= NULL
, *y
= NULL
;
4306 EVP_PKEY
*pkey
= NULL
;
4308 token
= json_get_member(jwk
, "kty");
4309 if (!token
|| token
->type
!= JSON_STRING
) {
4310 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
4313 if (os_strcmp(token
->string
, "EC") != 0) {
4314 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s",
4319 token
= json_get_member(jwk
, "crv");
4320 if (!token
|| token
->type
!= JSON_STRING
) {
4321 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
4324 curve
= dpp_get_curve_jwk_crv(token
->string
);
4326 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
4331 x
= json_get_member_base64url(jwk
, "x");
4333 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
4336 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
4337 if (wpabuf_len(x
) != curve
->prime_len
) {
4338 wpa_printf(MSG_DEBUG
,
4339 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4340 (unsigned int) wpabuf_len(x
),
4341 (unsigned int) curve
->prime_len
, curve
->name
);
4345 y
= json_get_member_base64url(jwk
, "y");
4347 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
4350 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
4351 if (wpabuf_len(y
) != curve
->prime_len
) {
4352 wpa_printf(MSG_DEBUG
,
4353 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4354 (unsigned int) wpabuf_len(y
),
4355 (unsigned int) curve
->prime_len
, curve
->name
);
4359 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
4361 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
4365 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
4377 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
4380 unsigned int year
, month
, day
, hour
, min
, sec
;
4384 /* ISO 8601 date and time:
4386 * YYYY-MM-DDTHH:MM:SSZ
4387 * YYYY-MM-DDTHH:MM:SS+03:00
4389 if (os_strlen(timestamp
) < 19) {
4390 wpa_printf(MSG_DEBUG
,
4391 "DPP: Too short timestamp - assume expired key");
4394 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
4395 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
4396 wpa_printf(MSG_DEBUG
,
4397 "DPP: Failed to parse expiration day - assume expired key");
4401 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
4402 wpa_printf(MSG_DEBUG
,
4403 "DPP: Invalid date/time information - assume expired key");
4407 pos
= timestamp
+ 19;
4408 if (*pos
== 'Z' || *pos
== '\0') {
4409 /* In UTC - no need to adjust */
4410 } else if (*pos
== '-' || *pos
== '+') {
4413 /* Adjust local time to UTC */
4414 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
4416 wpa_printf(MSG_DEBUG
,
4417 "DPP: Invalid time zone designator (%s) - assume expired key",
4422 utime
+= 3600 * hour
;
4424 utime
-= 3600 * hour
;
4432 wpa_printf(MSG_DEBUG
,
4433 "DPP: Invalid time zone designator (%s) - assume expired key",
4440 if (os_get_time(&now
) < 0) {
4441 wpa_printf(MSG_DEBUG
,
4442 "DPP: Cannot get current time - assume expired key");
4446 if (now
.sec
> utime
) {
4447 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
4456 static int dpp_parse_connector(struct dpp_authentication
*auth
,
4457 const unsigned char *payload
,
4460 struct json_token
*root
, *groups
, *netkey
, *token
;
4462 EVP_PKEY
*key
= NULL
;
4463 const struct dpp_curve_params
*curve
;
4464 unsigned int rules
= 0;
4466 root
= json_parse((const char *) payload
, payload_len
);
4468 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
4472 groups
= json_get_member(root
, "groups");
4473 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
4474 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
4477 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4478 struct json_token
*id
, *role
;
4480 id
= json_get_member(token
, "groupId");
4481 if (!id
|| id
->type
!= JSON_STRING
) {
4482 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
4486 role
= json_get_member(token
, "netRole");
4487 if (!role
|| role
->type
!= JSON_STRING
) {
4488 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
4491 wpa_printf(MSG_DEBUG
,
4492 "DPP: connector group: groupId='%s' netRole='%s'",
4493 id
->string
, role
->string
);
4499 wpa_printf(MSG_DEBUG
,
4500 "DPP: Connector includes no groups");
4504 token
= json_get_member(root
, "expiry");
4505 if (!token
|| token
->type
!= JSON_STRING
) {
4506 wpa_printf(MSG_DEBUG
,
4507 "DPP: No expiry string found - connector does not expire");
4509 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
4510 if (dpp_key_expired(token
->string
,
4511 &auth
->net_access_key_expiry
)) {
4512 wpa_printf(MSG_DEBUG
,
4513 "DPP: Connector (netAccessKey) has expired");
4518 netkey
= json_get_member(root
, "netAccessKey");
4519 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
4520 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
4524 key
= dpp_parse_jwk(netkey
, &curve
);
4527 dpp_debug_print_key("DPP: Received netAccessKey", key
);
4529 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
4530 wpa_printf(MSG_DEBUG
,
4531 "DPP: netAccessKey in connector does not match own protocol key");
4532 #ifdef CONFIG_TESTING_OPTIONS
4533 if (auth
->ignore_netaccesskey_mismatch
) {
4534 wpa_printf(MSG_DEBUG
,
4535 "DPP: TESTING - skip netAccessKey mismatch");
4539 #else /* CONFIG_TESTING_OPTIONS */
4541 #endif /* CONFIG_TESTING_OPTIONS */
4552 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
4554 struct wpabuf
*uncomp
;
4556 u8 hash
[SHA256_MAC_LEN
];
4560 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
4562 uncomp
= dpp_get_pubkey_point(pub
, 1);
4565 addr
[0] = wpabuf_head(uncomp
);
4566 len
[0] = wpabuf_len(uncomp
);
4567 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
4569 res
= sha256_vector(1, addr
, len
, hash
);
4570 wpabuf_free(uncomp
);
4573 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
4574 wpa_printf(MSG_DEBUG
,
4575 "DPP: Received hash value does not match calculated public key hash value");
4576 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
4577 hash
, SHA256_MAC_LEN
);
4584 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
4586 unsigned char *der
= NULL
;
4589 der_len
= i2d_PUBKEY(csign
, &der
);
4592 wpabuf_free(auth
->c_sign_key
);
4593 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
4598 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
4600 unsigned char *der
= NULL
;
4604 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
4608 der_len
= i2d_ECPrivateKey(eckey
, &der
);
4613 wpabuf_free(auth
->net_access_key
);
4614 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
4620 struct dpp_signed_connector_info
{
4621 unsigned char *payload
;
4625 static enum dpp_status_error
4626 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
4627 EVP_PKEY
*csign_pub
, const char *connector
)
4629 enum dpp_status_error ret
= 255;
4630 const char *pos
, *end
, *signed_start
, *signed_end
;
4631 struct wpabuf
*kid
= NULL
;
4632 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
4633 size_t prot_hdr_len
= 0, signature_len
= 0;
4634 const EVP_MD
*sign_md
= NULL
;
4635 unsigned char *der
= NULL
;
4638 EVP_MD_CTX
*md_ctx
= NULL
;
4639 ECDSA_SIG
*sig
= NULL
;
4640 BIGNUM
*r
= NULL
, *s
= NULL
;
4641 const struct dpp_curve_params
*curve
;
4643 const EC_GROUP
*group
;
4646 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
4649 group
= EC_KEY_get0_group(eckey
);
4652 nid
= EC_GROUP_get_curve_name(group
);
4653 curve
= dpp_get_curve_nid(nid
);
4656 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
4657 os_memset(info
, 0, sizeof(*info
));
4659 signed_start
= pos
= connector
;
4660 end
= os_strchr(pos
, '.');
4662 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
4663 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4666 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
4667 end
- pos
, &prot_hdr_len
);
4669 wpa_printf(MSG_DEBUG
,
4670 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
4671 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4674 wpa_hexdump_ascii(MSG_DEBUG
,
4675 "DPP: signedConnector - JWS Protected Header",
4676 prot_hdr
, prot_hdr_len
);
4677 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
4679 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4682 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
4683 wpa_printf(MSG_DEBUG
,
4684 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
4685 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
4686 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4691 end
= os_strchr(pos
, '.');
4693 wpa_printf(MSG_DEBUG
,
4694 "DPP: Missing dot(2) in signedConnector");
4695 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4698 signed_end
= end
- 1;
4699 info
->payload
= base64_url_decode((const unsigned char *) pos
,
4700 end
- pos
, &info
->payload_len
);
4701 if (!info
->payload
) {
4702 wpa_printf(MSG_DEBUG
,
4703 "DPP: Failed to base64url decode signedConnector JWS Payload");
4704 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4707 wpa_hexdump_ascii(MSG_DEBUG
,
4708 "DPP: signedConnector - JWS Payload",
4709 info
->payload
, info
->payload_len
);
4711 signature
= base64_url_decode((const unsigned char *) pos
,
4712 os_strlen(pos
), &signature_len
);
4714 wpa_printf(MSG_DEBUG
,
4715 "DPP: Failed to base64url decode signedConnector signature");
4716 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4719 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
4720 signature
, signature_len
);
4722 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
4723 ret
= DPP_STATUS_NO_MATCH
;
4727 if (signature_len
& 0x01) {
4728 wpa_printf(MSG_DEBUG
,
4729 "DPP: Unexpected signedConnector signature length (%d)",
4730 (int) signature_len
);
4731 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4735 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
4736 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
4737 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
4738 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
4739 sig
= ECDSA_SIG_new();
4740 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
4745 der_len
= i2d_ECDSA_SIG(sig
, &der
);
4747 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
4750 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
4751 md_ctx
= EVP_MD_CTX_create();
4756 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
4757 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
4758 ERR_error_string(ERR_get_error(), NULL
));
4761 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
4762 signed_end
- signed_start
+ 1) != 1) {
4763 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
4764 ERR_error_string(ERR_get_error(), NULL
));
4767 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
4769 wpa_printf(MSG_DEBUG
,
4770 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
4771 res
, ERR_error_string(ERR_get_error(), NULL
));
4772 ret
= DPP_STATUS_INVALID_CONNECTOR
;
4776 ret
= DPP_STATUS_OK
;
4779 EVP_MD_CTX_destroy(md_ctx
);
4783 ECDSA_SIG_free(sig
);
4791 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
4792 struct json_token
*cred
)
4794 struct dpp_signed_connector_info info
;
4795 struct json_token
*token
, *csign
;
4797 EVP_PKEY
*csign_pub
= NULL
;
4798 const struct dpp_curve_params
*key_curve
= NULL
;
4799 const char *signed_connector
;
4801 os_memset(&info
, 0, sizeof(info
));
4803 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
4805 csign
= json_get_member(cred
, "csign");
4806 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
4807 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
4811 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
4813 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
4816 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
4818 token
= json_get_member(cred
, "signedConnector");
4819 if (!token
|| token
->type
!= JSON_STRING
) {
4820 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
4823 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
4824 token
->string
, os_strlen(token
->string
));
4825 signed_connector
= token
->string
;
4827 if (os_strchr(signed_connector
, '"') ||
4828 os_strchr(signed_connector
, '\n')) {
4829 wpa_printf(MSG_DEBUG
,
4830 "DPP: Unexpected character in signedConnector");
4834 if (dpp_process_signed_connector(&info
, csign_pub
,
4835 signed_connector
) != DPP_STATUS_OK
)
4838 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
4839 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
4843 os_free(auth
->connector
);
4844 auth
->connector
= os_strdup(signed_connector
);
4846 dpp_copy_csign(auth
, csign_pub
);
4847 dpp_copy_netaccesskey(auth
);
4851 EVP_PKEY_free(csign_pub
);
4852 os_free(info
.payload
);
4857 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
4858 const u8
*conf_obj
, u16 conf_obj_len
)
4861 struct json_token
*root
, *token
, *discovery
, *cred
;
4863 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
4866 if (root
->type
!= JSON_OBJECT
) {
4867 dpp_auth_fail(auth
, "JSON root is not an object");
4871 token
= json_get_member(root
, "wi-fi_tech");
4872 if (!token
|| token
->type
!= JSON_STRING
) {
4873 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
4876 if (os_strcmp(token
->string
, "infra") != 0) {
4877 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
4879 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
4883 discovery
= json_get_member(root
, "discovery");
4884 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
4885 dpp_auth_fail(auth
, "No discovery object in JSON");
4889 token
= json_get_member(discovery
, "ssid");
4890 if (!token
|| token
->type
!= JSON_STRING
) {
4891 dpp_auth_fail(auth
, "No discovery::ssid string value found");
4894 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
4895 token
->string
, os_strlen(token
->string
));
4896 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
4897 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
4900 auth
->ssid_len
= os_strlen(token
->string
);
4901 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
4903 cred
= json_get_member(root
, "cred");
4904 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
4905 dpp_auth_fail(auth
, "No cred object in JSON");
4909 token
= json_get_member(cred
, "akm");
4910 if (!token
|| token
->type
!= JSON_STRING
) {
4911 dpp_auth_fail(auth
, "No cred::akm string value found");
4914 if (os_strcmp(token
->string
, "psk") == 0) {
4915 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
4917 } else if (os_strcmp(token
->string
, "dpp") == 0) {
4918 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
4921 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
4923 dpp_auth_fail(auth
, "Unsupported akm");
4927 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
4935 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
4936 const struct wpabuf
*resp
)
4938 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
4939 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
4942 u8
*unwrapped
= NULL
;
4943 size_t unwrapped_len
= 0;
4946 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
4947 dpp_auth_fail(auth
, "Invalid attribute in config response");
4951 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
4952 DPP_ATTR_WRAPPED_DATA
,
4954 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4956 "Missing or invalid required Wrapped Data attribute");
4960 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4961 wrapped_data
, wrapped_data_len
);
4962 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4963 unwrapped
= os_malloc(unwrapped_len
);
4967 addr
[0] = wpabuf_head(resp
);
4968 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
4969 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4971 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4972 wrapped_data
, wrapped_data_len
,
4973 1, addr
, len
, unwrapped
) < 0) {
4974 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4977 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4978 unwrapped
, unwrapped_len
);
4980 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4981 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4985 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4986 DPP_ATTR_ENROLLEE_NONCE
,
4988 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4990 "Missing or invalid Enrollee Nonce attribute");
4993 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4994 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
4995 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
4999 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5000 DPP_ATTR_STATUS
, &status_len
);
5001 if (!status
|| status_len
< 1) {
5003 "Missing or invalid required DPP Status attribute");
5006 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5007 if (status
[0] != DPP_STATUS_OK
) {
5008 dpp_auth_fail(auth
, "Configurator rejected configuration");
5012 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5013 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5016 "Missing required Configuration Object attribute");
5019 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5020 conf_obj
, conf_obj_len
);
5021 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5032 void dpp_configurator_free(struct dpp_configurator
*conf
)
5036 EVP_PKEY_free(conf
->csign
);
5042 struct dpp_configurator
*
5043 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
5046 struct dpp_configurator
*conf
;
5047 struct wpabuf
*csign_pub
= NULL
;
5048 u8 kid_hash
[SHA256_MAC_LEN
];
5052 conf
= os_zalloc(sizeof(*conf
));
5057 conf
->curve
= &dpp_curves
[0];
5059 conf
->curve
= dpp_get_curve_name(curve
);
5061 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5067 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
5070 conf
->csign
= dpp_gen_keypair(conf
->curve
);
5075 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
5077 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
5081 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5082 addr
[0] = wpabuf_head(csign_pub
);
5083 len
[0] = wpabuf_len(csign_pub
);
5084 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
5085 wpa_printf(MSG_DEBUG
,
5086 "DPP: Failed to derive kid for C-sign-key");
5090 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
5095 wpabuf_free(csign_pub
);
5098 dpp_configurator_free(conf
);
5104 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
5107 struct wpabuf
*conf_obj
;
5111 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
5116 auth
->curve
= &dpp_curves
[0];
5118 auth
->curve
= dpp_get_curve_name(curve
);
5120 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5125 wpa_printf(MSG_DEBUG
,
5126 "DPP: Building own configuration/connector with curve %s",
5129 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
5130 if (!auth
->own_protocol_key
)
5132 dpp_copy_netaccesskey(auth
);
5133 auth
->peer_protocol_key
= auth
->own_protocol_key
;
5134 dpp_copy_csign(auth
, auth
->conf
->csign
);
5136 conf_obj
= dpp_build_conf_obj(auth
, 0);
5139 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
5140 wpabuf_len(conf_obj
));
5142 wpabuf_free(conf_obj
);
5143 auth
->peer_protocol_key
= NULL
;
5148 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
5150 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
5151 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
5155 static int dpp_connector_compatible_group(struct json_token
*root
,
5156 const char *group_id
,
5157 const char *net_role
)
5159 struct json_token
*groups
, *token
;
5161 groups
= json_get_member(root
, "groups");
5162 if (!groups
|| groups
->type
!= JSON_ARRAY
)
5165 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5166 struct json_token
*id
, *role
;
5168 id
= json_get_member(token
, "groupId");
5169 if (!id
|| id
->type
!= JSON_STRING
)
5172 role
= json_get_member(token
, "netRole");
5173 if (!role
|| role
->type
!= JSON_STRING
)
5176 if (os_strcmp(id
->string
, "*") != 0 &&
5177 os_strcmp(group_id
, "*") != 0 &&
5178 os_strcmp(id
->string
, group_id
) != 0)
5181 if (dpp_compatible_netrole(role
->string
, net_role
))
5189 static int dpp_connector_match_groups(struct json_token
*own_root
,
5190 struct json_token
*peer_root
)
5192 struct json_token
*groups
, *token
;
5194 groups
= json_get_member(peer_root
, "groups");
5195 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5196 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
5200 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5201 struct json_token
*id
, *role
;
5203 id
= json_get_member(token
, "groupId");
5204 if (!id
|| id
->type
!= JSON_STRING
) {
5205 wpa_printf(MSG_DEBUG
,
5206 "DPP: Missing peer groupId string");
5210 role
= json_get_member(token
, "netRole");
5211 if (!role
|| role
->type
!= JSON_STRING
) {
5212 wpa_printf(MSG_DEBUG
,
5213 "DPP: Missing peer groups::netRole string");
5216 wpa_printf(MSG_DEBUG
,
5217 "DPP: peer connector group: groupId='%s' netRole='%s'",
5218 id
->string
, role
->string
);
5219 if (dpp_connector_compatible_group(own_root
, id
->string
,
5221 wpa_printf(MSG_DEBUG
,
5222 "DPP: Compatible group/netRole in own connector");
5231 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
5232 unsigned int hash_len
)
5234 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
5235 const char *info
= "DPP PMK";
5238 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5240 /* HKDF-Extract(<>, N.x) */
5241 os_memset(salt
, 0, hash_len
);
5242 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
5244 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5247 /* HKDF-Expand(PRK, info, L) */
5248 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
5249 os_memset(prk
, 0, hash_len
);
5253 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5259 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
5260 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
5262 struct wpabuf
*nkx
, *pkx
;
5266 u8 hash
[SHA256_MAC_LEN
];
5268 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5269 nkx
= dpp_get_pubkey_point(own_key
, 0);
5270 pkx
= dpp_get_pubkey_point(peer_key
, 0);
5273 addr
[0] = wpabuf_head(nkx
);
5274 len
[0] = wpabuf_len(nkx
) / 2;
5275 addr
[1] = wpabuf_head(pkx
);
5276 len
[1] = wpabuf_len(pkx
) / 2;
5277 if (len
[0] != len
[1])
5279 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
5280 addr
[0] = wpabuf_head(pkx
);
5281 addr
[1] = wpabuf_head(nkx
);
5283 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
5284 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
5285 res
= sha256_vector(2, addr
, len
, hash
);
5288 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
5289 os_memcpy(pmkid
, hash
, PMKID_LEN
);
5290 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
5299 enum dpp_status_error
5300 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
5301 const u8
*net_access_key
, size_t net_access_key_len
,
5302 const u8
*csign_key
, size_t csign_key_len
,
5303 const u8
*peer_connector
, size_t peer_connector_len
,
5306 struct json_token
*root
= NULL
, *netkey
, *token
;
5307 struct json_token
*own_root
= NULL
;
5308 enum dpp_status_error ret
= 255, res
;
5309 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
5310 struct wpabuf
*own_key_pub
= NULL
;
5311 const struct dpp_curve_params
*curve
, *own_curve
;
5312 struct dpp_signed_connector_info info
;
5313 const unsigned char *p
;
5314 EVP_PKEY
*csign
= NULL
;
5315 char *signed_connector
= NULL
;
5316 const char *pos
, *end
;
5317 unsigned char *own_conn
= NULL
;
5318 size_t own_conn_len
;
5319 EVP_PKEY_CTX
*ctx
= NULL
;
5321 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
5323 os_memset(intro
, 0, sizeof(*intro
));
5324 os_memset(&info
, 0, sizeof(info
));
5329 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
5331 wpa_printf(MSG_ERROR
,
5332 "DPP: Failed to parse local C-sign-key information");
5336 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
5337 net_access_key_len
);
5339 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
5343 pos
= os_strchr(own_connector
, '.');
5345 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
5349 end
= os_strchr(pos
, '.');
5351 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
5354 own_conn
= base64_url_decode((const unsigned char *) pos
,
5355 end
- pos
, &own_conn_len
);
5357 wpa_printf(MSG_DEBUG
,
5358 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5362 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
5364 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
5368 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
5369 peer_connector
, peer_connector_len
);
5370 signed_connector
= os_malloc(peer_connector_len
+ 1);
5371 if (!signed_connector
)
5373 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
5374 signed_connector
[peer_connector_len
] = '\0';
5376 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
5377 if (res
!= DPP_STATUS_OK
) {
5382 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
5384 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5385 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5389 if (!dpp_connector_match_groups(own_root
, root
)) {
5390 wpa_printf(MSG_DEBUG
,
5391 "DPP: Peer connector does not include compatible group netrole with own connector");
5392 ret
= DPP_STATUS_NO_MATCH
;
5396 token
= json_get_member(root
, "expiry");
5397 if (!token
|| token
->type
!= JSON_STRING
) {
5398 wpa_printf(MSG_DEBUG
,
5399 "DPP: No expiry string found - connector does not expire");
5401 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5402 if (dpp_key_expired(token
->string
, expiry
)) {
5403 wpa_printf(MSG_DEBUG
,
5404 "DPP: Connector (netAccessKey) has expired");
5405 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5410 netkey
= json_get_member(root
, "netAccessKey");
5411 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5412 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5413 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5417 peer_key
= dpp_parse_jwk(netkey
, &curve
);
5419 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5422 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
5424 if (own_curve
!= curve
) {
5425 wpa_printf(MSG_DEBUG
,
5426 "DPP: Mismatching netAccessKey curves (%s != %s)",
5427 own_curve
->name
, curve
->name
);
5428 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5432 /* ECDH: N = nk * PK */
5433 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
5435 EVP_PKEY_derive_init(ctx
) != 1 ||
5436 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
5437 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
5438 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5439 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
5440 wpa_printf(MSG_ERROR
,
5441 "DPP: Failed to derive ECDH shared secret: %s",
5442 ERR_error_string(ERR_get_error(), NULL
));
5446 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
5449 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5450 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
5451 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
5454 intro
->pmk_len
= curve
->hash_len
;
5456 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5457 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
5458 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
5462 ret
= DPP_STATUS_OK
;
5464 if (ret
!= DPP_STATUS_OK
)
5465 os_memset(intro
, 0, sizeof(*intro
));
5466 os_memset(Nx
, 0, sizeof(Nx
));
5467 EVP_PKEY_CTX_free(ctx
);
5469 os_free(signed_connector
);
5470 os_free(info
.payload
);
5471 EVP_PKEY_free(own_key
);
5472 wpabuf_free(own_key_pub
);
5473 EVP_PKEY_free(peer_key
);
5474 EVP_PKEY_free(csign
);
5476 json_free(own_root
);
5481 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
5485 size_t len
= curve
->prime_len
;
5488 switch (curve
->ike_group
) {
5490 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
5491 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
5494 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
5495 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
5498 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
5499 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
5502 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
5503 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
5506 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
5507 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
5510 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
5511 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
5517 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5520 return dpp_set_pubkey_point_group(group
, x
, y
, len
);
5524 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
5525 const u8
*mac_init
, const char *code
,
5526 const char *identifier
, BN_CTX
*bnctx
,
5527 const EC_GROUP
**ret_group
)
5529 u8 hash
[DPP_MAX_HASH_LEN
];
5532 unsigned int num_elem
= 0;
5533 EC_POINT
*Qi
= NULL
;
5534 EVP_PKEY
*Pi
= NULL
;
5535 EC_KEY
*Pi_ec
= NULL
;
5536 const EC_POINT
*Pi_point
;
5537 BIGNUM
*hash_bn
= NULL
;
5538 const EC_GROUP
*group
= NULL
;
5539 EC_GROUP
*group2
= NULL
;
5541 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5543 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
5544 addr
[num_elem
] = mac_init
;
5545 len
[num_elem
] = ETH_ALEN
;
5548 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5550 addr
[num_elem
] = (const u8
*) identifier
;
5551 len
[num_elem
] = os_strlen(identifier
);
5554 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5555 addr
[num_elem
] = (const u8
*) code
;
5556 len
[num_elem
] = os_strlen(code
);
5558 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5560 wpa_hexdump_key(MSG_DEBUG
,
5561 "DPP: H(MAC-Initiator | [identifier |] code)",
5562 hash
, curve
->hash_len
);
5563 Pi
= dpp_pkex_get_role_elem(curve
, 1);
5566 dpp_debug_print_key("DPP: Pi", Pi
);
5567 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
5570 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
5572 group
= EC_KEY_get0_group(Pi_ec
);
5575 group2
= EC_GROUP_dup(group
);
5578 Qi
= EC_POINT_new(group2
);
5580 EC_GROUP_free(group2
);
5583 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5585 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
5587 if (EC_POINT_is_at_infinity(group
, Qi
)) {
5588 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
5594 BN_clear_free(hash_bn
);
5596 *ret_group
= group2
;
5605 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
5606 const u8
*mac_resp
, const char *code
,
5607 const char *identifier
, BN_CTX
*bnctx
,
5608 const EC_GROUP
**ret_group
)
5610 u8 hash
[DPP_MAX_HASH_LEN
];
5613 unsigned int num_elem
= 0;
5614 EC_POINT
*Qr
= NULL
;
5615 EVP_PKEY
*Pr
= NULL
;
5616 EC_KEY
*Pr_ec
= NULL
;
5617 const EC_POINT
*Pr_point
;
5618 BIGNUM
*hash_bn
= NULL
;
5619 const EC_GROUP
*group
= NULL
;
5620 EC_GROUP
*group2
= NULL
;
5622 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5624 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
5625 addr
[num_elem
] = mac_resp
;
5626 len
[num_elem
] = ETH_ALEN
;
5629 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5631 addr
[num_elem
] = (const u8
*) identifier
;
5632 len
[num_elem
] = os_strlen(identifier
);
5635 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5636 addr
[num_elem
] = (const u8
*) code
;
5637 len
[num_elem
] = os_strlen(code
);
5639 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5641 wpa_hexdump_key(MSG_DEBUG
,
5642 "DPP: H(MAC-Responder | [identifier |] code)",
5643 hash
, curve
->hash_len
);
5644 Pr
= dpp_pkex_get_role_elem(curve
, 0);
5647 dpp_debug_print_key("DPP: Pr", Pr
);
5648 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
5651 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
5653 group
= EC_KEY_get0_group(Pr_ec
);
5656 group2
= EC_GROUP_dup(group
);
5659 Qr
= EC_POINT_new(group2
);
5661 EC_GROUP_free(group2
);
5664 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5666 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
5668 if (EC_POINT_is_at_infinity(group
, Qr
)) {
5669 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
5675 BN_clear_free(hash_bn
);
5677 *ret_group
= group2
;
5686 #ifdef CONFIG_TESTING_OPTIONS
5687 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
5688 const struct dpp_curve_params
*curve
)
5696 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5701 point
= EC_POINT_new(group
);
5704 if (!ctx
|| !point
|| !x
|| !y
)
5707 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
5710 /* Generate a random y coordinate that results in a point that is not
5713 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
5716 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
5720 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
5724 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
5725 curve
->prime_len
) < 0 ||
5726 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
5727 curve
->prime_len
) < 0)
5734 EC_POINT_free(point
);
5739 #endif /* CONFIG_TESTING_OPTIONS */
5742 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
5744 EC_KEY
*X_ec
= NULL
;
5745 const EC_POINT
*X_point
;
5746 BN_CTX
*bnctx
= NULL
;
5747 const EC_GROUP
*group
;
5748 EC_POINT
*Qi
= NULL
, *M
= NULL
;
5749 struct wpabuf
*M_buf
= NULL
;
5750 BIGNUM
*Mx
= NULL
, *My
= NULL
;
5751 struct wpabuf
*msg
= NULL
;
5753 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5755 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
5757 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5758 bnctx
= BN_CTX_new();
5761 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
5762 pkex
->identifier
, bnctx
, &group
);
5766 /* Generate a random ephemeral keypair x/X */
5767 pkex
->x
= dpp_gen_keypair(curve
);
5772 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
5775 X_point
= EC_KEY_get0_public_key(X_ec
);
5778 M
= EC_POINT_new(group
);
5781 if (!M
|| !Mx
|| !My
||
5782 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
5783 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
5786 /* Initiator -> Responder: group, [identifier,] M */
5788 if (pkex
->identifier
)
5789 attr_len
+= 4 + os_strlen(pkex
->identifier
);
5790 attr_len
+= 4 + 2 * curve
->prime_len
;
5791 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
5795 #ifdef CONFIG_TESTING_OPTIONS
5796 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
5797 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
5798 goto skip_finite_cyclic_group
;
5800 #endif /* CONFIG_TESTING_OPTIONS */
5802 /* Finite Cyclic Group attribute */
5803 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
5804 wpabuf_put_le16(msg
, 2);
5805 wpabuf_put_le16(msg
, curve
->ike_group
);
5807 #ifdef CONFIG_TESTING_OPTIONS
5808 skip_finite_cyclic_group
:
5809 #endif /* CONFIG_TESTING_OPTIONS */
5811 /* Code Identifier attribute */
5812 if (pkex
->identifier
) {
5813 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
5814 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
5815 wpabuf_put_str(msg
, pkex
->identifier
);
5818 #ifdef CONFIG_TESTING_OPTIONS
5819 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
5820 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
5823 #endif /* CONFIG_TESTING_OPTIONS */
5825 /* M in Encrypted Key attribute */
5826 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
5827 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
5829 #ifdef CONFIG_TESTING_OPTIONS
5830 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
5831 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
5832 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
5836 #endif /* CONFIG_TESTING_OPTIONS */
5838 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
5839 curve
->prime_len
) < 0 ||
5840 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
5841 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
5842 curve
->prime_len
) < 0)
5855 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
5862 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
5864 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
5868 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
5870 const char *identifier
,
5873 struct dpp_pkex
*pkex
;
5875 pkex
= os_zalloc(sizeof(*pkex
));
5878 pkex
->msg_ctx
= msg_ctx
;
5879 pkex
->initiator
= 1;
5881 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
5883 pkex
->identifier
= os_strdup(identifier
);
5884 if (!pkex
->identifier
)
5887 pkex
->code
= os_strdup(code
);
5890 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
5891 if (!pkex
->exchange_req
)
5895 dpp_pkex_free(pkex
);
5900 static struct wpabuf
*
5901 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
5902 enum dpp_status_error status
,
5903 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
5905 struct wpabuf
*msg
= NULL
;
5907 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5909 /* Initiator -> Responder: DPP Status, [identifier,] N */
5911 if (pkex
->identifier
)
5912 attr_len
+= 4 + os_strlen(pkex
->identifier
);
5913 attr_len
+= 4 + 2 * curve
->prime_len
;
5914 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
5918 #ifdef CONFIG_TESTING_OPTIONS
5919 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
5920 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
5924 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
5925 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
5928 #endif /* CONFIG_TESTING_OPTIONS */
5931 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
5932 wpabuf_put_le16(msg
, 1);
5933 wpabuf_put_u8(msg
, status
);
5935 #ifdef CONFIG_TESTING_OPTIONS
5937 #endif /* CONFIG_TESTING_OPTIONS */
5939 /* Code Identifier attribute */
5940 if (pkex
->identifier
) {
5941 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
5942 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
5943 wpabuf_put_str(msg
, pkex
->identifier
);
5946 if (status
!= DPP_STATUS_OK
)
5947 goto skip_encrypted_key
;
5949 #ifdef CONFIG_TESTING_OPTIONS
5950 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
5951 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
5952 goto skip_encrypted_key
;
5954 #endif /* CONFIG_TESTING_OPTIONS */
5956 /* N in Encrypted Key attribute */
5957 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
5958 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
5960 #ifdef CONFIG_TESTING_OPTIONS
5961 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
5962 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
5963 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
5965 goto skip_encrypted_key
;
5967 #endif /* CONFIG_TESTING_OPTIONS */
5969 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
5970 curve
->prime_len
) < 0 ||
5971 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
5972 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
5973 curve
->prime_len
) < 0)
5977 if (status
== DPP_STATUS_BAD_GROUP
) {
5978 /* Finite Cyclic Group attribute */
5979 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
5980 wpabuf_put_le16(msg
, 2);
5981 wpabuf_put_le16(msg
, curve
->ike_group
);
5991 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
5992 const u8
*Mx
, size_t Mx_len
,
5993 const u8
*Nx
, size_t Nx_len
,
5995 const u8
*Kx
, size_t Kx_len
,
5996 u8
*z
, unsigned int hash_len
)
5998 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6003 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6006 /* HKDF-Extract(<>, IKM=K.x) */
6007 os_memset(salt
, 0, hash_len
);
6008 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
6010 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
6012 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
6013 info
= os_malloc(info_len
);
6017 os_memcpy(pos
, mac_init
, ETH_ALEN
);
6019 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
6021 os_memcpy(pos
, Mx
, Mx_len
);
6023 os_memcpy(pos
, Nx
, Nx_len
);
6025 os_memcpy(pos
, code
, os_strlen(code
));
6027 /* HKDF-Expand(PRK, info, L) */
6029 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6031 else if (hash_len
== 48)
6032 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6034 else if (hash_len
== 64)
6035 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6040 os_memset(prk
, 0, hash_len
);
6044 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
6050 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
6051 struct dpp_bootstrap_info
*bi
,
6054 const char *identifier
,
6056 const u8
*buf
, size_t len
)
6058 const u8
*attr_group
, *attr_id
, *attr_key
;
6059 u16 attr_group_len
, attr_id_len
, attr_key_len
;
6060 const struct dpp_curve_params
*curve
= bi
->curve
;
6062 struct dpp_pkex
*pkex
= NULL
;
6063 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
6064 BN_CTX
*bnctx
= NULL
;
6065 const EC_GROUP
*group
;
6066 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6067 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
6068 const EC_POINT
*Y_point
;
6069 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6070 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6073 EVP_PKEY_CTX
*ctx
= NULL
;
6075 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
6076 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6077 "PKEX counter t limit reached - ignore message");
6081 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
6083 if (!attr_id
&& identifier
) {
6084 wpa_printf(MSG_DEBUG
,
6085 "DPP: No PKEX code identifier received, but expected one");
6088 if (attr_id
&& identifier
&&
6089 (os_strlen(identifier
) != attr_id_len
||
6090 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
6091 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
6095 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
6097 if (!attr_group
|| attr_group_len
!= 2) {
6098 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6099 "Missing or invalid Finite Cyclic Group attribute");
6102 ike_group
= WPA_GET_LE16(attr_group
);
6103 if (ike_group
!= curve
->ike_group
) {
6104 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6105 "Mismatching PKEX curve: peer=%u own=%u",
6106 ike_group
, curve
->ike_group
);
6107 pkex
= os_zalloc(sizeof(*pkex
));
6112 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
6113 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
6114 if (!pkex
->exchange_resp
)
6119 /* M in Encrypted Key attribute */
6120 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
6122 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
6123 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
6124 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6125 "Missing Encrypted Key attribute");
6129 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6130 bnctx
= BN_CTX_new();
6133 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
6139 X
= EC_POINT_new(group
);
6140 M
= EC_POINT_new(group
);
6141 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6142 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6143 if (!X
|| !M
|| !Mx
|| !My
||
6144 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
6145 EC_POINT_is_at_infinity(group
, M
) ||
6146 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
6147 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
6148 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
6149 EC_POINT_is_at_infinity(group
, X
) ||
6150 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
6151 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6152 "Invalid Encrypted Key value");
6157 pkex
= os_zalloc(sizeof(*pkex
));
6160 pkex
->t
= bi
->pkex_t
;
6161 pkex
->msg_ctx
= msg_ctx
;
6163 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6164 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
6166 pkex
->identifier
= os_strdup(identifier
);
6167 if (!pkex
->identifier
)
6170 pkex
->code
= os_strdup(code
);
6174 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
6176 X_ec
= EC_KEY_new();
6178 EC_KEY_set_group(X_ec
, group
) != 1 ||
6179 EC_KEY_set_public_key(X_ec
, X
) != 1)
6181 pkex
->x
= EVP_PKEY_new();
6183 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
6186 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6187 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
6191 /* Generate a random ephemeral keypair y/Y */
6192 pkex
->y
= dpp_gen_keypair(curve
);
6197 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
6200 Y_point
= EC_KEY_get0_public_key(Y_ec
);
6203 N
= EC_POINT_new(group
);
6206 if (!N
|| !Nx
|| !Ny
||
6207 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
6208 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
6211 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
6213 if (!pkex
->exchange_resp
)
6217 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
6219 EVP_PKEY_derive_init(ctx
) != 1 ||
6220 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
6221 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6222 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6223 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6224 wpa_printf(MSG_ERROR
,
6225 "DPP: Failed to derive ECDH shared secret: %s",
6226 ERR_error_string(ERR_get_error(), NULL
));
6230 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6233 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6235 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
6236 pkex
->Mx
, curve
->prime_len
,
6237 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
6238 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
6239 os_memset(Kx
, 0, Kx_len
);
6243 pkex
->exchange_done
= 1;
6246 EVP_PKEY_CTX_free(ctx
);
6261 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
6262 dpp_pkex_free(pkex
);
6268 static struct wpabuf
*
6269 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
6270 const struct wpabuf
*A_pub
, const u8
*u
)
6272 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6273 struct wpabuf
*msg
= NULL
;
6274 size_t clear_len
, attr_len
;
6275 struct wpabuf
*clear
= NULL
;
6281 /* {A, u, [bootstrapping info]}z */
6282 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6283 clear
= wpabuf_alloc(clear_len
);
6284 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6285 #ifdef CONFIG_TESTING_OPTIONS
6286 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
6288 #endif /* CONFIG_TESTING_OPTIONS */
6289 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
6293 #ifdef CONFIG_TESTING_OPTIONS
6294 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6295 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6296 goto skip_bootstrap_key
;
6298 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6299 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6300 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6301 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6302 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6304 goto skip_bootstrap_key
;
6306 #endif /* CONFIG_TESTING_OPTIONS */
6308 /* A in Bootstrap Key attribute */
6309 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6310 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
6311 wpabuf_put_buf(clear
, A_pub
);
6313 #ifdef CONFIG_TESTING_OPTIONS
6315 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
6316 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
6317 goto skip_i_auth_tag
;
6319 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
6320 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
6321 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6322 wpabuf_put_le16(clear
, curve
->hash_len
);
6323 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
6324 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
6325 goto skip_i_auth_tag
;
6327 #endif /* CONFIG_TESTING_OPTIONS */
6329 /* u in I-Auth tag attribute */
6330 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6331 wpabuf_put_le16(clear
, curve
->hash_len
);
6332 wpabuf_put_data(clear
, u
, curve
->hash_len
);
6334 #ifdef CONFIG_TESTING_OPTIONS
6336 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
6337 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6338 goto skip_wrapped_data
;
6340 #endif /* CONFIG_TESTING_OPTIONS */
6342 addr
[0] = wpabuf_head_u8(msg
) + 2;
6343 len
[0] = DPP_HDR_LEN
;
6346 len
[1] = sizeof(octet
);
6347 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6348 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6350 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6351 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6352 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6354 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6355 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6356 wpabuf_head(clear
), wpabuf_len(clear
),
6357 2, addr
, len
, wrapped
) < 0)
6359 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6360 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6362 #ifdef CONFIG_TESTING_OPTIONS
6363 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
6364 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6365 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
6366 wpabuf_put_le16(msg
, 0);
6369 #endif /* CONFIG_TESTING_OPTIONS */
6382 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
6383 const u8
*buf
, size_t buflen
)
6385 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
6386 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
6387 const EC_GROUP
*group
;
6388 BN_CTX
*bnctx
= NULL
;
6389 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6390 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6391 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
6392 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6393 EVP_PKEY_CTX
*ctx
= NULL
;
6394 EC_KEY
*Y_ec
= NULL
;
6395 size_t Jx_len
, Kx_len
;
6396 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6399 u8 u
[DPP_MAX_HASH_LEN
];
6402 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
)
6405 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
6407 if (!attr_status
|| attr_status_len
!= 1) {
6408 dpp_pkex_fail(pkex
, "No DPP Status attribute");
6411 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
6413 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
6414 attr_group
= dpp_get_attr(buf
, buflen
,
6415 DPP_ATTR_FINITE_CYCLIC_GROUP
,
6417 if (attr_group
&& attr_group_len
== 2) {
6418 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6419 "Peer indicated mismatching PKEX group - proposed %u",
6420 WPA_GET_LE16(attr_group
));
6425 if (attr_status
[0] != DPP_STATUS_OK
) {
6426 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
6430 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
6432 if (!attr_id
&& pkex
->identifier
) {
6433 wpa_printf(MSG_DEBUG
,
6434 "DPP: No PKEX code identifier received, but expected one");
6437 if (attr_id
&& pkex
->identifier
&&
6438 (os_strlen(pkex
->identifier
) != attr_id_len
||
6439 os_memcmp(pkex
->identifier
, attr_id
, attr_id_len
) != 0)) {
6440 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
6444 /* N in Encrypted Key attribute */
6445 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
6447 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
6448 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
6452 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
6453 bnctx
= BN_CTX_new();
6456 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
6457 pkex
->identifier
, bnctx
, &group
);
6462 Y
= EC_POINT_new(group
);
6463 N
= EC_POINT_new(group
);
6464 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6465 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6466 if (!Y
|| !N
|| !Nx
|| !Ny
||
6467 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
6468 EC_POINT_is_at_infinity(group
, N
) ||
6469 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
6470 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
6471 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
6472 EC_POINT_is_at_infinity(group
, Y
) ||
6473 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
6474 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
6479 pkex
->exchange_done
= 1;
6481 /* ECDH: J = a * Y’ */
6482 Y_ec
= EC_KEY_new();
6484 EC_KEY_set_group(Y_ec
, group
) != 1 ||
6485 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
6487 pkex
->y
= EVP_PKEY_new();
6489 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
6491 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
6493 EVP_PKEY_derive_init(ctx
) != 1 ||
6494 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
6495 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
6496 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6497 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
6498 wpa_printf(MSG_ERROR
,
6499 "DPP: Failed to derive ECDH shared secret: %s",
6500 ERR_error_string(ERR_get_error(), NULL
));
6504 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
6507 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
6508 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
6509 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6510 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6511 if (!A_pub
|| !Y_pub
|| !X_pub
)
6513 addr
[0] = pkex
->own_mac
;
6515 addr
[1] = wpabuf_head(A_pub
);
6516 len
[1] = wpabuf_len(A_pub
) / 2;
6517 addr
[2] = wpabuf_head(Y_pub
);
6518 len
[2] = wpabuf_len(Y_pub
) / 2;
6519 addr
[3] = wpabuf_head(X_pub
);
6520 len
[3] = wpabuf_len(X_pub
) / 2;
6521 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
6523 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
6526 EVP_PKEY_CTX_free(ctx
);
6527 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
6529 EVP_PKEY_derive_init(ctx
) != 1 ||
6530 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
6531 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6532 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6533 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6534 wpa_printf(MSG_ERROR
,
6535 "DPP: Failed to derive ECDH shared secret: %s",
6536 ERR_error_string(ERR_get_error(), NULL
));
6540 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6543 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6545 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
6546 pkex
->Mx
, curve
->prime_len
,
6547 attr_key
/* N.x */, attr_key_len
/ 2,
6548 pkex
->code
, Kx
, Kx_len
,
6549 pkex
->z
, curve
->hash_len
);
6550 os_memset(Kx
, 0, Kx_len
);
6554 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
6568 EVP_PKEY_CTX_free(ctx
);
6572 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
6577 static struct wpabuf
*
6578 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
6579 const struct wpabuf
*B_pub
, const u8
*v
)
6581 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6582 struct wpabuf
*msg
= NULL
;
6587 struct wpabuf
*clear
= NULL
;
6588 size_t clear_len
, attr_len
;
6590 /* {B, v [bootstrapping info]}z */
6591 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6592 clear
= wpabuf_alloc(clear_len
);
6593 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6594 #ifdef CONFIG_TESTING_OPTIONS
6595 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
6597 #endif /* CONFIG_TESTING_OPTIONS */
6598 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
6602 #ifdef CONFIG_TESTING_OPTIONS
6603 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
6604 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6605 goto skip_bootstrap_key
;
6607 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
6608 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6609 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6610 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6611 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6613 goto skip_bootstrap_key
;
6615 #endif /* CONFIG_TESTING_OPTIONS */
6617 /* B in Bootstrap Key attribute */
6618 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6619 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
6620 wpabuf_put_buf(clear
, B_pub
);
6622 #ifdef CONFIG_TESTING_OPTIONS
6624 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
6625 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
6626 goto skip_r_auth_tag
;
6628 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
6629 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
6630 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
6631 wpabuf_put_le16(clear
, curve
->hash_len
);
6632 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
6633 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
6634 goto skip_r_auth_tag
;
6636 #endif /* CONFIG_TESTING_OPTIONS */
6638 /* v in R-Auth tag attribute */
6639 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
6640 wpabuf_put_le16(clear
, curve
->hash_len
);
6641 wpabuf_put_data(clear
, v
, curve
->hash_len
);
6643 #ifdef CONFIG_TESTING_OPTIONS
6645 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
6646 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6647 goto skip_wrapped_data
;
6649 #endif /* CONFIG_TESTING_OPTIONS */
6651 addr
[0] = wpabuf_head_u8(msg
) + 2;
6652 len
[0] = DPP_HDR_LEN
;
6655 len
[1] = sizeof(octet
);
6656 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6657 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6659 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6660 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6661 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6663 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6664 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6665 wpabuf_head(clear
), wpabuf_len(clear
),
6666 2, addr
, len
, wrapped
) < 0)
6668 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6669 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6671 #ifdef CONFIG_TESTING_OPTIONS
6672 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
6673 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6674 wpabuf_put_le16(msg
, DPP_ATTR_TESTING
);
6675 wpabuf_put_le16(msg
, 0);
6678 #endif /* CONFIG_TESTING_OPTIONS */
6691 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
6693 const u8
*buf
, size_t buflen
)
6695 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6696 EVP_PKEY_CTX
*ctx
= NULL
;
6697 size_t Jx_len
, Lx_len
;
6698 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
6699 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
6700 const u8
*wrapped_data
, *b_key
, *peer_u
;
6701 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
6705 u8
*unwrapped
= NULL
;
6706 size_t unwrapped_len
= 0;
6707 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6708 struct wpabuf
*B_pub
= NULL
;
6709 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
6711 if (!pkex
->exchange_done
|| pkex
->failed
||
6712 pkex
->t
>= PKEX_COUNTER_T_LIMIT
)
6715 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
6717 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6719 "Missing or invalid required Wrapped Data attribute");
6723 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6724 wrapped_data
, wrapped_data_len
);
6725 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6726 unwrapped
= os_malloc(unwrapped_len
);
6731 len
[0] = DPP_HDR_LEN
;
6734 len
[1] = sizeof(octet
);
6735 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6736 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6738 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
6739 wrapped_data
, wrapped_data_len
,
6740 2, addr
, len
, unwrapped
) < 0) {
6742 "AES-SIV decryption failed - possible PKEX code mismatch");
6747 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6748 unwrapped
, unwrapped_len
);
6750 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6751 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
6755 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
6757 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
6758 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
6761 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
6763 if (!pkex
->peer_bootstrap_key
) {
6764 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
6767 dpp_debug_print_key("DPP: Peer bootstrap public key",
6768 pkex
->peer_bootstrap_key
);
6770 /* ECDH: J' = y * A' */
6771 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
6773 EVP_PKEY_derive_init(ctx
) != 1 ||
6774 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
6775 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
6776 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6777 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
6778 wpa_printf(MSG_ERROR
,
6779 "DPP: Failed to derive ECDH shared secret: %s",
6780 ERR_error_string(ERR_get_error(), NULL
));
6784 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
6787 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
6788 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
6789 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6790 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6791 if (!A_pub
|| !Y_pub
|| !X_pub
)
6793 addr
[0] = pkex
->peer_mac
;
6795 addr
[1] = wpabuf_head(A_pub
);
6796 len
[1] = wpabuf_len(A_pub
) / 2;
6797 addr
[2] = wpabuf_head(Y_pub
);
6798 len
[2] = wpabuf_len(Y_pub
) / 2;
6799 addr
[3] = wpabuf_head(X_pub
);
6800 len
[3] = wpabuf_len(X_pub
) / 2;
6801 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
6804 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
6806 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
6807 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
6808 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
6809 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
6810 u
, curve
->hash_len
);
6811 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
6815 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
6817 /* ECDH: L = b * X' */
6818 EVP_PKEY_CTX_free(ctx
);
6819 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
6821 EVP_PKEY_derive_init(ctx
) != 1 ||
6822 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
6823 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
6824 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6825 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
6826 wpa_printf(MSG_ERROR
,
6827 "DPP: Failed to derive ECDH shared secret: %s",
6828 ERR_error_string(ERR_get_error(), NULL
));
6832 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
6835 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
6836 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
6839 addr
[0] = pkex
->own_mac
;
6841 addr
[1] = wpabuf_head(B_pub
);
6842 len
[1] = wpabuf_len(B_pub
) / 2;
6843 addr
[2] = wpabuf_head(X_pub
);
6844 len
[2] = wpabuf_len(X_pub
) / 2;
6845 addr
[3] = wpabuf_head(Y_pub
);
6846 len
[3] = wpabuf_len(Y_pub
) / 2;
6847 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
6849 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
6851 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
6856 EVP_PKEY_CTX_free(ctx
);
6864 wpa_printf(MSG_DEBUG
,
6865 "DPP: PKEX Commit-Reveal Request processing failed");
6870 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
6871 const u8
*buf
, size_t buflen
)
6873 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6874 const u8
*wrapped_data
, *b_key
, *peer_v
;
6875 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
6879 u8
*unwrapped
= NULL
;
6880 size_t unwrapped_len
= 0;
6882 u8 v
[DPP_MAX_HASH_LEN
];
6884 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
6885 EVP_PKEY_CTX
*ctx
= NULL
;
6886 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6888 if (!pkex
->exchange_done
|| pkex
->failed
||
6889 pkex
->t
>= PKEX_COUNTER_T_LIMIT
)
6892 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
6894 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6896 "Missing or invalid required Wrapped Data attribute");
6900 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6901 wrapped_data
, wrapped_data_len
);
6902 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6903 unwrapped
= os_malloc(unwrapped_len
);
6908 len
[0] = DPP_HDR_LEN
;
6911 len
[1] = sizeof(octet
);
6912 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6913 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6915 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
6916 wrapped_data
, wrapped_data_len
,
6917 2, addr
, len
, unwrapped
) < 0) {
6919 "AES-SIV decryption failed - possible PKEX code mismatch");
6923 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6924 unwrapped
, unwrapped_len
);
6926 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6927 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
6931 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
6933 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
6934 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
6937 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
6939 if (!pkex
->peer_bootstrap_key
) {
6940 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
6943 dpp_debug_print_key("DPP: Peer bootstrap public key",
6944 pkex
->peer_bootstrap_key
);
6946 /* ECDH: L' = x * B' */
6947 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
6949 EVP_PKEY_derive_init(ctx
) != 1 ||
6950 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
6951 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
6952 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6953 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
6954 wpa_printf(MSG_ERROR
,
6955 "DPP: Failed to derive ECDH shared secret: %s",
6956 ERR_error_string(ERR_get_error(), NULL
));
6960 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
6963 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
6964 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
6965 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6966 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6967 if (!B_pub
|| !X_pub
|| !Y_pub
)
6969 addr
[0] = pkex
->peer_mac
;
6971 addr
[1] = wpabuf_head(B_pub
);
6972 len
[1] = wpabuf_len(B_pub
) / 2;
6973 addr
[2] = wpabuf_head(X_pub
);
6974 len
[2] = wpabuf_len(X_pub
) / 2;
6975 addr
[3] = wpabuf_head(Y_pub
);
6976 len
[3] = wpabuf_len(Y_pub
) / 2;
6977 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
6980 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
6982 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
6983 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
6984 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
6985 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
6986 v
, curve
->hash_len
);
6987 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
6991 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
6998 EVP_PKEY_CTX_free(ctx
);
7006 void dpp_pkex_free(struct dpp_pkex
*pkex
)
7011 os_free(pkex
->identifier
);
7012 os_free(pkex
->code
);
7013 EVP_PKEY_free(pkex
->x
);
7014 EVP_PKEY_free(pkex
->y
);
7015 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
7016 wpabuf_free(pkex
->exchange_req
);
7017 wpabuf_free(pkex
->exchange_resp
);