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"
28 #if OPENSSL_VERSION_NUMBER < 0x10100000L
29 /* Compatibility wrappers for older versions. */
31 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
39 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
51 static const struct dpp_curve_params dpp_curves
[] = {
52 /* The mandatory to support and the default NIST P-256 curve needs to
53 * be the first entry on this list. */
54 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
55 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
56 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
57 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
58 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
59 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
60 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
64 /* Role-specific elements for PKEX */
67 static const u8 pkex_init_x_p256
[32] = {
68 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
69 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
70 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
71 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
73 static const u8 pkex_init_y_p256
[32] = {
74 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
75 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
76 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
77 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
79 static const u8 pkex_resp_x_p256
[32] = {
80 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
81 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
82 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
83 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
85 static const u8 pkex_resp_y_p256
[32] = {
86 0x26, 0x04, 0x09, 0x45, 0x0a, 0x05, 0x20, 0xe7,
87 0xa7, 0x27, 0xc1, 0x36, 0x76, 0x85, 0xca, 0x3e,
88 0x42, 0x16, 0xf4, 0x89, 0x85, 0x34, 0x6e, 0xd5,
89 0x17, 0xde, 0xc0, 0xb8, 0xad, 0xfd, 0xb2, 0x98
93 static const u8 pkex_init_x_p384
[48] = {
94 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
95 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
96 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
97 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
98 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
99 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
101 static const u8 pkex_init_y_p384
[48] = {
102 0x89, 0xd0, 0x97, 0x7b, 0x59, 0x4f, 0xa6, 0xd6,
103 0x7c, 0x5d, 0x93, 0x5b, 0x93, 0xc4, 0x07, 0xa9,
104 0x89, 0xee, 0xd5, 0xcd, 0x6f, 0x42, 0xf8, 0x38,
105 0xc8, 0xc6, 0x62, 0x24, 0x69, 0x0c, 0xd4, 0x48,
106 0xd8, 0x44, 0xd6, 0xc2, 0xe8, 0xcc, 0x62, 0x6b,
107 0x3c, 0x25, 0x53, 0xba, 0x4f, 0x71, 0xf8, 0xe7
109 static const u8 pkex_resp_x_p384
[48] = {
110 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
111 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
112 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
113 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
114 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
115 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
117 static const u8 pkex_resp_y_p384
[48] = {
118 0x54, 0x58, 0x20, 0xad, 0x55, 0x1d, 0xca, 0xf3,
119 0x1c, 0x8a, 0xcd, 0x19, 0x40, 0xf9, 0x37, 0x83,
120 0xc7, 0xd6, 0xb3, 0x13, 0x7d, 0x53, 0x28, 0x5c,
121 0xf6, 0x2d, 0xf1, 0xdd, 0xa5, 0x8b, 0xad, 0x5d,
122 0x81, 0xab, 0xb1, 0x00, 0x39, 0xd6, 0xcc, 0x9c,
123 0xea, 0x1e, 0x84, 0x1d, 0xbf, 0xe3, 0x35, 0xf9
127 static const u8 pkex_init_x_p521
[66] = {
128 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
129 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
130 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
131 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
132 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
133 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
134 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
135 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
138 static const u8 pkex_init_y_p521
[66] = {
139 0x01, 0x4c, 0x71, 0xfd, 0x1b, 0xd5, 0x9c, 0xa6,
140 0xed, 0x39, 0xef, 0x45, 0xc5, 0x06, 0xfd, 0x66,
141 0xc0, 0xeb, 0x0f, 0xbf, 0x21, 0xa3, 0x36, 0x74,
142 0xfd, 0xaa, 0x05, 0x6e, 0x4e, 0x33, 0x95, 0x42,
143 0x1a, 0x9d, 0x3f, 0x3a, 0x1c, 0x5e, 0xa8, 0x60,
144 0xf7, 0xe5, 0x59, 0x1d, 0x07, 0xaa, 0x6f, 0x40,
145 0x0a, 0x59, 0x3c, 0x27, 0xad, 0xe0, 0x48, 0xfd,
146 0xd1, 0x83, 0x37, 0x4c, 0xdf, 0xe1, 0x86, 0x72,
149 static const u8 pkex_resp_x_p521
[66] = {
150 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
151 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
152 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
153 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
154 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
155 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
156 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
157 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
160 static const u8 pkex_resp_y_p521
[66] = {
161 0x01, 0xb9, 0x9c, 0xc6, 0x41, 0x32, 0x5b, 0xd2,
162 0x35, 0xd8, 0x8b, 0x2b, 0xe4, 0x6e, 0xcc, 0xdf,
163 0x7c, 0x38, 0xc4, 0x5b, 0xf6, 0x74, 0x71, 0x5c,
164 0x77, 0x16, 0x8a, 0x80, 0xa9, 0x84, 0xc7, 0x7b,
165 0x9d, 0xfd, 0x83, 0x6f, 0xae, 0xf8, 0x24, 0x16,
166 0x2f, 0x21, 0x25, 0x65, 0xa2, 0x1a, 0x6b, 0x2d,
167 0x30, 0x62, 0xb3, 0xcc, 0x6e, 0x59, 0x3c, 0x7f,
168 0x58, 0x91, 0x81, 0x72, 0x07, 0x8c, 0x91, 0xac,
172 /* Brainpool P-256r1 */
173 static const u8 pkex_init_x_bp_p256r1
[32] = {
174 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
175 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
176 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
177 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
179 static const u8 pkex_init_y_bp_p256r1
[32] = {
180 0x16, 0x30, 0x68, 0x32, 0x3b, 0xb0, 0x21, 0xee,
181 0xeb, 0xf7, 0xb6, 0x7c, 0xae, 0x52, 0x26, 0x42,
182 0x59, 0x28, 0x58, 0xb6, 0x14, 0x90, 0xed, 0x69,
183 0xd0, 0x67, 0xea, 0x25, 0x60, 0x0f, 0xa9, 0x6c
185 static const u8 pkex_resp_x_bp_p256r1
[32] = {
186 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
187 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
188 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
189 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
191 static const u8 pkex_resp_y_bp_p256r1
[32] = {
192 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
193 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
194 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
195 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
198 /* Brainpool P-384r1 */
199 static const u8 pkex_init_x_bp_p384r1
[48] = {
200 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
201 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
202 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
203 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
204 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
205 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
207 static const u8 pkex_init_y_bp_p384r1
[48] = {
208 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
209 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
210 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
211 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
212 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
213 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
215 static const u8 pkex_resp_x_bp_p384r1
[48] = {
216 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
217 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
218 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
219 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
220 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
221 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
223 static const u8 pkex_resp_y_bp_p384r1
[48] = {
224 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
225 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
226 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
227 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
228 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
229 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
232 /* Brainpool P-512r1 */
233 static const u8 pkex_init_x_bp_p512r1
[64] = {
234 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
235 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
236 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
237 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
238 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
239 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
240 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
241 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
243 static const u8 pkex_init_y_bp_p512r1
[64] = {
244 0x5a, 0x28, 0x01, 0xbe, 0x96, 0x82, 0x4e, 0xf6,
245 0xfa, 0xed, 0x7d, 0xfd, 0x48, 0x8b, 0x48, 0x4e,
246 0xd1, 0x97, 0x87, 0xc4, 0x05, 0x5d, 0x15, 0x2a,
247 0xf4, 0x91, 0x4b, 0x75, 0x90, 0xd9, 0x34, 0x2c,
248 0x3c, 0x12, 0xf2, 0xf5, 0x25, 0x94, 0x24, 0x34,
249 0xa7, 0x6d, 0x66, 0xbc, 0x27, 0xa4, 0xa0, 0x8d,
250 0xd5, 0xe1, 0x54, 0xa3, 0x55, 0x26, 0xd4, 0x14,
251 0x17, 0x0f, 0xc1, 0xc7, 0x3d, 0x68, 0x7f, 0x5a
253 static const u8 pkex_resp_x_bp_p512r1
[64] = {
254 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
255 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
256 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
257 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
258 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
259 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
260 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
261 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
263 static const u8 pkex_resp_y_bp_p512r1
[64] = {
264 0x2a, 0xbe, 0x59, 0xe6, 0xc4, 0xb3, 0xd8, 0x09,
265 0x66, 0x89, 0x0a, 0x2d, 0x19, 0xf0, 0x9c, 0x9f,
266 0xb4, 0xab, 0x8f, 0x50, 0x68, 0x3c, 0x74, 0x64,
267 0x4e, 0x19, 0x55, 0x81, 0x9b, 0x48, 0x5c, 0xf4,
268 0x12, 0x8d, 0xb9, 0xd8, 0x02, 0x5b, 0xe1, 0x26,
269 0x7e, 0x19, 0x5c, 0xfd, 0x70, 0xf7, 0x4b, 0xdc,
270 0xb5, 0x5d, 0xc1, 0x7a, 0xe9, 0xd1, 0x05, 0x2e,
271 0xd1, 0xfd, 0x2f, 0xce, 0x63, 0x77, 0x48, 0x2c
275 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
276 size_t num_elem
, const u8
*addr
[], const size_t *len
,
279 if (curve
->hash_len
== 32)
280 return sha256_vector(num_elem
, addr
, len
, mac
);
281 if (curve
->hash_len
== 48)
282 return sha384_vector(num_elem
, addr
, len
, mac
);
283 if (curve
->hash_len
== 64)
284 return sha512_vector(num_elem
, addr
, len
, mac
);
289 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
290 const char *label
, u8
*out
, size_t outlen
)
293 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
294 (const u8
*) label
, os_strlen(label
),
297 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
298 (const u8
*) label
, os_strlen(label
),
301 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
302 (const u8
*) label
, os_strlen(label
),
308 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
309 size_t num_elem
, const u8
*addr
[],
310 const size_t *len
, u8
*mac
)
313 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
316 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
319 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
325 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
326 const u8
*data
, size_t data_len
, u8
*mac
)
329 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
331 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
333 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
338 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
345 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
348 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
349 len
= i2o_ECPublicKey(eckey
, NULL
);
351 wpa_printf(MSG_ERROR
,
352 "DDP: Failed to determine public key encoding length");
357 buf
= wpabuf_alloc(len
);
363 pos
= wpabuf_put(buf
, len
);
364 res
= i2o_ECPublicKey(eckey
, &pos
);
367 wpa_printf(MSG_ERROR
,
368 "DDP: Failed to encode public key (res=%d/%d)",
375 /* Remove 0x04 prefix to match DPP definition */
376 pos
= wpabuf_mhead(buf
);
377 os_memmove(pos
, pos
+ 1, len
- 1);
385 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
386 const u8
*buf_x
, const u8
*buf_y
,
389 EC_KEY
*eckey
= NULL
;
391 EC_POINT
*point
= NULL
;
392 BIGNUM
*x
= NULL
, *y
= NULL
;
393 EVP_PKEY
*pkey
= NULL
;
397 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
401 point
= EC_POINT_new(group
);
402 x
= BN_bin2bn(buf_x
, len
, NULL
);
403 y
= BN_bin2bn(buf_y
, len
, NULL
);
404 if (!point
|| !x
|| !y
) {
405 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
409 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
410 wpa_printf(MSG_ERROR
,
411 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
412 ERR_error_string(ERR_get_error(), NULL
));
416 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
417 EC_POINT_is_at_infinity(group
, point
)) {
418 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
422 eckey
= EC_KEY_new();
424 EC_KEY_set_group(eckey
, group
) != 1 ||
425 EC_KEY_set_public_key(eckey
, point
) != 1) {
426 wpa_printf(MSG_ERROR
,
427 "DPP: Failed to set EC_KEY: %s",
428 ERR_error_string(ERR_get_error(), NULL
));
431 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
433 pkey
= EVP_PKEY_new();
434 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
435 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
443 EC_POINT_free(point
);
453 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
454 const u8
*buf
, size_t len
)
457 const EC_GROUP
*group
;
458 EVP_PKEY
*pkey
= NULL
;
463 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
465 wpa_printf(MSG_ERROR
,
466 "DPP: Could not get EC_KEY from group_key");
470 group
= EC_KEY_get0_group(eckey
);
472 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
475 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
482 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
487 msg
= wpabuf_alloc(7 + len
);
490 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
491 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
492 wpabuf_put_be24(msg
, OUI_WFA
);
493 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
494 wpabuf_put_u8(msg
, type
);
499 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
502 const u8
*pos
= buf
, *end
= buf
+ len
;
504 while (end
- pos
>= 4) {
505 id
= WPA_GET_LE16(pos
);
507 alen
= WPA_GET_LE16(pos
);
509 if (alen
> end
- pos
)
522 int dpp_check_attrs(const u8
*buf
, size_t len
)
528 while (end
- pos
>= 4) {
531 id
= WPA_GET_LE16(pos
);
533 alen
= WPA_GET_LE16(pos
);
535 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
537 if (alen
> end
- pos
) {
538 wpa_printf(MSG_DEBUG
,
539 "DPP: Truncated message - not enough room for the attribute - dropped");
546 wpa_printf(MSG_DEBUG
,
547 "DPP: Unexpected octets (%d) after the last attribute",
556 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
562 EVP_PKEY_free(info
->pubkey
);
567 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
570 case DPP_BOOTSTRAP_QR_CODE
:
572 case DPP_BOOTSTRAP_PKEX
:
579 static int dpp_uri_valid_info(const char *info
)
582 unsigned char val
= *info
++;
584 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
592 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
594 bi
->uri
= os_strdup(uri
);
595 return bi
->uri
? 0 : -1;
599 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
600 const char *chan_list
)
602 const char *pos
= chan_list
;
603 int opclass
, channel
, freq
;
605 while (pos
&& *pos
&& *pos
!= ';') {
609 pos
= os_strchr(pos
, '/');
616 while (*pos
>= '0' && *pos
<= '9')
618 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
619 wpa_printf(MSG_DEBUG
,
620 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
621 opclass
, channel
, freq
);
623 wpa_printf(MSG_DEBUG
,
624 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
626 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
627 wpa_printf(MSG_DEBUG
,
628 "DPP: Too many channels in URI channel-list - ignore list");
632 bi
->freq
[bi
->num_freq
++] = freq
;
635 if (*pos
== ';' || *pos
== '\0')
644 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
649 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
654 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
655 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
659 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
665 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
672 end
= os_strchr(info
, ';');
674 end
= info
+ os_strlen(info
);
675 bi
->info
= os_malloc(end
- info
+ 1);
678 os_memcpy(bi
->info
, info
, end
- info
);
679 bi
->info
[end
- info
] = '\0';
680 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
681 if (!dpp_uri_valid_info(bi
->info
)) {
682 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
690 static const struct dpp_curve_params
*
691 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
696 for (i
= 0; dpp_curves
[i
].name
; i
++) {
697 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
698 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
699 return &dpp_curves
[i
];
705 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
711 for (i
= 0; dpp_curves
[i
].name
; i
++) {
712 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
714 return &dpp_curves
[i
];
720 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
726 const unsigned char *p
;
728 X509_PUBKEY
*pub
= NULL
;
730 const unsigned char *pk
;
736 const ASN1_OBJECT
*poid
;
739 end
= os_strchr(info
, ';');
743 data
= base64_decode((const unsigned char *) info
, end
- info
,
746 wpa_printf(MSG_DEBUG
,
747 "DPP: Invalid base64 encoding on URI public-key");
750 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
753 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
754 bi
->pubkey_hash
) < 0) {
755 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
758 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
759 bi
->pubkey_hash
, SHA256_MAC_LEN
);
761 /* DER encoded ASN.1 SubjectPublicKeyInfo
763 * SubjectPublicKeyInfo ::= SEQUENCE {
764 * algorithm AlgorithmIdentifier,
765 * subjectPublicKey BIT STRING }
767 * AlgorithmIdentifier ::= SEQUENCE {
768 * algorithm OBJECT IDENTIFIER,
769 * parameters ANY DEFINED BY algorithm OPTIONAL }
771 * subjectPublicKey = compressed format public key per ANSI X9.63
772 * algorithm = ecPublicKey (1.2.840.10045.2.1)
773 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
774 * prime256v1 (1.2.840.10045.3.1.7)
778 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
782 wpa_printf(MSG_DEBUG
,
783 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
787 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
788 wpa_printf(MSG_DEBUG
,
789 "DPP: SubjectPublicKeyInfo does not describe an EC key");
794 res
= X509_PUBKEY_set(&pub
, pkey
);
796 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
800 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
802 wpa_printf(MSG_DEBUG
,
803 "DPP: Could not extract SubjectPublicKeyInfo parameters");
806 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
807 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
808 wpa_printf(MSG_DEBUG
,
809 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
812 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
813 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
814 wpa_printf(MSG_DEBUG
,
815 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
819 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
820 if (ptype
!= V_ASN1_OBJECT
) {
821 wpa_printf(MSG_DEBUG
,
822 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
826 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
827 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
828 wpa_printf(MSG_DEBUG
,
829 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
832 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
833 bi
->curve
= dpp_get_curve_oid(poid
);
835 wpa_printf(MSG_DEBUG
,
836 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
841 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
843 X509_PUBKEY_free(pub
);
847 X509_PUBKEY_free(pub
);
853 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
855 const char *pos
= uri
;
857 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
858 struct dpp_bootstrap_info
*bi
;
860 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
862 if (os_strncmp(pos
, "DPP:", 4) != 0) {
863 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
869 end
= os_strchr(pos
, ';');
874 /* Handle terminating ";;" and ignore unexpected ";"
875 * for parsing robustness. */
880 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
882 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
884 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
886 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
889 wpa_hexdump_ascii(MSG_DEBUG
,
890 "DPP: Ignore unrecognized URI parameter",
896 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
900 bi
= os_zalloc(sizeof(*bi
));
904 if (dpp_clone_uri(bi
, uri
) < 0 ||
905 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
906 dpp_parse_uri_mac(bi
, mac
) < 0 ||
907 dpp_parse_uri_info(bi
, info
) < 0 ||
908 dpp_parse_uri_pk(bi
, pk
) < 0) {
909 dpp_bootstrap_info_free(bi
);
917 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
919 struct dpp_bootstrap_info
*bi
;
921 bi
= dpp_parse_uri(uri
);
923 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
928 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
935 unsigned char *der
= NULL
;
938 out
= BIO_new(BIO_s_mem());
942 EVP_PKEY_print_private(out
, key
, 0, NULL
);
943 rlen
= BIO_ctrl_pending(out
);
944 txt
= os_malloc(rlen
+ 1);
946 res
= BIO_read(out
, txt
, rlen
);
949 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
955 eckey
= EVP_PKEY_get1_EC_KEY(key
);
959 der_len
= i2d_ECPrivateKey(eckey
, &der
);
961 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
965 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
967 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
975 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
977 #ifdef OPENSSL_IS_BORINGSSL
978 EVP_PKEY_CTX
*kctx
= NULL
;
979 const EC_GROUP
*group
;
982 EVP_PKEY_CTX
*pctx
, *kctx
= NULL
;
984 EVP_PKEY
*params
= NULL
, *key
= NULL
;
987 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
989 nid
= OBJ_txt2nid(curve
->name
);
990 if (nid
== NID_undef
) {
991 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
994 #ifdef OPENSSL_IS_BORINGSSL
995 group
= EC_GROUP_new_by_curve_name(nid
);
996 ec_params
= EC_KEY_new();
997 if (!ec_params
|| EC_KEY_set_group(ec_params
, group
) != 1) {
998 wpa_printf(MSG_ERROR
,
999 "DPP: Failed to generate EC_KEY parameters");
1002 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1003 params
= EVP_PKEY_new();
1004 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1005 wpa_printf(MSG_ERROR
,
1006 "DPP: Failed to generate EVP_PKEY parameters");
1010 pctx
= EVP_PKEY_CTX_new_id(EVP_PKEY_EC
, NULL
);
1012 EVP_PKEY_paramgen_init(pctx
) != 1 ||
1013 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx
, nid
) != 1 ||
1014 EVP_PKEY_CTX_set_ec_param_enc(pctx
, OPENSSL_EC_NAMED_CURVE
) != 1 ||
1015 EVP_PKEY_paramgen(pctx
, ¶ms
) != 1) {
1016 wpa_printf(MSG_ERROR
,
1017 "DPP: Failed to generate EVP_PKEY parameters");
1018 EVP_PKEY_CTX_free(pctx
);
1021 EVP_PKEY_CTX_free(pctx
);
1024 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1026 EVP_PKEY_keygen_init(kctx
) != 1 ||
1027 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1028 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1032 if (wpa_debug_show_keys
)
1033 dpp_debug_print_key("Own generated key", key
);
1035 EVP_PKEY_free(params
);
1036 EVP_PKEY_CTX_free(kctx
);
1039 EVP_PKEY_CTX_free(kctx
);
1040 EVP_PKEY_free(params
);
1045 static const struct dpp_curve_params
*
1046 dpp_get_curve_name(const char *name
)
1050 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1051 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1052 (dpp_curves
[i
].jwk_crv
&&
1053 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1054 return &dpp_curves
[i
];
1060 static const struct dpp_curve_params
*
1061 dpp_get_curve_jwk_crv(const char *name
)
1065 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1066 if (dpp_curves
[i
].jwk_crv
&&
1067 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1068 return &dpp_curves
[i
];
1074 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1075 const u8
*privkey
, size_t privkey_len
)
1079 const EC_GROUP
*group
;
1082 pkey
= EVP_PKEY_new();
1085 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1087 wpa_printf(MSG_INFO
,
1088 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1089 ERR_error_string(ERR_get_error(), NULL
));
1090 EVP_PKEY_free(pkey
);
1093 group
= EC_KEY_get0_group(eckey
);
1096 EVP_PKEY_free(pkey
);
1099 nid
= EC_GROUP_get_curve_name(group
);
1100 *curve
= dpp_get_curve_nid(nid
);
1102 wpa_printf(MSG_INFO
,
1103 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1106 EVP_PKEY_free(pkey
);
1110 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1112 EVP_PKEY_free(pkey
);
1119 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1121 unsigned char *der
= NULL
;
1127 /* Need to get the compressed form of the public key through EC_KEY, so
1128 * cannot use the simpler i2d_PUBKEY() here. */
1129 eckey
= EVP_PKEY_get1_EC_KEY(bi
->pubkey
);
1132 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_COMPRESSED
);
1133 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1136 wpa_printf(MSG_ERROR
,
1137 "DDP: Failed to build DER encoded public key");
1143 res
= sha256_vector(1, (const u8
**) &der
, &len
, bi
->pubkey_hash
);
1146 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1151 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1152 const u8
*privkey
, size_t privkey_len
)
1154 unsigned char *base64
= NULL
;
1157 unsigned char *der
= NULL
;
1162 bi
->curve
= &dpp_curves
[0];
1164 bi
->curve
= dpp_get_curve_name(curve
);
1166 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1172 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1174 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1179 /* Need to get the compressed form of the public key through EC_KEY, so
1180 * cannot use the simpler i2d_PUBKEY() here. */
1181 eckey
= EVP_PKEY_get1_EC_KEY(bi
->pubkey
);
1184 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_COMPRESSED
);
1185 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1188 wpa_printf(MSG_ERROR
,
1189 "DDP: Failed to build DER encoded public key");
1194 if (sha256_vector(1, (const u8
**) &der
, &len
, bi
->pubkey_hash
) < 0) {
1195 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1199 base64
= base64_encode(der
, der_len
, &len
);
1203 pos
= (char *) base64
;
1206 pos
= os_strchr(pos
, '\n');
1209 os_memmove(pos
, pos
+ 1, end
- pos
);
1211 return (char *) base64
;
1219 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1220 unsigned int hash_len
)
1222 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1223 const char *info
= "first intermediate key";
1226 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1228 /* HKDF-Extract(<>, M.x) */
1229 os_memset(salt
, 0, hash_len
);
1230 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1232 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1235 /* HKDF-Expand(PRK, info, L) */
1236 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1237 os_memset(prk
, 0, hash_len
);
1241 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1247 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1248 unsigned int hash_len
)
1250 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1251 const char *info
= "second intermediate key";
1254 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1256 /* HKDF-Extract(<>, N.x) */
1257 os_memset(salt
, 0, hash_len
);
1258 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1261 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1264 /* HKDF-Expand(PRK, info, L) */
1265 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1266 os_memset(prk
, 0, hash_len
);
1270 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1276 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1277 unsigned int hash_len
)
1280 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1281 const char *info_ke
= "DPP Key";
1282 u8 prk
[DPP_MAX_HASH_LEN
];
1286 size_t num_elem
= 0;
1288 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1290 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1291 nonce_len
= auth
->curve
->nonce_len
;
1292 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1293 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1294 addr
[num_elem
] = auth
->Mx
;
1295 len
[num_elem
] = auth
->secret_len
;
1297 addr
[num_elem
] = auth
->Nx
;
1298 len
[num_elem
] = auth
->secret_len
;
1300 if (auth
->peer_bi
&& auth
->own_bi
) {
1301 addr
[num_elem
] = auth
->Lx
;
1302 len
[num_elem
] = auth
->secret_len
;
1305 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1306 num_elem
, addr
, len
, prk
);
1309 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1312 /* HKDF-Expand(PRK, info, L) */
1313 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1314 os_memset(prk
, 0, hash_len
);
1318 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1324 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
1325 struct dpp_bootstrap_info
*peer_bi
,
1326 struct dpp_bootstrap_info
*own_bi
,
1329 struct dpp_authentication
*auth
;
1331 EVP_PKEY_CTX
*ctx
= NULL
;
1333 struct wpabuf
*msg
, *pi
= NULL
;
1334 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1335 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1338 size_t len
[1], siv_len
;
1340 auth
= os_zalloc(sizeof(*auth
));
1343 auth
->msg_ctx
= msg_ctx
;
1344 auth
->initiator
= 1;
1345 auth
->configurator
= configurator
;
1346 auth
->peer_bi
= peer_bi
;
1347 auth
->own_bi
= own_bi
;
1348 auth
->curve
= peer_bi
->curve
;
1350 nonce_len
= auth
->curve
->nonce_len
;
1351 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
1352 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
1355 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
1357 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
1358 if (!auth
->own_protocol_key
)
1361 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1365 /* ECDH: M = pI * BR */
1366 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
1368 EVP_PKEY_derive_init(ctx
) != 1 ||
1369 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
1370 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
1371 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
1372 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
1373 wpa_printf(MSG_ERROR
,
1374 "DPP: Failed to derive ECDH shared secret: %s",
1375 ERR_error_string(ERR_get_error(), NULL
));
1378 auth
->secret_len
= secret_len
;
1379 EVP_PKEY_CTX_free(ctx
);
1382 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
1383 auth
->Mx
, auth
->secret_len
);
1385 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
1386 auth
->curve
->hash_len
) < 0)
1389 /* Build DPP Authentication Request frame attributes */
1390 msg
= wpabuf_alloc(2 * (4 + SHA256_MAC_LEN
) + 4 + wpabuf_len(pi
) +
1391 4 + sizeof(wrapped_data
));
1394 auth
->req_attr
= msg
;
1396 /* Responder Bootstrapping Key Hash */
1397 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1398 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1399 wpabuf_put_data(msg
, auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
1401 /* Initiator Bootstrapping Key Hash */
1402 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1403 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1405 wpabuf_put_data(msg
, auth
->own_bi
->pubkey_hash
, SHA256_MAC_LEN
);
1407 os_memset(wpabuf_put(msg
, SHA256_MAC_LEN
), 0, SHA256_MAC_LEN
);
1409 /* Initiator Protocol Key */
1410 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1411 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1412 wpabuf_put_buf(msg
, pi
);
1416 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1419 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1421 WPA_PUT_LE16(pos
, nonce_len
);
1423 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1425 /* I-capabilities */
1426 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1428 WPA_PUT_LE16(pos
, 1);
1430 auth
->i_capab
= configurator
? DPP_CAPAB_CONFIGURATOR
:
1432 *pos
++ = auth
->i_capab
;
1434 addr
[0] = wpabuf_head(msg
);
1435 len
[0] = wpabuf_len(msg
);
1436 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
1437 siv_len
= pos
- clear
;
1438 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1439 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1440 1, addr
, len
, wrapped_data
) < 0)
1442 siv_len
+= AES_BLOCK_SIZE
;
1443 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1444 wrapped_data
, siv_len
);
1446 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1447 wpabuf_put_le16(msg
, siv_len
);
1448 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1450 wpa_hexdump_buf(MSG_DEBUG
,
1451 "DPP: Authentication Request frame attributes", msg
);
1456 EVP_PKEY_CTX_free(ctx
);
1457 dpp_auth_deinit(auth
);
1462 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
1466 size_t json_len
, clear_len
;
1467 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
1470 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
1472 nonce_len
= auth
->curve
->nonce_len
;
1473 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
1474 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
1477 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
1478 json_len
= os_strlen(json
);
1479 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
1481 /* { E-nonce, configAttrib }ke */
1482 clear_len
= 4 + nonce_len
+ 4 + json_len
;
1483 clear
= wpabuf_alloc(clear_len
);
1484 msg
= wpabuf_alloc(4 + clear_len
+ AES_BLOCK_SIZE
);
1489 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
1490 wpabuf_put_le16(clear
, nonce_len
);
1491 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
1494 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
1495 wpabuf_put_le16(clear
, json_len
);
1496 wpabuf_put_data(clear
, json
, json_len
);
1498 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1499 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
1500 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
1503 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
1504 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
1505 wpabuf_head(clear
), wpabuf_len(clear
),
1506 0, NULL
, NULL
, wrapped
) < 0)
1508 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1509 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
1511 wpa_hexdump_buf(MSG_DEBUG
,
1512 "DPP: Configuration Request frame attributes", msg
);
1523 static void dpp_auth_success(struct dpp_authentication
*auth
)
1525 wpa_printf(MSG_DEBUG
,
1526 "DPP: Authentication success - clear temporary keys");
1527 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
1528 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
1529 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
1530 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
1531 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
1533 auth
->auth_success
= 1;
1537 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
1539 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
1542 size_t i
, num_elem
= 0;
1547 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
1548 nonce_len
= auth
->curve
->nonce_len
;
1550 if (auth
->initiator
) {
1551 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1552 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
1554 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
1557 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
1559 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
1560 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1562 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
1565 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
1567 if (!pix
|| !prx
|| !brx
)
1570 addr
[num_elem
] = auth
->i_nonce
;
1571 len
[num_elem
] = nonce_len
;
1574 addr
[num_elem
] = auth
->r_nonce
;
1575 len
[num_elem
] = nonce_len
;
1578 addr
[num_elem
] = wpabuf_head(pix
);
1579 len
[num_elem
] = wpabuf_len(pix
) / 2;
1582 addr
[num_elem
] = wpabuf_head(prx
);
1583 len
[num_elem
] = wpabuf_len(prx
) / 2;
1587 addr
[num_elem
] = wpabuf_head(bix
);
1588 len
[num_elem
] = wpabuf_len(bix
) / 2;
1592 addr
[num_elem
] = wpabuf_head(brx
);
1593 len
[num_elem
] = wpabuf_len(brx
) / 2;
1596 addr
[num_elem
] = &zero
;
1600 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
1601 for (i
= 0; i
< num_elem
; i
++)
1602 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
1603 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
1605 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
1606 auth
->curve
->hash_len
);
1616 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
1618 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
1621 size_t i
, num_elem
= 0;
1626 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
1627 nonce_len
= auth
->curve
->nonce_len
;
1629 if (auth
->initiator
) {
1630 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1631 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
1633 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
1638 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
1640 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
1641 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1643 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
1648 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
1650 if (!pix
|| !prx
|| !brx
)
1653 addr
[num_elem
] = auth
->r_nonce
;
1654 len
[num_elem
] = nonce_len
;
1657 addr
[num_elem
] = auth
->i_nonce
;
1658 len
[num_elem
] = nonce_len
;
1661 addr
[num_elem
] = wpabuf_head(prx
);
1662 len
[num_elem
] = wpabuf_len(prx
) / 2;
1665 addr
[num_elem
] = wpabuf_head(pix
);
1666 len
[num_elem
] = wpabuf_len(pix
) / 2;
1669 addr
[num_elem
] = wpabuf_head(brx
);
1670 len
[num_elem
] = wpabuf_len(brx
) / 2;
1674 addr
[num_elem
] = wpabuf_head(bix
);
1675 len
[num_elem
] = wpabuf_len(bix
) / 2;
1679 addr
[num_elem
] = &one
;
1683 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
1684 for (i
= 0; i
< num_elem
; i
++)
1685 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
1686 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
1688 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
1689 auth
->curve
->hash_len
);
1699 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
1701 const EC_GROUP
*group
;
1703 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
1704 const EC_POINT
*BI_point
;
1706 BIGNUM
*lx
, *sum
, *q
;
1707 const BIGNUM
*bR_bn
, *pR_bn
;
1709 int num_bytes
, offset
;
1711 /* L = ((bR + pR) modulo q) * BI */
1713 bnctx
= BN_CTX_new();
1717 if (!bnctx
|| !sum
|| !q
|| !lx
)
1719 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
1722 BI_point
= EC_KEY_get0_public_key(BI
);
1723 group
= EC_KEY_get0_group(BI
);
1727 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
1728 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
1731 bR_bn
= EC_KEY_get0_private_key(bR
);
1732 pR_bn
= EC_KEY_get0_private_key(pR
);
1733 if (!bR_bn
|| !pR_bn
)
1735 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
1736 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
1738 l
= EC_POINT_new(group
);
1740 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
1741 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
1743 wpa_printf(MSG_ERROR
,
1744 "OpenSSL: failed: %s",
1745 ERR_error_string(ERR_get_error(), NULL
));
1749 num_bytes
= BN_num_bytes(lx
);
1750 if ((size_t) num_bytes
> auth
->secret_len
)
1752 if (auth
->secret_len
> (size_t) num_bytes
)
1753 offset
= auth
->secret_len
- num_bytes
;
1757 os_memset(auth
->Lx
, 0, offset
);
1758 BN_bn2bin(lx
, auth
->Lx
+ offset
);
1759 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
1762 EC_POINT_clear_free(l
);
1774 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
1776 const EC_GROUP
*group
;
1777 EC_POINT
*l
= NULL
, *sum
= NULL
;
1778 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
1779 const EC_POINT
*BR_point
, *PR_point
;
1782 const BIGNUM
*bI_bn
;
1784 int num_bytes
, offset
;
1786 /* L = bI * (BR + PR) */
1788 bnctx
= BN_CTX_new();
1792 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
1793 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
1796 BR_point
= EC_KEY_get0_public_key(BR
);
1797 PR_point
= EC_KEY_get0_public_key(PR
);
1799 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
1802 group
= EC_KEY_get0_group(bI
);
1803 bI_bn
= EC_KEY_get0_private_key(bI
);
1804 if (!group
|| !bI_bn
)
1806 sum
= EC_POINT_new(group
);
1807 l
= EC_POINT_new(group
);
1809 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
1810 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
1811 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
1813 wpa_printf(MSG_ERROR
,
1814 "OpenSSL: failed: %s",
1815 ERR_error_string(ERR_get_error(), NULL
));
1819 num_bytes
= BN_num_bytes(lx
);
1820 if ((size_t) num_bytes
> auth
->secret_len
)
1822 if (auth
->secret_len
> (size_t) num_bytes
)
1823 offset
= auth
->secret_len
- num_bytes
;
1827 os_memset(auth
->Lx
, 0, offset
);
1828 BN_bn2bin(lx
, auth
->Lx
+ offset
);
1829 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
1832 EC_POINT_clear_free(l
);
1842 static int dpp_auth_build_resp(struct dpp_authentication
*auth
)
1845 EVP_PKEY_CTX
*ctx
= NULL
;
1847 struct wpabuf
*msg
, *pr
= NULL
;
1848 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
1849 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
];
1850 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1851 4 + sizeof(wrapped_r_auth)
1852 size_t wrapped_r_auth_len
;
1853 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1854 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1857 size_t len
[1], siv_len
;
1859 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
1861 nonce_len
= auth
->curve
->nonce_len
;
1862 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
1863 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
1866 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
1868 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
1869 if (!auth
->own_protocol_key
)
1872 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
1876 /* ECDH: N = pR * PI */
1877 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
1879 EVP_PKEY_derive_init(ctx
) != 1 ||
1880 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
1881 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
1882 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
1883 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
1884 wpa_printf(MSG_ERROR
,
1885 "DPP: Failed to derive ECDH shared secret: %s",
1886 ERR_error_string(ERR_get_error(), NULL
));
1889 EVP_PKEY_CTX_free(ctx
);
1892 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
1893 auth
->Nx
, auth
->secret_len
);
1895 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
1896 auth
->curve
->hash_len
) < 0)
1899 if (auth
->own_bi
&& auth
->peer_bi
) {
1900 /* Mutual authentication */
1901 if (dpp_auth_derive_l_responder(auth
) < 0)
1905 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
1908 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
1909 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
1910 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
1911 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0 ||
1912 aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
1913 r_auth
, 4 + auth
->curve
->hash_len
,
1914 0, NULL
, NULL
, wrapped_r_auth
) < 0)
1916 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
1917 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
1918 wrapped_r_auth
, wrapped_r_auth_len
);
1920 /* Build DPP Authentication Response frame attributes */
1921 msg
= wpabuf_alloc(4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1922 4 + wpabuf_len(pr
) + 4 + sizeof(wrapped_data
));
1925 wpabuf_free(auth
->resp_attr
);
1926 auth
->resp_attr
= msg
;
1929 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1930 wpabuf_put_le16(msg
, 1);
1931 wpabuf_put_u8(msg
, DPP_STATUS_OK
);
1933 /* Responder Bootstrapping Key Hash */
1934 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1935 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1936 wpabuf_put_data(msg
, auth
->own_bi
->pubkey_hash
, SHA256_MAC_LEN
);
1938 if (auth
->peer_bi
) {
1939 /* Mutual authentication */
1940 /* Initiator Bootstrapping Key Hash */
1941 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1942 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1943 wpabuf_put_data(msg
, auth
->peer_bi
->pubkey_hash
,
1947 /* Responder Protocol Key */
1948 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1949 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1950 wpabuf_put_buf(msg
, pr
);
1954 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1957 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1959 WPA_PUT_LE16(pos
, nonce_len
);
1961 os_memcpy(pos
, auth
->r_nonce
, nonce_len
);
1964 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1966 WPA_PUT_LE16(pos
, nonce_len
);
1968 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1970 /* R-capabilities */
1971 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1973 WPA_PUT_LE16(pos
, 1);
1975 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1977 *pos
++ = auth
->r_capab
;
1979 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1981 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1983 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1984 pos
+= wrapped_r_auth_len
;
1986 addr
[0] = wpabuf_head(msg
);
1987 len
[0] = wpabuf_len(msg
);
1988 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
1989 siv_len
= pos
- clear
;
1990 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1991 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
, clear
, siv_len
,
1992 1, addr
, len
, wrapped_data
) < 0)
1994 siv_len
+= AES_BLOCK_SIZE
;
1995 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1996 wrapped_data
, siv_len
);
1998 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1999 wpabuf_put_le16(msg
, siv_len
);
2000 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
2002 wpa_hexdump_buf(MSG_DEBUG
,
2003 "DPP: Authentication Response frame attributes", msg
);
2013 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2014 enum dpp_status_error status
)
2018 #define DPP_AUTH_RESP_CLEAR_LEN2 4 + DPP_MAX_NONCE_LEN + 4 + 1
2019 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN2
];
2020 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN2
+ AES_BLOCK_SIZE
];
2023 size_t len
[1], siv_len
;
2025 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2027 /* Build DPP Authentication Response frame attributes */
2028 msg
= wpabuf_alloc(4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
2029 4 + sizeof(wrapped_data
));
2032 wpabuf_free(auth
->resp_attr
);
2033 auth
->resp_attr
= msg
;
2036 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
2037 wpabuf_put_le16(msg
, 1);
2038 wpabuf_put_u8(msg
, status
);
2040 /* Responder Bootstrapping Key Hash */
2041 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
2042 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2043 wpabuf_put_data(msg
, auth
->own_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2045 if (auth
->peer_bi
) {
2046 /* Mutual authentication */
2047 /* Initiator Bootstrapping Key Hash */
2048 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
2049 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2050 wpabuf_put_data(msg
, auth
->peer_bi
->pubkey_hash
,
2054 /* Wrapped data ({I-nonce, R-capabilities}k1) */
2057 nonce_len
= auth
->curve
->nonce_len
;
2058 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
2060 WPA_PUT_LE16(pos
, nonce_len
);
2062 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
2064 /* R-capabilities */
2065 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
2067 WPA_PUT_LE16(pos
, 1);
2069 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
2071 *pos
++ = auth
->r_capab
;
2073 addr
[0] = wpabuf_head(msg
);
2074 len
[0] = wpabuf_len(msg
);
2075 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
2076 siv_len
= pos
- clear
;
2077 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
2078 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
2079 1, addr
, len
, wrapped_data
) < 0)
2081 siv_len
+= AES_BLOCK_SIZE
;
2082 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2083 wrapped_data
, siv_len
);
2085 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2086 wpabuf_put_le16(msg
, siv_len
);
2087 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
2089 wpa_hexdump_buf(MSG_DEBUG
,
2090 "DPP: Authentication Response frame attributes", msg
);
2099 struct dpp_authentication
*
2100 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
2101 struct dpp_bootstrap_info
*peer_bi
,
2102 struct dpp_bootstrap_info
*own_bi
,
2103 unsigned int freq
, const u8
*attr_start
,
2104 const u8
*wrapped_data
, u16 wrapped_data_len
)
2106 EVP_PKEY
*pi
= NULL
;
2107 EVP_PKEY_CTX
*ctx
= NULL
;
2111 u8
*unwrapped
= NULL
;
2112 size_t unwrapped_len
= 0;
2113 const u8
*i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
;
2114 u16 i_proto_len
, i_nonce_len
, i_capab_len
, i_bootstrap_len
;
2115 struct dpp_authentication
*auth
= NULL
;
2118 if (wrapped_data_len
< AES_BLOCK_SIZE
)
2121 attr_len
= wrapped_data
- 4 - attr_start
;
2123 auth
= os_zalloc(sizeof(*auth
));
2126 auth
->msg_ctx
= msg_ctx
;
2127 auth
->peer_bi
= peer_bi
;
2128 auth
->own_bi
= own_bi
;
2129 auth
->curve
= own_bi
->curve
;
2130 auth
->curr_freq
= freq
;
2132 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
2135 wpa_printf(MSG_DEBUG
,
2136 "DPP: Missing required Initiator Protocol Key attribute");
2139 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
2140 i_proto
, i_proto_len
);
2143 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
2145 wpa_printf(MSG_DEBUG
, "DPP: Invalid Initiator Protocol Key");
2148 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
2150 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
2152 EVP_PKEY_derive_init(ctx
) != 1 ||
2153 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
2154 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2155 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2156 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2157 wpa_printf(MSG_ERROR
,
2158 "DPP: Failed to derive ECDH shared secret: %s",
2159 ERR_error_string(ERR_get_error(), NULL
));
2162 auth
->secret_len
= secret_len
;
2163 EVP_PKEY_CTX_free(ctx
);
2166 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2167 auth
->Mx
, auth
->secret_len
);
2169 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2170 auth
->curve
->hash_len
) < 0)
2173 addr
[0] = attr_start
;
2175 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
2176 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2177 wrapped_data
, wrapped_data_len
);
2178 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2179 unwrapped
= os_malloc(unwrapped_len
);
2182 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
2183 wrapped_data
, wrapped_data_len
,
2184 1, addr
, len
, unwrapped
) < 0) {
2185 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
2188 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2189 unwrapped
, unwrapped_len
);
2191 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
2192 wpa_printf(MSG_DEBUG
,
2193 "DPP: Invalid attribute in unwrapped data");
2197 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
2199 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
2200 wpa_printf(MSG_DEBUG
, "DPP: Missing or invalid I-nonce");
2203 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
2204 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
2206 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
2207 DPP_ATTR_I_CAPABILITIES
,
2209 if (!i_capab
|| i_capab_len
< 1) {
2210 wpa_printf(MSG_DEBUG
, "DPP: Missing or invalid I-capabilities");
2213 auth
->i_capab
= i_capab
[0];
2214 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
2216 bin_clear_free(unwrapped
, unwrapped_len
);
2219 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
2220 case DPP_CAPAB_ENROLLEE
:
2221 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
2222 wpa_printf(MSG_DEBUG
,
2223 "DPP: Local policy does not allow Configurator role");
2224 goto not_compatible
;
2226 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
2227 auth
->configurator
= 1;
2229 case DPP_CAPAB_CONFIGURATOR
:
2230 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
2231 wpa_printf(MSG_DEBUG
,
2232 "DPP: Local policy does not allow Enrollee role");
2233 goto not_compatible
;
2235 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
2236 auth
->configurator
= 0;
2239 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
2240 goto not_compatible
;
2243 auth
->peer_protocol_key
= pi
;
2245 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
2246 char hex
[SHA256_MAC_LEN
* 2 + 1];
2248 wpa_printf(MSG_DEBUG
,
2249 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2250 if (dpp_auth_build_resp_status(auth
,
2251 DPP_STATUS_RESPONSE_PENDING
) < 0)
2253 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2254 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
2256 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
2257 auth
->response_pending
= 1;
2258 os_memcpy(auth
->waiting_pubkey_hash
,
2259 i_bootstrap
, i_bootstrap_len
);
2260 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
2266 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
2270 if (dpp_auth_build_resp(auth
) < 0)
2276 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
2277 "i-capab=0x%02x", auth
->i_capab
);
2278 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
2279 auth
->configurator
= 1;
2281 auth
->configurator
= 0;
2282 auth
->peer_protocol_key
= pi
;
2284 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
2287 auth
->remove_on_tx_status
= 1;
2290 bin_clear_free(unwrapped
, unwrapped_len
);
2292 EVP_PKEY_CTX_free(ctx
);
2293 dpp_auth_deinit(auth
);
2298 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
2299 struct dpp_bootstrap_info
*peer_bi
)
2301 if (!auth
|| !auth
->response_pending
||
2302 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
2303 SHA256_MAC_LEN
) != 0)
2306 wpa_printf(MSG_DEBUG
,
2307 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2308 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
2309 auth
->peer_bi
= peer_bi
;
2311 if (dpp_auth_build_resp(auth
) < 0)
2318 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
)
2321 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
2327 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
2329 i_auth_len
= 4 + auth
->curve
->hash_len
;
2330 /* Build DPP Authentication Confirmation frame attributes */
2331 msg
= wpabuf_alloc(4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
2332 4 + i_auth_len
+ AES_BLOCK_SIZE
);
2337 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
2338 wpabuf_put_le16(msg
, 1);
2339 wpabuf_put_u8(msg
, DPP_STATUS_OK
);
2341 /* Responder Bootstrapping Key Hash */
2342 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
2343 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2344 wpabuf_put_data(msg
, auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2347 /* Mutual authentication */
2348 /* Initiator Bootstrapping Key Hash */
2349 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
2350 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
2351 wpabuf_put_data(msg
, auth
->own_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2354 addr
[0] = wpabuf_head(msg
);
2355 len
[0] = wpabuf_len(msg
);
2356 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2357 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
2358 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
2359 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2360 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
2361 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
2362 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0 ||
2363 aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2365 1, addr
, len
, wrapped_i_auth
) < 0)
2367 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
2368 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
2370 wpa_hexdump_buf(MSG_DEBUG
,
2371 "DPP: Authentication Confirmation frame attributes",
2373 dpp_auth_success(auth
);
2383 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
,
2384 const u8
*attr_start
, size_t attr_len
,
2385 const u8
*wrapped_data
, u16 wrapped_data_len
,
2386 enum dpp_status_error status
)
2390 u8
*unwrapped
= NULL
;
2391 size_t unwrapped_len
= 0;
2392 const u8
*i_nonce
, *r_capab
;
2393 u16 i_nonce_len
, r_capab_len
;
2395 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
2396 wpa_printf(MSG_DEBUG
,
2397 "DPP: Responder reported incompatible roles");
2398 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
2399 wpa_printf(MSG_DEBUG
,
2400 "DPP: Responder reported more time needed");
2402 wpa_printf(MSG_DEBUG
,
2403 "DPP: Responder reported failure (status %d)",
2408 addr
[0] = attr_start
;
2410 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
2411 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2412 wrapped_data
, wrapped_data_len
);
2413 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2414 unwrapped
= os_malloc(unwrapped_len
);
2417 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
2418 wrapped_data
, wrapped_data_len
,
2419 1, addr
, len
, unwrapped
) < 0) {
2420 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
2423 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2424 unwrapped
, unwrapped_len
);
2426 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
2427 wpa_printf(MSG_DEBUG
,
2428 "DPP: Invalid attribute in unwrapped data");
2432 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
2434 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
2435 wpa_printf(MSG_DEBUG
, "DPP: Missing or invalid I-nonce");
2438 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
2439 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
2440 wpa_printf(MSG_DEBUG
, "DPP: I-nonce mismatch");
2444 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
2445 DPP_ATTR_R_CAPABILITIES
,
2447 if (!r_capab
|| r_capab_len
< 1) {
2448 wpa_printf(MSG_DEBUG
, "DPP: Missing or invalid R-capabilities");
2451 auth
->r_capab
= r_capab
[0];
2452 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
2453 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
2454 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
2455 "r-capab=0x%02x", auth
->r_capab
);
2456 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
2457 wpa_printf(MSG_DEBUG
,
2458 "DPP: Continue waiting for full DPP Authentication Response");
2459 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_RESPONSE_PENDING
);
2462 bin_clear_free(unwrapped
, unwrapped_len
);
2467 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
2471 EVP_PKEY_CTX
*ctx
= NULL
;
2475 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
2476 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
2477 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
2478 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
2479 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
2480 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
2481 wrapped2_len
, r_auth_len
;
2482 u8 r_auth2
[DPP_MAX_HASH_LEN
];
2484 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2486 if (!wrapped_data
) {
2487 wpa_printf(MSG_DEBUG
,
2488 "DPP: Missing required Wrapped data attribute");
2491 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
2492 wrapped_data
, wrapped_data_len
);
2494 if (wrapped_data_len
< AES_BLOCK_SIZE
)
2497 attr_len
= wrapped_data
- 4 - attr_start
;
2499 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2500 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
2502 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
2503 wpa_printf(MSG_DEBUG
,
2504 "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
2507 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
2508 r_bootstrap
, r_bootstrap_len
);
2509 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
2510 SHA256_MAC_LEN
) != 0) {
2511 wpa_hexdump(MSG_DEBUG
,
2512 "DPP: Expected Responder Bootstrapping Key Hash",
2513 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2517 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2518 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
2521 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
2522 wpa_printf(MSG_DEBUG
,
2523 "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
2526 wpa_hexdump(MSG_MSGDUMP
,
2527 "DPP: Initiator Bootstrapping Key Hash",
2528 i_bootstrap
, i_bootstrap_len
);
2529 if (!auth
->own_bi
||
2530 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
2531 SHA256_MAC_LEN
) != 0) {
2532 wpa_printf(MSG_DEBUG
,
2533 "DPP: Initiator Bootstrapping Key Hash attribute did not match");
2538 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
2540 if (!status
|| status_len
< 1) {
2541 wpa_printf(MSG_DEBUG
,
2542 "DPP: Missing or invalid required DPP Status attribute");
2545 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
2546 auth
->auth_resp_status
= status
[0];
2547 if (status
[0] != DPP_STATUS_OK
) {
2548 dpp_auth_resp_rx_status(auth
, attr_start
,
2549 attr_len
, wrapped_data
,
2550 wrapped_data_len
, status
[0]);
2554 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
2557 wpa_printf(MSG_DEBUG
,
2558 "DPP: Missing required Responder Protocol Key attribute");
2561 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
2562 r_proto
, r_proto_len
);
2565 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
2567 wpa_printf(MSG_DEBUG
, "DPP: Invalid Responder Protocol Key");
2570 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
2572 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2574 EVP_PKEY_derive_init(ctx
) != 1 ||
2575 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
2576 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2577 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2578 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2579 wpa_printf(MSG_ERROR
,
2580 "DPP: Failed to derive ECDH shared secret: %s",
2581 ERR_error_string(ERR_get_error(), NULL
));
2584 EVP_PKEY_CTX_free(ctx
);
2586 auth
->peer_protocol_key
= pr
;
2589 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2590 auth
->Nx
, auth
->secret_len
);
2592 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2593 auth
->curve
->hash_len
) < 0)
2596 addr
[0] = attr_start
;
2598 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
2599 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2600 wrapped_data
, wrapped_data_len
);
2601 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2602 unwrapped
= os_malloc(unwrapped_len
);
2605 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
2606 wrapped_data
, wrapped_data_len
,
2607 1, addr
, len
, unwrapped
) < 0) {
2608 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
2611 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2612 unwrapped
, unwrapped_len
);
2614 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
2615 wpa_printf(MSG_DEBUG
,
2616 "DPP: Invalid attribute in unwrapped data");
2620 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
2622 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
2623 wpa_printf(MSG_DEBUG
, "DPP: Missing or invalid R-nonce");
2626 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
2627 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
2629 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
2631 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
2632 wpa_printf(MSG_DEBUG
, "DPP: Missing or invalid I-nonce");
2635 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
2636 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
2637 wpa_printf(MSG_DEBUG
, "DPP: I-nonce mismatch");
2641 if (auth
->own_bi
&& auth
->peer_bi
) {
2642 /* Mutual authentication */
2643 if (dpp_auth_derive_l_initiator(auth
) < 0)
2647 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2650 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
2651 DPP_ATTR_R_CAPABILITIES
,
2653 if (!r_capab
|| r_capab_len
< 1) {
2654 wpa_printf(MSG_DEBUG
, "DPP: Missing or invalid R-capabilities");
2657 auth
->r_capab
= r_capab
[0];
2658 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
2659 if ((auth
->configurator
&& (auth
->r_capab
& DPP_CAPAB_CONFIGURATOR
)) ||
2660 (!auth
->configurator
&& (auth
->r_capab
& DPP_CAPAB_ENROLLEE
))) {
2661 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
2665 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
2666 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
2667 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
2668 wpa_printf(MSG_DEBUG
,
2669 "DPP: Missing or invalid Secondary Wrapped Data");
2673 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2674 wrapped2
, wrapped2_len
);
2675 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
2676 unwrapped2
= os_malloc(unwrapped2_len
);
2679 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
2680 wrapped2
, wrapped2_len
,
2681 0, NULL
, NULL
, unwrapped2
) < 0) {
2682 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
2685 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2686 unwrapped2
, unwrapped2_len
);
2688 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
2689 wpa_printf(MSG_DEBUG
,
2690 "DPP: Invalid attribute in secondary unwrapped data");
2694 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
2696 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
2697 wpa_printf(MSG_DEBUG
,
2698 "DPP: Missing or invalid Responder Authenticating Tag");
2701 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
2702 r_auth
, r_auth_len
);
2703 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2704 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
2706 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
2707 r_auth2
, r_auth_len
);
2708 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
2709 wpa_printf(MSG_DEBUG
,
2710 "DPP: Mismatching Responder Authenticating Tag");
2714 bin_clear_free(unwrapped
, unwrapped_len
);
2715 bin_clear_free(unwrapped2
, unwrapped2_len
);
2717 return dpp_auth_build_conf(auth
);
2720 bin_clear_free(unwrapped
, unwrapped_len
);
2721 bin_clear_free(unwrapped2
, unwrapped2_len
);
2723 EVP_PKEY_CTX_free(ctx
);
2728 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
2731 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
2732 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
2736 u8
*unwrapped
= NULL
;
2737 size_t unwrapped_len
= 0;
2738 u8 i_auth2
[DPP_MAX_HASH_LEN
];
2740 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2742 if (!wrapped_data
) {
2743 wpa_printf(MSG_DEBUG
,
2744 "DPP: Missing required Wrapped data attribute");
2747 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
2748 wrapped_data
, wrapped_data_len
);
2750 if (wrapped_data_len
< AES_BLOCK_SIZE
)
2753 attr_len
= wrapped_data
- 4 - attr_start
;
2755 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2756 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
2758 if (!r_bootstrap
|| r_bootstrap
> wrapped_data
||
2759 r_bootstrap_len
!= SHA256_MAC_LEN
) {
2760 wpa_printf(MSG_DEBUG
,
2761 "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
2764 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
2765 r_bootstrap
, r_bootstrap_len
);
2766 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
2767 SHA256_MAC_LEN
) != 0) {
2768 wpa_hexdump(MSG_DEBUG
,
2769 "DPP: Expected Responder Bootstrapping Key Hash",
2770 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
2774 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
2775 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
2778 if (i_bootstrap
> wrapped_data
||
2779 i_bootstrap_len
!= SHA256_MAC_LEN
) {
2780 wpa_printf(MSG_DEBUG
,
2781 "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
2784 wpa_hexdump(MSG_MSGDUMP
,
2785 "DPP: Initiator Bootstrapping Key Hash",
2786 i_bootstrap
, i_bootstrap_len
);
2787 if (!auth
->peer_bi
||
2788 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
2789 SHA256_MAC_LEN
) != 0) {
2790 wpa_printf(MSG_DEBUG
,
2791 "DPP: Initiator Bootstrapping Key Hash attribute did not match");
2796 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
2798 if (!status
|| status_len
< 1) {
2799 wpa_printf(MSG_DEBUG
,
2800 "DPP: Missing or invalid required DPP Status attribute");
2803 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
2804 if (status
[0] != DPP_STATUS_OK
) {
2805 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
2809 addr
[0] = attr_start
;
2811 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
2812 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2813 wrapped_data
, wrapped_data_len
);
2814 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2815 unwrapped
= os_malloc(unwrapped_len
);
2818 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
2819 wrapped_data
, wrapped_data_len
,
2820 1, addr
, len
, unwrapped
) < 0) {
2821 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
2824 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
2825 unwrapped
, unwrapped_len
);
2827 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
2828 wpa_printf(MSG_DEBUG
,
2829 "DPP: Invalid attribute in unwrapped data");
2833 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
2835 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
2836 wpa_printf(MSG_DEBUG
,
2837 "DPP: Missing or invalid Initiator Authenticating Tag");
2840 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
2841 i_auth
, i_auth_len
);
2842 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2843 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
2845 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
2846 i_auth2
, i_auth_len
);
2847 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
2848 wpa_printf(MSG_DEBUG
,
2849 "DPP: Mismatching Initiator Authenticating Tag");
2853 bin_clear_free(unwrapped
, unwrapped_len
);
2854 dpp_auth_success(auth
);
2857 bin_clear_free(unwrapped
, unwrapped_len
);
2862 void dpp_configuration_free(struct dpp_configuration
*conf
)
2866 str_clear_free(conf
->passphrase
);
2867 bin_clear_free(conf
, sizeof(*conf
));
2871 void dpp_auth_deinit(struct dpp_authentication
*auth
)
2875 dpp_configuration_free(auth
->conf_ap
);
2876 dpp_configuration_free(auth
->conf_sta
);
2877 EVP_PKEY_free(auth
->own_protocol_key
);
2878 EVP_PKEY_free(auth
->peer_protocol_key
);
2879 wpabuf_free(auth
->req_attr
);
2880 wpabuf_free(auth
->resp_attr
);
2881 wpabuf_free(auth
->conf_req
);
2882 os_free(auth
->connector
);
2883 wpabuf_free(auth
->net_access_key
);
2884 wpabuf_free(auth
->c_sign_key
);
2885 #ifdef CONFIG_TESTING_OPTIONS
2886 os_free(auth
->config_obj_override
);
2887 os_free(auth
->discovery_override
);
2888 os_free(auth
->groups_override
);
2889 os_free(auth
->devices_override
);
2890 #endif /* CONFIG_TESTING_OPTIONS */
2891 bin_clear_free(auth
, sizeof(*auth
));
2895 static struct wpabuf
*
2896 dpp_build_conf_start(struct dpp_authentication
*auth
,
2897 struct dpp_configuration
*conf
, size_t tailroom
)
2900 char ssid
[6 * sizeof(conf
->ssid
) + 1];
2902 #ifdef CONFIG_TESTING_OPTIONS
2903 if (auth
->discovery_override
)
2904 tailroom
+= os_strlen(auth
->discovery_override
);
2905 #endif /* CONFIG_TESTING_OPTIONS */
2907 buf
= wpabuf_alloc(200 + tailroom
);
2910 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
2911 #ifdef CONFIG_TESTING_OPTIONS
2912 if (auth
->discovery_override
) {
2913 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
2914 auth
->discovery_override
);
2915 wpabuf_put_str(buf
, auth
->discovery_override
);
2916 wpabuf_put_u8(buf
, ',');
2919 #endif /* CONFIG_TESTING_OPTIONS */
2920 wpabuf_put_str(buf
, "{\"ssid\":\"");
2921 json_escape_string(ssid
, sizeof(ssid
),
2922 (const char *) conf
->ssid
, conf
->ssid_len
);
2923 wpabuf_put_str(buf
, ssid
);
2924 wpabuf_put_str(buf
, "\"");
2925 /* TODO: optional channel information */
2926 wpabuf_put_str(buf
, "},");
2932 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
2934 int num_bytes
, offset
;
2936 num_bytes
= BN_num_bytes(bn
);
2937 if ((size_t) num_bytes
> len
)
2939 offset
= len
- num_bytes
;
2940 os_memset(pos
, 0, offset
);
2941 BN_bn2bin(bn
, pos
+ offset
);
2946 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
2947 const char *kid
, const struct dpp_curve_params
*curve
)
2951 char *x
= NULL
, *y
= NULL
;
2954 pub
= dpp_get_pubkey_point(key
, 0);
2957 pos
= wpabuf_head(pub
);
2958 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
2959 pos
+= curve
->prime_len
;
2960 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
2962 wpabuf_put_str(buf
, "\"");
2963 wpabuf_put_str(buf
, name
);
2964 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
2965 wpabuf_put_str(buf
, curve
->jwk_crv
);
2966 wpabuf_put_str(buf
, "\",\"x\":\"");
2967 wpabuf_put_str(buf
, x
);
2968 wpabuf_put_str(buf
, "\",\"y\":\"");
2969 wpabuf_put_str(buf
, y
);
2971 wpabuf_put_str(buf
, "\",\"kid\":\"");
2972 wpabuf_put_str(buf
, kid
);
2974 wpabuf_put_str(buf
, "\"}");
2986 static struct wpabuf
*
2987 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
2988 struct dpp_configuration
*conf
)
2990 struct wpabuf
*buf
= NULL
;
2991 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
2993 const struct dpp_curve_params
*curve
;
2994 char jws_prot_hdr
[100];
2995 size_t signed1_len
, signed2_len
, signed3_len
;
2996 struct wpabuf
*dppcon
= NULL
;
2997 unsigned char *signature
= NULL
;
2998 const unsigned char *p
;
2999 size_t signature_len
;
3000 EVP_MD_CTX
*md_ctx
= NULL
;
3001 ECDSA_SIG
*sig
= NULL
;
3003 const EVP_MD
*sign_md
;
3004 const BIGNUM
*r
, *s
;
3005 size_t extra_len
= 1000;
3008 wpa_printf(MSG_INFO
,
3009 "DPP: No configurator specified - cannot generate DPP config object");
3012 curve
= auth
->conf
->curve
;
3013 if (curve
->hash_len
== SHA256_MAC_LEN
) {
3014 sign_md
= EVP_sha256();
3015 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
3016 sign_md
= EVP_sha384();
3017 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
3018 sign_md
= EVP_sha512();
3020 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
3024 #ifdef CONFIG_TESTING_OPTIONS
3025 if (auth
->groups_override
)
3026 extra_len
+= os_strlen(auth
->groups_override
);
3027 if (auth
->devices_override
)
3028 extra_len
+= os_strlen(auth
->devices_override
);
3029 #endif /* CONFIG_TESTING_OPTIONS */
3031 /* Connector (JSON dppCon object) */
3032 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
3035 #ifdef CONFIG_TESTING_OPTIONS
3036 if (auth
->groups_override
|| auth
->devices_override
) {
3037 wpabuf_put_u8(dppcon
, '{');
3038 if (auth
->groups_override
) {
3039 wpa_printf(MSG_DEBUG
,
3040 "DPP: TESTING - groups override: '%s'",
3041 auth
->groups_override
);
3042 wpabuf_put_str(dppcon
, "\"groups\":");
3043 wpabuf_put_str(dppcon
, auth
->groups_override
);
3044 wpabuf_put_u8(dppcon
, ',');
3046 if (auth
->devices_override
) {
3047 wpa_printf(MSG_DEBUG
,
3048 "DPP: TESTING - devices override: '%s'",
3049 auth
->devices_override
);
3050 wpabuf_put_str(dppcon
, "\"devices\":");
3051 wpabuf_put_str(dppcon
, auth
->devices_override
);
3052 wpabuf_put_u8(dppcon
, ',');
3056 #endif /* CONFIG_TESTING_OPTIONS */
3057 wpabuf_put_str(dppcon
, "{\"groups\":[{\"groupId\":\"*\",");
3058 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
3059 #ifdef CONFIG_TESTING_OPTIONS
3061 #endif /* CONFIG_TESTING_OPTIONS */
3062 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
3064 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
3067 if (conf
->netaccesskey_expiry
) {
3070 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
3071 wpa_printf(MSG_DEBUG
,
3072 "DPP: Failed to generate expiry string");
3075 wpabuf_printf(dppcon
,
3076 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3077 tm
.year
, tm
.month
, tm
.day
,
3078 tm
.hour
, tm
.min
, tm
.sec
);
3080 wpabuf_put_u8(dppcon
, '}');
3081 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
3082 (const char *) wpabuf_head(dppcon
));
3084 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
3085 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
3086 auth
->conf
->kid
, curve
->jws_alg
);
3087 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
3088 os_strlen(jws_prot_hdr
),
3090 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
3093 if (!signed1
|| !signed2
)
3096 md_ctx
= EVP_MD_CTX_create();
3101 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
3102 auth
->conf
->csign
) != 1) {
3103 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
3104 ERR_error_string(ERR_get_error(), NULL
));
3107 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
3108 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
3109 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
3110 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
3111 ERR_error_string(ERR_get_error(), NULL
));
3114 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
3115 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
3116 ERR_error_string(ERR_get_error(), NULL
));
3119 signature
= os_malloc(signature_len
);
3122 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
3123 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
3124 ERR_error_string(ERR_get_error(), NULL
));
3127 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
3128 signature
, signature_len
);
3129 /* Convert to raw coordinates r,s */
3131 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
3134 ECDSA_SIG_get0(sig
, &r
, &s
);
3135 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
3136 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
3137 curve
->prime_len
) < 0)
3139 signature_len
= 2 * curve
->prime_len
;
3140 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
3141 signature
, signature_len
);
3142 signed3
= (char *) base64_url_encode(signature
, signature_len
,
3148 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
3149 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
3150 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
3154 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
3155 wpabuf_put_str(buf
, signed1
);
3156 wpabuf_put_u8(buf
, '.');
3157 wpabuf_put_str(buf
, signed2
);
3158 wpabuf_put_u8(buf
, '.');
3159 wpabuf_put_str(buf
, signed3
);
3160 wpabuf_put_str(buf
, "\",");
3161 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
3163 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
3166 if (auth
->conf
->csign_expiry
) {
3169 if (os_gmtime(auth
->conf
->csign_expiry
, &tm
) < 0) {
3170 wpa_printf(MSG_DEBUG
,
3171 "DPP: Failed to generate expiry string");
3175 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3176 tm
.year
, tm
.month
, tm
.day
,
3177 tm
.hour
, tm
.min
, tm
.sec
);
3180 wpabuf_put_str(buf
, "}}");
3182 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
3183 wpabuf_head(buf
), wpabuf_len(buf
));
3186 EVP_MD_CTX_destroy(md_ctx
);
3187 ECDSA_SIG_free(sig
);
3192 wpabuf_free(dppcon
);
3195 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
3202 static struct wpabuf
*
3203 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
3204 struct dpp_configuration
*conf
)
3208 buf
= dpp_build_conf_start(auth
, conf
, 1000);
3212 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"psk\",");
3213 if (conf
->passphrase
) {
3214 char pass
[63 * 6 + 1];
3216 if (os_strlen(conf
->passphrase
) > 63) {
3221 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
3222 os_strlen(conf
->passphrase
));
3223 wpabuf_put_str(buf
, "\"pass\":\"");
3224 wpabuf_put_str(buf
, pass
);
3225 wpabuf_put_str(buf
, "\"");
3227 char psk
[2 * sizeof(conf
->psk
) + 1];
3229 wpa_snprintf_hex(psk
, sizeof(psk
),
3230 conf
->psk
, sizeof(conf
->psk
));
3231 wpabuf_put_str(buf
, "\"psk_hex\":\"");
3232 wpabuf_put_str(buf
, psk
);
3233 wpabuf_put_str(buf
, "\"");
3235 wpabuf_put_str(buf
, "}}");
3237 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
3238 wpabuf_head(buf
), wpabuf_len(buf
));
3244 static struct wpabuf
*
3245 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
3247 struct dpp_configuration
*conf
;
3249 #ifdef CONFIG_TESTING_OPTIONS
3250 if (auth
->config_obj_override
) {
3251 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
3252 return wpabuf_alloc_copy(auth
->config_obj_override
,
3253 os_strlen(auth
->config_obj_override
));
3255 #endif /* CONFIG_TESTING_OPTIONS */
3257 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
3259 wpa_printf(MSG_DEBUG
,
3260 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
3266 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
3267 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
3271 static struct wpabuf
*
3272 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
3273 u16 e_nonce_len
, int ap
)
3275 struct wpabuf
*conf
;
3277 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
3281 enum dpp_status_error status
;
3283 conf
= dpp_build_conf_obj(auth
, ap
);
3285 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
3286 wpabuf_head(conf
), wpabuf_len(conf
));
3288 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
3290 /* { E-nonce, configurationObject}ke */
3291 clear_len
= 4 + e_nonce_len
;
3293 clear_len
+= 4 + wpabuf_len(conf
);
3294 clear
= wpabuf_alloc(clear_len
);
3295 msg
= wpabuf_alloc(4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
);
3300 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
3301 wpabuf_put_le16(clear
, e_nonce_len
);
3302 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
3305 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
3306 wpabuf_put_le16(clear
, wpabuf_len(conf
));
3307 wpabuf_put_buf(clear
, conf
);
3313 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
3314 wpabuf_put_le16(msg
, 1);
3315 wpabuf_put_u8(msg
, status
);
3317 addr
[0] = wpabuf_head(msg
);
3318 len
[0] = wpabuf_len(msg
);
3319 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
3321 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3322 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
3323 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
3325 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
3326 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3327 wpabuf_head(clear
), wpabuf_len(clear
),
3328 1, addr
, len
, wrapped
) < 0)
3330 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3331 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
3335 wpa_hexdump_buf(MSG_DEBUG
,
3336 "DPP: Configuration Response attributes", msg
);
3347 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
3350 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
3351 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
3352 u8
*unwrapped
= NULL
;
3353 size_t unwrapped_len
= 0;
3354 struct wpabuf
*resp
= NULL
;
3355 struct json_token
*root
= NULL
, *token
;
3358 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
3359 wpa_printf(MSG_DEBUG
,
3360 "DPP: Invalid attribute in config request");
3364 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3366 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3367 wpa_printf(MSG_DEBUG
,
3368 "DPP: Missing or invalid required Wrapped data attribute");
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
);
3378 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3379 wrapped_data
, wrapped_data_len
,
3380 0, NULL
, NULL
, unwrapped
) < 0) {
3381 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
3384 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3385 unwrapped
, unwrapped_len
);
3387 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3388 wpa_printf(MSG_DEBUG
,
3389 "DPP: Invalid attribute in unwrapped data");
3393 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
3394 DPP_ATTR_ENROLLEE_NONCE
,
3396 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
3397 wpa_printf(MSG_DEBUG
,
3398 "DPP: Missing or invalid Enrollee Nonce attribute");
3401 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
3403 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
3404 DPP_ATTR_CONFIG_ATTR_OBJ
,
3407 wpa_printf(MSG_DEBUG
,
3408 "DPP: Missing or invalid Config Attributes attribute");
3411 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
3412 config_attr
, config_attr_len
);
3414 root
= json_parse((const char *) config_attr
, config_attr_len
);
3416 wpa_printf(MSG_DEBUG
, "DPP: Could not parse Config Attributes");
3420 token
= json_get_member(root
, "name");
3421 if (!token
|| token
->type
!= JSON_STRING
) {
3422 wpa_printf(MSG_DEBUG
, "DPP: No Config Attributes - name");
3425 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
3427 token
= json_get_member(root
, "wi-fi_tech");
3428 if (!token
|| token
->type
!= JSON_STRING
) {
3429 wpa_printf(MSG_DEBUG
, "DPP: No Config Attributes - wi-fi_tech");
3432 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
3433 if (os_strcmp(token
->string
, "infra") != 0) {
3434 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
3439 token
= json_get_member(root
, "netRole");
3440 if (!token
|| token
->type
!= JSON_STRING
) {
3441 wpa_printf(MSG_DEBUG
, "DPP: No Config Attributes - netRole");
3444 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
3445 if (os_strcmp(token
->string
, "sta") == 0) {
3447 } else if (os_strcmp(token
->string
, "ap") == 0) {
3450 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
3455 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
3464 static struct wpabuf
*
3465 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
3466 const u8
*prot_hdr
, u16 prot_hdr_len
,
3467 const EVP_MD
**ret_md
)
3469 struct json_token
*root
, *token
;
3470 struct wpabuf
*kid
= NULL
;
3472 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
3474 wpa_printf(MSG_DEBUG
,
3475 "DPP: JSON parsing failed for JWS Protected Header");
3479 if (root
->type
!= JSON_OBJECT
) {
3480 wpa_printf(MSG_DEBUG
,
3481 "DPP: JWS Protected Header root is not an object");
3485 token
= json_get_member(root
, "typ");
3486 if (!token
|| token
->type
!= JSON_STRING
) {
3487 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
3490 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
3492 if (os_strcmp(token
->string
, "dppCon") != 0) {
3493 wpa_printf(MSG_DEBUG
,
3494 "DPP: Unsupported JWS Protected Header typ=%s",
3499 token
= json_get_member(root
, "alg");
3500 if (!token
|| token
->type
!= JSON_STRING
) {
3501 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
3504 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
3506 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
3507 wpa_printf(MSG_DEBUG
,
3508 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
3509 token
->string
, curve
->jws_alg
);
3512 if (os_strcmp(token
->string
, "ES256") == 0 ||
3513 os_strcmp(token
->string
, "BS256") == 0)
3514 *ret_md
= EVP_sha256();
3515 else if (os_strcmp(token
->string
, "ES384") == 0 ||
3516 os_strcmp(token
->string
, "BS384") == 0)
3517 *ret_md
= EVP_sha384();
3518 else if (os_strcmp(token
->string
, "ES512") == 0 ||
3519 os_strcmp(token
->string
, "BS512") == 0)
3520 *ret_md
= EVP_sha512();
3524 wpa_printf(MSG_DEBUG
,
3525 "DPP: Unsupported JWS Protected Header alg=%s",
3530 kid
= json_get_member_base64url(root
, "kid");
3532 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
3535 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
3544 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
3545 struct json_token
*cred
)
3547 struct json_token
*pass
, *psk_hex
;
3549 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
3551 pass
= json_get_member(cred
, "pass");
3552 psk_hex
= json_get_member(cred
, "psk_hex");
3554 if (pass
&& pass
->type
== JSON_STRING
) {
3555 size_t len
= os_strlen(pass
->string
);
3557 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
3559 if (len
< 8 || len
> 63)
3561 os_strlcpy(auth
->passphrase
, pass
->string
,
3562 sizeof(auth
->passphrase
));
3563 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
3564 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
3565 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
3566 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
3569 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
3570 auth
->psk
, PMK_LEN
);
3573 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
3581 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
3582 const struct dpp_curve_params
**key_curve
)
3584 struct json_token
*token
;
3585 const struct dpp_curve_params
*curve
;
3586 struct wpabuf
*x
= NULL
, *y
= NULL
;
3588 EVP_PKEY
*pkey
= NULL
;
3590 token
= json_get_member(jwk
, "kty");
3591 if (!token
|| token
->type
!= JSON_STRING
) {
3592 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
3595 if (os_strcmp(token
->string
, "EC") != 0) {
3596 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s",
3601 token
= json_get_member(jwk
, "crv");
3602 if (!token
|| token
->type
!= JSON_STRING
) {
3603 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
3606 curve
= dpp_get_curve_jwk_crv(token
->string
);
3608 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
3613 x
= json_get_member_base64url(jwk
, "x");
3615 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
3618 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
3619 if (wpabuf_len(x
) != curve
->prime_len
) {
3620 wpa_printf(MSG_DEBUG
,
3621 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
3622 (unsigned int) wpabuf_len(x
),
3623 (unsigned int) curve
->prime_len
, curve
->name
);
3627 y
= json_get_member_base64url(jwk
, "y");
3629 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
3632 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
3633 if (wpabuf_len(y
) != curve
->prime_len
) {
3634 wpa_printf(MSG_DEBUG
,
3635 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
3636 (unsigned int) wpabuf_len(y
),
3637 (unsigned int) curve
->prime_len
, curve
->name
);
3641 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
3643 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
3647 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
3659 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
3662 unsigned int year
, month
, day
, hour
, min
, sec
;
3666 /* ISO 8601 date and time:
3668 * YYYY-MM-DDTHH:MM:SSZ
3669 * YYYY-MM-DDTHH:MM:SS+03:00
3671 if (os_strlen(timestamp
) < 19) {
3672 wpa_printf(MSG_DEBUG
,
3673 "DPP: Too short timestamp - assume expired key");
3676 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
3677 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
3678 wpa_printf(MSG_DEBUG
,
3679 "DPP: Failed to parse expiration day - assume expired key");
3683 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
3684 wpa_printf(MSG_DEBUG
,
3685 "DPP: Invalid date/time information - assume expired key");
3689 pos
= timestamp
+ 19;
3690 if (*pos
== 'Z' || *pos
== '\0') {
3691 /* In UTC - no need to adjust */
3692 } else if (*pos
== '-' || *pos
== '+') {
3695 /* Adjust local time to UTC */
3696 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
3698 wpa_printf(MSG_DEBUG
,
3699 "DPP: Invalid time zone designator (%s) - assume expired key",
3704 utime
+= 3600 * hour
;
3706 utime
-= 3600 * hour
;
3714 wpa_printf(MSG_DEBUG
,
3715 "DPP: Invalid time zone designator (%s) - assume expired key",
3722 if (os_get_time(&now
) < 0) {
3723 wpa_printf(MSG_DEBUG
,
3724 "DPP: Cannot get current time - assume expired key");
3728 if (now
.sec
> utime
) {
3729 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
3738 static int dpp_parse_connector(struct dpp_authentication
*auth
,
3739 const unsigned char *payload
,
3742 struct json_token
*root
, *groups
, *devices
, *netkey
, *token
;
3744 EVP_PKEY
*key
= NULL
;
3745 const struct dpp_curve_params
*curve
;
3746 unsigned int rules
= 0;
3748 root
= json_parse((const char *) payload
, payload_len
);
3750 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
3754 groups
= json_get_member(root
, "groups");
3755 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
3756 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
3759 for (token
= groups
->child
; token
; token
= token
->sibling
) {
3760 struct json_token
*id
, *role
;
3762 id
= json_get_member(token
, "groupId");
3763 if (!id
|| id
->type
!= JSON_STRING
) {
3764 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
3768 role
= json_get_member(token
, "netRole");
3769 if (!role
|| role
->type
!= JSON_STRING
) {
3770 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
3773 wpa_printf(MSG_DEBUG
,
3774 "DPP: connector group: groupId='%s' netRole='%s'",
3775 id
->string
, role
->string
);
3780 devices
= json_get_member(root
, "devices");
3781 if (!devices
|| devices
->type
!= JSON_ARRAY
) {
3782 wpa_printf(MSG_DEBUG
, "DPP: No devices array found");
3785 for (token
= devices
->child
; token
; token
= token
->sibling
) {
3787 struct json_token
*role
;
3789 id
= json_get_member_base64url(token
, "deviceId");
3791 wpa_printf(MSG_DEBUG
,
3792 "DPP: Missing or invalid deviceId string");
3795 wpa_hexdump_buf(MSG_DEBUG
, "DPP: deviceId", id
);
3796 if (wpabuf_len(id
) != SHA256_MAC_LEN
) {
3797 wpa_printf(MSG_DEBUG
,
3798 "DPP: Unexpected deviceId length");
3804 role
= json_get_member(token
, "netRole");
3805 if (!role
|| role
->type
!= JSON_STRING
) {
3806 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
3809 wpa_printf(MSG_DEBUG
, "DPP: connector device netRole='%s'",
3816 wpa_printf(MSG_DEBUG
,
3817 "DPP: Connector includes no groups or devices");
3821 token
= json_get_member(root
, "expiry");
3822 if (!token
|| token
->type
!= JSON_STRING
) {
3823 wpa_printf(MSG_DEBUG
,
3824 "DPP: No expiry string found - connector does not expire");
3826 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
3827 if (dpp_key_expired(token
->string
,
3828 &auth
->net_access_key_expiry
)) {
3829 wpa_printf(MSG_DEBUG
,
3830 "DPP: Connector (netAccessKey) has expired");
3835 netkey
= json_get_member(root
, "netAccessKey");
3836 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
3837 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
3841 key
= dpp_parse_jwk(netkey
, &curve
);
3844 dpp_debug_print_key("DPP: Received netAccessKey", key
);
3846 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
3847 wpa_printf(MSG_DEBUG
,
3848 "DPP: netAccessKey in connector does not match own protocol key");
3849 #ifdef CONFIG_TESTING_OPTIONS
3850 if (auth
->ignore_netaccesskey_mismatch
) {
3851 wpa_printf(MSG_DEBUG
,
3852 "DPP: TESTING - skip netAccessKey mismatch");
3856 #else /* CONFIG_TESTING_OPTIONS */
3858 #endif /* CONFIG_TESTING_OPTIONS */
3869 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
3871 struct wpabuf
*uncomp
;
3873 u8 hash
[SHA256_MAC_LEN
];
3877 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
3879 uncomp
= dpp_get_pubkey_point(pub
, 1);
3882 addr
[0] = wpabuf_head(uncomp
);
3883 len
[0] = wpabuf_len(uncomp
);
3884 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
3886 res
= sha256_vector(1, addr
, len
, hash
);
3887 wpabuf_free(uncomp
);
3890 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
3891 wpa_printf(MSG_DEBUG
,
3892 "DPP: Received hash value does not match calculated public key hash value");
3893 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
3894 hash
, SHA256_MAC_LEN
);
3901 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
3903 unsigned char *der
= NULL
;
3906 der_len
= i2d_PUBKEY(csign
, &der
);
3909 wpabuf_free(auth
->c_sign_key
);
3910 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
3915 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
3917 unsigned char *der
= NULL
;
3921 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
3925 der_len
= i2d_ECPrivateKey(eckey
, &der
);
3930 wpabuf_free(auth
->net_access_key
);
3931 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
3937 struct dpp_signed_connector_info
{
3938 unsigned char *payload
;
3943 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
3944 EVP_PKEY
*csign_pub
, const char *connector
)
3947 const char *pos
, *end
, *signed_start
, *signed_end
;
3948 struct wpabuf
*kid
= NULL
;
3949 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
3950 size_t prot_hdr_len
= 0, signature_len
= 0;
3951 const EVP_MD
*sign_md
= NULL
;
3952 unsigned char *der
= NULL
;
3955 EVP_MD_CTX
*md_ctx
= NULL
;
3956 ECDSA_SIG
*sig
= NULL
;
3957 BIGNUM
*r
= NULL
, *s
= NULL
;
3958 const struct dpp_curve_params
*curve
;
3960 const EC_GROUP
*group
;
3963 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
3966 group
= EC_KEY_get0_group(eckey
);
3969 nid
= EC_GROUP_get_curve_name(group
);
3970 curve
= dpp_get_curve_nid(nid
);
3973 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
3974 os_memset(info
, 0, sizeof(*info
));
3976 signed_start
= pos
= connector
;
3977 end
= os_strchr(pos
, '.');
3979 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
3982 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
3983 end
- pos
, &prot_hdr_len
);
3985 wpa_printf(MSG_DEBUG
,
3986 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
3989 wpa_hexdump_ascii(MSG_DEBUG
,
3990 "DPP: signedConnector - JWS Protected Header",
3991 prot_hdr
, prot_hdr_len
);
3992 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
3995 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
3996 wpa_printf(MSG_DEBUG
,
3997 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
3998 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
4003 end
= os_strchr(pos
, '.');
4005 wpa_printf(MSG_DEBUG
,
4006 "DPP: Missing dot(2) in signedConnector");
4009 signed_end
= end
- 1;
4010 info
->payload
= base64_url_decode((const unsigned char *) pos
,
4011 end
- pos
, &info
->payload_len
);
4012 if (!info
->payload
) {
4013 wpa_printf(MSG_DEBUG
,
4014 "DPP: Failed to base64url decode signedConnector JWS Payload");
4017 wpa_hexdump_ascii(MSG_DEBUG
,
4018 "DPP: signedConnector - JWS Payload",
4019 info
->payload
, info
->payload_len
);
4021 signature
= base64_url_decode((const unsigned char *) pos
,
4022 os_strlen(pos
), &signature_len
);
4024 wpa_printf(MSG_DEBUG
,
4025 "DPP: Failed to base64url decode signedConnector signature");
4028 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
4029 signature
, signature_len
);
4031 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0)
4034 if (signature_len
& 0x01) {
4035 wpa_printf(MSG_DEBUG
,
4036 "DPP: Unexpected signedConnector signature length (%d)",
4037 (int) signature_len
);
4041 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
4042 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
4043 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
4044 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
4045 sig
= ECDSA_SIG_new();
4046 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
4051 der_len
= i2d_ECDSA_SIG(sig
, &der
);
4053 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
4056 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
4057 md_ctx
= EVP_MD_CTX_create();
4062 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
4063 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
4064 ERR_error_string(ERR_get_error(), NULL
));
4067 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
4068 signed_end
- signed_start
+ 1) != 1) {
4069 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
4070 ERR_error_string(ERR_get_error(), NULL
));
4073 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
4075 wpa_printf(MSG_DEBUG
,
4076 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
4077 res
, ERR_error_string(ERR_get_error(), NULL
));
4084 EVP_MD_CTX_destroy(md_ctx
);
4088 ECDSA_SIG_free(sig
);
4096 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
4097 struct json_token
*cred
)
4099 struct dpp_signed_connector_info info
;
4100 struct json_token
*token
, *csign
;
4102 EVP_PKEY
*csign_pub
= NULL
;
4103 const struct dpp_curve_params
*key_curve
= NULL
;
4104 const char *signed_connector
;
4106 os_memset(&info
, 0, sizeof(info
));
4108 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
4110 csign
= json_get_member(cred
, "csign");
4111 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
4112 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
4116 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
4118 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
4121 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
4123 token
= json_get_member(cred
, "expiry");
4124 if (!token
|| token
->type
!= JSON_STRING
) {
4125 wpa_printf(MSG_DEBUG
,
4126 "DPP: No expiry string found - C-sign-key does not expire");
4128 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
4129 if (dpp_key_expired(token
->string
, &auth
->c_sign_key_expiry
)) {
4130 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key has expired");
4135 token
= json_get_member(cred
, "signedConnector");
4136 if (!token
|| token
->type
!= JSON_STRING
) {
4137 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
4140 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
4141 token
->string
, os_strlen(token
->string
));
4142 signed_connector
= token
->string
;
4144 if (os_strchr(signed_connector
, '"') ||
4145 os_strchr(signed_connector
, '\n')) {
4146 wpa_printf(MSG_DEBUG
,
4147 "DPP: Unexpected character in signedConnector");
4151 if (dpp_process_signed_connector(&info
, csign_pub
,
4152 signed_connector
) < 0)
4155 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
4156 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
4160 os_free(auth
->connector
);
4161 auth
->connector
= os_strdup(signed_connector
);
4163 dpp_copy_csign(auth
, csign_pub
);
4164 dpp_copy_netaccesskey(auth
);
4168 EVP_PKEY_free(csign_pub
);
4169 os_free(info
.payload
);
4174 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
4175 const u8
*conf_obj
, u16 conf_obj_len
)
4178 struct json_token
*root
, *token
, *discovery
, *cred
;
4180 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
4183 if (root
->type
!= JSON_OBJECT
) {
4184 wpa_printf(MSG_DEBUG
, "DPP: JSON root is not an object");
4188 token
= json_get_member(root
, "wi-fi_tech");
4189 if (!token
|| token
->type
!= JSON_STRING
) {
4190 wpa_printf(MSG_DEBUG
, "DPP: No wi-fi_tech string value found");
4193 if (os_strcmp(token
->string
, "infra") != 0) {
4194 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
4199 discovery
= json_get_member(root
, "discovery");
4200 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
4201 wpa_printf(MSG_DEBUG
, "DPP: No discovery object in JSON");
4205 token
= json_get_member(discovery
, "ssid");
4206 if (!token
|| token
->type
!= JSON_STRING
) {
4207 wpa_printf(MSG_DEBUG
,
4208 "DPP: No discovery::ssid string value found");
4211 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
4212 token
->string
, os_strlen(token
->string
));
4213 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
4214 wpa_printf(MSG_DEBUG
,
4215 "DPP: Too long discovery::ssid string value");
4218 auth
->ssid_len
= os_strlen(token
->string
);
4219 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
4221 cred
= json_get_member(root
, "cred");
4222 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
4223 wpa_printf(MSG_DEBUG
, "DPP: No cred object in JSON");
4227 token
= json_get_member(cred
, "akm");
4228 if (!token
|| token
->type
!= JSON_STRING
) {
4229 wpa_printf(MSG_DEBUG
,
4230 "DPP: No cred::akm string value found");
4233 if (os_strcmp(token
->string
, "psk") == 0) {
4234 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
4236 } else if (os_strcmp(token
->string
, "dpp") == 0) {
4237 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
4240 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
4245 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
4253 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
4254 const struct wpabuf
*resp
)
4256 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
4257 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
4260 u8
*unwrapped
= NULL
;
4261 size_t unwrapped_len
= 0;
4264 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
4265 wpa_printf(MSG_DEBUG
,
4266 "DPP: Invalid attribute in config response");
4270 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
4271 DPP_ATTR_WRAPPED_DATA
,
4273 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4274 wpa_printf(MSG_DEBUG
,
4275 "DPP: Missing or invalid required Wrapped data attribute");
4279 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4280 wrapped_data
, wrapped_data_len
);
4281 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4282 unwrapped
= os_malloc(unwrapped_len
);
4286 addr
[0] = wpabuf_head(resp
);
4287 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
4288 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4290 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4291 wrapped_data
, wrapped_data_len
,
4292 1, addr
, len
, unwrapped
) < 0) {
4293 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
4296 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4297 unwrapped
, unwrapped_len
);
4299 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4300 wpa_printf(MSG_DEBUG
,
4301 "DPP: Invalid attribute in unwrapped data");
4305 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4306 DPP_ATTR_ENROLLEE_NONCE
,
4308 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4309 wpa_printf(MSG_DEBUG
,
4310 "DPP: Missing or invalid Enrollee Nonce attribute");
4313 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4314 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
4315 wpa_printf(MSG_DEBUG
, "Enrollee Nonce mismatch");
4319 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
4320 DPP_ATTR_STATUS
, &status_len
);
4321 if (!status
|| status_len
< 1) {
4322 wpa_printf(MSG_DEBUG
,
4323 "DPP: Missing or invalid required DPP Status attribute");
4326 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4327 if (status
[0] != DPP_STATUS_OK
) {
4328 wpa_printf(MSG_DEBUG
, "DPP: Configuration failed");
4332 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
4333 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
4335 wpa_printf(MSG_DEBUG
,
4336 "DPP: Missing required Configuration Object attribute");
4339 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4340 conf_obj
, conf_obj_len
);
4341 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
4352 void dpp_configurator_free(struct dpp_configurator
*conf
)
4356 EVP_PKEY_free(conf
->csign
);
4362 struct dpp_configurator
*
4363 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
4366 struct dpp_configurator
*conf
;
4367 struct wpabuf
*csign_pub
= NULL
;
4368 u8 kid_hash
[SHA256_MAC_LEN
];
4372 conf
= os_zalloc(sizeof(*conf
));
4377 conf
->curve
= &dpp_curves
[0];
4379 conf
->curve
= dpp_get_curve_name(curve
);
4381 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
4387 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
4390 conf
->csign
= dpp_gen_keypair(conf
->curve
);
4395 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
4397 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
4401 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
4402 addr
[0] = wpabuf_head(csign_pub
);
4403 len
[0] = wpabuf_len(csign_pub
);
4404 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
4405 wpa_printf(MSG_DEBUG
,
4406 "DPP: Failed to derive kid for C-sign-key");
4410 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
4415 wpabuf_free(csign_pub
);
4418 dpp_configurator_free(conf
);
4424 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
4427 struct wpabuf
*conf_obj
;
4431 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
4436 auth
->curve
= &dpp_curves
[0];
4438 auth
->curve
= dpp_get_curve_name(curve
);
4440 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
4445 wpa_printf(MSG_DEBUG
,
4446 "DPP: Building own configuration/connector with curve %s",
4449 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
4450 if (!auth
->own_protocol_key
)
4452 dpp_copy_netaccesskey(auth
);
4453 auth
->peer_protocol_key
= auth
->own_protocol_key
;
4454 dpp_copy_csign(auth
, auth
->conf
->csign
);
4456 conf_obj
= dpp_build_conf_obj(auth
, 0);
4459 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
4460 wpabuf_len(conf_obj
));
4462 wpabuf_free(conf_obj
);
4463 auth
->peer_protocol_key
= NULL
;
4468 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
4470 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
4471 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
4475 static int dpp_connector_compatible_group(struct json_token
*root
,
4476 const char *group_id
,
4477 const char *net_role
)
4479 struct json_token
*groups
, *token
;
4481 groups
= json_get_member(root
, "groups");
4482 if (!groups
|| groups
->type
!= JSON_ARRAY
)
4485 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4486 struct json_token
*id
, *role
;
4488 id
= json_get_member(token
, "groupId");
4489 if (!id
|| id
->type
!= JSON_STRING
)
4492 role
= json_get_member(token
, "netRole");
4493 if (!role
|| role
->type
!= JSON_STRING
)
4496 if (os_strcmp(id
->string
, "*") != 0 &&
4497 os_strcmp(group_id
, "*") != 0 &&
4498 os_strcmp(id
->string
, group_id
) != 0)
4501 if (dpp_compatible_netrole(role
->string
, net_role
))
4509 static int dpp_connector_match_groups(struct json_token
*own_root
,
4510 struct json_token
*peer_root
)
4512 struct json_token
*groups
, *token
;
4514 groups
= json_get_member(peer_root
, "groups");
4515 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
4516 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
4520 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4521 struct json_token
*id
, *role
;
4523 id
= json_get_member(token
, "groupId");
4524 if (!id
|| id
->type
!= JSON_STRING
) {
4525 wpa_printf(MSG_DEBUG
,
4526 "DPP: Missing peer groupId string");
4530 role
= json_get_member(token
, "netRole");
4531 if (!role
|| role
->type
!= JSON_STRING
) {
4532 wpa_printf(MSG_DEBUG
,
4533 "DPP: Missing peer groups::netRole string");
4536 wpa_printf(MSG_DEBUG
,
4537 "DPP: peer connector group: groupId='%s' netRole='%s'",
4538 id
->string
, role
->string
);
4539 if (dpp_connector_compatible_group(own_root
, id
->string
,
4541 wpa_printf(MSG_DEBUG
,
4542 "DPP: Compatible group/netRole in own connector");
4551 static int dpp_connector_compatible_device(struct json_token
*root
,
4552 const char *device_id
,
4553 const char *net_role
)
4555 struct json_token
*groups
, *token
;
4557 groups
= json_get_member(root
, "devices");
4558 if (!groups
|| groups
->type
!= JSON_ARRAY
)
4561 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4562 struct json_token
*id
, *role
;
4564 id
= json_get_member(token
, "deviceId");
4565 if (!id
|| id
->type
!= JSON_STRING
)
4568 role
= json_get_member(token
, "netRole");
4569 if (!role
|| role
->type
!= JSON_STRING
)
4572 if (os_strcmp(id
->string
, device_id
) != 0)
4575 if (dpp_compatible_netrole(role
->string
, net_role
))
4583 static int dpp_connector_match_devices(struct json_token
*own_root
,
4584 struct json_token
*peer_root
,
4585 const char *own_deviceid
)
4587 struct json_token
*devices
, *token
;
4589 devices
= json_get_member(peer_root
, "devices");
4590 if (!devices
|| devices
->type
!= JSON_ARRAY
) {
4591 wpa_printf(MSG_DEBUG
, "DPP: No peer devices array found");
4595 for (token
= devices
->child
; token
; token
= token
->sibling
) {
4596 struct json_token
*id
, *role
;
4598 id
= json_get_member(token
, "deviceId");
4599 if (!id
|| id
->type
!= JSON_STRING
) {
4600 wpa_printf(MSG_DEBUG
,
4601 "DPP: Missing or invalid deviceId string");
4605 role
= json_get_member(token
, "netRole");
4606 if (!role
|| role
->type
!= JSON_STRING
) {
4607 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
4610 wpa_printf(MSG_DEBUG
,
4611 "DPP: connector device deviceId='%s' netRole='%s'",
4612 id
->string
, role
->string
);
4613 if (os_strcmp(id
->string
, own_deviceid
) != 0)
4616 wpa_printf(MSG_DEBUG
,
4617 "DPP: Listed deviceId matches own deviceId");
4618 /* TODO: Is this next step required? */
4619 if (dpp_connector_compatible_device(own_root
, id
->string
,
4621 wpa_printf(MSG_DEBUG
,
4622 "DPP: Compatible device/netRole in own connector");
4625 /* TODO: For now, accept this for interop testing purposes based
4626 * on a simple match of deviceId while ignoring netRole. Once
4627 * the spec is clearer on the expected behavior, either this
4628 * comment or the following return 1 statement needs to be
4638 static int dpp_connector_match(struct json_token
*own_root
,
4639 struct json_token
*peer_root
,
4640 const char *own_deviceid
)
4642 return dpp_connector_match_groups(own_root
, peer_root
) ||
4643 dpp_connector_match_devices(own_root
, peer_root
, own_deviceid
);
4647 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
4648 unsigned int hash_len
)
4650 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
4651 const char *info
= "DPP PMK";
4654 /* PMK = HKDF(<>, "DPP PMK", N.x) */
4656 /* HKDF-Extract(<>, N.x) */
4657 os_memset(salt
, 0, hash_len
);
4658 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
4660 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
4663 /* HKDF-Expand(PRK, info, L) */
4664 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
4665 os_memset(prk
, 0, hash_len
);
4669 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
4675 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
4676 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
4678 struct wpabuf
*nkx
, *pkx
;
4682 u8 hash
[DPP_MAX_HASH_LEN
];
4684 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
4685 nkx
= dpp_get_pubkey_point(own_key
, 0);
4686 pkx
= dpp_get_pubkey_point(peer_key
, 0);
4689 addr
[0] = wpabuf_head(nkx
);
4690 len
[0] = wpabuf_len(nkx
) / 2;
4691 addr
[1] = wpabuf_head(pkx
);
4692 len
[1] = wpabuf_len(pkx
) / 2;
4693 if (len
[0] != len
[1])
4695 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
4696 addr
[0] = wpabuf_head(pkx
);
4697 addr
[1] = wpabuf_head(nkx
);
4699 wpa_printf(MSG_DEBUG
, "DPP: PMKID H=SHA%u",
4700 (unsigned int) curve
->hash_len
* 8);
4701 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
4702 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
4703 res
= dpp_hash_vector(curve
, 2, addr
, len
, hash
);
4706 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output",
4707 hash
, curve
->hash_len
);
4708 os_memcpy(pmkid
, hash
, PMKID_LEN
);
4709 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
4718 static int dpp_netkey_hash(EVP_PKEY
*key
, u8
*hash
)
4721 unsigned char *der
= NULL
;
4726 eckey
= EVP_PKEY_get1_EC_KEY(key
);
4729 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_COMPRESSED
);
4730 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
4736 ret
= sha256_vector(1, addr
, len
, hash
);
4742 int dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
4743 const u8
*net_access_key
, size_t net_access_key_len
,
4744 const u8
*csign_key
, size_t csign_key_len
,
4745 const u8
*peer_connector
, size_t peer_connector_len
,
4748 struct json_token
*root
= NULL
, *netkey
, *token
;
4749 struct json_token
*own_root
= NULL
;
4751 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
4752 struct wpabuf
*own_key_pub
= NULL
;
4753 char *own_deviceid
= NULL
;
4754 const struct dpp_curve_params
*curve
, *own_curve
;
4755 struct dpp_signed_connector_info info
;
4756 const unsigned char *p
;
4757 EVP_PKEY
*csign
= NULL
;
4758 char *signed_connector
= NULL
;
4759 const char *pos
, *end
;
4760 unsigned char *own_conn
= NULL
;
4761 size_t own_conn_len
;
4762 EVP_PKEY_CTX
*ctx
= NULL
;
4764 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
4765 u8 hash
[SHA256_MAC_LEN
];
4769 os_memset(intro
, 0, sizeof(*intro
));
4770 os_memset(&info
, 0, sizeof(info
));
4775 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
4777 wpa_printf(MSG_ERROR
,
4778 "DPP: Failed to parse local C-sign-key information");
4782 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
4783 net_access_key_len
);
4785 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
4788 /* deviceId = SHA256(ANSI X9.63 uncompressed netAccessKey) */
4789 own_key_pub
= dpp_get_pubkey_point(own_key
, 1);
4792 wpa_hexdump_buf(MSG_DEBUG
,
4793 "DPP: ANSI X9.63 uncompressed public key of own netAccessKey",
4795 addr
[0] = wpabuf_head(own_key_pub
);
4796 len
[0] = wpabuf_len(own_key_pub
);
4797 if (sha256_vector(1, addr
, len
, hash
) < 0)
4799 wpa_hexdump(MSG_DEBUG
,
4800 "DPP: SHA256 hash of ANSI X9.63 uncompressed form",
4801 hash
, SHA256_MAC_LEN
);
4803 own_deviceid
= (char *) base64_url_encode(hash
, sizeof(hash
), NULL
, 0);
4806 wpa_printf(MSG_DEBUG
,
4807 "DPP: Own deviceId (base64url encoded hash value): %s",
4810 pos
= os_strchr(own_connector
, '.');
4812 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
4816 end
= os_strchr(pos
, '.');
4818 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
4821 own_conn
= base64_url_decode((const unsigned char *) pos
,
4822 end
- pos
, &own_conn_len
);
4824 wpa_printf(MSG_DEBUG
,
4825 "DPP: Failed to base64url decode own signedConnector JWS Payload");
4829 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
4831 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
4835 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
4836 peer_connector
, peer_connector_len
);
4837 signed_connector
= os_malloc(peer_connector_len
+ 1);
4838 if (!signed_connector
)
4840 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
4841 signed_connector
[peer_connector_len
] = '\0';
4843 if (dpp_process_signed_connector(&info
, csign
, signed_connector
) < 0)
4846 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
4848 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
4852 if (!dpp_connector_match(own_root
, root
, own_deviceid
)) {
4853 wpa_printf(MSG_DEBUG
,
4854 "DPP: Peer connector does not include compatible group/device netrole with own connector");
4858 token
= json_get_member(root
, "expiry");
4859 if (!token
|| token
->type
!= JSON_STRING
) {
4860 wpa_printf(MSG_DEBUG
,
4861 "DPP: No expiry string found - connector does not expire");
4863 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
4864 if (dpp_key_expired(token
->string
, expiry
)) {
4865 wpa_printf(MSG_DEBUG
,
4866 "DPP: Connector (netAccessKey) has expired");
4871 netkey
= json_get_member(root
, "netAccessKey");
4872 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
4873 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
4877 peer_key
= dpp_parse_jwk(netkey
, &curve
);
4880 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
4882 if (own_curve
!= curve
) {
4883 wpa_printf(MSG_DEBUG
,
4884 "DPP: Mismatching netAccessKey curves (%s != %s)",
4885 own_curve
->name
, curve
->name
);
4889 /* ECDH: N = nk * PK */
4890 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
4892 EVP_PKEY_derive_init(ctx
) != 1 ||
4893 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
4894 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
4895 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
4896 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
4897 wpa_printf(MSG_ERROR
,
4898 "DPP: Failed to derive ECDH shared secret: %s",
4899 ERR_error_string(ERR_get_error(), NULL
));
4903 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
4906 /* PMK = HKDF(<>, "DPP PMK", N.x) */
4907 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
4908 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
4911 intro
->pmk_len
= curve
->hash_len
;
4913 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
4914 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
4915 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
4919 if (dpp_netkey_hash(own_key
, intro
->nk_hash
) < 0 ||
4920 dpp_netkey_hash(peer_key
, intro
->pk_hash
) < 0) {
4921 wpa_printf(MSG_ERROR
, "DPP: Failed to derive NK/PK hash");
4928 os_memset(intro
, 0, sizeof(*intro
));
4929 os_memset(Nx
, 0, sizeof(Nx
));
4930 EVP_PKEY_CTX_free(ctx
);
4932 os_free(signed_connector
);
4933 os_free(info
.payload
);
4934 EVP_PKEY_free(own_key
);
4935 wpabuf_free(own_key_pub
);
4936 os_free(own_deviceid
);
4937 EVP_PKEY_free(peer_key
);
4938 EVP_PKEY_free(csign
);
4940 json_free(own_root
);
4945 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
4949 size_t len
= curve
->prime_len
;
4952 switch (curve
->ike_group
) {
4954 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
4955 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
4958 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
4959 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
4962 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
4963 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
4966 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
4967 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
4970 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
4971 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
4974 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
4975 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
4981 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
4984 return dpp_set_pubkey_point_group(group
, x
, y
, len
);
4988 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
4989 const u8
*mac_init
, const char *code
,
4990 const char *identifier
, BN_CTX
*bnctx
,
4991 const EC_GROUP
**ret_group
)
4993 u8 hash
[DPP_MAX_HASH_LEN
];
4996 unsigned int num_elem
= 0;
4997 EC_POINT
*Qi
= NULL
;
4998 EVP_PKEY
*Pi
= NULL
;
4999 EC_KEY
*Pi_ec
= NULL
;
5000 const EC_POINT
*Pi_point
;
5001 BIGNUM
*hash_bn
= NULL
;
5002 const EC_GROUP
*group
= NULL
;
5003 EC_GROUP
*group2
= NULL
;
5005 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5007 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
5008 addr
[num_elem
] = mac_init
;
5009 len
[num_elem
] = ETH_ALEN
;
5012 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5014 addr
[num_elem
] = (const u8
*) identifier
;
5015 len
[num_elem
] = os_strlen(identifier
);
5018 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5019 addr
[num_elem
] = (const u8
*) code
;
5020 len
[num_elem
] = os_strlen(code
);
5022 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5024 wpa_hexdump_key(MSG_DEBUG
,
5025 "DPP: H(MAC-Initiator | [identifier |] code)",
5026 hash
, curve
->hash_len
);
5027 Pi
= dpp_pkex_get_role_elem(curve
, 1);
5030 dpp_debug_print_key("DPP: Pi", Pi
);
5031 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
5034 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
5036 group
= EC_KEY_get0_group(Pi_ec
);
5039 group2
= EC_GROUP_dup(group
);
5042 Qi
= EC_POINT_new(group2
);
5044 EC_GROUP_free(group2
);
5047 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5049 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
5054 BN_clear_free(hash_bn
);
5056 *ret_group
= group2
;
5065 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
5066 const u8
*mac_resp
, const char *code
,
5067 const char *identifier
, BN_CTX
*bnctx
,
5068 const EC_GROUP
**ret_group
)
5070 u8 hash
[DPP_MAX_HASH_LEN
];
5073 unsigned int num_elem
= 0;
5074 EC_POINT
*Qr
= NULL
;
5075 EVP_PKEY
*Pr
= NULL
;
5076 EC_KEY
*Pr_ec
= NULL
;
5077 const EC_POINT
*Pr_point
;
5078 BIGNUM
*hash_bn
= NULL
;
5079 const EC_GROUP
*group
= NULL
;
5080 EC_GROUP
*group2
= NULL
;
5082 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5084 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
5085 addr
[num_elem
] = mac_resp
;
5086 len
[num_elem
] = ETH_ALEN
;
5089 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
5091 addr
[num_elem
] = (const u8
*) identifier
;
5092 len
[num_elem
] = os_strlen(identifier
);
5095 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
5096 addr
[num_elem
] = (const u8
*) code
;
5097 len
[num_elem
] = os_strlen(code
);
5099 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
5101 wpa_hexdump_key(MSG_DEBUG
,
5102 "DPP: H(MAC-Responder | [identifier |] code)",
5103 hash
, curve
->hash_len
);
5104 Pr
= dpp_pkex_get_role_elem(curve
, 0);
5107 dpp_debug_print_key("DPP: Pr", Pr
);
5108 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
5111 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
5113 group
= EC_KEY_get0_group(Pr_ec
);
5116 group2
= EC_GROUP_dup(group
);
5119 Qr
= EC_POINT_new(group2
);
5121 EC_GROUP_free(group2
);
5124 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
5126 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
5131 BN_clear_free(hash_bn
);
5133 *ret_group
= group2
;
5142 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
5144 EC_KEY
*X_ec
= NULL
;
5145 const EC_POINT
*X_point
;
5146 BN_CTX
*bnctx
= NULL
;
5147 const EC_GROUP
*group
;
5148 EC_POINT
*Qi
= NULL
, *M
= NULL
;
5149 struct wpabuf
*M_buf
= NULL
;
5150 BIGNUM
*Mx
= NULL
, *My
= NULL
;
5151 struct wpabuf
*msg
= NULL
;
5153 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5154 int num_bytes
, offset
;
5156 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
5158 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5159 bnctx
= BN_CTX_new();
5162 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
5163 pkex
->identifier
, bnctx
, &group
);
5167 /* Generate a random ephemeral keypair x/X */
5168 pkex
->x
= dpp_gen_keypair(curve
);
5173 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
5176 X_point
= EC_KEY_get0_public_key(X_ec
);
5179 M
= EC_POINT_new(group
);
5182 if (!M
|| !Mx
|| !My
||
5183 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
5184 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
5187 /* Initiator -> Responder: group, [identifier,] M */
5189 if (pkex
->identifier
)
5190 attr_len
+= 4 + os_strlen(pkex
->identifier
);
5191 attr_len
+= 4 + 2 * curve
->prime_len
;
5192 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
5196 /* Finite Cyclic Group attribute */
5197 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
5198 wpabuf_put_le16(msg
, 2);
5199 wpabuf_put_le16(msg
, curve
->ike_group
);
5201 /* Code Identifier attribute */
5202 if (pkex
->identifier
) {
5203 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
5204 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
5205 wpabuf_put_str(msg
, pkex
->identifier
);
5208 /* M in Encrypted Key attribute */
5209 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
5210 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
5212 num_bytes
= BN_num_bytes(Mx
);
5213 if ((size_t) num_bytes
> curve
->prime_len
)
5215 if (curve
->prime_len
> (size_t) num_bytes
)
5216 offset
= curve
->prime_len
- num_bytes
;
5219 os_memset(wpabuf_put(msg
, offset
), 0, offset
);
5220 BN_bn2bin(Mx
, wpabuf_put(msg
, num_bytes
));
5221 os_memset(pkex
->Mx
, 0, offset
);
5222 BN_bn2bin(Mx
, pkex
->Mx
+ offset
);
5224 num_bytes
= BN_num_bytes(My
);
5225 if ((size_t) num_bytes
> curve
->prime_len
)
5227 if (curve
->prime_len
> (size_t) num_bytes
)
5228 offset
= curve
->prime_len
- num_bytes
;
5231 os_memset(wpabuf_put(msg
, offset
), 0, offset
);
5232 BN_bn2bin(My
, wpabuf_put(msg
, num_bytes
));
5244 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
5251 struct dpp_pkex
* dpp_pkex_init(struct dpp_bootstrap_info
*bi
,
5253 const char *identifier
,
5256 struct dpp_pkex
*pkex
;
5258 pkex
= os_zalloc(sizeof(*pkex
));
5261 pkex
->initiator
= 1;
5263 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
5265 pkex
->identifier
= os_strdup(identifier
);
5266 if (!pkex
->identifier
)
5269 pkex
->code
= os_strdup(code
);
5272 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
5273 if (!pkex
->exchange_req
)
5277 dpp_pkex_free(pkex
);
5282 struct dpp_pkex
* dpp_pkex_rx_exchange_req(struct dpp_bootstrap_info
*bi
,
5285 const char *identifier
,
5287 const u8
*buf
, size_t len
)
5289 const u8
*attr_group
, *attr_id
, *attr_key
;
5290 u16 attr_group_len
, attr_id_len
, attr_key_len
;
5291 const struct dpp_curve_params
*curve
= bi
->curve
;
5293 struct dpp_pkex
*pkex
= NULL
;
5294 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
5295 BN_CTX
*bnctx
= NULL
;
5296 const EC_GROUP
*group
;
5297 BIGNUM
*Mx
= NULL
, *My
= NULL
;
5298 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
5299 const EC_POINT
*Y_point
;
5300 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
5301 struct wpabuf
*msg
= NULL
;
5303 int num_bytes
, offset
;
5305 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
5307 if (!attr_id
&& identifier
) {
5308 wpa_printf(MSG_DEBUG
,
5309 "DPP: No PKEX code identifier received, but expected one");
5312 if (attr_id
&& identifier
&&
5313 (os_strlen(identifier
) != attr_id_len
||
5314 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
5315 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
5319 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
5321 if (!attr_group
|| attr_group_len
!= 2) {
5322 wpa_printf(MSG_DEBUG
,
5323 "DPP: Missing or invalid Finite Cyclic Group attribute");
5326 ike_group
= WPA_GET_LE16(attr_group
);
5327 if (ike_group
!= curve
->ike_group
) {
5328 wpa_printf(MSG_DEBUG
,
5329 "DPP: Mismatching PKEX curve: peer=%u own=%u",
5330 ike_group
, curve
->ike_group
);
5331 /* TODO: error response with suggested curve:
5332 * DPP Status, group */
5336 /* M in Encrypted Key attribute */
5337 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
5339 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
5340 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
5341 wpa_printf(MSG_DEBUG
, "DPP: Missing Encrypted Key attribute");
5345 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5346 bnctx
= BN_CTX_new();
5349 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
5355 X
= EC_POINT_new(group
);
5356 M
= EC_POINT_new(group
);
5357 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
5358 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
5359 if (!X
|| !M
|| !Mx
|| !My
||
5360 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
5361 EC_POINT_is_at_infinity(group
, M
) ||
5362 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
5363 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
5364 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
5365 EC_POINT_is_at_infinity(group
, X
) ||
5366 !EC_POINT_is_on_curve(group
, X
, bnctx
))
5369 pkex
= os_zalloc(sizeof(*pkex
));
5373 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
5374 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
5376 pkex
->identifier
= os_strdup(identifier
);
5377 if (!pkex
->identifier
)
5380 pkex
->code
= os_strdup(code
);
5384 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
5386 X_ec
= EC_KEY_new();
5388 EC_KEY_set_group(X_ec
, group
) != 1 ||
5389 EC_KEY_set_public_key(X_ec
, X
) != 1)
5391 pkex
->x
= EVP_PKEY_new();
5393 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
5396 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5397 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
5401 /* Generate a random ephemeral keypair y/Y */
5402 pkex
->y
= dpp_gen_keypair(curve
);
5407 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
5410 Y_point
= EC_KEY_get0_public_key(Y_ec
);
5413 N
= EC_POINT_new(group
);
5416 if (!N
|| !Nx
|| !Ny
||
5417 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
5418 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
5421 /* Initiator -> Responder: DPP Status, [identifier,] N */
5424 attr_len
+= 4 + os_strlen(identifier
);
5425 attr_len
+= 4 + 2 * curve
->prime_len
;
5426 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
5431 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
5432 wpabuf_put_le16(msg
, 1);
5433 wpabuf_put_u8(msg
, DPP_STATUS_OK
);
5435 /* Code Identifier attribute */
5436 if (pkex
->identifier
) {
5437 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
5438 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
5439 wpabuf_put_str(msg
, pkex
->identifier
);
5442 /* N in Encrypted Key attribute */
5443 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
5444 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
5446 num_bytes
= BN_num_bytes(Nx
);
5447 if ((size_t) num_bytes
> curve
->prime_len
)
5449 if (curve
->prime_len
> (size_t) num_bytes
)
5450 offset
= curve
->prime_len
- num_bytes
;
5453 os_memset(wpabuf_put(msg
, offset
), 0, offset
);
5454 BN_bn2bin(Nx
, wpabuf_put(msg
, num_bytes
));
5455 os_memset(pkex
->Nx
, 0, offset
);
5456 BN_bn2bin(Nx
, pkex
->Nx
+ offset
);
5458 num_bytes
= BN_num_bytes(Ny
);
5459 if ((size_t) num_bytes
> curve
->prime_len
)
5461 if (curve
->prime_len
> (size_t) num_bytes
)
5462 offset
= curve
->prime_len
- num_bytes
;
5465 os_memset(wpabuf_put(msg
, offset
), 0, offset
);
5466 BN_bn2bin(Ny
, wpabuf_put(msg
, num_bytes
));
5468 pkex
->exchange_resp
= msg
;
5470 pkex
->exchange_done
= 1;
5488 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing faileed");
5489 dpp_pkex_free(pkex
);
5495 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
5496 const u8
*Mx
, size_t Mx_len
,
5497 const u8
*Nx
, size_t Nx_len
,
5499 const u8
*Zx
, size_t Zx_len
,
5500 u8
*z
, unsigned int hash_len
)
5502 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
5507 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, Z.x)
5510 /* HKDF-Extract(<>, IKM=Z.x) */
5511 os_memset(salt
, 0, hash_len
);
5512 if (dpp_hmac(hash_len
, salt
, hash_len
, Zx
, Zx_len
, prk
) < 0)
5514 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
5516 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
5517 info
= os_malloc(info_len
);
5521 os_memcpy(pos
, mac_init
, ETH_ALEN
);
5523 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
5525 os_memcpy(pos
, Mx
, Mx_len
);
5527 os_memcpy(pos
, Nx
, Nx_len
);
5529 os_memcpy(pos
, code
, os_strlen(code
));
5531 /* HKDF-Expand(PRK, info, L) */
5533 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
5535 else if (hash_len
== 48)
5536 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
5538 else if (hash_len
== 64)
5539 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
5544 os_memset(prk
, 0, hash_len
);
5548 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
5554 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
5555 const u8
*buf
, size_t buflen
)
5557 const u8
*attr_status
, *attr_id
, *attr_key
;
5558 u16 attr_status_len
, attr_id_len
, attr_key_len
;
5559 const EC_GROUP
*group
;
5560 BN_CTX
*bnctx
= NULL
;
5562 struct wpabuf
*clear
= NULL
;
5564 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
5565 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5566 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
5567 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
5568 EVP_PKEY_CTX
*ctx
= NULL
;
5569 EC_KEY
*Y_ec
= NULL
;
5570 size_t Jx_len
, Zx_len
;
5571 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Zx
[DPP_MAX_SHARED_SECRET_LEN
];
5574 u8 u
[DPP_MAX_HASH_LEN
];
5577 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
5579 if (!attr_status
|| attr_status_len
!= 1) {
5580 wpa_printf(MSG_DEBUG
, "DPP: No DPP Status attribute");
5583 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
5584 if (attr_status
[0] != DPP_STATUS_OK
) {
5585 wpa_printf(MSG_DEBUG
, "DPP: PKEX failed");
5589 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
5591 if (!attr_id
&& pkex
->identifier
) {
5592 wpa_printf(MSG_DEBUG
,
5593 "DPP: No PKEX code identifier received, but expected one");
5596 if (attr_id
&& pkex
->identifier
&&
5597 (os_strlen(pkex
->identifier
) != attr_id_len
||
5598 os_memcmp(pkex
->identifier
, attr_id
, attr_id_len
) != 0)) {
5599 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
5603 /* N in Encrypted Key attribute */
5604 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
5606 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
5607 wpa_printf(MSG_DEBUG
, "DPP: Missing Encrypted Key attribute");
5611 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
5612 bnctx
= BN_CTX_new();
5615 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
5616 pkex
->identifier
, bnctx
, &group
);
5621 Y
= EC_POINT_new(group
);
5622 N
= EC_POINT_new(group
);
5623 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
5624 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
5625 if (!Y
|| !N
|| !Nx
|| !Ny
||
5626 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
5627 EC_POINT_is_at_infinity(group
, N
) ||
5628 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
5629 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
5630 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
5631 EC_POINT_is_at_infinity(group
, Y
) ||
5632 !EC_POINT_is_on_curve(group
, Y
, bnctx
))
5635 pkex
->exchange_done
= 1;
5637 /* ECDH: J = a * Y’ */
5638 Y_ec
= EC_KEY_new();
5640 EC_KEY_set_group(Y_ec
, group
) != 1 ||
5641 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
5643 pkex
->y
= EVP_PKEY_new();
5645 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
5647 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
5649 EVP_PKEY_derive_init(ctx
) != 1 ||
5650 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
5651 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
5652 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5653 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
5654 wpa_printf(MSG_ERROR
,
5655 "DPP: Failed to derive ECDH shared secret: %s",
5656 ERR_error_string(ERR_get_error(), NULL
));
5660 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
5663 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
5664 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
5665 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
5666 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
5667 if (!A_pub
|| !Y_pub
|| !X_pub
)
5669 addr
[0] = pkex
->own_mac
;
5671 addr
[1] = wpabuf_head(A_pub
);
5672 len
[1] = wpabuf_len(A_pub
) / 2;
5673 addr
[2] = wpabuf_head(Y_pub
);
5674 len
[2] = wpabuf_len(Y_pub
) / 2;
5675 addr
[3] = wpabuf_head(X_pub
);
5676 len
[3] = wpabuf_len(X_pub
) / 2;
5677 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
5679 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
5682 EVP_PKEY_CTX_free(ctx
);
5683 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
5685 EVP_PKEY_derive_init(ctx
) != 1 ||
5686 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
5687 EVP_PKEY_derive(ctx
, NULL
, &Zx_len
) != 1 ||
5688 Zx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5689 EVP_PKEY_derive(ctx
, Zx
, &Zx_len
) != 1) {
5690 wpa_printf(MSG_ERROR
,
5691 "DPP: Failed to derive ECDH shared secret: %s",
5692 ERR_error_string(ERR_get_error(), NULL
));
5696 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (Z.x)",
5699 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, Z.x)
5701 if (dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
5702 pkex
->Mx
, curve
->prime_len
,
5703 attr_key
/* N.x */, attr_key_len
/ 2, pkex
->code
,
5704 Zx
, Zx_len
, pkex
->z
, curve
->hash_len
) < 0)
5707 /* {A, u, [bootstrapping info]}z */
5708 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
5709 clear
= wpabuf_alloc(clear_len
);
5710 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
,
5711 4 + clear_len
+ AES_BLOCK_SIZE
);
5715 /* A in Bootstrap Key attribute */
5716 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
5717 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
5718 wpabuf_put_buf(clear
, A_pub
);
5720 /* u in I-Auth tag attribute */
5721 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
5722 wpabuf_put_le16(clear
, curve
->hash_len
);
5723 wpabuf_put_data(clear
, u
, curve
->hash_len
);
5727 len
[0] = sizeof(octet
);
5728 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5730 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5731 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5732 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5734 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5735 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
5736 wpabuf_head(clear
), wpabuf_len(clear
),
5737 1, addr
, len
, wrapped
) < 0)
5739 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5740 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5753 EVP_PKEY_CTX_free(ctx
);
5757 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing faileed");
5764 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
5765 const u8
*buf
, size_t buflen
)
5767 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5769 size_t Jx_len
, Zx_len
, Lx_len
;
5770 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Zx
[DPP_MAX_SHARED_SECRET_LEN
];
5771 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
5772 const u8
*wrapped_data
, *b_key
, *peer_u
;
5773 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
5777 u8
*unwrapped
= NULL
;
5778 size_t unwrapped_len
= 0;
5779 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
5780 struct wpabuf
*B_pub
= NULL
;
5781 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
5783 struct wpabuf
*clear
= NULL
;
5787 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
5789 EVP_PKEY_derive_init(ctx
) != 1 ||
5790 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
5791 EVP_PKEY_derive(ctx
, NULL
, &Zx_len
) != 1 ||
5792 Zx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5793 EVP_PKEY_derive(ctx
, Zx
, &Zx_len
) != 1) {
5794 wpa_printf(MSG_ERROR
,
5795 "DPP: Failed to derive ECDH shared secret: %s",
5796 ERR_error_string(ERR_get_error(), NULL
));
5800 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (Z.x)",
5803 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, Z.x)
5805 if (dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
5806 pkex
->Mx
, curve
->prime_len
,
5807 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
5808 Zx
, Zx_len
, pkex
->z
, curve
->hash_len
) < 0)
5811 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
5813 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5814 wpa_printf(MSG_DEBUG
,
5815 "DPP: Missing or invalid required Wrapped data attribute");
5819 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5820 wrapped_data
, wrapped_data_len
);
5821 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5822 unwrapped
= os_malloc(unwrapped_len
);
5828 len
[0] = sizeof(octet
);
5829 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5831 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
5832 wrapped_data
, wrapped_data_len
,
5833 1, addr
, len
, unwrapped
) < 0) {
5834 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
5837 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5838 unwrapped
, unwrapped_len
);
5840 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5841 wpa_printf(MSG_DEBUG
,
5842 "DPP: Invalid attribute in unwrapped data");
5846 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
5848 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
5849 wpa_printf(MSG_DEBUG
,
5850 "DPP: No valid peer bootstrapping key found");
5853 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
5855 if (!pkex
->peer_bootstrap_key
)
5857 dpp_debug_print_key("DPP: Peer bootstrap public key",
5858 pkex
->peer_bootstrap_key
);
5860 /* ECDH: J' = y * A' */
5861 EVP_PKEY_CTX_free(ctx
);
5862 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
5864 EVP_PKEY_derive_init(ctx
) != 1 ||
5865 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
5866 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
5867 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5868 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
5869 wpa_printf(MSG_ERROR
,
5870 "DPP: Failed to derive ECDH shared secret: %s",
5871 ERR_error_string(ERR_get_error(), NULL
));
5875 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
5878 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
5879 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
5880 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
5881 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
5882 if (!A_pub
|| !Y_pub
|| !X_pub
)
5884 addr
[0] = pkex
->peer_mac
;
5886 addr
[1] = wpabuf_head(A_pub
);
5887 len
[1] = wpabuf_len(A_pub
) / 2;
5888 addr
[2] = wpabuf_head(Y_pub
);
5889 len
[2] = wpabuf_len(Y_pub
) / 2;
5890 addr
[3] = wpabuf_head(X_pub
);
5891 len
[3] = wpabuf_len(X_pub
) / 2;
5892 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
5895 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
5897 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
5898 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
5899 wpa_printf(MSG_DEBUG
, "DPP: No valid u (I-Auth tag) found");
5900 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
5901 u
, curve
->hash_len
);
5902 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
5905 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
5907 /* ECDH: L = b * X' */
5908 EVP_PKEY_CTX_free(ctx
);
5909 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
5911 EVP_PKEY_derive_init(ctx
) != 1 ||
5912 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
5913 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
5914 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5915 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
5916 wpa_printf(MSG_ERROR
,
5917 "DPP: Failed to derive ECDH shared secret: %s",
5918 ERR_error_string(ERR_get_error(), NULL
));
5922 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
5925 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
5926 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
5929 addr
[0] = pkex
->own_mac
;
5931 addr
[1] = wpabuf_head(B_pub
);
5932 len
[1] = wpabuf_len(B_pub
) / 2;
5933 addr
[2] = wpabuf_head(X_pub
);
5934 len
[2] = wpabuf_len(X_pub
) / 2;
5935 addr
[3] = wpabuf_head(Y_pub
);
5936 len
[3] = wpabuf_len(Y_pub
) / 2;
5937 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
5939 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
5941 /* {B, v [bootstrapping info]}z */
5942 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
5943 clear
= wpabuf_alloc(clear_len
);
5944 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
,
5945 4 + clear_len
+ AES_BLOCK_SIZE
);
5949 /* A in Bootstrap Key attribute */
5950 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
5951 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
5952 wpabuf_put_buf(clear
, B_pub
);
5954 /* v in R-Auth tag attribute */
5955 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
5956 wpabuf_put_le16(clear
, curve
->hash_len
);
5957 wpabuf_put_data(clear
, v
, curve
->hash_len
);
5961 len
[0] = sizeof(octet
);
5962 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5964 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5965 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5966 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5968 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5969 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
5970 wpabuf_head(clear
), wpabuf_len(clear
),
5971 1, addr
, len
, wrapped
) < 0)
5973 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5974 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5976 EVP_PKEY_CTX_free(ctx
);
5991 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
,
5992 const u8
*buf
, size_t buflen
)
5994 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
5995 const u8
*wrapped_data
, *b_key
, *peer_v
;
5996 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
6000 u8
*unwrapped
= NULL
;
6001 size_t unwrapped_len
= 0;
6003 u8 v
[DPP_MAX_HASH_LEN
];
6005 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
6006 EVP_PKEY_CTX
*ctx
= NULL
;
6007 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6009 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
6011 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6012 wpa_printf(MSG_DEBUG
,
6013 "DPP: Missing or invalid required Wrapped data attribute");
6017 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6018 wrapped_data
, wrapped_data_len
);
6019 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6020 unwrapped
= os_malloc(unwrapped_len
);
6026 len
[0] = sizeof(octet
);
6027 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
6029 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
6030 wrapped_data
, wrapped_data_len
,
6031 1, addr
, len
, unwrapped
) < 0) {
6032 wpa_printf(MSG_DEBUG
, "DPP: AES-SIV decryption failed");
6035 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6036 unwrapped
, unwrapped_len
);
6038 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6039 wpa_printf(MSG_DEBUG
,
6040 "DPP: Invalid attribute in unwrapped data");
6044 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
6046 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
6047 wpa_printf(MSG_DEBUG
,
6048 "DPP: No valid peer bootstrapping key found");
6051 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
6053 if (!pkex
->peer_bootstrap_key
)
6055 dpp_debug_print_key("DPP: Peer bootstrap public key",
6056 pkex
->peer_bootstrap_key
);
6058 /* ECDH: L' = x * B' */
6059 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
6061 EVP_PKEY_derive_init(ctx
) != 1 ||
6062 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
6063 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
6064 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6065 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
6066 wpa_printf(MSG_ERROR
,
6067 "DPP: Failed to derive ECDH shared secret: %s",
6068 ERR_error_string(ERR_get_error(), NULL
));
6072 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
6075 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
6076 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
6077 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
6078 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
6079 if (!B_pub
|| !X_pub
|| !Y_pub
)
6081 addr
[0] = pkex
->peer_mac
;
6083 addr
[1] = wpabuf_head(B_pub
);
6084 len
[1] = wpabuf_len(B_pub
) / 2;
6085 addr
[2] = wpabuf_head(X_pub
);
6086 len
[2] = wpabuf_len(X_pub
) / 2;
6087 addr
[3] = wpabuf_head(Y_pub
);
6088 len
[3] = wpabuf_len(Y_pub
) / 2;
6089 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
6092 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
6094 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
6095 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
6096 wpa_printf(MSG_DEBUG
, "DPP: No valid v (R-Auth tag) found");
6097 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
6098 v
, curve
->hash_len
);
6099 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
6102 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
6109 EVP_PKEY_CTX_free(ctx
);
6117 void dpp_pkex_free(struct dpp_pkex
*pkex
)
6122 os_free(pkex
->identifier
);
6123 os_free(pkex
->code
);
6124 EVP_PKEY_free(pkex
->x
);
6125 EVP_PKEY_free(pkex
->y
);
6126 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
6127 wpabuf_free(pkex
->exchange_req
);
6128 wpabuf_free(pkex
->exchange_resp
);