2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
10 #include <openssl/opensslv.h>
11 #include <openssl/err.h>
12 #include <openssl/asn1.h>
13 #include <openssl/asn1t.h>
15 #include "utils/common.h"
16 #include "utils/base64.h"
17 #include "utils/json.h"
18 #include "common/ieee802_11_common.h"
19 #include "common/ieee802_11_defs.h"
20 #include "common/wpa_ctrl.h"
21 #include "crypto/crypto.h"
22 #include "crypto/random.h"
23 #include "crypto/aes.h"
24 #include "crypto/aes_siv.h"
25 #include "crypto/sha384.h"
26 #include "crypto/sha512.h"
27 #include "drivers/driver.h"
31 #ifdef CONFIG_TESTING_OPTIONS
32 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
33 u8 dpp_pkex_own_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
34 u8 dpp_pkex_peer_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
35 u8 dpp_pkex_ephemeral_key_override
[600];
36 size_t dpp_pkex_ephemeral_key_override_len
= 0;
37 u8 dpp_protocol_key_override
[600];
38 size_t dpp_protocol_key_override_len
= 0;
39 u8 dpp_nonce_override
[DPP_MAX_NONCE_LEN
];
40 size_t dpp_nonce_override_len
= 0;
42 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
43 const struct dpp_curve_params
*curve
);
44 #endif /* CONFIG_TESTING_OPTIONS */
46 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
47 (defined(LIBRESSL_VERSION_NUMBER) && \
48 LIBRESSL_VERSION_NUMBER < 0x20700000L)
49 /* Compatibility wrappers for older versions. */
51 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
59 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
71 static const struct dpp_curve_params dpp_curves
[] = {
72 /* The mandatory to support and the default NIST P-256 curve needs to
73 * be the first entry on this list. */
74 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
75 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
76 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
77 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
78 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
79 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
80 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
84 /* Role-specific elements for PKEX */
87 static const u8 pkex_init_x_p256
[32] = {
88 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
89 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
90 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
91 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
93 static const u8 pkex_init_y_p256
[32] = {
94 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
95 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
96 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
97 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
99 static const u8 pkex_resp_x_p256
[32] = {
100 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
101 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
102 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
103 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
105 static const u8 pkex_resp_y_p256
[32] = {
106 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
107 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
108 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
109 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
113 static const u8 pkex_init_x_p384
[48] = {
114 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
115 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
116 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
117 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
118 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
119 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
121 static const u8 pkex_init_y_p384
[48] = {
122 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
123 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
124 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
125 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
126 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
127 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
129 static const u8 pkex_resp_x_p384
[48] = {
130 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
131 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
132 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
133 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
134 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
135 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
137 static const u8 pkex_resp_y_p384
[48] = {
138 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
139 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
140 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
141 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
142 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
143 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
147 static const u8 pkex_init_x_p521
[66] = {
148 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
149 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
150 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
151 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
152 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
153 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
154 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
155 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
158 static const u8 pkex_init_y_p521
[66] = {
159 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
160 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
161 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
162 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
163 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
164 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
165 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
166 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
169 static const u8 pkex_resp_x_p521
[66] = {
170 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
171 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
172 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
173 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
174 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
175 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
176 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
177 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
180 static const u8 pkex_resp_y_p521
[66] = {
181 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
182 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
183 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
184 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
185 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
186 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
187 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
188 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
192 /* Brainpool P-256r1 */
193 static const u8 pkex_init_x_bp_p256r1
[32] = {
194 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
195 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
196 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
197 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
199 static const u8 pkex_init_y_bp_p256r1
[32] = {
200 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
201 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
202 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
203 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
205 static const u8 pkex_resp_x_bp_p256r1
[32] = {
206 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
207 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
208 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
209 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
211 static const u8 pkex_resp_y_bp_p256r1
[32] = {
212 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
213 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
214 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
215 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
218 /* Brainpool P-384r1 */
219 static const u8 pkex_init_x_bp_p384r1
[48] = {
220 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
221 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
222 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
223 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
224 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
225 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
227 static const u8 pkex_init_y_bp_p384r1
[48] = {
228 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
229 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
230 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
231 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
232 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
233 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
235 static const u8 pkex_resp_x_bp_p384r1
[48] = {
236 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
237 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
238 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
239 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
240 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
241 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
243 static const u8 pkex_resp_y_bp_p384r1
[48] = {
244 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
245 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
246 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
247 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
248 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
249 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
252 /* Brainpool P-512r1 */
253 static const u8 pkex_init_x_bp_p512r1
[64] = {
254 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
255 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
256 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
257 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
258 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
259 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
260 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
261 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
263 static const u8 pkex_init_y_bp_p512r1
[64] = {
264 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
265 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
266 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
267 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
268 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
269 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
270 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
271 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
273 static const u8 pkex_resp_x_bp_p512r1
[64] = {
274 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
275 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
276 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
277 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
278 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
279 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
280 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
281 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
283 static const u8 pkex_resp_y_bp_p512r1
[64] = {
284 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
285 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
286 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
287 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
288 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
289 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
290 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
291 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
295 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
296 const EC_POINT
*point
)
300 char *x_str
= NULL
, *y_str
= NULL
;
302 if (!wpa_debug_show_keys
)
308 if (!ctx
|| !x
|| !y
||
309 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
312 x_str
= BN_bn2hex(x
);
313 y_str
= BN_bn2hex(y
);
314 if (!x_str
|| !y_str
)
317 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
328 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
329 size_t num_elem
, const u8
*addr
[], const size_t *len
,
332 if (curve
->hash_len
== 32)
333 return sha256_vector(num_elem
, addr
, len
, mac
);
334 if (curve
->hash_len
== 48)
335 return sha384_vector(num_elem
, addr
, len
, mac
);
336 if (curve
->hash_len
== 64)
337 return sha512_vector(num_elem
, addr
, len
, mac
);
342 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
343 const char *label
, u8
*out
, size_t outlen
)
346 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
347 (const u8
*) label
, os_strlen(label
),
350 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
351 (const u8
*) label
, os_strlen(label
),
354 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
355 (const u8
*) label
, os_strlen(label
),
361 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
362 size_t num_elem
, const u8
*addr
[],
363 const size_t *len
, u8
*mac
)
366 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
369 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
372 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
378 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
379 const u8
*data
, size_t data_len
, u8
*mac
)
382 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
384 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
386 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
391 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
393 int num_bytes
, offset
;
395 num_bytes
= BN_num_bytes(bn
);
396 if ((size_t) num_bytes
> len
)
398 offset
= len
- num_bytes
;
399 os_memset(pos
, 0, offset
);
400 BN_bn2bin(bn
, pos
+ offset
);
405 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
412 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
415 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
416 len
= i2o_ECPublicKey(eckey
, NULL
);
418 wpa_printf(MSG_ERROR
,
419 "DDP: Failed to determine public key encoding length");
424 buf
= wpabuf_alloc(len
);
430 pos
= wpabuf_put(buf
, len
);
431 res
= i2o_ECPublicKey(eckey
, &pos
);
434 wpa_printf(MSG_ERROR
,
435 "DDP: Failed to encode public key (res=%d/%d)",
442 /* Remove 0x04 prefix to match DPP definition */
443 pos
= wpabuf_mhead(buf
);
444 os_memmove(pos
, pos
+ 1, len
- 1);
452 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
453 const u8
*buf_x
, const u8
*buf_y
,
456 EC_KEY
*eckey
= NULL
;
458 EC_POINT
*point
= NULL
;
459 BIGNUM
*x
= NULL
, *y
= NULL
;
460 EVP_PKEY
*pkey
= NULL
;
464 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
468 point
= EC_POINT_new(group
);
469 x
= BN_bin2bn(buf_x
, len
, NULL
);
470 y
= BN_bin2bn(buf_y
, len
, NULL
);
471 if (!point
|| !x
|| !y
) {
472 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
476 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
477 wpa_printf(MSG_ERROR
,
478 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
479 ERR_error_string(ERR_get_error(), NULL
));
483 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
484 EC_POINT_is_at_infinity(group
, point
)) {
485 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
488 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
490 eckey
= EC_KEY_new();
492 EC_KEY_set_group(eckey
, group
) != 1 ||
493 EC_KEY_set_public_key(eckey
, point
) != 1) {
494 wpa_printf(MSG_ERROR
,
495 "DPP: Failed to set EC_KEY: %s",
496 ERR_error_string(ERR_get_error(), NULL
));
499 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
501 pkey
= EVP_PKEY_new();
502 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
503 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
511 EC_POINT_free(point
);
521 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
522 const u8
*buf
, size_t len
)
525 const EC_GROUP
*group
;
526 EVP_PKEY
*pkey
= NULL
;
531 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
533 wpa_printf(MSG_ERROR
,
534 "DPP: Could not get EC_KEY from group_key");
538 group
= EC_KEY_get0_group(eckey
);
540 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
543 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
550 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
552 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
556 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
561 msg
= wpabuf_alloc(8 + len
);
564 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
565 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
566 wpabuf_put_be24(msg
, OUI_WFA
);
567 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
568 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
569 wpabuf_put_u8(msg
, type
);
574 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
577 const u8
*pos
= buf
, *end
= buf
+ len
;
579 while (end
- pos
>= 4) {
580 id
= WPA_GET_LE16(pos
);
582 alen
= WPA_GET_LE16(pos
);
584 if (alen
> end
- pos
)
597 int dpp_check_attrs(const u8
*buf
, size_t len
)
600 int wrapped_data
= 0;
604 while (end
- pos
>= 4) {
607 id
= WPA_GET_LE16(pos
);
609 alen
= WPA_GET_LE16(pos
);
611 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
613 if (alen
> end
- pos
) {
614 wpa_printf(MSG_DEBUG
,
615 "DPP: Truncated message - not enough room for the attribute - dropped");
619 wpa_printf(MSG_DEBUG
,
620 "DPP: An unexpected attribute included after the Wrapped Data attribute");
623 if (id
== DPP_ATTR_WRAPPED_DATA
)
629 wpa_printf(MSG_DEBUG
,
630 "DPP: Unexpected octets (%d) after the last attribute",
639 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
645 EVP_PKEY_free(info
->pubkey
);
650 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
653 case DPP_BOOTSTRAP_QR_CODE
:
655 case DPP_BOOTSTRAP_PKEX
:
662 static int dpp_uri_valid_info(const char *info
)
665 unsigned char val
= *info
++;
667 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
675 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
677 bi
->uri
= os_strdup(uri
);
678 return bi
->uri
? 0 : -1;
682 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
683 const char *chan_list
)
685 const char *pos
= chan_list
;
686 int opclass
, channel
, freq
;
688 while (pos
&& *pos
&& *pos
!= ';') {
692 pos
= os_strchr(pos
, '/');
699 while (*pos
>= '0' && *pos
<= '9')
701 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
702 wpa_printf(MSG_DEBUG
,
703 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
704 opclass
, channel
, freq
);
706 wpa_printf(MSG_DEBUG
,
707 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
709 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
710 wpa_printf(MSG_DEBUG
,
711 "DPP: Too many channels in URI channel-list - ignore list");
715 bi
->freq
[bi
->num_freq
++] = freq
;
718 if (*pos
== ';' || *pos
== '\0')
727 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
732 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
737 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
738 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
742 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
748 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
755 end
= os_strchr(info
, ';');
757 end
= info
+ os_strlen(info
);
758 bi
->info
= os_malloc(end
- info
+ 1);
761 os_memcpy(bi
->info
, info
, end
- info
);
762 bi
->info
[end
- info
] = '\0';
763 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
764 if (!dpp_uri_valid_info(bi
->info
)) {
765 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
773 static const struct dpp_curve_params
*
774 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
779 for (i
= 0; dpp_curves
[i
].name
; i
++) {
780 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
781 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
782 return &dpp_curves
[i
];
788 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
794 for (i
= 0; dpp_curves
[i
].name
; i
++) {
795 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
797 return &dpp_curves
[i
];
803 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
809 const unsigned char *p
;
811 X509_PUBKEY
*pub
= NULL
;
813 const unsigned char *pk
;
816 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
819 const ASN1_OBJECT
*pa_oid
;
823 const ASN1_OBJECT
*poid
;
826 end
= os_strchr(info
, ';');
830 data
= base64_decode((const unsigned char *) info
, end
- info
,
833 wpa_printf(MSG_DEBUG
,
834 "DPP: Invalid base64 encoding on URI public-key");
837 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
840 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
841 bi
->pubkey_hash
) < 0) {
842 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
846 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
847 bi
->pubkey_hash
, SHA256_MAC_LEN
);
849 /* DER encoded ASN.1 SubjectPublicKeyInfo
851 * SubjectPublicKeyInfo ::= SEQUENCE {
852 * algorithm AlgorithmIdentifier,
853 * subjectPublicKey BIT STRING }
855 * AlgorithmIdentifier ::= SEQUENCE {
856 * algorithm OBJECT IDENTIFIER,
857 * parameters ANY DEFINED BY algorithm OPTIONAL }
859 * subjectPublicKey = compressed format public key per ANSI X9.63
860 * algorithm = ecPublicKey (1.2.840.10045.2.1)
861 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
862 * prime256v1 (1.2.840.10045.3.1.7)
866 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
870 wpa_printf(MSG_DEBUG
,
871 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
875 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
876 wpa_printf(MSG_DEBUG
,
877 "DPP: SubjectPublicKeyInfo does not describe an EC key");
882 res
= X509_PUBKEY_set(&pub
, pkey
);
884 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
888 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
890 wpa_printf(MSG_DEBUG
,
891 "DPP: Could not extract SubjectPublicKeyInfo parameters");
894 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
895 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
896 wpa_printf(MSG_DEBUG
,
897 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
900 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
901 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
902 wpa_printf(MSG_DEBUG
,
903 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
907 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
908 if (ptype
!= V_ASN1_OBJECT
) {
909 wpa_printf(MSG_DEBUG
,
910 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
914 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
915 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
916 wpa_printf(MSG_DEBUG
,
917 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
920 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
921 bi
->curve
= dpp_get_curve_oid(poid
);
923 wpa_printf(MSG_DEBUG
,
924 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
929 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
931 X509_PUBKEY_free(pub
);
935 X509_PUBKEY_free(pub
);
941 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
943 const char *pos
= uri
;
945 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
946 struct dpp_bootstrap_info
*bi
;
948 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
950 if (os_strncmp(pos
, "DPP:", 4) != 0) {
951 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
957 end
= os_strchr(pos
, ';');
962 /* Handle terminating ";;" and ignore unexpected ";"
963 * for parsing robustness. */
968 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
970 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
972 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
974 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
977 wpa_hexdump_ascii(MSG_DEBUG
,
978 "DPP: Ignore unrecognized URI parameter",
984 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
988 bi
= os_zalloc(sizeof(*bi
));
992 if (dpp_clone_uri(bi
, uri
) < 0 ||
993 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
994 dpp_parse_uri_mac(bi
, mac
) < 0 ||
995 dpp_parse_uri_info(bi
, info
) < 0 ||
996 dpp_parse_uri_pk(bi
, pk
) < 0) {
997 dpp_bootstrap_info_free(bi
);
1005 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
1007 struct dpp_bootstrap_info
*bi
;
1009 bi
= dpp_parse_uri(uri
);
1011 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
1016 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1023 unsigned char *der
= NULL
;
1025 const EC_GROUP
*group
;
1026 const EC_POINT
*point
;
1028 out
= BIO_new(BIO_s_mem());
1032 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1033 rlen
= BIO_ctrl_pending(out
);
1034 txt
= os_malloc(rlen
+ 1);
1036 res
= BIO_read(out
, txt
, rlen
);
1039 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1045 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1049 group
= EC_KEY_get0_group(eckey
);
1050 point
= EC_KEY_get0_public_key(eckey
);
1052 dpp_debug_print_point(title
, group
, point
);
1054 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1056 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1060 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1062 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1070 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1072 EVP_PKEY_CTX
*kctx
= NULL
;
1074 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1077 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1079 nid
= OBJ_txt2nid(curve
->name
);
1080 if (nid
== NID_undef
) {
1081 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1085 ec_params
= EC_KEY_new_by_curve_name(nid
);
1087 wpa_printf(MSG_ERROR
,
1088 "DPP: Failed to generate EC_KEY parameters");
1091 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1092 params
= EVP_PKEY_new();
1093 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1094 wpa_printf(MSG_ERROR
,
1095 "DPP: Failed to generate EVP_PKEY parameters");
1099 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1101 EVP_PKEY_keygen_init(kctx
) != 1 ||
1102 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1103 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1107 if (wpa_debug_show_keys
)
1108 dpp_debug_print_key("Own generated key", key
);
1110 EVP_PKEY_free(params
);
1111 EVP_PKEY_CTX_free(kctx
);
1114 EVP_PKEY_CTX_free(kctx
);
1115 EVP_PKEY_free(params
);
1120 static const struct dpp_curve_params
*
1121 dpp_get_curve_name(const char *name
)
1125 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1126 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1127 (dpp_curves
[i
].jwk_crv
&&
1128 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1129 return &dpp_curves
[i
];
1135 static const struct dpp_curve_params
*
1136 dpp_get_curve_jwk_crv(const char *name
)
1140 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1141 if (dpp_curves
[i
].jwk_crv
&&
1142 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1143 return &dpp_curves
[i
];
1149 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1150 const u8
*privkey
, size_t privkey_len
)
1154 const EC_GROUP
*group
;
1157 pkey
= EVP_PKEY_new();
1160 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1162 wpa_printf(MSG_INFO
,
1163 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1164 ERR_error_string(ERR_get_error(), NULL
));
1165 EVP_PKEY_free(pkey
);
1168 group
= EC_KEY_get0_group(eckey
);
1171 EVP_PKEY_free(pkey
);
1174 nid
= EC_GROUP_get_curve_name(group
);
1175 *curve
= dpp_get_curve_nid(nid
);
1177 wpa_printf(MSG_INFO
,
1178 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1181 EVP_PKEY_free(pkey
);
1185 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1187 EVP_PKEY_free(pkey
);
1195 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1196 * as an OID identifying the curve */
1198 /* Compressed format public key per ANSI X9.63 */
1199 ASN1_BIT_STRING
*pub_key
;
1200 } DPP_BOOTSTRAPPING_KEY
;
1202 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1203 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1204 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1205 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1207 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1210 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1212 unsigned char *der
= NULL
;
1215 struct wpabuf
*ret
= NULL
;
1217 const EC_GROUP
*group
;
1218 const EC_POINT
*point
;
1220 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1224 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1228 group
= EC_KEY_get0_group(eckey
);
1229 point
= EC_KEY_get0_public_key(eckey
);
1230 if (!group
|| !point
)
1232 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1233 nid
= EC_GROUP_get_curve_name(group
);
1235 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1237 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1238 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1241 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1246 der
= OPENSSL_malloc(len
);
1249 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1252 OPENSSL_free(bootstrap
->pub_key
->data
);
1253 bootstrap
->pub_key
->data
= der
;
1255 bootstrap
->pub_key
->length
= len
;
1256 /* No unused bits */
1257 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1258 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1260 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1262 wpa_printf(MSG_ERROR
,
1263 "DDP: Failed to build DER encoded public key");
1267 ret
= wpabuf_alloc_copy(der
, der_len
);
1269 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1277 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1284 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1287 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1290 addr
[0] = wpabuf_head(der
);
1291 len
[0] = wpabuf_len(der
);
1292 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1294 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1296 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1303 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1304 const u8
*privkey
, size_t privkey_len
)
1306 unsigned char *base64
= NULL
;
1309 struct wpabuf
*der
= NULL
;
1314 bi
->curve
= &dpp_curves
[0];
1316 bi
->curve
= dpp_get_curve_name(curve
);
1318 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1324 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1326 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1331 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1334 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1337 addr
[0] = wpabuf_head(der
);
1338 len
= wpabuf_len(der
);
1339 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1341 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1344 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1347 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1352 pos
= (char *) base64
;
1355 pos
= os_strchr(pos
, '\n');
1358 os_memmove(pos
, pos
+ 1, end
- pos
);
1360 return (char *) base64
;
1368 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1369 unsigned int hash_len
)
1371 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1372 const char *info
= "first intermediate key";
1375 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1377 /* HKDF-Extract(<>, M.x) */
1378 os_memset(salt
, 0, hash_len
);
1379 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1381 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1384 /* HKDF-Expand(PRK, info, L) */
1385 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1386 os_memset(prk
, 0, hash_len
);
1390 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1396 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1397 unsigned int hash_len
)
1399 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1400 const char *info
= "second intermediate key";
1403 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1405 /* HKDF-Extract(<>, N.x) */
1406 os_memset(salt
, 0, hash_len
);
1407 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1410 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1413 /* HKDF-Expand(PRK, info, L) */
1414 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1415 os_memset(prk
, 0, hash_len
);
1419 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1425 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1426 unsigned int hash_len
)
1429 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1430 const char *info_ke
= "DPP Key";
1431 u8 prk
[DPP_MAX_HASH_LEN
];
1435 size_t num_elem
= 0;
1437 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1438 wpa_printf(MSG_DEBUG
,
1439 "DPP: Mx/Nx not available - cannot derive ke");
1443 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1445 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1446 nonce_len
= auth
->curve
->nonce_len
;
1447 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1448 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1449 addr
[num_elem
] = auth
->Mx
;
1450 len
[num_elem
] = auth
->Mx_len
;
1452 addr
[num_elem
] = auth
->Nx
;
1453 len
[num_elem
] = auth
->Nx_len
;
1455 if (auth
->peer_bi
&& auth
->own_bi
) {
1456 if (!auth
->Lx_len
) {
1457 wpa_printf(MSG_DEBUG
,
1458 "DPP: Lx not available - cannot derive ke");
1461 addr
[num_elem
] = auth
->Lx
;
1462 len
[num_elem
] = auth
->secret_len
;
1465 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1466 num_elem
, addr
, len
, prk
);
1469 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1472 /* HKDF-Expand(PRK, info, L) */
1473 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1474 os_memset(prk
, 0, hash_len
);
1478 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1484 static void dpp_build_attr_status(struct wpabuf
*msg
,
1485 enum dpp_status_error status
)
1487 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1488 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1489 wpabuf_put_le16(msg
, 1);
1490 wpabuf_put_u8(msg
, status
);
1494 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1498 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1499 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1500 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1501 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1506 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1510 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1511 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1512 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1513 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1518 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1519 const struct wpabuf
*pi
,
1521 const u8
*r_pubkey_hash
,
1522 const u8
*i_pubkey_hash
,
1523 unsigned int neg_freq
)
1526 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1527 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1530 size_t len
[2], siv_len
, attr_len
;
1531 u8
*attr_start
, *attr_end
;
1533 /* Build DPP Authentication Request frame attributes */
1534 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1535 4 + sizeof(wrapped_data
);
1538 #ifdef CONFIG_TESTING_OPTIONS
1539 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1541 #endif /* CONFIG_TESTING_OPTIONS */
1542 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1546 attr_start
= wpabuf_put(msg
, 0);
1548 /* Responder Bootstrapping Key Hash */
1549 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1551 /* Initiator Bootstrapping Key Hash */
1552 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1554 /* Initiator Protocol Key */
1556 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1557 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1558 wpabuf_put_buf(msg
, pi
);
1563 u8 op_class
, channel
;
1565 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1567 NUM_HOSTAPD_MODES
) {
1568 wpa_printf(MSG_INFO
,
1569 "DPP: Unsupported negotiation frequency request: %d",
1574 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1575 wpabuf_put_le16(msg
, 2);
1576 wpabuf_put_u8(msg
, op_class
);
1577 wpabuf_put_u8(msg
, channel
);
1580 #ifdef CONFIG_TESTING_OPTIONS
1581 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1582 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1583 goto skip_wrapped_data
;
1585 #endif /* CONFIG_TESTING_OPTIONS */
1587 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1590 #ifdef CONFIG_TESTING_OPTIONS
1591 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1592 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1595 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1596 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1597 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1599 WPA_PUT_LE16(pos
, nonce_len
- 1);
1601 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1602 pos
+= nonce_len
- 1;
1605 #endif /* CONFIG_TESTING_OPTIONS */
1608 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1610 WPA_PUT_LE16(pos
, nonce_len
);
1612 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1615 #ifdef CONFIG_TESTING_OPTIONS
1617 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1618 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1621 #endif /* CONFIG_TESTING_OPTIONS */
1623 /* I-capabilities */
1624 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1626 WPA_PUT_LE16(pos
, 1);
1628 auth
->i_capab
= auth
->allowed_roles
;
1629 *pos
++ = auth
->i_capab
;
1630 #ifdef CONFIG_TESTING_OPTIONS
1631 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1632 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1636 #endif /* CONFIG_TESTING_OPTIONS */
1638 attr_end
= wpabuf_put(msg
, 0);
1640 /* OUI, OUI type, Crypto Suite, DPP frame type */
1641 addr
[0] = wpabuf_head_u8(msg
) + 2;
1642 len
[0] = 3 + 1 + 1 + 1;
1643 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1645 /* Attributes before Wrapped Data */
1646 addr
[1] = attr_start
;
1647 len
[1] = attr_end
- attr_start
;
1648 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1650 siv_len
= pos
- clear
;
1651 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1652 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1653 2, addr
, len
, wrapped_data
) < 0) {
1657 siv_len
+= AES_BLOCK_SIZE
;
1658 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1659 wrapped_data
, siv_len
);
1661 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1662 wpabuf_put_le16(msg
, siv_len
);
1663 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1665 #ifdef CONFIG_TESTING_OPTIONS
1666 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1667 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1668 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1671 #endif /* CONFIG_TESTING_OPTIONS */
1673 wpa_hexdump_buf(MSG_DEBUG
,
1674 "DPP: Authentication Request frame attributes", msg
);
1680 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1681 enum dpp_status_error status
,
1682 const struct wpabuf
*pr
,
1684 const u8
*r_pubkey_hash
,
1685 const u8
*i_pubkey_hash
,
1686 const u8
*r_nonce
, const u8
*i_nonce
,
1687 const u8
*wrapped_r_auth
,
1688 size_t wrapped_r_auth_len
,
1692 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1693 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1694 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1695 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1697 size_t len
[2], siv_len
, attr_len
;
1698 u8
*attr_start
, *attr_end
, *pos
;
1700 auth
->waiting_auth_conf
= 1;
1701 auth
->auth_resp_tries
= 0;
1703 /* Build DPP Authentication Response frame attributes */
1704 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1705 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1706 #ifdef CONFIG_TESTING_OPTIONS
1707 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1709 #endif /* CONFIG_TESTING_OPTIONS */
1710 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1714 attr_start
= wpabuf_put(msg
, 0);
1718 dpp_build_attr_status(msg
, status
);
1720 /* Responder Bootstrapping Key Hash */
1721 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1723 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1724 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1726 /* Responder Protocol Key */
1728 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1729 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1730 wpabuf_put_buf(msg
, pr
);
1733 attr_end
= wpabuf_put(msg
, 0);
1735 #ifdef CONFIG_TESTING_OPTIONS
1736 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1737 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1738 goto skip_wrapped_data
;
1740 #endif /* CONFIG_TESTING_OPTIONS */
1742 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1747 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1749 WPA_PUT_LE16(pos
, nonce_len
);
1751 os_memcpy(pos
, r_nonce
, nonce_len
);
1757 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1759 WPA_PUT_LE16(pos
, nonce_len
);
1761 os_memcpy(pos
, i_nonce
, nonce_len
);
1762 #ifdef CONFIG_TESTING_OPTIONS
1763 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1764 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1765 pos
[nonce_len
/ 2] ^= 0x01;
1767 #endif /* CONFIG_TESTING_OPTIONS */
1771 #ifdef CONFIG_TESTING_OPTIONS
1772 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1773 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1776 #endif /* CONFIG_TESTING_OPTIONS */
1778 /* R-capabilities */
1779 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1781 WPA_PUT_LE16(pos
, 1);
1783 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1785 *pos
++ = auth
->r_capab
;
1786 #ifdef CONFIG_TESTING_OPTIONS
1787 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1788 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1790 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1791 wpa_printf(MSG_INFO
,
1792 "DPP: TESTING - incompatible R-capabilities");
1793 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1794 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1797 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1798 DPP_CAPAB_CONFIGURATOR
;
1801 #endif /* CONFIG_TESTING_OPTIONS */
1803 if (wrapped_r_auth
) {
1805 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1807 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1809 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1810 pos
+= wrapped_r_auth_len
;
1813 /* OUI, OUI type, Crypto Suite, DPP frame type */
1814 addr
[0] = wpabuf_head_u8(msg
) + 2;
1815 len
[0] = 3 + 1 + 1 + 1;
1816 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1818 /* Attributes before Wrapped Data */
1819 addr
[1] = attr_start
;
1820 len
[1] = attr_end
- attr_start
;
1821 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1823 siv_len
= pos
- clear
;
1824 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1825 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1826 2, addr
, len
, wrapped_data
) < 0) {
1830 siv_len
+= AES_BLOCK_SIZE
;
1831 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1832 wrapped_data
, siv_len
);
1834 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1835 wpabuf_put_le16(msg
, siv_len
);
1836 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1838 #ifdef CONFIG_TESTING_OPTIONS
1839 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1840 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1841 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1844 #endif /* CONFIG_TESTING_OPTIONS */
1846 wpa_hexdump_buf(MSG_DEBUG
,
1847 "DPP: Authentication Response frame attributes", msg
);
1852 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1853 u16 num_modes
, unsigned int freq
)
1858 if (!own_modes
|| !num_modes
)
1861 for (m
= 0; m
< num_modes
; m
++) {
1862 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1863 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1866 flag
= own_modes
[m
].channels
[c
].flag
;
1867 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1868 HOSTAPD_CHAN_NO_IR
|
1869 HOSTAPD_CHAN_RADAR
)))
1874 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1879 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1883 if (freqs
[--num
] == freq
)
1890 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1895 for (i
= 0; i
< num
; i
++) {
1896 if (freqs
[i
] == freq
)
1899 if (i
== 0 || i
>= num
)
1901 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1906 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1907 struct hostapd_hw_modes
*own_modes
,
1910 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1911 unsigned int i
, freq
;
1913 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
1914 freq
= peer_bi
->freq
[i
];
1915 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1917 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
1918 auth
->freq
[auth
->num_freq
++] = freq
;
1920 if (!auth
->num_freq
) {
1921 wpa_printf(MSG_INFO
,
1922 "DPP: No available channels for initiating DPP Authentication");
1925 auth
->curr_freq
= auth
->freq
[0];
1930 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
1931 struct hostapd_hw_modes
*own_modes
,
1940 if (!own_modes
|| !num_modes
) {
1941 auth
->freq
[0] = 2412;
1942 auth
->freq
[1] = 2437;
1943 auth
->freq
[2] = 2462;
1948 for (m
= 0; m
< num_modes
; m
++) {
1949 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1950 freq
= own_modes
[m
].channels
[c
].freq
;
1951 flag
= own_modes
[m
].channels
[c
].flag
;
1952 if (flag
& (HOSTAPD_CHAN_DISABLED
|
1953 HOSTAPD_CHAN_NO_IR
|
1954 HOSTAPD_CHAN_RADAR
))
1956 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1958 auth
->freq
[auth
->num_freq
++] = freq
;
1959 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
1966 return auth
->num_freq
== 0 ? -1 : 0;
1970 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
1971 struct hostapd_hw_modes
*own_modes
,
1975 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
1978 if (auth
->peer_bi
->num_freq
> 0)
1979 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
1981 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
1985 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1986 * likely channels first. */
1987 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
1988 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
1989 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
1992 auth
->curr_freq
= auth
->freq
[0];
1995 end
= pos
+ sizeof(freqs
);
1996 for (i
= 0; i
< auth
->num_freq
; i
++) {
1997 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
1998 if (os_snprintf_error(end
- pos
, res
))
2003 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2010 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2012 struct dpp_bootstrap_info
*bi
;
2017 return 0; /* already generated */
2019 bi
= os_zalloc(sizeof(*bi
));
2022 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2023 pk
= dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0);
2027 len
= 4; /* "DPP:" */
2028 len
+= 4 + os_strlen(pk
);
2029 bi
->uri
= os_malloc(len
+ 1);
2032 os_snprintf(bi
->uri
, len
+ 1, "DPP:K:%s;;", pk
);
2033 wpa_printf(MSG_DEBUG
,
2034 "DPP: Auto-generated own bootstrapping key info: URI %s",
2037 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2044 dpp_bootstrap_info_free(bi
);
2049 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2050 struct dpp_bootstrap_info
*peer_bi
,
2051 struct dpp_bootstrap_info
*own_bi
,
2052 u8 dpp_allowed_roles
,
2053 unsigned int neg_freq
,
2054 struct hostapd_hw_modes
*own_modes
,
2057 struct dpp_authentication
*auth
;
2059 EVP_PKEY_CTX
*ctx
= NULL
;
2061 struct wpabuf
*pi
= NULL
;
2062 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2063 #ifdef CONFIG_TESTING_OPTIONS
2064 u8 test_hash
[SHA256_MAC_LEN
];
2065 #endif /* CONFIG_TESTING_OPTIONS */
2067 auth
= os_zalloc(sizeof(*auth
));
2070 auth
->msg_ctx
= msg_ctx
;
2071 auth
->initiator
= 1;
2072 auth
->waiting_auth_resp
= 1;
2073 auth
->allowed_roles
= dpp_allowed_roles
;
2074 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2075 auth
->peer_bi
= peer_bi
;
2076 auth
->own_bi
= own_bi
;
2077 auth
->curve
= peer_bi
->curve
;
2079 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2080 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2083 #ifdef CONFIG_TESTING_OPTIONS
2084 if (dpp_nonce_override_len
> 0) {
2085 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2086 nonce_len
= dpp_nonce_override_len
;
2087 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2089 nonce_len
= auth
->curve
->nonce_len
;
2090 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2091 wpa_printf(MSG_ERROR
,
2092 "DPP: Failed to generate I-nonce");
2096 #else /* CONFIG_TESTING_OPTIONS */
2097 nonce_len
= auth
->curve
->nonce_len
;
2098 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2099 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2102 #endif /* CONFIG_TESTING_OPTIONS */
2103 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2105 #ifdef CONFIG_TESTING_OPTIONS
2106 if (dpp_protocol_key_override_len
) {
2107 const struct dpp_curve_params
*tmp_curve
;
2109 wpa_printf(MSG_INFO
,
2110 "DPP: TESTING - override protocol key");
2111 auth
->own_protocol_key
= dpp_set_keypair(
2112 &tmp_curve
, dpp_protocol_key_override
,
2113 dpp_protocol_key_override_len
);
2115 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2117 #else /* CONFIG_TESTING_OPTIONS */
2118 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2119 #endif /* CONFIG_TESTING_OPTIONS */
2120 if (!auth
->own_protocol_key
)
2123 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2127 /* ECDH: M = pI * BR */
2128 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2130 EVP_PKEY_derive_init(ctx
) != 1 ||
2131 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
2132 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2133 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2134 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2135 wpa_printf(MSG_ERROR
,
2136 "DPP: Failed to derive ECDH shared secret: %s",
2137 ERR_error_string(ERR_get_error(), NULL
));
2140 auth
->secret_len
= secret_len
;
2141 EVP_PKEY_CTX_free(ctx
);
2144 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2145 auth
->Mx
, auth
->secret_len
);
2146 auth
->Mx_len
= auth
->secret_len
;
2148 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2149 auth
->curve
->hash_len
) < 0)
2152 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2153 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2155 #ifdef CONFIG_TESTING_OPTIONS
2156 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2157 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2158 r_pubkey_hash
= NULL
;
2159 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2160 wpa_printf(MSG_INFO
,
2161 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2162 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2163 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2164 r_pubkey_hash
= test_hash
;
2165 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2166 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2167 i_pubkey_hash
= NULL
;
2168 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2169 wpa_printf(MSG_INFO
,
2170 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2171 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2172 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2173 i_pubkey_hash
= test_hash
;
2174 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2175 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2178 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2179 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2181 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2182 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2185 #endif /* CONFIG_TESTING_OPTIONS */
2187 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2188 i_pubkey_hash
, neg_freq
);
2194 EVP_PKEY_CTX_free(ctx
);
2197 dpp_auth_deinit(auth
);
2203 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2207 size_t json_len
, clear_len
;
2208 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2212 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2214 nonce_len
= auth
->curve
->nonce_len
;
2215 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2216 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2219 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2220 json_len
= os_strlen(json
);
2221 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
2223 /* { E-nonce, configAttrib }ke */
2224 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2225 clear
= wpabuf_alloc(clear_len
);
2226 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2227 #ifdef CONFIG_TESTING_OPTIONS
2228 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2230 #endif /* CONFIG_TESTING_OPTIONS */
2231 msg
= wpabuf_alloc(attr_len
);
2235 #ifdef CONFIG_TESTING_OPTIONS
2236 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2237 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2240 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2241 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2242 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2243 wpabuf_put_le16(clear
, nonce_len
- 1);
2244 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2247 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2248 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2249 goto skip_wrapped_data
;
2251 #endif /* CONFIG_TESTING_OPTIONS */
2254 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2255 wpabuf_put_le16(clear
, nonce_len
);
2256 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2258 #ifdef CONFIG_TESTING_OPTIONS
2260 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2261 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2262 goto skip_conf_attr_obj
;
2264 #endif /* CONFIG_TESTING_OPTIONS */
2267 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2268 wpabuf_put_le16(clear
, json_len
);
2269 wpabuf_put_data(clear
, json
, json_len
);
2271 #ifdef CONFIG_TESTING_OPTIONS
2273 #endif /* CONFIG_TESTING_OPTIONS */
2275 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2276 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2277 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2280 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2281 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2282 wpabuf_head(clear
), wpabuf_len(clear
),
2283 0, NULL
, NULL
, wrapped
) < 0)
2285 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2286 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2288 #ifdef CONFIG_TESTING_OPTIONS
2289 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2290 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2291 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2294 #endif /* CONFIG_TESTING_OPTIONS */
2296 wpa_hexdump_buf(MSG_DEBUG
,
2297 "DPP: Configuration Request frame attributes", msg
);
2308 static void dpp_auth_success(struct dpp_authentication
*auth
)
2310 wpa_printf(MSG_DEBUG
,
2311 "DPP: Authentication success - clear temporary keys");
2312 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2314 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2316 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2318 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2319 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2321 auth
->auth_success
= 1;
2325 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2327 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2330 size_t i
, num_elem
= 0;
2335 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2336 nonce_len
= auth
->curve
->nonce_len
;
2338 if (auth
->initiator
) {
2339 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2340 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2342 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2345 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2347 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2348 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2350 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2353 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2355 if (!pix
|| !prx
|| !brx
)
2358 addr
[num_elem
] = auth
->i_nonce
;
2359 len
[num_elem
] = nonce_len
;
2362 addr
[num_elem
] = auth
->r_nonce
;
2363 len
[num_elem
] = nonce_len
;
2366 addr
[num_elem
] = wpabuf_head(pix
);
2367 len
[num_elem
] = wpabuf_len(pix
) / 2;
2370 addr
[num_elem
] = wpabuf_head(prx
);
2371 len
[num_elem
] = wpabuf_len(prx
) / 2;
2375 addr
[num_elem
] = wpabuf_head(bix
);
2376 len
[num_elem
] = wpabuf_len(bix
) / 2;
2380 addr
[num_elem
] = wpabuf_head(brx
);
2381 len
[num_elem
] = wpabuf_len(brx
) / 2;
2384 addr
[num_elem
] = &zero
;
2388 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2389 for (i
= 0; i
< num_elem
; i
++)
2390 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2391 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2393 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2394 auth
->curve
->hash_len
);
2404 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2406 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2409 size_t i
, num_elem
= 0;
2414 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2415 nonce_len
= auth
->curve
->nonce_len
;
2417 if (auth
->initiator
) {
2418 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2419 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2421 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2426 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2428 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2429 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2431 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2436 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2438 if (!pix
|| !prx
|| !brx
)
2441 addr
[num_elem
] = auth
->r_nonce
;
2442 len
[num_elem
] = nonce_len
;
2445 addr
[num_elem
] = auth
->i_nonce
;
2446 len
[num_elem
] = nonce_len
;
2449 addr
[num_elem
] = wpabuf_head(prx
);
2450 len
[num_elem
] = wpabuf_len(prx
) / 2;
2453 addr
[num_elem
] = wpabuf_head(pix
);
2454 len
[num_elem
] = wpabuf_len(pix
) / 2;
2457 addr
[num_elem
] = wpabuf_head(brx
);
2458 len
[num_elem
] = wpabuf_len(brx
) / 2;
2462 addr
[num_elem
] = wpabuf_head(bix
);
2463 len
[num_elem
] = wpabuf_len(bix
) / 2;
2467 addr
[num_elem
] = &one
;
2471 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2472 for (i
= 0; i
< num_elem
; i
++)
2473 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2474 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2476 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2477 auth
->curve
->hash_len
);
2487 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2489 const EC_GROUP
*group
;
2491 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2492 const EC_POINT
*BI_point
;
2494 BIGNUM
*lx
, *sum
, *q
;
2495 const BIGNUM
*bR_bn
, *pR_bn
;
2498 /* L = ((bR + pR) modulo q) * BI */
2500 bnctx
= BN_CTX_new();
2504 if (!bnctx
|| !sum
|| !q
|| !lx
)
2506 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2509 BI_point
= EC_KEY_get0_public_key(BI
);
2510 group
= EC_KEY_get0_group(BI
);
2514 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2515 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2518 bR_bn
= EC_KEY_get0_private_key(bR
);
2519 pR_bn
= EC_KEY_get0_private_key(pR
);
2520 if (!bR_bn
|| !pR_bn
)
2522 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2523 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2525 l
= EC_POINT_new(group
);
2527 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2528 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2530 wpa_printf(MSG_ERROR
,
2531 "OpenSSL: failed: %s",
2532 ERR_error_string(ERR_get_error(), NULL
));
2536 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2538 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2539 auth
->Lx_len
= auth
->secret_len
;
2542 EC_POINT_clear_free(l
);
2554 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2556 const EC_GROUP
*group
;
2557 EC_POINT
*l
= NULL
, *sum
= NULL
;
2558 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2559 const EC_POINT
*BR_point
, *PR_point
;
2562 const BIGNUM
*bI_bn
;
2565 /* L = bI * (BR + PR) */
2567 bnctx
= BN_CTX_new();
2571 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2572 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2575 BR_point
= EC_KEY_get0_public_key(BR
);
2576 PR_point
= EC_KEY_get0_public_key(PR
);
2578 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2581 group
= EC_KEY_get0_group(bI
);
2582 bI_bn
= EC_KEY_get0_private_key(bI
);
2583 if (!group
|| !bI_bn
)
2585 sum
= EC_POINT_new(group
);
2586 l
= EC_POINT_new(group
);
2588 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2589 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2590 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2592 wpa_printf(MSG_ERROR
,
2593 "OpenSSL: failed: %s",
2594 ERR_error_string(ERR_get_error(), NULL
));
2598 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2600 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2601 auth
->Lx_len
= auth
->secret_len
;
2604 EC_POINT_clear_free(l
);
2605 EC_POINT_clear_free(sum
);
2615 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2618 EVP_PKEY_CTX
*ctx
= NULL
;
2620 struct wpabuf
*msg
, *pr
= NULL
;
2621 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2622 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2623 size_t wrapped_r_auth_len
;
2625 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2626 enum dpp_status_error status
= DPP_STATUS_OK
;
2627 #ifdef CONFIG_TESTING_OPTIONS
2628 u8 test_hash
[SHA256_MAC_LEN
];
2629 #endif /* CONFIG_TESTING_OPTIONS */
2631 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2635 #ifdef CONFIG_TESTING_OPTIONS
2636 if (dpp_nonce_override_len
> 0) {
2637 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
2638 nonce_len
= dpp_nonce_override_len
;
2639 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
2641 nonce_len
= auth
->curve
->nonce_len
;
2642 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2643 wpa_printf(MSG_ERROR
,
2644 "DPP: Failed to generate R-nonce");
2648 #else /* CONFIG_TESTING_OPTIONS */
2649 nonce_len
= auth
->curve
->nonce_len
;
2650 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2651 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2654 #endif /* CONFIG_TESTING_OPTIONS */
2655 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2657 #ifdef CONFIG_TESTING_OPTIONS
2658 if (dpp_protocol_key_override_len
) {
2659 const struct dpp_curve_params
*tmp_curve
;
2661 wpa_printf(MSG_INFO
,
2662 "DPP: TESTING - override protocol key");
2663 auth
->own_protocol_key
= dpp_set_keypair(
2664 &tmp_curve
, dpp_protocol_key_override
,
2665 dpp_protocol_key_override_len
);
2667 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2669 #else /* CONFIG_TESTING_OPTIONS */
2670 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2671 #endif /* CONFIG_TESTING_OPTIONS */
2672 if (!auth
->own_protocol_key
)
2675 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2679 /* ECDH: N = pR * PI */
2680 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2682 EVP_PKEY_derive_init(ctx
) != 1 ||
2683 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2684 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2685 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2686 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2687 wpa_printf(MSG_ERROR
,
2688 "DPP: Failed to derive ECDH shared secret: %s",
2689 ERR_error_string(ERR_get_error(), NULL
));
2692 EVP_PKEY_CTX_free(ctx
);
2695 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2696 auth
->Nx
, auth
->secret_len
);
2697 auth
->Nx_len
= auth
->secret_len
;
2699 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2700 auth
->curve
->hash_len
) < 0)
2703 if (auth
->own_bi
&& auth
->peer_bi
) {
2704 /* Mutual authentication */
2705 if (dpp_auth_derive_l_responder(auth
) < 0)
2709 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2712 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2713 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2714 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2715 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2717 #ifdef CONFIG_TESTING_OPTIONS
2718 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2719 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2720 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2722 #endif /* CONFIG_TESTING_OPTIONS */
2723 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2724 r_auth
, 4 + auth
->curve
->hash_len
,
2725 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2727 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2728 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2729 wrapped_r_auth
, wrapped_r_auth_len
);
2730 w_r_auth
= wrapped_r_auth
;
2732 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2734 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2736 i_pubkey_hash
= NULL
;
2738 i_nonce
= auth
->i_nonce
;
2739 r_nonce
= auth
->r_nonce
;
2741 #ifdef CONFIG_TESTING_OPTIONS
2742 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2743 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2744 r_pubkey_hash
= NULL
;
2745 } else if (dpp_test
==
2746 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2747 wpa_printf(MSG_INFO
,
2748 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2749 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2750 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2751 r_pubkey_hash
= test_hash
;
2752 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2753 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2754 i_pubkey_hash
= NULL
;
2755 } else if (dpp_test
==
2756 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2757 wpa_printf(MSG_INFO
,
2758 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2760 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2762 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2763 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2764 i_pubkey_hash
= test_hash
;
2765 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2766 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2769 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
2770 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
2772 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2773 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
2775 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2776 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2778 wrapped_r_auth_len
= 0;
2779 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2780 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2782 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
2783 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
2785 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2786 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2788 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2789 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2792 #endif /* CONFIG_TESTING_OPTIONS */
2794 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2795 r_pubkey_hash
, i_pubkey_hash
,
2797 w_r_auth
, wrapped_r_auth_len
,
2801 wpabuf_free(auth
->resp_msg
);
2802 auth
->resp_msg
= msg
;
2810 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2811 enum dpp_status_error status
)
2814 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2815 #ifdef CONFIG_TESTING_OPTIONS
2816 u8 test_hash
[SHA256_MAC_LEN
];
2817 #endif /* CONFIG_TESTING_OPTIONS */
2821 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2823 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2825 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2827 i_pubkey_hash
= NULL
;
2829 i_nonce
= auth
->i_nonce
;
2831 #ifdef CONFIG_TESTING_OPTIONS
2832 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2833 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2834 r_pubkey_hash
= NULL
;
2835 } else if (dpp_test
==
2836 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2837 wpa_printf(MSG_INFO
,
2838 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2839 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2840 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2841 r_pubkey_hash
= test_hash
;
2842 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2843 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2844 i_pubkey_hash
= NULL
;
2845 } else if (dpp_test
==
2846 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2847 wpa_printf(MSG_INFO
,
2848 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2850 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2852 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2853 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2854 i_pubkey_hash
= test_hash
;
2855 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2856 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2858 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2859 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2862 #endif /* CONFIG_TESTING_OPTIONS */
2864 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
2865 r_pubkey_hash
, i_pubkey_hash
,
2866 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
2869 wpabuf_free(auth
->resp_msg
);
2870 auth
->resp_msg
= msg
;
2875 struct dpp_authentication
*
2876 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
2877 struct dpp_bootstrap_info
*peer_bi
,
2878 struct dpp_bootstrap_info
*own_bi
,
2879 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
2882 EVP_PKEY
*pi
= NULL
;
2883 EVP_PKEY_CTX
*ctx
= NULL
;
2887 u8
*unwrapped
= NULL
;
2888 size_t unwrapped_len
= 0;
2889 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
2891 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
2892 i_bootstrap_len
, channel_len
;
2893 struct dpp_authentication
*auth
= NULL
;
2895 #ifdef CONFIG_TESTING_OPTIONS
2896 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
2897 wpa_printf(MSG_INFO
,
2898 "DPP: TESTING - stop at Authentication Request");
2901 #endif /* CONFIG_TESTING_OPTIONS */
2903 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2905 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
2906 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
2907 "Missing or invalid required Wrapped Data attribute");
2910 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
2911 wrapped_data
, wrapped_data_len
);
2912 attr_len
= wrapped_data
- 4 - attr_start
;
2914 auth
= os_zalloc(sizeof(*auth
));
2917 auth
->msg_ctx
= msg_ctx
;
2918 auth
->peer_bi
= peer_bi
;
2919 auth
->own_bi
= own_bi
;
2920 auth
->curve
= own_bi
->curve
;
2921 auth
->curr_freq
= freq
;
2923 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
2928 if (channel_len
< 2) {
2929 dpp_auth_fail(auth
, "Too short Channel attribute");
2933 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
2934 wpa_printf(MSG_DEBUG
,
2935 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2936 channel
[0], channel
[1], neg_freq
);
2939 "Unsupported Channel attribute value");
2943 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
2944 wpa_printf(MSG_DEBUG
,
2945 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2947 auth
->curr_freq
= neg_freq
;
2951 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
2955 "Missing required Initiator Protocol Key attribute");
2958 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
2959 i_proto
, i_proto_len
);
2962 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
2964 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
2967 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
2969 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
2971 EVP_PKEY_derive_init(ctx
) != 1 ||
2972 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
2973 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2974 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2975 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2976 wpa_printf(MSG_ERROR
,
2977 "DPP: Failed to derive ECDH shared secret: %s",
2978 ERR_error_string(ERR_get_error(), NULL
));
2979 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
2982 auth
->secret_len
= secret_len
;
2983 EVP_PKEY_CTX_free(ctx
);
2986 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2987 auth
->Mx
, auth
->secret_len
);
2988 auth
->Mx_len
= auth
->secret_len
;
2990 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2991 auth
->curve
->hash_len
) < 0)
2995 len
[0] = DPP_HDR_LEN
;
2996 addr
[1] = attr_start
;
2998 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2999 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3000 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3001 wrapped_data
, wrapped_data_len
);
3002 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3003 unwrapped
= os_malloc(unwrapped_len
);
3006 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3007 wrapped_data
, wrapped_data_len
,
3008 2, addr
, len
, unwrapped
) < 0) {
3009 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3012 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3013 unwrapped
, unwrapped_len
);
3015 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3016 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3020 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3022 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3023 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3026 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3027 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3029 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3030 DPP_ATTR_I_CAPABILITIES
,
3032 if (!i_capab
|| i_capab_len
< 1) {
3033 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3036 auth
->i_capab
= i_capab
[0];
3037 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3039 bin_clear_free(unwrapped
, unwrapped_len
);
3042 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3043 case DPP_CAPAB_ENROLLEE
:
3044 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3045 wpa_printf(MSG_DEBUG
,
3046 "DPP: Local policy does not allow Configurator role");
3047 goto not_compatible
;
3049 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3050 auth
->configurator
= 1;
3052 case DPP_CAPAB_CONFIGURATOR
:
3053 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3054 wpa_printf(MSG_DEBUG
,
3055 "DPP: Local policy does not allow Enrollee role");
3056 goto not_compatible
;
3058 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3059 auth
->configurator
= 0;
3061 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3062 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3063 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3064 auth
->configurator
= 0;
3065 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3066 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3067 auth
->configurator
= 1;
3069 wpa_printf(MSG_DEBUG
,
3070 "DPP: Local policy does not allow Configurator/Enrollee role");
3071 goto not_compatible
;
3075 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3076 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3077 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3078 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3082 auth
->peer_protocol_key
= pi
;
3084 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3085 char hex
[SHA256_MAC_LEN
* 2 + 1];
3087 wpa_printf(MSG_DEBUG
,
3088 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3089 if (dpp_auth_build_resp_status(auth
,
3090 DPP_STATUS_RESPONSE_PENDING
) < 0)
3092 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3093 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3095 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3096 auth
->response_pending
= 1;
3097 os_memcpy(auth
->waiting_pubkey_hash
,
3098 i_bootstrap
, i_bootstrap_len
);
3099 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3105 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3109 if (dpp_auth_build_resp_ok(auth
) < 0)
3115 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3116 "i-capab=0x%02x", auth
->i_capab
);
3117 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3118 auth
->configurator
= 1;
3120 auth
->configurator
= 0;
3121 auth
->peer_protocol_key
= pi
;
3123 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3126 auth
->remove_on_tx_status
= 1;
3129 bin_clear_free(unwrapped
, unwrapped_len
);
3131 EVP_PKEY_CTX_free(ctx
);
3132 dpp_auth_deinit(auth
);
3137 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3138 struct dpp_bootstrap_info
*peer_bi
)
3140 if (!auth
|| !auth
->response_pending
||
3141 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3142 SHA256_MAC_LEN
) != 0)
3145 wpa_printf(MSG_DEBUG
,
3146 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3147 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3148 auth
->peer_bi
= peer_bi
;
3150 if (dpp_auth_build_resp_ok(auth
) < 0)
3157 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3158 enum dpp_status_error status
)
3161 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3163 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3166 size_t len
[2], attr_len
;
3168 u8
*wrapped_r_nonce
;
3169 u8
*attr_start
, *attr_end
;
3170 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3171 #ifdef CONFIG_TESTING_OPTIONS
3172 u8 test_hash
[SHA256_MAC_LEN
];
3173 #endif /* CONFIG_TESTING_OPTIONS */
3175 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3177 i_auth_len
= 4 + auth
->curve
->hash_len
;
3178 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3179 /* Build DPP Authentication Confirmation frame attributes */
3180 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3181 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3182 #ifdef CONFIG_TESTING_OPTIONS
3183 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3185 #endif /* CONFIG_TESTING_OPTIONS */
3186 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3190 attr_start
= wpabuf_put(msg
, 0);
3192 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3194 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3196 i_pubkey_hash
= NULL
;
3198 #ifdef CONFIG_TESTING_OPTIONS
3199 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3200 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3202 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3203 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3206 #endif /* CONFIG_TESTING_OPTIONS */
3209 dpp_build_attr_status(msg
, status
);
3211 #ifdef CONFIG_TESTING_OPTIONS
3213 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3214 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3215 r_pubkey_hash
= NULL
;
3216 } else if (dpp_test
==
3217 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3218 wpa_printf(MSG_INFO
,
3219 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3220 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3221 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3222 r_pubkey_hash
= test_hash
;
3223 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3224 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3225 i_pubkey_hash
= NULL
;
3226 } else if (dpp_test
==
3227 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3228 wpa_printf(MSG_INFO
,
3229 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3231 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3233 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3234 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3235 i_pubkey_hash
= test_hash
;
3237 #endif /* CONFIG_TESTING_OPTIONS */
3239 /* Responder Bootstrapping Key Hash */
3240 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3242 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3243 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3245 #ifdef CONFIG_TESTING_OPTIONS
3246 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3247 goto skip_wrapped_data
;
3248 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3250 #endif /* CONFIG_TESTING_OPTIONS */
3252 attr_end
= wpabuf_put(msg
, 0);
3254 /* OUI, OUI type, Crypto Suite, DPP frame type */
3255 addr
[0] = wpabuf_head_u8(msg
) + 2;
3256 len
[0] = 3 + 1 + 1 + 1;
3257 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3259 /* Attributes before Wrapped Data */
3260 addr
[1] = attr_start
;
3261 len
[1] = attr_end
- attr_start
;
3262 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3264 if (status
== DPP_STATUS_OK
) {
3265 /* I-auth wrapped with ke */
3266 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3267 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3268 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3270 #ifdef CONFIG_TESTING_OPTIONS
3271 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3273 #endif /* CONFIG_TESTING_OPTIONS */
3275 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3277 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3278 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3279 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3282 #ifdef CONFIG_TESTING_OPTIONS
3283 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3284 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3285 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3288 #endif /* CONFIG_TESTING_OPTIONS */
3289 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3291 2, addr
, len
, wrapped_i_auth
) < 0)
3293 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3294 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3296 /* R-nonce wrapped with k2 */
3297 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3298 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3299 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3301 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3302 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3303 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3305 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3306 r_nonce
, r_nonce_len
,
3307 2, addr
, len
, wrapped_r_nonce
) < 0)
3309 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3310 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3313 #ifdef CONFIG_TESTING_OPTIONS
3314 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3315 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3316 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3319 #endif /* CONFIG_TESTING_OPTIONS */
3321 wpa_hexdump_buf(MSG_DEBUG
,
3322 "DPP: Authentication Confirmation frame attributes",
3324 if (status
== DPP_STATUS_OK
)
3325 dpp_auth_success(auth
);
3336 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3337 const u8
*attr_start
, size_t attr_len
,
3338 const u8
*wrapped_data
, u16 wrapped_data_len
,
3339 enum dpp_status_error status
)
3343 u8
*unwrapped
= NULL
;
3344 size_t unwrapped_len
= 0;
3345 const u8
*i_nonce
, *r_capab
;
3346 u16 i_nonce_len
, r_capab_len
;
3348 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3349 wpa_printf(MSG_DEBUG
,
3350 "DPP: Responder reported incompatible roles");
3351 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3352 wpa_printf(MSG_DEBUG
,
3353 "DPP: Responder reported more time needed");
3355 wpa_printf(MSG_DEBUG
,
3356 "DPP: Responder reported failure (status %d)",
3358 dpp_auth_fail(auth
, "Responder reported failure");
3363 len
[0] = DPP_HDR_LEN
;
3364 addr
[1] = attr_start
;
3366 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3367 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3368 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3369 wrapped_data
, wrapped_data_len
);
3370 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3371 unwrapped
= os_malloc(unwrapped_len
);
3374 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3375 wrapped_data
, wrapped_data_len
,
3376 2, addr
, len
, unwrapped
) < 0) {
3377 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3380 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3381 unwrapped
, unwrapped_len
);
3383 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3384 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3388 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3390 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3391 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3394 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3395 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3396 dpp_auth_fail(auth
, "I-nonce mismatch");
3400 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3401 DPP_ATTR_R_CAPABILITIES
,
3403 if (!r_capab
|| r_capab_len
< 1) {
3404 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3407 auth
->r_capab
= r_capab
[0];
3408 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3409 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3410 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3411 "r-capab=0x%02x", auth
->r_capab
);
3412 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3413 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3415 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3416 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3417 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3418 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3421 wpa_printf(MSG_DEBUG
,
3422 "DPP: Continue waiting for full DPP Authentication Response");
3423 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3424 DPP_EVENT_RESPONSE_PENDING
"%s",
3425 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3429 bin_clear_free(unwrapped
, unwrapped_len
);
3434 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3435 const u8
*attr_start
, size_t attr_len
)
3438 EVP_PKEY_CTX
*ctx
= NULL
;
3442 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3443 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3444 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3445 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3446 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3447 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3448 wrapped2_len
, r_auth_len
;
3449 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3452 #ifdef CONFIG_TESTING_OPTIONS
3453 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3454 wpa_printf(MSG_INFO
,
3455 "DPP: TESTING - stop at Authentication Response");
3458 #endif /* CONFIG_TESTING_OPTIONS */
3460 if (!auth
->initiator
|| !auth
->peer_bi
) {
3461 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3465 auth
->waiting_auth_resp
= 0;
3467 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3469 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3471 "Missing or invalid required Wrapped Data attribute");
3474 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3475 wrapped_data
, wrapped_data_len
);
3477 attr_len
= wrapped_data
- 4 - attr_start
;
3479 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3480 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3482 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3484 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3487 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3488 r_bootstrap
, r_bootstrap_len
);
3489 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3490 SHA256_MAC_LEN
) != 0) {
3492 "Unexpected Responder Bootstrapping Key Hash value");
3493 wpa_hexdump(MSG_DEBUG
,
3494 "DPP: Expected Responder Bootstrapping Key Hash",
3495 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3499 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3500 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3503 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3505 "Invalid Initiator Bootstrapping Key Hash attribute");
3508 wpa_hexdump(MSG_MSGDUMP
,
3509 "DPP: Initiator Bootstrapping Key Hash",
3510 i_bootstrap
, i_bootstrap_len
);
3511 if (!auth
->own_bi
||
3512 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3513 SHA256_MAC_LEN
) != 0) {
3515 "Initiator Bootstrapping Key Hash attribute did not match");
3518 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3519 /* PKEX bootstrapping mandates use of mutual authentication */
3521 "Missing Initiator Bootstrapping Key Hash attribute");
3525 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3527 if (!status
|| status_len
< 1) {
3529 "Missing or invalid required DPP Status attribute");
3532 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3533 auth
->auth_resp_status
= status
[0];
3534 if (status
[0] != DPP_STATUS_OK
) {
3535 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3536 attr_len
, wrapped_data
,
3537 wrapped_data_len
, status
[0]);
3541 if (!i_bootstrap
&& auth
->own_bi
) {
3542 wpa_printf(MSG_DEBUG
,
3543 "DPP: Responder decided not to use mutual authentication");
3544 auth
->own_bi
= NULL
;
3547 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3548 auth
->own_bi
!= NULL
);
3550 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3554 "Missing required Responder Protocol Key attribute");
3557 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3558 r_proto
, r_proto_len
);
3561 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3563 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3566 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3568 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3570 EVP_PKEY_derive_init(ctx
) != 1 ||
3571 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3572 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3573 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3574 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3575 wpa_printf(MSG_ERROR
,
3576 "DPP: Failed to derive ECDH shared secret: %s",
3577 ERR_error_string(ERR_get_error(), NULL
));
3578 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3581 EVP_PKEY_CTX_free(ctx
);
3583 auth
->peer_protocol_key
= pr
;
3586 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3587 auth
->Nx
, auth
->secret_len
);
3588 auth
->Nx_len
= auth
->secret_len
;
3590 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3591 auth
->curve
->hash_len
) < 0)
3595 len
[0] = DPP_HDR_LEN
;
3596 addr
[1] = attr_start
;
3598 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3599 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3600 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3601 wrapped_data
, wrapped_data_len
);
3602 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3603 unwrapped
= os_malloc(unwrapped_len
);
3606 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3607 wrapped_data
, wrapped_data_len
,
3608 2, addr
, len
, unwrapped
) < 0) {
3609 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3612 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3613 unwrapped
, unwrapped_len
);
3615 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3616 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3620 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3622 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3623 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3626 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3627 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3629 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3631 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3632 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3635 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3636 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3637 dpp_auth_fail(auth
, "I-nonce mismatch");
3642 /* Mutual authentication */
3643 if (dpp_auth_derive_l_initiator(auth
) < 0)
3647 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3648 DPP_ATTR_R_CAPABILITIES
,
3650 if (!r_capab
|| r_capab_len
< 1) {
3651 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3654 auth
->r_capab
= r_capab
[0];
3655 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3656 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3657 if ((auth
->allowed_roles
==
3658 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3659 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3660 /* Peer selected its role, so move from "either role" to the
3661 * role that is compatible with peer's selection. */
3662 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3663 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3664 auth
->configurator
? "Configurator" : "Enrollee");
3665 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3666 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3667 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3668 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3669 "Unexpected role in R-capabilities 0x%02x",
3671 if (role
!= DPP_CAPAB_ENROLLEE
&&
3672 role
!= DPP_CAPAB_CONFIGURATOR
)
3674 bin_clear_free(unwrapped
, unwrapped_len
);
3675 auth
->remove_on_tx_status
= 1;
3676 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3679 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3680 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3681 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3683 "Missing or invalid Secondary Wrapped Data");
3687 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3688 wrapped2
, wrapped2_len
);
3690 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3693 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3694 unwrapped2
= os_malloc(unwrapped2_len
);
3697 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3698 wrapped2
, wrapped2_len
,
3699 0, NULL
, NULL
, unwrapped2
) < 0) {
3700 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3703 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3704 unwrapped2
, unwrapped2_len
);
3706 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3708 "Invalid attribute in secondary unwrapped data");
3712 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3714 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3716 "Missing or invalid Responder Authenticating Tag");
3719 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3720 r_auth
, r_auth_len
);
3721 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3722 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3724 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3725 r_auth2
, r_auth_len
);
3726 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3727 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3728 bin_clear_free(unwrapped
, unwrapped_len
);
3729 bin_clear_free(unwrapped2
, unwrapped2_len
);
3730 auth
->remove_on_tx_status
= 1;
3731 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3734 bin_clear_free(unwrapped
, unwrapped_len
);
3735 bin_clear_free(unwrapped2
, unwrapped2_len
);
3737 #ifdef CONFIG_TESTING_OPTIONS
3738 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
3739 wpa_printf(MSG_INFO
,
3740 "DPP: TESTING - Authentication Response in place of Confirm");
3741 if (dpp_auth_build_resp_ok(auth
) < 0)
3743 return wpabuf_dup(auth
->resp_msg
);
3745 #endif /* CONFIG_TESTING_OPTIONS */
3747 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3750 bin_clear_free(unwrapped
, unwrapped_len
);
3751 bin_clear_free(unwrapped2
, unwrapped2_len
);
3753 EVP_PKEY_CTX_free(ctx
);
3758 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3760 const u8
*attr_start
, size_t attr_len
,
3761 const u8
*wrapped_data
,
3762 u16 wrapped_data_len
,
3763 enum dpp_status_error status
)
3767 u8
*unwrapped
= NULL
;
3768 size_t unwrapped_len
= 0;
3772 /* Authentication Confirm failure cases are expected to include
3773 * {R-nonce}k2 in the Wrapped Data attribute. */
3776 len
[0] = DPP_HDR_LEN
;
3777 addr
[1] = attr_start
;
3779 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3780 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3781 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3782 wrapped_data
, wrapped_data_len
);
3783 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3784 unwrapped
= os_malloc(unwrapped_len
);
3786 dpp_auth_fail(auth
, "Authentication failed");
3789 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3790 wrapped_data
, wrapped_data_len
,
3791 2, addr
, len
, unwrapped
) < 0) {
3792 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3795 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3796 unwrapped
, unwrapped_len
);
3798 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3799 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3803 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3805 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3806 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3809 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3810 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3811 r_nonce
, r_nonce_len
);
3812 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3813 auth
->r_nonce
, r_nonce_len
);
3814 dpp_auth_fail(auth
, "R-nonce mismatch");
3818 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3819 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3820 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3821 dpp_auth_fail(auth
, "Peer reported authentication failure)");
3824 bin_clear_free(unwrapped
, unwrapped_len
);
3829 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3830 const u8
*attr_start
, size_t attr_len
)
3832 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
3833 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3837 u8
*unwrapped
= NULL
;
3838 size_t unwrapped_len
= 0;
3839 u8 i_auth2
[DPP_MAX_HASH_LEN
];
3841 #ifdef CONFIG_TESTING_OPTIONS
3842 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
3843 wpa_printf(MSG_INFO
,
3844 "DPP: TESTING - stop at Authentication Confirm");
3847 #endif /* CONFIG_TESTING_OPTIONS */
3849 if (auth
->initiator
|| !auth
->own_bi
) {
3850 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
3854 auth
->waiting_auth_conf
= 0;
3856 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3858 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3860 "Missing or invalid required Wrapped Data attribute");
3863 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3864 wrapped_data
, wrapped_data_len
);
3866 attr_len
= wrapped_data
- 4 - attr_start
;
3868 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3869 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3871 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3873 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3876 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3877 r_bootstrap
, r_bootstrap_len
);
3878 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
3879 SHA256_MAC_LEN
) != 0) {
3880 wpa_hexdump(MSG_DEBUG
,
3881 "DPP: Expected Responder Bootstrapping Key Hash",
3882 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3884 "Responder Bootstrapping Key Hash mismatch");
3888 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3889 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3892 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3894 "Invalid Initiator Bootstrapping Key Hash attribute");
3897 wpa_hexdump(MSG_MSGDUMP
,
3898 "DPP: Initiator Bootstrapping Key Hash",
3899 i_bootstrap
, i_bootstrap_len
);
3900 if (!auth
->peer_bi
||
3901 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3902 SHA256_MAC_LEN
) != 0) {
3904 "Initiator Bootstrapping Key Hash mismatch");
3907 } else if (auth
->peer_bi
) {
3908 /* Mutual authentication and peer did not include its
3909 * Bootstrapping Key Hash attribute. */
3911 "Missing Initiator Bootstrapping Key Hash attribute");
3915 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3917 if (!status
|| status_len
< 1) {
3919 "Missing or invalid required DPP Status attribute");
3922 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3923 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
3924 status
[0] == DPP_STATUS_AUTH_FAILURE
)
3925 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
3926 attr_len
, wrapped_data
,
3927 wrapped_data_len
, status
[0]);
3929 if (status
[0] != DPP_STATUS_OK
) {
3930 dpp_auth_fail(auth
, "Authentication failed");
3935 len
[0] = DPP_HDR_LEN
;
3936 addr
[1] = attr_start
;
3938 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3939 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3940 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3941 wrapped_data
, wrapped_data_len
);
3942 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3943 unwrapped
= os_malloc(unwrapped_len
);
3946 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3947 wrapped_data
, wrapped_data_len
,
3948 2, addr
, len
, unwrapped
) < 0) {
3949 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3952 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3953 unwrapped
, unwrapped_len
);
3955 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3956 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3960 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
3962 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
3964 "Missing or invalid Initiator Authenticating Tag");
3967 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
3968 i_auth
, i_auth_len
);
3969 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3970 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
3972 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
3973 i_auth2
, i_auth_len
);
3974 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
3975 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
3979 bin_clear_free(unwrapped
, unwrapped_len
);
3980 dpp_auth_success(auth
);
3983 bin_clear_free(unwrapped
, unwrapped_len
);
3988 void dpp_configuration_free(struct dpp_configuration
*conf
)
3992 str_clear_free(conf
->passphrase
);
3993 os_free(conf
->group_id
);
3994 bin_clear_free(conf
, sizeof(*conf
));
3998 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4002 dpp_configuration_free(auth
->conf_ap
);
4003 dpp_configuration_free(auth
->conf_sta
);
4004 EVP_PKEY_free(auth
->own_protocol_key
);
4005 EVP_PKEY_free(auth
->peer_protocol_key
);
4006 wpabuf_free(auth
->req_msg
);
4007 wpabuf_free(auth
->resp_msg
);
4008 wpabuf_free(auth
->conf_req
);
4009 os_free(auth
->connector
);
4010 wpabuf_free(auth
->net_access_key
);
4011 wpabuf_free(auth
->c_sign_key
);
4012 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4013 #ifdef CONFIG_TESTING_OPTIONS
4014 os_free(auth
->config_obj_override
);
4015 os_free(auth
->discovery_override
);
4016 os_free(auth
->groups_override
);
4017 #endif /* CONFIG_TESTING_OPTIONS */
4018 bin_clear_free(auth
, sizeof(*auth
));
4022 static struct wpabuf
*
4023 dpp_build_conf_start(struct dpp_authentication
*auth
,
4024 struct dpp_configuration
*conf
, size_t tailroom
)
4027 char ssid
[6 * sizeof(conf
->ssid
) + 1];
4029 #ifdef CONFIG_TESTING_OPTIONS
4030 if (auth
->discovery_override
)
4031 tailroom
+= os_strlen(auth
->discovery_override
);
4032 #endif /* CONFIG_TESTING_OPTIONS */
4034 buf
= wpabuf_alloc(200 + tailroom
);
4037 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4038 #ifdef CONFIG_TESTING_OPTIONS
4039 if (auth
->discovery_override
) {
4040 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4041 auth
->discovery_override
);
4042 wpabuf_put_str(buf
, auth
->discovery_override
);
4043 wpabuf_put_u8(buf
, ',');
4046 #endif /* CONFIG_TESTING_OPTIONS */
4047 wpabuf_put_str(buf
, "{\"ssid\":\"");
4048 json_escape_string(ssid
, sizeof(ssid
),
4049 (const char *) conf
->ssid
, conf
->ssid_len
);
4050 wpabuf_put_str(buf
, ssid
);
4051 wpabuf_put_str(buf
, "\"},");
4057 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4058 const char *kid
, const struct dpp_curve_params
*curve
)
4062 char *x
= NULL
, *y
= NULL
;
4065 pub
= dpp_get_pubkey_point(key
, 0);
4068 pos
= wpabuf_head(pub
);
4069 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4070 pos
+= curve
->prime_len
;
4071 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4075 wpabuf_put_str(buf
, "\"");
4076 wpabuf_put_str(buf
, name
);
4077 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
4078 wpabuf_put_str(buf
, curve
->jwk_crv
);
4079 wpabuf_put_str(buf
, "\",\"x\":\"");
4080 wpabuf_put_str(buf
, x
);
4081 wpabuf_put_str(buf
, "\",\"y\":\"");
4082 wpabuf_put_str(buf
, y
);
4084 wpabuf_put_str(buf
, "\",\"kid\":\"");
4085 wpabuf_put_str(buf
, kid
);
4087 wpabuf_put_str(buf
, "\"}");
4097 static struct wpabuf
*
4098 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
4099 struct dpp_configuration
*conf
)
4101 struct wpabuf
*buf
= NULL
;
4102 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4104 const struct dpp_curve_params
*curve
;
4105 char jws_prot_hdr
[100];
4106 size_t signed1_len
, signed2_len
, signed3_len
;
4107 struct wpabuf
*dppcon
= NULL
;
4108 unsigned char *signature
= NULL
;
4109 const unsigned char *p
;
4110 size_t signature_len
;
4111 EVP_MD_CTX
*md_ctx
= NULL
;
4112 ECDSA_SIG
*sig
= NULL
;
4114 const EVP_MD
*sign_md
;
4115 const BIGNUM
*r
, *s
;
4116 size_t extra_len
= 1000;
4119 wpa_printf(MSG_INFO
,
4120 "DPP: No configurator specified - cannot generate DPP config object");
4123 curve
= auth
->conf
->curve
;
4124 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4125 sign_md
= EVP_sha256();
4126 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4127 sign_md
= EVP_sha384();
4128 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4129 sign_md
= EVP_sha512();
4131 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4135 #ifdef CONFIG_TESTING_OPTIONS
4136 if (auth
->groups_override
)
4137 extra_len
+= os_strlen(auth
->groups_override
);
4138 #endif /* CONFIG_TESTING_OPTIONS */
4141 extra_len
+= os_strlen(conf
->group_id
);
4143 /* Connector (JSON dppCon object) */
4144 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4147 #ifdef CONFIG_TESTING_OPTIONS
4148 if (auth
->groups_override
) {
4149 wpabuf_put_u8(dppcon
, '{');
4150 if (auth
->groups_override
) {
4151 wpa_printf(MSG_DEBUG
,
4152 "DPP: TESTING - groups override: '%s'",
4153 auth
->groups_override
);
4154 wpabuf_put_str(dppcon
, "\"groups\":");
4155 wpabuf_put_str(dppcon
, auth
->groups_override
);
4156 wpabuf_put_u8(dppcon
, ',');
4160 #endif /* CONFIG_TESTING_OPTIONS */
4161 wpabuf_printf(dppcon
, "{\"groups\":[{\"groupId\":\"%s\",",
4162 conf
->group_id
? conf
->group_id
: "*");
4163 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
4164 #ifdef CONFIG_TESTING_OPTIONS
4166 #endif /* CONFIG_TESTING_OPTIONS */
4167 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4169 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4172 if (conf
->netaccesskey_expiry
) {
4175 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4176 wpa_printf(MSG_DEBUG
,
4177 "DPP: Failed to generate expiry string");
4180 wpabuf_printf(dppcon
,
4181 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4182 tm
.year
, tm
.month
, tm
.day
,
4183 tm
.hour
, tm
.min
, tm
.sec
);
4185 wpabuf_put_u8(dppcon
, '}');
4186 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4187 (const char *) wpabuf_head(dppcon
));
4189 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
4190 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4191 auth
->conf
->kid
, curve
->jws_alg
);
4192 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
4193 os_strlen(jws_prot_hdr
),
4195 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
4198 if (!signed1
|| !signed2
)
4201 md_ctx
= EVP_MD_CTX_create();
4206 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4207 auth
->conf
->csign
) != 1) {
4208 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4209 ERR_error_string(ERR_get_error(), NULL
));
4212 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4213 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4214 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4215 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4216 ERR_error_string(ERR_get_error(), NULL
));
4219 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4220 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4221 ERR_error_string(ERR_get_error(), NULL
));
4224 signature
= os_malloc(signature_len
);
4227 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4228 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4229 ERR_error_string(ERR_get_error(), NULL
));
4232 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4233 signature
, signature_len
);
4234 /* Convert to raw coordinates r,s */
4236 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4239 ECDSA_SIG_get0(sig
, &r
, &s
);
4240 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4241 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4242 curve
->prime_len
) < 0)
4244 signature_len
= 2 * curve
->prime_len
;
4245 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4246 signature
, signature_len
);
4247 signed3
= (char *) base64_url_encode(signature
, signature_len
,
4253 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4254 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4255 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4259 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
4260 wpabuf_put_str(buf
, signed1
);
4261 wpabuf_put_u8(buf
, '.');
4262 wpabuf_put_str(buf
, signed2
);
4263 wpabuf_put_u8(buf
, '.');
4264 wpabuf_put_str(buf
, signed3
);
4265 wpabuf_put_str(buf
, "\",");
4266 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4268 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4272 wpabuf_put_str(buf
, "}}");
4274 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4275 wpabuf_head(buf
), wpabuf_len(buf
));
4278 EVP_MD_CTX_destroy(md_ctx
);
4279 ECDSA_SIG_free(sig
);
4284 wpabuf_free(dppcon
);
4287 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4294 static struct wpabuf
*
4295 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
4296 struct dpp_configuration
*conf
)
4300 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4304 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf
->akm
));
4305 if (conf
->passphrase
) {
4306 char pass
[63 * 6 + 1];
4308 if (os_strlen(conf
->passphrase
) > 63) {
4313 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
4314 os_strlen(conf
->passphrase
));
4315 wpabuf_put_str(buf
, "\"pass\":\"");
4316 wpabuf_put_str(buf
, pass
);
4317 wpabuf_put_str(buf
, "\"");
4319 char psk
[2 * sizeof(conf
->psk
) + 1];
4321 wpa_snprintf_hex(psk
, sizeof(psk
),
4322 conf
->psk
, sizeof(conf
->psk
));
4323 wpabuf_put_str(buf
, "\"psk_hex\":\"");
4324 wpabuf_put_str(buf
, psk
);
4325 wpabuf_put_str(buf
, "\"");
4327 wpabuf_put_str(buf
, "}}");
4329 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4330 wpabuf_head(buf
), wpabuf_len(buf
));
4336 static struct wpabuf
*
4337 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
4339 struct dpp_configuration
*conf
;
4341 #ifdef CONFIG_TESTING_OPTIONS
4342 if (auth
->config_obj_override
) {
4343 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
4344 return wpabuf_alloc_copy(auth
->config_obj_override
,
4345 os_strlen(auth
->config_obj_override
));
4347 #endif /* CONFIG_TESTING_OPTIONS */
4349 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
4351 wpa_printf(MSG_DEBUG
,
4352 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4357 if (conf
->akm
== DPP_AKM_DPP
)
4358 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
4359 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
4363 static struct wpabuf
*
4364 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
4365 u16 e_nonce_len
, int ap
)
4367 struct wpabuf
*conf
;
4368 size_t clear_len
, attr_len
;
4369 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
4373 enum dpp_status_error status
;
4375 conf
= dpp_build_conf_obj(auth
, ap
);
4377 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4378 wpabuf_head(conf
), wpabuf_len(conf
));
4380 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
4382 /* { E-nonce, configurationObject}ke */
4383 clear_len
= 4 + e_nonce_len
;
4385 clear_len
+= 4 + wpabuf_len(conf
);
4386 clear
= wpabuf_alloc(clear_len
);
4387 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
4388 #ifdef CONFIG_TESTING_OPTIONS
4389 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
4391 #endif /* CONFIG_TESTING_OPTIONS */
4392 msg
= wpabuf_alloc(attr_len
);
4396 #ifdef CONFIG_TESTING_OPTIONS
4397 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
4398 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
4401 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
4402 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
4403 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4404 wpabuf_put_le16(clear
, e_nonce_len
);
4405 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4406 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4409 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4410 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4411 goto skip_wrapped_data
;
4413 #endif /* CONFIG_TESTING_OPTIONS */
4416 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4417 wpabuf_put_le16(clear
, e_nonce_len
);
4418 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4420 #ifdef CONFIG_TESTING_OPTIONS
4422 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4423 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4424 goto skip_config_obj
;
4426 #endif /* CONFIG_TESTING_OPTIONS */
4429 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4430 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4431 wpabuf_put_buf(clear
, conf
);
4434 #ifdef CONFIG_TESTING_OPTIONS
4436 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4437 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4440 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4441 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4444 #endif /* CONFIG_TESTING_OPTIONS */
4447 dpp_build_attr_status(msg
, status
);
4449 #ifdef CONFIG_TESTING_OPTIONS
4451 #endif /* CONFIG_TESTING_OPTIONS */
4453 addr
[0] = wpabuf_head(msg
);
4454 len
[0] = wpabuf_len(msg
);
4455 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4457 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4458 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4459 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4461 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4462 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4463 wpabuf_head(clear
), wpabuf_len(clear
),
4464 1, addr
, len
, wrapped
) < 0)
4466 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4467 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4469 #ifdef CONFIG_TESTING_OPTIONS
4470 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4471 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4472 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
4475 #endif /* CONFIG_TESTING_OPTIONS */
4477 wpa_hexdump_buf(MSG_DEBUG
,
4478 "DPP: Configuration Response attributes", msg
);
4492 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4495 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4496 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4497 u8
*unwrapped
= NULL
;
4498 size_t unwrapped_len
= 0;
4499 struct wpabuf
*resp
= NULL
;
4500 struct json_token
*root
= NULL
, *token
;
4503 #ifdef CONFIG_TESTING_OPTIONS
4504 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
4505 wpa_printf(MSG_INFO
,
4506 "DPP: TESTING - stop at Config Request");
4509 #endif /* CONFIG_TESTING_OPTIONS */
4511 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4512 dpp_auth_fail(auth
, "Invalid attribute in config request");
4516 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4518 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4520 "Missing or invalid required Wrapped Data attribute");
4524 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4525 wrapped_data
, wrapped_data_len
);
4526 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4527 unwrapped
= os_malloc(unwrapped_len
);
4530 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4531 wrapped_data
, wrapped_data_len
,
4532 0, NULL
, NULL
, unwrapped
) < 0) {
4533 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4536 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4537 unwrapped
, unwrapped_len
);
4539 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4540 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4544 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4545 DPP_ATTR_ENROLLEE_NONCE
,
4547 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4549 "Missing or invalid Enrollee Nonce attribute");
4552 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4554 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
4555 DPP_ATTR_CONFIG_ATTR_OBJ
,
4559 "Missing or invalid Config Attributes attribute");
4562 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
4563 config_attr
, config_attr_len
);
4565 root
= json_parse((const char *) config_attr
, config_attr_len
);
4567 dpp_auth_fail(auth
, "Could not parse Config Attributes");
4571 token
= json_get_member(root
, "name");
4572 if (!token
|| token
->type
!= JSON_STRING
) {
4573 dpp_auth_fail(auth
, "No Config Attributes - name");
4576 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
4578 token
= json_get_member(root
, "wi-fi_tech");
4579 if (!token
|| token
->type
!= JSON_STRING
) {
4580 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
4583 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
4584 if (os_strcmp(token
->string
, "infra") != 0) {
4585 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
4587 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
4591 token
= json_get_member(root
, "netRole");
4592 if (!token
|| token
->type
!= JSON_STRING
) {
4593 dpp_auth_fail(auth
, "No Config Attributes - netRole");
4596 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
4597 if (os_strcmp(token
->string
, "sta") == 0) {
4599 } else if (os_strcmp(token
->string
, "ap") == 0) {
4602 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
4604 dpp_auth_fail(auth
, "Unsupported netRole");
4608 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
4617 static struct wpabuf
*
4618 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
4619 const u8
*prot_hdr
, u16 prot_hdr_len
,
4620 const EVP_MD
**ret_md
)
4622 struct json_token
*root
, *token
;
4623 struct wpabuf
*kid
= NULL
;
4625 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
4627 wpa_printf(MSG_DEBUG
,
4628 "DPP: JSON parsing failed for JWS Protected Header");
4632 if (root
->type
!= JSON_OBJECT
) {
4633 wpa_printf(MSG_DEBUG
,
4634 "DPP: JWS Protected Header root is not an object");
4638 token
= json_get_member(root
, "typ");
4639 if (!token
|| token
->type
!= JSON_STRING
) {
4640 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
4643 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
4645 if (os_strcmp(token
->string
, "dppCon") != 0) {
4646 wpa_printf(MSG_DEBUG
,
4647 "DPP: Unsupported JWS Protected Header typ=%s",
4652 token
= json_get_member(root
, "alg");
4653 if (!token
|| token
->type
!= JSON_STRING
) {
4654 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
4657 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
4659 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
4660 wpa_printf(MSG_DEBUG
,
4661 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4662 token
->string
, curve
->jws_alg
);
4665 if (os_strcmp(token
->string
, "ES256") == 0 ||
4666 os_strcmp(token
->string
, "BS256") == 0)
4667 *ret_md
= EVP_sha256();
4668 else if (os_strcmp(token
->string
, "ES384") == 0 ||
4669 os_strcmp(token
->string
, "BS384") == 0)
4670 *ret_md
= EVP_sha384();
4671 else if (os_strcmp(token
->string
, "ES512") == 0 ||
4672 os_strcmp(token
->string
, "BS512") == 0)
4673 *ret_md
= EVP_sha512();
4677 wpa_printf(MSG_DEBUG
,
4678 "DPP: Unsupported JWS Protected Header alg=%s",
4683 kid
= json_get_member_base64url(root
, "kid");
4685 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
4688 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
4697 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
4698 struct json_token
*cred
)
4700 struct json_token
*pass
, *psk_hex
;
4702 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
4704 pass
= json_get_member(cred
, "pass");
4705 psk_hex
= json_get_member(cred
, "psk_hex");
4707 if (pass
&& pass
->type
== JSON_STRING
) {
4708 size_t len
= os_strlen(pass
->string
);
4710 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
4712 if (len
< 8 || len
> 63)
4714 os_strlcpy(auth
->passphrase
, pass
->string
,
4715 sizeof(auth
->passphrase
));
4716 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
4717 if (auth
->akm
== DPP_AKM_SAE
) {
4718 wpa_printf(MSG_DEBUG
,
4719 "DPP: Unexpected psk_hex with akm=sae");
4722 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
4723 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
4724 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
4727 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
4728 auth
->psk
, PMK_LEN
);
4731 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
4735 if ((auth
->akm
== DPP_AKM_SAE
|| auth
->akm
== DPP_AKM_PSK_SAE
) &&
4736 !auth
->passphrase
[0]) {
4737 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
4745 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
4746 const struct dpp_curve_params
**key_curve
)
4748 struct json_token
*token
;
4749 const struct dpp_curve_params
*curve
;
4750 struct wpabuf
*x
= NULL
, *y
= NULL
;
4752 EVP_PKEY
*pkey
= NULL
;
4754 token
= json_get_member(jwk
, "kty");
4755 if (!token
|| token
->type
!= JSON_STRING
) {
4756 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
4759 if (os_strcmp(token
->string
, "EC") != 0) {
4760 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
4765 token
= json_get_member(jwk
, "crv");
4766 if (!token
|| token
->type
!= JSON_STRING
) {
4767 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
4770 curve
= dpp_get_curve_jwk_crv(token
->string
);
4772 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
4777 x
= json_get_member_base64url(jwk
, "x");
4779 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
4782 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
4783 if (wpabuf_len(x
) != curve
->prime_len
) {
4784 wpa_printf(MSG_DEBUG
,
4785 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4786 (unsigned int) wpabuf_len(x
),
4787 (unsigned int) curve
->prime_len
, curve
->name
);
4791 y
= json_get_member_base64url(jwk
, "y");
4793 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
4796 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
4797 if (wpabuf_len(y
) != curve
->prime_len
) {
4798 wpa_printf(MSG_DEBUG
,
4799 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4800 (unsigned int) wpabuf_len(y
),
4801 (unsigned int) curve
->prime_len
, curve
->name
);
4805 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
4807 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
4811 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
4823 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
4826 unsigned int year
, month
, day
, hour
, min
, sec
;
4830 /* ISO 8601 date and time:
4832 * YYYY-MM-DDTHH:MM:SSZ
4833 * YYYY-MM-DDTHH:MM:SS+03:00
4835 if (os_strlen(timestamp
) < 19) {
4836 wpa_printf(MSG_DEBUG
,
4837 "DPP: Too short timestamp - assume expired key");
4840 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
4841 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
4842 wpa_printf(MSG_DEBUG
,
4843 "DPP: Failed to parse expiration day - assume expired key");
4847 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
4848 wpa_printf(MSG_DEBUG
,
4849 "DPP: Invalid date/time information - assume expired key");
4853 pos
= timestamp
+ 19;
4854 if (*pos
== 'Z' || *pos
== '\0') {
4855 /* In UTC - no need to adjust */
4856 } else if (*pos
== '-' || *pos
== '+') {
4859 /* Adjust local time to UTC */
4860 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
4862 wpa_printf(MSG_DEBUG
,
4863 "DPP: Invalid time zone designator (%s) - assume expired key",
4868 utime
+= 3600 * hour
;
4870 utime
-= 3600 * hour
;
4878 wpa_printf(MSG_DEBUG
,
4879 "DPP: Invalid time zone designator (%s) - assume expired key",
4886 if (os_get_time(&now
) < 0) {
4887 wpa_printf(MSG_DEBUG
,
4888 "DPP: Cannot get current time - assume expired key");
4892 if (now
.sec
> utime
) {
4893 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
4902 static int dpp_parse_connector(struct dpp_authentication
*auth
,
4903 const unsigned char *payload
,
4906 struct json_token
*root
, *groups
, *netkey
, *token
;
4908 EVP_PKEY
*key
= NULL
;
4909 const struct dpp_curve_params
*curve
;
4910 unsigned int rules
= 0;
4912 root
= json_parse((const char *) payload
, payload_len
);
4914 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
4918 groups
= json_get_member(root
, "groups");
4919 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
4920 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
4923 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4924 struct json_token
*id
, *role
;
4926 id
= json_get_member(token
, "groupId");
4927 if (!id
|| id
->type
!= JSON_STRING
) {
4928 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
4932 role
= json_get_member(token
, "netRole");
4933 if (!role
|| role
->type
!= JSON_STRING
) {
4934 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
4937 wpa_printf(MSG_DEBUG
,
4938 "DPP: connector group: groupId='%s' netRole='%s'",
4939 id
->string
, role
->string
);
4945 wpa_printf(MSG_DEBUG
,
4946 "DPP: Connector includes no groups");
4950 token
= json_get_member(root
, "expiry");
4951 if (!token
|| token
->type
!= JSON_STRING
) {
4952 wpa_printf(MSG_DEBUG
,
4953 "DPP: No expiry string found - connector does not expire");
4955 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
4956 if (dpp_key_expired(token
->string
,
4957 &auth
->net_access_key_expiry
)) {
4958 wpa_printf(MSG_DEBUG
,
4959 "DPP: Connector (netAccessKey) has expired");
4964 netkey
= json_get_member(root
, "netAccessKey");
4965 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
4966 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
4970 key
= dpp_parse_jwk(netkey
, &curve
);
4973 dpp_debug_print_key("DPP: Received netAccessKey", key
);
4975 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
4976 wpa_printf(MSG_DEBUG
,
4977 "DPP: netAccessKey in connector does not match own protocol key");
4978 #ifdef CONFIG_TESTING_OPTIONS
4979 if (auth
->ignore_netaccesskey_mismatch
) {
4980 wpa_printf(MSG_DEBUG
,
4981 "DPP: TESTING - skip netAccessKey mismatch");
4985 #else /* CONFIG_TESTING_OPTIONS */
4987 #endif /* CONFIG_TESTING_OPTIONS */
4998 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
5000 struct wpabuf
*uncomp
;
5002 u8 hash
[SHA256_MAC_LEN
];
5006 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
5008 uncomp
= dpp_get_pubkey_point(pub
, 1);
5011 addr
[0] = wpabuf_head(uncomp
);
5012 len
[0] = wpabuf_len(uncomp
);
5013 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5015 res
= sha256_vector(1, addr
, len
, hash
);
5016 wpabuf_free(uncomp
);
5019 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5020 wpa_printf(MSG_DEBUG
,
5021 "DPP: Received hash value does not match calculated public key hash value");
5022 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5023 hash
, SHA256_MAC_LEN
);
5030 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
5032 unsigned char *der
= NULL
;
5035 der_len
= i2d_PUBKEY(csign
, &der
);
5038 wpabuf_free(auth
->c_sign_key
);
5039 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5044 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
5046 unsigned char *der
= NULL
;
5050 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5054 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5059 wpabuf_free(auth
->net_access_key
);
5060 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5066 struct dpp_signed_connector_info
{
5067 unsigned char *payload
;
5071 static enum dpp_status_error
5072 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5073 EVP_PKEY
*csign_pub
, const char *connector
)
5075 enum dpp_status_error ret
= 255;
5076 const char *pos
, *end
, *signed_start
, *signed_end
;
5077 struct wpabuf
*kid
= NULL
;
5078 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5079 size_t prot_hdr_len
= 0, signature_len
= 0;
5080 const EVP_MD
*sign_md
= NULL
;
5081 unsigned char *der
= NULL
;
5084 EVP_MD_CTX
*md_ctx
= NULL
;
5085 ECDSA_SIG
*sig
= NULL
;
5086 BIGNUM
*r
= NULL
, *s
= NULL
;
5087 const struct dpp_curve_params
*curve
;
5089 const EC_GROUP
*group
;
5092 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5095 group
= EC_KEY_get0_group(eckey
);
5098 nid
= EC_GROUP_get_curve_name(group
);
5099 curve
= dpp_get_curve_nid(nid
);
5102 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5103 os_memset(info
, 0, sizeof(*info
));
5105 signed_start
= pos
= connector
;
5106 end
= os_strchr(pos
, '.');
5108 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5109 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5112 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
5113 end
- pos
, &prot_hdr_len
);
5115 wpa_printf(MSG_DEBUG
,
5116 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5117 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5120 wpa_hexdump_ascii(MSG_DEBUG
,
5121 "DPP: signedConnector - JWS Protected Header",
5122 prot_hdr
, prot_hdr_len
);
5123 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5125 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5128 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5129 wpa_printf(MSG_DEBUG
,
5130 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5131 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5132 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5137 end
= os_strchr(pos
, '.');
5139 wpa_printf(MSG_DEBUG
,
5140 "DPP: Missing dot(2) in signedConnector");
5141 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5144 signed_end
= end
- 1;
5145 info
->payload
= base64_url_decode((const unsigned char *) pos
,
5146 end
- pos
, &info
->payload_len
);
5147 if (!info
->payload
) {
5148 wpa_printf(MSG_DEBUG
,
5149 "DPP: Failed to base64url decode signedConnector JWS Payload");
5150 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5153 wpa_hexdump_ascii(MSG_DEBUG
,
5154 "DPP: signedConnector - JWS Payload",
5155 info
->payload
, info
->payload_len
);
5157 signature
= base64_url_decode((const unsigned char *) pos
,
5158 os_strlen(pos
), &signature_len
);
5160 wpa_printf(MSG_DEBUG
,
5161 "DPP: Failed to base64url decode signedConnector signature");
5162 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5165 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
5166 signature
, signature_len
);
5168 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
5169 ret
= DPP_STATUS_NO_MATCH
;
5173 if (signature_len
& 0x01) {
5174 wpa_printf(MSG_DEBUG
,
5175 "DPP: Unexpected signedConnector signature length (%d)",
5176 (int) signature_len
);
5177 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5181 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5182 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5183 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
5184 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
5185 sig
= ECDSA_SIG_new();
5186 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
5191 der_len
= i2d_ECDSA_SIG(sig
, &der
);
5193 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
5196 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
5197 md_ctx
= EVP_MD_CTX_create();
5202 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
5203 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
5204 ERR_error_string(ERR_get_error(), NULL
));
5207 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
5208 signed_end
- signed_start
+ 1) != 1) {
5209 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
5210 ERR_error_string(ERR_get_error(), NULL
));
5213 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
5215 wpa_printf(MSG_DEBUG
,
5216 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5217 res
, ERR_error_string(ERR_get_error(), NULL
));
5218 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5222 ret
= DPP_STATUS_OK
;
5225 EVP_MD_CTX_destroy(md_ctx
);
5229 ECDSA_SIG_free(sig
);
5237 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5238 struct json_token
*cred
)
5240 struct dpp_signed_connector_info info
;
5241 struct json_token
*token
, *csign
;
5243 EVP_PKEY
*csign_pub
= NULL
;
5244 const struct dpp_curve_params
*key_curve
= NULL
;
5245 const char *signed_connector
;
5247 os_memset(&info
, 0, sizeof(info
));
5249 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5251 csign
= json_get_member(cred
, "csign");
5252 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5253 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5257 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5259 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5262 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5264 token
= json_get_member(cred
, "signedConnector");
5265 if (!token
|| token
->type
!= JSON_STRING
) {
5266 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5269 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5270 token
->string
, os_strlen(token
->string
));
5271 signed_connector
= token
->string
;
5273 if (os_strchr(signed_connector
, '"') ||
5274 os_strchr(signed_connector
, '\n')) {
5275 wpa_printf(MSG_DEBUG
,
5276 "DPP: Unexpected character in signedConnector");
5280 if (dpp_process_signed_connector(&info
, csign_pub
,
5281 signed_connector
) != DPP_STATUS_OK
)
5284 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
5285 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
5289 os_free(auth
->connector
);
5290 auth
->connector
= os_strdup(signed_connector
);
5292 dpp_copy_csign(auth
, csign_pub
);
5293 dpp_copy_netaccesskey(auth
);
5297 EVP_PKEY_free(csign_pub
);
5298 os_free(info
.payload
);
5303 const char * dpp_akm_str(enum dpp_akm akm
)
5312 case DPP_AKM_PSK_SAE
:
5320 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
5322 if (os_strcmp(akm
, "psk") == 0)
5324 if (os_strcmp(akm
, "sae") == 0)
5326 if (os_strcmp(akm
, "psk+sae") == 0)
5327 return DPP_AKM_PSK_SAE
;
5328 if (os_strcmp(akm
, "dpp") == 0)
5330 return DPP_AKM_UNKNOWN
;
5334 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
5335 const u8
*conf_obj
, u16 conf_obj_len
)
5338 struct json_token
*root
, *token
, *discovery
, *cred
;
5340 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
5343 if (root
->type
!= JSON_OBJECT
) {
5344 dpp_auth_fail(auth
, "JSON root is not an object");
5348 token
= json_get_member(root
, "wi-fi_tech");
5349 if (!token
|| token
->type
!= JSON_STRING
) {
5350 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
5353 if (os_strcmp(token
->string
, "infra") != 0) {
5354 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
5356 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
5360 discovery
= json_get_member(root
, "discovery");
5361 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
5362 dpp_auth_fail(auth
, "No discovery object in JSON");
5366 token
= json_get_member(discovery
, "ssid");
5367 if (!token
|| token
->type
!= JSON_STRING
) {
5368 dpp_auth_fail(auth
, "No discovery::ssid string value found");
5371 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
5372 token
->string
, os_strlen(token
->string
));
5373 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
5374 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
5377 auth
->ssid_len
= os_strlen(token
->string
);
5378 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
5380 cred
= json_get_member(root
, "cred");
5381 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
5382 dpp_auth_fail(auth
, "No cred object in JSON");
5386 token
= json_get_member(cred
, "akm");
5387 if (!token
|| token
->type
!= JSON_STRING
) {
5388 dpp_auth_fail(auth
, "No cred::akm string value found");
5391 auth
->akm
= dpp_akm_from_str(token
->string
);
5393 if (auth
->akm
== DPP_AKM_PSK
|| auth
->akm
== DPP_AKM_SAE
||
5394 auth
->akm
== DPP_AKM_PSK_SAE
) {
5395 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5397 } else if (auth
->akm
== DPP_AKM_DPP
) {
5398 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
5401 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
5403 dpp_auth_fail(auth
, "Unsupported akm");
5407 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
5415 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
5416 const struct wpabuf
*resp
)
5418 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
5419 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
5422 u8
*unwrapped
= NULL
;
5423 size_t unwrapped_len
= 0;
5426 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
5427 dpp_auth_fail(auth
, "Invalid attribute in config response");
5431 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5432 DPP_ATTR_WRAPPED_DATA
,
5434 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5436 "Missing or invalid required Wrapped Data attribute");
5440 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5441 wrapped_data
, wrapped_data_len
);
5442 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5443 unwrapped
= os_malloc(unwrapped_len
);
5447 addr
[0] = wpabuf_head(resp
);
5448 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
5449 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5451 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5452 wrapped_data
, wrapped_data_len
,
5453 1, addr
, len
, unwrapped
) < 0) {
5454 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5457 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5458 unwrapped
, unwrapped_len
);
5460 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5461 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5465 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5466 DPP_ATTR_ENROLLEE_NONCE
,
5468 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5470 "Missing or invalid Enrollee Nonce attribute");
5473 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5474 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5475 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5479 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5480 DPP_ATTR_STATUS
, &status_len
);
5481 if (!status
|| status_len
< 1) {
5483 "Missing or invalid required DPP Status attribute");
5486 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5487 if (status
[0] != DPP_STATUS_OK
) {
5488 dpp_auth_fail(auth
, "Configurator rejected configuration");
5492 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5493 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5496 "Missing required Configuration Object attribute");
5499 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5500 conf_obj
, conf_obj_len
);
5501 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5512 void dpp_configurator_free(struct dpp_configurator
*conf
)
5516 EVP_PKEY_free(conf
->csign
);
5522 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
5526 int key_len
, ret
= -1;
5527 unsigned char *key
= NULL
;
5532 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
5536 key_len
= i2d_ECPrivateKey(eckey
, &key
);
5538 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
5546 struct dpp_configurator
*
5547 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
5550 struct dpp_configurator
*conf
;
5551 struct wpabuf
*csign_pub
= NULL
;
5552 u8 kid_hash
[SHA256_MAC_LEN
];
5556 conf
= os_zalloc(sizeof(*conf
));
5561 conf
->curve
= &dpp_curves
[0];
5563 conf
->curve
= dpp_get_curve_name(curve
);
5565 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5572 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
5575 conf
->csign
= dpp_gen_keypair(conf
->curve
);
5580 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
5582 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
5586 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5587 addr
[0] = wpabuf_head(csign_pub
);
5588 len
[0] = wpabuf_len(csign_pub
);
5589 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
5590 wpa_printf(MSG_DEBUG
,
5591 "DPP: Failed to derive kid for C-sign-key");
5595 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
5600 wpabuf_free(csign_pub
);
5603 dpp_configurator_free(conf
);
5609 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
5610 const char *curve
, int ap
)
5612 struct wpabuf
*conf_obj
;
5616 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
5621 auth
->curve
= &dpp_curves
[0];
5623 auth
->curve
= dpp_get_curve_name(curve
);
5625 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5630 wpa_printf(MSG_DEBUG
,
5631 "DPP: Building own configuration/connector with curve %s",
5634 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
5635 if (!auth
->own_protocol_key
)
5637 dpp_copy_netaccesskey(auth
);
5638 auth
->peer_protocol_key
= auth
->own_protocol_key
;
5639 dpp_copy_csign(auth
, auth
->conf
->csign
);
5641 conf_obj
= dpp_build_conf_obj(auth
, ap
);
5644 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
5645 wpabuf_len(conf_obj
));
5647 wpabuf_free(conf_obj
);
5648 auth
->peer_protocol_key
= NULL
;
5653 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
5655 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
5656 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
5660 static int dpp_connector_compatible_group(struct json_token
*root
,
5661 const char *group_id
,
5662 const char *net_role
)
5664 struct json_token
*groups
, *token
;
5666 groups
= json_get_member(root
, "groups");
5667 if (!groups
|| groups
->type
!= JSON_ARRAY
)
5670 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5671 struct json_token
*id
, *role
;
5673 id
= json_get_member(token
, "groupId");
5674 if (!id
|| id
->type
!= JSON_STRING
)
5677 role
= json_get_member(token
, "netRole");
5678 if (!role
|| role
->type
!= JSON_STRING
)
5681 if (os_strcmp(id
->string
, "*") != 0 &&
5682 os_strcmp(group_id
, "*") != 0 &&
5683 os_strcmp(id
->string
, group_id
) != 0)
5686 if (dpp_compatible_netrole(role
->string
, net_role
))
5694 static int dpp_connector_match_groups(struct json_token
*own_root
,
5695 struct json_token
*peer_root
)
5697 struct json_token
*groups
, *token
;
5699 groups
= json_get_member(peer_root
, "groups");
5700 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5701 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
5705 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5706 struct json_token
*id
, *role
;
5708 id
= json_get_member(token
, "groupId");
5709 if (!id
|| id
->type
!= JSON_STRING
) {
5710 wpa_printf(MSG_DEBUG
,
5711 "DPP: Missing peer groupId string");
5715 role
= json_get_member(token
, "netRole");
5716 if (!role
|| role
->type
!= JSON_STRING
) {
5717 wpa_printf(MSG_DEBUG
,
5718 "DPP: Missing peer groups::netRole string");
5721 wpa_printf(MSG_DEBUG
,
5722 "DPP: peer connector group: groupId='%s' netRole='%s'",
5723 id
->string
, role
->string
);
5724 if (dpp_connector_compatible_group(own_root
, id
->string
,
5726 wpa_printf(MSG_DEBUG
,
5727 "DPP: Compatible group/netRole in own connector");
5736 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
5737 unsigned int hash_len
)
5739 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
5740 const char *info
= "DPP PMK";
5743 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5745 /* HKDF-Extract(<>, N.x) */
5746 os_memset(salt
, 0, hash_len
);
5747 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
5749 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5752 /* HKDF-Expand(PRK, info, L) */
5753 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
5754 os_memset(prk
, 0, hash_len
);
5758 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5764 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
5765 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
5767 struct wpabuf
*nkx
, *pkx
;
5771 u8 hash
[SHA256_MAC_LEN
];
5773 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5774 nkx
= dpp_get_pubkey_point(own_key
, 0);
5775 pkx
= dpp_get_pubkey_point(peer_key
, 0);
5778 addr
[0] = wpabuf_head(nkx
);
5779 len
[0] = wpabuf_len(nkx
) / 2;
5780 addr
[1] = wpabuf_head(pkx
);
5781 len
[1] = wpabuf_len(pkx
) / 2;
5782 if (len
[0] != len
[1])
5784 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
5785 addr
[0] = wpabuf_head(pkx
);
5786 addr
[1] = wpabuf_head(nkx
);
5788 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
5789 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
5790 res
= sha256_vector(2, addr
, len
, hash
);
5793 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
5794 os_memcpy(pmkid
, hash
, PMKID_LEN
);
5795 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
5804 enum dpp_status_error
5805 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
5806 const u8
*net_access_key
, size_t net_access_key_len
,
5807 const u8
*csign_key
, size_t csign_key_len
,
5808 const u8
*peer_connector
, size_t peer_connector_len
,
5811 struct json_token
*root
= NULL
, *netkey
, *token
;
5812 struct json_token
*own_root
= NULL
;
5813 enum dpp_status_error ret
= 255, res
;
5814 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
5815 struct wpabuf
*own_key_pub
= NULL
;
5816 const struct dpp_curve_params
*curve
, *own_curve
;
5817 struct dpp_signed_connector_info info
;
5818 const unsigned char *p
;
5819 EVP_PKEY
*csign
= NULL
;
5820 char *signed_connector
= NULL
;
5821 const char *pos
, *end
;
5822 unsigned char *own_conn
= NULL
;
5823 size_t own_conn_len
;
5824 EVP_PKEY_CTX
*ctx
= NULL
;
5826 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
5828 os_memset(intro
, 0, sizeof(*intro
));
5829 os_memset(&info
, 0, sizeof(info
));
5834 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
5836 wpa_printf(MSG_ERROR
,
5837 "DPP: Failed to parse local C-sign-key information");
5841 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
5842 net_access_key_len
);
5844 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
5848 pos
= os_strchr(own_connector
, '.');
5850 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
5854 end
= os_strchr(pos
, '.');
5856 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
5859 own_conn
= base64_url_decode((const unsigned char *) pos
,
5860 end
- pos
, &own_conn_len
);
5862 wpa_printf(MSG_DEBUG
,
5863 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5867 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
5869 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
5873 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
5874 peer_connector
, peer_connector_len
);
5875 signed_connector
= os_malloc(peer_connector_len
+ 1);
5876 if (!signed_connector
)
5878 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
5879 signed_connector
[peer_connector_len
] = '\0';
5881 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
5882 if (res
!= DPP_STATUS_OK
) {
5887 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
5889 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5890 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5894 if (!dpp_connector_match_groups(own_root
, root
)) {
5895 wpa_printf(MSG_DEBUG
,
5896 "DPP: Peer connector does not include compatible group netrole with own connector");
5897 ret
= DPP_STATUS_NO_MATCH
;
5901 token
= json_get_member(root
, "expiry");
5902 if (!token
|| token
->type
!= JSON_STRING
) {
5903 wpa_printf(MSG_DEBUG
,
5904 "DPP: No expiry string found - connector does not expire");
5906 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5907 if (dpp_key_expired(token
->string
, expiry
)) {
5908 wpa_printf(MSG_DEBUG
,
5909 "DPP: Connector (netAccessKey) has expired");
5910 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5915 netkey
= json_get_member(root
, "netAccessKey");
5916 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5917 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5918 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5922 peer_key
= dpp_parse_jwk(netkey
, &curve
);
5924 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5927 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
5929 if (own_curve
!= curve
) {
5930 wpa_printf(MSG_DEBUG
,
5931 "DPP: Mismatching netAccessKey curves (%s != %s)",
5932 own_curve
->name
, curve
->name
);
5933 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5937 /* ECDH: N = nk * PK */
5938 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
5940 EVP_PKEY_derive_init(ctx
) != 1 ||
5941 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
5942 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
5943 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5944 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
5945 wpa_printf(MSG_ERROR
,
5946 "DPP: Failed to derive ECDH shared secret: %s",
5947 ERR_error_string(ERR_get_error(), NULL
));
5951 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
5954 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5955 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
5956 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
5959 intro
->pmk_len
= curve
->hash_len
;
5961 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5962 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
5963 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
5967 ret
= DPP_STATUS_OK
;
5969 if (ret
!= DPP_STATUS_OK
)
5970 os_memset(intro
, 0, sizeof(*intro
));
5971 os_memset(Nx
, 0, sizeof(Nx
));
5972 EVP_PKEY_CTX_free(ctx
);
5974 os_free(signed_connector
);
5975 os_free(info
.payload
);
5976 EVP_PKEY_free(own_key
);
5977 wpabuf_free(own_key_pub
);
5978 EVP_PKEY_free(peer_key
);
5979 EVP_PKEY_free(csign
);
5981 json_free(own_root
);
5986 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
5990 size_t len
= curve
->prime_len
;
5993 switch (curve
->ike_group
) {
5995 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
5996 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
5999 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
6000 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
6003 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
6004 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
6007 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
6008 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
6011 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
6012 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
6015 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
6016 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
6022 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6025 return dpp_set_pubkey_point_group(group
, x
, y
, len
);
6029 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
6030 const u8
*mac_init
, const char *code
,
6031 const char *identifier
, BN_CTX
*bnctx
,
6032 const EC_GROUP
**ret_group
)
6034 u8 hash
[DPP_MAX_HASH_LEN
];
6037 unsigned int num_elem
= 0;
6038 EC_POINT
*Qi
= NULL
;
6039 EVP_PKEY
*Pi
= NULL
;
6040 EC_KEY
*Pi_ec
= NULL
;
6041 const EC_POINT
*Pi_point
;
6042 BIGNUM
*hash_bn
= NULL
;
6043 const EC_GROUP
*group
= NULL
;
6044 EC_GROUP
*group2
= NULL
;
6046 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6048 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
6049 addr
[num_elem
] = mac_init
;
6050 len
[num_elem
] = ETH_ALEN
;
6053 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6055 addr
[num_elem
] = (const u8
*) identifier
;
6056 len
[num_elem
] = os_strlen(identifier
);
6059 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6060 addr
[num_elem
] = (const u8
*) code
;
6061 len
[num_elem
] = os_strlen(code
);
6063 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6065 wpa_hexdump_key(MSG_DEBUG
,
6066 "DPP: H(MAC-Initiator | [identifier |] code)",
6067 hash
, curve
->hash_len
);
6068 Pi
= dpp_pkex_get_role_elem(curve
, 1);
6071 dpp_debug_print_key("DPP: Pi", Pi
);
6072 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
6075 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
6077 group
= EC_KEY_get0_group(Pi_ec
);
6080 group2
= EC_GROUP_dup(group
);
6083 Qi
= EC_POINT_new(group2
);
6085 EC_GROUP_free(group2
);
6088 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6090 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
6092 if (EC_POINT_is_at_infinity(group
, Qi
)) {
6093 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
6096 dpp_debug_print_point("DPP: Qi", group
, Qi
);
6100 BN_clear_free(hash_bn
);
6102 *ret_group
= group2
;
6111 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
6112 const u8
*mac_resp
, const char *code
,
6113 const char *identifier
, BN_CTX
*bnctx
,
6114 const EC_GROUP
**ret_group
)
6116 u8 hash
[DPP_MAX_HASH_LEN
];
6119 unsigned int num_elem
= 0;
6120 EC_POINT
*Qr
= NULL
;
6121 EVP_PKEY
*Pr
= NULL
;
6122 EC_KEY
*Pr_ec
= NULL
;
6123 const EC_POINT
*Pr_point
;
6124 BIGNUM
*hash_bn
= NULL
;
6125 const EC_GROUP
*group
= NULL
;
6126 EC_GROUP
*group2
= NULL
;
6128 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6130 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
6131 addr
[num_elem
] = mac_resp
;
6132 len
[num_elem
] = ETH_ALEN
;
6135 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6137 addr
[num_elem
] = (const u8
*) identifier
;
6138 len
[num_elem
] = os_strlen(identifier
);
6141 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6142 addr
[num_elem
] = (const u8
*) code
;
6143 len
[num_elem
] = os_strlen(code
);
6145 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6147 wpa_hexdump_key(MSG_DEBUG
,
6148 "DPP: H(MAC-Responder | [identifier |] code)",
6149 hash
, curve
->hash_len
);
6150 Pr
= dpp_pkex_get_role_elem(curve
, 0);
6153 dpp_debug_print_key("DPP: Pr", Pr
);
6154 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
6157 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
6159 group
= EC_KEY_get0_group(Pr_ec
);
6162 group2
= EC_GROUP_dup(group
);
6165 Qr
= EC_POINT_new(group2
);
6167 EC_GROUP_free(group2
);
6170 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6172 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
6174 if (EC_POINT_is_at_infinity(group
, Qr
)) {
6175 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
6178 dpp_debug_print_point("DPP: Qr", group
, Qr
);
6182 BN_clear_free(hash_bn
);
6184 *ret_group
= group2
;
6193 #ifdef CONFIG_TESTING_OPTIONS
6194 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
6195 const struct dpp_curve_params
*curve
)
6203 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6208 point
= EC_POINT_new(group
);
6211 if (!ctx
|| !point
|| !x
|| !y
)
6214 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
6217 /* Generate a random y coordinate that results in a point that is not
6220 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
6223 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
6225 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
6226 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6227 * return an error from EC_POINT_set_affine_coordinates_GFp()
6228 * when the point is not on the curve. */
6230 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
6232 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
6235 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
6239 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
6240 curve
->prime_len
) < 0 ||
6241 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
6242 curve
->prime_len
) < 0)
6248 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
6251 EC_POINT_free(point
);
6256 #endif /* CONFIG_TESTING_OPTIONS */
6259 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
6261 EC_KEY
*X_ec
= NULL
;
6262 const EC_POINT
*X_point
;
6263 BN_CTX
*bnctx
= NULL
;
6264 const EC_GROUP
*group
;
6265 EC_POINT
*Qi
= NULL
, *M
= NULL
;
6266 struct wpabuf
*M_buf
= NULL
;
6267 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6268 struct wpabuf
*msg
= NULL
;
6270 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6272 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
6274 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6275 bnctx
= BN_CTX_new();
6278 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
6279 pkex
->identifier
, bnctx
, &group
);
6283 /* Generate a random ephemeral keypair x/X */
6284 #ifdef CONFIG_TESTING_OPTIONS
6285 if (dpp_pkex_ephemeral_key_override_len
) {
6286 const struct dpp_curve_params
*tmp_curve
;
6288 wpa_printf(MSG_INFO
,
6289 "DPP: TESTING - override ephemeral key x/X");
6290 pkex
->x
= dpp_set_keypair(&tmp_curve
,
6291 dpp_pkex_ephemeral_key_override
,
6292 dpp_pkex_ephemeral_key_override_len
);
6294 pkex
->x
= dpp_gen_keypair(curve
);
6296 #else /* CONFIG_TESTING_OPTIONS */
6297 pkex
->x
= dpp_gen_keypair(curve
);
6298 #endif /* CONFIG_TESTING_OPTIONS */
6303 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
6306 X_point
= EC_KEY_get0_public_key(X_ec
);
6309 dpp_debug_print_point("DPP: X", group
, X_point
);
6310 M
= EC_POINT_new(group
);
6313 if (!M
|| !Mx
|| !My
||
6314 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
6315 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
6317 dpp_debug_print_point("DPP: M", group
, M
);
6319 /* Initiator -> Responder: group, [identifier,] M */
6321 if (pkex
->identifier
)
6322 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6323 attr_len
+= 4 + 2 * curve
->prime_len
;
6324 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
6328 #ifdef CONFIG_TESTING_OPTIONS
6329 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
6330 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
6331 goto skip_finite_cyclic_group
;
6333 #endif /* CONFIG_TESTING_OPTIONS */
6335 /* Finite Cyclic Group attribute */
6336 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6337 wpabuf_put_le16(msg
, 2);
6338 wpabuf_put_le16(msg
, curve
->ike_group
);
6340 #ifdef CONFIG_TESTING_OPTIONS
6341 skip_finite_cyclic_group
:
6342 #endif /* CONFIG_TESTING_OPTIONS */
6344 /* Code Identifier attribute */
6345 if (pkex
->identifier
) {
6346 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6347 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6348 wpabuf_put_str(msg
, pkex
->identifier
);
6351 #ifdef CONFIG_TESTING_OPTIONS
6352 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6353 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6356 #endif /* CONFIG_TESTING_OPTIONS */
6358 /* M in Encrypted Key attribute */
6359 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6360 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6362 #ifdef CONFIG_TESTING_OPTIONS
6363 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6364 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6365 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6369 #endif /* CONFIG_TESTING_OPTIONS */
6371 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
6372 curve
->prime_len
) < 0 ||
6373 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
6374 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
6375 curve
->prime_len
) < 0)
6388 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
6395 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
6397 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
6401 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
6403 const char *identifier
,
6406 struct dpp_pkex
*pkex
;
6408 #ifdef CONFIG_TESTING_OPTIONS
6409 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
6410 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
6411 MAC2STR(dpp_pkex_own_mac_override
));
6412 own_mac
= dpp_pkex_own_mac_override
;
6414 #endif /* CONFIG_TESTING_OPTIONS */
6416 pkex
= os_zalloc(sizeof(*pkex
));
6419 pkex
->msg_ctx
= msg_ctx
;
6420 pkex
->initiator
= 1;
6422 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6424 pkex
->identifier
= os_strdup(identifier
);
6425 if (!pkex
->identifier
)
6428 pkex
->code
= os_strdup(code
);
6431 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
6432 if (!pkex
->exchange_req
)
6436 dpp_pkex_free(pkex
);
6441 static struct wpabuf
*
6442 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
6443 enum dpp_status_error status
,
6444 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
6446 struct wpabuf
*msg
= NULL
;
6448 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6450 /* Initiator -> Responder: DPP Status, [identifier,] N */
6452 if (pkex
->identifier
)
6453 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6454 attr_len
+= 4 + 2 * curve
->prime_len
;
6455 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
6459 #ifdef CONFIG_TESTING_OPTIONS
6460 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
6461 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
6465 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
6466 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
6469 #endif /* CONFIG_TESTING_OPTIONS */
6472 dpp_build_attr_status(msg
, status
);
6474 #ifdef CONFIG_TESTING_OPTIONS
6476 #endif /* CONFIG_TESTING_OPTIONS */
6478 /* Code Identifier attribute */
6479 if (pkex
->identifier
) {
6480 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6481 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6482 wpabuf_put_str(msg
, pkex
->identifier
);
6485 if (status
!= DPP_STATUS_OK
)
6486 goto skip_encrypted_key
;
6488 #ifdef CONFIG_TESTING_OPTIONS
6489 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6490 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6491 goto skip_encrypted_key
;
6493 #endif /* CONFIG_TESTING_OPTIONS */
6495 /* N in Encrypted Key attribute */
6496 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6497 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6499 #ifdef CONFIG_TESTING_OPTIONS
6500 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6501 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6502 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6504 goto skip_encrypted_key
;
6506 #endif /* CONFIG_TESTING_OPTIONS */
6508 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
6509 curve
->prime_len
) < 0 ||
6510 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
6511 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
6512 curve
->prime_len
) < 0)
6516 if (status
== DPP_STATUS_BAD_GROUP
) {
6517 /* Finite Cyclic Group attribute */
6518 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6519 wpabuf_put_le16(msg
, 2);
6520 wpabuf_put_le16(msg
, curve
->ike_group
);
6530 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
6531 const u8
*Mx
, size_t Mx_len
,
6532 const u8
*Nx
, size_t Nx_len
,
6534 const u8
*Kx
, size_t Kx_len
,
6535 u8
*z
, unsigned int hash_len
)
6537 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6542 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6545 /* HKDF-Extract(<>, IKM=K.x) */
6546 os_memset(salt
, 0, hash_len
);
6547 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
6549 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
6551 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
6552 info
= os_malloc(info_len
);
6556 os_memcpy(pos
, mac_init
, ETH_ALEN
);
6558 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
6560 os_memcpy(pos
, Mx
, Mx_len
);
6562 os_memcpy(pos
, Nx
, Nx_len
);
6564 os_memcpy(pos
, code
, os_strlen(code
));
6566 /* HKDF-Expand(PRK, info, L) */
6568 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6570 else if (hash_len
== 48)
6571 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6573 else if (hash_len
== 64)
6574 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6579 os_memset(prk
, 0, hash_len
);
6583 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
6589 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
6590 const char *identifier
)
6592 if (!attr_id
&& identifier
) {
6593 wpa_printf(MSG_DEBUG
,
6594 "DPP: No PKEX code identifier received, but expected one");
6598 if (attr_id
&& !identifier
) {
6599 wpa_printf(MSG_DEBUG
,
6600 "DPP: PKEX code identifier received, but not expecting one");
6604 if (attr_id
&& identifier
&&
6605 (os_strlen(identifier
) != attr_id_len
||
6606 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
6607 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
6615 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
6616 struct dpp_bootstrap_info
*bi
,
6619 const char *identifier
,
6621 const u8
*buf
, size_t len
)
6623 const u8
*attr_group
, *attr_id
, *attr_key
;
6624 u16 attr_group_len
, attr_id_len
, attr_key_len
;
6625 const struct dpp_curve_params
*curve
= bi
->curve
;
6627 struct dpp_pkex
*pkex
= NULL
;
6628 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
6629 BN_CTX
*bnctx
= NULL
;
6630 const EC_GROUP
*group
;
6631 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6632 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
6633 const EC_POINT
*Y_point
;
6634 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6635 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6638 EVP_PKEY_CTX
*ctx
= NULL
;
6640 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
6641 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6642 "PKEX counter t limit reached - ignore message");
6646 #ifdef CONFIG_TESTING_OPTIONS
6647 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
6648 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
6649 MAC2STR(dpp_pkex_peer_mac_override
));
6650 peer_mac
= dpp_pkex_peer_mac_override
;
6652 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
6653 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
6654 MAC2STR(dpp_pkex_own_mac_override
));
6655 own_mac
= dpp_pkex_own_mac_override
;
6657 #endif /* CONFIG_TESTING_OPTIONS */
6660 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
6662 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
6665 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
6667 if (!attr_group
|| attr_group_len
!= 2) {
6668 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6669 "Missing or invalid Finite Cyclic Group attribute");
6672 ike_group
= WPA_GET_LE16(attr_group
);
6673 if (ike_group
!= curve
->ike_group
) {
6674 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6675 "Mismatching PKEX curve: peer=%u own=%u",
6676 ike_group
, curve
->ike_group
);
6677 pkex
= os_zalloc(sizeof(*pkex
));
6682 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
6683 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
6684 if (!pkex
->exchange_resp
)
6689 /* M in Encrypted Key attribute */
6690 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
6692 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
6693 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
6694 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6695 "Missing Encrypted Key attribute");
6699 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6700 bnctx
= BN_CTX_new();
6703 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
6709 X
= EC_POINT_new(group
);
6710 M
= EC_POINT_new(group
);
6711 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6712 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6713 if (!X
|| !M
|| !Mx
|| !My
||
6714 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
6715 EC_POINT_is_at_infinity(group
, M
) ||
6716 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
6717 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
6718 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
6719 EC_POINT_is_at_infinity(group
, X
) ||
6720 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
6721 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6722 "Invalid Encrypted Key value");
6726 dpp_debug_print_point("DPP: M", group
, M
);
6727 dpp_debug_print_point("DPP: X'", group
, X
);
6729 pkex
= os_zalloc(sizeof(*pkex
));
6732 pkex
->t
= bi
->pkex_t
;
6733 pkex
->msg_ctx
= msg_ctx
;
6735 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6736 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
6738 pkex
->identifier
= os_strdup(identifier
);
6739 if (!pkex
->identifier
)
6742 pkex
->code
= os_strdup(code
);
6746 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
6748 X_ec
= EC_KEY_new();
6750 EC_KEY_set_group(X_ec
, group
) != 1 ||
6751 EC_KEY_set_public_key(X_ec
, X
) != 1)
6753 pkex
->x
= EVP_PKEY_new();
6755 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
6758 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6759 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
6763 /* Generate a random ephemeral keypair y/Y */
6764 #ifdef CONFIG_TESTING_OPTIONS
6765 if (dpp_pkex_ephemeral_key_override_len
) {
6766 const struct dpp_curve_params
*tmp_curve
;
6768 wpa_printf(MSG_INFO
,
6769 "DPP: TESTING - override ephemeral key y/Y");
6770 pkex
->y
= dpp_set_keypair(&tmp_curve
,
6771 dpp_pkex_ephemeral_key_override
,
6772 dpp_pkex_ephemeral_key_override_len
);
6774 pkex
->y
= dpp_gen_keypair(curve
);
6776 #else /* CONFIG_TESTING_OPTIONS */
6777 pkex
->y
= dpp_gen_keypair(curve
);
6778 #endif /* CONFIG_TESTING_OPTIONS */
6783 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
6786 Y_point
= EC_KEY_get0_public_key(Y_ec
);
6789 dpp_debug_print_point("DPP: Y", group
, Y_point
);
6790 N
= EC_POINT_new(group
);
6793 if (!N
|| !Nx
|| !Ny
||
6794 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
6795 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
6797 dpp_debug_print_point("DPP: N", group
, N
);
6799 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
6801 if (!pkex
->exchange_resp
)
6805 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
6807 EVP_PKEY_derive_init(ctx
) != 1 ||
6808 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
6809 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6810 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6811 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6812 wpa_printf(MSG_ERROR
,
6813 "DPP: Failed to derive ECDH shared secret: %s",
6814 ERR_error_string(ERR_get_error(), NULL
));
6818 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6821 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6823 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
6824 pkex
->Mx
, curve
->prime_len
,
6825 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
6826 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
6827 os_memset(Kx
, 0, Kx_len
);
6831 pkex
->exchange_done
= 1;
6834 EVP_PKEY_CTX_free(ctx
);
6849 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
6850 dpp_pkex_free(pkex
);
6856 static struct wpabuf
*
6857 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
6858 const struct wpabuf
*A_pub
, const u8
*u
)
6860 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6861 struct wpabuf
*msg
= NULL
;
6862 size_t clear_len
, attr_len
;
6863 struct wpabuf
*clear
= NULL
;
6869 /* {A, u, [bootstrapping info]}z */
6870 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6871 clear
= wpabuf_alloc(clear_len
);
6872 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6873 #ifdef CONFIG_TESTING_OPTIONS
6874 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
6876 #endif /* CONFIG_TESTING_OPTIONS */
6877 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
6881 #ifdef CONFIG_TESTING_OPTIONS
6882 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6883 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6884 goto skip_bootstrap_key
;
6886 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6887 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6888 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6889 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6890 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6892 goto skip_bootstrap_key
;
6894 #endif /* CONFIG_TESTING_OPTIONS */
6896 /* A in Bootstrap Key attribute */
6897 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6898 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
6899 wpabuf_put_buf(clear
, A_pub
);
6901 #ifdef CONFIG_TESTING_OPTIONS
6903 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
6904 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
6905 goto skip_i_auth_tag
;
6907 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
6908 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
6909 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6910 wpabuf_put_le16(clear
, curve
->hash_len
);
6911 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
6912 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
6913 goto skip_i_auth_tag
;
6915 #endif /* CONFIG_TESTING_OPTIONS */
6917 /* u in I-Auth tag attribute */
6918 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6919 wpabuf_put_le16(clear
, curve
->hash_len
);
6920 wpabuf_put_data(clear
, u
, curve
->hash_len
);
6922 #ifdef CONFIG_TESTING_OPTIONS
6924 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
6925 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6926 goto skip_wrapped_data
;
6928 #endif /* CONFIG_TESTING_OPTIONS */
6930 addr
[0] = wpabuf_head_u8(msg
) + 2;
6931 len
[0] = DPP_HDR_LEN
;
6934 len
[1] = sizeof(octet
);
6935 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6936 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6938 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6939 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6940 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6942 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6943 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6944 wpabuf_head(clear
), wpabuf_len(clear
),
6945 2, addr
, len
, wrapped
) < 0)
6947 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6948 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6950 #ifdef CONFIG_TESTING_OPTIONS
6951 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
6952 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6953 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
6956 #endif /* CONFIG_TESTING_OPTIONS */
6969 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
6971 const u8
*buf
, size_t buflen
)
6973 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
6974 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
6975 const EC_GROUP
*group
;
6976 BN_CTX
*bnctx
= NULL
;
6977 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6978 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6979 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
6980 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6981 EVP_PKEY_CTX
*ctx
= NULL
;
6982 EC_KEY
*Y_ec
= NULL
;
6983 size_t Jx_len
, Kx_len
;
6984 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6987 u8 u
[DPP_MAX_HASH_LEN
];
6990 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
6993 #ifdef CONFIG_TESTING_OPTIONS
6994 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
6995 wpa_printf(MSG_INFO
,
6996 "DPP: TESTING - stop at PKEX Exchange Response");
7001 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7002 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7003 MAC2STR(dpp_pkex_peer_mac_override
));
7004 peer_mac
= dpp_pkex_peer_mac_override
;
7006 #endif /* CONFIG_TESTING_OPTIONS */
7008 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7010 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
7012 if (!attr_status
|| attr_status_len
!= 1) {
7013 dpp_pkex_fail(pkex
, "No DPP Status attribute");
7016 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
7018 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
7019 attr_group
= dpp_get_attr(buf
, buflen
,
7020 DPP_ATTR_FINITE_CYCLIC_GROUP
,
7022 if (attr_group
&& attr_group_len
== 2) {
7023 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7024 "Peer indicated mismatching PKEX group - proposed %u",
7025 WPA_GET_LE16(attr_group
));
7030 if (attr_status
[0] != DPP_STATUS_OK
) {
7031 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
7036 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
7038 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
7039 pkex
->identifier
)) {
7040 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
7044 /* N in Encrypted Key attribute */
7045 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
7047 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
7048 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
7052 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7053 bnctx
= BN_CTX_new();
7056 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
7057 pkex
->identifier
, bnctx
, &group
);
7062 Y
= EC_POINT_new(group
);
7063 N
= EC_POINT_new(group
);
7064 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7065 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7066 if (!Y
|| !N
|| !Nx
|| !Ny
||
7067 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
7068 EC_POINT_is_at_infinity(group
, N
) ||
7069 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
7070 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
7071 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
7072 EC_POINT_is_at_infinity(group
, Y
) ||
7073 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
7074 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
7078 dpp_debug_print_point("DPP: N", group
, N
);
7079 dpp_debug_print_point("DPP: Y'", group
, Y
);
7081 pkex
->exchange_done
= 1;
7083 /* ECDH: J = a * Y’ */
7084 Y_ec
= EC_KEY_new();
7086 EC_KEY_set_group(Y_ec
, group
) != 1 ||
7087 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
7089 pkex
->y
= EVP_PKEY_new();
7091 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
7093 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7095 EVP_PKEY_derive_init(ctx
) != 1 ||
7096 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7097 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7098 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7099 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7100 wpa_printf(MSG_ERROR
,
7101 "DPP: Failed to derive ECDH shared secret: %s",
7102 ERR_error_string(ERR_get_error(), NULL
));
7106 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7109 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7110 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7111 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7112 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7113 if (!A_pub
|| !Y_pub
|| !X_pub
)
7115 addr
[0] = pkex
->own_mac
;
7117 addr
[1] = wpabuf_head(A_pub
);
7118 len
[1] = wpabuf_len(A_pub
) / 2;
7119 addr
[2] = wpabuf_head(Y_pub
);
7120 len
[2] = wpabuf_len(Y_pub
) / 2;
7121 addr
[3] = wpabuf_head(X_pub
);
7122 len
[3] = wpabuf_len(X_pub
) / 2;
7123 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7125 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
7128 EVP_PKEY_CTX_free(ctx
);
7129 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7131 EVP_PKEY_derive_init(ctx
) != 1 ||
7132 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7133 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7134 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7135 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7136 wpa_printf(MSG_ERROR
,
7137 "DPP: Failed to derive ECDH shared secret: %s",
7138 ERR_error_string(ERR_get_error(), NULL
));
7142 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7145 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7147 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
7148 pkex
->Mx
, curve
->prime_len
,
7149 attr_key
/* N.x */, attr_key_len
/ 2,
7150 pkex
->code
, Kx
, Kx_len
,
7151 pkex
->z
, curve
->hash_len
);
7152 os_memset(Kx
, 0, Kx_len
);
7156 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
7170 EVP_PKEY_CTX_free(ctx
);
7174 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
7179 static struct wpabuf
*
7180 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
7181 const struct wpabuf
*B_pub
, const u8
*v
)
7183 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7184 struct wpabuf
*msg
= NULL
;
7189 struct wpabuf
*clear
= NULL
;
7190 size_t clear_len
, attr_len
;
7192 /* {B, v [bootstrapping info]}z */
7193 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7194 clear
= wpabuf_alloc(clear_len
);
7195 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7196 #ifdef CONFIG_TESTING_OPTIONS
7197 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
7199 #endif /* CONFIG_TESTING_OPTIONS */
7200 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
7204 #ifdef CONFIG_TESTING_OPTIONS
7205 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7206 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7207 goto skip_bootstrap_key
;
7209 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7210 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7211 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7212 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7213 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7215 goto skip_bootstrap_key
;
7217 #endif /* CONFIG_TESTING_OPTIONS */
7219 /* B in Bootstrap Key attribute */
7220 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7221 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
7222 wpabuf_put_buf(clear
, B_pub
);
7224 #ifdef CONFIG_TESTING_OPTIONS
7226 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
7227 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
7228 goto skip_r_auth_tag
;
7230 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
7231 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
7232 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7233 wpabuf_put_le16(clear
, curve
->hash_len
);
7234 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
7235 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
7236 goto skip_r_auth_tag
;
7238 #endif /* CONFIG_TESTING_OPTIONS */
7240 /* v in R-Auth tag attribute */
7241 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7242 wpabuf_put_le16(clear
, curve
->hash_len
);
7243 wpabuf_put_data(clear
, v
, curve
->hash_len
);
7245 #ifdef CONFIG_TESTING_OPTIONS
7247 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
7248 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7249 goto skip_wrapped_data
;
7251 #endif /* CONFIG_TESTING_OPTIONS */
7253 addr
[0] = wpabuf_head_u8(msg
) + 2;
7254 len
[0] = DPP_HDR_LEN
;
7257 len
[1] = sizeof(octet
);
7258 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7259 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7261 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7262 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7263 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7265 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7266 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7267 wpabuf_head(clear
), wpabuf_len(clear
),
7268 2, addr
, len
, wrapped
) < 0)
7270 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7271 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7273 #ifdef CONFIG_TESTING_OPTIONS
7274 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
7275 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7276 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7279 #endif /* CONFIG_TESTING_OPTIONS */
7292 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
7294 const u8
*buf
, size_t buflen
)
7296 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7297 EVP_PKEY_CTX
*ctx
= NULL
;
7298 size_t Jx_len
, Lx_len
;
7299 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
7300 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7301 const u8
*wrapped_data
, *b_key
, *peer_u
;
7302 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
7306 u8
*unwrapped
= NULL
;
7307 size_t unwrapped_len
= 0;
7308 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7309 struct wpabuf
*B_pub
= NULL
;
7310 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
7312 #ifdef CONFIG_TESTING_OPTIONS
7313 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
7314 wpa_printf(MSG_INFO
,
7315 "DPP: TESTING - stop at PKEX CR Request");
7319 #endif /* CONFIG_TESTING_OPTIONS */
7321 if (!pkex
->exchange_done
|| pkex
->failed
||
7322 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
7325 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7327 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7329 "Missing or invalid required Wrapped Data attribute");
7333 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7334 wrapped_data
, wrapped_data_len
);
7335 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7336 unwrapped
= os_malloc(unwrapped_len
);
7341 len
[0] = DPP_HDR_LEN
;
7344 len
[1] = sizeof(octet
);
7345 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7346 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7348 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7349 wrapped_data
, wrapped_data_len
,
7350 2, addr
, len
, unwrapped
) < 0) {
7352 "AES-SIV decryption failed - possible PKEX code mismatch");
7357 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7358 unwrapped
, unwrapped_len
);
7360 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7361 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7365 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7367 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7368 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7371 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7373 if (!pkex
->peer_bootstrap_key
) {
7374 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7377 dpp_debug_print_key("DPP: Peer bootstrap public key",
7378 pkex
->peer_bootstrap_key
);
7380 /* ECDH: J' = y * A' */
7381 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7383 EVP_PKEY_derive_init(ctx
) != 1 ||
7384 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7385 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7386 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7387 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7388 wpa_printf(MSG_ERROR
,
7389 "DPP: Failed to derive ECDH shared secret: %s",
7390 ERR_error_string(ERR_get_error(), NULL
));
7394 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7397 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7398 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7399 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7400 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7401 if (!A_pub
|| !Y_pub
|| !X_pub
)
7403 addr
[0] = pkex
->peer_mac
;
7405 addr
[1] = wpabuf_head(A_pub
);
7406 len
[1] = wpabuf_len(A_pub
) / 2;
7407 addr
[2] = wpabuf_head(Y_pub
);
7408 len
[2] = wpabuf_len(Y_pub
) / 2;
7409 addr
[3] = wpabuf_head(X_pub
);
7410 len
[3] = wpabuf_len(X_pub
) / 2;
7411 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7414 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
7416 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
7417 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
7418 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
7419 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
7420 u
, curve
->hash_len
);
7421 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
7425 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
7427 /* ECDH: L = b * X' */
7428 EVP_PKEY_CTX_free(ctx
);
7429 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7431 EVP_PKEY_derive_init(ctx
) != 1 ||
7432 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
7433 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
7434 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7435 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
7436 wpa_printf(MSG_ERROR
,
7437 "DPP: Failed to derive ECDH shared secret: %s",
7438 ERR_error_string(ERR_get_error(), NULL
));
7442 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
7445 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7446 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7449 addr
[0] = pkex
->own_mac
;
7451 addr
[1] = wpabuf_head(B_pub
);
7452 len
[1] = wpabuf_len(B_pub
) / 2;
7453 addr
[2] = wpabuf_head(X_pub
);
7454 len
[2] = wpabuf_len(X_pub
) / 2;
7455 addr
[3] = wpabuf_head(Y_pub
);
7456 len
[3] = wpabuf_len(Y_pub
) / 2;
7457 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7459 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
7461 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
7466 EVP_PKEY_CTX_free(ctx
);
7474 wpa_printf(MSG_DEBUG
,
7475 "DPP: PKEX Commit-Reveal Request processing failed");
7480 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
7481 const u8
*buf
, size_t buflen
)
7483 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7484 const u8
*wrapped_data
, *b_key
, *peer_v
;
7485 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
7489 u8
*unwrapped
= NULL
;
7490 size_t unwrapped_len
= 0;
7492 u8 v
[DPP_MAX_HASH_LEN
];
7494 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7495 EVP_PKEY_CTX
*ctx
= NULL
;
7496 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7498 #ifdef CONFIG_TESTING_OPTIONS
7499 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
7500 wpa_printf(MSG_INFO
,
7501 "DPP: TESTING - stop at PKEX CR Response");
7505 #endif /* CONFIG_TESTING_OPTIONS */
7507 if (!pkex
->exchange_done
|| pkex
->failed
||
7508 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
7511 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7513 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7515 "Missing or invalid required Wrapped Data attribute");
7519 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7520 wrapped_data
, wrapped_data_len
);
7521 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7522 unwrapped
= os_malloc(unwrapped_len
);
7527 len
[0] = DPP_HDR_LEN
;
7530 len
[1] = sizeof(octet
);
7531 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7532 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7534 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7535 wrapped_data
, wrapped_data_len
,
7536 2, addr
, len
, unwrapped
) < 0) {
7538 "AES-SIV decryption failed - possible PKEX code mismatch");
7542 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7543 unwrapped
, unwrapped_len
);
7545 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7546 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7550 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7552 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7553 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7556 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7558 if (!pkex
->peer_bootstrap_key
) {
7559 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7562 dpp_debug_print_key("DPP: Peer bootstrap public key",
7563 pkex
->peer_bootstrap_key
);
7565 /* ECDH: L' = x * B' */
7566 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7568 EVP_PKEY_derive_init(ctx
) != 1 ||
7569 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7570 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
7571 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7572 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
7573 wpa_printf(MSG_ERROR
,
7574 "DPP: Failed to derive ECDH shared secret: %s",
7575 ERR_error_string(ERR_get_error(), NULL
));
7579 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
7582 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
7583 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7584 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7585 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7586 if (!B_pub
|| !X_pub
|| !Y_pub
)
7588 addr
[0] = pkex
->peer_mac
;
7590 addr
[1] = wpabuf_head(B_pub
);
7591 len
[1] = wpabuf_len(B_pub
) / 2;
7592 addr
[2] = wpabuf_head(X_pub
);
7593 len
[2] = wpabuf_len(X_pub
) / 2;
7594 addr
[3] = wpabuf_head(Y_pub
);
7595 len
[3] = wpabuf_len(Y_pub
) / 2;
7596 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7599 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
7601 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
7602 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
7603 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
7604 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
7605 v
, curve
->hash_len
);
7606 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
7610 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
7617 EVP_PKEY_CTX_free(ctx
);
7625 void dpp_pkex_free(struct dpp_pkex
*pkex
)
7630 os_free(pkex
->identifier
);
7631 os_free(pkex
->code
);
7632 EVP_PKEY_free(pkex
->x
);
7633 EVP_PKEY_free(pkex
->y
);
7634 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
7635 wpabuf_free(pkex
->exchange_req
);
7636 wpabuf_free(pkex
->exchange_resp
);
7641 #ifdef CONFIG_TESTING_OPTIONS
7642 char * dpp_corrupt_connector_signature(const char *connector
)
7644 char *tmp
, *pos
, *signed3
= NULL
;
7645 unsigned char *signature
= NULL
;
7646 size_t signature_len
= 0, signed3_len
;
7648 tmp
= os_zalloc(os_strlen(connector
) + 5);
7651 os_memcpy(tmp
, connector
, os_strlen(connector
));
7653 pos
= os_strchr(tmp
, '.');
7657 pos
= os_strchr(pos
+ 1, '.');
7662 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
7664 signature
= base64_url_decode((const unsigned char *) pos
,
7665 os_strlen(pos
), &signature_len
);
7666 if (!signature
|| signature_len
== 0)
7668 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
7669 signature
, signature_len
);
7670 signature
[signature_len
- 1] ^= 0x01;
7671 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
7672 signature
, signature_len
);
7673 signed3
= (char *) base64_url_encode(signature
, signature_len
,
7677 os_memcpy(pos
, signed3
, signed3_len
);
7678 pos
[signed3_len
] = '\0';
7679 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
7691 #endif /* CONFIG_TESTING_OPTIONS */