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 /* Compatibility wrappers for older versions. */
49 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
57 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
69 static const struct dpp_curve_params dpp_curves
[] = {
70 /* The mandatory to support and the default NIST P-256 curve needs to
71 * be the first entry on this list. */
72 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
73 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
74 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
75 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
76 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
77 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
78 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
82 /* Role-specific elements for PKEX */
85 static const u8 pkex_init_x_p256
[32] = {
86 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
87 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
88 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
89 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
91 static const u8 pkex_init_y_p256
[32] = {
92 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
93 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
94 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
95 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
97 static const u8 pkex_resp_x_p256
[32] = {
98 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
99 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
100 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
101 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
103 static const u8 pkex_resp_y_p256
[32] = {
104 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
105 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
106 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
107 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
111 static const u8 pkex_init_x_p384
[48] = {
112 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
113 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
114 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
115 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
116 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
117 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
119 static const u8 pkex_init_y_p384
[48] = {
120 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
121 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
122 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
123 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
124 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
125 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
127 static const u8 pkex_resp_x_p384
[48] = {
128 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
129 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
130 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
131 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
132 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
133 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
135 static const u8 pkex_resp_y_p384
[48] = {
136 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
137 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
138 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
139 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
140 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
141 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
145 static const u8 pkex_init_x_p521
[66] = {
146 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
147 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
148 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
149 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
150 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
151 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
152 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
153 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
156 static const u8 pkex_init_y_p521
[66] = {
157 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
158 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
159 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
160 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
161 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
162 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
163 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
164 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
167 static const u8 pkex_resp_x_p521
[66] = {
168 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
169 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
170 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
171 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
172 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
173 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
174 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
175 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
178 static const u8 pkex_resp_y_p521
[66] = {
179 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
180 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
181 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
182 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
183 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
184 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
185 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
186 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
190 /* Brainpool P-256r1 */
191 static const u8 pkex_init_x_bp_p256r1
[32] = {
192 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
193 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
194 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
195 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
197 static const u8 pkex_init_y_bp_p256r1
[32] = {
198 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
199 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
200 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
201 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
203 static const u8 pkex_resp_x_bp_p256r1
[32] = {
204 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
205 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
206 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
207 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
209 static const u8 pkex_resp_y_bp_p256r1
[32] = {
210 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
211 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
212 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
213 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
216 /* Brainpool P-384r1 */
217 static const u8 pkex_init_x_bp_p384r1
[48] = {
218 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
219 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
220 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
221 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
222 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
223 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
225 static const u8 pkex_init_y_bp_p384r1
[48] = {
226 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
227 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
228 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
229 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
230 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
231 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
233 static const u8 pkex_resp_x_bp_p384r1
[48] = {
234 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
235 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
236 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
237 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
238 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
239 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
241 static const u8 pkex_resp_y_bp_p384r1
[48] = {
242 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
243 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
244 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
245 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
246 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
247 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
250 /* Brainpool P-512r1 */
251 static const u8 pkex_init_x_bp_p512r1
[64] = {
252 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
253 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
254 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
255 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
256 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
257 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
258 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
259 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
261 static const u8 pkex_init_y_bp_p512r1
[64] = {
262 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
263 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
264 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
265 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
266 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
267 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
268 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
269 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
271 static const u8 pkex_resp_x_bp_p512r1
[64] = {
272 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
273 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
274 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
275 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
276 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
277 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
278 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
279 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
281 static const u8 pkex_resp_y_bp_p512r1
[64] = {
282 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
283 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
284 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
285 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
286 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
287 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
288 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
289 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
293 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
294 const EC_POINT
*point
)
298 char *x_str
= NULL
, *y_str
= NULL
;
300 if (!wpa_debug_show_keys
)
306 if (!ctx
|| !x
|| !y
||
307 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
310 x_str
= BN_bn2hex(x
);
311 y_str
= BN_bn2hex(y
);
312 if (!x_str
|| !y_str
)
315 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
326 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
327 size_t num_elem
, const u8
*addr
[], const size_t *len
,
330 if (curve
->hash_len
== 32)
331 return sha256_vector(num_elem
, addr
, len
, mac
);
332 if (curve
->hash_len
== 48)
333 return sha384_vector(num_elem
, addr
, len
, mac
);
334 if (curve
->hash_len
== 64)
335 return sha512_vector(num_elem
, addr
, len
, mac
);
340 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
341 const char *label
, u8
*out
, size_t outlen
)
344 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
345 (const u8
*) label
, os_strlen(label
),
348 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
349 (const u8
*) label
, os_strlen(label
),
352 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
353 (const u8
*) label
, os_strlen(label
),
359 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
360 size_t num_elem
, const u8
*addr
[],
361 const size_t *len
, u8
*mac
)
364 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
367 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
370 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
376 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
377 const u8
*data
, size_t data_len
, u8
*mac
)
380 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
382 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
384 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
389 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
391 int num_bytes
, offset
;
393 num_bytes
= BN_num_bytes(bn
);
394 if ((size_t) num_bytes
> len
)
396 offset
= len
- num_bytes
;
397 os_memset(pos
, 0, offset
);
398 BN_bn2bin(bn
, pos
+ offset
);
403 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
410 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
413 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
414 len
= i2o_ECPublicKey(eckey
, NULL
);
416 wpa_printf(MSG_ERROR
,
417 "DDP: Failed to determine public key encoding length");
422 buf
= wpabuf_alloc(len
);
428 pos
= wpabuf_put(buf
, len
);
429 res
= i2o_ECPublicKey(eckey
, &pos
);
432 wpa_printf(MSG_ERROR
,
433 "DDP: Failed to encode public key (res=%d/%d)",
440 /* Remove 0x04 prefix to match DPP definition */
441 pos
= wpabuf_mhead(buf
);
442 os_memmove(pos
, pos
+ 1, len
- 1);
450 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
451 const u8
*buf_x
, const u8
*buf_y
,
454 EC_KEY
*eckey
= NULL
;
456 EC_POINT
*point
= NULL
;
457 BIGNUM
*x
= NULL
, *y
= NULL
;
458 EVP_PKEY
*pkey
= NULL
;
462 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
466 point
= EC_POINT_new(group
);
467 x
= BN_bin2bn(buf_x
, len
, NULL
);
468 y
= BN_bin2bn(buf_y
, len
, NULL
);
469 if (!point
|| !x
|| !y
) {
470 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
474 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
475 wpa_printf(MSG_ERROR
,
476 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
477 ERR_error_string(ERR_get_error(), NULL
));
481 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
482 EC_POINT_is_at_infinity(group
, point
)) {
483 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
486 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
488 eckey
= EC_KEY_new();
490 EC_KEY_set_group(eckey
, group
) != 1 ||
491 EC_KEY_set_public_key(eckey
, point
) != 1) {
492 wpa_printf(MSG_ERROR
,
493 "DPP: Failed to set EC_KEY: %s",
494 ERR_error_string(ERR_get_error(), NULL
));
497 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
499 pkey
= EVP_PKEY_new();
500 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
501 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
509 EC_POINT_free(point
);
519 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
520 const u8
*buf
, size_t len
)
523 const EC_GROUP
*group
;
524 EVP_PKEY
*pkey
= NULL
;
529 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
531 wpa_printf(MSG_ERROR
,
532 "DPP: Could not get EC_KEY from group_key");
536 group
= EC_KEY_get0_group(eckey
);
538 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
541 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
548 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
550 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
554 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
559 msg
= wpabuf_alloc(8 + len
);
562 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
563 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
564 wpabuf_put_be24(msg
, OUI_WFA
);
565 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
566 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
567 wpabuf_put_u8(msg
, type
);
572 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
575 const u8
*pos
= buf
, *end
= buf
+ len
;
577 while (end
- pos
>= 4) {
578 id
= WPA_GET_LE16(pos
);
580 alen
= WPA_GET_LE16(pos
);
582 if (alen
> end
- pos
)
595 int dpp_check_attrs(const u8
*buf
, size_t len
)
598 int wrapped_data
= 0;
602 while (end
- pos
>= 4) {
605 id
= WPA_GET_LE16(pos
);
607 alen
= WPA_GET_LE16(pos
);
609 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
611 if (alen
> end
- pos
) {
612 wpa_printf(MSG_DEBUG
,
613 "DPP: Truncated message - not enough room for the attribute - dropped");
617 wpa_printf(MSG_DEBUG
,
618 "DPP: An unexpected attribute included after the Wrapped Data attribute");
621 if (id
== DPP_ATTR_WRAPPED_DATA
)
627 wpa_printf(MSG_DEBUG
,
628 "DPP: Unexpected octets (%d) after the last attribute",
637 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
643 EVP_PKEY_free(info
->pubkey
);
648 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
651 case DPP_BOOTSTRAP_QR_CODE
:
653 case DPP_BOOTSTRAP_PKEX
:
660 static int dpp_uri_valid_info(const char *info
)
663 unsigned char val
= *info
++;
665 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
673 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
675 bi
->uri
= os_strdup(uri
);
676 return bi
->uri
? 0 : -1;
680 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
681 const char *chan_list
)
683 const char *pos
= chan_list
;
684 int opclass
, channel
, freq
;
686 while (pos
&& *pos
&& *pos
!= ';') {
690 pos
= os_strchr(pos
, '/');
697 while (*pos
>= '0' && *pos
<= '9')
699 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
700 wpa_printf(MSG_DEBUG
,
701 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
702 opclass
, channel
, freq
);
704 wpa_printf(MSG_DEBUG
,
705 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
707 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
708 wpa_printf(MSG_DEBUG
,
709 "DPP: Too many channels in URI channel-list - ignore list");
713 bi
->freq
[bi
->num_freq
++] = freq
;
716 if (*pos
== ';' || *pos
== '\0')
725 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
730 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
735 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
736 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
740 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
746 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
753 end
= os_strchr(info
, ';');
755 end
= info
+ os_strlen(info
);
756 bi
->info
= os_malloc(end
- info
+ 1);
759 os_memcpy(bi
->info
, info
, end
- info
);
760 bi
->info
[end
- info
] = '\0';
761 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
762 if (!dpp_uri_valid_info(bi
->info
)) {
763 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
771 static const struct dpp_curve_params
*
772 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
777 for (i
= 0; dpp_curves
[i
].name
; i
++) {
778 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
779 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
780 return &dpp_curves
[i
];
786 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
792 for (i
= 0; dpp_curves
[i
].name
; i
++) {
793 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
795 return &dpp_curves
[i
];
801 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
807 const unsigned char *p
;
809 X509_PUBKEY
*pub
= NULL
;
811 const unsigned char *pk
;
814 #if OPENSSL_VERSION_NUMBER < 0x10100000L
817 const ASN1_OBJECT
*pa_oid
;
821 const ASN1_OBJECT
*poid
;
824 end
= os_strchr(info
, ';');
828 data
= base64_decode((const unsigned char *) info
, end
- info
,
831 wpa_printf(MSG_DEBUG
,
832 "DPP: Invalid base64 encoding on URI public-key");
835 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
838 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
839 bi
->pubkey_hash
) < 0) {
840 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
843 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
844 bi
->pubkey_hash
, SHA256_MAC_LEN
);
846 /* DER encoded ASN.1 SubjectPublicKeyInfo
848 * SubjectPublicKeyInfo ::= SEQUENCE {
849 * algorithm AlgorithmIdentifier,
850 * subjectPublicKey BIT STRING }
852 * AlgorithmIdentifier ::= SEQUENCE {
853 * algorithm OBJECT IDENTIFIER,
854 * parameters ANY DEFINED BY algorithm OPTIONAL }
856 * subjectPublicKey = compressed format public key per ANSI X9.63
857 * algorithm = ecPublicKey (1.2.840.10045.2.1)
858 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
859 * prime256v1 (1.2.840.10045.3.1.7)
863 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
867 wpa_printf(MSG_DEBUG
,
868 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
872 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
873 wpa_printf(MSG_DEBUG
,
874 "DPP: SubjectPublicKeyInfo does not describe an EC key");
879 res
= X509_PUBKEY_set(&pub
, pkey
);
881 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
885 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
887 wpa_printf(MSG_DEBUG
,
888 "DPP: Could not extract SubjectPublicKeyInfo parameters");
891 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
892 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
893 wpa_printf(MSG_DEBUG
,
894 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
897 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
898 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
899 wpa_printf(MSG_DEBUG
,
900 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
904 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
905 if (ptype
!= V_ASN1_OBJECT
) {
906 wpa_printf(MSG_DEBUG
,
907 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
911 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
912 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
913 wpa_printf(MSG_DEBUG
,
914 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
917 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
918 bi
->curve
= dpp_get_curve_oid(poid
);
920 wpa_printf(MSG_DEBUG
,
921 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
926 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
928 X509_PUBKEY_free(pub
);
932 X509_PUBKEY_free(pub
);
938 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
940 const char *pos
= uri
;
942 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
943 struct dpp_bootstrap_info
*bi
;
945 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
947 if (os_strncmp(pos
, "DPP:", 4) != 0) {
948 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
954 end
= os_strchr(pos
, ';');
959 /* Handle terminating ";;" and ignore unexpected ";"
960 * for parsing robustness. */
965 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
967 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
969 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
971 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
974 wpa_hexdump_ascii(MSG_DEBUG
,
975 "DPP: Ignore unrecognized URI parameter",
981 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
985 bi
= os_zalloc(sizeof(*bi
));
989 if (dpp_clone_uri(bi
, uri
) < 0 ||
990 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
991 dpp_parse_uri_mac(bi
, mac
) < 0 ||
992 dpp_parse_uri_info(bi
, info
) < 0 ||
993 dpp_parse_uri_pk(bi
, pk
) < 0) {
994 dpp_bootstrap_info_free(bi
);
1002 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
1004 struct dpp_bootstrap_info
*bi
;
1006 bi
= dpp_parse_uri(uri
);
1008 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
1013 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1020 unsigned char *der
= NULL
;
1022 const EC_GROUP
*group
;
1023 const EC_POINT
*point
;
1025 out
= BIO_new(BIO_s_mem());
1029 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1030 rlen
= BIO_ctrl_pending(out
);
1031 txt
= os_malloc(rlen
+ 1);
1033 res
= BIO_read(out
, txt
, rlen
);
1036 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1042 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1046 group
= EC_KEY_get0_group(eckey
);
1047 point
= EC_KEY_get0_public_key(eckey
);
1049 dpp_debug_print_point(title
, group
, point
);
1051 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1053 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1057 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1059 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1067 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1069 EVP_PKEY_CTX
*kctx
= NULL
;
1071 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1074 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1076 nid
= OBJ_txt2nid(curve
->name
);
1077 if (nid
== NID_undef
) {
1078 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1082 ec_params
= EC_KEY_new_by_curve_name(nid
);
1084 wpa_printf(MSG_ERROR
,
1085 "DPP: Failed to generate EC_KEY parameters");
1088 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1089 params
= EVP_PKEY_new();
1090 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1091 wpa_printf(MSG_ERROR
,
1092 "DPP: Failed to generate EVP_PKEY parameters");
1096 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1098 EVP_PKEY_keygen_init(kctx
) != 1 ||
1099 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1100 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1104 if (wpa_debug_show_keys
)
1105 dpp_debug_print_key("Own generated key", key
);
1107 EVP_PKEY_free(params
);
1108 EVP_PKEY_CTX_free(kctx
);
1111 EVP_PKEY_CTX_free(kctx
);
1112 EVP_PKEY_free(params
);
1117 static const struct dpp_curve_params
*
1118 dpp_get_curve_name(const char *name
)
1122 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1123 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1124 (dpp_curves
[i
].jwk_crv
&&
1125 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1126 return &dpp_curves
[i
];
1132 static const struct dpp_curve_params
*
1133 dpp_get_curve_jwk_crv(const char *name
)
1137 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1138 if (dpp_curves
[i
].jwk_crv
&&
1139 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1140 return &dpp_curves
[i
];
1146 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1147 const u8
*privkey
, size_t privkey_len
)
1151 const EC_GROUP
*group
;
1154 pkey
= EVP_PKEY_new();
1157 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1159 wpa_printf(MSG_INFO
,
1160 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1161 ERR_error_string(ERR_get_error(), NULL
));
1162 EVP_PKEY_free(pkey
);
1165 group
= EC_KEY_get0_group(eckey
);
1168 EVP_PKEY_free(pkey
);
1171 nid
= EC_GROUP_get_curve_name(group
);
1172 *curve
= dpp_get_curve_nid(nid
);
1174 wpa_printf(MSG_INFO
,
1175 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1178 EVP_PKEY_free(pkey
);
1182 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1184 EVP_PKEY_free(pkey
);
1192 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1193 * as an OID identifying the curve */
1195 /* Compressed format public key per ANSI X9.63 */
1196 ASN1_BIT_STRING
*pub_key
;
1197 } DPP_BOOTSTRAPPING_KEY
;
1199 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1200 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1201 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1202 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1204 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1207 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1209 unsigned char *der
= NULL
;
1212 struct wpabuf
*ret
= NULL
;
1214 const EC_GROUP
*group
;
1215 const EC_POINT
*point
;
1217 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1221 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1225 group
= EC_KEY_get0_group(eckey
);
1226 point
= EC_KEY_get0_public_key(eckey
);
1227 if (!group
|| !point
)
1229 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1230 nid
= EC_GROUP_get_curve_name(group
);
1232 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1234 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1235 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1238 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1243 der
= OPENSSL_malloc(len
);
1246 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1249 OPENSSL_free(bootstrap
->pub_key
->data
);
1250 bootstrap
->pub_key
->data
= der
;
1252 bootstrap
->pub_key
->length
= len
;
1253 /* No unused bits */
1254 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1255 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1257 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1259 wpa_printf(MSG_ERROR
,
1260 "DDP: Failed to build DER encoded public key");
1264 ret
= wpabuf_alloc_copy(der
, der_len
);
1266 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1274 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1281 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1284 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1287 addr
[0] = wpabuf_head(der
);
1288 len
[0] = wpabuf_len(der
);
1289 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1291 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1293 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1300 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1301 const u8
*privkey
, size_t privkey_len
)
1303 unsigned char *base64
= NULL
;
1306 struct wpabuf
*der
= NULL
;
1311 bi
->curve
= &dpp_curves
[0];
1313 bi
->curve
= dpp_get_curve_name(curve
);
1315 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1321 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1323 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1328 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1331 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1334 addr
[0] = wpabuf_head(der
);
1335 len
= wpabuf_len(der
);
1336 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1338 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1341 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1344 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1349 pos
= (char *) base64
;
1352 pos
= os_strchr(pos
, '\n');
1355 os_memmove(pos
, pos
+ 1, end
- pos
);
1357 return (char *) base64
;
1365 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1366 unsigned int hash_len
)
1368 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1369 const char *info
= "first intermediate key";
1372 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1374 /* HKDF-Extract(<>, M.x) */
1375 os_memset(salt
, 0, hash_len
);
1376 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1378 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1381 /* HKDF-Expand(PRK, info, L) */
1382 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1383 os_memset(prk
, 0, hash_len
);
1387 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1393 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1394 unsigned int hash_len
)
1396 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1397 const char *info
= "second intermediate key";
1400 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1402 /* HKDF-Extract(<>, N.x) */
1403 os_memset(salt
, 0, hash_len
);
1404 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1407 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1410 /* HKDF-Expand(PRK, info, L) */
1411 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1412 os_memset(prk
, 0, hash_len
);
1416 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1422 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1423 unsigned int hash_len
)
1426 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1427 const char *info_ke
= "DPP Key";
1428 u8 prk
[DPP_MAX_HASH_LEN
];
1432 size_t num_elem
= 0;
1434 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1435 wpa_printf(MSG_DEBUG
,
1436 "DPP: Mx/Nx not available - cannot derive ke");
1440 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1442 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1443 nonce_len
= auth
->curve
->nonce_len
;
1444 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1445 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1446 addr
[num_elem
] = auth
->Mx
;
1447 len
[num_elem
] = auth
->Mx_len
;
1449 addr
[num_elem
] = auth
->Nx
;
1450 len
[num_elem
] = auth
->Nx_len
;
1452 if (auth
->peer_bi
&& auth
->own_bi
) {
1453 if (!auth
->Lx_len
) {
1454 wpa_printf(MSG_DEBUG
,
1455 "DPP: Lx not available - cannot derive ke");
1458 addr
[num_elem
] = auth
->Lx
;
1459 len
[num_elem
] = auth
->secret_len
;
1462 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1463 num_elem
, addr
, len
, prk
);
1466 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1469 /* HKDF-Expand(PRK, info, L) */
1470 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1471 os_memset(prk
, 0, hash_len
);
1475 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1481 static void dpp_build_attr_status(struct wpabuf
*msg
,
1482 enum dpp_status_error status
)
1484 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1485 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1486 wpabuf_put_le16(msg
, 1);
1487 wpabuf_put_u8(msg
, status
);
1491 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1495 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1496 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1497 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1498 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1503 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1507 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1508 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1509 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1510 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1515 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1516 const struct wpabuf
*pi
,
1518 const u8
*r_pubkey_hash
,
1519 const u8
*i_pubkey_hash
,
1520 unsigned int neg_freq
)
1523 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1524 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1527 size_t len
[2], siv_len
, attr_len
;
1528 u8
*attr_start
, *attr_end
;
1530 /* Build DPP Authentication Request frame attributes */
1531 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1532 4 + sizeof(wrapped_data
);
1535 #ifdef CONFIG_TESTING_OPTIONS
1536 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1538 #endif /* CONFIG_TESTING_OPTIONS */
1539 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1543 attr_start
= wpabuf_put(msg
, 0);
1545 /* Responder Bootstrapping Key Hash */
1546 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1548 /* Initiator Bootstrapping Key Hash */
1549 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1551 /* Initiator Protocol Key */
1553 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1554 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1555 wpabuf_put_buf(msg
, pi
);
1560 u8 op_class
, channel
;
1562 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1564 NUM_HOSTAPD_MODES
) {
1565 wpa_printf(MSG_INFO
,
1566 "DPP: Unsupported negotiation frequency request: %d",
1571 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1572 wpabuf_put_le16(msg
, 2);
1573 wpabuf_put_u8(msg
, op_class
);
1574 wpabuf_put_u8(msg
, channel
);
1577 #ifdef CONFIG_TESTING_OPTIONS
1578 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1579 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1580 goto skip_wrapped_data
;
1582 #endif /* CONFIG_TESTING_OPTIONS */
1584 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1587 #ifdef CONFIG_TESTING_OPTIONS
1588 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1589 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1592 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1593 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1594 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1596 WPA_PUT_LE16(pos
, nonce_len
- 1);
1598 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1599 pos
+= nonce_len
- 1;
1602 #endif /* CONFIG_TESTING_OPTIONS */
1605 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1607 WPA_PUT_LE16(pos
, nonce_len
);
1609 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1612 #ifdef CONFIG_TESTING_OPTIONS
1614 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1615 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1618 #endif /* CONFIG_TESTING_OPTIONS */
1620 /* I-capabilities */
1621 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1623 WPA_PUT_LE16(pos
, 1);
1625 auth
->i_capab
= auth
->allowed_roles
;
1626 *pos
++ = auth
->i_capab
;
1627 #ifdef CONFIG_TESTING_OPTIONS
1628 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1629 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1633 #endif /* CONFIG_TESTING_OPTIONS */
1635 attr_end
= wpabuf_put(msg
, 0);
1637 /* OUI, OUI type, Crypto Suite, DPP frame type */
1638 addr
[0] = wpabuf_head_u8(msg
) + 2;
1639 len
[0] = 3 + 1 + 1 + 1;
1640 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1642 /* Attributes before Wrapped Data */
1643 addr
[1] = attr_start
;
1644 len
[1] = attr_end
- attr_start
;
1645 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1647 siv_len
= pos
- clear
;
1648 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1649 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1650 2, addr
, len
, wrapped_data
) < 0) {
1654 siv_len
+= AES_BLOCK_SIZE
;
1655 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1656 wrapped_data
, siv_len
);
1658 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1659 wpabuf_put_le16(msg
, siv_len
);
1660 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1662 #ifdef CONFIG_TESTING_OPTIONS
1663 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1664 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1665 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1668 #endif /* CONFIG_TESTING_OPTIONS */
1670 wpa_hexdump_buf(MSG_DEBUG
,
1671 "DPP: Authentication Request frame attributes", msg
);
1677 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1678 enum dpp_status_error status
,
1679 const struct wpabuf
*pr
,
1681 const u8
*r_pubkey_hash
,
1682 const u8
*i_pubkey_hash
,
1683 const u8
*r_nonce
, const u8
*i_nonce
,
1684 const u8
*wrapped_r_auth
,
1685 size_t wrapped_r_auth_len
,
1689 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1690 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1691 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1692 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1694 size_t len
[2], siv_len
, attr_len
;
1695 u8
*attr_start
, *attr_end
, *pos
;
1697 auth
->waiting_auth_conf
= 1;
1698 auth
->auth_resp_tries
= 0;
1700 /* Build DPP Authentication Response frame attributes */
1701 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1702 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1703 #ifdef CONFIG_TESTING_OPTIONS
1704 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1706 #endif /* CONFIG_TESTING_OPTIONS */
1707 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1711 attr_start
= wpabuf_put(msg
, 0);
1715 dpp_build_attr_status(msg
, status
);
1717 /* Responder Bootstrapping Key Hash */
1718 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1720 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1721 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1723 /* Responder Protocol Key */
1725 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1726 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1727 wpabuf_put_buf(msg
, pr
);
1730 attr_end
= wpabuf_put(msg
, 0);
1732 #ifdef CONFIG_TESTING_OPTIONS
1733 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1734 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1735 goto skip_wrapped_data
;
1737 #endif /* CONFIG_TESTING_OPTIONS */
1739 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1744 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1746 WPA_PUT_LE16(pos
, nonce_len
);
1748 os_memcpy(pos
, r_nonce
, nonce_len
);
1754 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1756 WPA_PUT_LE16(pos
, nonce_len
);
1758 os_memcpy(pos
, i_nonce
, nonce_len
);
1759 #ifdef CONFIG_TESTING_OPTIONS
1760 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1761 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1762 pos
[nonce_len
/ 2] ^= 0x01;
1764 #endif /* CONFIG_TESTING_OPTIONS */
1768 #ifdef CONFIG_TESTING_OPTIONS
1769 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1770 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1773 #endif /* CONFIG_TESTING_OPTIONS */
1775 /* R-capabilities */
1776 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1778 WPA_PUT_LE16(pos
, 1);
1780 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1782 *pos
++ = auth
->r_capab
;
1783 #ifdef CONFIG_TESTING_OPTIONS
1784 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1785 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1787 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1788 wpa_printf(MSG_INFO
,
1789 "DPP: TESTING - incompatible R-capabilities");
1790 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1791 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1794 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1795 DPP_CAPAB_CONFIGURATOR
;
1798 #endif /* CONFIG_TESTING_OPTIONS */
1800 if (wrapped_r_auth
) {
1802 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1804 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1806 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1807 pos
+= wrapped_r_auth_len
;
1810 /* OUI, OUI type, Crypto Suite, DPP frame type */
1811 addr
[0] = wpabuf_head_u8(msg
) + 2;
1812 len
[0] = 3 + 1 + 1 + 1;
1813 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1815 /* Attributes before Wrapped Data */
1816 addr
[1] = attr_start
;
1817 len
[1] = attr_end
- attr_start
;
1818 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1820 siv_len
= pos
- clear
;
1821 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1822 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1823 2, addr
, len
, wrapped_data
) < 0) {
1827 siv_len
+= AES_BLOCK_SIZE
;
1828 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1829 wrapped_data
, siv_len
);
1831 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1832 wpabuf_put_le16(msg
, siv_len
);
1833 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1835 #ifdef CONFIG_TESTING_OPTIONS
1836 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1837 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1838 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1841 #endif /* CONFIG_TESTING_OPTIONS */
1843 wpa_hexdump_buf(MSG_DEBUG
,
1844 "DPP: Authentication Response frame attributes", msg
);
1849 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1850 u16 num_modes
, unsigned int freq
)
1855 if (!own_modes
|| !num_modes
)
1858 for (m
= 0; m
< num_modes
; m
++) {
1859 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1860 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1863 flag
= own_modes
[m
].channels
[c
].flag
;
1864 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1865 HOSTAPD_CHAN_NO_IR
|
1866 HOSTAPD_CHAN_RADAR
)))
1871 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1876 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1880 if (freqs
[--num
] == freq
)
1887 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1892 for (i
= 0; i
< num
; i
++) {
1893 if (freqs
[i
] == freq
)
1896 if (i
== 0 || i
>= num
)
1898 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1903 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1904 struct hostapd_hw_modes
*own_modes
,
1907 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1908 unsigned int i
, freq
;
1910 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
1911 freq
= peer_bi
->freq
[i
];
1912 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1914 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
1915 auth
->freq
[auth
->num_freq
++] = freq
;
1917 if (!auth
->num_freq
) {
1918 wpa_printf(MSG_INFO
,
1919 "DPP: No available channels for initiating DPP Authentication");
1922 auth
->curr_freq
= auth
->freq
[0];
1927 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
1928 struct hostapd_hw_modes
*own_modes
,
1937 if (!own_modes
|| !num_modes
) {
1938 auth
->freq
[0] = 2412;
1939 auth
->freq
[1] = 2437;
1940 auth
->freq
[2] = 2462;
1945 for (m
= 0; m
< num_modes
; m
++) {
1946 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1947 freq
= own_modes
[m
].channels
[c
].freq
;
1948 flag
= own_modes
[m
].channels
[c
].flag
;
1949 if (flag
& (HOSTAPD_CHAN_DISABLED
|
1950 HOSTAPD_CHAN_NO_IR
|
1951 HOSTAPD_CHAN_RADAR
))
1953 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
1955 auth
->freq
[auth
->num_freq
++] = freq
;
1956 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
1963 return auth
->num_freq
== 0 ? -1 : 0;
1967 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
1968 struct hostapd_hw_modes
*own_modes
,
1972 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
1975 if (auth
->peer_bi
->num_freq
> 0)
1976 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
1978 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
1982 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1983 * likely channels first. */
1984 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
1985 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
1986 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
1989 auth
->curr_freq
= auth
->freq
[0];
1992 end
= pos
+ sizeof(freqs
);
1993 for (i
= 0; i
< auth
->num_freq
; i
++) {
1994 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
1995 if (os_snprintf_error(end
- pos
, res
))
2000 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2007 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2009 struct dpp_bootstrap_info
*bi
;
2014 return 0; /* already generated */
2016 bi
= os_zalloc(sizeof(*bi
));
2019 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2020 pk
= dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0);
2024 len
= 4; /* "DPP:" */
2025 len
+= 4 + os_strlen(pk
);
2026 bi
->uri
= os_malloc(len
+ 1);
2029 os_snprintf(bi
->uri
, len
+ 1, "DPP:K:%s;;", pk
);
2030 wpa_printf(MSG_DEBUG
,
2031 "DPP: Auto-generated own bootstrapping key info: URI %s",
2034 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2041 dpp_bootstrap_info_free(bi
);
2046 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2047 struct dpp_bootstrap_info
*peer_bi
,
2048 struct dpp_bootstrap_info
*own_bi
,
2049 u8 dpp_allowed_roles
,
2050 unsigned int neg_freq
,
2051 struct hostapd_hw_modes
*own_modes
,
2054 struct dpp_authentication
*auth
;
2056 EVP_PKEY_CTX
*ctx
= NULL
;
2058 struct wpabuf
*pi
= NULL
;
2059 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2060 #ifdef CONFIG_TESTING_OPTIONS
2061 u8 test_hash
[SHA256_MAC_LEN
];
2062 #endif /* CONFIG_TESTING_OPTIONS */
2064 auth
= os_zalloc(sizeof(*auth
));
2067 auth
->msg_ctx
= msg_ctx
;
2068 auth
->initiator
= 1;
2069 auth
->waiting_auth_resp
= 1;
2070 auth
->allowed_roles
= dpp_allowed_roles
;
2071 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2072 auth
->peer_bi
= peer_bi
;
2073 auth
->own_bi
= own_bi
;
2074 auth
->curve
= peer_bi
->curve
;
2076 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2077 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2080 #ifdef CONFIG_TESTING_OPTIONS
2081 if (dpp_nonce_override_len
> 0) {
2082 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2083 nonce_len
= dpp_nonce_override_len
;
2084 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2086 nonce_len
= auth
->curve
->nonce_len
;
2087 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2088 wpa_printf(MSG_ERROR
,
2089 "DPP: Failed to generate I-nonce");
2093 #else /* CONFIG_TESTING_OPTIONS */
2094 nonce_len
= auth
->curve
->nonce_len
;
2095 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2096 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2099 #endif /* CONFIG_TESTING_OPTIONS */
2100 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2102 #ifdef CONFIG_TESTING_OPTIONS
2103 if (dpp_protocol_key_override_len
) {
2104 const struct dpp_curve_params
*tmp_curve
;
2106 wpa_printf(MSG_INFO
,
2107 "DPP: TESTING - override protocol key");
2108 auth
->own_protocol_key
= dpp_set_keypair(
2109 &tmp_curve
, dpp_protocol_key_override
,
2110 dpp_protocol_key_override_len
);
2112 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2114 #else /* CONFIG_TESTING_OPTIONS */
2115 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2116 #endif /* CONFIG_TESTING_OPTIONS */
2117 if (!auth
->own_protocol_key
)
2120 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2124 /* ECDH: M = pI * BR */
2125 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2127 EVP_PKEY_derive_init(ctx
) != 1 ||
2128 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
2129 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2130 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2131 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2132 wpa_printf(MSG_ERROR
,
2133 "DPP: Failed to derive ECDH shared secret: %s",
2134 ERR_error_string(ERR_get_error(), NULL
));
2137 auth
->secret_len
= secret_len
;
2138 EVP_PKEY_CTX_free(ctx
);
2141 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2142 auth
->Mx
, auth
->secret_len
);
2143 auth
->Mx_len
= auth
->secret_len
;
2145 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2146 auth
->curve
->hash_len
) < 0)
2149 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2150 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2152 #ifdef CONFIG_TESTING_OPTIONS
2153 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2154 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2155 r_pubkey_hash
= NULL
;
2156 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2157 wpa_printf(MSG_INFO
,
2158 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2159 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2160 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2161 r_pubkey_hash
= test_hash
;
2162 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2163 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2164 i_pubkey_hash
= NULL
;
2165 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2166 wpa_printf(MSG_INFO
,
2167 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2168 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2169 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2170 i_pubkey_hash
= test_hash
;
2171 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2172 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2175 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2176 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2178 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2179 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2182 #endif /* CONFIG_TESTING_OPTIONS */
2184 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2185 i_pubkey_hash
, neg_freq
);
2191 EVP_PKEY_CTX_free(ctx
);
2194 dpp_auth_deinit(auth
);
2200 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2204 size_t json_len
, clear_len
;
2205 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2209 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2211 nonce_len
= auth
->curve
->nonce_len
;
2212 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2213 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2216 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2217 json_len
= os_strlen(json
);
2218 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
2220 /* { E-nonce, configAttrib }ke */
2221 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2222 clear
= wpabuf_alloc(clear_len
);
2223 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2224 #ifdef CONFIG_TESTING_OPTIONS
2225 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2227 #endif /* CONFIG_TESTING_OPTIONS */
2228 msg
= wpabuf_alloc(attr_len
);
2232 #ifdef CONFIG_TESTING_OPTIONS
2233 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2234 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2237 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2238 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2239 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2240 wpabuf_put_le16(clear
, nonce_len
- 1);
2241 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2244 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2245 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2246 goto skip_wrapped_data
;
2248 #endif /* CONFIG_TESTING_OPTIONS */
2251 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2252 wpabuf_put_le16(clear
, nonce_len
);
2253 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2255 #ifdef CONFIG_TESTING_OPTIONS
2257 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2258 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2259 goto skip_conf_attr_obj
;
2261 #endif /* CONFIG_TESTING_OPTIONS */
2264 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2265 wpabuf_put_le16(clear
, json_len
);
2266 wpabuf_put_data(clear
, json
, json_len
);
2268 #ifdef CONFIG_TESTING_OPTIONS
2270 #endif /* CONFIG_TESTING_OPTIONS */
2272 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2273 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2274 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2277 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2278 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2279 wpabuf_head(clear
), wpabuf_len(clear
),
2280 0, NULL
, NULL
, wrapped
) < 0)
2282 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2283 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2285 #ifdef CONFIG_TESTING_OPTIONS
2286 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2287 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2288 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2291 #endif /* CONFIG_TESTING_OPTIONS */
2293 wpa_hexdump_buf(MSG_DEBUG
,
2294 "DPP: Configuration Request frame attributes", msg
);
2305 static void dpp_auth_success(struct dpp_authentication
*auth
)
2307 wpa_printf(MSG_DEBUG
,
2308 "DPP: Authentication success - clear temporary keys");
2309 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2311 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2313 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2315 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2316 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2318 auth
->auth_success
= 1;
2322 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2324 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2327 size_t i
, num_elem
= 0;
2332 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2333 nonce_len
= auth
->curve
->nonce_len
;
2335 if (auth
->initiator
) {
2336 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2337 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2339 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2342 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2344 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2345 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2347 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2350 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2352 if (!pix
|| !prx
|| !brx
)
2355 addr
[num_elem
] = auth
->i_nonce
;
2356 len
[num_elem
] = nonce_len
;
2359 addr
[num_elem
] = auth
->r_nonce
;
2360 len
[num_elem
] = nonce_len
;
2363 addr
[num_elem
] = wpabuf_head(pix
);
2364 len
[num_elem
] = wpabuf_len(pix
) / 2;
2367 addr
[num_elem
] = wpabuf_head(prx
);
2368 len
[num_elem
] = wpabuf_len(prx
) / 2;
2372 addr
[num_elem
] = wpabuf_head(bix
);
2373 len
[num_elem
] = wpabuf_len(bix
) / 2;
2377 addr
[num_elem
] = wpabuf_head(brx
);
2378 len
[num_elem
] = wpabuf_len(brx
) / 2;
2381 addr
[num_elem
] = &zero
;
2385 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2386 for (i
= 0; i
< num_elem
; i
++)
2387 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2388 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2390 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2391 auth
->curve
->hash_len
);
2401 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2403 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2406 size_t i
, num_elem
= 0;
2411 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2412 nonce_len
= auth
->curve
->nonce_len
;
2414 if (auth
->initiator
) {
2415 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2416 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2418 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2423 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2425 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2426 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2428 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2433 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2435 if (!pix
|| !prx
|| !brx
)
2438 addr
[num_elem
] = auth
->r_nonce
;
2439 len
[num_elem
] = nonce_len
;
2442 addr
[num_elem
] = auth
->i_nonce
;
2443 len
[num_elem
] = nonce_len
;
2446 addr
[num_elem
] = wpabuf_head(prx
);
2447 len
[num_elem
] = wpabuf_len(prx
) / 2;
2450 addr
[num_elem
] = wpabuf_head(pix
);
2451 len
[num_elem
] = wpabuf_len(pix
) / 2;
2454 addr
[num_elem
] = wpabuf_head(brx
);
2455 len
[num_elem
] = wpabuf_len(brx
) / 2;
2459 addr
[num_elem
] = wpabuf_head(bix
);
2460 len
[num_elem
] = wpabuf_len(bix
) / 2;
2464 addr
[num_elem
] = &one
;
2468 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2469 for (i
= 0; i
< num_elem
; i
++)
2470 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2471 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2473 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2474 auth
->curve
->hash_len
);
2484 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2486 const EC_GROUP
*group
;
2488 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2489 const EC_POINT
*BI_point
;
2491 BIGNUM
*lx
, *sum
, *q
;
2492 const BIGNUM
*bR_bn
, *pR_bn
;
2495 /* L = ((bR + pR) modulo q) * BI */
2497 bnctx
= BN_CTX_new();
2501 if (!bnctx
|| !sum
|| !q
|| !lx
)
2503 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2506 BI_point
= EC_KEY_get0_public_key(BI
);
2507 group
= EC_KEY_get0_group(BI
);
2511 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2512 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2515 bR_bn
= EC_KEY_get0_private_key(bR
);
2516 pR_bn
= EC_KEY_get0_private_key(pR
);
2517 if (!bR_bn
|| !pR_bn
)
2519 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2520 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2522 l
= EC_POINT_new(group
);
2524 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2525 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2527 wpa_printf(MSG_ERROR
,
2528 "OpenSSL: failed: %s",
2529 ERR_error_string(ERR_get_error(), NULL
));
2533 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2535 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2536 auth
->Lx_len
= auth
->secret_len
;
2539 EC_POINT_clear_free(l
);
2551 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2553 const EC_GROUP
*group
;
2554 EC_POINT
*l
= NULL
, *sum
= NULL
;
2555 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2556 const EC_POINT
*BR_point
, *PR_point
;
2559 const BIGNUM
*bI_bn
;
2562 /* L = bI * (BR + PR) */
2564 bnctx
= BN_CTX_new();
2568 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2569 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2572 BR_point
= EC_KEY_get0_public_key(BR
);
2573 PR_point
= EC_KEY_get0_public_key(PR
);
2575 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2578 group
= EC_KEY_get0_group(bI
);
2579 bI_bn
= EC_KEY_get0_private_key(bI
);
2580 if (!group
|| !bI_bn
)
2582 sum
= EC_POINT_new(group
);
2583 l
= EC_POINT_new(group
);
2585 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2586 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2587 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2589 wpa_printf(MSG_ERROR
,
2590 "OpenSSL: failed: %s",
2591 ERR_error_string(ERR_get_error(), NULL
));
2595 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2597 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2598 auth
->Lx_len
= auth
->secret_len
;
2601 EC_POINT_clear_free(l
);
2611 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2614 EVP_PKEY_CTX
*ctx
= NULL
;
2616 struct wpabuf
*msg
, *pr
= NULL
;
2617 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2618 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2619 size_t wrapped_r_auth_len
;
2621 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2622 enum dpp_status_error status
= DPP_STATUS_OK
;
2623 #ifdef CONFIG_TESTING_OPTIONS
2624 u8 test_hash
[SHA256_MAC_LEN
];
2625 #endif /* CONFIG_TESTING_OPTIONS */
2627 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2631 #ifdef CONFIG_TESTING_OPTIONS
2632 if (dpp_nonce_override_len
> 0) {
2633 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
2634 nonce_len
= dpp_nonce_override_len
;
2635 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
2637 nonce_len
= auth
->curve
->nonce_len
;
2638 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2639 wpa_printf(MSG_ERROR
,
2640 "DPP: Failed to generate R-nonce");
2644 #else /* CONFIG_TESTING_OPTIONS */
2645 nonce_len
= auth
->curve
->nonce_len
;
2646 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2647 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2650 #endif /* CONFIG_TESTING_OPTIONS */
2651 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2653 #ifdef CONFIG_TESTING_OPTIONS
2654 if (dpp_protocol_key_override_len
) {
2655 const struct dpp_curve_params
*tmp_curve
;
2657 wpa_printf(MSG_INFO
,
2658 "DPP: TESTING - override protocol key");
2659 auth
->own_protocol_key
= dpp_set_keypair(
2660 &tmp_curve
, dpp_protocol_key_override
,
2661 dpp_protocol_key_override_len
);
2663 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2665 #else /* CONFIG_TESTING_OPTIONS */
2666 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2667 #endif /* CONFIG_TESTING_OPTIONS */
2668 if (!auth
->own_protocol_key
)
2671 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2675 /* ECDH: N = pR * PI */
2676 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2678 EVP_PKEY_derive_init(ctx
) != 1 ||
2679 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2680 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2681 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2682 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2683 wpa_printf(MSG_ERROR
,
2684 "DPP: Failed to derive ECDH shared secret: %s",
2685 ERR_error_string(ERR_get_error(), NULL
));
2688 EVP_PKEY_CTX_free(ctx
);
2691 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2692 auth
->Nx
, auth
->secret_len
);
2693 auth
->Nx_len
= auth
->secret_len
;
2695 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2696 auth
->curve
->hash_len
) < 0)
2699 if (auth
->own_bi
&& auth
->peer_bi
) {
2700 /* Mutual authentication */
2701 if (dpp_auth_derive_l_responder(auth
) < 0)
2705 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2708 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2709 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2710 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2711 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2713 #ifdef CONFIG_TESTING_OPTIONS
2714 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2715 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2716 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2718 #endif /* CONFIG_TESTING_OPTIONS */
2719 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2720 r_auth
, 4 + auth
->curve
->hash_len
,
2721 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2723 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2724 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2725 wrapped_r_auth
, wrapped_r_auth_len
);
2726 w_r_auth
= wrapped_r_auth
;
2728 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2730 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2732 i_pubkey_hash
= NULL
;
2734 i_nonce
= auth
->i_nonce
;
2735 r_nonce
= auth
->r_nonce
;
2737 #ifdef CONFIG_TESTING_OPTIONS
2738 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2739 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2740 r_pubkey_hash
= NULL
;
2741 } else if (dpp_test
==
2742 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2743 wpa_printf(MSG_INFO
,
2744 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2745 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2746 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2747 r_pubkey_hash
= test_hash
;
2748 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2749 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2750 i_pubkey_hash
= NULL
;
2751 } else if (dpp_test
==
2752 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2753 wpa_printf(MSG_INFO
,
2754 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2756 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2758 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2759 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2760 i_pubkey_hash
= test_hash
;
2761 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2762 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2765 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
2766 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
2768 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2769 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
2771 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2772 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2774 wrapped_r_auth_len
= 0;
2775 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2776 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2778 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
2779 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
2781 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2782 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2784 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2785 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2788 #endif /* CONFIG_TESTING_OPTIONS */
2790 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2791 r_pubkey_hash
, i_pubkey_hash
,
2793 w_r_auth
, wrapped_r_auth_len
,
2797 wpabuf_free(auth
->resp_msg
);
2798 auth
->resp_msg
= msg
;
2806 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2807 enum dpp_status_error status
)
2810 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2811 #ifdef CONFIG_TESTING_OPTIONS
2812 u8 test_hash
[SHA256_MAC_LEN
];
2813 #endif /* CONFIG_TESTING_OPTIONS */
2817 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2819 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2821 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2823 i_pubkey_hash
= NULL
;
2825 i_nonce
= auth
->i_nonce
;
2827 #ifdef CONFIG_TESTING_OPTIONS
2828 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2829 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2830 r_pubkey_hash
= NULL
;
2831 } else if (dpp_test
==
2832 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2833 wpa_printf(MSG_INFO
,
2834 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2835 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2836 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2837 r_pubkey_hash
= test_hash
;
2838 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2839 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2840 i_pubkey_hash
= NULL
;
2841 } else if (dpp_test
==
2842 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2843 wpa_printf(MSG_INFO
,
2844 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2846 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2848 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2849 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2850 i_pubkey_hash
= test_hash
;
2851 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2852 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2854 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2855 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2858 #endif /* CONFIG_TESTING_OPTIONS */
2860 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
2861 r_pubkey_hash
, i_pubkey_hash
,
2862 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
2865 wpabuf_free(auth
->resp_msg
);
2866 auth
->resp_msg
= msg
;
2871 struct dpp_authentication
*
2872 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
2873 struct dpp_bootstrap_info
*peer_bi
,
2874 struct dpp_bootstrap_info
*own_bi
,
2875 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
2878 EVP_PKEY
*pi
= NULL
;
2879 EVP_PKEY_CTX
*ctx
= NULL
;
2883 u8
*unwrapped
= NULL
;
2884 size_t unwrapped_len
= 0;
2885 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
2887 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
2888 i_bootstrap_len
, channel_len
;
2889 struct dpp_authentication
*auth
= NULL
;
2891 #ifdef CONFIG_TESTING_OPTIONS
2892 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
2893 wpa_printf(MSG_INFO
,
2894 "DPP: TESTING - stop at Authentication Request");
2897 #endif /* CONFIG_TESTING_OPTIONS */
2899 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
2901 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
2902 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
2903 "Missing or invalid required Wrapped Data attribute");
2906 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
2907 wrapped_data
, wrapped_data_len
);
2908 attr_len
= wrapped_data
- 4 - attr_start
;
2910 auth
= os_zalloc(sizeof(*auth
));
2913 auth
->msg_ctx
= msg_ctx
;
2914 auth
->peer_bi
= peer_bi
;
2915 auth
->own_bi
= own_bi
;
2916 auth
->curve
= own_bi
->curve
;
2917 auth
->curr_freq
= freq
;
2919 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
2924 if (channel_len
< 2) {
2925 dpp_auth_fail(auth
, "Too short Channel attribute");
2929 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
2930 wpa_printf(MSG_DEBUG
,
2931 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2932 channel
[0], channel
[1], neg_freq
);
2935 "Unsupported Channel attribute value");
2939 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
2940 wpa_printf(MSG_DEBUG
,
2941 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2943 auth
->curr_freq
= neg_freq
;
2947 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
2951 "Missing required Initiator Protocol Key attribute");
2954 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
2955 i_proto
, i_proto_len
);
2958 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
2960 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
2963 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
2965 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
2967 EVP_PKEY_derive_init(ctx
) != 1 ||
2968 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
2969 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2970 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2971 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2972 wpa_printf(MSG_ERROR
,
2973 "DPP: Failed to derive ECDH shared secret: %s",
2974 ERR_error_string(ERR_get_error(), NULL
));
2975 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
2978 auth
->secret_len
= secret_len
;
2979 EVP_PKEY_CTX_free(ctx
);
2982 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2983 auth
->Mx
, auth
->secret_len
);
2984 auth
->Mx_len
= auth
->secret_len
;
2986 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2987 auth
->curve
->hash_len
) < 0)
2991 len
[0] = DPP_HDR_LEN
;
2992 addr
[1] = attr_start
;
2994 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2995 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2996 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2997 wrapped_data
, wrapped_data_len
);
2998 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
2999 unwrapped
= os_malloc(unwrapped_len
);
3002 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3003 wrapped_data
, wrapped_data_len
,
3004 2, addr
, len
, unwrapped
) < 0) {
3005 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3008 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3009 unwrapped
, unwrapped_len
);
3011 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3012 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3016 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3018 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3019 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3022 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3023 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3025 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3026 DPP_ATTR_I_CAPABILITIES
,
3028 if (!i_capab
|| i_capab_len
< 1) {
3029 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3032 auth
->i_capab
= i_capab
[0];
3033 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3035 bin_clear_free(unwrapped
, unwrapped_len
);
3038 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3039 case DPP_CAPAB_ENROLLEE
:
3040 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3041 wpa_printf(MSG_DEBUG
,
3042 "DPP: Local policy does not allow Configurator role");
3043 goto not_compatible
;
3045 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3046 auth
->configurator
= 1;
3048 case DPP_CAPAB_CONFIGURATOR
:
3049 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3050 wpa_printf(MSG_DEBUG
,
3051 "DPP: Local policy does not allow Enrollee role");
3052 goto not_compatible
;
3054 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3055 auth
->configurator
= 0;
3057 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3058 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3059 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3060 auth
->configurator
= 0;
3061 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3062 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3063 auth
->configurator
= 1;
3065 wpa_printf(MSG_DEBUG
,
3066 "DPP: Local policy does not allow Configurator/Enrollee role");
3067 goto not_compatible
;
3071 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3072 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3073 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3074 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3078 auth
->peer_protocol_key
= pi
;
3080 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3081 char hex
[SHA256_MAC_LEN
* 2 + 1];
3083 wpa_printf(MSG_DEBUG
,
3084 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3085 if (dpp_auth_build_resp_status(auth
,
3086 DPP_STATUS_RESPONSE_PENDING
) < 0)
3088 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3089 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3091 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3092 auth
->response_pending
= 1;
3093 os_memcpy(auth
->waiting_pubkey_hash
,
3094 i_bootstrap
, i_bootstrap_len
);
3095 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3101 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3105 if (dpp_auth_build_resp_ok(auth
) < 0)
3111 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3112 "i-capab=0x%02x", auth
->i_capab
);
3113 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3114 auth
->configurator
= 1;
3116 auth
->configurator
= 0;
3117 auth
->peer_protocol_key
= pi
;
3119 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3122 auth
->remove_on_tx_status
= 1;
3125 bin_clear_free(unwrapped
, unwrapped_len
);
3127 EVP_PKEY_CTX_free(ctx
);
3128 dpp_auth_deinit(auth
);
3133 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3134 struct dpp_bootstrap_info
*peer_bi
)
3136 if (!auth
|| !auth
->response_pending
||
3137 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3138 SHA256_MAC_LEN
) != 0)
3141 wpa_printf(MSG_DEBUG
,
3142 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3143 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3144 auth
->peer_bi
= peer_bi
;
3146 if (dpp_auth_build_resp_ok(auth
) < 0)
3153 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3154 enum dpp_status_error status
)
3157 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3159 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3162 size_t len
[2], attr_len
;
3164 u8
*wrapped_r_nonce
;
3165 u8
*attr_start
, *attr_end
;
3166 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3167 #ifdef CONFIG_TESTING_OPTIONS
3168 u8 test_hash
[SHA256_MAC_LEN
];
3169 #endif /* CONFIG_TESTING_OPTIONS */
3171 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3173 i_auth_len
= 4 + auth
->curve
->hash_len
;
3174 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3175 /* Build DPP Authentication Confirmation frame attributes */
3176 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3177 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3178 #ifdef CONFIG_TESTING_OPTIONS
3179 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3181 #endif /* CONFIG_TESTING_OPTIONS */
3182 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3186 attr_start
= wpabuf_put(msg
, 0);
3188 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3190 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3192 i_pubkey_hash
= NULL
;
3194 #ifdef CONFIG_TESTING_OPTIONS
3195 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3196 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3198 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3199 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3202 #endif /* CONFIG_TESTING_OPTIONS */
3205 dpp_build_attr_status(msg
, status
);
3207 #ifdef CONFIG_TESTING_OPTIONS
3209 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3210 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3211 r_pubkey_hash
= NULL
;
3212 } else if (dpp_test
==
3213 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3214 wpa_printf(MSG_INFO
,
3215 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3216 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3217 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3218 r_pubkey_hash
= test_hash
;
3219 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3220 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3221 i_pubkey_hash
= NULL
;
3222 } else if (dpp_test
==
3223 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3224 wpa_printf(MSG_INFO
,
3225 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3227 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3229 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3230 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3231 i_pubkey_hash
= test_hash
;
3233 #endif /* CONFIG_TESTING_OPTIONS */
3235 /* Responder Bootstrapping Key Hash */
3236 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3238 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3239 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3241 #ifdef CONFIG_TESTING_OPTIONS
3242 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3243 goto skip_wrapped_data
;
3244 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3246 #endif /* CONFIG_TESTING_OPTIONS */
3248 attr_end
= wpabuf_put(msg
, 0);
3250 /* OUI, OUI type, Crypto Suite, DPP frame type */
3251 addr
[0] = wpabuf_head_u8(msg
) + 2;
3252 len
[0] = 3 + 1 + 1 + 1;
3253 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3255 /* Attributes before Wrapped Data */
3256 addr
[1] = attr_start
;
3257 len
[1] = attr_end
- attr_start
;
3258 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3260 if (status
== DPP_STATUS_OK
) {
3261 /* I-auth wrapped with ke */
3262 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3263 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3264 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3266 #ifdef CONFIG_TESTING_OPTIONS
3267 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3269 #endif /* CONFIG_TESTING_OPTIONS */
3271 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3273 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3274 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3275 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3278 #ifdef CONFIG_TESTING_OPTIONS
3279 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3280 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3281 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3284 #endif /* CONFIG_TESTING_OPTIONS */
3285 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3287 2, addr
, len
, wrapped_i_auth
) < 0)
3289 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3290 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3292 /* R-nonce wrapped with k2 */
3293 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3294 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3295 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3297 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3298 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3299 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3301 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3302 r_nonce
, r_nonce_len
,
3303 2, addr
, len
, wrapped_r_nonce
) < 0)
3305 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3306 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3309 #ifdef CONFIG_TESTING_OPTIONS
3310 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3311 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3312 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3315 #endif /* CONFIG_TESTING_OPTIONS */
3317 wpa_hexdump_buf(MSG_DEBUG
,
3318 "DPP: Authentication Confirmation frame attributes",
3320 if (status
== DPP_STATUS_OK
)
3321 dpp_auth_success(auth
);
3332 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3333 const u8
*attr_start
, size_t attr_len
,
3334 const u8
*wrapped_data
, u16 wrapped_data_len
,
3335 enum dpp_status_error status
)
3339 u8
*unwrapped
= NULL
;
3340 size_t unwrapped_len
= 0;
3341 const u8
*i_nonce
, *r_capab
;
3342 u16 i_nonce_len
, r_capab_len
;
3344 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3345 wpa_printf(MSG_DEBUG
,
3346 "DPP: Responder reported incompatible roles");
3347 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3348 wpa_printf(MSG_DEBUG
,
3349 "DPP: Responder reported more time needed");
3351 wpa_printf(MSG_DEBUG
,
3352 "DPP: Responder reported failure (status %d)",
3354 dpp_auth_fail(auth
, "Responder reported failure");
3359 len
[0] = DPP_HDR_LEN
;
3360 addr
[1] = attr_start
;
3362 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3363 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3364 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3365 wrapped_data
, wrapped_data_len
);
3366 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3367 unwrapped
= os_malloc(unwrapped_len
);
3370 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3371 wrapped_data
, wrapped_data_len
,
3372 2, addr
, len
, unwrapped
) < 0) {
3373 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3376 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3377 unwrapped
, unwrapped_len
);
3379 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3380 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3384 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3386 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3387 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3390 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3391 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3392 dpp_auth_fail(auth
, "I-nonce mismatch");
3396 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3397 DPP_ATTR_R_CAPABILITIES
,
3399 if (!r_capab
|| r_capab_len
< 1) {
3400 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3403 auth
->r_capab
= r_capab
[0];
3404 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3405 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3406 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3407 "r-capab=0x%02x", auth
->r_capab
);
3408 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3409 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3411 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3412 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3413 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3414 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3417 wpa_printf(MSG_DEBUG
,
3418 "DPP: Continue waiting for full DPP Authentication Response");
3419 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3420 DPP_EVENT_RESPONSE_PENDING
"%s",
3421 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3425 bin_clear_free(unwrapped
, unwrapped_len
);
3430 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3431 const u8
*attr_start
, size_t attr_len
)
3434 EVP_PKEY_CTX
*ctx
= NULL
;
3438 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3439 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3440 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3441 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3442 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3443 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3444 wrapped2_len
, r_auth_len
;
3445 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3448 #ifdef CONFIG_TESTING_OPTIONS
3449 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3450 wpa_printf(MSG_INFO
,
3451 "DPP: TESTING - stop at Authentication Response");
3454 #endif /* CONFIG_TESTING_OPTIONS */
3456 if (!auth
->initiator
) {
3457 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3461 auth
->waiting_auth_resp
= 0;
3463 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3465 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3467 "Missing or invalid required Wrapped Data attribute");
3470 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3471 wrapped_data
, wrapped_data_len
);
3473 attr_len
= wrapped_data
- 4 - attr_start
;
3475 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3476 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3478 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3480 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3483 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3484 r_bootstrap
, r_bootstrap_len
);
3485 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3486 SHA256_MAC_LEN
) != 0) {
3488 "Unexpected Responder Bootstrapping Key Hash value");
3489 wpa_hexdump(MSG_DEBUG
,
3490 "DPP: Expected Responder Bootstrapping Key Hash",
3491 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3495 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3496 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3499 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3501 "Invalid Initiator Bootstrapping Key Hash attribute");
3504 wpa_hexdump(MSG_MSGDUMP
,
3505 "DPP: Initiator Bootstrapping Key Hash",
3506 i_bootstrap
, i_bootstrap_len
);
3507 if (!auth
->own_bi
||
3508 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3509 SHA256_MAC_LEN
) != 0) {
3511 "Initiator Bootstrapping Key Hash attribute did not match");
3514 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3515 /* PKEX bootstrapping mandates use of mutual authentication */
3517 "Missing Initiator Bootstrapping Key Hash attribute");
3521 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3523 if (!status
|| status_len
< 1) {
3525 "Missing or invalid required DPP Status attribute");
3528 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3529 auth
->auth_resp_status
= status
[0];
3530 if (status
[0] != DPP_STATUS_OK
) {
3531 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3532 attr_len
, wrapped_data
,
3533 wrapped_data_len
, status
[0]);
3537 if (!i_bootstrap
&& auth
->own_bi
) {
3538 wpa_printf(MSG_DEBUG
,
3539 "DPP: Responder decided not to use mutual authentication");
3540 auth
->own_bi
= NULL
;
3543 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3544 auth
->own_bi
!= NULL
);
3546 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3550 "Missing required Responder Protocol Key attribute");
3553 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3554 r_proto
, r_proto_len
);
3557 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3559 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3562 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3564 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3566 EVP_PKEY_derive_init(ctx
) != 1 ||
3567 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3568 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3569 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3570 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3571 wpa_printf(MSG_ERROR
,
3572 "DPP: Failed to derive ECDH shared secret: %s",
3573 ERR_error_string(ERR_get_error(), NULL
));
3574 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3577 EVP_PKEY_CTX_free(ctx
);
3579 auth
->peer_protocol_key
= pr
;
3582 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3583 auth
->Nx
, auth
->secret_len
);
3584 auth
->Nx_len
= auth
->secret_len
;
3586 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3587 auth
->curve
->hash_len
) < 0)
3591 len
[0] = DPP_HDR_LEN
;
3592 addr
[1] = attr_start
;
3594 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3595 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3596 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3597 wrapped_data
, wrapped_data_len
);
3598 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3599 unwrapped
= os_malloc(unwrapped_len
);
3602 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3603 wrapped_data
, wrapped_data_len
,
3604 2, addr
, len
, unwrapped
) < 0) {
3605 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3608 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3609 unwrapped
, unwrapped_len
);
3611 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3612 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3616 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3618 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3619 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3622 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3623 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3625 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3627 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3628 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3631 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3632 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3633 dpp_auth_fail(auth
, "I-nonce mismatch");
3637 if (auth
->own_bi
&& auth
->peer_bi
) {
3638 /* Mutual authentication */
3639 if (dpp_auth_derive_l_initiator(auth
) < 0)
3643 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3644 DPP_ATTR_R_CAPABILITIES
,
3646 if (!r_capab
|| r_capab_len
< 1) {
3647 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3650 auth
->r_capab
= r_capab
[0];
3651 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3652 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3653 if ((auth
->allowed_roles
==
3654 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3655 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3656 /* Peer selected its role, so move from "either role" to the
3657 * role that is compatible with peer's selection. */
3658 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3659 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3660 auth
->configurator
? "Configurator" : "Enrollee");
3661 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3662 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3663 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3664 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3665 "Unexpected role in R-capabilities 0x%02x",
3667 if (role
!= DPP_CAPAB_ENROLLEE
&&
3668 role
!= DPP_CAPAB_CONFIGURATOR
)
3670 bin_clear_free(unwrapped
, unwrapped_len
);
3671 auth
->remove_on_tx_status
= 1;
3672 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3675 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3676 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3677 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3679 "Missing or invalid Secondary Wrapped Data");
3683 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3684 wrapped2
, wrapped2_len
);
3686 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3689 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3690 unwrapped2
= os_malloc(unwrapped2_len
);
3693 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3694 wrapped2
, wrapped2_len
,
3695 0, NULL
, NULL
, unwrapped2
) < 0) {
3696 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3699 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3700 unwrapped2
, unwrapped2_len
);
3702 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3704 "Invalid attribute in secondary unwrapped data");
3708 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3710 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3712 "Missing or invalid Responder Authenticating Tag");
3715 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3716 r_auth
, r_auth_len
);
3717 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3718 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3720 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3721 r_auth2
, r_auth_len
);
3722 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3723 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3724 bin_clear_free(unwrapped
, unwrapped_len
);
3725 bin_clear_free(unwrapped2
, unwrapped2_len
);
3726 auth
->remove_on_tx_status
= 1;
3727 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3730 bin_clear_free(unwrapped
, unwrapped_len
);
3731 bin_clear_free(unwrapped2
, unwrapped2_len
);
3733 #ifdef CONFIG_TESTING_OPTIONS
3734 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
3735 wpa_printf(MSG_INFO
,
3736 "DPP: TESTING - Authentication Response in place of Confirm");
3737 if (dpp_auth_build_resp_ok(auth
) < 0)
3739 return wpabuf_dup(auth
->resp_msg
);
3741 #endif /* CONFIG_TESTING_OPTIONS */
3743 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3746 bin_clear_free(unwrapped
, unwrapped_len
);
3747 bin_clear_free(unwrapped2
, unwrapped2_len
);
3749 EVP_PKEY_CTX_free(ctx
);
3754 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3756 const u8
*attr_start
, size_t attr_len
,
3757 const u8
*wrapped_data
,
3758 u16 wrapped_data_len
,
3759 enum dpp_status_error status
)
3763 u8
*unwrapped
= NULL
;
3764 size_t unwrapped_len
= 0;
3768 /* Authentication Confirm failure cases are expected to include
3769 * {R-nonce}k2 in the Wrapped Data attribute. */
3772 len
[0] = DPP_HDR_LEN
;
3773 addr
[1] = attr_start
;
3775 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3776 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3777 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3778 wrapped_data
, wrapped_data_len
);
3779 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3780 unwrapped
= os_malloc(unwrapped_len
);
3782 dpp_auth_fail(auth
, "Authentication failed");
3785 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3786 wrapped_data
, wrapped_data_len
,
3787 2, addr
, len
, unwrapped
) < 0) {
3788 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3791 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3792 unwrapped
, unwrapped_len
);
3794 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3795 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3799 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3801 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3802 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3805 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3806 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3807 r_nonce
, r_nonce_len
);
3808 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3809 auth
->r_nonce
, r_nonce_len
);
3810 dpp_auth_fail(auth
, "R-nonce mismatch");
3814 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3815 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3816 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3817 dpp_auth_fail(auth
, "Peer reported authentication failure)");
3820 bin_clear_free(unwrapped
, unwrapped_len
);
3825 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3826 const u8
*attr_start
, size_t attr_len
)
3828 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
3829 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3833 u8
*unwrapped
= NULL
;
3834 size_t unwrapped_len
= 0;
3835 u8 i_auth2
[DPP_MAX_HASH_LEN
];
3837 #ifdef CONFIG_TESTING_OPTIONS
3838 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
3839 wpa_printf(MSG_INFO
,
3840 "DPP: TESTING - stop at Authentication Confirm");
3843 #endif /* CONFIG_TESTING_OPTIONS */
3845 if (auth
->initiator
) {
3846 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
3850 auth
->waiting_auth_conf
= 0;
3852 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3854 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3856 "Missing or invalid required Wrapped Data attribute");
3859 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3860 wrapped_data
, wrapped_data_len
);
3862 attr_len
= wrapped_data
- 4 - attr_start
;
3864 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3865 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3867 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3869 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3872 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3873 r_bootstrap
, r_bootstrap_len
);
3874 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
3875 SHA256_MAC_LEN
) != 0) {
3876 wpa_hexdump(MSG_DEBUG
,
3877 "DPP: Expected Responder Bootstrapping Key Hash",
3878 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3880 "Responder Bootstrapping Key Hash mismatch");
3884 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3885 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3888 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3890 "Invalid Initiator Bootstrapping Key Hash attribute");
3893 wpa_hexdump(MSG_MSGDUMP
,
3894 "DPP: Initiator Bootstrapping Key Hash",
3895 i_bootstrap
, i_bootstrap_len
);
3896 if (!auth
->peer_bi
||
3897 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3898 SHA256_MAC_LEN
) != 0) {
3900 "Initiator Bootstrapping Key Hash mismatch");
3903 } else if (auth
->own_bi
&& auth
->peer_bi
) {
3904 /* Mutual authentication and peer did not include its
3905 * Bootstrapping Key Hash attribute. */
3907 "Missing Initiator Bootstrapping Key Hash attribute");
3911 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3913 if (!status
|| status_len
< 1) {
3915 "Missing or invalid required DPP Status attribute");
3918 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3919 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
3920 status
[0] == DPP_STATUS_AUTH_FAILURE
)
3921 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
3922 attr_len
, wrapped_data
,
3923 wrapped_data_len
, status
[0]);
3925 if (status
[0] != DPP_STATUS_OK
) {
3926 dpp_auth_fail(auth
, "Authentication failed");
3931 len
[0] = DPP_HDR_LEN
;
3932 addr
[1] = attr_start
;
3934 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3935 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3936 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3937 wrapped_data
, wrapped_data_len
);
3938 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3939 unwrapped
= os_malloc(unwrapped_len
);
3942 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3943 wrapped_data
, wrapped_data_len
,
3944 2, addr
, len
, unwrapped
) < 0) {
3945 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3948 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3949 unwrapped
, unwrapped_len
);
3951 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3952 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3956 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
3958 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
3960 "Missing or invalid Initiator Authenticating Tag");
3963 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
3964 i_auth
, i_auth_len
);
3965 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3966 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
3968 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
3969 i_auth2
, i_auth_len
);
3970 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
3971 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
3975 bin_clear_free(unwrapped
, unwrapped_len
);
3976 dpp_auth_success(auth
);
3979 bin_clear_free(unwrapped
, unwrapped_len
);
3984 void dpp_configuration_free(struct dpp_configuration
*conf
)
3988 str_clear_free(conf
->passphrase
);
3989 bin_clear_free(conf
, sizeof(*conf
));
3993 void dpp_auth_deinit(struct dpp_authentication
*auth
)
3997 dpp_configuration_free(auth
->conf_ap
);
3998 dpp_configuration_free(auth
->conf_sta
);
3999 EVP_PKEY_free(auth
->own_protocol_key
);
4000 EVP_PKEY_free(auth
->peer_protocol_key
);
4001 wpabuf_free(auth
->req_msg
);
4002 wpabuf_free(auth
->resp_msg
);
4003 wpabuf_free(auth
->conf_req
);
4004 os_free(auth
->connector
);
4005 wpabuf_free(auth
->net_access_key
);
4006 wpabuf_free(auth
->c_sign_key
);
4007 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4008 #ifdef CONFIG_TESTING_OPTIONS
4009 os_free(auth
->config_obj_override
);
4010 os_free(auth
->discovery_override
);
4011 os_free(auth
->groups_override
);
4012 #endif /* CONFIG_TESTING_OPTIONS */
4013 bin_clear_free(auth
, sizeof(*auth
));
4017 static struct wpabuf
*
4018 dpp_build_conf_start(struct dpp_authentication
*auth
,
4019 struct dpp_configuration
*conf
, size_t tailroom
)
4022 char ssid
[6 * sizeof(conf
->ssid
) + 1];
4024 #ifdef CONFIG_TESTING_OPTIONS
4025 if (auth
->discovery_override
)
4026 tailroom
+= os_strlen(auth
->discovery_override
);
4027 #endif /* CONFIG_TESTING_OPTIONS */
4029 buf
= wpabuf_alloc(200 + tailroom
);
4032 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4033 #ifdef CONFIG_TESTING_OPTIONS
4034 if (auth
->discovery_override
) {
4035 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4036 auth
->discovery_override
);
4037 wpabuf_put_str(buf
, auth
->discovery_override
);
4038 wpabuf_put_u8(buf
, ',');
4041 #endif /* CONFIG_TESTING_OPTIONS */
4042 wpabuf_put_str(buf
, "{\"ssid\":\"");
4043 json_escape_string(ssid
, sizeof(ssid
),
4044 (const char *) conf
->ssid
, conf
->ssid_len
);
4045 wpabuf_put_str(buf
, ssid
);
4046 wpabuf_put_str(buf
, "\"},");
4052 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4053 const char *kid
, const struct dpp_curve_params
*curve
)
4057 char *x
= NULL
, *y
= NULL
;
4060 pub
= dpp_get_pubkey_point(key
, 0);
4063 pos
= wpabuf_head(pub
);
4064 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4065 pos
+= curve
->prime_len
;
4066 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4070 wpabuf_put_str(buf
, "\"");
4071 wpabuf_put_str(buf
, name
);
4072 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
4073 wpabuf_put_str(buf
, curve
->jwk_crv
);
4074 wpabuf_put_str(buf
, "\",\"x\":\"");
4075 wpabuf_put_str(buf
, x
);
4076 wpabuf_put_str(buf
, "\",\"y\":\"");
4077 wpabuf_put_str(buf
, y
);
4079 wpabuf_put_str(buf
, "\",\"kid\":\"");
4080 wpabuf_put_str(buf
, kid
);
4082 wpabuf_put_str(buf
, "\"}");
4092 static struct wpabuf
*
4093 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
4094 struct dpp_configuration
*conf
)
4096 struct wpabuf
*buf
= NULL
;
4097 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4099 const struct dpp_curve_params
*curve
;
4100 char jws_prot_hdr
[100];
4101 size_t signed1_len
, signed2_len
, signed3_len
;
4102 struct wpabuf
*dppcon
= NULL
;
4103 unsigned char *signature
= NULL
;
4104 const unsigned char *p
;
4105 size_t signature_len
;
4106 EVP_MD_CTX
*md_ctx
= NULL
;
4107 ECDSA_SIG
*sig
= NULL
;
4109 const EVP_MD
*sign_md
;
4110 const BIGNUM
*r
, *s
;
4111 size_t extra_len
= 1000;
4114 wpa_printf(MSG_INFO
,
4115 "DPP: No configurator specified - cannot generate DPP config object");
4118 curve
= auth
->conf
->curve
;
4119 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4120 sign_md
= EVP_sha256();
4121 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4122 sign_md
= EVP_sha384();
4123 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4124 sign_md
= EVP_sha512();
4126 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4130 #ifdef CONFIG_TESTING_OPTIONS
4131 if (auth
->groups_override
)
4132 extra_len
+= os_strlen(auth
->groups_override
);
4133 #endif /* CONFIG_TESTING_OPTIONS */
4135 /* Connector (JSON dppCon object) */
4136 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4139 #ifdef CONFIG_TESTING_OPTIONS
4140 if (auth
->groups_override
) {
4141 wpabuf_put_u8(dppcon
, '{');
4142 if (auth
->groups_override
) {
4143 wpa_printf(MSG_DEBUG
,
4144 "DPP: TESTING - groups override: '%s'",
4145 auth
->groups_override
);
4146 wpabuf_put_str(dppcon
, "\"groups\":");
4147 wpabuf_put_str(dppcon
, auth
->groups_override
);
4148 wpabuf_put_u8(dppcon
, ',');
4152 #endif /* CONFIG_TESTING_OPTIONS */
4153 wpabuf_put_str(dppcon
, "{\"groups\":[{\"groupId\":\"*\",");
4154 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
4155 #ifdef CONFIG_TESTING_OPTIONS
4157 #endif /* CONFIG_TESTING_OPTIONS */
4158 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4160 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4163 if (conf
->netaccesskey_expiry
) {
4166 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4167 wpa_printf(MSG_DEBUG
,
4168 "DPP: Failed to generate expiry string");
4171 wpabuf_printf(dppcon
,
4172 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4173 tm
.year
, tm
.month
, tm
.day
,
4174 tm
.hour
, tm
.min
, tm
.sec
);
4176 wpabuf_put_u8(dppcon
, '}');
4177 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4178 (const char *) wpabuf_head(dppcon
));
4180 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
4181 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4182 auth
->conf
->kid
, curve
->jws_alg
);
4183 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
4184 os_strlen(jws_prot_hdr
),
4186 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
4189 if (!signed1
|| !signed2
)
4192 md_ctx
= EVP_MD_CTX_create();
4197 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4198 auth
->conf
->csign
) != 1) {
4199 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4200 ERR_error_string(ERR_get_error(), NULL
));
4203 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4204 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4205 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4206 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4207 ERR_error_string(ERR_get_error(), NULL
));
4210 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4211 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4212 ERR_error_string(ERR_get_error(), NULL
));
4215 signature
= os_malloc(signature_len
);
4218 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4219 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4220 ERR_error_string(ERR_get_error(), NULL
));
4223 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4224 signature
, signature_len
);
4225 /* Convert to raw coordinates r,s */
4227 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4230 ECDSA_SIG_get0(sig
, &r
, &s
);
4231 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4232 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4233 curve
->prime_len
) < 0)
4235 signature_len
= 2 * curve
->prime_len
;
4236 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4237 signature
, signature_len
);
4238 signed3
= (char *) base64_url_encode(signature
, signature_len
,
4244 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4245 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4246 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4250 wpabuf_put_str(buf
, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
4251 wpabuf_put_str(buf
, signed1
);
4252 wpabuf_put_u8(buf
, '.');
4253 wpabuf_put_str(buf
, signed2
);
4254 wpabuf_put_u8(buf
, '.');
4255 wpabuf_put_str(buf
, signed3
);
4256 wpabuf_put_str(buf
, "\",");
4257 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4259 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4263 wpabuf_put_str(buf
, "}}");
4265 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4266 wpabuf_head(buf
), wpabuf_len(buf
));
4269 EVP_MD_CTX_destroy(md_ctx
);
4270 ECDSA_SIG_free(sig
);
4275 wpabuf_free(dppcon
);
4278 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4285 static struct wpabuf
*
4286 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
4287 struct dpp_configuration
*conf
)
4291 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4295 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf
->akm
));
4296 if (conf
->passphrase
) {
4297 char pass
[63 * 6 + 1];
4299 if (os_strlen(conf
->passphrase
) > 63) {
4304 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
4305 os_strlen(conf
->passphrase
));
4306 wpabuf_put_str(buf
, "\"pass\":\"");
4307 wpabuf_put_str(buf
, pass
);
4308 wpabuf_put_str(buf
, "\"");
4310 char psk
[2 * sizeof(conf
->psk
) + 1];
4312 wpa_snprintf_hex(psk
, sizeof(psk
),
4313 conf
->psk
, sizeof(conf
->psk
));
4314 wpabuf_put_str(buf
, "\"psk_hex\":\"");
4315 wpabuf_put_str(buf
, psk
);
4316 wpabuf_put_str(buf
, "\"");
4318 wpabuf_put_str(buf
, "}}");
4320 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4321 wpabuf_head(buf
), wpabuf_len(buf
));
4327 static struct wpabuf
*
4328 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
4330 struct dpp_configuration
*conf
;
4332 #ifdef CONFIG_TESTING_OPTIONS
4333 if (auth
->config_obj_override
) {
4334 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
4335 return wpabuf_alloc_copy(auth
->config_obj_override
,
4336 os_strlen(auth
->config_obj_override
));
4338 #endif /* CONFIG_TESTING_OPTIONS */
4340 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
4342 wpa_printf(MSG_DEBUG
,
4343 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4348 if (conf
->akm
== DPP_AKM_DPP
)
4349 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
4350 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
4354 static struct wpabuf
*
4355 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
4356 u16 e_nonce_len
, int ap
)
4358 struct wpabuf
*conf
;
4359 size_t clear_len
, attr_len
;
4360 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
4364 enum dpp_status_error status
;
4366 conf
= dpp_build_conf_obj(auth
, ap
);
4368 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4369 wpabuf_head(conf
), wpabuf_len(conf
));
4371 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
4373 /* { E-nonce, configurationObject}ke */
4374 clear_len
= 4 + e_nonce_len
;
4376 clear_len
+= 4 + wpabuf_len(conf
);
4377 clear
= wpabuf_alloc(clear_len
);
4378 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
4379 #ifdef CONFIG_TESTING_OPTIONS
4380 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
4382 #endif /* CONFIG_TESTING_OPTIONS */
4383 msg
= wpabuf_alloc(attr_len
);
4387 #ifdef CONFIG_TESTING_OPTIONS
4388 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
4389 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
4392 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
4393 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
4394 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4395 wpabuf_put_le16(clear
, e_nonce_len
);
4396 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4397 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4400 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4401 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4402 goto skip_wrapped_data
;
4404 #endif /* CONFIG_TESTING_OPTIONS */
4407 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4408 wpabuf_put_le16(clear
, e_nonce_len
);
4409 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4411 #ifdef CONFIG_TESTING_OPTIONS
4413 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4414 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4415 goto skip_config_obj
;
4417 #endif /* CONFIG_TESTING_OPTIONS */
4420 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4421 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4422 wpabuf_put_buf(clear
, conf
);
4425 #ifdef CONFIG_TESTING_OPTIONS
4427 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4428 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4431 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4432 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4435 #endif /* CONFIG_TESTING_OPTIONS */
4438 dpp_build_attr_status(msg
, status
);
4440 #ifdef CONFIG_TESTING_OPTIONS
4442 #endif /* CONFIG_TESTING_OPTIONS */
4444 addr
[0] = wpabuf_head(msg
);
4445 len
[0] = wpabuf_len(msg
);
4446 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4448 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4449 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4450 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4452 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4453 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4454 wpabuf_head(clear
), wpabuf_len(clear
),
4455 1, addr
, len
, wrapped
) < 0)
4457 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4458 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4460 #ifdef CONFIG_TESTING_OPTIONS
4461 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4462 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4463 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
4466 #endif /* CONFIG_TESTING_OPTIONS */
4468 wpa_hexdump_buf(MSG_DEBUG
,
4469 "DPP: Configuration Response attributes", msg
);
4483 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4486 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4487 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4488 u8
*unwrapped
= NULL
;
4489 size_t unwrapped_len
= 0;
4490 struct wpabuf
*resp
= NULL
;
4491 struct json_token
*root
= NULL
, *token
;
4494 #ifdef CONFIG_TESTING_OPTIONS
4495 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
4496 wpa_printf(MSG_INFO
,
4497 "DPP: TESTING - stop at Config Request");
4500 #endif /* CONFIG_TESTING_OPTIONS */
4502 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4503 dpp_auth_fail(auth
, "Invalid attribute in config request");
4507 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4509 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4511 "Missing or invalid required Wrapped Data attribute");
4515 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4516 wrapped_data
, wrapped_data_len
);
4517 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4518 unwrapped
= os_malloc(unwrapped_len
);
4521 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4522 wrapped_data
, wrapped_data_len
,
4523 0, NULL
, NULL
, unwrapped
) < 0) {
4524 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4527 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4528 unwrapped
, unwrapped_len
);
4530 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4531 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4535 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4536 DPP_ATTR_ENROLLEE_NONCE
,
4538 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4540 "Missing or invalid Enrollee Nonce attribute");
4543 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4545 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
4546 DPP_ATTR_CONFIG_ATTR_OBJ
,
4550 "Missing or invalid Config Attributes attribute");
4553 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
4554 config_attr
, config_attr_len
);
4556 root
= json_parse((const char *) config_attr
, config_attr_len
);
4558 dpp_auth_fail(auth
, "Could not parse Config Attributes");
4562 token
= json_get_member(root
, "name");
4563 if (!token
|| token
->type
!= JSON_STRING
) {
4564 dpp_auth_fail(auth
, "No Config Attributes - name");
4567 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
4569 token
= json_get_member(root
, "wi-fi_tech");
4570 if (!token
|| token
->type
!= JSON_STRING
) {
4571 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
4574 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
4575 if (os_strcmp(token
->string
, "infra") != 0) {
4576 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
4578 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
4582 token
= json_get_member(root
, "netRole");
4583 if (!token
|| token
->type
!= JSON_STRING
) {
4584 dpp_auth_fail(auth
, "No Config Attributes - netRole");
4587 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
4588 if (os_strcmp(token
->string
, "sta") == 0) {
4590 } else if (os_strcmp(token
->string
, "ap") == 0) {
4593 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
4595 dpp_auth_fail(auth
, "Unsupported netRole");
4599 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
4608 static struct wpabuf
*
4609 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
4610 const u8
*prot_hdr
, u16 prot_hdr_len
,
4611 const EVP_MD
**ret_md
)
4613 struct json_token
*root
, *token
;
4614 struct wpabuf
*kid
= NULL
;
4616 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
4618 wpa_printf(MSG_DEBUG
,
4619 "DPP: JSON parsing failed for JWS Protected Header");
4623 if (root
->type
!= JSON_OBJECT
) {
4624 wpa_printf(MSG_DEBUG
,
4625 "DPP: JWS Protected Header root is not an object");
4629 token
= json_get_member(root
, "typ");
4630 if (!token
|| token
->type
!= JSON_STRING
) {
4631 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
4634 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
4636 if (os_strcmp(token
->string
, "dppCon") != 0) {
4637 wpa_printf(MSG_DEBUG
,
4638 "DPP: Unsupported JWS Protected Header typ=%s",
4643 token
= json_get_member(root
, "alg");
4644 if (!token
|| token
->type
!= JSON_STRING
) {
4645 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
4648 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
4650 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
4651 wpa_printf(MSG_DEBUG
,
4652 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4653 token
->string
, curve
->jws_alg
);
4656 if (os_strcmp(token
->string
, "ES256") == 0 ||
4657 os_strcmp(token
->string
, "BS256") == 0)
4658 *ret_md
= EVP_sha256();
4659 else if (os_strcmp(token
->string
, "ES384") == 0 ||
4660 os_strcmp(token
->string
, "BS384") == 0)
4661 *ret_md
= EVP_sha384();
4662 else if (os_strcmp(token
->string
, "ES512") == 0 ||
4663 os_strcmp(token
->string
, "BS512") == 0)
4664 *ret_md
= EVP_sha512();
4668 wpa_printf(MSG_DEBUG
,
4669 "DPP: Unsupported JWS Protected Header alg=%s",
4674 kid
= json_get_member_base64url(root
, "kid");
4676 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
4679 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
4688 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
4689 struct json_token
*cred
)
4691 struct json_token
*pass
, *psk_hex
;
4693 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
4695 pass
= json_get_member(cred
, "pass");
4696 psk_hex
= json_get_member(cred
, "psk_hex");
4698 if (pass
&& pass
->type
== JSON_STRING
) {
4699 size_t len
= os_strlen(pass
->string
);
4701 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
4703 if (len
< 8 || len
> 63)
4705 os_strlcpy(auth
->passphrase
, pass
->string
,
4706 sizeof(auth
->passphrase
));
4707 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
4708 if (auth
->akm
== DPP_AKM_SAE
) {
4709 wpa_printf(MSG_DEBUG
,
4710 "DPP: Unexpected psk_hex with akm=sae");
4713 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
4714 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
4715 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
4718 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
4719 auth
->psk
, PMK_LEN
);
4722 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
4726 if ((auth
->akm
== DPP_AKM_SAE
|| auth
->akm
== DPP_AKM_PSK_SAE
) &&
4727 !auth
->passphrase
[0]) {
4728 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
4736 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
4737 const struct dpp_curve_params
**key_curve
)
4739 struct json_token
*token
;
4740 const struct dpp_curve_params
*curve
;
4741 struct wpabuf
*x
= NULL
, *y
= NULL
;
4743 EVP_PKEY
*pkey
= NULL
;
4745 token
= json_get_member(jwk
, "kty");
4746 if (!token
|| token
->type
!= JSON_STRING
) {
4747 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
4750 if (os_strcmp(token
->string
, "EC") != 0) {
4751 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s",
4756 token
= json_get_member(jwk
, "crv");
4757 if (!token
|| token
->type
!= JSON_STRING
) {
4758 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
4761 curve
= dpp_get_curve_jwk_crv(token
->string
);
4763 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
4768 x
= json_get_member_base64url(jwk
, "x");
4770 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
4773 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
4774 if (wpabuf_len(x
) != curve
->prime_len
) {
4775 wpa_printf(MSG_DEBUG
,
4776 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4777 (unsigned int) wpabuf_len(x
),
4778 (unsigned int) curve
->prime_len
, curve
->name
);
4782 y
= json_get_member_base64url(jwk
, "y");
4784 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
4787 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
4788 if (wpabuf_len(y
) != curve
->prime_len
) {
4789 wpa_printf(MSG_DEBUG
,
4790 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4791 (unsigned int) wpabuf_len(y
),
4792 (unsigned int) curve
->prime_len
, curve
->name
);
4796 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
4798 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
4802 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
4814 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
4817 unsigned int year
, month
, day
, hour
, min
, sec
;
4821 /* ISO 8601 date and time:
4823 * YYYY-MM-DDTHH:MM:SSZ
4824 * YYYY-MM-DDTHH:MM:SS+03:00
4826 if (os_strlen(timestamp
) < 19) {
4827 wpa_printf(MSG_DEBUG
,
4828 "DPP: Too short timestamp - assume expired key");
4831 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
4832 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
4833 wpa_printf(MSG_DEBUG
,
4834 "DPP: Failed to parse expiration day - assume expired key");
4838 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
4839 wpa_printf(MSG_DEBUG
,
4840 "DPP: Invalid date/time information - assume expired key");
4844 pos
= timestamp
+ 19;
4845 if (*pos
== 'Z' || *pos
== '\0') {
4846 /* In UTC - no need to adjust */
4847 } else if (*pos
== '-' || *pos
== '+') {
4850 /* Adjust local time to UTC */
4851 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
4853 wpa_printf(MSG_DEBUG
,
4854 "DPP: Invalid time zone designator (%s) - assume expired key",
4859 utime
+= 3600 * hour
;
4861 utime
-= 3600 * hour
;
4869 wpa_printf(MSG_DEBUG
,
4870 "DPP: Invalid time zone designator (%s) - assume expired key",
4877 if (os_get_time(&now
) < 0) {
4878 wpa_printf(MSG_DEBUG
,
4879 "DPP: Cannot get current time - assume expired key");
4883 if (now
.sec
> utime
) {
4884 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
4893 static int dpp_parse_connector(struct dpp_authentication
*auth
,
4894 const unsigned char *payload
,
4897 struct json_token
*root
, *groups
, *netkey
, *token
;
4899 EVP_PKEY
*key
= NULL
;
4900 const struct dpp_curve_params
*curve
;
4901 unsigned int rules
= 0;
4903 root
= json_parse((const char *) payload
, payload_len
);
4905 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
4909 groups
= json_get_member(root
, "groups");
4910 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
4911 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
4914 for (token
= groups
->child
; token
; token
= token
->sibling
) {
4915 struct json_token
*id
, *role
;
4917 id
= json_get_member(token
, "groupId");
4918 if (!id
|| id
->type
!= JSON_STRING
) {
4919 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
4923 role
= json_get_member(token
, "netRole");
4924 if (!role
|| role
->type
!= JSON_STRING
) {
4925 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
4928 wpa_printf(MSG_DEBUG
,
4929 "DPP: connector group: groupId='%s' netRole='%s'",
4930 id
->string
, role
->string
);
4936 wpa_printf(MSG_DEBUG
,
4937 "DPP: Connector includes no groups");
4941 token
= json_get_member(root
, "expiry");
4942 if (!token
|| token
->type
!= JSON_STRING
) {
4943 wpa_printf(MSG_DEBUG
,
4944 "DPP: No expiry string found - connector does not expire");
4946 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
4947 if (dpp_key_expired(token
->string
,
4948 &auth
->net_access_key_expiry
)) {
4949 wpa_printf(MSG_DEBUG
,
4950 "DPP: Connector (netAccessKey) has expired");
4955 netkey
= json_get_member(root
, "netAccessKey");
4956 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
4957 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
4961 key
= dpp_parse_jwk(netkey
, &curve
);
4964 dpp_debug_print_key("DPP: Received netAccessKey", key
);
4966 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
4967 wpa_printf(MSG_DEBUG
,
4968 "DPP: netAccessKey in connector does not match own protocol key");
4969 #ifdef CONFIG_TESTING_OPTIONS
4970 if (auth
->ignore_netaccesskey_mismatch
) {
4971 wpa_printf(MSG_DEBUG
,
4972 "DPP: TESTING - skip netAccessKey mismatch");
4976 #else /* CONFIG_TESTING_OPTIONS */
4978 #endif /* CONFIG_TESTING_OPTIONS */
4989 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
4991 struct wpabuf
*uncomp
;
4993 u8 hash
[SHA256_MAC_LEN
];
4997 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
4999 uncomp
= dpp_get_pubkey_point(pub
, 1);
5002 addr
[0] = wpabuf_head(uncomp
);
5003 len
[0] = wpabuf_len(uncomp
);
5004 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5006 res
= sha256_vector(1, addr
, len
, hash
);
5007 wpabuf_free(uncomp
);
5010 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5011 wpa_printf(MSG_DEBUG
,
5012 "DPP: Received hash value does not match calculated public key hash value");
5013 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5014 hash
, SHA256_MAC_LEN
);
5021 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
5023 unsigned char *der
= NULL
;
5026 der_len
= i2d_PUBKEY(csign
, &der
);
5029 wpabuf_free(auth
->c_sign_key
);
5030 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5035 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
5037 unsigned char *der
= NULL
;
5041 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5045 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5050 wpabuf_free(auth
->net_access_key
);
5051 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5057 struct dpp_signed_connector_info
{
5058 unsigned char *payload
;
5062 static enum dpp_status_error
5063 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5064 EVP_PKEY
*csign_pub
, const char *connector
)
5066 enum dpp_status_error ret
= 255;
5067 const char *pos
, *end
, *signed_start
, *signed_end
;
5068 struct wpabuf
*kid
= NULL
;
5069 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5070 size_t prot_hdr_len
= 0, signature_len
= 0;
5071 const EVP_MD
*sign_md
= NULL
;
5072 unsigned char *der
= NULL
;
5075 EVP_MD_CTX
*md_ctx
= NULL
;
5076 ECDSA_SIG
*sig
= NULL
;
5077 BIGNUM
*r
= NULL
, *s
= NULL
;
5078 const struct dpp_curve_params
*curve
;
5080 const EC_GROUP
*group
;
5083 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5086 group
= EC_KEY_get0_group(eckey
);
5089 nid
= EC_GROUP_get_curve_name(group
);
5090 curve
= dpp_get_curve_nid(nid
);
5093 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5094 os_memset(info
, 0, sizeof(*info
));
5096 signed_start
= pos
= connector
;
5097 end
= os_strchr(pos
, '.');
5099 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5100 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5103 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
5104 end
- pos
, &prot_hdr_len
);
5106 wpa_printf(MSG_DEBUG
,
5107 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5108 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5111 wpa_hexdump_ascii(MSG_DEBUG
,
5112 "DPP: signedConnector - JWS Protected Header",
5113 prot_hdr
, prot_hdr_len
);
5114 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5116 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5119 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5120 wpa_printf(MSG_DEBUG
,
5121 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5122 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5123 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5128 end
= os_strchr(pos
, '.');
5130 wpa_printf(MSG_DEBUG
,
5131 "DPP: Missing dot(2) in signedConnector");
5132 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5135 signed_end
= end
- 1;
5136 info
->payload
= base64_url_decode((const unsigned char *) pos
,
5137 end
- pos
, &info
->payload_len
);
5138 if (!info
->payload
) {
5139 wpa_printf(MSG_DEBUG
,
5140 "DPP: Failed to base64url decode signedConnector JWS Payload");
5141 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5144 wpa_hexdump_ascii(MSG_DEBUG
,
5145 "DPP: signedConnector - JWS Payload",
5146 info
->payload
, info
->payload_len
);
5148 signature
= base64_url_decode((const unsigned char *) pos
,
5149 os_strlen(pos
), &signature_len
);
5151 wpa_printf(MSG_DEBUG
,
5152 "DPP: Failed to base64url decode signedConnector signature");
5153 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5156 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
5157 signature
, signature_len
);
5159 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
5160 ret
= DPP_STATUS_NO_MATCH
;
5164 if (signature_len
& 0x01) {
5165 wpa_printf(MSG_DEBUG
,
5166 "DPP: Unexpected signedConnector signature length (%d)",
5167 (int) signature_len
);
5168 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5172 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5173 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5174 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
5175 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
5176 sig
= ECDSA_SIG_new();
5177 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
5182 der_len
= i2d_ECDSA_SIG(sig
, &der
);
5184 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
5187 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
5188 md_ctx
= EVP_MD_CTX_create();
5193 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
5194 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
5195 ERR_error_string(ERR_get_error(), NULL
));
5198 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
5199 signed_end
- signed_start
+ 1) != 1) {
5200 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
5201 ERR_error_string(ERR_get_error(), NULL
));
5204 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
5206 wpa_printf(MSG_DEBUG
,
5207 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5208 res
, ERR_error_string(ERR_get_error(), NULL
));
5209 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5213 ret
= DPP_STATUS_OK
;
5216 EVP_MD_CTX_destroy(md_ctx
);
5220 ECDSA_SIG_free(sig
);
5228 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5229 struct json_token
*cred
)
5231 struct dpp_signed_connector_info info
;
5232 struct json_token
*token
, *csign
;
5234 EVP_PKEY
*csign_pub
= NULL
;
5235 const struct dpp_curve_params
*key_curve
= NULL
;
5236 const char *signed_connector
;
5238 os_memset(&info
, 0, sizeof(info
));
5240 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5242 csign
= json_get_member(cred
, "csign");
5243 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5244 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5248 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5250 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5253 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5255 token
= json_get_member(cred
, "signedConnector");
5256 if (!token
|| token
->type
!= JSON_STRING
) {
5257 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5260 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5261 token
->string
, os_strlen(token
->string
));
5262 signed_connector
= token
->string
;
5264 if (os_strchr(signed_connector
, '"') ||
5265 os_strchr(signed_connector
, '\n')) {
5266 wpa_printf(MSG_DEBUG
,
5267 "DPP: Unexpected character in signedConnector");
5271 if (dpp_process_signed_connector(&info
, csign_pub
,
5272 signed_connector
) != DPP_STATUS_OK
)
5275 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
5276 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
5280 os_free(auth
->connector
);
5281 auth
->connector
= os_strdup(signed_connector
);
5283 dpp_copy_csign(auth
, csign_pub
);
5284 dpp_copy_netaccesskey(auth
);
5288 EVP_PKEY_free(csign_pub
);
5289 os_free(info
.payload
);
5294 const char * dpp_akm_str(enum dpp_akm akm
)
5303 case DPP_AKM_PSK_SAE
:
5311 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
5313 if (os_strcmp(akm
, "psk") == 0)
5315 if (os_strcmp(akm
, "sae") == 0)
5317 if (os_strcmp(akm
, "psk+sae") == 0)
5318 return DPP_AKM_PSK_SAE
;
5319 if (os_strcmp(akm
, "dpp") == 0)
5321 return DPP_AKM_UNKNOWN
;
5325 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
5326 const u8
*conf_obj
, u16 conf_obj_len
)
5329 struct json_token
*root
, *token
, *discovery
, *cred
;
5331 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
5334 if (root
->type
!= JSON_OBJECT
) {
5335 dpp_auth_fail(auth
, "JSON root is not an object");
5339 token
= json_get_member(root
, "wi-fi_tech");
5340 if (!token
|| token
->type
!= JSON_STRING
) {
5341 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
5344 if (os_strcmp(token
->string
, "infra") != 0) {
5345 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
5347 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
5351 discovery
= json_get_member(root
, "discovery");
5352 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
5353 dpp_auth_fail(auth
, "No discovery object in JSON");
5357 token
= json_get_member(discovery
, "ssid");
5358 if (!token
|| token
->type
!= JSON_STRING
) {
5359 dpp_auth_fail(auth
, "No discovery::ssid string value found");
5362 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
5363 token
->string
, os_strlen(token
->string
));
5364 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
5365 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
5368 auth
->ssid_len
= os_strlen(token
->string
);
5369 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
5371 cred
= json_get_member(root
, "cred");
5372 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
5373 dpp_auth_fail(auth
, "No cred object in JSON");
5377 token
= json_get_member(cred
, "akm");
5378 if (!token
|| token
->type
!= JSON_STRING
) {
5379 dpp_auth_fail(auth
, "No cred::akm string value found");
5382 auth
->akm
= dpp_akm_from_str(token
->string
);
5384 if (auth
->akm
== DPP_AKM_PSK
|| auth
->akm
== DPP_AKM_SAE
||
5385 auth
->akm
== DPP_AKM_PSK_SAE
) {
5386 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5388 } else if (auth
->akm
== DPP_AKM_DPP
) {
5389 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
5392 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
5394 dpp_auth_fail(auth
, "Unsupported akm");
5398 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
5406 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
5407 const struct wpabuf
*resp
)
5409 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
5410 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
5413 u8
*unwrapped
= NULL
;
5414 size_t unwrapped_len
= 0;
5417 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
5418 dpp_auth_fail(auth
, "Invalid attribute in config response");
5422 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5423 DPP_ATTR_WRAPPED_DATA
,
5425 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5427 "Missing or invalid required Wrapped Data attribute");
5431 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5432 wrapped_data
, wrapped_data_len
);
5433 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5434 unwrapped
= os_malloc(unwrapped_len
);
5438 addr
[0] = wpabuf_head(resp
);
5439 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
5440 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5442 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5443 wrapped_data
, wrapped_data_len
,
5444 1, addr
, len
, unwrapped
) < 0) {
5445 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5448 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5449 unwrapped
, unwrapped_len
);
5451 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5452 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5456 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5457 DPP_ATTR_ENROLLEE_NONCE
,
5459 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5461 "Missing or invalid Enrollee Nonce attribute");
5464 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5465 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5466 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5470 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5471 DPP_ATTR_STATUS
, &status_len
);
5472 if (!status
|| status_len
< 1) {
5474 "Missing or invalid required DPP Status attribute");
5477 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5478 if (status
[0] != DPP_STATUS_OK
) {
5479 dpp_auth_fail(auth
, "Configurator rejected configuration");
5483 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5484 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5487 "Missing required Configuration Object attribute");
5490 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5491 conf_obj
, conf_obj_len
);
5492 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5503 void dpp_configurator_free(struct dpp_configurator
*conf
)
5507 EVP_PKEY_free(conf
->csign
);
5513 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
5517 int key_len
, ret
= -1;
5518 unsigned char *key
= NULL
;
5523 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
5527 key_len
= i2d_ECPrivateKey(eckey
, &key
);
5529 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
5537 struct dpp_configurator
*
5538 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
5541 struct dpp_configurator
*conf
;
5542 struct wpabuf
*csign_pub
= NULL
;
5543 u8 kid_hash
[SHA256_MAC_LEN
];
5547 conf
= os_zalloc(sizeof(*conf
));
5552 conf
->curve
= &dpp_curves
[0];
5554 conf
->curve
= dpp_get_curve_name(curve
);
5556 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5562 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
5565 conf
->csign
= dpp_gen_keypair(conf
->curve
);
5570 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
5572 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
5576 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5577 addr
[0] = wpabuf_head(csign_pub
);
5578 len
[0] = wpabuf_len(csign_pub
);
5579 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
5580 wpa_printf(MSG_DEBUG
,
5581 "DPP: Failed to derive kid for C-sign-key");
5585 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
5590 wpabuf_free(csign_pub
);
5593 dpp_configurator_free(conf
);
5599 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
5600 const char *curve
, int ap
)
5602 struct wpabuf
*conf_obj
;
5606 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
5611 auth
->curve
= &dpp_curves
[0];
5613 auth
->curve
= dpp_get_curve_name(curve
);
5615 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
5620 wpa_printf(MSG_DEBUG
,
5621 "DPP: Building own configuration/connector with curve %s",
5624 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
5625 if (!auth
->own_protocol_key
)
5627 dpp_copy_netaccesskey(auth
);
5628 auth
->peer_protocol_key
= auth
->own_protocol_key
;
5629 dpp_copy_csign(auth
, auth
->conf
->csign
);
5631 conf_obj
= dpp_build_conf_obj(auth
, ap
);
5634 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
5635 wpabuf_len(conf_obj
));
5637 wpabuf_free(conf_obj
);
5638 auth
->peer_protocol_key
= NULL
;
5643 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
5645 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
5646 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
5650 static int dpp_connector_compatible_group(struct json_token
*root
,
5651 const char *group_id
,
5652 const char *net_role
)
5654 struct json_token
*groups
, *token
;
5656 groups
= json_get_member(root
, "groups");
5657 if (!groups
|| groups
->type
!= JSON_ARRAY
)
5660 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5661 struct json_token
*id
, *role
;
5663 id
= json_get_member(token
, "groupId");
5664 if (!id
|| id
->type
!= JSON_STRING
)
5667 role
= json_get_member(token
, "netRole");
5668 if (!role
|| role
->type
!= JSON_STRING
)
5671 if (os_strcmp(id
->string
, "*") != 0 &&
5672 os_strcmp(group_id
, "*") != 0 &&
5673 os_strcmp(id
->string
, group_id
) != 0)
5676 if (dpp_compatible_netrole(role
->string
, net_role
))
5684 static int dpp_connector_match_groups(struct json_token
*own_root
,
5685 struct json_token
*peer_root
)
5687 struct json_token
*groups
, *token
;
5689 groups
= json_get_member(peer_root
, "groups");
5690 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5691 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
5695 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5696 struct json_token
*id
, *role
;
5698 id
= json_get_member(token
, "groupId");
5699 if (!id
|| id
->type
!= JSON_STRING
) {
5700 wpa_printf(MSG_DEBUG
,
5701 "DPP: Missing peer groupId string");
5705 role
= json_get_member(token
, "netRole");
5706 if (!role
|| role
->type
!= JSON_STRING
) {
5707 wpa_printf(MSG_DEBUG
,
5708 "DPP: Missing peer groups::netRole string");
5711 wpa_printf(MSG_DEBUG
,
5712 "DPP: peer connector group: groupId='%s' netRole='%s'",
5713 id
->string
, role
->string
);
5714 if (dpp_connector_compatible_group(own_root
, id
->string
,
5716 wpa_printf(MSG_DEBUG
,
5717 "DPP: Compatible group/netRole in own connector");
5726 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
5727 unsigned int hash_len
)
5729 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
5730 const char *info
= "DPP PMK";
5733 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5735 /* HKDF-Extract(<>, N.x) */
5736 os_memset(salt
, 0, hash_len
);
5737 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
5739 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5742 /* HKDF-Expand(PRK, info, L) */
5743 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
5744 os_memset(prk
, 0, hash_len
);
5748 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5754 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
5755 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
5757 struct wpabuf
*nkx
, *pkx
;
5761 u8 hash
[SHA256_MAC_LEN
];
5763 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5764 nkx
= dpp_get_pubkey_point(own_key
, 0);
5765 pkx
= dpp_get_pubkey_point(peer_key
, 0);
5768 addr
[0] = wpabuf_head(nkx
);
5769 len
[0] = wpabuf_len(nkx
) / 2;
5770 addr
[1] = wpabuf_head(pkx
);
5771 len
[1] = wpabuf_len(pkx
) / 2;
5772 if (len
[0] != len
[1])
5774 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
5775 addr
[0] = wpabuf_head(pkx
);
5776 addr
[1] = wpabuf_head(nkx
);
5778 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
5779 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
5780 res
= sha256_vector(2, addr
, len
, hash
);
5783 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
5784 os_memcpy(pmkid
, hash
, PMKID_LEN
);
5785 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
5794 enum dpp_status_error
5795 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
5796 const u8
*net_access_key
, size_t net_access_key_len
,
5797 const u8
*csign_key
, size_t csign_key_len
,
5798 const u8
*peer_connector
, size_t peer_connector_len
,
5801 struct json_token
*root
= NULL
, *netkey
, *token
;
5802 struct json_token
*own_root
= NULL
;
5803 enum dpp_status_error ret
= 255, res
;
5804 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
5805 struct wpabuf
*own_key_pub
= NULL
;
5806 const struct dpp_curve_params
*curve
, *own_curve
;
5807 struct dpp_signed_connector_info info
;
5808 const unsigned char *p
;
5809 EVP_PKEY
*csign
= NULL
;
5810 char *signed_connector
= NULL
;
5811 const char *pos
, *end
;
5812 unsigned char *own_conn
= NULL
;
5813 size_t own_conn_len
;
5814 EVP_PKEY_CTX
*ctx
= NULL
;
5816 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
5818 os_memset(intro
, 0, sizeof(*intro
));
5819 os_memset(&info
, 0, sizeof(info
));
5824 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
5826 wpa_printf(MSG_ERROR
,
5827 "DPP: Failed to parse local C-sign-key information");
5831 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
5832 net_access_key_len
);
5834 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
5838 pos
= os_strchr(own_connector
, '.');
5840 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
5844 end
= os_strchr(pos
, '.');
5846 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
5849 own_conn
= base64_url_decode((const unsigned char *) pos
,
5850 end
- pos
, &own_conn_len
);
5852 wpa_printf(MSG_DEBUG
,
5853 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5857 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
5859 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
5863 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
5864 peer_connector
, peer_connector_len
);
5865 signed_connector
= os_malloc(peer_connector_len
+ 1);
5866 if (!signed_connector
)
5868 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
5869 signed_connector
[peer_connector_len
] = '\0';
5871 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
5872 if (res
!= DPP_STATUS_OK
) {
5877 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
5879 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5880 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5884 if (!dpp_connector_match_groups(own_root
, root
)) {
5885 wpa_printf(MSG_DEBUG
,
5886 "DPP: Peer connector does not include compatible group netrole with own connector");
5887 ret
= DPP_STATUS_NO_MATCH
;
5891 token
= json_get_member(root
, "expiry");
5892 if (!token
|| token
->type
!= JSON_STRING
) {
5893 wpa_printf(MSG_DEBUG
,
5894 "DPP: No expiry string found - connector does not expire");
5896 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5897 if (dpp_key_expired(token
->string
, expiry
)) {
5898 wpa_printf(MSG_DEBUG
,
5899 "DPP: Connector (netAccessKey) has expired");
5900 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5905 netkey
= json_get_member(root
, "netAccessKey");
5906 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5907 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5908 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5912 peer_key
= dpp_parse_jwk(netkey
, &curve
);
5914 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5917 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
5919 if (own_curve
!= curve
) {
5920 wpa_printf(MSG_DEBUG
,
5921 "DPP: Mismatching netAccessKey curves (%s != %s)",
5922 own_curve
->name
, curve
->name
);
5923 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5927 /* ECDH: N = nk * PK */
5928 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
5930 EVP_PKEY_derive_init(ctx
) != 1 ||
5931 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
5932 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
5933 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
5934 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
5935 wpa_printf(MSG_ERROR
,
5936 "DPP: Failed to derive ECDH shared secret: %s",
5937 ERR_error_string(ERR_get_error(), NULL
));
5941 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
5944 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5945 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
5946 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
5949 intro
->pmk_len
= curve
->hash_len
;
5951 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5952 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
5953 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
5957 ret
= DPP_STATUS_OK
;
5959 if (ret
!= DPP_STATUS_OK
)
5960 os_memset(intro
, 0, sizeof(*intro
));
5961 os_memset(Nx
, 0, sizeof(Nx
));
5962 EVP_PKEY_CTX_free(ctx
);
5964 os_free(signed_connector
);
5965 os_free(info
.payload
);
5966 EVP_PKEY_free(own_key
);
5967 wpabuf_free(own_key_pub
);
5968 EVP_PKEY_free(peer_key
);
5969 EVP_PKEY_free(csign
);
5971 json_free(own_root
);
5976 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
5980 size_t len
= curve
->prime_len
;
5983 switch (curve
->ike_group
) {
5985 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
5986 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
5989 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
5990 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
5993 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
5994 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
5997 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
5998 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
6001 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
6002 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
6005 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
6006 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
6012 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6015 return dpp_set_pubkey_point_group(group
, x
, y
, len
);
6019 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
6020 const u8
*mac_init
, const char *code
,
6021 const char *identifier
, BN_CTX
*bnctx
,
6022 const EC_GROUP
**ret_group
)
6024 u8 hash
[DPP_MAX_HASH_LEN
];
6027 unsigned int num_elem
= 0;
6028 EC_POINT
*Qi
= NULL
;
6029 EVP_PKEY
*Pi
= NULL
;
6030 EC_KEY
*Pi_ec
= NULL
;
6031 const EC_POINT
*Pi_point
;
6032 BIGNUM
*hash_bn
= NULL
;
6033 const EC_GROUP
*group
= NULL
;
6034 EC_GROUP
*group2
= NULL
;
6036 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6038 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
6039 addr
[num_elem
] = mac_init
;
6040 len
[num_elem
] = ETH_ALEN
;
6043 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6045 addr
[num_elem
] = (const u8
*) identifier
;
6046 len
[num_elem
] = os_strlen(identifier
);
6049 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6050 addr
[num_elem
] = (const u8
*) code
;
6051 len
[num_elem
] = os_strlen(code
);
6053 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6055 wpa_hexdump_key(MSG_DEBUG
,
6056 "DPP: H(MAC-Initiator | [identifier |] code)",
6057 hash
, curve
->hash_len
);
6058 Pi
= dpp_pkex_get_role_elem(curve
, 1);
6061 dpp_debug_print_key("DPP: Pi", Pi
);
6062 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
6065 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
6067 group
= EC_KEY_get0_group(Pi_ec
);
6070 group2
= EC_GROUP_dup(group
);
6073 Qi
= EC_POINT_new(group2
);
6075 EC_GROUP_free(group2
);
6078 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6080 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
6082 if (EC_POINT_is_at_infinity(group
, Qi
)) {
6083 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
6086 dpp_debug_print_point("DPP: Qi", group
, Qi
);
6090 BN_clear_free(hash_bn
);
6092 *ret_group
= group2
;
6101 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
6102 const u8
*mac_resp
, const char *code
,
6103 const char *identifier
, BN_CTX
*bnctx
,
6104 const EC_GROUP
**ret_group
)
6106 u8 hash
[DPP_MAX_HASH_LEN
];
6109 unsigned int num_elem
= 0;
6110 EC_POINT
*Qr
= NULL
;
6111 EVP_PKEY
*Pr
= NULL
;
6112 EC_KEY
*Pr_ec
= NULL
;
6113 const EC_POINT
*Pr_point
;
6114 BIGNUM
*hash_bn
= NULL
;
6115 const EC_GROUP
*group
= NULL
;
6116 EC_GROUP
*group2
= NULL
;
6118 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6120 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
6121 addr
[num_elem
] = mac_resp
;
6122 len
[num_elem
] = ETH_ALEN
;
6125 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6127 addr
[num_elem
] = (const u8
*) identifier
;
6128 len
[num_elem
] = os_strlen(identifier
);
6131 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6132 addr
[num_elem
] = (const u8
*) code
;
6133 len
[num_elem
] = os_strlen(code
);
6135 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6137 wpa_hexdump_key(MSG_DEBUG
,
6138 "DPP: H(MAC-Responder | [identifier |] code)",
6139 hash
, curve
->hash_len
);
6140 Pr
= dpp_pkex_get_role_elem(curve
, 0);
6143 dpp_debug_print_key("DPP: Pr", Pr
);
6144 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
6147 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
6149 group
= EC_KEY_get0_group(Pr_ec
);
6152 group2
= EC_GROUP_dup(group
);
6155 Qr
= EC_POINT_new(group2
);
6157 EC_GROUP_free(group2
);
6160 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6162 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
6164 if (EC_POINT_is_at_infinity(group
, Qr
)) {
6165 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
6168 dpp_debug_print_point("DPP: Qr", group
, Qr
);
6172 BN_clear_free(hash_bn
);
6174 *ret_group
= group2
;
6183 #ifdef CONFIG_TESTING_OPTIONS
6184 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
6185 const struct dpp_curve_params
*curve
)
6193 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6198 point
= EC_POINT_new(group
);
6201 if (!ctx
|| !point
|| !x
|| !y
)
6204 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
6207 /* Generate a random y coordinate that results in a point that is not
6210 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
6213 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
6215 #ifdef OPENSSL_IS_BORINGSSL
6216 /* Unlike OpenSSL, BoringSSL returns an error from
6217 * EC_POINT_set_affine_coordinates_GFp() is not on the curve. */
6219 #else /* OPENSSL_IS_BORINGSSL */
6221 #endif /* OPENSSL_IS_BORINGSSL */
6224 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
6228 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
6229 curve
->prime_len
) < 0 ||
6230 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
6231 curve
->prime_len
) < 0)
6237 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
6240 EC_POINT_free(point
);
6245 #endif /* CONFIG_TESTING_OPTIONS */
6248 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
6250 EC_KEY
*X_ec
= NULL
;
6251 const EC_POINT
*X_point
;
6252 BN_CTX
*bnctx
= NULL
;
6253 const EC_GROUP
*group
;
6254 EC_POINT
*Qi
= NULL
, *M
= NULL
;
6255 struct wpabuf
*M_buf
= NULL
;
6256 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6257 struct wpabuf
*msg
= NULL
;
6259 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6261 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
6263 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6264 bnctx
= BN_CTX_new();
6267 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
6268 pkex
->identifier
, bnctx
, &group
);
6272 /* Generate a random ephemeral keypair x/X */
6273 #ifdef CONFIG_TESTING_OPTIONS
6274 if (dpp_pkex_ephemeral_key_override_len
) {
6275 const struct dpp_curve_params
*tmp_curve
;
6277 wpa_printf(MSG_INFO
,
6278 "DPP: TESTING - override ephemeral key x/X");
6279 pkex
->x
= dpp_set_keypair(&tmp_curve
,
6280 dpp_pkex_ephemeral_key_override
,
6281 dpp_pkex_ephemeral_key_override_len
);
6283 pkex
->x
= dpp_gen_keypair(curve
);
6285 #else /* CONFIG_TESTING_OPTIONS */
6286 pkex
->x
= dpp_gen_keypair(curve
);
6287 #endif /* CONFIG_TESTING_OPTIONS */
6292 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
6295 X_point
= EC_KEY_get0_public_key(X_ec
);
6298 dpp_debug_print_point("DPP: X", group
, X_point
);
6299 M
= EC_POINT_new(group
);
6302 if (!M
|| !Mx
|| !My
||
6303 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
6304 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
6306 dpp_debug_print_point("DPP: M", group
, M
);
6308 /* Initiator -> Responder: group, [identifier,] M */
6310 if (pkex
->identifier
)
6311 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6312 attr_len
+= 4 + 2 * curve
->prime_len
;
6313 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
6317 #ifdef CONFIG_TESTING_OPTIONS
6318 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
6319 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
6320 goto skip_finite_cyclic_group
;
6322 #endif /* CONFIG_TESTING_OPTIONS */
6324 /* Finite Cyclic Group attribute */
6325 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6326 wpabuf_put_le16(msg
, 2);
6327 wpabuf_put_le16(msg
, curve
->ike_group
);
6329 #ifdef CONFIG_TESTING_OPTIONS
6330 skip_finite_cyclic_group
:
6331 #endif /* CONFIG_TESTING_OPTIONS */
6333 /* Code Identifier attribute */
6334 if (pkex
->identifier
) {
6335 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6336 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6337 wpabuf_put_str(msg
, pkex
->identifier
);
6340 #ifdef CONFIG_TESTING_OPTIONS
6341 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6342 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6345 #endif /* CONFIG_TESTING_OPTIONS */
6347 /* M in Encrypted Key attribute */
6348 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6349 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6351 #ifdef CONFIG_TESTING_OPTIONS
6352 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6353 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6354 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6358 #endif /* CONFIG_TESTING_OPTIONS */
6360 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
6361 curve
->prime_len
) < 0 ||
6362 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
6363 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
6364 curve
->prime_len
) < 0)
6377 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
6384 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
6386 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
6390 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
6392 const char *identifier
,
6395 struct dpp_pkex
*pkex
;
6397 #ifdef CONFIG_TESTING_OPTIONS
6398 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
6399 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
6400 MAC2STR(dpp_pkex_own_mac_override
));
6401 own_mac
= dpp_pkex_own_mac_override
;
6403 #endif /* CONFIG_TESTING_OPTIONS */
6405 pkex
= os_zalloc(sizeof(*pkex
));
6408 pkex
->msg_ctx
= msg_ctx
;
6409 pkex
->initiator
= 1;
6411 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6413 pkex
->identifier
= os_strdup(identifier
);
6414 if (!pkex
->identifier
)
6417 pkex
->code
= os_strdup(code
);
6420 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
6421 if (!pkex
->exchange_req
)
6425 dpp_pkex_free(pkex
);
6430 static struct wpabuf
*
6431 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
6432 enum dpp_status_error status
,
6433 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
6435 struct wpabuf
*msg
= NULL
;
6437 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6439 /* Initiator -> Responder: DPP Status, [identifier,] N */
6441 if (pkex
->identifier
)
6442 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6443 attr_len
+= 4 + 2 * curve
->prime_len
;
6444 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
6448 #ifdef CONFIG_TESTING_OPTIONS
6449 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
6450 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
6454 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
6455 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
6458 #endif /* CONFIG_TESTING_OPTIONS */
6461 dpp_build_attr_status(msg
, status
);
6463 #ifdef CONFIG_TESTING_OPTIONS
6465 #endif /* CONFIG_TESTING_OPTIONS */
6467 /* Code Identifier attribute */
6468 if (pkex
->identifier
) {
6469 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6470 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6471 wpabuf_put_str(msg
, pkex
->identifier
);
6474 if (status
!= DPP_STATUS_OK
)
6475 goto skip_encrypted_key
;
6477 #ifdef CONFIG_TESTING_OPTIONS
6478 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6479 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6480 goto skip_encrypted_key
;
6482 #endif /* CONFIG_TESTING_OPTIONS */
6484 /* N in Encrypted Key attribute */
6485 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6486 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6488 #ifdef CONFIG_TESTING_OPTIONS
6489 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
6490 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6491 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6493 goto skip_encrypted_key
;
6495 #endif /* CONFIG_TESTING_OPTIONS */
6497 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
6498 curve
->prime_len
) < 0 ||
6499 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
6500 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
6501 curve
->prime_len
) < 0)
6505 if (status
== DPP_STATUS_BAD_GROUP
) {
6506 /* Finite Cyclic Group attribute */
6507 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6508 wpabuf_put_le16(msg
, 2);
6509 wpabuf_put_le16(msg
, curve
->ike_group
);
6519 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
6520 const u8
*Mx
, size_t Mx_len
,
6521 const u8
*Nx
, size_t Nx_len
,
6523 const u8
*Kx
, size_t Kx_len
,
6524 u8
*z
, unsigned int hash_len
)
6526 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6531 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6534 /* HKDF-Extract(<>, IKM=K.x) */
6535 os_memset(salt
, 0, hash_len
);
6536 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
6538 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
6540 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
6541 info
= os_malloc(info_len
);
6545 os_memcpy(pos
, mac_init
, ETH_ALEN
);
6547 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
6549 os_memcpy(pos
, Mx
, Mx_len
);
6551 os_memcpy(pos
, Nx
, Nx_len
);
6553 os_memcpy(pos
, code
, os_strlen(code
));
6555 /* HKDF-Expand(PRK, info, L) */
6557 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6559 else if (hash_len
== 48)
6560 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6562 else if (hash_len
== 64)
6563 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
6568 os_memset(prk
, 0, hash_len
);
6572 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
6578 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
6579 struct dpp_bootstrap_info
*bi
,
6582 const char *identifier
,
6584 const u8
*buf
, size_t len
)
6586 const u8
*attr_group
, *attr_id
, *attr_key
;
6587 u16 attr_group_len
, attr_id_len
, attr_key_len
;
6588 const struct dpp_curve_params
*curve
= bi
->curve
;
6590 struct dpp_pkex
*pkex
= NULL
;
6591 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
6592 BN_CTX
*bnctx
= NULL
;
6593 const EC_GROUP
*group
;
6594 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6595 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
6596 const EC_POINT
*Y_point
;
6597 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6598 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6601 EVP_PKEY_CTX
*ctx
= NULL
;
6603 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
6604 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6605 "PKEX counter t limit reached - ignore message");
6609 #ifdef CONFIG_TESTING_OPTIONS
6610 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
6611 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
6612 MAC2STR(dpp_pkex_peer_mac_override
));
6613 peer_mac
= dpp_pkex_peer_mac_override
;
6615 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
6616 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
6617 MAC2STR(dpp_pkex_own_mac_override
));
6618 own_mac
= dpp_pkex_own_mac_override
;
6620 #endif /* CONFIG_TESTING_OPTIONS */
6622 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
6624 if (!attr_id
&& identifier
) {
6625 wpa_printf(MSG_DEBUG
,
6626 "DPP: No PKEX code identifier received, but expected one");
6629 if (attr_id
&& identifier
&&
6630 (os_strlen(identifier
) != attr_id_len
||
6631 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
6632 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
6636 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
6638 if (!attr_group
|| attr_group_len
!= 2) {
6639 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6640 "Missing or invalid Finite Cyclic Group attribute");
6643 ike_group
= WPA_GET_LE16(attr_group
);
6644 if (ike_group
!= curve
->ike_group
) {
6645 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6646 "Mismatching PKEX curve: peer=%u own=%u",
6647 ike_group
, curve
->ike_group
);
6648 pkex
= os_zalloc(sizeof(*pkex
));
6653 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
6654 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
6655 if (!pkex
->exchange_resp
)
6660 /* M in Encrypted Key attribute */
6661 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
6663 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
6664 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
6665 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6666 "Missing Encrypted Key attribute");
6670 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6671 bnctx
= BN_CTX_new();
6674 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
6680 X
= EC_POINT_new(group
);
6681 M
= EC_POINT_new(group
);
6682 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
6683 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
6684 if (!X
|| !M
|| !Mx
|| !My
||
6685 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
6686 EC_POINT_is_at_infinity(group
, M
) ||
6687 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
6688 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
6689 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
6690 EC_POINT_is_at_infinity(group
, X
) ||
6691 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
6692 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6693 "Invalid Encrypted Key value");
6697 dpp_debug_print_point("DPP: M", group
, M
);
6698 dpp_debug_print_point("DPP: X'", group
, X
);
6700 pkex
= os_zalloc(sizeof(*pkex
));
6703 pkex
->t
= bi
->pkex_t
;
6704 pkex
->msg_ctx
= msg_ctx
;
6706 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
6707 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
6709 pkex
->identifier
= os_strdup(identifier
);
6710 if (!pkex
->identifier
)
6713 pkex
->code
= os_strdup(code
);
6717 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
6719 X_ec
= EC_KEY_new();
6721 EC_KEY_set_group(X_ec
, group
) != 1 ||
6722 EC_KEY_set_public_key(X_ec
, X
) != 1)
6724 pkex
->x
= EVP_PKEY_new();
6726 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
6729 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6730 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
6734 /* Generate a random ephemeral keypair y/Y */
6735 #ifdef CONFIG_TESTING_OPTIONS
6736 if (dpp_pkex_ephemeral_key_override_len
) {
6737 const struct dpp_curve_params
*tmp_curve
;
6739 wpa_printf(MSG_INFO
,
6740 "DPP: TESTING - override ephemeral key y/Y");
6741 pkex
->y
= dpp_set_keypair(&tmp_curve
,
6742 dpp_pkex_ephemeral_key_override
,
6743 dpp_pkex_ephemeral_key_override_len
);
6745 pkex
->y
= dpp_gen_keypair(curve
);
6747 #else /* CONFIG_TESTING_OPTIONS */
6748 pkex
->y
= dpp_gen_keypair(curve
);
6749 #endif /* CONFIG_TESTING_OPTIONS */
6754 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
6757 Y_point
= EC_KEY_get0_public_key(Y_ec
);
6760 dpp_debug_print_point("DPP: Y", group
, Y_point
);
6761 N
= EC_POINT_new(group
);
6764 if (!N
|| !Nx
|| !Ny
||
6765 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
6766 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
6768 dpp_debug_print_point("DPP: N", group
, N
);
6770 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
6772 if (!pkex
->exchange_resp
)
6776 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
6778 EVP_PKEY_derive_init(ctx
) != 1 ||
6779 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
6780 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
6781 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6782 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
6783 wpa_printf(MSG_ERROR
,
6784 "DPP: Failed to derive ECDH shared secret: %s",
6785 ERR_error_string(ERR_get_error(), NULL
));
6789 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
6792 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6794 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
6795 pkex
->Mx
, curve
->prime_len
,
6796 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
6797 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
6798 os_memset(Kx
, 0, Kx_len
);
6802 pkex
->exchange_done
= 1;
6805 EVP_PKEY_CTX_free(ctx
);
6820 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
6821 dpp_pkex_free(pkex
);
6827 static struct wpabuf
*
6828 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
6829 const struct wpabuf
*A_pub
, const u8
*u
)
6831 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6832 struct wpabuf
*msg
= NULL
;
6833 size_t clear_len
, attr_len
;
6834 struct wpabuf
*clear
= NULL
;
6840 /* {A, u, [bootstrapping info]}z */
6841 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
6842 clear
= wpabuf_alloc(clear_len
);
6843 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6844 #ifdef CONFIG_TESTING_OPTIONS
6845 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
6847 #endif /* CONFIG_TESTING_OPTIONS */
6848 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
6852 #ifdef CONFIG_TESTING_OPTIONS
6853 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6854 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
6855 goto skip_bootstrap_key
;
6857 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
6858 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
6859 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6860 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
6861 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
6863 goto skip_bootstrap_key
;
6865 #endif /* CONFIG_TESTING_OPTIONS */
6867 /* A in Bootstrap Key attribute */
6868 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
6869 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
6870 wpabuf_put_buf(clear
, A_pub
);
6872 #ifdef CONFIG_TESTING_OPTIONS
6874 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
6875 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
6876 goto skip_i_auth_tag
;
6878 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
6879 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
6880 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6881 wpabuf_put_le16(clear
, curve
->hash_len
);
6882 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
6883 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
6884 goto skip_i_auth_tag
;
6886 #endif /* CONFIG_TESTING_OPTIONS */
6888 /* u in I-Auth tag attribute */
6889 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
6890 wpabuf_put_le16(clear
, curve
->hash_len
);
6891 wpabuf_put_data(clear
, u
, curve
->hash_len
);
6893 #ifdef CONFIG_TESTING_OPTIONS
6895 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
6896 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
6897 goto skip_wrapped_data
;
6899 #endif /* CONFIG_TESTING_OPTIONS */
6901 addr
[0] = wpabuf_head_u8(msg
) + 2;
6902 len
[0] = DPP_HDR_LEN
;
6905 len
[1] = sizeof(octet
);
6906 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6907 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6909 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6910 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6911 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6913 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6914 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
6915 wpabuf_head(clear
), wpabuf_len(clear
),
6916 2, addr
, len
, wrapped
) < 0)
6918 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6919 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6921 #ifdef CONFIG_TESTING_OPTIONS
6922 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
6923 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
6924 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
6927 #endif /* CONFIG_TESTING_OPTIONS */
6940 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
6942 const u8
*buf
, size_t buflen
)
6944 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
6945 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
6946 const EC_GROUP
*group
;
6947 BN_CTX
*bnctx
= NULL
;
6948 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
6949 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6950 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
6951 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
6952 EVP_PKEY_CTX
*ctx
= NULL
;
6953 EC_KEY
*Y_ec
= NULL
;
6954 size_t Jx_len
, Kx_len
;
6955 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
6958 u8 u
[DPP_MAX_HASH_LEN
];
6961 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
6964 #ifdef CONFIG_TESTING_OPTIONS
6965 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
6966 wpa_printf(MSG_INFO
,
6967 "DPP: TESTING - stop at PKEX Exchange Response");
6972 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
6973 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
6974 MAC2STR(dpp_pkex_peer_mac_override
));
6975 peer_mac
= dpp_pkex_peer_mac_override
;
6977 #endif /* CONFIG_TESTING_OPTIONS */
6979 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
6981 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
6983 if (!attr_status
|| attr_status_len
!= 1) {
6984 dpp_pkex_fail(pkex
, "No DPP Status attribute");
6987 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
6989 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
6990 attr_group
= dpp_get_attr(buf
, buflen
,
6991 DPP_ATTR_FINITE_CYCLIC_GROUP
,
6993 if (attr_group
&& attr_group_len
== 2) {
6994 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
6995 "Peer indicated mismatching PKEX group - proposed %u",
6996 WPA_GET_LE16(attr_group
));
7001 if (attr_status
[0] != DPP_STATUS_OK
) {
7002 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
7006 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
7008 if (!attr_id
&& pkex
->identifier
) {
7009 wpa_printf(MSG_DEBUG
,
7010 "DPP: No PKEX code identifier received, but expected one");
7013 if (attr_id
&& pkex
->identifier
&&
7014 (os_strlen(pkex
->identifier
) != attr_id_len
||
7015 os_memcmp(pkex
->identifier
, attr_id
, attr_id_len
) != 0)) {
7016 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
7020 /* N in Encrypted Key attribute */
7021 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
7023 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
7024 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
7028 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7029 bnctx
= BN_CTX_new();
7032 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
7033 pkex
->identifier
, bnctx
, &group
);
7038 Y
= EC_POINT_new(group
);
7039 N
= EC_POINT_new(group
);
7040 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7041 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7042 if (!Y
|| !N
|| !Nx
|| !Ny
||
7043 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
7044 EC_POINT_is_at_infinity(group
, N
) ||
7045 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
7046 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
7047 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
7048 EC_POINT_is_at_infinity(group
, Y
) ||
7049 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
7050 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
7054 dpp_debug_print_point("DPP: N", group
, N
);
7055 dpp_debug_print_point("DPP: Y'", group
, Y
);
7057 pkex
->exchange_done
= 1;
7059 /* ECDH: J = a * Y’ */
7060 Y_ec
= EC_KEY_new();
7062 EC_KEY_set_group(Y_ec
, group
) != 1 ||
7063 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
7065 pkex
->y
= EVP_PKEY_new();
7067 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
7069 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7071 EVP_PKEY_derive_init(ctx
) != 1 ||
7072 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7073 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7074 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7075 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7076 wpa_printf(MSG_ERROR
,
7077 "DPP: Failed to derive ECDH shared secret: %s",
7078 ERR_error_string(ERR_get_error(), NULL
));
7082 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7085 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7086 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7087 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7088 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7089 if (!A_pub
|| !Y_pub
|| !X_pub
)
7091 addr
[0] = pkex
->own_mac
;
7093 addr
[1] = wpabuf_head(A_pub
);
7094 len
[1] = wpabuf_len(A_pub
) / 2;
7095 addr
[2] = wpabuf_head(Y_pub
);
7096 len
[2] = wpabuf_len(Y_pub
) / 2;
7097 addr
[3] = wpabuf_head(X_pub
);
7098 len
[3] = wpabuf_len(X_pub
) / 2;
7099 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7101 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
7104 EVP_PKEY_CTX_free(ctx
);
7105 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7107 EVP_PKEY_derive_init(ctx
) != 1 ||
7108 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7109 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7110 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7111 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7112 wpa_printf(MSG_ERROR
,
7113 "DPP: Failed to derive ECDH shared secret: %s",
7114 ERR_error_string(ERR_get_error(), NULL
));
7118 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7121 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7123 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
7124 pkex
->Mx
, curve
->prime_len
,
7125 attr_key
/* N.x */, attr_key_len
/ 2,
7126 pkex
->code
, Kx
, Kx_len
,
7127 pkex
->z
, curve
->hash_len
);
7128 os_memset(Kx
, 0, Kx_len
);
7132 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
7146 EVP_PKEY_CTX_free(ctx
);
7150 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
7155 static struct wpabuf
*
7156 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
7157 const struct wpabuf
*B_pub
, const u8
*v
)
7159 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7160 struct wpabuf
*msg
= NULL
;
7165 struct wpabuf
*clear
= NULL
;
7166 size_t clear_len
, attr_len
;
7168 /* {B, v [bootstrapping info]}z */
7169 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7170 clear
= wpabuf_alloc(clear_len
);
7171 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7172 #ifdef CONFIG_TESTING_OPTIONS
7173 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
7175 #endif /* CONFIG_TESTING_OPTIONS */
7176 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
7180 #ifdef CONFIG_TESTING_OPTIONS
7181 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7182 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7183 goto skip_bootstrap_key
;
7185 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7186 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7187 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7188 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7189 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7191 goto skip_bootstrap_key
;
7193 #endif /* CONFIG_TESTING_OPTIONS */
7195 /* B in Bootstrap Key attribute */
7196 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7197 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
7198 wpabuf_put_buf(clear
, B_pub
);
7200 #ifdef CONFIG_TESTING_OPTIONS
7202 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
7203 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
7204 goto skip_r_auth_tag
;
7206 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
7207 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
7208 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7209 wpabuf_put_le16(clear
, curve
->hash_len
);
7210 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
7211 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
7212 goto skip_r_auth_tag
;
7214 #endif /* CONFIG_TESTING_OPTIONS */
7216 /* v in R-Auth tag attribute */
7217 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7218 wpabuf_put_le16(clear
, curve
->hash_len
);
7219 wpabuf_put_data(clear
, v
, curve
->hash_len
);
7221 #ifdef CONFIG_TESTING_OPTIONS
7223 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
7224 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7225 goto skip_wrapped_data
;
7227 #endif /* CONFIG_TESTING_OPTIONS */
7229 addr
[0] = wpabuf_head_u8(msg
) + 2;
7230 len
[0] = DPP_HDR_LEN
;
7233 len
[1] = sizeof(octet
);
7234 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7235 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7237 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7238 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7239 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7241 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7242 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7243 wpabuf_head(clear
), wpabuf_len(clear
),
7244 2, addr
, len
, wrapped
) < 0)
7246 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7247 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7249 #ifdef CONFIG_TESTING_OPTIONS
7250 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
7251 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7252 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7255 #endif /* CONFIG_TESTING_OPTIONS */
7268 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
7270 const u8
*buf
, size_t buflen
)
7272 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7273 EVP_PKEY_CTX
*ctx
= NULL
;
7274 size_t Jx_len
, Lx_len
;
7275 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
7276 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7277 const u8
*wrapped_data
, *b_key
, *peer_u
;
7278 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
7282 u8
*unwrapped
= NULL
;
7283 size_t unwrapped_len
= 0;
7284 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7285 struct wpabuf
*B_pub
= NULL
;
7286 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
7288 #ifdef CONFIG_TESTING_OPTIONS
7289 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
7290 wpa_printf(MSG_INFO
,
7291 "DPP: TESTING - stop at PKEX CR Request");
7295 #endif /* CONFIG_TESTING_OPTIONS */
7297 if (!pkex
->exchange_done
|| pkex
->failed
||
7298 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
7301 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7303 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7305 "Missing or invalid required Wrapped Data attribute");
7309 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7310 wrapped_data
, wrapped_data_len
);
7311 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7312 unwrapped
= os_malloc(unwrapped_len
);
7317 len
[0] = DPP_HDR_LEN
;
7320 len
[1] = sizeof(octet
);
7321 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7322 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7324 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7325 wrapped_data
, wrapped_data_len
,
7326 2, addr
, len
, unwrapped
) < 0) {
7328 "AES-SIV decryption failed - possible PKEX code mismatch");
7333 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7334 unwrapped
, unwrapped_len
);
7336 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7337 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7341 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7343 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7344 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7347 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7349 if (!pkex
->peer_bootstrap_key
) {
7350 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7353 dpp_debug_print_key("DPP: Peer bootstrap public key",
7354 pkex
->peer_bootstrap_key
);
7356 /* ECDH: J' = y * A' */
7357 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7359 EVP_PKEY_derive_init(ctx
) != 1 ||
7360 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7361 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7362 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7363 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7364 wpa_printf(MSG_ERROR
,
7365 "DPP: Failed to derive ECDH shared secret: %s",
7366 ERR_error_string(ERR_get_error(), NULL
));
7370 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7373 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7374 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7375 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7376 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7377 if (!A_pub
|| !Y_pub
|| !X_pub
)
7379 addr
[0] = pkex
->peer_mac
;
7381 addr
[1] = wpabuf_head(A_pub
);
7382 len
[1] = wpabuf_len(A_pub
) / 2;
7383 addr
[2] = wpabuf_head(Y_pub
);
7384 len
[2] = wpabuf_len(Y_pub
) / 2;
7385 addr
[3] = wpabuf_head(X_pub
);
7386 len
[3] = wpabuf_len(X_pub
) / 2;
7387 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7390 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
7392 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
7393 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
7394 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
7395 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
7396 u
, curve
->hash_len
);
7397 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
7401 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
7403 /* ECDH: L = b * X' */
7404 EVP_PKEY_CTX_free(ctx
);
7405 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7407 EVP_PKEY_derive_init(ctx
) != 1 ||
7408 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
7409 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
7410 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7411 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
7412 wpa_printf(MSG_ERROR
,
7413 "DPP: Failed to derive ECDH shared secret: %s",
7414 ERR_error_string(ERR_get_error(), NULL
));
7418 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
7421 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7422 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7425 addr
[0] = pkex
->own_mac
;
7427 addr
[1] = wpabuf_head(B_pub
);
7428 len
[1] = wpabuf_len(B_pub
) / 2;
7429 addr
[2] = wpabuf_head(X_pub
);
7430 len
[2] = wpabuf_len(X_pub
) / 2;
7431 addr
[3] = wpabuf_head(Y_pub
);
7432 len
[3] = wpabuf_len(Y_pub
) / 2;
7433 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7435 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
7437 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
7442 EVP_PKEY_CTX_free(ctx
);
7450 wpa_printf(MSG_DEBUG
,
7451 "DPP: PKEX Commit-Reveal Request processing failed");
7456 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
7457 const u8
*buf
, size_t buflen
)
7459 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7460 const u8
*wrapped_data
, *b_key
, *peer_v
;
7461 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
7465 u8
*unwrapped
= NULL
;
7466 size_t unwrapped_len
= 0;
7468 u8 v
[DPP_MAX_HASH_LEN
];
7470 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7471 EVP_PKEY_CTX
*ctx
= NULL
;
7472 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7474 #ifdef CONFIG_TESTING_OPTIONS
7475 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
7476 wpa_printf(MSG_INFO
,
7477 "DPP: TESTING - stop at PKEX CR Response");
7481 #endif /* CONFIG_TESTING_OPTIONS */
7483 if (!pkex
->exchange_done
|| pkex
->failed
||
7484 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
7487 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7489 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7491 "Missing or invalid required Wrapped Data attribute");
7495 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7496 wrapped_data
, wrapped_data_len
);
7497 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7498 unwrapped
= os_malloc(unwrapped_len
);
7503 len
[0] = DPP_HDR_LEN
;
7506 len
[1] = sizeof(octet
);
7507 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7508 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7510 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7511 wrapped_data
, wrapped_data_len
,
7512 2, addr
, len
, unwrapped
) < 0) {
7514 "AES-SIV decryption failed - possible PKEX code mismatch");
7518 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7519 unwrapped
, unwrapped_len
);
7521 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7522 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7526 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7528 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7529 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7532 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7534 if (!pkex
->peer_bootstrap_key
) {
7535 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7538 dpp_debug_print_key("DPP: Peer bootstrap public key",
7539 pkex
->peer_bootstrap_key
);
7541 /* ECDH: L' = x * B' */
7542 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7544 EVP_PKEY_derive_init(ctx
) != 1 ||
7545 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7546 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
7547 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7548 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
7549 wpa_printf(MSG_ERROR
,
7550 "DPP: Failed to derive ECDH shared secret: %s",
7551 ERR_error_string(ERR_get_error(), NULL
));
7555 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
7558 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
7559 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7560 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7561 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7562 if (!B_pub
|| !X_pub
|| !Y_pub
)
7564 addr
[0] = pkex
->peer_mac
;
7566 addr
[1] = wpabuf_head(B_pub
);
7567 len
[1] = wpabuf_len(B_pub
) / 2;
7568 addr
[2] = wpabuf_head(X_pub
);
7569 len
[2] = wpabuf_len(X_pub
) / 2;
7570 addr
[3] = wpabuf_head(Y_pub
);
7571 len
[3] = wpabuf_len(Y_pub
) / 2;
7572 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
7575 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
7577 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
7578 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
7579 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
7580 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
7581 v
, curve
->hash_len
);
7582 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
7586 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
7593 EVP_PKEY_CTX_free(ctx
);
7601 void dpp_pkex_free(struct dpp_pkex
*pkex
)
7606 os_free(pkex
->identifier
);
7607 os_free(pkex
->code
);
7608 EVP_PKEY_free(pkex
->x
);
7609 EVP_PKEY_free(pkex
->y
);
7610 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
7611 wpabuf_free(pkex
->exchange_req
);
7612 wpabuf_free(pkex
->exchange_resp
);
7617 #ifdef CONFIG_TESTING_OPTIONS
7618 char * dpp_corrupt_connector_signature(const char *connector
)
7620 char *tmp
, *pos
, *signed3
= NULL
;
7621 unsigned char *signature
= NULL
;
7622 size_t signature_len
= 0, signed3_len
;
7624 tmp
= os_zalloc(os_strlen(connector
) + 5);
7627 os_memcpy(tmp
, connector
, os_strlen(connector
));
7629 pos
= os_strchr(tmp
, '.');
7633 pos
= os_strchr(pos
+ 1, '.');
7638 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
7640 signature
= base64_url_decode((const unsigned char *) pos
,
7641 os_strlen(pos
), &signature_len
);
7642 if (!signature
|| signature_len
== 0)
7644 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
7645 signature
, signature_len
);
7646 signature
[signature_len
- 1] ^= 0x01;
7647 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
7648 signature
, signature_len
);
7649 signed3
= (char *) base64_url_encode(signature
, signature_len
,
7653 os_memcpy(pos
, signed3
, signed3_len
);
7654 pos
[signed3_len
] = '\0';
7655 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
7667 #endif /* CONFIG_TESTING_OPTIONS */