]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/common/dpp.c
DPP: Support retrieving of configurator's private key
[thirdparty/hostap.git] / src / common / dpp.c
1 /*
2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
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>
14
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"
28 #include "dpp.h"
29
30
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;
41
42 static int dpp_test_gen_invalid_key(struct wpabuf *msg,
43 const struct dpp_curve_params *curve);
44 #endif /* CONFIG_TESTING_OPTIONS */
45
46 #if OPENSSL_VERSION_NUMBER < 0x10100000L
47 /* Compatibility wrappers for older versions. */
48
49 static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
50 {
51 sig->r = r;
52 sig->s = s;
53 return 1;
54 }
55
56
57 static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
58 const BIGNUM **ps)
59 {
60 if (pr)
61 *pr = sig->r;
62 if (ps)
63 *ps = sig->s;
64 }
65
66 #endif
67
68
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 }
79 };
80
81
82 /* Role-specific elements for PKEX */
83
84 /* NIST P-256 */
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
90 };
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
96 };
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
102 };
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
108 };
109
110 /* NIST P-384 */
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
118 };
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
126 };
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
134 };
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
142 };
143
144 /* NIST P-521 */
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,
154 0x97, 0x76
155 };
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,
165 0x03, 0xa8
166 };
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,
176 0x84, 0xb4
177 };
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,
187 0xce, 0xe1
188 };
189
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
196 };
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
202 };
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
208 };
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
214 };
215
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
224 };
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
232 };
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
240 };
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
248 };
249
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
260 };
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
270 };
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
280 };
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
290 };
291
292
293 static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
294 const EC_POINT *point)
295 {
296 BIGNUM *x, *y;
297 BN_CTX *ctx;
298 char *x_str = NULL, *y_str = NULL;
299
300 if (!wpa_debug_show_keys)
301 return;
302
303 ctx = BN_CTX_new();
304 x = BN_new();
305 y = BN_new();
306 if (!ctx || !x || !y ||
307 EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
308 goto fail;
309
310 x_str = BN_bn2hex(x);
311 y_str = BN_bn2hex(y);
312 if (!x_str || !y_str)
313 goto fail;
314
315 wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
316
317 fail:
318 OPENSSL_free(x_str);
319 OPENSSL_free(y_str);
320 BN_free(x);
321 BN_free(y);
322 BN_CTX_free(ctx);
323 }
324
325
326 static int dpp_hash_vector(const struct dpp_curve_params *curve,
327 size_t num_elem, const u8 *addr[], const size_t *len,
328 u8 *mac)
329 {
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);
336 return -1;
337 }
338
339
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)
342 {
343 if (hash_len == 32)
344 return hmac_sha256_kdf(secret, secret_len, NULL,
345 (const u8 *) label, os_strlen(label),
346 out, outlen);
347 if (hash_len == 48)
348 return hmac_sha384_kdf(secret, secret_len, NULL,
349 (const u8 *) label, os_strlen(label),
350 out, outlen);
351 if (hash_len == 64)
352 return hmac_sha512_kdf(secret, secret_len, NULL,
353 (const u8 *) label, os_strlen(label),
354 out, outlen);
355 return -1;
356 }
357
358
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)
362 {
363 if (hash_len == 32)
364 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
365 mac);
366 if (hash_len == 48)
367 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
368 mac);
369 if (hash_len == 64)
370 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
371 mac);
372 return -1;
373 }
374
375
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)
378 {
379 if (hash_len == 32)
380 return hmac_sha256(key, key_len, data, data_len, mac);
381 if (hash_len == 48)
382 return hmac_sha384(key, key_len, data, data_len, mac);
383 if (hash_len == 64)
384 return hmac_sha512(key, key_len, data, data_len, mac);
385 return -1;
386 }
387
388
389 static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
390 {
391 int num_bytes, offset;
392
393 num_bytes = BN_num_bytes(bn);
394 if ((size_t) num_bytes > len)
395 return -1;
396 offset = len - num_bytes;
397 os_memset(pos, 0, offset);
398 BN_bn2bin(bn, pos + offset);
399 return 0;
400 }
401
402
403 static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
404 {
405 int len, res;
406 EC_KEY *eckey;
407 struct wpabuf *buf;
408 unsigned char *pos;
409
410 eckey = EVP_PKEY_get1_EC_KEY(pkey);
411 if (!eckey)
412 return NULL;
413 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
414 len = i2o_ECPublicKey(eckey, NULL);
415 if (len <= 0) {
416 wpa_printf(MSG_ERROR,
417 "DDP: Failed to determine public key encoding length");
418 EC_KEY_free(eckey);
419 return NULL;
420 }
421
422 buf = wpabuf_alloc(len);
423 if (!buf) {
424 EC_KEY_free(eckey);
425 return NULL;
426 }
427
428 pos = wpabuf_put(buf, len);
429 res = i2o_ECPublicKey(eckey, &pos);
430 EC_KEY_free(eckey);
431 if (res != len) {
432 wpa_printf(MSG_ERROR,
433 "DDP: Failed to encode public key (res=%d/%d)",
434 res, len);
435 wpabuf_free(buf);
436 return NULL;
437 }
438
439 if (!prefix) {
440 /* Remove 0x04 prefix to match DPP definition */
441 pos = wpabuf_mhead(buf);
442 os_memmove(pos, pos + 1, len - 1);
443 buf->used--;
444 }
445
446 return buf;
447 }
448
449
450 static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
451 const u8 *buf_x, const u8 *buf_y,
452 size_t len)
453 {
454 EC_KEY *eckey = NULL;
455 BN_CTX *ctx;
456 EC_POINT *point = NULL;
457 BIGNUM *x = NULL, *y = NULL;
458 EVP_PKEY *pkey = NULL;
459
460 ctx = BN_CTX_new();
461 if (!ctx) {
462 wpa_printf(MSG_ERROR, "DPP: Out of memory");
463 return NULL;
464 }
465
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");
471 goto fail;
472 }
473
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));
478 goto fail;
479 }
480
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");
484 goto fail;
485 }
486 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
487
488 eckey = EC_KEY_new();
489 if (!eckey ||
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));
495 goto fail;
496 }
497 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
498
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");
502 goto fail;
503 }
504
505 out:
506 BN_free(x);
507 BN_free(y);
508 EC_KEY_free(eckey);
509 EC_POINT_free(point);
510 BN_CTX_free(ctx);
511 return pkey;
512 fail:
513 EVP_PKEY_free(pkey);
514 pkey = NULL;
515 goto out;
516 }
517
518
519 static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
520 const u8 *buf, size_t len)
521 {
522 EC_KEY *eckey;
523 const EC_GROUP *group;
524 EVP_PKEY *pkey = NULL;
525
526 if (len & 1)
527 return NULL;
528
529 eckey = EVP_PKEY_get1_EC_KEY(group_key);
530 if (!eckey) {
531 wpa_printf(MSG_ERROR,
532 "DPP: Could not get EC_KEY from group_key");
533 return NULL;
534 }
535
536 group = EC_KEY_get0_group(eckey);
537 if (group)
538 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
539 len / 2);
540 else
541 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
542
543 EC_KEY_free(eckey);
544 return pkey;
545 }
546
547
548 static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
549 {
550 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
551 }
552
553
554 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
555 size_t len)
556 {
557 struct wpabuf *msg;
558
559 msg = wpabuf_alloc(8 + len);
560 if (!msg)
561 return NULL;
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);
568 return msg;
569 }
570
571
572 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
573 {
574 u16 id, alen;
575 const u8 *pos = buf, *end = buf + len;
576
577 while (end - pos >= 4) {
578 id = WPA_GET_LE16(pos);
579 pos += 2;
580 alen = WPA_GET_LE16(pos);
581 pos += 2;
582 if (alen > end - pos)
583 return NULL;
584 if (id == req_id) {
585 *ret_len = alen;
586 return pos;
587 }
588 pos += alen;
589 }
590
591 return NULL;
592 }
593
594
595 int dpp_check_attrs(const u8 *buf, size_t len)
596 {
597 const u8 *pos, *end;
598 int wrapped_data = 0;
599
600 pos = buf;
601 end = buf + len;
602 while (end - pos >= 4) {
603 u16 id, alen;
604
605 id = WPA_GET_LE16(pos);
606 pos += 2;
607 alen = WPA_GET_LE16(pos);
608 pos += 2;
609 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
610 id, alen);
611 if (alen > end - pos) {
612 wpa_printf(MSG_DEBUG,
613 "DPP: Truncated message - not enough room for the attribute - dropped");
614 return -1;
615 }
616 if (wrapped_data) {
617 wpa_printf(MSG_DEBUG,
618 "DPP: An unexpected attribute included after the Wrapped Data attribute");
619 return -1;
620 }
621 if (id == DPP_ATTR_WRAPPED_DATA)
622 wrapped_data = 1;
623 pos += alen;
624 }
625
626 if (end != pos) {
627 wpa_printf(MSG_DEBUG,
628 "DPP: Unexpected octets (%d) after the last attribute",
629 (int) (end - pos));
630 return -1;
631 }
632
633 return 0;
634 }
635
636
637 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
638 {
639 if (!info)
640 return;
641 os_free(info->uri);
642 os_free(info->info);
643 EVP_PKEY_free(info->pubkey);
644 os_free(info);
645 }
646
647
648 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
649 {
650 switch (type) {
651 case DPP_BOOTSTRAP_QR_CODE:
652 return "QRCODE";
653 case DPP_BOOTSTRAP_PKEX:
654 return "PKEX";
655 }
656 return "??";
657 }
658
659
660 static int dpp_uri_valid_info(const char *info)
661 {
662 while (*info) {
663 unsigned char val = *info++;
664
665 if (val < 0x20 || val > 0x7e || val == 0x3b)
666 return 0;
667 }
668
669 return 1;
670 }
671
672
673 static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
674 {
675 bi->uri = os_strdup(uri);
676 return bi->uri ? 0 : -1;
677 }
678
679
680 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
681 const char *chan_list)
682 {
683 const char *pos = chan_list;
684 int opclass, channel, freq;
685
686 while (pos && *pos && *pos != ';') {
687 opclass = atoi(pos);
688 if (opclass <= 0)
689 goto fail;
690 pos = os_strchr(pos, '/');
691 if (!pos)
692 goto fail;
693 pos++;
694 channel = atoi(pos);
695 if (channel <= 0)
696 goto fail;
697 while (*pos >= '0' && *pos <= '9')
698 pos++;
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);
703 if (freq < 0) {
704 wpa_printf(MSG_DEBUG,
705 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
706 opclass, channel);
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");
710 bi->num_freq = 0;
711 break;
712 } else {
713 bi->freq[bi->num_freq++] = freq;
714 }
715
716 if (*pos == ';' || *pos == '\0')
717 break;
718 if (*pos != ',')
719 goto fail;
720 pos++;
721 }
722
723 return 0;
724 fail:
725 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
726 return -1;
727 }
728
729
730 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
731 {
732 if (!mac)
733 return 0;
734
735 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
736 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
737 return -1;
738 }
739
740 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
741
742 return 0;
743 }
744
745
746 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
747 {
748 const char *end;
749
750 if (!info)
751 return 0;
752
753 end = os_strchr(info, ';');
754 if (!end)
755 end = info + os_strlen(info);
756 bi->info = os_malloc(end - info + 1);
757 if (!bi->info)
758 return -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");
764 return -1;
765 }
766
767 return 0;
768 }
769
770
771 static const struct dpp_curve_params *
772 dpp_get_curve_oid(const ASN1_OBJECT *poid)
773 {
774 ASN1_OBJECT *oid;
775 int i;
776
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];
781 }
782 return NULL;
783 }
784
785
786 static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
787 {
788 int i, tmp;
789
790 if (!nid)
791 return NULL;
792 for (i = 0; dpp_curves[i].name; i++) {
793 tmp = OBJ_txt2nid(dpp_curves[i].name);
794 if (tmp == nid)
795 return &dpp_curves[i];
796 }
797 return NULL;
798 }
799
800
801 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
802 {
803 const char *end;
804 u8 *data;
805 size_t data_len;
806 EVP_PKEY *pkey;
807 const unsigned char *p;
808 int res;
809 X509_PUBKEY *pub = NULL;
810 ASN1_OBJECT *ppkalg;
811 const unsigned char *pk;
812 int ppklen;
813 X509_ALGOR *pa;
814 #if OPENSSL_VERSION_NUMBER < 0x10100000L
815 ASN1_OBJECT *pa_oid;
816 #else
817 const ASN1_OBJECT *pa_oid;
818 #endif
819 const void *pval;
820 int ptype;
821 const ASN1_OBJECT *poid;
822 char buf[100];
823
824 end = os_strchr(info, ';');
825 if (!end)
826 return -1;
827
828 data = base64_decode((const unsigned char *) info, end - info,
829 &data_len);
830 if (!data) {
831 wpa_printf(MSG_DEBUG,
832 "DPP: Invalid base64 encoding on URI public-key");
833 return -1;
834 }
835 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
836 data, data_len);
837
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");
841 return -1;
842 }
843 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
844 bi->pubkey_hash, SHA256_MAC_LEN);
845
846 /* DER encoded ASN.1 SubjectPublicKeyInfo
847 *
848 * SubjectPublicKeyInfo ::= SEQUENCE {
849 * algorithm AlgorithmIdentifier,
850 * subjectPublicKey BIT STRING }
851 *
852 * AlgorithmIdentifier ::= SEQUENCE {
853 * algorithm OBJECT IDENTIFIER,
854 * parameters ANY DEFINED BY algorithm OPTIONAL }
855 *
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)
860 */
861
862 p = data;
863 pkey = d2i_PUBKEY(NULL, &p, data_len);
864 os_free(data);
865
866 if (!pkey) {
867 wpa_printf(MSG_DEBUG,
868 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
869 return -1;
870 }
871
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");
875 EVP_PKEY_free(pkey);
876 return -1;
877 }
878
879 res = X509_PUBKEY_set(&pub, pkey);
880 if (res != 1) {
881 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
882 goto fail;
883 }
884
885 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
886 if (res != 1) {
887 wpa_printf(MSG_DEBUG,
888 "DPP: Could not extract SubjectPublicKeyInfo parameters");
889 goto fail;
890 }
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");
895 goto fail;
896 }
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");
901 goto fail;
902 }
903
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");
908 goto fail;
909 }
910 poid = pval;
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");
915 goto fail;
916 }
917 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
918 bi->curve = dpp_get_curve_oid(poid);
919 if (!bi->curve) {
920 wpa_printf(MSG_DEBUG,
921 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
922 buf);
923 goto fail;
924 }
925
926 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
927
928 X509_PUBKEY_free(pub);
929 bi->pubkey = pkey;
930 return 0;
931 fail:
932 X509_PUBKEY_free(pub);
933 EVP_PKEY_free(pkey);
934 return -1;
935 }
936
937
938 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
939 {
940 const char *pos = uri;
941 const char *end;
942 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
943 struct dpp_bootstrap_info *bi;
944
945 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
946
947 if (os_strncmp(pos, "DPP:", 4) != 0) {
948 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
949 return NULL;
950 }
951 pos += 4;
952
953 for (;;) {
954 end = os_strchr(pos, ';');
955 if (!end)
956 break;
957
958 if (end == pos) {
959 /* Handle terminating ";;" and ignore unexpected ";"
960 * for parsing robustness. */
961 pos++;
962 continue;
963 }
964
965 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
966 chan_list = pos + 2;
967 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
968 mac = pos + 2;
969 else if (pos[0] == 'I' && pos[1] == ':' && !info)
970 info = pos + 2;
971 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
972 pk = pos + 2;
973 else
974 wpa_hexdump_ascii(MSG_DEBUG,
975 "DPP: Ignore unrecognized URI parameter",
976 pos, end - pos);
977 pos = end + 1;
978 }
979
980 if (!pk) {
981 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
982 return NULL;
983 }
984
985 bi = os_zalloc(sizeof(*bi));
986 if (!bi)
987 return NULL;
988
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);
995 bi = NULL;
996 }
997
998 return bi;
999 }
1000
1001
1002 struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
1003 {
1004 struct dpp_bootstrap_info *bi;
1005
1006 bi = dpp_parse_uri(uri);
1007 if (bi)
1008 bi->type = DPP_BOOTSTRAP_QR_CODE;
1009 return bi;
1010 }
1011
1012
1013 static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
1014 {
1015 EC_KEY *eckey;
1016 BIO *out;
1017 size_t rlen;
1018 char *txt;
1019 int res;
1020 unsigned char *der = NULL;
1021 int der_len;
1022 const EC_GROUP *group;
1023 const EC_POINT *point;
1024
1025 out = BIO_new(BIO_s_mem());
1026 if (!out)
1027 return;
1028
1029 EVP_PKEY_print_private(out, key, 0, NULL);
1030 rlen = BIO_ctrl_pending(out);
1031 txt = os_malloc(rlen + 1);
1032 if (txt) {
1033 res = BIO_read(out, txt, rlen);
1034 if (res > 0) {
1035 txt[res] = '\0';
1036 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
1037 }
1038 os_free(txt);
1039 }
1040 BIO_free(out);
1041
1042 eckey = EVP_PKEY_get1_EC_KEY(key);
1043 if (!eckey)
1044 return;
1045
1046 group = EC_KEY_get0_group(eckey);
1047 point = EC_KEY_get0_public_key(eckey);
1048 if (group && point)
1049 dpp_debug_print_point(title, group, point);
1050
1051 der_len = i2d_ECPrivateKey(eckey, &der);
1052 if (der_len > 0)
1053 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1054 OPENSSL_free(der);
1055 if (der_len <= 0) {
1056 der = NULL;
1057 der_len = i2d_EC_PUBKEY(eckey, &der);
1058 if (der_len > 0)
1059 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1060 OPENSSL_free(der);
1061 }
1062
1063 EC_KEY_free(eckey);
1064 }
1065
1066
1067 static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1068 {
1069 EVP_PKEY_CTX *kctx = NULL;
1070 EC_KEY *ec_params;
1071 EVP_PKEY *params = NULL, *key = NULL;
1072 int nid;
1073
1074 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1075
1076 nid = OBJ_txt2nid(curve->name);
1077 if (nid == NID_undef) {
1078 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1079 return NULL;
1080 }
1081
1082 ec_params = EC_KEY_new_by_curve_name(nid);
1083 if (!ec_params) {
1084 wpa_printf(MSG_ERROR,
1085 "DPP: Failed to generate EC_KEY parameters");
1086 goto fail;
1087 }
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");
1093 goto fail;
1094 }
1095
1096 kctx = EVP_PKEY_CTX_new(params, NULL);
1097 if (!kctx ||
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");
1101 goto fail;
1102 }
1103
1104 if (wpa_debug_show_keys)
1105 dpp_debug_print_key("Own generated key", key);
1106
1107 EVP_PKEY_free(params);
1108 EVP_PKEY_CTX_free(kctx);
1109 return key;
1110 fail:
1111 EVP_PKEY_CTX_free(kctx);
1112 EVP_PKEY_free(params);
1113 return NULL;
1114 }
1115
1116
1117 static const struct dpp_curve_params *
1118 dpp_get_curve_name(const char *name)
1119 {
1120 int i;
1121
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];
1127 }
1128 return NULL;
1129 }
1130
1131
1132 static const struct dpp_curve_params *
1133 dpp_get_curve_jwk_crv(const char *name)
1134 {
1135 int i;
1136
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];
1141 }
1142 return NULL;
1143 }
1144
1145
1146 static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1147 const u8 *privkey, size_t privkey_len)
1148 {
1149 EVP_PKEY *pkey;
1150 EC_KEY *eckey;
1151 const EC_GROUP *group;
1152 int nid;
1153
1154 pkey = EVP_PKEY_new();
1155 if (!pkey)
1156 return NULL;
1157 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1158 if (!eckey) {
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);
1163 return NULL;
1164 }
1165 group = EC_KEY_get0_group(eckey);
1166 if (!group) {
1167 EC_KEY_free(eckey);
1168 EVP_PKEY_free(pkey);
1169 return NULL;
1170 }
1171 nid = EC_GROUP_get_curve_name(group);
1172 *curve = dpp_get_curve_nid(nid);
1173 if (!*curve) {
1174 wpa_printf(MSG_INFO,
1175 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1176 nid);
1177 EC_KEY_free(eckey);
1178 EVP_PKEY_free(pkey);
1179 return NULL;
1180 }
1181
1182 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1183 EC_KEY_free(eckey);
1184 EVP_PKEY_free(pkey);
1185 return NULL;
1186 }
1187 return pkey;
1188 }
1189
1190
1191 typedef struct {
1192 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1193 * as an OID identifying the curve */
1194 X509_ALGOR *alg;
1195 /* Compressed format public key per ANSI X9.63 */
1196 ASN1_BIT_STRING *pub_key;
1197 } DPP_BOOTSTRAPPING_KEY;
1198
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);
1203
1204 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1205
1206
1207 static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
1208 {
1209 unsigned char *der = NULL;
1210 int der_len;
1211 EC_KEY *eckey;
1212 struct wpabuf *ret = NULL;
1213 size_t len;
1214 const EC_GROUP *group;
1215 const EC_POINT *point;
1216 BN_CTX *ctx;
1217 DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1218 int nid;
1219
1220 ctx = BN_CTX_new();
1221 eckey = EVP_PKEY_get1_EC_KEY(key);
1222 if (!ctx || !eckey)
1223 goto fail;
1224
1225 group = EC_KEY_get0_group(eckey);
1226 point = EC_KEY_get0_public_key(eckey);
1227 if (!group || !point)
1228 goto fail;
1229 dpp_debug_print_point("DPP: bootstrap public key", group, point);
1230 nid = EC_GROUP_get_curve_name(group);
1231
1232 bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1233 if (!bootstrap ||
1234 X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1235 V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1236 goto fail;
1237
1238 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1239 NULL, 0, ctx);
1240 if (len == 0)
1241 goto fail;
1242
1243 der = OPENSSL_malloc(len);
1244 if (!der)
1245 goto fail;
1246 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1247 der, len, ctx);
1248
1249 OPENSSL_free(bootstrap->pub_key->data);
1250 bootstrap->pub_key->data = der;
1251 der = NULL;
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;
1256
1257 der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
1258 if (der_len <= 0) {
1259 wpa_printf(MSG_ERROR,
1260 "DDP: Failed to build DER encoded public key");
1261 goto fail;
1262 }
1263
1264 ret = wpabuf_alloc_copy(der, der_len);
1265 fail:
1266 DPP_BOOTSTRAPPING_KEY_free(bootstrap);
1267 OPENSSL_free(der);
1268 EC_KEY_free(eckey);
1269 BN_CTX_free(ctx);
1270 return ret;
1271 }
1272
1273
1274 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
1275 {
1276 struct wpabuf *der;
1277 int res;
1278 const u8 *addr[1];
1279 size_t len[1];
1280
1281 der = dpp_bootstrap_key_der(bi->pubkey);
1282 if (!der)
1283 return -1;
1284 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1285 der);
1286
1287 addr[0] = wpabuf_head(der);
1288 len[0] = wpabuf_len(der);
1289 res = sha256_vector(1, addr, len, bi->pubkey_hash);
1290 if (res < 0)
1291 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1292 else
1293 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1294 SHA256_MAC_LEN);
1295 wpabuf_free(der);
1296 return res;
1297 }
1298
1299
1300 char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1301 const u8 *privkey, size_t privkey_len)
1302 {
1303 unsigned char *base64 = NULL;
1304 char *pos, *end;
1305 size_t len;
1306 struct wpabuf *der = NULL;
1307 const u8 *addr[1];
1308 int res;
1309
1310 if (!curve) {
1311 bi->curve = &dpp_curves[0];
1312 } else {
1313 bi->curve = dpp_get_curve_name(curve);
1314 if (!bi->curve) {
1315 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1316 curve);
1317 return NULL;
1318 }
1319 }
1320 if (privkey)
1321 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1322 else
1323 bi->pubkey = dpp_gen_keypair(bi->curve);
1324 if (!bi->pubkey)
1325 goto fail;
1326 bi->own = 1;
1327
1328 der = dpp_bootstrap_key_der(bi->pubkey);
1329 if (!der)
1330 goto fail;
1331 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1332 der);
1333
1334 addr[0] = wpabuf_head(der);
1335 len = wpabuf_len(der);
1336 res = sha256_vector(1, addr, &len, bi->pubkey_hash);
1337 if (res < 0) {
1338 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1339 goto fail;
1340 }
1341 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1342 SHA256_MAC_LEN);
1343
1344 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1345 wpabuf_free(der);
1346 der = NULL;
1347 if (!base64)
1348 goto fail;
1349 pos = (char *) base64;
1350 end = pos + len;
1351 for (;;) {
1352 pos = os_strchr(pos, '\n');
1353 if (!pos)
1354 break;
1355 os_memmove(pos, pos + 1, end - pos);
1356 }
1357 return (char *) base64;
1358 fail:
1359 os_free(base64);
1360 wpabuf_free(der);
1361 return NULL;
1362 }
1363
1364
1365 static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1366 unsigned int hash_len)
1367 {
1368 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1369 const char *info = "first intermediate key";
1370 int res;
1371
1372 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1373
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)
1377 return -1;
1378 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1379 prk, hash_len);
1380
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);
1384 if (res < 0)
1385 return -1;
1386
1387 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1388 k1, hash_len);
1389 return 0;
1390 }
1391
1392
1393 static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1394 unsigned int hash_len)
1395 {
1396 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1397 const char *info = "second intermediate key";
1398 int res;
1399
1400 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1401
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);
1405 if (res < 0)
1406 return -1;
1407 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1408 prk, hash_len);
1409
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);
1413 if (res < 0)
1414 return -1;
1415
1416 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1417 k2, hash_len);
1418 return 0;
1419 }
1420
1421
1422 static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1423 unsigned int hash_len)
1424 {
1425 size_t nonce_len;
1426 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1427 const char *info_ke = "DPP Key";
1428 u8 prk[DPP_MAX_HASH_LEN];
1429 int res;
1430 const u8 *addr[3];
1431 size_t len[3];
1432 size_t num_elem = 0;
1433
1434 if (!auth->Mx_len || !auth->Nx_len) {
1435 wpa_printf(MSG_DEBUG,
1436 "DPP: Mx/Nx not available - cannot derive ke");
1437 return -1;
1438 }
1439
1440 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1441
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;
1448 num_elem++;
1449 addr[num_elem] = auth->Nx;
1450 len[num_elem] = auth->Nx_len;
1451 num_elem++;
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");
1456 return -1;
1457 }
1458 addr[num_elem] = auth->Lx;
1459 len[num_elem] = auth->secret_len;
1460 num_elem++;
1461 }
1462 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1463 num_elem, addr, len, prk);
1464 if (res < 0)
1465 return -1;
1466 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1467 prk, hash_len);
1468
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);
1472 if (res < 0)
1473 return -1;
1474
1475 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1476 ke, hash_len);
1477 return 0;
1478 }
1479
1480
1481 static void dpp_build_attr_status(struct wpabuf *msg,
1482 enum dpp_status_error status)
1483 {
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);
1488 }
1489
1490
1491 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1492 const u8 *hash)
1493 {
1494 if (hash) {
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);
1499 }
1500 }
1501
1502
1503 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1504 const u8 *hash)
1505 {
1506 if (hash) {
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);
1511 }
1512 }
1513
1514
1515 static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1516 const struct wpabuf *pi,
1517 size_t nonce_len,
1518 const u8 *r_pubkey_hash,
1519 const u8 *i_pubkey_hash,
1520 unsigned int neg_freq)
1521 {
1522 struct wpabuf *msg;
1523 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1524 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1525 u8 *pos;
1526 const u8 *addr[2];
1527 size_t len[2], siv_len, attr_len;
1528 u8 *attr_start, *attr_end;
1529
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);
1533 if (neg_freq > 0)
1534 attr_len += 4 + 2;
1535 #ifdef CONFIG_TESTING_OPTIONS
1536 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1537 attr_len += 5;
1538 #endif /* CONFIG_TESTING_OPTIONS */
1539 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1540 if (!msg)
1541 return NULL;
1542
1543 attr_start = wpabuf_put(msg, 0);
1544
1545 /* Responder Bootstrapping Key Hash */
1546 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1547
1548 /* Initiator Bootstrapping Key Hash */
1549 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1550
1551 /* Initiator Protocol Key */
1552 if (pi) {
1553 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1554 wpabuf_put_le16(msg, wpabuf_len(pi));
1555 wpabuf_put_buf(msg, pi);
1556 }
1557
1558 /* Channel */
1559 if (neg_freq > 0) {
1560 u8 op_class, channel;
1561
1562 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1563 &channel) ==
1564 NUM_HOSTAPD_MODES) {
1565 wpa_printf(MSG_INFO,
1566 "DPP: Unsupported negotiation frequency request: %d",
1567 neg_freq);
1568 wpabuf_free(msg);
1569 return NULL;
1570 }
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);
1575 }
1576
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;
1581 }
1582 #endif /* CONFIG_TESTING_OPTIONS */
1583
1584 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1585 pos = clear;
1586
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");
1590 goto skip_i_nonce;
1591 }
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);
1595 pos += 2;
1596 WPA_PUT_LE16(pos, nonce_len - 1);
1597 pos += 2;
1598 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1599 pos += nonce_len - 1;
1600 goto skip_i_nonce;
1601 }
1602 #endif /* CONFIG_TESTING_OPTIONS */
1603
1604 /* I-nonce */
1605 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1606 pos += 2;
1607 WPA_PUT_LE16(pos, nonce_len);
1608 pos += 2;
1609 os_memcpy(pos, auth->i_nonce, nonce_len);
1610 pos += nonce_len;
1611
1612 #ifdef CONFIG_TESTING_OPTIONS
1613 skip_i_nonce:
1614 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1615 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1616 goto skip_i_capab;
1617 }
1618 #endif /* CONFIG_TESTING_OPTIONS */
1619
1620 /* I-capabilities */
1621 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1622 pos += 2;
1623 WPA_PUT_LE16(pos, 1);
1624 pos += 2;
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");
1630 pos[-1] = 0;
1631 }
1632 skip_i_capab:
1633 #endif /* CONFIG_TESTING_OPTIONS */
1634
1635 attr_end = wpabuf_put(msg, 0);
1636
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]);
1641
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]);
1646
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) {
1651 wpabuf_free(msg);
1652 return NULL;
1653 }
1654 siv_len += AES_BLOCK_SIZE;
1655 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1656 wrapped_data, siv_len);
1657
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);
1661
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);
1666 }
1667 skip_wrapped_data:
1668 #endif /* CONFIG_TESTING_OPTIONS */
1669
1670 wpa_hexdump_buf(MSG_DEBUG,
1671 "DPP: Authentication Request frame attributes", msg);
1672
1673 return msg;
1674 }
1675
1676
1677 static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1678 enum dpp_status_error status,
1679 const struct wpabuf *pr,
1680 size_t nonce_len,
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,
1686 const u8 *siv_key)
1687 {
1688 struct wpabuf *msg;
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];
1693 const u8 *addr[2];
1694 size_t len[2], siv_len, attr_len;
1695 u8 *attr_start, *attr_end, *pos;
1696
1697 auth->waiting_auth_conf = 1;
1698 auth->auth_resp_tries = 0;
1699
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)
1705 attr_len += 5;
1706 #endif /* CONFIG_TESTING_OPTIONS */
1707 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1708 if (!msg)
1709 return NULL;
1710
1711 attr_start = wpabuf_put(msg, 0);
1712
1713 /* DPP Status */
1714 if (status != 255)
1715 dpp_build_attr_status(msg, status);
1716
1717 /* Responder Bootstrapping Key Hash */
1718 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1719
1720 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1721 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1722
1723 /* Responder Protocol Key */
1724 if (pr) {
1725 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1726 wpabuf_put_le16(msg, wpabuf_len(pr));
1727 wpabuf_put_buf(msg, pr);
1728 }
1729
1730 attr_end = wpabuf_put(msg, 0);
1731
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;
1736 }
1737 #endif /* CONFIG_TESTING_OPTIONS */
1738
1739 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1740 pos = clear;
1741
1742 if (r_nonce) {
1743 /* R-nonce */
1744 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1745 pos += 2;
1746 WPA_PUT_LE16(pos, nonce_len);
1747 pos += 2;
1748 os_memcpy(pos, r_nonce, nonce_len);
1749 pos += nonce_len;
1750 }
1751
1752 if (i_nonce) {
1753 /* I-nonce */
1754 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1755 pos += 2;
1756 WPA_PUT_LE16(pos, nonce_len);
1757 pos += 2;
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;
1763 }
1764 #endif /* CONFIG_TESTING_OPTIONS */
1765 pos += nonce_len;
1766 }
1767
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");
1771 goto skip_r_capab;
1772 }
1773 #endif /* CONFIG_TESTING_OPTIONS */
1774
1775 /* R-capabilities */
1776 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1777 pos += 2;
1778 WPA_PUT_LE16(pos, 1);
1779 pos += 2;
1780 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1781 DPP_CAPAB_ENROLLEE;
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");
1786 pos[-1] = 0;
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))
1792 pos[-1] = 0;
1793 else
1794 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
1795 DPP_CAPAB_CONFIGURATOR;
1796 }
1797 skip_r_capab:
1798 #endif /* CONFIG_TESTING_OPTIONS */
1799
1800 if (wrapped_r_auth) {
1801 /* {R-auth}ke */
1802 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1803 pos += 2;
1804 WPA_PUT_LE16(pos, wrapped_r_auth_len);
1805 pos += 2;
1806 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1807 pos += wrapped_r_auth_len;
1808 }
1809
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]);
1814
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]);
1819
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) {
1824 wpabuf_free(msg);
1825 return NULL;
1826 }
1827 siv_len += AES_BLOCK_SIZE;
1828 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1829 wrapped_data, siv_len);
1830
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);
1834
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);
1839 }
1840 skip_wrapped_data:
1841 #endif /* CONFIG_TESTING_OPTIONS */
1842
1843 wpa_hexdump_buf(MSG_DEBUG,
1844 "DPP: Authentication Response frame attributes", msg);
1845 return msg;
1846 }
1847
1848
1849 static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
1850 u16 num_modes, unsigned int freq)
1851 {
1852 u16 m;
1853 int c, flag;
1854
1855 if (!own_modes || !num_modes)
1856 return 1;
1857
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 !=
1861 freq)
1862 continue;
1863 flag = own_modes[m].channels[c].flag;
1864 if (!(flag & (HOSTAPD_CHAN_DISABLED |
1865 HOSTAPD_CHAN_NO_IR |
1866 HOSTAPD_CHAN_RADAR)))
1867 return 1;
1868 }
1869 }
1870
1871 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
1872 return 0;
1873 }
1874
1875
1876 static int freq_included(const unsigned int freqs[], unsigned int num,
1877 unsigned int freq)
1878 {
1879 while (num > 0) {
1880 if (freqs[--num] == freq)
1881 return 1;
1882 }
1883 return 0;
1884 }
1885
1886
1887 static void freq_to_start(unsigned int freqs[], unsigned int num,
1888 unsigned int freq)
1889 {
1890 unsigned int i;
1891
1892 for (i = 0; i < num; i++) {
1893 if (freqs[i] == freq)
1894 break;
1895 }
1896 if (i == 0 || i >= num)
1897 return;
1898 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
1899 freqs[0] = freq;
1900 }
1901
1902
1903 static int dpp_channel_intersect(struct dpp_authentication *auth,
1904 struct hostapd_hw_modes *own_modes,
1905 u16 num_modes)
1906 {
1907 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
1908 unsigned int i, freq;
1909
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))
1913 continue;
1914 if (dpp_channel_ok_init(own_modes, num_modes, freq))
1915 auth->freq[auth->num_freq++] = freq;
1916 }
1917 if (!auth->num_freq) {
1918 wpa_printf(MSG_INFO,
1919 "DPP: No available channels for initiating DPP Authentication");
1920 return -1;
1921 }
1922 auth->curr_freq = auth->freq[0];
1923 return 0;
1924 }
1925
1926
1927 static int dpp_channel_local_list(struct dpp_authentication *auth,
1928 struct hostapd_hw_modes *own_modes,
1929 u16 num_modes)
1930 {
1931 u16 m;
1932 int c, flag;
1933 unsigned int freq;
1934
1935 auth->num_freq = 0;
1936
1937 if (!own_modes || !num_modes) {
1938 auth->freq[0] = 2412;
1939 auth->freq[1] = 2437;
1940 auth->freq[2] = 2462;
1941 auth->num_freq = 3;
1942 return 0;
1943 }
1944
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))
1952 continue;
1953 if (freq_included(auth->freq, auth->num_freq, freq))
1954 continue;
1955 auth->freq[auth->num_freq++] = freq;
1956 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
1957 m = num_modes;
1958 break;
1959 }
1960 }
1961 }
1962
1963 return auth->num_freq == 0 ? -1 : 0;
1964 }
1965
1966
1967 static int dpp_prepare_channel_list(struct dpp_authentication *auth,
1968 struct hostapd_hw_modes *own_modes,
1969 u16 num_modes)
1970 {
1971 int res;
1972 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
1973 unsigned int i;
1974
1975 if (auth->peer_bi->num_freq > 0)
1976 res = dpp_channel_intersect(auth, own_modes, num_modes);
1977 else
1978 res = dpp_channel_local_list(auth, own_modes, num_modes);
1979 if (res < 0)
1980 return res;
1981
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);
1987
1988 auth->freq_idx = 0;
1989 auth->curr_freq = auth->freq[0];
1990
1991 pos = freqs;
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))
1996 break;
1997 pos += res;
1998 }
1999 *pos = '\0';
2000 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
2001 freqs);
2002
2003 return 0;
2004 }
2005
2006
2007 static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
2008 {
2009 struct dpp_bootstrap_info *bi;
2010 char *pk = NULL;
2011 size_t len;
2012
2013 if (auth->own_bi)
2014 return 0; /* already generated */
2015
2016 bi = os_zalloc(sizeof(*bi));
2017 if (!bi)
2018 return -1;
2019 bi->type = DPP_BOOTSTRAP_QR_CODE;
2020 pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
2021 if (!pk)
2022 goto fail;
2023
2024 len = 4; /* "DPP:" */
2025 len += 4 + os_strlen(pk);
2026 bi->uri = os_malloc(len + 1);
2027 if (!bi->uri)
2028 goto fail;
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",
2032 bi->uri);
2033
2034 auth->tmp_own_bi = auth->own_bi = bi;
2035
2036 os_free(pk);
2037
2038 return 0;
2039 fail:
2040 os_free(pk);
2041 dpp_bootstrap_info_free(bi);
2042 return -1;
2043 }
2044
2045
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,
2052 u16 num_modes)
2053 {
2054 struct dpp_authentication *auth;
2055 size_t nonce_len;
2056 EVP_PKEY_CTX *ctx = NULL;
2057 size_t secret_len;
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 */
2063
2064 auth = os_zalloc(sizeof(*auth));
2065 if (!auth)
2066 return NULL;
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;
2075
2076 if (dpp_autogen_bootstrap_key(auth) < 0 ||
2077 dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
2078 goto fail;
2079
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);
2085 } else {
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");
2090 goto fail;
2091 }
2092 }
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");
2097 goto fail;
2098 }
2099 #endif /* CONFIG_TESTING_OPTIONS */
2100 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2101
2102 #ifdef CONFIG_TESTING_OPTIONS
2103 if (dpp_protocol_key_override_len) {
2104 const struct dpp_curve_params *tmp_curve;
2105
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);
2111 } else {
2112 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2113 }
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)
2118 goto fail;
2119
2120 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2121 if (!pi)
2122 goto fail;
2123
2124 /* ECDH: M = pI * BR */
2125 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2126 if (!ctx ||
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));
2135 goto fail;
2136 }
2137 auth->secret_len = secret_len;
2138 EVP_PKEY_CTX_free(ctx);
2139 ctx = NULL;
2140
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;
2144
2145 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2146 auth->curve->hash_len) < 0)
2147 goto fail;
2148
2149 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2150 i_pubkey_hash = auth->own_bi->pubkey_hash;
2151
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");
2173 wpabuf_free(pi);
2174 pi = NULL;
2175 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2176 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2177 wpabuf_free(pi);
2178 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2179 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2180 goto fail;
2181 }
2182 #endif /* CONFIG_TESTING_OPTIONS */
2183
2184 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
2185 i_pubkey_hash, neg_freq);
2186 if (!auth->req_msg)
2187 goto fail;
2188
2189 out:
2190 wpabuf_free(pi);
2191 EVP_PKEY_CTX_free(ctx);
2192 return auth;
2193 fail:
2194 dpp_auth_deinit(auth);
2195 auth = NULL;
2196 goto out;
2197 }
2198
2199
2200 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2201 const char *json)
2202 {
2203 size_t nonce_len;
2204 size_t json_len, clear_len;
2205 struct wpabuf *clear = NULL, *msg = NULL;
2206 u8 *wrapped;
2207 size_t attr_len;
2208
2209 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2210
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");
2214 goto fail;
2215 }
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);
2219
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)
2226 attr_len += 5;
2227 #endif /* CONFIG_TESTING_OPTIONS */
2228 msg = wpabuf_alloc(attr_len);
2229 if (!clear || !msg)
2230 goto fail;
2231
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");
2235 goto skip_e_nonce;
2236 }
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);
2242 goto skip_e_nonce;
2243 }
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;
2247 }
2248 #endif /* CONFIG_TESTING_OPTIONS */
2249
2250 /* E-nonce */
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);
2254
2255 #ifdef CONFIG_TESTING_OPTIONS
2256 skip_e_nonce:
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;
2260 }
2261 #endif /* CONFIG_TESTING_OPTIONS */
2262
2263 /* configAttrib */
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);
2267
2268 #ifdef CONFIG_TESTING_OPTIONS
2269 skip_conf_attr_obj:
2270 #endif /* CONFIG_TESTING_OPTIONS */
2271
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);
2275
2276 /* No AES-SIV AD */
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)
2281 goto fail;
2282 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2283 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2284
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);
2289 }
2290 skip_wrapped_data:
2291 #endif /* CONFIG_TESTING_OPTIONS */
2292
2293 wpa_hexdump_buf(MSG_DEBUG,
2294 "DPP: Configuration Request frame attributes", msg);
2295 wpabuf_free(clear);
2296 return msg;
2297
2298 fail:
2299 wpabuf_free(clear);
2300 wpabuf_free(msg);
2301 return NULL;
2302 }
2303
2304
2305 static void dpp_auth_success(struct dpp_authentication *auth)
2306 {
2307 wpa_printf(MSG_DEBUG,
2308 "DPP: Authentication success - clear temporary keys");
2309 os_memset(auth->Mx, 0, sizeof(auth->Mx));
2310 auth->Mx_len = 0;
2311 os_memset(auth->Nx, 0, sizeof(auth->Nx));
2312 auth->Nx_len = 0;
2313 os_memset(auth->Lx, 0, sizeof(auth->Lx));
2314 auth->Lx_len = 0;
2315 os_memset(auth->k1, 0, sizeof(auth->k1));
2316 os_memset(auth->k2, 0, sizeof(auth->k2));
2317
2318 auth->auth_success = 1;
2319 }
2320
2321
2322 static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2323 {
2324 struct wpabuf *pix, *prx, *bix, *brx;
2325 const u8 *addr[7];
2326 size_t len[7];
2327 size_t i, num_elem = 0;
2328 size_t nonce_len;
2329 u8 zero = 0;
2330 int res = -1;
2331
2332 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2333 nonce_len = auth->curve->nonce_len;
2334
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);
2338 if (auth->own_bi)
2339 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2340 else
2341 bix = NULL;
2342 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2343 } else {
2344 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2345 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2346 if (auth->peer_bi)
2347 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2348 else
2349 bix = NULL;
2350 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2351 }
2352 if (!pix || !prx || !brx)
2353 goto fail;
2354
2355 addr[num_elem] = auth->i_nonce;
2356 len[num_elem] = nonce_len;
2357 num_elem++;
2358
2359 addr[num_elem] = auth->r_nonce;
2360 len[num_elem] = nonce_len;
2361 num_elem++;
2362
2363 addr[num_elem] = wpabuf_head(pix);
2364 len[num_elem] = wpabuf_len(pix) / 2;
2365 num_elem++;
2366
2367 addr[num_elem] = wpabuf_head(prx);
2368 len[num_elem] = wpabuf_len(prx) / 2;
2369 num_elem++;
2370
2371 if (bix) {
2372 addr[num_elem] = wpabuf_head(bix);
2373 len[num_elem] = wpabuf_len(bix) / 2;
2374 num_elem++;
2375 }
2376
2377 addr[num_elem] = wpabuf_head(brx);
2378 len[num_elem] = wpabuf_len(brx) / 2;
2379 num_elem++;
2380
2381 addr[num_elem] = &zero;
2382 len[num_elem] = 1;
2383 num_elem++;
2384
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);
2389 if (res == 0)
2390 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2391 auth->curve->hash_len);
2392 fail:
2393 wpabuf_free(pix);
2394 wpabuf_free(prx);
2395 wpabuf_free(bix);
2396 wpabuf_free(brx);
2397 return res;
2398 }
2399
2400
2401 static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2402 {
2403 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2404 const u8 *addr[7];
2405 size_t len[7];
2406 size_t i, num_elem = 0;
2407 size_t nonce_len;
2408 u8 one = 1;
2409 int res = -1;
2410
2411 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2412 nonce_len = auth->curve->nonce_len;
2413
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);
2417 if (auth->own_bi)
2418 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2419 else
2420 bix = NULL;
2421 if (!auth->peer_bi)
2422 goto fail;
2423 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2424 } else {
2425 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2426 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2427 if (auth->peer_bi)
2428 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2429 else
2430 bix = NULL;
2431 if (!auth->own_bi)
2432 goto fail;
2433 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2434 }
2435 if (!pix || !prx || !brx)
2436 goto fail;
2437
2438 addr[num_elem] = auth->r_nonce;
2439 len[num_elem] = nonce_len;
2440 num_elem++;
2441
2442 addr[num_elem] = auth->i_nonce;
2443 len[num_elem] = nonce_len;
2444 num_elem++;
2445
2446 addr[num_elem] = wpabuf_head(prx);
2447 len[num_elem] = wpabuf_len(prx) / 2;
2448 num_elem++;
2449
2450 addr[num_elem] = wpabuf_head(pix);
2451 len[num_elem] = wpabuf_len(pix) / 2;
2452 num_elem++;
2453
2454 addr[num_elem] = wpabuf_head(brx);
2455 len[num_elem] = wpabuf_len(brx) / 2;
2456 num_elem++;
2457
2458 if (bix) {
2459 addr[num_elem] = wpabuf_head(bix);
2460 len[num_elem] = wpabuf_len(bix) / 2;
2461 num_elem++;
2462 }
2463
2464 addr[num_elem] = &one;
2465 len[num_elem] = 1;
2466 num_elem++;
2467
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);
2472 if (res == 0)
2473 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2474 auth->curve->hash_len);
2475 fail:
2476 wpabuf_free(pix);
2477 wpabuf_free(prx);
2478 wpabuf_free(bix);
2479 wpabuf_free(brx);
2480 return res;
2481 }
2482
2483
2484 static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2485 {
2486 const EC_GROUP *group;
2487 EC_POINT *l = NULL;
2488 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2489 const EC_POINT *BI_point;
2490 BN_CTX *bnctx;
2491 BIGNUM *lx, *sum, *q;
2492 const BIGNUM *bR_bn, *pR_bn;
2493 int ret = -1;
2494
2495 /* L = ((bR + pR) modulo q) * BI */
2496
2497 bnctx = BN_CTX_new();
2498 sum = BN_new();
2499 q = BN_new();
2500 lx = BN_new();
2501 if (!bnctx || !sum || !q || !lx)
2502 goto fail;
2503 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2504 if (!BI)
2505 goto fail;
2506 BI_point = EC_KEY_get0_public_key(BI);
2507 group = EC_KEY_get0_group(BI);
2508 if (!group)
2509 goto fail;
2510
2511 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2512 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2513 if (!bR || !pR)
2514 goto fail;
2515 bR_bn = EC_KEY_get0_private_key(bR);
2516 pR_bn = EC_KEY_get0_private_key(pR);
2517 if (!bR_bn || !pR_bn)
2518 goto fail;
2519 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2520 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2521 goto fail;
2522 l = EC_POINT_new(group);
2523 if (!l ||
2524 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2525 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2526 bnctx) != 1) {
2527 wpa_printf(MSG_ERROR,
2528 "OpenSSL: failed: %s",
2529 ERR_error_string(ERR_get_error(), NULL));
2530 goto fail;
2531 }
2532
2533 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2534 goto fail;
2535 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2536 auth->Lx_len = auth->secret_len;
2537 ret = 0;
2538 fail:
2539 EC_POINT_clear_free(l);
2540 EC_KEY_free(BI);
2541 EC_KEY_free(bR);
2542 EC_KEY_free(pR);
2543 BN_clear_free(lx);
2544 BN_clear_free(sum);
2545 BN_free(q);
2546 BN_CTX_free(bnctx);
2547 return ret;
2548 }
2549
2550
2551 static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2552 {
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;
2557 BN_CTX *bnctx;
2558 BIGNUM *lx;
2559 const BIGNUM *bI_bn;
2560 int ret = -1;
2561
2562 /* L = bI * (BR + PR) */
2563
2564 bnctx = BN_CTX_new();
2565 lx = BN_new();
2566 if (!bnctx || !lx)
2567 goto fail;
2568 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2569 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
2570 if (!BR || !PR)
2571 goto fail;
2572 BR_point = EC_KEY_get0_public_key(BR);
2573 PR_point = EC_KEY_get0_public_key(PR);
2574
2575 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2576 if (!bI)
2577 goto fail;
2578 group = EC_KEY_get0_group(bI);
2579 bI_bn = EC_KEY_get0_private_key(bI);
2580 if (!group || !bI_bn)
2581 goto fail;
2582 sum = EC_POINT_new(group);
2583 l = EC_POINT_new(group);
2584 if (!sum || !l ||
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,
2588 bnctx) != 1) {
2589 wpa_printf(MSG_ERROR,
2590 "OpenSSL: failed: %s",
2591 ERR_error_string(ERR_get_error(), NULL));
2592 goto fail;
2593 }
2594
2595 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2596 goto fail;
2597 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2598 auth->Lx_len = auth->secret_len;
2599 ret = 0;
2600 fail:
2601 EC_POINT_clear_free(l);
2602 EC_KEY_free(bI);
2603 EC_KEY_free(BR);
2604 EC_KEY_free(PR);
2605 BN_clear_free(lx);
2606 BN_CTX_free(bnctx);
2607 return ret;
2608 }
2609
2610
2611 static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
2612 {
2613 size_t nonce_len;
2614 EVP_PKEY_CTX *ctx = NULL;
2615 size_t secret_len;
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;
2620 int ret = -1;
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 */
2626
2627 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2628 if (!auth->own_bi)
2629 return -1;
2630
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);
2636 } else {
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");
2641 goto fail;
2642 }
2643 }
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");
2648 goto fail;
2649 }
2650 #endif /* CONFIG_TESTING_OPTIONS */
2651 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
2652
2653 #ifdef CONFIG_TESTING_OPTIONS
2654 if (dpp_protocol_key_override_len) {
2655 const struct dpp_curve_params *tmp_curve;
2656
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);
2662 } else {
2663 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2664 }
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)
2669 goto fail;
2670
2671 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2672 if (!pr)
2673 goto fail;
2674
2675 /* ECDH: N = pR * PI */
2676 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2677 if (!ctx ||
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));
2686 goto fail;
2687 }
2688 EVP_PKEY_CTX_free(ctx);
2689 ctx = NULL;
2690
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;
2694
2695 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2696 auth->curve->hash_len) < 0)
2697 goto fail;
2698
2699 if (auth->own_bi && auth->peer_bi) {
2700 /* Mutual authentication */
2701 if (dpp_auth_derive_l_responder(auth) < 0)
2702 goto fail;
2703 }
2704
2705 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2706 goto fail;
2707
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)
2712 goto fail;
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;
2717 }
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)
2722 goto fail;
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;
2727
2728 r_pubkey_hash = auth->own_bi->pubkey_hash;
2729 if (auth->peer_bi)
2730 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2731 else
2732 i_pubkey_hash = NULL;
2733
2734 i_nonce = auth->i_nonce;
2735 r_nonce = auth->r_nonce;
2736
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");
2755 if (i_pubkey_hash)
2756 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2757 else
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");
2763 wpabuf_free(pr);
2764 pr = NULL;
2765 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
2766 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
2767 wpabuf_free(pr);
2768 pr = wpabuf_alloc(2 * auth->curve->prime_len);
2769 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
2770 goto fail;
2771 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
2772 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
2773 w_r_auth = NULL;
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");
2777 status = 255;
2778 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
2779 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2780 status = 254;
2781 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
2782 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
2783 r_nonce = NULL;
2784 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2785 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2786 i_nonce = NULL;
2787 }
2788 #endif /* CONFIG_TESTING_OPTIONS */
2789
2790 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
2791 r_pubkey_hash, i_pubkey_hash,
2792 r_nonce, i_nonce,
2793 w_r_auth, wrapped_r_auth_len,
2794 auth->k2);
2795 if (!msg)
2796 goto fail;
2797 wpabuf_free(auth->resp_msg);
2798 auth->resp_msg = msg;
2799 ret = 0;
2800 fail:
2801 wpabuf_free(pr);
2802 return ret;
2803 }
2804
2805
2806 static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
2807 enum dpp_status_error status)
2808 {
2809 struct wpabuf *msg;
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 */
2814
2815 if (!auth->own_bi)
2816 return -1;
2817 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2818
2819 r_pubkey_hash = auth->own_bi->pubkey_hash;
2820 if (auth->peer_bi)
2821 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2822 else
2823 i_pubkey_hash = NULL;
2824
2825 i_nonce = auth->i_nonce;
2826
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");
2845 if (i_pubkey_hash)
2846 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2847 else
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");
2853 status = -1;
2854 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2855 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2856 i_nonce = NULL;
2857 }
2858 #endif /* CONFIG_TESTING_OPTIONS */
2859
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);
2863 if (!msg)
2864 return -1;
2865 wpabuf_free(auth->resp_msg);
2866 auth->resp_msg = msg;
2867 return 0;
2868 }
2869
2870
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,
2876 size_t attr_len)
2877 {
2878 EVP_PKEY *pi = NULL;
2879 EVP_PKEY_CTX *ctx = NULL;
2880 size_t secret_len;
2881 const u8 *addr[2];
2882 size_t len[2];
2883 u8 *unwrapped = NULL;
2884 size_t unwrapped_len = 0;
2885 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
2886 *channel;
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;
2890
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");
2895 return NULL;
2896 }
2897 #endif /* CONFIG_TESTING_OPTIONS */
2898
2899 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2900 &wrapped_data_len);
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");
2904 return NULL;
2905 }
2906 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
2907 wrapped_data, wrapped_data_len);
2908 attr_len = wrapped_data - 4 - attr_start;
2909
2910 auth = os_zalloc(sizeof(*auth));
2911 if (!auth)
2912 goto fail;
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;
2918
2919 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
2920 &channel_len);
2921 if (channel) {
2922 int neg_freq;
2923
2924 if (channel_len < 2) {
2925 dpp_auth_fail(auth, "Too short Channel attribute");
2926 goto fail;
2927 }
2928
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);
2933 if (neg_freq < 0) {
2934 dpp_auth_fail(auth,
2935 "Unsupported Channel attribute value");
2936 goto fail;
2937 }
2938
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",
2942 freq, neg_freq);
2943 auth->curr_freq = neg_freq;
2944 }
2945 }
2946
2947 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
2948 &i_proto_len);
2949 if (!i_proto) {
2950 dpp_auth_fail(auth,
2951 "Missing required Initiator Protocol Key attribute");
2952 goto fail;
2953 }
2954 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
2955 i_proto, i_proto_len);
2956
2957 /* M = bR * PI */
2958 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
2959 if (!pi) {
2960 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
2961 goto fail;
2962 }
2963 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
2964
2965 ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
2966 if (!ctx ||
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");
2976 goto fail;
2977 }
2978 auth->secret_len = secret_len;
2979 EVP_PKEY_CTX_free(ctx);
2980 ctx = NULL;
2981
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;
2985
2986 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2987 auth->curve->hash_len) < 0)
2988 goto fail;
2989
2990 addr[0] = hdr;
2991 len[0] = DPP_HDR_LEN;
2992 addr[1] = attr_start;
2993 len[1] = attr_len;
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);
3000 if (!unwrapped)
3001 goto fail;
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");
3006 goto fail;
3007 }
3008 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3009 unwrapped, unwrapped_len);
3010
3011 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3012 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3013 goto fail;
3014 }
3015
3016 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3017 &i_nonce_len);
3018 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3019 dpp_auth_fail(auth, "Missing or invalid I-nonce");
3020 goto fail;
3021 }
3022 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3023 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
3024
3025 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
3026 DPP_ATTR_I_CAPABILITIES,
3027 &i_capab_len);
3028 if (!i_capab || i_capab_len < 1) {
3029 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
3030 goto fail;
3031 }
3032 auth->i_capab = i_capab[0];
3033 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
3034
3035 bin_clear_free(unwrapped, unwrapped_len);
3036 unwrapped = NULL;
3037
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;
3044 }
3045 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3046 auth->configurator = 1;
3047 break;
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;
3053 }
3054 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3055 auth->configurator = 0;
3056 break;
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;
3064 } else {
3065 wpa_printf(MSG_DEBUG,
3066 "DPP: Local policy does not allow Configurator/Enrollee role");
3067 goto not_compatible;
3068 }
3069 break;
3070 default:
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);
3075 goto fail;
3076 }
3077
3078 auth->peer_protocol_key = pi;
3079 pi = NULL;
3080 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
3081 char hex[SHA256_MAC_LEN * 2 + 1];
3082
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)
3087 goto fail;
3088 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3089 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3090 &i_bootstrap_len);
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,
3096 i_bootstrap_len);
3097 } else {
3098 hex[0] = '\0';
3099 }
3100
3101 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
3102 "%s", hex);
3103 return auth;
3104 }
3105 if (dpp_auth_build_resp_ok(auth) < 0)
3106 goto fail;
3107
3108 return auth;
3109
3110 not_compatible:
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;
3115 else
3116 auth->configurator = 0;
3117 auth->peer_protocol_key = pi;
3118 pi = NULL;
3119 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
3120 goto fail;
3121
3122 auth->remove_on_tx_status = 1;
3123 return auth;
3124 fail:
3125 bin_clear_free(unwrapped, unwrapped_len);
3126 EVP_PKEY_free(pi);
3127 EVP_PKEY_CTX_free(ctx);
3128 dpp_auth_deinit(auth);
3129 return NULL;
3130 }
3131
3132
3133 int dpp_notify_new_qr_code(struct dpp_authentication *auth,
3134 struct dpp_bootstrap_info *peer_bi)
3135 {
3136 if (!auth || !auth->response_pending ||
3137 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
3138 SHA256_MAC_LEN) != 0)
3139 return 0;
3140
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;
3145
3146 if (dpp_auth_build_resp_ok(auth) < 0)
3147 return -1;
3148
3149 return 1;
3150 }
3151
3152
3153 static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
3154 enum dpp_status_error status)
3155 {
3156 struct wpabuf *msg;
3157 u8 i_auth[4 + DPP_MAX_HASH_LEN];
3158 size_t i_auth_len;
3159 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3160 size_t r_nonce_len;
3161 const u8 *addr[2];
3162 size_t len[2], attr_len;
3163 u8 *wrapped_i_auth;
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 */
3170
3171 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3172
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)
3180 attr_len += 5;
3181 #endif /* CONFIG_TESTING_OPTIONS */
3182 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
3183 if (!msg)
3184 goto fail;
3185
3186 attr_start = wpabuf_put(msg, 0);
3187
3188 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3189 if (auth->own_bi)
3190 i_pubkey_hash = auth->own_bi->pubkey_hash;
3191 else
3192 i_pubkey_hash = NULL;
3193
3194 #ifdef CONFIG_TESTING_OPTIONS
3195 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3196 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3197 goto skip_status;
3198 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3199 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3200 status = 254;
3201 }
3202 #endif /* CONFIG_TESTING_OPTIONS */
3203
3204 /* DPP Status */
3205 dpp_build_attr_status(msg, status);
3206
3207 #ifdef CONFIG_TESTING_OPTIONS
3208 skip_status:
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");
3226 if (i_pubkey_hash)
3227 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3228 else
3229 os_memset(test_hash, 0, SHA256_MAC_LEN);
3230 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3231 i_pubkey_hash = test_hash;
3232 }
3233 #endif /* CONFIG_TESTING_OPTIONS */
3234
3235 /* Responder Bootstrapping Key Hash */
3236 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
3237
3238 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3239 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
3240
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)
3245 i_auth_len = 0;
3246 #endif /* CONFIG_TESTING_OPTIONS */
3247
3248 attr_end = wpabuf_put(msg, 0);
3249
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]);
3254
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]);
3259
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);
3265
3266 #ifdef CONFIG_TESTING_OPTIONS
3267 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3268 goto skip_i_auth;
3269 #endif /* CONFIG_TESTING_OPTIONS */
3270
3271 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3272 * 1) */
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)
3276 goto fail;
3277
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;
3282 }
3283 skip_i_auth:
3284 #endif /* CONFIG_TESTING_OPTIONS */
3285 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3286 i_auth, i_auth_len,
3287 2, addr, len, wrapped_i_auth) < 0)
3288 goto fail;
3289 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3290 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3291 } else {
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);
3296
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);
3300
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)
3304 goto fail;
3305 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3306 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3307 }
3308
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);
3313 }
3314 skip_wrapped_data:
3315 #endif /* CONFIG_TESTING_OPTIONS */
3316
3317 wpa_hexdump_buf(MSG_DEBUG,
3318 "DPP: Authentication Confirmation frame attributes",
3319 msg);
3320 if (status == DPP_STATUS_OK)
3321 dpp_auth_success(auth);
3322
3323 return msg;
3324
3325 fail:
3326 wpabuf_free(msg);
3327 return NULL;
3328 }
3329
3330
3331 static void
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)
3336 {
3337 const u8 *addr[2];
3338 size_t len[2];
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;
3343
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");
3350 } else {
3351 wpa_printf(MSG_DEBUG,
3352 "DPP: Responder reported failure (status %d)",
3353 status);
3354 dpp_auth_fail(auth, "Responder reported failure");
3355 return;
3356 }
3357
3358 addr[0] = hdr;
3359 len[0] = DPP_HDR_LEN;
3360 addr[1] = attr_start;
3361 len[1] = attr_len;
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);
3368 if (!unwrapped)
3369 goto fail;
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");
3374 goto fail;
3375 }
3376 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3377 unwrapped, unwrapped_len);
3378
3379 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3380 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3381 goto fail;
3382 }
3383
3384 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3385 &i_nonce_len);
3386 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3387 dpp_auth_fail(auth, "Missing or invalid I-nonce");
3388 goto fail;
3389 }
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");
3393 goto fail;
3394 }
3395
3396 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3397 DPP_ATTR_R_CAPABILITIES,
3398 &r_capab_len);
3399 if (!r_capab || r_capab_len < 1) {
3400 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
3401 goto fail;
3402 }
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;
3410
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",
3415 role);
3416 } else {
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 : "");
3422 }
3423 }
3424 fail:
3425 bin_clear_free(unwrapped, unwrapped_len);
3426 }
3427
3428
3429 struct wpabuf *
3430 dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3431 const u8 *attr_start, size_t attr_len)
3432 {
3433 EVP_PKEY *pr;
3434 EVP_PKEY_CTX *ctx = NULL;
3435 size_t secret_len;
3436 const u8 *addr[2];
3437 size_t len[2];
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];
3446 u8 role;
3447
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");
3452 return NULL;
3453 }
3454 #endif /* CONFIG_TESTING_OPTIONS */
3455
3456 if (!auth->initiator) {
3457 dpp_auth_fail(auth, "Unexpected Authentication Response");
3458 return NULL;
3459 }
3460
3461 auth->waiting_auth_resp = 0;
3462
3463 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3464 &wrapped_data_len);
3465 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3466 dpp_auth_fail(auth,
3467 "Missing or invalid required Wrapped Data attribute");
3468 return NULL;
3469 }
3470 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3471 wrapped_data, wrapped_data_len);
3472
3473 attr_len = wrapped_data - 4 - attr_start;
3474
3475 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3476 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3477 &r_bootstrap_len);
3478 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3479 dpp_auth_fail(auth,
3480 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3481 return NULL;
3482 }
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) {
3487 dpp_auth_fail(auth,
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);
3492 return NULL;
3493 }
3494
3495 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3496 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3497 &i_bootstrap_len);
3498 if (i_bootstrap) {
3499 if (i_bootstrap_len != SHA256_MAC_LEN) {
3500 dpp_auth_fail(auth,
3501 "Invalid Initiator Bootstrapping Key Hash attribute");
3502 return NULL;
3503 }
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) {
3510 dpp_auth_fail(auth,
3511 "Initiator Bootstrapping Key Hash attribute did not match");
3512 return NULL;
3513 }
3514 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3515 /* PKEX bootstrapping mandates use of mutual authentication */
3516 dpp_auth_fail(auth,
3517 "Missing Initiator Bootstrapping Key Hash attribute");
3518 return NULL;
3519 }
3520
3521 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3522 &status_len);
3523 if (!status || status_len < 1) {
3524 dpp_auth_fail(auth,
3525 "Missing or invalid required DPP Status attribute");
3526 return NULL;
3527 }
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]);
3534 return NULL;
3535 }
3536
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;
3541 }
3542
3543 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
3544 auth->own_bi != NULL);
3545
3546 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3547 &r_proto_len);
3548 if (!r_proto) {
3549 dpp_auth_fail(auth,
3550 "Missing required Responder Protocol Key attribute");
3551 return NULL;
3552 }
3553 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3554 r_proto, r_proto_len);
3555
3556 /* N = pI * PR */
3557 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3558 if (!pr) {
3559 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
3560 return NULL;
3561 }
3562 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3563
3564 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
3565 if (!ctx ||
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");
3575 goto fail;
3576 }
3577 EVP_PKEY_CTX_free(ctx);
3578 ctx = NULL;
3579 auth->peer_protocol_key = pr;
3580 pr = NULL;
3581
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;
3585
3586 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3587 auth->curve->hash_len) < 0)
3588 goto fail;
3589
3590 addr[0] = hdr;
3591 len[0] = DPP_HDR_LEN;
3592 addr[1] = attr_start;
3593 len[1] = attr_len;
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);
3600 if (!unwrapped)
3601 goto fail;
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");
3606 goto fail;
3607 }
3608 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3609 unwrapped, unwrapped_len);
3610
3611 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3612 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3613 goto fail;
3614 }
3615
3616 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3617 &r_nonce_len);
3618 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3619 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3620 goto fail;
3621 }
3622 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
3623 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
3624
3625 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3626 &i_nonce_len);
3627 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3628 dpp_auth_fail(auth, "Missing or invalid I-nonce");
3629 goto fail;
3630 }
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");
3634 goto fail;
3635 }
3636
3637 if (auth->own_bi && auth->peer_bi) {
3638 /* Mutual authentication */
3639 if (dpp_auth_derive_l_initiator(auth) < 0)
3640 goto fail;
3641 }
3642
3643 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3644 DPP_ATTR_R_CAPABILITIES,
3645 &r_capab_len);
3646 if (!r_capab || r_capab_len < 1) {
3647 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
3648 goto fail;
3649 }
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",
3666 role);
3667 if (role != DPP_CAPAB_ENROLLEE &&
3668 role != DPP_CAPAB_CONFIGURATOR)
3669 goto fail;
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);
3673 }
3674
3675 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
3676 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
3677 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
3678 dpp_auth_fail(auth,
3679 "Missing or invalid Secondary Wrapped Data");
3680 goto fail;
3681 }
3682
3683 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3684 wrapped2, wrapped2_len);
3685
3686 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3687 goto fail;
3688
3689 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
3690 unwrapped2 = os_malloc(unwrapped2_len);
3691 if (!unwrapped2)
3692 goto fail;
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");
3697 goto fail;
3698 }
3699 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3700 unwrapped2, unwrapped2_len);
3701
3702 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
3703 dpp_auth_fail(auth,
3704 "Invalid attribute in secondary unwrapped data");
3705 goto fail;
3706 }
3707
3708 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
3709 &r_auth_len);
3710 if (!r_auth || r_auth_len != auth->curve->hash_len) {
3711 dpp_auth_fail(auth,
3712 "Missing or invalid Responder Authenticating Tag");
3713 goto fail;
3714 }
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)
3719 goto fail;
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);
3728 }
3729
3730 bin_clear_free(unwrapped, unwrapped_len);
3731 bin_clear_free(unwrapped2, unwrapped2_len);
3732
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)
3738 return NULL;
3739 return wpabuf_dup(auth->resp_msg);
3740 }
3741 #endif /* CONFIG_TESTING_OPTIONS */
3742
3743 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
3744
3745 fail:
3746 bin_clear_free(unwrapped, unwrapped_len);
3747 bin_clear_free(unwrapped2, unwrapped2_len);
3748 EVP_PKEY_free(pr);
3749 EVP_PKEY_CTX_free(ctx);
3750 return NULL;
3751 }
3752
3753
3754 static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
3755 const u8 *hdr,
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)
3760 {
3761 const u8 *addr[2];
3762 size_t len[2];
3763 u8 *unwrapped = NULL;
3764 size_t unwrapped_len = 0;
3765 const u8 *r_nonce;
3766 u16 r_nonce_len;
3767
3768 /* Authentication Confirm failure cases are expected to include
3769 * {R-nonce}k2 in the Wrapped Data attribute. */
3770
3771 addr[0] = hdr;
3772 len[0] = DPP_HDR_LEN;
3773 addr[1] = attr_start;
3774 len[1] = attr_len;
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);
3781 if (!unwrapped) {
3782 dpp_auth_fail(auth, "Authentication failed");
3783 goto fail;
3784 }
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");
3789 goto fail;
3790 }
3791 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3792 unwrapped, unwrapped_len);
3793
3794 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3795 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3796 goto fail;
3797 }
3798
3799 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3800 &r_nonce_len);
3801 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3802 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3803 goto fail;
3804 }
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");
3811 goto fail;
3812 }
3813
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)");
3818
3819 fail:
3820 bin_clear_free(unwrapped, unwrapped_len);
3821 return -1;
3822 }
3823
3824
3825 int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
3826 const u8 *attr_start, size_t attr_len)
3827 {
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,
3830 i_auth_len;
3831 const u8 *addr[2];
3832 size_t len[2];
3833 u8 *unwrapped = NULL;
3834 size_t unwrapped_len = 0;
3835 u8 i_auth2[DPP_MAX_HASH_LEN];
3836
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");
3841 return -1;
3842 }
3843 #endif /* CONFIG_TESTING_OPTIONS */
3844
3845 if (auth->initiator) {
3846 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
3847 return -1;
3848 }
3849
3850 auth->waiting_auth_conf = 0;
3851
3852 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3853 &wrapped_data_len);
3854 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3855 dpp_auth_fail(auth,
3856 "Missing or invalid required Wrapped Data attribute");
3857 return -1;
3858 }
3859 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3860 wrapped_data, wrapped_data_len);
3861
3862 attr_len = wrapped_data - 4 - attr_start;
3863
3864 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3865 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3866 &r_bootstrap_len);
3867 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3868 dpp_auth_fail(auth,
3869 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3870 return -1;
3871 }
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);
3879 dpp_auth_fail(auth,
3880 "Responder Bootstrapping Key Hash mismatch");
3881 return -1;
3882 }
3883
3884 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3885 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3886 &i_bootstrap_len);
3887 if (i_bootstrap) {
3888 if (i_bootstrap_len != SHA256_MAC_LEN) {
3889 dpp_auth_fail(auth,
3890 "Invalid Initiator Bootstrapping Key Hash attribute");
3891 return -1;
3892 }
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) {
3899 dpp_auth_fail(auth,
3900 "Initiator Bootstrapping Key Hash mismatch");
3901 return -1;
3902 }
3903 } else if (auth->own_bi && auth->peer_bi) {
3904 /* Mutual authentication and peer did not include its
3905 * Bootstrapping Key Hash attribute. */
3906 dpp_auth_fail(auth,
3907 "Missing Initiator Bootstrapping Key Hash attribute");
3908 return -1;
3909 }
3910
3911 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3912 &status_len);
3913 if (!status || status_len < 1) {
3914 dpp_auth_fail(auth,
3915 "Missing or invalid required DPP Status attribute");
3916 return -1;
3917 }
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]);
3924
3925 if (status[0] != DPP_STATUS_OK) {
3926 dpp_auth_fail(auth, "Authentication failed");
3927 return -1;
3928 }
3929
3930 addr[0] = hdr;
3931 len[0] = DPP_HDR_LEN;
3932 addr[1] = attr_start;
3933 len[1] = attr_len;
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);
3940 if (!unwrapped)
3941 return -1;
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");
3946 goto fail;
3947 }
3948 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3949 unwrapped, unwrapped_len);
3950
3951 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3952 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3953 goto fail;
3954 }
3955
3956 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
3957 &i_auth_len);
3958 if (!i_auth || i_auth_len != auth->curve->hash_len) {
3959 dpp_auth_fail(auth,
3960 "Missing or invalid Initiator Authenticating Tag");
3961 goto fail;
3962 }
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)
3967 goto fail;
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");
3972 goto fail;
3973 }
3974
3975 bin_clear_free(unwrapped, unwrapped_len);
3976 dpp_auth_success(auth);
3977 return 0;
3978 fail:
3979 bin_clear_free(unwrapped, unwrapped_len);
3980 return -1;
3981 }
3982
3983
3984 void dpp_configuration_free(struct dpp_configuration *conf)
3985 {
3986 if (!conf)
3987 return;
3988 str_clear_free(conf->passphrase);
3989 bin_clear_free(conf, sizeof(*conf));
3990 }
3991
3992
3993 void dpp_auth_deinit(struct dpp_authentication *auth)
3994 {
3995 if (!auth)
3996 return;
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));
4014 }
4015
4016
4017 static struct wpabuf *
4018 dpp_build_conf_start(struct dpp_authentication *auth,
4019 struct dpp_configuration *conf, size_t tailroom)
4020 {
4021 struct wpabuf *buf;
4022 char ssid[6 * sizeof(conf->ssid) + 1];
4023
4024 #ifdef CONFIG_TESTING_OPTIONS
4025 if (auth->discovery_override)
4026 tailroom += os_strlen(auth->discovery_override);
4027 #endif /* CONFIG_TESTING_OPTIONS */
4028
4029 buf = wpabuf_alloc(200 + tailroom);
4030 if (!buf)
4031 return NULL;
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, ',');
4039 return buf;
4040 }
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, "\"},");
4047
4048 return buf;
4049 }
4050
4051
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)
4054 {
4055 struct wpabuf *pub;
4056 const u8 *pos;
4057 char *x = NULL, *y = NULL;
4058 int ret = -1;
4059
4060 pub = dpp_get_pubkey_point(key, 0);
4061 if (!pub)
4062 goto fail;
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);
4067 if (!x || !y)
4068 goto fail;
4069
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);
4078 if (kid) {
4079 wpabuf_put_str(buf, "\",\"kid\":\"");
4080 wpabuf_put_str(buf, kid);
4081 }
4082 wpabuf_put_str(buf, "\"}");
4083 ret = 0;
4084 fail:
4085 wpabuf_free(pub);
4086 os_free(x);
4087 os_free(y);
4088 return ret;
4089 }
4090
4091
4092 static struct wpabuf *
4093 dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
4094 struct dpp_configuration *conf)
4095 {
4096 struct wpabuf *buf = NULL;
4097 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
4098 size_t tailroom;
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;
4108 char *dot = ".";
4109 const EVP_MD *sign_md;
4110 const BIGNUM *r, *s;
4111 size_t extra_len = 1000;
4112
4113 if (!auth->conf) {
4114 wpa_printf(MSG_INFO,
4115 "DPP: No configurator specified - cannot generate DPP config object");
4116 goto fail;
4117 }
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();
4125 } else {
4126 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
4127 goto fail;
4128 }
4129
4130 #ifdef CONFIG_TESTING_OPTIONS
4131 if (auth->groups_override)
4132 extra_len += os_strlen(auth->groups_override);
4133 #endif /* CONFIG_TESTING_OPTIONS */
4134
4135 /* Connector (JSON dppCon object) */
4136 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
4137 if (!dppcon)
4138 goto fail;
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, ',');
4149 }
4150 goto skip_groups;
4151 }
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
4156 skip_groups:
4157 #endif /* CONFIG_TESTING_OPTIONS */
4158 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
4159 auth->curve) < 0) {
4160 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
4161 goto fail;
4162 }
4163 if (conf->netaccesskey_expiry) {
4164 struct os_tm tm;
4165
4166 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
4167 wpa_printf(MSG_DEBUG,
4168 "DPP: Failed to generate expiry string");
4169 goto fail;
4170 }
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);
4175 }
4176 wpabuf_put_u8(dppcon, '}');
4177 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
4178 (const char *) wpabuf_head(dppcon));
4179
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),
4185 &signed1_len, 0);
4186 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
4187 wpabuf_len(dppcon),
4188 &signed2_len, 0);
4189 if (!signed1 || !signed2)
4190 goto fail;
4191
4192 md_ctx = EVP_MD_CTX_create();
4193 if (!md_ctx)
4194 goto fail;
4195
4196 ERR_clear_error();
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));
4201 goto fail;
4202 }
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));
4208 goto fail;
4209 }
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));
4213 goto fail;
4214 }
4215 signature = os_malloc(signature_len);
4216 if (!signature)
4217 goto fail;
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));
4221 goto fail;
4222 }
4223 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
4224 signature, signature_len);
4225 /* Convert to raw coordinates r,s */
4226 p = signature;
4227 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
4228 if (!sig)
4229 goto fail;
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)
4234 goto fail;
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,
4239 &signed3_len, 0);
4240 if (!signed3)
4241 goto fail;
4242
4243 tailroom = 1000;
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);
4247 if (!buf)
4248 goto fail;
4249
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,
4258 curve) < 0) {
4259 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4260 goto fail;
4261 }
4262
4263 wpabuf_put_str(buf, "}}");
4264
4265 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4266 wpabuf_head(buf), wpabuf_len(buf));
4267
4268 out:
4269 EVP_MD_CTX_destroy(md_ctx);
4270 ECDSA_SIG_free(sig);
4271 os_free(signed1);
4272 os_free(signed2);
4273 os_free(signed3);
4274 os_free(signature);
4275 wpabuf_free(dppcon);
4276 return buf;
4277 fail:
4278 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4279 wpabuf_free(buf);
4280 buf = NULL;
4281 goto out;
4282 }
4283
4284
4285 static struct wpabuf *
4286 dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
4287 struct dpp_configuration *conf)
4288 {
4289 struct wpabuf *buf;
4290
4291 buf = dpp_build_conf_start(auth, conf, 1000);
4292 if (!buf)
4293 return NULL;
4294
4295 wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
4296 if (conf->passphrase) {
4297 char pass[63 * 6 + 1];
4298
4299 if (os_strlen(conf->passphrase) > 63) {
4300 wpabuf_free(buf);
4301 return NULL;
4302 }
4303
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, "\"");
4309 } else {
4310 char psk[2 * sizeof(conf->psk) + 1];
4311
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, "\"");
4317 }
4318 wpabuf_put_str(buf, "}}");
4319
4320 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4321 wpabuf_head(buf), wpabuf_len(buf));
4322
4323 return buf;
4324 }
4325
4326
4327 static struct wpabuf *
4328 dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
4329 {
4330 struct dpp_configuration *conf;
4331
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));
4337 }
4338 #endif /* CONFIG_TESTING_OPTIONS */
4339
4340 conf = ap ? auth->conf_ap : auth->conf_sta;
4341 if (!conf) {
4342 wpa_printf(MSG_DEBUG,
4343 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4344 ap ? "ap" : "sta");
4345 return NULL;
4346 }
4347
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);
4351 }
4352
4353
4354 static struct wpabuf *
4355 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4356 u16 e_nonce_len, int ap)
4357 {
4358 struct wpabuf *conf;
4359 size_t clear_len, attr_len;
4360 struct wpabuf *clear = NULL, *msg = NULL;
4361 u8 *wrapped;
4362 const u8 *addr[1];
4363 size_t len[1];
4364 enum dpp_status_error status;
4365
4366 conf = dpp_build_conf_obj(auth, ap);
4367 if (conf) {
4368 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4369 wpabuf_head(conf), wpabuf_len(conf));
4370 }
4371 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
4372
4373 /* { E-nonce, configurationObject}ke */
4374 clear_len = 4 + e_nonce_len;
4375 if (conf)
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)
4381 attr_len += 5;
4382 #endif /* CONFIG_TESTING_OPTIONS */
4383 msg = wpabuf_alloc(attr_len);
4384 if (!clear || !msg)
4385 goto fail;
4386
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");
4390 goto skip_e_nonce;
4391 }
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);
4398 goto skip_e_nonce;
4399 }
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;
4403 }
4404 #endif /* CONFIG_TESTING_OPTIONS */
4405
4406 /* E-nonce */
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);
4410
4411 #ifdef CONFIG_TESTING_OPTIONS
4412 skip_e_nonce:
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;
4416 }
4417 #endif /* CONFIG_TESTING_OPTIONS */
4418
4419 if (conf) {
4420 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4421 wpabuf_put_le16(clear, wpabuf_len(conf));
4422 wpabuf_put_buf(clear, conf);
4423 }
4424
4425 #ifdef CONFIG_TESTING_OPTIONS
4426 skip_config_obj:
4427 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4428 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4429 goto skip_status;
4430 }
4431 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4432 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4433 status = 255;
4434 }
4435 #endif /* CONFIG_TESTING_OPTIONS */
4436
4437 /* DPP Status */
4438 dpp_build_attr_status(msg, status);
4439
4440 #ifdef CONFIG_TESTING_OPTIONS
4441 skip_status:
4442 #endif /* CONFIG_TESTING_OPTIONS */
4443
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]);
4447
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);
4451
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)
4456 goto fail;
4457 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4458 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
4459
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);
4464 }
4465 skip_wrapped_data:
4466 #endif /* CONFIG_TESTING_OPTIONS */
4467
4468 wpa_hexdump_buf(MSG_DEBUG,
4469 "DPP: Configuration Response attributes", msg);
4470 out:
4471 wpabuf_free(conf);
4472 wpabuf_free(clear);
4473
4474 return msg;
4475 fail:
4476 wpabuf_free(msg);
4477 msg = NULL;
4478 goto out;
4479 }
4480
4481
4482 struct wpabuf *
4483 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4484 size_t attr_len)
4485 {
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;
4492 int ap;
4493
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");
4498 return NULL;
4499 }
4500 #endif /* CONFIG_TESTING_OPTIONS */
4501
4502 if (dpp_check_attrs(attr_start, attr_len) < 0) {
4503 dpp_auth_fail(auth, "Invalid attribute in config request");
4504 return NULL;
4505 }
4506
4507 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4508 &wrapped_data_len);
4509 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4510 dpp_auth_fail(auth,
4511 "Missing or invalid required Wrapped Data attribute");
4512 return NULL;
4513 }
4514
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);
4519 if (!unwrapped)
4520 return NULL;
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");
4525 goto fail;
4526 }
4527 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4528 unwrapped, unwrapped_len);
4529
4530 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4531 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4532 goto fail;
4533 }
4534
4535 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4536 DPP_ATTR_ENROLLEE_NONCE,
4537 &e_nonce_len);
4538 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
4539 dpp_auth_fail(auth,
4540 "Missing or invalid Enrollee Nonce attribute");
4541 goto fail;
4542 }
4543 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4544
4545 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
4546 DPP_ATTR_CONFIG_ATTR_OBJ,
4547 &config_attr_len);
4548 if (!config_attr) {
4549 dpp_auth_fail(auth,
4550 "Missing or invalid Config Attributes attribute");
4551 goto fail;
4552 }
4553 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
4554 config_attr, config_attr_len);
4555
4556 root = json_parse((const char *) config_attr, config_attr_len);
4557 if (!root) {
4558 dpp_auth_fail(auth, "Could not parse Config Attributes");
4559 goto fail;
4560 }
4561
4562 token = json_get_member(root, "name");
4563 if (!token || token->type != JSON_STRING) {
4564 dpp_auth_fail(auth, "No Config Attributes - name");
4565 goto fail;
4566 }
4567 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
4568
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");
4572 goto fail;
4573 }
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'",
4577 token->string);
4578 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
4579 goto fail;
4580 }
4581
4582 token = json_get_member(root, "netRole");
4583 if (!token || token->type != JSON_STRING) {
4584 dpp_auth_fail(auth, "No Config Attributes - netRole");
4585 goto fail;
4586 }
4587 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
4588 if (os_strcmp(token->string, "sta") == 0) {
4589 ap = 0;
4590 } else if (os_strcmp(token->string, "ap") == 0) {
4591 ap = 1;
4592 } else {
4593 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
4594 token->string);
4595 dpp_auth_fail(auth, "Unsupported netRole");
4596 goto fail;
4597 }
4598
4599 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
4600
4601 fail:
4602 json_free(root);
4603 os_free(unwrapped);
4604 return resp;
4605 }
4606
4607
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)
4612 {
4613 struct json_token *root, *token;
4614 struct wpabuf *kid = NULL;
4615
4616 root = json_parse((const char *) prot_hdr, prot_hdr_len);
4617 if (!root) {
4618 wpa_printf(MSG_DEBUG,
4619 "DPP: JSON parsing failed for JWS Protected Header");
4620 goto fail;
4621 }
4622
4623 if (root->type != JSON_OBJECT) {
4624 wpa_printf(MSG_DEBUG,
4625 "DPP: JWS Protected Header root is not an object");
4626 goto fail;
4627 }
4628
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");
4632 goto fail;
4633 }
4634 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
4635 token->string);
4636 if (os_strcmp(token->string, "dppCon") != 0) {
4637 wpa_printf(MSG_DEBUG,
4638 "DPP: Unsupported JWS Protected Header typ=%s",
4639 token->string);
4640 goto fail;
4641 }
4642
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");
4646 goto fail;
4647 }
4648 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
4649 token->string);
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);
4654 goto fail;
4655 }
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();
4665 else
4666 *ret_md = NULL;
4667 if (!*ret_md) {
4668 wpa_printf(MSG_DEBUG,
4669 "DPP: Unsupported JWS Protected Header alg=%s",
4670 token->string);
4671 goto fail;
4672 }
4673
4674 kid = json_get_member_base64url(root, "kid");
4675 if (!kid) {
4676 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
4677 goto fail;
4678 }
4679 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
4680 kid);
4681
4682 fail:
4683 json_free(root);
4684 return kid;
4685 }
4686
4687
4688 static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
4689 struct json_token *cred)
4690 {
4691 struct json_token *pass, *psk_hex;
4692
4693 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
4694
4695 pass = json_get_member(cred, "pass");
4696 psk_hex = json_get_member(cred, "psk_hex");
4697
4698 if (pass && pass->type == JSON_STRING) {
4699 size_t len = os_strlen(pass->string);
4700
4701 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
4702 pass->string, len);
4703 if (len < 8 || len > 63)
4704 return -1;
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");
4711 return -1;
4712 }
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");
4716 return -1;
4717 }
4718 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
4719 auth->psk, PMK_LEN);
4720 auth->psk_set = 1;
4721 } else {
4722 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
4723 return -1;
4724 }
4725
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");
4729 return -1;
4730 }
4731
4732 return 0;
4733 }
4734
4735
4736 static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
4737 const struct dpp_curve_params **key_curve)
4738 {
4739 struct json_token *token;
4740 const struct dpp_curve_params *curve;
4741 struct wpabuf *x = NULL, *y = NULL;
4742 EC_GROUP *group;
4743 EVP_PKEY *pkey = NULL;
4744
4745 token = json_get_member(jwk, "kty");
4746 if (!token || token->type != JSON_STRING) {
4747 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
4748 goto fail;
4749 }
4750 if (os_strcmp(token->string, "EC") != 0) {
4751 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s",
4752 token->string);
4753 goto fail;
4754 }
4755
4756 token = json_get_member(jwk, "crv");
4757 if (!token || token->type != JSON_STRING) {
4758 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
4759 goto fail;
4760 }
4761 curve = dpp_get_curve_jwk_crv(token->string);
4762 if (!curve) {
4763 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
4764 token->string);
4765 goto fail;
4766 }
4767
4768 x = json_get_member_base64url(jwk, "x");
4769 if (!x) {
4770 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
4771 goto fail;
4772 }
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);
4779 goto fail;
4780 }
4781
4782 y = json_get_member_base64url(jwk, "y");
4783 if (!y) {
4784 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
4785 goto fail;
4786 }
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);
4793 goto fail;
4794 }
4795
4796 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
4797 if (!group) {
4798 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
4799 goto fail;
4800 }
4801
4802 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
4803 wpabuf_len(x));
4804 *key_curve = curve;
4805
4806 fail:
4807 wpabuf_free(x);
4808 wpabuf_free(y);
4809
4810 return pkey;
4811 }
4812
4813
4814 int dpp_key_expired(const char *timestamp, os_time_t *expiry)
4815 {
4816 struct os_time now;
4817 unsigned int year, month, day, hour, min, sec;
4818 os_time_t utime;
4819 const char *pos;
4820
4821 /* ISO 8601 date and time:
4822 * <date>T<time>
4823 * YYYY-MM-DDTHH:MM:SSZ
4824 * YYYY-MM-DDTHH:MM:SS+03:00
4825 */
4826 if (os_strlen(timestamp) < 19) {
4827 wpa_printf(MSG_DEBUG,
4828 "DPP: Too short timestamp - assume expired key");
4829 return 1;
4830 }
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");
4835 return 1;
4836 }
4837
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");
4841 return 1;
4842 }
4843
4844 pos = timestamp + 19;
4845 if (*pos == 'Z' || *pos == '\0') {
4846 /* In UTC - no need to adjust */
4847 } else if (*pos == '-' || *pos == '+') {
4848 int items;
4849
4850 /* Adjust local time to UTC */
4851 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
4852 if (items < 1) {
4853 wpa_printf(MSG_DEBUG,
4854 "DPP: Invalid time zone designator (%s) - assume expired key",
4855 pos);
4856 return 1;
4857 }
4858 if (*pos == '-')
4859 utime += 3600 * hour;
4860 if (*pos == '+')
4861 utime -= 3600 * hour;
4862 if (items > 1) {
4863 if (*pos == '-')
4864 utime += 60 * min;
4865 if (*pos == '+')
4866 utime -= 60 * min;
4867 }
4868 } else {
4869 wpa_printf(MSG_DEBUG,
4870 "DPP: Invalid time zone designator (%s) - assume expired key",
4871 pos);
4872 return 1;
4873 }
4874 if (expiry)
4875 *expiry = utime;
4876
4877 if (os_get_time(&now) < 0) {
4878 wpa_printf(MSG_DEBUG,
4879 "DPP: Cannot get current time - assume expired key");
4880 return 1;
4881 }
4882
4883 if (now.sec > utime) {
4884 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
4885 utime, now.sec);
4886 return 1;
4887 }
4888
4889 return 0;
4890 }
4891
4892
4893 static int dpp_parse_connector(struct dpp_authentication *auth,
4894 const unsigned char *payload,
4895 u16 payload_len)
4896 {
4897 struct json_token *root, *groups, *netkey, *token;
4898 int ret = -1;
4899 EVP_PKEY *key = NULL;
4900 const struct dpp_curve_params *curve;
4901 unsigned int rules = 0;
4902
4903 root = json_parse((const char *) payload, payload_len);
4904 if (!root) {
4905 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4906 goto fail;
4907 }
4908
4909 groups = json_get_member(root, "groups");
4910 if (!groups || groups->type != JSON_ARRAY) {
4911 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
4912 goto skip_groups;
4913 }
4914 for (token = groups->child; token; token = token->sibling) {
4915 struct json_token *id, *role;
4916
4917 id = json_get_member(token, "groupId");
4918 if (!id || id->type != JSON_STRING) {
4919 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
4920 goto fail;
4921 }
4922
4923 role = json_get_member(token, "netRole");
4924 if (!role || role->type != JSON_STRING) {
4925 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
4926 goto fail;
4927 }
4928 wpa_printf(MSG_DEBUG,
4929 "DPP: connector group: groupId='%s' netRole='%s'",
4930 id->string, role->string);
4931 rules++;
4932 }
4933 skip_groups:
4934
4935 if (!rules) {
4936 wpa_printf(MSG_DEBUG,
4937 "DPP: Connector includes no groups");
4938 goto fail;
4939 }
4940
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");
4945 } else {
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");
4951 goto fail;
4952 }
4953 }
4954
4955 netkey = json_get_member(root, "netAccessKey");
4956 if (!netkey || netkey->type != JSON_OBJECT) {
4957 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4958 goto fail;
4959 }
4960
4961 key = dpp_parse_jwk(netkey, &curve);
4962 if (!key)
4963 goto fail;
4964 dpp_debug_print_key("DPP: Received netAccessKey", key);
4965
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");
4973 } else {
4974 goto fail;
4975 }
4976 #else /* CONFIG_TESTING_OPTIONS */
4977 goto fail;
4978 #endif /* CONFIG_TESTING_OPTIONS */
4979 }
4980
4981 ret = 0;
4982 fail:
4983 EVP_PKEY_free(key);
4984 json_free(root);
4985 return ret;
4986 }
4987
4988
4989 static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
4990 {
4991 struct wpabuf *uncomp;
4992 int res;
4993 u8 hash[SHA256_MAC_LEN];
4994 const u8 *addr[1];
4995 size_t len[1];
4996
4997 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
4998 return -1;
4999 uncomp = dpp_get_pubkey_point(pub, 1);
5000 if (!uncomp)
5001 return -1;
5002 addr[0] = wpabuf_head(uncomp);
5003 len[0] = wpabuf_len(uncomp);
5004 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
5005 addr[0], len[0]);
5006 res = sha256_vector(1, addr, len, hash);
5007 wpabuf_free(uncomp);
5008 if (res < 0)
5009 return -1;
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);
5015 return -1;
5016 }
5017 return 0;
5018 }
5019
5020
5021 static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
5022 {
5023 unsigned char *der = NULL;
5024 int der_len;
5025
5026 der_len = i2d_PUBKEY(csign, &der);
5027 if (der_len <= 0)
5028 return;
5029 wpabuf_free(auth->c_sign_key);
5030 auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
5031 OPENSSL_free(der);
5032 }
5033
5034
5035 static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
5036 {
5037 unsigned char *der = NULL;
5038 int der_len;
5039 EC_KEY *eckey;
5040
5041 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
5042 if (!eckey)
5043 return;
5044
5045 der_len = i2d_ECPrivateKey(eckey, &der);
5046 if (der_len <= 0) {
5047 EC_KEY_free(eckey);
5048 return;
5049 }
5050 wpabuf_free(auth->net_access_key);
5051 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
5052 OPENSSL_free(der);
5053 EC_KEY_free(eckey);
5054 }
5055
5056
5057 struct dpp_signed_connector_info {
5058 unsigned char *payload;
5059 size_t payload_len;
5060 };
5061
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)
5065 {
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;
5073 int der_len;
5074 int res;
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;
5079 EC_KEY *eckey;
5080 const EC_GROUP *group;
5081 int nid;
5082
5083 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
5084 if (!eckey)
5085 goto fail;
5086 group = EC_KEY_get0_group(eckey);
5087 if (!group)
5088 goto fail;
5089 nid = EC_GROUP_get_curve_name(group);
5090 curve = dpp_get_curve_nid(nid);
5091 if (!curve)
5092 goto fail;
5093 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
5094 os_memset(info, 0, sizeof(*info));
5095
5096 signed_start = pos = connector;
5097 end = os_strchr(pos, '.');
5098 if (!end) {
5099 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
5100 ret = DPP_STATUS_INVALID_CONNECTOR;
5101 goto fail;
5102 }
5103 prot_hdr = base64_url_decode((const unsigned char *) pos,
5104 end - pos, &prot_hdr_len);
5105 if (!prot_hdr) {
5106 wpa_printf(MSG_DEBUG,
5107 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5108 ret = DPP_STATUS_INVALID_CONNECTOR;
5109 goto fail;
5110 }
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);
5115 if (!kid) {
5116 ret = DPP_STATUS_INVALID_CONNECTOR;
5117 goto fail;
5118 }
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;
5124 goto fail;
5125 }
5126
5127 pos = end + 1;
5128 end = os_strchr(pos, '.');
5129 if (!end) {
5130 wpa_printf(MSG_DEBUG,
5131 "DPP: Missing dot(2) in signedConnector");
5132 ret = DPP_STATUS_INVALID_CONNECTOR;
5133 goto fail;
5134 }
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;
5142 goto fail;
5143 }
5144 wpa_hexdump_ascii(MSG_DEBUG,
5145 "DPP: signedConnector - JWS Payload",
5146 info->payload, info->payload_len);
5147 pos = end + 1;
5148 signature = base64_url_decode((const unsigned char *) pos,
5149 os_strlen(pos), &signature_len);
5150 if (!signature) {
5151 wpa_printf(MSG_DEBUG,
5152 "DPP: Failed to base64url decode signedConnector signature");
5153 ret = DPP_STATUS_INVALID_CONNECTOR;
5154 goto fail;
5155 }
5156 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5157 signature, signature_len);
5158
5159 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5160 ret = DPP_STATUS_NO_MATCH;
5161 goto fail;
5162 }
5163
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;
5169 goto fail;
5170 }
5171
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)
5178 goto fail;
5179 r = NULL;
5180 s = NULL;
5181
5182 der_len = i2d_ECDSA_SIG(sig, &der);
5183 if (der_len <= 0) {
5184 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
5185 goto fail;
5186 }
5187 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
5188 md_ctx = EVP_MD_CTX_create();
5189 if (!md_ctx)
5190 goto fail;
5191
5192 ERR_clear_error();
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));
5196 goto fail;
5197 }
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));
5202 goto fail;
5203 }
5204 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
5205 if (res != 1) {
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;
5210 goto fail;
5211 }
5212
5213 ret = DPP_STATUS_OK;
5214 fail:
5215 EC_KEY_free(eckey);
5216 EVP_MD_CTX_destroy(md_ctx);
5217 os_free(prot_hdr);
5218 wpabuf_free(kid);
5219 os_free(signature);
5220 ECDSA_SIG_free(sig);
5221 BN_free(r);
5222 BN_free(s);
5223 OPENSSL_free(der);
5224 return ret;
5225 }
5226
5227
5228 static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5229 struct json_token *cred)
5230 {
5231 struct dpp_signed_connector_info info;
5232 struct json_token *token, *csign;
5233 int ret = -1;
5234 EVP_PKEY *csign_pub = NULL;
5235 const struct dpp_curve_params *key_curve = NULL;
5236 const char *signed_connector;
5237
5238 os_memset(&info, 0, sizeof(info));
5239
5240 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5241
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");
5245 goto fail;
5246 }
5247
5248 csign_pub = dpp_parse_jwk(csign, &key_curve);
5249 if (!csign_pub) {
5250 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5251 goto fail;
5252 }
5253 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5254
5255 token = json_get_member(cred, "signedConnector");
5256 if (!token || token->type != JSON_STRING) {
5257 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5258 goto fail;
5259 }
5260 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5261 token->string, os_strlen(token->string));
5262 signed_connector = token->string;
5263
5264 if (os_strchr(signed_connector, '"') ||
5265 os_strchr(signed_connector, '\n')) {
5266 wpa_printf(MSG_DEBUG,
5267 "DPP: Unexpected character in signedConnector");
5268 goto fail;
5269 }
5270
5271 if (dpp_process_signed_connector(&info, csign_pub,
5272 signed_connector) != DPP_STATUS_OK)
5273 goto fail;
5274
5275 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
5276 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5277 goto fail;
5278 }
5279
5280 os_free(auth->connector);
5281 auth->connector = os_strdup(signed_connector);
5282
5283 dpp_copy_csign(auth, csign_pub);
5284 dpp_copy_netaccesskey(auth);
5285
5286 ret = 0;
5287 fail:
5288 EVP_PKEY_free(csign_pub);
5289 os_free(info.payload);
5290 return ret;
5291 }
5292
5293
5294 const char * dpp_akm_str(enum dpp_akm akm)
5295 {
5296 switch (akm) {
5297 case DPP_AKM_DPP:
5298 return "dpp";
5299 case DPP_AKM_PSK:
5300 return "psk";
5301 case DPP_AKM_SAE:
5302 return "sae";
5303 case DPP_AKM_PSK_SAE:
5304 return "psk+sae";
5305 default:
5306 return "??";
5307 }
5308 }
5309
5310
5311 static enum dpp_akm dpp_akm_from_str(const char *akm)
5312 {
5313 if (os_strcmp(akm, "psk") == 0)
5314 return DPP_AKM_PSK;
5315 if (os_strcmp(akm, "sae") == 0)
5316 return DPP_AKM_SAE;
5317 if (os_strcmp(akm, "psk+sae") == 0)
5318 return DPP_AKM_PSK_SAE;
5319 if (os_strcmp(akm, "dpp") == 0)
5320 return DPP_AKM_DPP;
5321 return DPP_AKM_UNKNOWN;
5322 }
5323
5324
5325 static int dpp_parse_conf_obj(struct dpp_authentication *auth,
5326 const u8 *conf_obj, u16 conf_obj_len)
5327 {
5328 int ret = -1;
5329 struct json_token *root, *token, *discovery, *cred;
5330
5331 root = json_parse((const char *) conf_obj, conf_obj_len);
5332 if (!root)
5333 return -1;
5334 if (root->type != JSON_OBJECT) {
5335 dpp_auth_fail(auth, "JSON root is not an object");
5336 goto fail;
5337 }
5338
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");
5342 goto fail;
5343 }
5344 if (os_strcmp(token->string, "infra") != 0) {
5345 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5346 token->string);
5347 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
5348 goto fail;
5349 }
5350
5351 discovery = json_get_member(root, "discovery");
5352 if (!discovery || discovery->type != JSON_OBJECT) {
5353 dpp_auth_fail(auth, "No discovery object in JSON");
5354 goto fail;
5355 }
5356
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");
5360 goto fail;
5361 }
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");
5366 goto fail;
5367 }
5368 auth->ssid_len = os_strlen(token->string);
5369 os_memcpy(auth->ssid, token->string, auth->ssid_len);
5370
5371 cred = json_get_member(root, "cred");
5372 if (!cred || cred->type != JSON_OBJECT) {
5373 dpp_auth_fail(auth, "No cred object in JSON");
5374 goto fail;
5375 }
5376
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");
5380 goto fail;
5381 }
5382 auth->akm = dpp_akm_from_str(token->string);
5383
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)
5387 goto fail;
5388 } else if (auth->akm == DPP_AKM_DPP) {
5389 if (dpp_parse_cred_dpp(auth, cred) < 0)
5390 goto fail;
5391 } else {
5392 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5393 token->string);
5394 dpp_auth_fail(auth, "Unsupported akm");
5395 goto fail;
5396 }
5397
5398 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5399 ret = 0;
5400 fail:
5401 json_free(root);
5402 return ret;
5403 }
5404
5405
5406 int dpp_conf_resp_rx(struct dpp_authentication *auth,
5407 const struct wpabuf *resp)
5408 {
5409 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5410 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5411 const u8 *addr[1];
5412 size_t len[1];
5413 u8 *unwrapped = NULL;
5414 size_t unwrapped_len = 0;
5415 int ret = -1;
5416
5417 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
5418 dpp_auth_fail(auth, "Invalid attribute in config response");
5419 return -1;
5420 }
5421
5422 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5423 DPP_ATTR_WRAPPED_DATA,
5424 &wrapped_data_len);
5425 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
5426 dpp_auth_fail(auth,
5427 "Missing or invalid required Wrapped Data attribute");
5428 return -1;
5429 }
5430
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);
5435 if (!unwrapped)
5436 return -1;
5437
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]);
5441
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");
5446 goto fail;
5447 }
5448 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5449 unwrapped, unwrapped_len);
5450
5451 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
5452 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
5453 goto fail;
5454 }
5455
5456 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5457 DPP_ATTR_ENROLLEE_NONCE,
5458 &e_nonce_len);
5459 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
5460 dpp_auth_fail(auth,
5461 "Missing or invalid Enrollee Nonce attribute");
5462 goto fail;
5463 }
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");
5467 goto fail;
5468 }
5469
5470 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5471 DPP_ATTR_STATUS, &status_len);
5472 if (!status || status_len < 1) {
5473 dpp_auth_fail(auth,
5474 "Missing or invalid required DPP Status attribute");
5475 goto fail;
5476 }
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");
5480 goto fail;
5481 }
5482
5483 conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
5484 DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
5485 if (!conf_obj) {
5486 dpp_auth_fail(auth,
5487 "Missing required Configuration Object attribute");
5488 goto fail;
5489 }
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)
5493 goto fail;
5494
5495 ret = 0;
5496
5497 fail:
5498 os_free(unwrapped);
5499 return ret;
5500 }
5501
5502
5503 void dpp_configurator_free(struct dpp_configurator *conf)
5504 {
5505 if (!conf)
5506 return;
5507 EVP_PKEY_free(conf->csign);
5508 os_free(conf->kid);
5509 os_free(conf);
5510 }
5511
5512
5513 int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
5514 size_t buflen)
5515 {
5516 EC_KEY *eckey;
5517 int key_len, ret = -1;
5518 unsigned char *key = NULL;
5519
5520 if (!conf->csign)
5521 return -1;
5522
5523 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
5524 if (!eckey)
5525 return -1;
5526
5527 key_len = i2d_ECPrivateKey(eckey, &key);
5528 if (key_len > 0)
5529 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
5530
5531 EC_KEY_free(eckey);
5532 OPENSSL_free(key);
5533 return ret;
5534 }
5535
5536
5537 struct dpp_configurator *
5538 dpp_keygen_configurator(const char *curve, const u8 *privkey,
5539 size_t privkey_len)
5540 {
5541 struct dpp_configurator *conf;
5542 struct wpabuf *csign_pub = NULL;
5543 u8 kid_hash[SHA256_MAC_LEN];
5544 const u8 *addr[1];
5545 size_t len[1];
5546
5547 conf = os_zalloc(sizeof(*conf));
5548 if (!conf)
5549 return NULL;
5550
5551 if (!curve) {
5552 conf->curve = &dpp_curves[0];
5553 } else {
5554 conf->curve = dpp_get_curve_name(curve);
5555 if (!conf->curve) {
5556 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5557 curve);
5558 return NULL;
5559 }
5560 }
5561 if (privkey)
5562 conf->csign = dpp_set_keypair(&conf->curve, privkey,
5563 privkey_len);
5564 else
5565 conf->csign = dpp_gen_keypair(conf->curve);
5566 if (!conf->csign)
5567 goto fail;
5568 conf->own = 1;
5569
5570 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
5571 if (!csign_pub) {
5572 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
5573 goto fail;
5574 }
5575
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");
5582 goto fail;
5583 }
5584
5585 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
5586 NULL, 0);
5587 if (!conf->kid)
5588 goto fail;
5589 out:
5590 wpabuf_free(csign_pub);
5591 return conf;
5592 fail:
5593 dpp_configurator_free(conf);
5594 conf = NULL;
5595 goto out;
5596 }
5597
5598
5599 int dpp_configurator_own_config(struct dpp_authentication *auth,
5600 const char *curve, int ap)
5601 {
5602 struct wpabuf *conf_obj;
5603 int ret = -1;
5604
5605 if (!auth->conf) {
5606 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
5607 return -1;
5608 }
5609
5610 if (!curve) {
5611 auth->curve = &dpp_curves[0];
5612 } else {
5613 auth->curve = dpp_get_curve_name(curve);
5614 if (!auth->curve) {
5615 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5616 curve);
5617 return -1;
5618 }
5619 }
5620 wpa_printf(MSG_DEBUG,
5621 "DPP: Building own configuration/connector with curve %s",
5622 auth->curve->name);
5623
5624 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
5625 if (!auth->own_protocol_key)
5626 return -1;
5627 dpp_copy_netaccesskey(auth);
5628 auth->peer_protocol_key = auth->own_protocol_key;
5629 dpp_copy_csign(auth, auth->conf->csign);
5630
5631 conf_obj = dpp_build_conf_obj(auth, ap);
5632 if (!conf_obj)
5633 goto fail;
5634 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
5635 wpabuf_len(conf_obj));
5636 fail:
5637 wpabuf_free(conf_obj);
5638 auth->peer_protocol_key = NULL;
5639 return ret;
5640 }
5641
5642
5643 static int dpp_compatible_netrole(const char *role1, const char *role2)
5644 {
5645 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
5646 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
5647 }
5648
5649
5650 static int dpp_connector_compatible_group(struct json_token *root,
5651 const char *group_id,
5652 const char *net_role)
5653 {
5654 struct json_token *groups, *token;
5655
5656 groups = json_get_member(root, "groups");
5657 if (!groups || groups->type != JSON_ARRAY)
5658 return 0;
5659
5660 for (token = groups->child; token; token = token->sibling) {
5661 struct json_token *id, *role;
5662
5663 id = json_get_member(token, "groupId");
5664 if (!id || id->type != JSON_STRING)
5665 continue;
5666
5667 role = json_get_member(token, "netRole");
5668 if (!role || role->type != JSON_STRING)
5669 continue;
5670
5671 if (os_strcmp(id->string, "*") != 0 &&
5672 os_strcmp(group_id, "*") != 0 &&
5673 os_strcmp(id->string, group_id) != 0)
5674 continue;
5675
5676 if (dpp_compatible_netrole(role->string, net_role))
5677 return 1;
5678 }
5679
5680 return 0;
5681 }
5682
5683
5684 static int dpp_connector_match_groups(struct json_token *own_root,
5685 struct json_token *peer_root)
5686 {
5687 struct json_token *groups, *token;
5688
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");
5692 return 0;
5693 }
5694
5695 for (token = groups->child; token; token = token->sibling) {
5696 struct json_token *id, *role;
5697
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");
5702 continue;
5703 }
5704
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");
5709 continue;
5710 }
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,
5715 role->string)) {
5716 wpa_printf(MSG_DEBUG,
5717 "DPP: Compatible group/netRole in own connector");
5718 return 1;
5719 }
5720 }
5721
5722 return 0;
5723 }
5724
5725
5726 static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
5727 unsigned int hash_len)
5728 {
5729 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5730 const char *info = "DPP PMK";
5731 int res;
5732
5733 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5734
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)
5738 return -1;
5739 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5740 prk, hash_len);
5741
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);
5745 if (res < 0)
5746 return -1;
5747
5748 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5749 pmk, hash_len);
5750 return 0;
5751 }
5752
5753
5754 static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
5755 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
5756 {
5757 struct wpabuf *nkx, *pkx;
5758 int ret = -1, res;
5759 const u8 *addr[2];
5760 size_t len[2];
5761 u8 hash[SHA256_MAC_LEN];
5762
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);
5766 if (!nkx || !pkx)
5767 goto fail;
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])
5773 goto fail;
5774 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
5775 addr[0] = wpabuf_head(pkx);
5776 addr[1] = wpabuf_head(nkx);
5777 }
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);
5781 if (res < 0)
5782 goto fail;
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);
5786 ret = 0;
5787 fail:
5788 wpabuf_free(nkx);
5789 wpabuf_free(pkx);
5790 return ret;
5791 }
5792
5793
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,
5799 os_time_t *expiry)
5800 {
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;
5815 size_t Nx_len;
5816 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
5817
5818 os_memset(intro, 0, sizeof(*intro));
5819 os_memset(&info, 0, sizeof(info));
5820 if (expiry)
5821 *expiry = 0;
5822
5823 p = csign_key;
5824 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
5825 if (!csign) {
5826 wpa_printf(MSG_ERROR,
5827 "DPP: Failed to parse local C-sign-key information");
5828 goto fail;
5829 }
5830
5831 own_key = dpp_set_keypair(&own_curve, net_access_key,
5832 net_access_key_len);
5833 if (!own_key) {
5834 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
5835 goto fail;
5836 }
5837
5838 pos = os_strchr(own_connector, '.');
5839 if (!pos) {
5840 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
5841 goto fail;
5842 }
5843 pos++;
5844 end = os_strchr(pos, '.');
5845 if (!end) {
5846 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
5847 goto fail;
5848 }
5849 own_conn = base64_url_decode((const unsigned char *) pos,
5850 end - pos, &own_conn_len);
5851 if (!own_conn) {
5852 wpa_printf(MSG_DEBUG,
5853 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5854 goto fail;
5855 }
5856
5857 own_root = json_parse((const char *) own_conn, own_conn_len);
5858 if (!own_root) {
5859 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
5860 goto fail;
5861 }
5862
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)
5867 goto fail;
5868 os_memcpy(signed_connector, peer_connector, peer_connector_len);
5869 signed_connector[peer_connector_len] = '\0';
5870
5871 res = dpp_process_signed_connector(&info, csign, signed_connector);
5872 if (res != DPP_STATUS_OK) {
5873 ret = res;
5874 goto fail;
5875 }
5876
5877 root = json_parse((const char *) info.payload, info.payload_len);
5878 if (!root) {
5879 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5880 ret = DPP_STATUS_INVALID_CONNECTOR;
5881 goto fail;
5882 }
5883
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;
5888 goto fail;
5889 }
5890
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");
5895 } else {
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;
5901 goto fail;
5902 }
5903 }
5904
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;
5909 goto fail;
5910 }
5911
5912 peer_key = dpp_parse_jwk(netkey, &curve);
5913 if (!peer_key) {
5914 ret = DPP_STATUS_INVALID_CONNECTOR;
5915 goto fail;
5916 }
5917 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
5918
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;
5924 goto fail;
5925 }
5926
5927 /* ECDH: N = nk * PK */
5928 ctx = EVP_PKEY_CTX_new(own_key, NULL);
5929 if (!ctx ||
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));
5938 goto fail;
5939 }
5940
5941 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
5942 Nx, Nx_len);
5943
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");
5947 goto fail;
5948 }
5949 intro->pmk_len = curve->hash_len;
5950
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");
5954 goto fail;
5955 }
5956
5957 ret = DPP_STATUS_OK;
5958 fail:
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);
5963 os_free(own_conn);
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);
5970 json_free(root);
5971 json_free(own_root);
5972 return ret;
5973 }
5974
5975
5976 static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
5977 int init)
5978 {
5979 EC_GROUP *group;
5980 size_t len = curve->prime_len;
5981 const u8 *x, *y;
5982
5983 switch (curve->ike_group) {
5984 case 19:
5985 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
5986 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
5987 break;
5988 case 20:
5989 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
5990 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
5991 break;
5992 case 21:
5993 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
5994 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
5995 break;
5996 case 28:
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;
5999 break;
6000 case 29:
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;
6003 break;
6004 case 30:
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;
6007 break;
6008 default:
6009 return NULL;
6010 }
6011
6012 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6013 if (!group)
6014 return NULL;
6015 return dpp_set_pubkey_point_group(group, x, y, len);
6016 }
6017
6018
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)
6023 {
6024 u8 hash[DPP_MAX_HASH_LEN];
6025 const u8 *addr[3];
6026 size_t len[3];
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;
6035
6036 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6037
6038 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
6039 addr[num_elem] = mac_init;
6040 len[num_elem] = ETH_ALEN;
6041 num_elem++;
6042 if (identifier) {
6043 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6044 identifier);
6045 addr[num_elem] = (const u8 *) identifier;
6046 len[num_elem] = os_strlen(identifier);
6047 num_elem++;
6048 }
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);
6052 num_elem++;
6053 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6054 goto fail;
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);
6059 if (!Pi)
6060 goto fail;
6061 dpp_debug_print_key("DPP: Pi", Pi);
6062 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
6063 if (!Pi_ec)
6064 goto fail;
6065 Pi_point = EC_KEY_get0_public_key(Pi_ec);
6066
6067 group = EC_KEY_get0_group(Pi_ec);
6068 if (!group)
6069 goto fail;
6070 group2 = EC_GROUP_dup(group);
6071 if (!group2)
6072 goto fail;
6073 Qi = EC_POINT_new(group2);
6074 if (!Qi) {
6075 EC_GROUP_free(group2);
6076 goto fail;
6077 }
6078 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6079 if (!hash_bn ||
6080 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
6081 goto fail;
6082 if (EC_POINT_is_at_infinity(group, Qi)) {
6083 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
6084 goto fail;
6085 }
6086 dpp_debug_print_point("DPP: Qi", group, Qi);
6087 out:
6088 EC_KEY_free(Pi_ec);
6089 EVP_PKEY_free(Pi);
6090 BN_clear_free(hash_bn);
6091 if (ret_group)
6092 *ret_group = group2;
6093 return Qi;
6094 fail:
6095 EC_POINT_free(Qi);
6096 Qi = NULL;
6097 goto out;
6098 }
6099
6100
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)
6105 {
6106 u8 hash[DPP_MAX_HASH_LEN];
6107 const u8 *addr[3];
6108 size_t len[3];
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;
6117
6118 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6119
6120 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
6121 addr[num_elem] = mac_resp;
6122 len[num_elem] = ETH_ALEN;
6123 num_elem++;
6124 if (identifier) {
6125 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6126 identifier);
6127 addr[num_elem] = (const u8 *) identifier;
6128 len[num_elem] = os_strlen(identifier);
6129 num_elem++;
6130 }
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);
6134 num_elem++;
6135 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6136 goto fail;
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);
6141 if (!Pr)
6142 goto fail;
6143 dpp_debug_print_key("DPP: Pr", Pr);
6144 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
6145 if (!Pr_ec)
6146 goto fail;
6147 Pr_point = EC_KEY_get0_public_key(Pr_ec);
6148
6149 group = EC_KEY_get0_group(Pr_ec);
6150 if (!group)
6151 goto fail;
6152 group2 = EC_GROUP_dup(group);
6153 if (!group2)
6154 goto fail;
6155 Qr = EC_POINT_new(group2);
6156 if (!Qr) {
6157 EC_GROUP_free(group2);
6158 goto fail;
6159 }
6160 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6161 if (!hash_bn ||
6162 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
6163 goto fail;
6164 if (EC_POINT_is_at_infinity(group, Qr)) {
6165 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
6166 goto fail;
6167 }
6168 dpp_debug_print_point("DPP: Qr", group, Qr);
6169 out:
6170 EC_KEY_free(Pr_ec);
6171 EVP_PKEY_free(Pr);
6172 BN_clear_free(hash_bn);
6173 if (ret_group)
6174 *ret_group = group2;
6175 return Qr;
6176 fail:
6177 EC_POINT_free(Qr);
6178 Qr = NULL;
6179 goto out;
6180 }
6181
6182
6183 #ifdef CONFIG_TESTING_OPTIONS
6184 static int dpp_test_gen_invalid_key(struct wpabuf *msg,
6185 const struct dpp_curve_params *curve)
6186 {
6187 BN_CTX *ctx;
6188 BIGNUM *x, *y;
6189 int ret = -1;
6190 EC_GROUP *group;
6191 EC_POINT *point;
6192
6193 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6194 if (!group)
6195 return -1;
6196
6197 ctx = BN_CTX_new();
6198 point = EC_POINT_new(group);
6199 x = BN_new();
6200 y = BN_new();
6201 if (!ctx || !point || !x || !y)
6202 goto fail;
6203
6204 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
6205 goto fail;
6206
6207 /* Generate a random y coordinate that results in a point that is not
6208 * on the curve. */
6209 for (;;) {
6210 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
6211 goto fail;
6212
6213 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
6214 ctx) != 1) {
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. */
6218 break;
6219 #else /* OPENSSL_IS_BORINGSSL */
6220 goto fail;
6221 #endif /* OPENSSL_IS_BORINGSSL */
6222 }
6223
6224 if (!EC_POINT_is_on_curve(group, point, ctx))
6225 break;
6226 }
6227
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)
6232 goto fail;
6233
6234 ret = 0;
6235 fail:
6236 if (ret < 0)
6237 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
6238 BN_free(x);
6239 BN_free(y);
6240 EC_POINT_free(point);
6241 BN_CTX_free(ctx);
6242
6243 return ret;
6244 }
6245 #endif /* CONFIG_TESTING_OPTIONS */
6246
6247
6248 static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
6249 {
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;
6258 size_t attr_len;
6259 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6260
6261 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
6262
6263 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6264 bnctx = BN_CTX_new();
6265 if (!bnctx)
6266 goto fail;
6267 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
6268 pkex->identifier, bnctx, &group);
6269 if (!Qi)
6270 goto fail;
6271
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;
6276
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);
6282 } else {
6283 pkex->x = dpp_gen_keypair(curve);
6284 }
6285 #else /* CONFIG_TESTING_OPTIONS */
6286 pkex->x = dpp_gen_keypair(curve);
6287 #endif /* CONFIG_TESTING_OPTIONS */
6288 if (!pkex->x)
6289 goto fail;
6290
6291 /* M = X + Qi */
6292 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
6293 if (!X_ec)
6294 goto fail;
6295 X_point = EC_KEY_get0_public_key(X_ec);
6296 if (!X_point)
6297 goto fail;
6298 dpp_debug_print_point("DPP: X", group, X_point);
6299 M = EC_POINT_new(group);
6300 Mx = BN_new();
6301 My = BN_new();
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)
6305 goto fail;
6306 dpp_debug_print_point("DPP: M", group, M);
6307
6308 /* Initiator -> Responder: group, [identifier,] M */
6309 attr_len = 4 + 2;
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);
6314 if (!msg)
6315 goto fail;
6316
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;
6321 }
6322 #endif /* CONFIG_TESTING_OPTIONS */
6323
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);
6328
6329 #ifdef CONFIG_TESTING_OPTIONS
6330 skip_finite_cyclic_group:
6331 #endif /* CONFIG_TESTING_OPTIONS */
6332
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);
6338 }
6339
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");
6343 goto out;
6344 }
6345 #endif /* CONFIG_TESTING_OPTIONS */
6346
6347 /* M in Encrypted Key attribute */
6348 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6349 wpabuf_put_le16(msg, 2 * curve->prime_len);
6350
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)
6355 goto fail;
6356 goto out;
6357 }
6358 #endif /* CONFIG_TESTING_OPTIONS */
6359
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)
6365 goto fail;
6366
6367 out:
6368 wpabuf_free(M_buf);
6369 EC_KEY_free(X_ec);
6370 EC_POINT_free(M);
6371 EC_POINT_free(Qi);
6372 BN_clear_free(Mx);
6373 BN_clear_free(My);
6374 BN_CTX_free(bnctx);
6375 return msg;
6376 fail:
6377 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
6378 wpabuf_free(msg);
6379 msg = NULL;
6380 goto out;
6381 }
6382
6383
6384 static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
6385 {
6386 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
6387 }
6388
6389
6390 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
6391 const u8 *own_mac,
6392 const char *identifier,
6393 const char *code)
6394 {
6395 struct dpp_pkex *pkex;
6396
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;
6402 }
6403 #endif /* CONFIG_TESTING_OPTIONS */
6404
6405 pkex = os_zalloc(sizeof(*pkex));
6406 if (!pkex)
6407 return NULL;
6408 pkex->msg_ctx = msg_ctx;
6409 pkex->initiator = 1;
6410 pkex->own_bi = bi;
6411 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6412 if (identifier) {
6413 pkex->identifier = os_strdup(identifier);
6414 if (!pkex->identifier)
6415 goto fail;
6416 }
6417 pkex->code = os_strdup(code);
6418 if (!pkex->code)
6419 goto fail;
6420 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
6421 if (!pkex->exchange_req)
6422 goto fail;
6423 return pkex;
6424 fail:
6425 dpp_pkex_free(pkex);
6426 return NULL;
6427 }
6428
6429
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)
6434 {
6435 struct wpabuf *msg = NULL;
6436 size_t attr_len;
6437 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6438
6439 /* Initiator -> Responder: DPP Status, [identifier,] N */
6440 attr_len = 4 + 1;
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);
6445 if (!msg)
6446 goto fail;
6447
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");
6451 goto skip_status;
6452 }
6453
6454 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
6455 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
6456 status = 255;
6457 }
6458 #endif /* CONFIG_TESTING_OPTIONS */
6459
6460 /* DPP Status */
6461 dpp_build_attr_status(msg, status);
6462
6463 #ifdef CONFIG_TESTING_OPTIONS
6464 skip_status:
6465 #endif /* CONFIG_TESTING_OPTIONS */
6466
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);
6472 }
6473
6474 if (status != DPP_STATUS_OK)
6475 goto skip_encrypted_key;
6476
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;
6481 }
6482 #endif /* CONFIG_TESTING_OPTIONS */
6483
6484 /* N in Encrypted Key attribute */
6485 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6486 wpabuf_put_le16(msg, 2 * curve->prime_len);
6487
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)
6492 goto fail;
6493 goto skip_encrypted_key;
6494 }
6495 #endif /* CONFIG_TESTING_OPTIONS */
6496
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)
6502 goto fail;
6503
6504 skip_encrypted_key:
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);
6510 }
6511
6512 return msg;
6513 fail:
6514 wpabuf_free(msg);
6515 return NULL;
6516 }
6517
6518
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,
6522 const char *code,
6523 const u8 *Kx, size_t Kx_len,
6524 u8 *z, unsigned int hash_len)
6525 {
6526 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6527 int res;
6528 u8 *info, *pos;
6529 size_t info_len;
6530
6531 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6532 */
6533
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)
6537 return -1;
6538 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
6539 prk, hash_len);
6540 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
6541 info = os_malloc(info_len);
6542 if (!info)
6543 return -1;
6544 pos = info;
6545 os_memcpy(pos, mac_init, ETH_ALEN);
6546 pos += ETH_ALEN;
6547 os_memcpy(pos, mac_resp, ETH_ALEN);
6548 pos += ETH_ALEN;
6549 os_memcpy(pos, Mx, Mx_len);
6550 pos += Mx_len;
6551 os_memcpy(pos, Nx, Nx_len);
6552 pos += Nx_len;
6553 os_memcpy(pos, code, os_strlen(code));
6554
6555 /* HKDF-Expand(PRK, info, L) */
6556 if (hash_len == 32)
6557 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
6558 z, hash_len);
6559 else if (hash_len == 48)
6560 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
6561 z, hash_len);
6562 else if (hash_len == 64)
6563 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
6564 z, hash_len);
6565 else
6566 res = -1;
6567 os_free(info);
6568 os_memset(prk, 0, hash_len);
6569 if (res < 0)
6570 return -1;
6571
6572 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
6573 z, hash_len);
6574 return 0;
6575 }
6576
6577
6578 struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
6579 struct dpp_bootstrap_info *bi,
6580 const u8 *own_mac,
6581 const u8 *peer_mac,
6582 const char *identifier,
6583 const char *code,
6584 const u8 *buf, size_t len)
6585 {
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;
6589 u16 ike_group;
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];
6599 size_t Kx_len;
6600 int res;
6601 EVP_PKEY_CTX *ctx = NULL;
6602
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");
6606 return NULL;
6607 }
6608
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;
6614 }
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;
6619 }
6620 #endif /* CONFIG_TESTING_OPTIONS */
6621
6622 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
6623 &attr_id_len);
6624 if (!attr_id && identifier) {
6625 wpa_printf(MSG_DEBUG,
6626 "DPP: No PKEX code identifier received, but expected one");
6627 return NULL;
6628 }
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");
6633 return NULL;
6634 }
6635
6636 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
6637 &attr_group_len);
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");
6641 return NULL;
6642 }
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));
6649 if (!pkex)
6650 goto fail;
6651 pkex->own_bi = bi;
6652 pkex->failed = 1;
6653 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
6654 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
6655 if (!pkex->exchange_resp)
6656 goto fail;
6657 return pkex;
6658 }
6659
6660 /* M in Encrypted Key attribute */
6661 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
6662 &attr_key_len);
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");
6667 return NULL;
6668 }
6669
6670 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6671 bnctx = BN_CTX_new();
6672 if (!bnctx)
6673 goto fail;
6674 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
6675 &group);
6676 if (!Qi)
6677 goto fail;
6678
6679 /* X' = M - Qi */
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");
6694 bi->pkex_t++;
6695 goto fail;
6696 }
6697 dpp_debug_print_point("DPP: M", group, M);
6698 dpp_debug_print_point("DPP: X'", group, X);
6699
6700 pkex = os_zalloc(sizeof(*pkex));
6701 if (!pkex)
6702 goto fail;
6703 pkex->t = bi->pkex_t;
6704 pkex->msg_ctx = msg_ctx;
6705 pkex->own_bi = bi;
6706 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6707 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
6708 if (identifier) {
6709 pkex->identifier = os_strdup(identifier);
6710 if (!pkex->identifier)
6711 goto fail;
6712 }
6713 pkex->code = os_strdup(code);
6714 if (!pkex->code)
6715 goto fail;
6716
6717 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
6718
6719 X_ec = EC_KEY_new();
6720 if (!X_ec ||
6721 EC_KEY_set_group(X_ec, group) != 1 ||
6722 EC_KEY_set_public_key(X_ec, X) != 1)
6723 goto fail;
6724 pkex->x = EVP_PKEY_new();
6725 if (!pkex->x ||
6726 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
6727 goto fail;
6728
6729 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6730 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
6731 if (!Qr)
6732 goto fail;
6733
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;
6738
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);
6744 } else {
6745 pkex->y = dpp_gen_keypair(curve);
6746 }
6747 #else /* CONFIG_TESTING_OPTIONS */
6748 pkex->y = dpp_gen_keypair(curve);
6749 #endif /* CONFIG_TESTING_OPTIONS */
6750 if (!pkex->y)
6751 goto fail;
6752
6753 /* N = Y + Qr */
6754 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
6755 if (!Y_ec)
6756 goto fail;
6757 Y_point = EC_KEY_get0_public_key(Y_ec);
6758 if (!Y_point)
6759 goto fail;
6760 dpp_debug_print_point("DPP: Y", group, Y_point);
6761 N = EC_POINT_new(group);
6762 Nx = BN_new();
6763 Ny = BN_new();
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)
6767 goto fail;
6768 dpp_debug_print_point("DPP: N", group, N);
6769
6770 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
6771 Nx, Ny);
6772 if (!pkex->exchange_resp)
6773 goto fail;
6774
6775 /* K = y * X' */
6776 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
6777 if (!ctx ||
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));
6786 goto fail;
6787 }
6788
6789 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6790 Kx, Kx_len);
6791
6792 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6793 */
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);
6799 if (res < 0)
6800 goto fail;
6801
6802 pkex->exchange_done = 1;
6803
6804 out:
6805 EVP_PKEY_CTX_free(ctx);
6806 BN_CTX_free(bnctx);
6807 EC_POINT_free(Qi);
6808 EC_POINT_free(Qr);
6809 BN_free(Mx);
6810 BN_free(My);
6811 BN_free(Nx);
6812 BN_free(Ny);
6813 EC_POINT_free(M);
6814 EC_POINT_free(N);
6815 EC_POINT_free(X);
6816 EC_KEY_free(X_ec);
6817 EC_KEY_free(Y_ec);
6818 return pkex;
6819 fail:
6820 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
6821 dpp_pkex_free(pkex);
6822 pkex = NULL;
6823 goto out;
6824 }
6825
6826
6827 static struct wpabuf *
6828 dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
6829 const struct wpabuf *A_pub, const u8 *u)
6830 {
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;
6835 u8 *wrapped;
6836 u8 octet;
6837 const u8 *addr[2];
6838 size_t len[2];
6839
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)
6846 attr_len += 5;
6847 #endif /* CONFIG_TESTING_OPTIONS */
6848 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
6849 if (!clear || !msg)
6850 goto fail;
6851
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;
6856 }
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)
6862 goto fail;
6863 goto skip_bootstrap_key;
6864 }
6865 #endif /* CONFIG_TESTING_OPTIONS */
6866
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);
6871
6872 #ifdef CONFIG_TESTING_OPTIONS
6873 skip_bootstrap_key:
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;
6877 }
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;
6885 }
6886 #endif /* CONFIG_TESTING_OPTIONS */
6887
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);
6892
6893 #ifdef CONFIG_TESTING_OPTIONS
6894 skip_i_auth_tag:
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;
6898 }
6899 #endif /* CONFIG_TESTING_OPTIONS */
6900
6901 addr[0] = wpabuf_head_u8(msg) + 2;
6902 len[0] = DPP_HDR_LEN;
6903 octet = 0;
6904 addr[1] = &octet;
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]);
6908
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);
6912
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)
6917 goto fail;
6918 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6919 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6920
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);
6925 }
6926 skip_wrapped_data:
6927 #endif /* CONFIG_TESTING_OPTIONS */
6928
6929 out:
6930 wpabuf_free(clear);
6931 return msg;
6932
6933 fail:
6934 wpabuf_free(msg);
6935 msg = NULL;
6936 goto out;
6937 }
6938
6939
6940 struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
6941 const u8 *peer_mac,
6942 const u8 *buf, size_t buflen)
6943 {
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];
6956 const u8 *addr[4];
6957 size_t len[4];
6958 u8 u[DPP_MAX_HASH_LEN];
6959 int res;
6960
6961 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
6962 return NULL;
6963
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");
6968 pkex->failed = 1;
6969 return NULL;
6970 }
6971
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;
6976 }
6977 #endif /* CONFIG_TESTING_OPTIONS */
6978
6979 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
6980
6981 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
6982 &attr_status_len);
6983 if (!attr_status || attr_status_len != 1) {
6984 dpp_pkex_fail(pkex, "No DPP Status attribute");
6985 return NULL;
6986 }
6987 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
6988
6989 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
6990 attr_group = dpp_get_attr(buf, buflen,
6991 DPP_ATTR_FINITE_CYCLIC_GROUP,
6992 &attr_group_len);
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));
6997 return NULL;
6998 }
6999 }
7000
7001 if (attr_status[0] != DPP_STATUS_OK) {
7002 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
7003 return NULL;
7004 }
7005
7006 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
7007 &attr_id_len);
7008 if (!attr_id && pkex->identifier) {
7009 wpa_printf(MSG_DEBUG,
7010 "DPP: No PKEX code identifier received, but expected one");
7011 return NULL;
7012 }
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");
7017 return NULL;
7018 }
7019
7020 /* N in Encrypted Key attribute */
7021 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
7022 &attr_key_len);
7023 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
7024 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
7025 return NULL;
7026 }
7027
7028 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7029 bnctx = BN_CTX_new();
7030 if (!bnctx)
7031 goto fail;
7032 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
7033 pkex->identifier, bnctx, &group);
7034 if (!Qr)
7035 goto fail;
7036
7037 /* Y' = N - Qr */
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");
7051 pkex->t++;
7052 goto fail;
7053 }
7054 dpp_debug_print_point("DPP: N", group, N);
7055 dpp_debug_print_point("DPP: Y'", group, Y);
7056
7057 pkex->exchange_done = 1;
7058
7059 /* ECDH: J = a * Y’ */
7060 Y_ec = EC_KEY_new();
7061 if (!Y_ec ||
7062 EC_KEY_set_group(Y_ec, group) != 1 ||
7063 EC_KEY_set_public_key(Y_ec, Y) != 1)
7064 goto fail;
7065 pkex->y = EVP_PKEY_new();
7066 if (!pkex->y ||
7067 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
7068 goto fail;
7069 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7070 if (!ctx ||
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));
7079 goto fail;
7080 }
7081
7082 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7083 Jx, Jx_len);
7084
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)
7090 goto fail;
7091 addr[0] = pkex->own_mac;
7092 len[0] = ETH_ALEN;
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)
7100 goto fail;
7101 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
7102
7103 /* K = x * Y’ */
7104 EVP_PKEY_CTX_free(ctx);
7105 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
7106 if (!ctx ||
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));
7115 goto fail;
7116 }
7117
7118 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7119 Kx, Kx_len);
7120
7121 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7122 */
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);
7129 if (res < 0)
7130 goto fail;
7131
7132 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
7133 if (!msg)
7134 goto fail;
7135
7136 out:
7137 wpabuf_free(A_pub);
7138 wpabuf_free(X_pub);
7139 wpabuf_free(Y_pub);
7140 EC_POINT_free(Qr);
7141 EC_POINT_free(Y);
7142 EC_POINT_free(N);
7143 BN_free(Nx);
7144 BN_free(Ny);
7145 EC_KEY_free(Y_ec);
7146 EVP_PKEY_CTX_free(ctx);
7147 BN_CTX_free(bnctx);
7148 return msg;
7149 fail:
7150 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
7151 goto out;
7152 }
7153
7154
7155 static struct wpabuf *
7156 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
7157 const struct wpabuf *B_pub, const u8 *v)
7158 {
7159 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7160 struct wpabuf *msg = NULL;
7161 const u8 *addr[2];
7162 size_t len[2];
7163 u8 octet;
7164 u8 *wrapped;
7165 struct wpabuf *clear = NULL;
7166 size_t clear_len, attr_len;
7167
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)
7174 attr_len += 5;
7175 #endif /* CONFIG_TESTING_OPTIONS */
7176 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
7177 if (!clear || !msg)
7178 goto fail;
7179
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;
7184 }
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)
7190 goto fail;
7191 goto skip_bootstrap_key;
7192 }
7193 #endif /* CONFIG_TESTING_OPTIONS */
7194
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);
7199
7200 #ifdef CONFIG_TESTING_OPTIONS
7201 skip_bootstrap_key:
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;
7205 }
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;
7213 }
7214 #endif /* CONFIG_TESTING_OPTIONS */
7215
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);
7220
7221 #ifdef CONFIG_TESTING_OPTIONS
7222 skip_r_auth_tag:
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;
7226 }
7227 #endif /* CONFIG_TESTING_OPTIONS */
7228
7229 addr[0] = wpabuf_head_u8(msg) + 2;
7230 len[0] = DPP_HDR_LEN;
7231 octet = 1;
7232 addr[1] = &octet;
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]);
7236
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);
7240
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)
7245 goto fail;
7246 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7247 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
7248
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);
7253 }
7254 skip_wrapped_data:
7255 #endif /* CONFIG_TESTING_OPTIONS */
7256
7257 out:
7258 wpabuf_free(clear);
7259 return msg;
7260
7261 fail:
7262 wpabuf_free(msg);
7263 msg = NULL;
7264 goto out;
7265 }
7266
7267
7268 struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
7269 const u8 *hdr,
7270 const u8 *buf, size_t buflen)
7271 {
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;
7279 const u8 *addr[4];
7280 size_t len[4];
7281 u8 octet;
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];
7287
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");
7292 pkex->failed = 1;
7293 return NULL;
7294 }
7295 #endif /* CONFIG_TESTING_OPTIONS */
7296
7297 if (!pkex->exchange_done || pkex->failed ||
7298 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
7299 goto fail;
7300
7301 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7302 &wrapped_data_len);
7303 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7304 dpp_pkex_fail(pkex,
7305 "Missing or invalid required Wrapped Data attribute");
7306 goto fail;
7307 }
7308
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);
7313 if (!unwrapped)
7314 goto fail;
7315
7316 addr[0] = hdr;
7317 len[0] = DPP_HDR_LEN;
7318 octet = 0;
7319 addr[1] = &octet;
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]);
7323
7324 if (aes_siv_decrypt(pkex->z, curve->hash_len,
7325 wrapped_data, wrapped_data_len,
7326 2, addr, len, unwrapped) < 0) {
7327 dpp_pkex_fail(pkex,
7328 "AES-SIV decryption failed - possible PKEX code mismatch");
7329 pkex->failed = 1;
7330 pkex->t++;
7331 goto fail;
7332 }
7333 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7334 unwrapped, unwrapped_len);
7335
7336 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7337 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
7338 goto fail;
7339 }
7340
7341 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7342 &b_key_len);
7343 if (!b_key || b_key_len != 2 * curve->prime_len) {
7344 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
7345 goto fail;
7346 }
7347 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7348 b_key_len);
7349 if (!pkex->peer_bootstrap_key) {
7350 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
7351 goto fail;
7352 }
7353 dpp_debug_print_key("DPP: Peer bootstrap public key",
7354 pkex->peer_bootstrap_key);
7355
7356 /* ECDH: J' = y * A' */
7357 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
7358 if (!ctx ||
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));
7367 goto fail;
7368 }
7369
7370 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7371 Jx, Jx_len);
7372
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)
7378 goto fail;
7379 addr[0] = pkex->peer_mac;
7380 len[0] = ETH_ALEN;
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)
7388 goto fail;
7389
7390 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
7391 &peer_u_len);
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);
7398 pkex->t++;
7399 goto fail;
7400 }
7401 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
7402
7403 /* ECDH: L = b * X' */
7404 EVP_PKEY_CTX_free(ctx);
7405 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7406 if (!ctx ||
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));
7415 goto fail;
7416 }
7417
7418 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7419 Lx, Lx_len);
7420
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);
7423 if (!B_pub)
7424 goto fail;
7425 addr[0] = pkex->own_mac;
7426 len[0] = ETH_ALEN;
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)
7434 goto fail;
7435 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
7436
7437 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
7438 if (!msg)
7439 goto fail;
7440
7441 out:
7442 EVP_PKEY_CTX_free(ctx);
7443 os_free(unwrapped);
7444 wpabuf_free(A_pub);
7445 wpabuf_free(B_pub);
7446 wpabuf_free(X_pub);
7447 wpabuf_free(Y_pub);
7448 return msg;
7449 fail:
7450 wpa_printf(MSG_DEBUG,
7451 "DPP: PKEX Commit-Reveal Request processing failed");
7452 goto out;
7453 }
7454
7455
7456 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
7457 const u8 *buf, size_t buflen)
7458 {
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;
7462 const u8 *addr[4];
7463 size_t len[4];
7464 u8 octet;
7465 u8 *unwrapped = NULL;
7466 size_t unwrapped_len = 0;
7467 int ret = -1;
7468 u8 v[DPP_MAX_HASH_LEN];
7469 size_t Lx_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;
7473
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");
7478 pkex->failed = 1;
7479 goto fail;
7480 }
7481 #endif /* CONFIG_TESTING_OPTIONS */
7482
7483 if (!pkex->exchange_done || pkex->failed ||
7484 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
7485 goto fail;
7486
7487 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7488 &wrapped_data_len);
7489 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7490 dpp_pkex_fail(pkex,
7491 "Missing or invalid required Wrapped Data attribute");
7492 goto fail;
7493 }
7494
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);
7499 if (!unwrapped)
7500 goto fail;
7501
7502 addr[0] = hdr;
7503 len[0] = DPP_HDR_LEN;
7504 octet = 1;
7505 addr[1] = &octet;
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]);
7509
7510 if (aes_siv_decrypt(pkex->z, curve->hash_len,
7511 wrapped_data, wrapped_data_len,
7512 2, addr, len, unwrapped) < 0) {
7513 dpp_pkex_fail(pkex,
7514 "AES-SIV decryption failed - possible PKEX code mismatch");
7515 pkex->t++;
7516 goto fail;
7517 }
7518 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7519 unwrapped, unwrapped_len);
7520
7521 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7522 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
7523 goto fail;
7524 }
7525
7526 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7527 &b_key_len);
7528 if (!b_key || b_key_len != 2 * curve->prime_len) {
7529 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
7530 goto fail;
7531 }
7532 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7533 b_key_len);
7534 if (!pkex->peer_bootstrap_key) {
7535 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
7536 goto fail;
7537 }
7538 dpp_debug_print_key("DPP: Peer bootstrap public key",
7539 pkex->peer_bootstrap_key);
7540
7541 /* ECDH: L' = x * B' */
7542 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
7543 if (!ctx ||
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));
7552 goto fail;
7553 }
7554
7555 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7556 Lx, Lx_len);
7557
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)
7563 goto fail;
7564 addr[0] = pkex->peer_mac;
7565 len[0] = ETH_ALEN;
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)
7573 goto fail;
7574
7575 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
7576 &peer_v_len);
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);
7583 pkex->t++;
7584 goto fail;
7585 }
7586 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
7587
7588 ret = 0;
7589 out:
7590 wpabuf_free(B_pub);
7591 wpabuf_free(X_pub);
7592 wpabuf_free(Y_pub);
7593 EVP_PKEY_CTX_free(ctx);
7594 os_free(unwrapped);
7595 return ret;
7596 fail:
7597 goto out;
7598 }
7599
7600
7601 void dpp_pkex_free(struct dpp_pkex *pkex)
7602 {
7603 if (!pkex)
7604 return;
7605
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);
7613 os_free(pkex);
7614 }
7615
7616
7617 #ifdef CONFIG_TESTING_OPTIONS
7618 char * dpp_corrupt_connector_signature(const char *connector)
7619 {
7620 char *tmp, *pos, *signed3 = NULL;
7621 unsigned char *signature = NULL;
7622 size_t signature_len = 0, signed3_len;
7623
7624 tmp = os_zalloc(os_strlen(connector) + 5);
7625 if (!tmp)
7626 goto fail;
7627 os_memcpy(tmp, connector, os_strlen(connector));
7628
7629 pos = os_strchr(tmp, '.');
7630 if (!pos)
7631 goto fail;
7632
7633 pos = os_strchr(pos + 1, '.');
7634 if (!pos)
7635 goto fail;
7636 pos++;
7637
7638 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
7639 pos);
7640 signature = base64_url_decode((const unsigned char *) pos,
7641 os_strlen(pos), &signature_len);
7642 if (!signature || signature_len == 0)
7643 goto fail;
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,
7650 &signed3_len, 0);
7651 if (!signed3)
7652 goto fail;
7653 os_memcpy(pos, signed3, signed3_len);
7654 pos[signed3_len] = '\0';
7655 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
7656 pos);
7657
7658 out:
7659 os_free(signature);
7660 os_free(signed3);
7661 return tmp;
7662 fail:
7663 os_free(tmp);
7664 tmp = NULL;
7665 goto out;
7666 }
7667 #endif /* CONFIG_TESTING_OPTIONS */