]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/common/dpp.c
DPP: Protocol testing for invalid Peer Discovery Req/Resp values
[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
34 static int dpp_test_gen_invalid_key(struct wpabuf *msg,
35 const struct dpp_curve_params *curve);
36 #endif /* CONFIG_TESTING_OPTIONS */
37
38 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
39 /* Compatibility wrappers for older versions. */
40
41 static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
42 {
43 sig->r = r;
44 sig->s = s;
45 return 1;
46 }
47
48
49 static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
50 const BIGNUM **ps)
51 {
52 if (pr)
53 *pr = sig->r;
54 if (ps)
55 *ps = sig->s;
56 }
57
58 #endif
59
60
61 static const struct dpp_curve_params dpp_curves[] = {
62 /* The mandatory to support and the default NIST P-256 curve needs to
63 * be the first entry on this list. */
64 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
65 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
66 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
67 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
68 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
69 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
70 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
71 };
72
73
74 /* Role-specific elements for PKEX */
75
76 /* NIST P-256 */
77 static const u8 pkex_init_x_p256[32] = {
78 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
79 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
80 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
81 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
82 };
83 static const u8 pkex_init_y_p256[32] = {
84 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
85 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
86 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
87 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
88 };
89 static const u8 pkex_resp_x_p256[32] = {
90 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
91 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
92 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
93 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
94 };
95 static const u8 pkex_resp_y_p256[32] = {
96 0x26, 0x04, 0x09, 0x45, 0x0a, 0x05, 0x20, 0xe7,
97 0xa7, 0x27, 0xc1, 0x36, 0x76, 0x85, 0xca, 0x3e,
98 0x42, 0x16, 0xf4, 0x89, 0x85, 0x34, 0x6e, 0xd5,
99 0x17, 0xde, 0xc0, 0xb8, 0xad, 0xfd, 0xb2, 0x98
100 };
101
102 /* NIST P-384 */
103 static const u8 pkex_init_x_p384[48] = {
104 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
105 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
106 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
107 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
108 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
109 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
110 };
111 static const u8 pkex_init_y_p384[48] = {
112 0x89, 0xd0, 0x97, 0x7b, 0x59, 0x4f, 0xa6, 0xd6,
113 0x7c, 0x5d, 0x93, 0x5b, 0x93, 0xc4, 0x07, 0xa9,
114 0x89, 0xee, 0xd5, 0xcd, 0x6f, 0x42, 0xf8, 0x38,
115 0xc8, 0xc6, 0x62, 0x24, 0x69, 0x0c, 0xd4, 0x48,
116 0xd8, 0x44, 0xd6, 0xc2, 0xe8, 0xcc, 0x62, 0x6b,
117 0x3c, 0x25, 0x53, 0xba, 0x4f, 0x71, 0xf8, 0xe7
118 };
119 static const u8 pkex_resp_x_p384[48] = {
120 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
121 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
122 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
123 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
124 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
125 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
126 };
127 static const u8 pkex_resp_y_p384[48] = {
128 0x54, 0x58, 0x20, 0xad, 0x55, 0x1d, 0xca, 0xf3,
129 0x1c, 0x8a, 0xcd, 0x19, 0x40, 0xf9, 0x37, 0x83,
130 0xc7, 0xd6, 0xb3, 0x13, 0x7d, 0x53, 0x28, 0x5c,
131 0xf6, 0x2d, 0xf1, 0xdd, 0xa5, 0x8b, 0xad, 0x5d,
132 0x81, 0xab, 0xb1, 0x00, 0x39, 0xd6, 0xcc, 0x9c,
133 0xea, 0x1e, 0x84, 0x1d, 0xbf, 0xe3, 0x35, 0xf9
134 };
135
136 /* NIST P-521 */
137 static const u8 pkex_init_x_p521[66] = {
138 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
139 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
140 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
141 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
142 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
143 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
144 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
145 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
146 0x97, 0x76
147 };
148 static const u8 pkex_init_y_p521[66] = {
149 0x01, 0x4c, 0x71, 0xfd, 0x1b, 0xd5, 0x9c, 0xa6,
150 0xed, 0x39, 0xef, 0x45, 0xc5, 0x06, 0xfd, 0x66,
151 0xc0, 0xeb, 0x0f, 0xbf, 0x21, 0xa3, 0x36, 0x74,
152 0xfd, 0xaa, 0x05, 0x6e, 0x4e, 0x33, 0x95, 0x42,
153 0x1a, 0x9d, 0x3f, 0x3a, 0x1c, 0x5e, 0xa8, 0x60,
154 0xf7, 0xe5, 0x59, 0x1d, 0x07, 0xaa, 0x6f, 0x40,
155 0x0a, 0x59, 0x3c, 0x27, 0xad, 0xe0, 0x48, 0xfd,
156 0xd1, 0x83, 0x37, 0x4c, 0xdf, 0xe1, 0x86, 0x72,
157 0xfc, 0x57
158 };
159 static const u8 pkex_resp_x_p521[66] = {
160 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
161 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
162 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
163 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
164 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
165 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
166 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
167 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
168 0x84, 0xb4
169 };
170 static const u8 pkex_resp_y_p521[66] = {
171 0x01, 0xb9, 0x9c, 0xc6, 0x41, 0x32, 0x5b, 0xd2,
172 0x35, 0xd8, 0x8b, 0x2b, 0xe4, 0x6e, 0xcc, 0xdf,
173 0x7c, 0x38, 0xc4, 0x5b, 0xf6, 0x74, 0x71, 0x5c,
174 0x77, 0x16, 0x8a, 0x80, 0xa9, 0x84, 0xc7, 0x7b,
175 0x9d, 0xfd, 0x83, 0x6f, 0xae, 0xf8, 0x24, 0x16,
176 0x2f, 0x21, 0x25, 0x65, 0xa2, 0x1a, 0x6b, 0x2d,
177 0x30, 0x62, 0xb3, 0xcc, 0x6e, 0x59, 0x3c, 0x7f,
178 0x58, 0x91, 0x81, 0x72, 0x07, 0x8c, 0x91, 0xac,
179 0x31, 0x1e
180 };
181
182 /* Brainpool P-256r1 */
183 static const u8 pkex_init_x_bp_p256r1[32] = {
184 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
185 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
186 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
187 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
188 };
189 static const u8 pkex_init_y_bp_p256r1[32] = {
190 0x16, 0x30, 0x68, 0x32, 0x3b, 0xb0, 0x21, 0xee,
191 0xeb, 0xf7, 0xb6, 0x7c, 0xae, 0x52, 0x26, 0x42,
192 0x59, 0x28, 0x58, 0xb6, 0x14, 0x90, 0xed, 0x69,
193 0xd0, 0x67, 0xea, 0x25, 0x60, 0x0f, 0xa9, 0x6c
194 };
195 static const u8 pkex_resp_x_bp_p256r1[32] = {
196 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
197 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
198 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
199 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
200 };
201 static const u8 pkex_resp_y_bp_p256r1[32] = {
202 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
203 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
204 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
205 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
206 };
207
208 /* Brainpool P-384r1 */
209 static const u8 pkex_init_x_bp_p384r1[48] = {
210 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
211 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
212 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
213 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
214 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
215 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
216 };
217 static const u8 pkex_init_y_bp_p384r1[48] = {
218 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
219 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
220 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
221 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
222 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
223 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
224 };
225 static const u8 pkex_resp_x_bp_p384r1[48] = {
226 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
227 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
228 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
229 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
230 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
231 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
232 };
233 static const u8 pkex_resp_y_bp_p384r1[48] = {
234 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
235 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
236 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
237 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
238 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
239 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
240 };
241
242 /* Brainpool P-512r1 */
243 static const u8 pkex_init_x_bp_p512r1[64] = {
244 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
245 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
246 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
247 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
248 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
249 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
250 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
251 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
252 };
253 static const u8 pkex_init_y_bp_p512r1[64] = {
254 0x5a, 0x28, 0x01, 0xbe, 0x96, 0x82, 0x4e, 0xf6,
255 0xfa, 0xed, 0x7d, 0xfd, 0x48, 0x8b, 0x48, 0x4e,
256 0xd1, 0x97, 0x87, 0xc4, 0x05, 0x5d, 0x15, 0x2a,
257 0xf4, 0x91, 0x4b, 0x75, 0x90, 0xd9, 0x34, 0x2c,
258 0x3c, 0x12, 0xf2, 0xf5, 0x25, 0x94, 0x24, 0x34,
259 0xa7, 0x6d, 0x66, 0xbc, 0x27, 0xa4, 0xa0, 0x8d,
260 0xd5, 0xe1, 0x54, 0xa3, 0x55, 0x26, 0xd4, 0x14,
261 0x17, 0x0f, 0xc1, 0xc7, 0x3d, 0x68, 0x7f, 0x5a
262 };
263 static const u8 pkex_resp_x_bp_p512r1[64] = {
264 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
265 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
266 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
267 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
268 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
269 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
270 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
271 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
272 };
273 static const u8 pkex_resp_y_bp_p512r1[64] = {
274 0x2a, 0xbe, 0x59, 0xe6, 0xc4, 0xb3, 0xd8, 0x09,
275 0x66, 0x89, 0x0a, 0x2d, 0x19, 0xf0, 0x9c, 0x9f,
276 0xb4, 0xab, 0x8f, 0x50, 0x68, 0x3c, 0x74, 0x64,
277 0x4e, 0x19, 0x55, 0x81, 0x9b, 0x48, 0x5c, 0xf4,
278 0x12, 0x8d, 0xb9, 0xd8, 0x02, 0x5b, 0xe1, 0x26,
279 0x7e, 0x19, 0x5c, 0xfd, 0x70, 0xf7, 0x4b, 0xdc,
280 0xb5, 0x5d, 0xc1, 0x7a, 0xe9, 0xd1, 0x05, 0x2e,
281 0xd1, 0xfd, 0x2f, 0xce, 0x63, 0x77, 0x48, 0x2c
282 };
283
284
285 static int dpp_hash_vector(const struct dpp_curve_params *curve,
286 size_t num_elem, const u8 *addr[], const size_t *len,
287 u8 *mac)
288 {
289 if (curve->hash_len == 32)
290 return sha256_vector(num_elem, addr, len, mac);
291 if (curve->hash_len == 48)
292 return sha384_vector(num_elem, addr, len, mac);
293 if (curve->hash_len == 64)
294 return sha512_vector(num_elem, addr, len, mac);
295 return -1;
296 }
297
298
299 static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
300 const char *label, u8 *out, size_t outlen)
301 {
302 if (hash_len == 32)
303 return hmac_sha256_kdf(secret, secret_len, NULL,
304 (const u8 *) label, os_strlen(label),
305 out, outlen);
306 if (hash_len == 48)
307 return hmac_sha384_kdf(secret, secret_len, NULL,
308 (const u8 *) label, os_strlen(label),
309 out, outlen);
310 if (hash_len == 64)
311 return hmac_sha512_kdf(secret, secret_len, NULL,
312 (const u8 *) label, os_strlen(label),
313 out, outlen);
314 return -1;
315 }
316
317
318 static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
319 size_t num_elem, const u8 *addr[],
320 const size_t *len, u8 *mac)
321 {
322 if (hash_len == 32)
323 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
324 mac);
325 if (hash_len == 48)
326 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
327 mac);
328 if (hash_len == 64)
329 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
330 mac);
331 return -1;
332 }
333
334
335 static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
336 const u8 *data, size_t data_len, u8 *mac)
337 {
338 if (hash_len == 32)
339 return hmac_sha256(key, key_len, data, data_len, mac);
340 if (hash_len == 48)
341 return hmac_sha384(key, key_len, data, data_len, mac);
342 if (hash_len == 64)
343 return hmac_sha512(key, key_len, data, data_len, mac);
344 return -1;
345 }
346
347
348 static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
349 {
350 int num_bytes, offset;
351
352 num_bytes = BN_num_bytes(bn);
353 if ((size_t) num_bytes > len)
354 return -1;
355 offset = len - num_bytes;
356 os_memset(pos, 0, offset);
357 BN_bn2bin(bn, pos + offset);
358 return 0;
359 }
360
361
362 static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
363 {
364 int len, res;
365 EC_KEY *eckey;
366 struct wpabuf *buf;
367 unsigned char *pos;
368
369 eckey = EVP_PKEY_get1_EC_KEY(pkey);
370 if (!eckey)
371 return NULL;
372 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
373 len = i2o_ECPublicKey(eckey, NULL);
374 if (len <= 0) {
375 wpa_printf(MSG_ERROR,
376 "DDP: Failed to determine public key encoding length");
377 EC_KEY_free(eckey);
378 return NULL;
379 }
380
381 buf = wpabuf_alloc(len);
382 if (!buf) {
383 EC_KEY_free(eckey);
384 return NULL;
385 }
386
387 pos = wpabuf_put(buf, len);
388 res = i2o_ECPublicKey(eckey, &pos);
389 EC_KEY_free(eckey);
390 if (res != len) {
391 wpa_printf(MSG_ERROR,
392 "DDP: Failed to encode public key (res=%d/%d)",
393 res, len);
394 wpabuf_free(buf);
395 return NULL;
396 }
397
398 if (!prefix) {
399 /* Remove 0x04 prefix to match DPP definition */
400 pos = wpabuf_mhead(buf);
401 os_memmove(pos, pos + 1, len - 1);
402 buf->used--;
403 }
404
405 return buf;
406 }
407
408
409 static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
410 const u8 *buf_x, const u8 *buf_y,
411 size_t len)
412 {
413 EC_KEY *eckey = NULL;
414 BN_CTX *ctx;
415 EC_POINT *point = NULL;
416 BIGNUM *x = NULL, *y = NULL;
417 EVP_PKEY *pkey = NULL;
418
419 ctx = BN_CTX_new();
420 if (!ctx) {
421 wpa_printf(MSG_ERROR, "DPP: Out of memory");
422 return NULL;
423 }
424
425 point = EC_POINT_new(group);
426 x = BN_bin2bn(buf_x, len, NULL);
427 y = BN_bin2bn(buf_y, len, NULL);
428 if (!point || !x || !y) {
429 wpa_printf(MSG_ERROR, "DPP: Out of memory");
430 goto fail;
431 }
432
433 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
434 wpa_printf(MSG_ERROR,
435 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
436 ERR_error_string(ERR_get_error(), NULL));
437 goto fail;
438 }
439
440 if (!EC_POINT_is_on_curve(group, point, ctx) ||
441 EC_POINT_is_at_infinity(group, point)) {
442 wpa_printf(MSG_ERROR, "DPP: Invalid point");
443 goto fail;
444 }
445
446 eckey = EC_KEY_new();
447 if (!eckey ||
448 EC_KEY_set_group(eckey, group) != 1 ||
449 EC_KEY_set_public_key(eckey, point) != 1) {
450 wpa_printf(MSG_ERROR,
451 "DPP: Failed to set EC_KEY: %s",
452 ERR_error_string(ERR_get_error(), NULL));
453 goto fail;
454 }
455 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
456
457 pkey = EVP_PKEY_new();
458 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
459 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
460 goto fail;
461 }
462
463 out:
464 BN_free(x);
465 BN_free(y);
466 EC_KEY_free(eckey);
467 EC_POINT_free(point);
468 BN_CTX_free(ctx);
469 return pkey;
470 fail:
471 EVP_PKEY_free(pkey);
472 pkey = NULL;
473 goto out;
474 }
475
476
477 static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
478 const u8 *buf, size_t len)
479 {
480 EC_KEY *eckey;
481 const EC_GROUP *group;
482 EVP_PKEY *pkey = NULL;
483
484 if (len & 1)
485 return NULL;
486
487 eckey = EVP_PKEY_get1_EC_KEY(group_key);
488 if (!eckey) {
489 wpa_printf(MSG_ERROR,
490 "DPP: Could not get EC_KEY from group_key");
491 return NULL;
492 }
493
494 group = EC_KEY_get0_group(eckey);
495 if (group)
496 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
497 len / 2);
498 else
499 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
500
501 EC_KEY_free(eckey);
502 return pkey;
503 }
504
505
506 static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
507 {
508 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
509 }
510
511
512 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
513 size_t len)
514 {
515 struct wpabuf *msg;
516
517 msg = wpabuf_alloc(8 + len);
518 if (!msg)
519 return NULL;
520 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
521 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
522 wpabuf_put_be24(msg, OUI_WFA);
523 wpabuf_put_u8(msg, DPP_OUI_TYPE);
524 wpabuf_put_u8(msg, 1); /* Crypto Suite */
525 wpabuf_put_u8(msg, type);
526 return msg;
527 }
528
529
530 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
531 {
532 u16 id, alen;
533 const u8 *pos = buf, *end = buf + len;
534
535 while (end - pos >= 4) {
536 id = WPA_GET_LE16(pos);
537 pos += 2;
538 alen = WPA_GET_LE16(pos);
539 pos += 2;
540 if (alen > end - pos)
541 return NULL;
542 if (id == req_id) {
543 *ret_len = alen;
544 return pos;
545 }
546 pos += alen;
547 }
548
549 return NULL;
550 }
551
552
553 int dpp_check_attrs(const u8 *buf, size_t len)
554 {
555 const u8 *pos, *end;
556 int wrapped_data = 0;
557
558 pos = buf;
559 end = buf + len;
560 while (end - pos >= 4) {
561 u16 id, alen;
562
563 id = WPA_GET_LE16(pos);
564 pos += 2;
565 alen = WPA_GET_LE16(pos);
566 pos += 2;
567 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
568 id, alen);
569 if (alen > end - pos) {
570 wpa_printf(MSG_DEBUG,
571 "DPP: Truncated message - not enough room for the attribute - dropped");
572 return -1;
573 }
574 if (wrapped_data) {
575 wpa_printf(MSG_DEBUG,
576 "DPP: An unexpected attribute included after the Wrapped Data attribute");
577 return -1;
578 }
579 if (id == DPP_ATTR_WRAPPED_DATA)
580 wrapped_data = 1;
581 pos += alen;
582 }
583
584 if (end != pos) {
585 wpa_printf(MSG_DEBUG,
586 "DPP: Unexpected octets (%d) after the last attribute",
587 (int) (end - pos));
588 return -1;
589 }
590
591 return 0;
592 }
593
594
595 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
596 {
597 if (!info)
598 return;
599 os_free(info->uri);
600 os_free(info->info);
601 EVP_PKEY_free(info->pubkey);
602 os_free(info);
603 }
604
605
606 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
607 {
608 switch (type) {
609 case DPP_BOOTSTRAP_QR_CODE:
610 return "QRCODE";
611 case DPP_BOOTSTRAP_PKEX:
612 return "PKEX";
613 }
614 return "??";
615 }
616
617
618 static int dpp_uri_valid_info(const char *info)
619 {
620 while (*info) {
621 unsigned char val = *info++;
622
623 if (val < 0x20 || val > 0x7e || val == 0x3b)
624 return 0;
625 }
626
627 return 1;
628 }
629
630
631 static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
632 {
633 bi->uri = os_strdup(uri);
634 return bi->uri ? 0 : -1;
635 }
636
637
638 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
639 const char *chan_list)
640 {
641 const char *pos = chan_list;
642 int opclass, channel, freq;
643
644 while (pos && *pos && *pos != ';') {
645 opclass = atoi(pos);
646 if (opclass <= 0)
647 goto fail;
648 pos = os_strchr(pos, '/');
649 if (!pos)
650 goto fail;
651 pos++;
652 channel = atoi(pos);
653 if (channel <= 0)
654 goto fail;
655 while (*pos >= '0' && *pos <= '9')
656 pos++;
657 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
658 wpa_printf(MSG_DEBUG,
659 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
660 opclass, channel, freq);
661 if (freq < 0) {
662 wpa_printf(MSG_DEBUG,
663 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
664 opclass, channel);
665 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
666 wpa_printf(MSG_DEBUG,
667 "DPP: Too many channels in URI channel-list - ignore list");
668 bi->num_freq = 0;
669 break;
670 } else {
671 bi->freq[bi->num_freq++] = freq;
672 }
673
674 if (*pos == ';' || *pos == '\0')
675 break;
676 if (*pos != ',')
677 goto fail;
678 pos++;
679 }
680
681 return 0;
682 fail:
683 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
684 return -1;
685 }
686
687
688 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
689 {
690 if (!mac)
691 return 0;
692
693 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
694 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
695 return -1;
696 }
697
698 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
699
700 return 0;
701 }
702
703
704 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
705 {
706 const char *end;
707
708 if (!info)
709 return 0;
710
711 end = os_strchr(info, ';');
712 if (!end)
713 end = info + os_strlen(info);
714 bi->info = os_malloc(end - info + 1);
715 if (!bi->info)
716 return -1;
717 os_memcpy(bi->info, info, end - info);
718 bi->info[end - info] = '\0';
719 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
720 if (!dpp_uri_valid_info(bi->info)) {
721 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
722 return -1;
723 }
724
725 return 0;
726 }
727
728
729 static const struct dpp_curve_params *
730 dpp_get_curve_oid(const ASN1_OBJECT *poid)
731 {
732 ASN1_OBJECT *oid;
733 int i;
734
735 for (i = 0; dpp_curves[i].name; i++) {
736 oid = OBJ_txt2obj(dpp_curves[i].name, 0);
737 if (oid && OBJ_cmp(poid, oid) == 0)
738 return &dpp_curves[i];
739 }
740 return NULL;
741 }
742
743
744 static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
745 {
746 int i, tmp;
747
748 if (!nid)
749 return NULL;
750 for (i = 0; dpp_curves[i].name; i++) {
751 tmp = OBJ_txt2nid(dpp_curves[i].name);
752 if (tmp == nid)
753 return &dpp_curves[i];
754 }
755 return NULL;
756 }
757
758
759 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
760 {
761 const char *end;
762 u8 *data;
763 size_t data_len;
764 EVP_PKEY *pkey;
765 const unsigned char *p;
766 int res;
767 X509_PUBKEY *pub = NULL;
768 ASN1_OBJECT *ppkalg;
769 const unsigned char *pk;
770 int ppklen;
771 X509_ALGOR *pa;
772 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
773 ASN1_OBJECT *pa_oid;
774 #else
775 const ASN1_OBJECT *pa_oid;
776 #endif
777 const void *pval;
778 int ptype;
779 const ASN1_OBJECT *poid;
780 char buf[100];
781
782 end = os_strchr(info, ';');
783 if (!end)
784 return -1;
785
786 data = base64_decode((const unsigned char *) info, end - info,
787 &data_len);
788 if (!data) {
789 wpa_printf(MSG_DEBUG,
790 "DPP: Invalid base64 encoding on URI public-key");
791 return -1;
792 }
793 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
794 data, data_len);
795
796 if (sha256_vector(1, (const u8 **) &data, &data_len,
797 bi->pubkey_hash) < 0) {
798 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
799 return -1;
800 }
801 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
802 bi->pubkey_hash, SHA256_MAC_LEN);
803
804 /* DER encoded ASN.1 SubjectPublicKeyInfo
805 *
806 * SubjectPublicKeyInfo ::= SEQUENCE {
807 * algorithm AlgorithmIdentifier,
808 * subjectPublicKey BIT STRING }
809 *
810 * AlgorithmIdentifier ::= SEQUENCE {
811 * algorithm OBJECT IDENTIFIER,
812 * parameters ANY DEFINED BY algorithm OPTIONAL }
813 *
814 * subjectPublicKey = compressed format public key per ANSI X9.63
815 * algorithm = ecPublicKey (1.2.840.10045.2.1)
816 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
817 * prime256v1 (1.2.840.10045.3.1.7)
818 */
819
820 p = data;
821 pkey = d2i_PUBKEY(NULL, &p, data_len);
822 os_free(data);
823
824 if (!pkey) {
825 wpa_printf(MSG_DEBUG,
826 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
827 return -1;
828 }
829
830 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
831 wpa_printf(MSG_DEBUG,
832 "DPP: SubjectPublicKeyInfo does not describe an EC key");
833 EVP_PKEY_free(pkey);
834 return -1;
835 }
836
837 res = X509_PUBKEY_set(&pub, pkey);
838 if (res != 1) {
839 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
840 goto fail;
841 }
842
843 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
844 if (res != 1) {
845 wpa_printf(MSG_DEBUG,
846 "DPP: Could not extract SubjectPublicKeyInfo parameters");
847 goto fail;
848 }
849 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
850 if (res < 0 || (size_t) res >= sizeof(buf)) {
851 wpa_printf(MSG_DEBUG,
852 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
853 goto fail;
854 }
855 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
856 if (os_strcmp(buf, "id-ecPublicKey") != 0) {
857 wpa_printf(MSG_DEBUG,
858 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
859 goto fail;
860 }
861
862 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
863 if (ptype != V_ASN1_OBJECT) {
864 wpa_printf(MSG_DEBUG,
865 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
866 goto fail;
867 }
868 poid = pval;
869 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
870 if (res < 0 || (size_t) res >= sizeof(buf)) {
871 wpa_printf(MSG_DEBUG,
872 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
873 goto fail;
874 }
875 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
876 bi->curve = dpp_get_curve_oid(poid);
877 if (!bi->curve) {
878 wpa_printf(MSG_DEBUG,
879 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
880 buf);
881 goto fail;
882 }
883
884 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
885
886 X509_PUBKEY_free(pub);
887 bi->pubkey = pkey;
888 return 0;
889 fail:
890 X509_PUBKEY_free(pub);
891 EVP_PKEY_free(pkey);
892 return -1;
893 }
894
895
896 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
897 {
898 const char *pos = uri;
899 const char *end;
900 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
901 struct dpp_bootstrap_info *bi;
902
903 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
904
905 if (os_strncmp(pos, "DPP:", 4) != 0) {
906 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
907 return NULL;
908 }
909 pos += 4;
910
911 for (;;) {
912 end = os_strchr(pos, ';');
913 if (!end)
914 break;
915
916 if (end == pos) {
917 /* Handle terminating ";;" and ignore unexpected ";"
918 * for parsing robustness. */
919 pos++;
920 continue;
921 }
922
923 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
924 chan_list = pos + 2;
925 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
926 mac = pos + 2;
927 else if (pos[0] == 'I' && pos[1] == ':' && !info)
928 info = pos + 2;
929 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
930 pk = pos + 2;
931 else
932 wpa_hexdump_ascii(MSG_DEBUG,
933 "DPP: Ignore unrecognized URI parameter",
934 pos, end - pos);
935 pos = end + 1;
936 }
937
938 if (!pk) {
939 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
940 return NULL;
941 }
942
943 bi = os_zalloc(sizeof(*bi));
944 if (!bi)
945 return NULL;
946
947 if (dpp_clone_uri(bi, uri) < 0 ||
948 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
949 dpp_parse_uri_mac(bi, mac) < 0 ||
950 dpp_parse_uri_info(bi, info) < 0 ||
951 dpp_parse_uri_pk(bi, pk) < 0) {
952 dpp_bootstrap_info_free(bi);
953 bi = NULL;
954 }
955
956 return bi;
957 }
958
959
960 struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
961 {
962 struct dpp_bootstrap_info *bi;
963
964 bi = dpp_parse_uri(uri);
965 if (bi)
966 bi->type = DPP_BOOTSTRAP_QR_CODE;
967 return bi;
968 }
969
970
971 static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
972 {
973 EC_KEY *eckey;
974 BIO *out;
975 size_t rlen;
976 char *txt;
977 int res;
978 unsigned char *der = NULL;
979 int der_len;
980
981 out = BIO_new(BIO_s_mem());
982 if (!out)
983 return;
984
985 EVP_PKEY_print_private(out, key, 0, NULL);
986 rlen = BIO_ctrl_pending(out);
987 txt = os_malloc(rlen + 1);
988 if (txt) {
989 res = BIO_read(out, txt, rlen);
990 if (res > 0) {
991 txt[res] = '\0';
992 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
993 }
994 os_free(txt);
995 }
996 BIO_free(out);
997
998 eckey = EVP_PKEY_get1_EC_KEY(key);
999 if (!eckey)
1000 return;
1001
1002 der_len = i2d_ECPrivateKey(eckey, &der);
1003 if (der_len > 0)
1004 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1005 OPENSSL_free(der);
1006 if (der_len <= 0) {
1007 der = NULL;
1008 der_len = i2d_EC_PUBKEY(eckey, &der);
1009 if (der_len > 0)
1010 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1011 OPENSSL_free(der);
1012 }
1013
1014 EC_KEY_free(eckey);
1015 }
1016
1017
1018 static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1019 {
1020 #ifdef OPENSSL_IS_BORINGSSL
1021 EVP_PKEY_CTX *kctx = NULL;
1022 const EC_GROUP *group;
1023 EC_KEY *ec_params;
1024 #else
1025 EVP_PKEY_CTX *pctx, *kctx = NULL;
1026 #endif
1027 EVP_PKEY *params = NULL, *key = NULL;
1028 int nid;
1029
1030 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1031
1032 nid = OBJ_txt2nid(curve->name);
1033 if (nid == NID_undef) {
1034 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1035 return NULL;
1036 }
1037 #ifdef OPENSSL_IS_BORINGSSL
1038 group = EC_GROUP_new_by_curve_name(nid);
1039 ec_params = EC_KEY_new();
1040 if (!ec_params || EC_KEY_set_group(ec_params, group) != 1) {
1041 wpa_printf(MSG_ERROR,
1042 "DPP: Failed to generate EC_KEY parameters");
1043 goto fail;
1044 }
1045 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
1046 params = EVP_PKEY_new();
1047 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
1048 wpa_printf(MSG_ERROR,
1049 "DPP: Failed to generate EVP_PKEY parameters");
1050 goto fail;
1051 }
1052 #else
1053 pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
1054 if (!pctx ||
1055 EVP_PKEY_paramgen_init(pctx) != 1 ||
1056 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1 ||
1057 EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE) != 1 ||
1058 EVP_PKEY_paramgen(pctx, &params) != 1) {
1059 wpa_printf(MSG_ERROR,
1060 "DPP: Failed to generate EVP_PKEY parameters");
1061 EVP_PKEY_CTX_free(pctx);
1062 goto fail;
1063 }
1064 EVP_PKEY_CTX_free(pctx);
1065 #endif
1066
1067 kctx = EVP_PKEY_CTX_new(params, NULL);
1068 if (!kctx ||
1069 EVP_PKEY_keygen_init(kctx) != 1 ||
1070 EVP_PKEY_keygen(kctx, &key) != 1) {
1071 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
1072 goto fail;
1073 }
1074
1075 if (wpa_debug_show_keys)
1076 dpp_debug_print_key("Own generated key", key);
1077
1078 EVP_PKEY_free(params);
1079 EVP_PKEY_CTX_free(kctx);
1080 return key;
1081 fail:
1082 EVP_PKEY_CTX_free(kctx);
1083 EVP_PKEY_free(params);
1084 return NULL;
1085 }
1086
1087
1088 static const struct dpp_curve_params *
1089 dpp_get_curve_name(const char *name)
1090 {
1091 int i;
1092
1093 for (i = 0; dpp_curves[i].name; i++) {
1094 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
1095 (dpp_curves[i].jwk_crv &&
1096 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
1097 return &dpp_curves[i];
1098 }
1099 return NULL;
1100 }
1101
1102
1103 static const struct dpp_curve_params *
1104 dpp_get_curve_jwk_crv(const char *name)
1105 {
1106 int i;
1107
1108 for (i = 0; dpp_curves[i].name; i++) {
1109 if (dpp_curves[i].jwk_crv &&
1110 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
1111 return &dpp_curves[i];
1112 }
1113 return NULL;
1114 }
1115
1116
1117 static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1118 const u8 *privkey, size_t privkey_len)
1119 {
1120 EVP_PKEY *pkey;
1121 EC_KEY *eckey;
1122 const EC_GROUP *group;
1123 int nid;
1124
1125 pkey = EVP_PKEY_new();
1126 if (!pkey)
1127 return NULL;
1128 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1129 if (!eckey) {
1130 wpa_printf(MSG_INFO,
1131 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1132 ERR_error_string(ERR_get_error(), NULL));
1133 EVP_PKEY_free(pkey);
1134 return NULL;
1135 }
1136 group = EC_KEY_get0_group(eckey);
1137 if (!group) {
1138 EC_KEY_free(eckey);
1139 EVP_PKEY_free(pkey);
1140 return NULL;
1141 }
1142 nid = EC_GROUP_get_curve_name(group);
1143 *curve = dpp_get_curve_nid(nid);
1144 if (!*curve) {
1145 wpa_printf(MSG_INFO,
1146 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1147 nid);
1148 EC_KEY_free(eckey);
1149 EVP_PKEY_free(pkey);
1150 return NULL;
1151 }
1152
1153 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1154 EC_KEY_free(eckey);
1155 EVP_PKEY_free(pkey);
1156 return NULL;
1157 }
1158 return pkey;
1159 }
1160
1161
1162 typedef struct {
1163 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1164 * as an OID identifying the curve */
1165 X509_ALGOR *alg;
1166 /* Compressed format public key per ANSI X9.63 */
1167 ASN1_BIT_STRING *pub_key;
1168 } DPP_BOOTSTRAPPING_KEY;
1169
1170 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
1171 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
1172 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
1173 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
1174
1175 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1176
1177
1178 static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
1179 {
1180 unsigned char *der = NULL;
1181 int der_len;
1182 EC_KEY *eckey;
1183 struct wpabuf *ret = NULL;
1184 size_t len;
1185 const EC_GROUP *group;
1186 const EC_POINT *point;
1187 BN_CTX *ctx;
1188 DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1189 int nid;
1190
1191 ctx = BN_CTX_new();
1192 eckey = EVP_PKEY_get1_EC_KEY(key);
1193 if (!ctx || !eckey)
1194 goto fail;
1195
1196 group = EC_KEY_get0_group(eckey);
1197 point = EC_KEY_get0_public_key(eckey);
1198 if (!group || !point)
1199 goto fail;
1200 nid = EC_GROUP_get_curve_name(group);
1201
1202 bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1203 if (!bootstrap ||
1204 X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1205 V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1206 goto fail;
1207
1208 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1209 NULL, 0, ctx);
1210 if (len == 0)
1211 goto fail;
1212
1213 der = OPENSSL_malloc(len);
1214 if (!der)
1215 goto fail;
1216 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1217 der, len, ctx);
1218
1219 OPENSSL_free(bootstrap->pub_key->data);
1220 bootstrap->pub_key->data = der;
1221 der = NULL;
1222 bootstrap->pub_key->length = len;
1223 /* No unused bits */
1224 bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
1225 bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
1226
1227 der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
1228 if (der_len <= 0) {
1229 wpa_printf(MSG_ERROR,
1230 "DDP: Failed to build DER encoded public key");
1231 goto fail;
1232 }
1233
1234 ret = wpabuf_alloc_copy(der, der_len);
1235 fail:
1236 DPP_BOOTSTRAPPING_KEY_free(bootstrap);
1237 OPENSSL_free(der);
1238 EC_KEY_free(eckey);
1239 BN_CTX_free(ctx);
1240 return ret;
1241 }
1242
1243
1244 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
1245 {
1246 struct wpabuf *der;
1247 int res;
1248 const u8 *addr[1];
1249 size_t len[1];
1250
1251 der = dpp_bootstrap_key_der(bi->pubkey);
1252 if (!der)
1253 return -1;
1254 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1255 der);
1256
1257 addr[0] = wpabuf_head(der);
1258 len[0] = wpabuf_len(der);
1259 res = sha256_vector(1, addr, len, bi->pubkey_hash);
1260 if (res < 0)
1261 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1262 else
1263 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1264 SHA256_MAC_LEN);
1265 wpabuf_free(der);
1266 return res;
1267 }
1268
1269
1270 char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1271 const u8 *privkey, size_t privkey_len)
1272 {
1273 unsigned char *base64 = NULL;
1274 char *pos, *end;
1275 size_t len;
1276 struct wpabuf *der = NULL;
1277 const u8 *addr[1];
1278 int res;
1279
1280 if (!curve) {
1281 bi->curve = &dpp_curves[0];
1282 } else {
1283 bi->curve = dpp_get_curve_name(curve);
1284 if (!bi->curve) {
1285 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1286 curve);
1287 return NULL;
1288 }
1289 }
1290 if (privkey)
1291 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1292 else
1293 bi->pubkey = dpp_gen_keypair(bi->curve);
1294 if (!bi->pubkey)
1295 goto fail;
1296 bi->own = 1;
1297
1298 der = dpp_bootstrap_key_der(bi->pubkey);
1299 if (!der)
1300 goto fail;
1301 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1302 der);
1303
1304 addr[0] = wpabuf_head(der);
1305 len = wpabuf_len(der);
1306 res = sha256_vector(1, addr, &len, bi->pubkey_hash);
1307 if (res < 0)
1308 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1309 else
1310 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1311 SHA256_MAC_LEN);
1312
1313 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1314 wpabuf_free(der);
1315 der = NULL;
1316 if (!base64)
1317 goto fail;
1318 pos = (char *) base64;
1319 end = pos + len;
1320 for (;;) {
1321 pos = os_strchr(pos, '\n');
1322 if (!pos)
1323 break;
1324 os_memmove(pos, pos + 1, end - pos);
1325 }
1326 return (char *) base64;
1327 fail:
1328 os_free(base64);
1329 wpabuf_free(der);
1330 return NULL;
1331 }
1332
1333
1334 static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1335 unsigned int hash_len)
1336 {
1337 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1338 const char *info = "first intermediate key";
1339 int res;
1340
1341 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1342
1343 /* HKDF-Extract(<>, M.x) */
1344 os_memset(salt, 0, hash_len);
1345 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
1346 return -1;
1347 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1348 prk, hash_len);
1349
1350 /* HKDF-Expand(PRK, info, L) */
1351 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
1352 os_memset(prk, 0, hash_len);
1353 if (res < 0)
1354 return -1;
1355
1356 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1357 k1, hash_len);
1358 return 0;
1359 }
1360
1361
1362 static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1363 unsigned int hash_len)
1364 {
1365 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1366 const char *info = "second intermediate key";
1367 int res;
1368
1369 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1370
1371 /* HKDF-Extract(<>, N.x) */
1372 os_memset(salt, 0, hash_len);
1373 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
1374 if (res < 0)
1375 return -1;
1376 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1377 prk, hash_len);
1378
1379 /* HKDF-Expand(PRK, info, L) */
1380 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
1381 os_memset(prk, 0, hash_len);
1382 if (res < 0)
1383 return -1;
1384
1385 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1386 k2, hash_len);
1387 return 0;
1388 }
1389
1390
1391 static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1392 unsigned int hash_len)
1393 {
1394 size_t nonce_len;
1395 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1396 const char *info_ke = "DPP Key";
1397 u8 prk[DPP_MAX_HASH_LEN];
1398 int res;
1399 const u8 *addr[3];
1400 size_t len[3];
1401 size_t num_elem = 0;
1402
1403 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1404
1405 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1406 nonce_len = auth->curve->nonce_len;
1407 os_memcpy(nonces, auth->i_nonce, nonce_len);
1408 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1409 addr[num_elem] = auth->Mx;
1410 len[num_elem] = auth->secret_len;
1411 num_elem++;
1412 addr[num_elem] = auth->Nx;
1413 len[num_elem] = auth->secret_len;
1414 num_elem++;
1415 if (auth->peer_bi && auth->own_bi) {
1416 addr[num_elem] = auth->Lx;
1417 len[num_elem] = auth->secret_len;
1418 num_elem++;
1419 }
1420 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1421 num_elem, addr, len, prk);
1422 if (res < 0)
1423 return -1;
1424 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1425 prk, hash_len);
1426
1427 /* HKDF-Expand(PRK, info, L) */
1428 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
1429 os_memset(prk, 0, hash_len);
1430 if (res < 0)
1431 return -1;
1432
1433 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1434 ke, hash_len);
1435 return 0;
1436 }
1437
1438
1439 static void dpp_build_attr_status(struct wpabuf *msg,
1440 enum dpp_status_error status)
1441 {
1442 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
1443 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1444 wpabuf_put_le16(msg, 1);
1445 wpabuf_put_u8(msg, status);
1446 }
1447
1448
1449 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1450 const u8 *hash)
1451 {
1452 if (hash) {
1453 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1454 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1455 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1456 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1457 }
1458 }
1459
1460
1461 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1462 const u8 *hash)
1463 {
1464 if (hash) {
1465 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1466 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1467 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1468 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1469 }
1470 }
1471
1472
1473 static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1474 const struct wpabuf *pi,
1475 size_t nonce_len,
1476 const u8 *r_pubkey_hash,
1477 const u8 *i_pubkey_hash,
1478 unsigned int neg_freq)
1479 {
1480 struct wpabuf *msg;
1481 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1482 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1483 u8 *pos;
1484 const u8 *addr[2];
1485 size_t len[2], siv_len, attr_len;
1486 u8 *attr_start, *attr_end;
1487
1488 /* Build DPP Authentication Request frame attributes */
1489 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
1490 4 + sizeof(wrapped_data);
1491 if (neg_freq > 0)
1492 attr_len += 4 + 2;
1493 #ifdef CONFIG_TESTING_OPTIONS
1494 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1495 attr_len += 5;
1496 #endif /* CONFIG_TESTING_OPTIONS */
1497 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1498 if (!msg)
1499 return NULL;
1500
1501 attr_start = wpabuf_put(msg, 0);
1502
1503 /* Responder Bootstrapping Key Hash */
1504 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1505
1506 /* Initiator Bootstrapping Key Hash */
1507 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1508
1509 /* Initiator Protocol Key */
1510 if (pi) {
1511 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1512 wpabuf_put_le16(msg, wpabuf_len(pi));
1513 wpabuf_put_buf(msg, pi);
1514 }
1515
1516 /* Channel */
1517 if (neg_freq > 0) {
1518 u8 op_class, channel;
1519
1520 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1521 &channel) ==
1522 NUM_HOSTAPD_MODES) {
1523 wpa_printf(MSG_INFO,
1524 "DPP: Unsupported negotiation frequency request: %d",
1525 neg_freq);
1526 wpabuf_free(msg);
1527 return NULL;
1528 }
1529 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1530 wpabuf_put_le16(msg, 2);
1531 wpabuf_put_u8(msg, op_class);
1532 wpabuf_put_u8(msg, channel);
1533 }
1534
1535 #ifdef CONFIG_TESTING_OPTIONS
1536 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1537 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1538 goto skip_wrapped_data;
1539 }
1540 #endif /* CONFIG_TESTING_OPTIONS */
1541
1542 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1543 pos = clear;
1544
1545 #ifdef CONFIG_TESTING_OPTIONS
1546 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1547 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1548 goto skip_i_nonce;
1549 }
1550 #endif /* CONFIG_TESTING_OPTIONS */
1551
1552 /* I-nonce */
1553 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1554 pos += 2;
1555 WPA_PUT_LE16(pos, nonce_len);
1556 pos += 2;
1557 os_memcpy(pos, auth->i_nonce, nonce_len);
1558 pos += nonce_len;
1559
1560 #ifdef CONFIG_TESTING_OPTIONS
1561 skip_i_nonce:
1562 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1563 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1564 goto skip_i_capab;
1565 }
1566 #endif /* CONFIG_TESTING_OPTIONS */
1567
1568 /* I-capabilities */
1569 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1570 pos += 2;
1571 WPA_PUT_LE16(pos, 1);
1572 pos += 2;
1573 auth->i_capab = auth->allowed_roles;
1574 *pos++ = auth->i_capab;
1575 #ifdef CONFIG_TESTING_OPTIONS
1576 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1577 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1578 pos[-1] = 0;
1579 }
1580 skip_i_capab:
1581 #endif /* CONFIG_TESTING_OPTIONS */
1582
1583 attr_end = wpabuf_put(msg, 0);
1584
1585 /* OUI, OUI type, Crypto Suite, DPP frame type */
1586 addr[0] = wpabuf_head_u8(msg) + 2;
1587 len[0] = 3 + 1 + 1 + 1;
1588 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1589
1590 /* Attributes before Wrapped Data */
1591 addr[1] = attr_start;
1592 len[1] = attr_end - attr_start;
1593 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1594
1595 siv_len = pos - clear;
1596 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1597 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1598 2, addr, len, wrapped_data) < 0) {
1599 wpabuf_free(msg);
1600 return NULL;
1601 }
1602 siv_len += AES_BLOCK_SIZE;
1603 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1604 wrapped_data, siv_len);
1605
1606 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1607 wpabuf_put_le16(msg, siv_len);
1608 wpabuf_put_data(msg, wrapped_data, siv_len);
1609
1610 #ifdef CONFIG_TESTING_OPTIONS
1611 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1612 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1613 dpp_build_attr_status(msg, DPP_STATUS_OK);
1614 }
1615 skip_wrapped_data:
1616 #endif /* CONFIG_TESTING_OPTIONS */
1617
1618 wpa_hexdump_buf(MSG_DEBUG,
1619 "DPP: Authentication Request frame attributes", msg);
1620
1621 return msg;
1622 }
1623
1624
1625 static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1626 enum dpp_status_error status,
1627 const struct wpabuf *pr,
1628 size_t nonce_len,
1629 const u8 *r_pubkey_hash,
1630 const u8 *i_pubkey_hash,
1631 const u8 *r_nonce, const u8 *i_nonce,
1632 const u8 *wrapped_r_auth,
1633 size_t wrapped_r_auth_len,
1634 const u8 *siv_key)
1635 {
1636 struct wpabuf *msg;
1637 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1638 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1639 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1640 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1641 const u8 *addr[2];
1642 size_t len[2], siv_len, attr_len;
1643 u8 *attr_start, *attr_end, *pos;
1644
1645 auth->waiting_auth_conf = 1;
1646 auth->auth_resp_tries = 0;
1647
1648 /* Build DPP Authentication Response frame attributes */
1649 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1650 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
1651 #ifdef CONFIG_TESTING_OPTIONS
1652 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1653 attr_len += 5;
1654 #endif /* CONFIG_TESTING_OPTIONS */
1655 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1656 if (!msg)
1657 return NULL;
1658
1659 attr_start = wpabuf_put(msg, 0);
1660
1661 /* DPP Status */
1662 if (status != 255)
1663 dpp_build_attr_status(msg, status);
1664
1665 /* Responder Bootstrapping Key Hash */
1666 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1667
1668 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1669 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1670
1671 /* Responder Protocol Key */
1672 if (pr) {
1673 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1674 wpabuf_put_le16(msg, wpabuf_len(pr));
1675 wpabuf_put_buf(msg, pr);
1676 }
1677
1678 attr_end = wpabuf_put(msg, 0);
1679
1680 #ifdef CONFIG_TESTING_OPTIONS
1681 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
1682 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1683 goto skip_wrapped_data;
1684 }
1685 #endif /* CONFIG_TESTING_OPTIONS */
1686
1687 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1688 pos = clear;
1689
1690 if (r_nonce) {
1691 /* R-nonce */
1692 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1693 pos += 2;
1694 WPA_PUT_LE16(pos, nonce_len);
1695 pos += 2;
1696 os_memcpy(pos, r_nonce, nonce_len);
1697 pos += nonce_len;
1698 }
1699
1700 if (i_nonce) {
1701 /* I-nonce */
1702 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1703 pos += 2;
1704 WPA_PUT_LE16(pos, nonce_len);
1705 pos += 2;
1706 os_memcpy(pos, i_nonce, nonce_len);
1707 #ifdef CONFIG_TESTING_OPTIONS
1708 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
1709 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
1710 pos[nonce_len / 2] ^= 0x01;
1711 }
1712 #endif /* CONFIG_TESTING_OPTIONS */
1713 pos += nonce_len;
1714 }
1715
1716 #ifdef CONFIG_TESTING_OPTIONS
1717 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
1718 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
1719 goto skip_r_capab;
1720 }
1721 #endif /* CONFIG_TESTING_OPTIONS */
1722
1723 /* R-capabilities */
1724 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1725 pos += 2;
1726 WPA_PUT_LE16(pos, 1);
1727 pos += 2;
1728 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1729 DPP_CAPAB_ENROLLEE;
1730 *pos++ = auth->r_capab;
1731 #ifdef CONFIG_TESTING_OPTIONS
1732 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
1733 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
1734 pos[-1] = 0;
1735 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
1736 wpa_printf(MSG_INFO,
1737 "DPP: TESTING - incompatible R-capabilities");
1738 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
1739 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
1740 pos[-1] = 0;
1741 else
1742 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
1743 DPP_CAPAB_CONFIGURATOR;
1744 }
1745 skip_r_capab:
1746 #endif /* CONFIG_TESTING_OPTIONS */
1747
1748 if (wrapped_r_auth) {
1749 /* {R-auth}ke */
1750 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1751 pos += 2;
1752 WPA_PUT_LE16(pos, wrapped_r_auth_len);
1753 pos += 2;
1754 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1755 pos += wrapped_r_auth_len;
1756 }
1757
1758 /* OUI, OUI type, Crypto Suite, DPP frame type */
1759 addr[0] = wpabuf_head_u8(msg) + 2;
1760 len[0] = 3 + 1 + 1 + 1;
1761 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1762
1763 /* Attributes before Wrapped Data */
1764 addr[1] = attr_start;
1765 len[1] = attr_end - attr_start;
1766 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1767
1768 siv_len = pos - clear;
1769 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1770 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
1771 2, addr, len, wrapped_data) < 0) {
1772 wpabuf_free(msg);
1773 return NULL;
1774 }
1775 siv_len += AES_BLOCK_SIZE;
1776 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1777 wrapped_data, siv_len);
1778
1779 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1780 wpabuf_put_le16(msg, siv_len);
1781 wpabuf_put_data(msg, wrapped_data, siv_len);
1782
1783 #ifdef CONFIG_TESTING_OPTIONS
1784 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
1785 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1786 dpp_build_attr_status(msg, DPP_STATUS_OK);
1787 }
1788 skip_wrapped_data:
1789 #endif /* CONFIG_TESTING_OPTIONS */
1790
1791 wpa_hexdump_buf(MSG_DEBUG,
1792 "DPP: Authentication Response frame attributes", msg);
1793 return msg;
1794 }
1795
1796
1797 static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
1798 u16 num_modes, unsigned int freq)
1799 {
1800 u16 m;
1801 int c, flag;
1802
1803 if (!own_modes || !num_modes)
1804 return 1;
1805
1806 for (m = 0; m < num_modes; m++) {
1807 for (c = 0; c < own_modes[m].num_channels; c++) {
1808 if ((unsigned int) own_modes[m].channels[c].freq !=
1809 freq)
1810 continue;
1811 flag = own_modes[m].channels[c].flag;
1812 if (!(flag & (HOSTAPD_CHAN_DISABLED |
1813 HOSTAPD_CHAN_NO_IR |
1814 HOSTAPD_CHAN_RADAR)))
1815 return 1;
1816 }
1817 }
1818
1819 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
1820 return 0;
1821 }
1822
1823
1824 static int freq_included(const unsigned int freqs[], unsigned int num,
1825 unsigned int freq)
1826 {
1827 while (num > 0) {
1828 if (freqs[--num] == freq)
1829 return 1;
1830 }
1831 return 0;
1832 }
1833
1834
1835 static void freq_to_start(unsigned int freqs[], unsigned int num,
1836 unsigned int freq)
1837 {
1838 unsigned int i;
1839
1840 for (i = 0; i < num; i++) {
1841 if (freqs[i] == freq)
1842 break;
1843 }
1844 if (i == 0 || i >= num)
1845 return;
1846 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
1847 freqs[0] = freq;
1848 }
1849
1850
1851 static int dpp_channel_intersect(struct dpp_authentication *auth,
1852 struct hostapd_hw_modes *own_modes,
1853 u16 num_modes)
1854 {
1855 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
1856 unsigned int i, freq;
1857
1858 for (i = 0; i < peer_bi->num_freq; i++) {
1859 freq = peer_bi->freq[i];
1860 if (freq_included(auth->freq, auth->num_freq, freq))
1861 continue;
1862 if (dpp_channel_ok_init(own_modes, num_modes, freq))
1863 auth->freq[auth->num_freq++] = freq;
1864 }
1865 if (!auth->num_freq) {
1866 wpa_printf(MSG_INFO,
1867 "DPP: No available channels for initiating DPP Authentication");
1868 return -1;
1869 }
1870 auth->curr_freq = auth->freq[0];
1871 return 0;
1872 }
1873
1874
1875 static int dpp_channel_local_list(struct dpp_authentication *auth,
1876 struct hostapd_hw_modes *own_modes,
1877 u16 num_modes)
1878 {
1879 u16 m;
1880 int c, flag;
1881 unsigned int freq;
1882
1883 auth->num_freq = 0;
1884
1885 if (!own_modes || !num_modes) {
1886 auth->freq[0] = 2412;
1887 auth->freq[1] = 2437;
1888 auth->freq[2] = 2462;
1889 auth->num_freq = 3;
1890 return 0;
1891 }
1892
1893 for (m = 0; m < num_modes; m++) {
1894 for (c = 0; c < own_modes[m].num_channels; c++) {
1895 freq = own_modes[m].channels[c].freq;
1896 flag = own_modes[m].channels[c].flag;
1897 if (flag & (HOSTAPD_CHAN_DISABLED |
1898 HOSTAPD_CHAN_NO_IR |
1899 HOSTAPD_CHAN_RADAR))
1900 continue;
1901 if (freq_included(auth->freq, auth->num_freq, freq))
1902 continue;
1903 auth->freq[auth->num_freq++] = freq;
1904 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
1905 m = num_modes;
1906 break;
1907 }
1908 }
1909 }
1910
1911 return auth->num_freq == 0 ? -1 : 0;
1912 }
1913
1914
1915 static int dpp_prepare_channel_list(struct dpp_authentication *auth,
1916 struct hostapd_hw_modes *own_modes,
1917 u16 num_modes)
1918 {
1919 int res;
1920 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
1921 unsigned int i;
1922
1923 if (auth->peer_bi->num_freq > 0)
1924 res = dpp_channel_intersect(auth, own_modes, num_modes);
1925 else
1926 res = dpp_channel_local_list(auth, own_modes, num_modes);
1927 if (res < 0)
1928 return res;
1929
1930 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1931 * likely channels first. */
1932 freq_to_start(auth->freq, auth->num_freq, 2462);
1933 freq_to_start(auth->freq, auth->num_freq, 2412);
1934 freq_to_start(auth->freq, auth->num_freq, 2437);
1935
1936 auth->freq_idx = 0;
1937 auth->curr_freq = auth->freq[0];
1938
1939 pos = freqs;
1940 end = pos + sizeof(freqs);
1941 for (i = 0; i < auth->num_freq; i++) {
1942 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
1943 if (os_snprintf_error(end - pos, res))
1944 break;
1945 pos += res;
1946 }
1947 *pos = '\0';
1948 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
1949 freqs);
1950
1951 return 0;
1952 }
1953
1954
1955 struct dpp_authentication * dpp_auth_init(void *msg_ctx,
1956 struct dpp_bootstrap_info *peer_bi,
1957 struct dpp_bootstrap_info *own_bi,
1958 u8 dpp_allowed_roles,
1959 unsigned int neg_freq,
1960 struct hostapd_hw_modes *own_modes,
1961 u16 num_modes)
1962 {
1963 struct dpp_authentication *auth;
1964 size_t nonce_len;
1965 EVP_PKEY_CTX *ctx = NULL;
1966 size_t secret_len;
1967 struct wpabuf *pi = NULL;
1968 u8 zero[SHA256_MAC_LEN];
1969 const u8 *r_pubkey_hash, *i_pubkey_hash;
1970 #ifdef CONFIG_TESTING_OPTIONS
1971 u8 test_hash[SHA256_MAC_LEN];
1972 #endif /* CONFIG_TESTING_OPTIONS */
1973
1974 auth = os_zalloc(sizeof(*auth));
1975 if (!auth)
1976 return NULL;
1977 auth->msg_ctx = msg_ctx;
1978 auth->initiator = 1;
1979 auth->waiting_auth_resp = 1;
1980 auth->allowed_roles = dpp_allowed_roles;
1981 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
1982 auth->peer_bi = peer_bi;
1983 auth->own_bi = own_bi;
1984 auth->curve = peer_bi->curve;
1985
1986 if (dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
1987 goto fail;
1988
1989 nonce_len = auth->curve->nonce_len;
1990 if (random_get_bytes(auth->i_nonce, nonce_len)) {
1991 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
1992 goto fail;
1993 }
1994 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
1995
1996 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1997 if (!auth->own_protocol_key)
1998 goto fail;
1999
2000 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2001 if (!pi)
2002 goto fail;
2003
2004 /* ECDH: M = pI * BR */
2005 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2006 if (!ctx ||
2007 EVP_PKEY_derive_init(ctx) != 1 ||
2008 EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
2009 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2010 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2011 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
2012 wpa_printf(MSG_ERROR,
2013 "DPP: Failed to derive ECDH shared secret: %s",
2014 ERR_error_string(ERR_get_error(), NULL));
2015 goto fail;
2016 }
2017 auth->secret_len = secret_len;
2018 EVP_PKEY_CTX_free(ctx);
2019 ctx = NULL;
2020
2021 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2022 auth->Mx, auth->secret_len);
2023
2024 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2025 auth->curve->hash_len) < 0)
2026 goto fail;
2027
2028 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2029
2030 if (auth->own_bi) {
2031 i_pubkey_hash = auth->own_bi->pubkey_hash;
2032 } else {
2033 os_memset(zero, 0, SHA256_MAC_LEN);
2034 i_pubkey_hash = zero;
2035 }
2036
2037 #ifdef CONFIG_TESTING_OPTIONS
2038 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2039 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2040 r_pubkey_hash = NULL;
2041 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2042 wpa_printf(MSG_INFO,
2043 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2044 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2045 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2046 r_pubkey_hash = test_hash;
2047 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2048 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2049 i_pubkey_hash = NULL;
2050 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2051 wpa_printf(MSG_INFO,
2052 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2053 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2054 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2055 i_pubkey_hash = test_hash;
2056 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2057 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2058 wpabuf_free(pi);
2059 pi = NULL;
2060 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2061 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2062 wpabuf_free(pi);
2063 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2064 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2065 goto fail;
2066 }
2067 #endif /* CONFIG_TESTING_OPTIONS */
2068
2069 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
2070 i_pubkey_hash, neg_freq);
2071 if (!auth->req_msg)
2072 goto fail;
2073
2074 out:
2075 wpabuf_free(pi);
2076 EVP_PKEY_CTX_free(ctx);
2077 return auth;
2078 fail:
2079 dpp_auth_deinit(auth);
2080 auth = NULL;
2081 goto out;
2082 }
2083
2084
2085 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2086 const char *json)
2087 {
2088 size_t nonce_len;
2089 size_t json_len, clear_len;
2090 struct wpabuf *clear = NULL, *msg = NULL;
2091 u8 *wrapped;
2092 size_t attr_len;
2093
2094 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2095
2096 nonce_len = auth->curve->nonce_len;
2097 if (random_get_bytes(auth->e_nonce, nonce_len)) {
2098 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2099 goto fail;
2100 }
2101 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2102 json_len = os_strlen(json);
2103 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
2104
2105 /* { E-nonce, configAttrib }ke */
2106 clear_len = 4 + nonce_len + 4 + json_len;
2107 clear = wpabuf_alloc(clear_len);
2108 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2109 #ifdef CONFIG_TESTING_OPTIONS
2110 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
2111 attr_len += 5;
2112 #endif /* CONFIG_TESTING_OPTIONS */
2113 msg = wpabuf_alloc(attr_len);
2114 if (!clear || !msg)
2115 goto fail;
2116
2117 #ifdef CONFIG_TESTING_OPTIONS
2118 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2119 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2120 goto skip_e_nonce;
2121 }
2122 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2123 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2124 goto skip_wrapped_data;
2125 }
2126 #endif /* CONFIG_TESTING_OPTIONS */
2127
2128 /* E-nonce */
2129 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2130 wpabuf_put_le16(clear, nonce_len);
2131 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2132
2133 #ifdef CONFIG_TESTING_OPTIONS
2134 skip_e_nonce:
2135 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2136 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2137 goto skip_conf_attr_obj;
2138 }
2139 #endif /* CONFIG_TESTING_OPTIONS */
2140
2141 /* configAttrib */
2142 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2143 wpabuf_put_le16(clear, json_len);
2144 wpabuf_put_data(clear, json, json_len);
2145
2146 #ifdef CONFIG_TESTING_OPTIONS
2147 skip_conf_attr_obj:
2148 #endif /* CONFIG_TESTING_OPTIONS */
2149
2150 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2151 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2152 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2153
2154 /* No AES-SIV AD */
2155 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2156 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2157 wpabuf_head(clear), wpabuf_len(clear),
2158 0, NULL, NULL, wrapped) < 0)
2159 goto fail;
2160 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2161 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2162
2163 #ifdef CONFIG_TESTING_OPTIONS
2164 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2165 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2166 dpp_build_attr_status(msg, DPP_STATUS_OK);
2167 }
2168 skip_wrapped_data:
2169 #endif /* CONFIG_TESTING_OPTIONS */
2170
2171 wpa_hexdump_buf(MSG_DEBUG,
2172 "DPP: Configuration Request frame attributes", msg);
2173 wpabuf_free(clear);
2174 return msg;
2175
2176 fail:
2177 wpabuf_free(clear);
2178 wpabuf_free(msg);
2179 return NULL;
2180 }
2181
2182
2183 static void dpp_auth_success(struct dpp_authentication *auth)
2184 {
2185 wpa_printf(MSG_DEBUG,
2186 "DPP: Authentication success - clear temporary keys");
2187 os_memset(auth->Mx, 0, sizeof(auth->Mx));
2188 os_memset(auth->Nx, 0, sizeof(auth->Nx));
2189 os_memset(auth->Lx, 0, sizeof(auth->Lx));
2190 os_memset(auth->k1, 0, sizeof(auth->k1));
2191 os_memset(auth->k2, 0, sizeof(auth->k2));
2192
2193 auth->auth_success = 1;
2194 }
2195
2196
2197 static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2198 {
2199 struct wpabuf *pix, *prx, *bix, *brx;
2200 const u8 *addr[7];
2201 size_t len[7];
2202 size_t i, num_elem = 0;
2203 size_t nonce_len;
2204 u8 zero = 0;
2205 int res = -1;
2206
2207 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2208 nonce_len = auth->curve->nonce_len;
2209
2210 if (auth->initiator) {
2211 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2212 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2213 if (auth->own_bi)
2214 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2215 else
2216 bix = NULL;
2217 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2218 } else {
2219 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2220 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2221 if (auth->peer_bi)
2222 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2223 else
2224 bix = NULL;
2225 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2226 }
2227 if (!pix || !prx || !brx)
2228 goto fail;
2229
2230 addr[num_elem] = auth->i_nonce;
2231 len[num_elem] = nonce_len;
2232 num_elem++;
2233
2234 addr[num_elem] = auth->r_nonce;
2235 len[num_elem] = nonce_len;
2236 num_elem++;
2237
2238 addr[num_elem] = wpabuf_head(pix);
2239 len[num_elem] = wpabuf_len(pix) / 2;
2240 num_elem++;
2241
2242 addr[num_elem] = wpabuf_head(prx);
2243 len[num_elem] = wpabuf_len(prx) / 2;
2244 num_elem++;
2245
2246 if (bix) {
2247 addr[num_elem] = wpabuf_head(bix);
2248 len[num_elem] = wpabuf_len(bix) / 2;
2249 num_elem++;
2250 }
2251
2252 addr[num_elem] = wpabuf_head(brx);
2253 len[num_elem] = wpabuf_len(brx) / 2;
2254 num_elem++;
2255
2256 addr[num_elem] = &zero;
2257 len[num_elem] = 1;
2258 num_elem++;
2259
2260 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2261 for (i = 0; i < num_elem; i++)
2262 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2263 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
2264 if (res == 0)
2265 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2266 auth->curve->hash_len);
2267 fail:
2268 wpabuf_free(pix);
2269 wpabuf_free(prx);
2270 wpabuf_free(bix);
2271 wpabuf_free(brx);
2272 return res;
2273 }
2274
2275
2276 static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2277 {
2278 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2279 const u8 *addr[7];
2280 size_t len[7];
2281 size_t i, num_elem = 0;
2282 size_t nonce_len;
2283 u8 one = 1;
2284 int res = -1;
2285
2286 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2287 nonce_len = auth->curve->nonce_len;
2288
2289 if (auth->initiator) {
2290 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2291 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2292 if (auth->own_bi)
2293 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2294 else
2295 bix = NULL;
2296 if (!auth->peer_bi)
2297 goto fail;
2298 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2299 } else {
2300 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2301 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2302 if (auth->peer_bi)
2303 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2304 else
2305 bix = NULL;
2306 if (!auth->own_bi)
2307 goto fail;
2308 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2309 }
2310 if (!pix || !prx || !brx)
2311 goto fail;
2312
2313 addr[num_elem] = auth->r_nonce;
2314 len[num_elem] = nonce_len;
2315 num_elem++;
2316
2317 addr[num_elem] = auth->i_nonce;
2318 len[num_elem] = nonce_len;
2319 num_elem++;
2320
2321 addr[num_elem] = wpabuf_head(prx);
2322 len[num_elem] = wpabuf_len(prx) / 2;
2323 num_elem++;
2324
2325 addr[num_elem] = wpabuf_head(pix);
2326 len[num_elem] = wpabuf_len(pix) / 2;
2327 num_elem++;
2328
2329 addr[num_elem] = wpabuf_head(brx);
2330 len[num_elem] = wpabuf_len(brx) / 2;
2331 num_elem++;
2332
2333 if (bix) {
2334 addr[num_elem] = wpabuf_head(bix);
2335 len[num_elem] = wpabuf_len(bix) / 2;
2336 num_elem++;
2337 }
2338
2339 addr[num_elem] = &one;
2340 len[num_elem] = 1;
2341 num_elem++;
2342
2343 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2344 for (i = 0; i < num_elem; i++)
2345 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2346 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
2347 if (res == 0)
2348 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2349 auth->curve->hash_len);
2350 fail:
2351 wpabuf_free(pix);
2352 wpabuf_free(prx);
2353 wpabuf_free(bix);
2354 wpabuf_free(brx);
2355 return res;
2356 }
2357
2358
2359 static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2360 {
2361 const EC_GROUP *group;
2362 EC_POINT *l = NULL;
2363 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2364 const EC_POINT *BI_point;
2365 BN_CTX *bnctx;
2366 BIGNUM *lx, *sum, *q;
2367 const BIGNUM *bR_bn, *pR_bn;
2368 int ret = -1;
2369
2370 /* L = ((bR + pR) modulo q) * BI */
2371
2372 bnctx = BN_CTX_new();
2373 sum = BN_new();
2374 q = BN_new();
2375 lx = BN_new();
2376 if (!bnctx || !sum || !q || !lx)
2377 goto fail;
2378 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2379 if (!BI)
2380 goto fail;
2381 BI_point = EC_KEY_get0_public_key(BI);
2382 group = EC_KEY_get0_group(BI);
2383 if (!group)
2384 goto fail;
2385
2386 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2387 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2388 if (!bR || !pR)
2389 goto fail;
2390 bR_bn = EC_KEY_get0_private_key(bR);
2391 pR_bn = EC_KEY_get0_private_key(pR);
2392 if (!bR_bn || !pR_bn)
2393 goto fail;
2394 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2395 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2396 goto fail;
2397 l = EC_POINT_new(group);
2398 if (!l ||
2399 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2400 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2401 bnctx) != 1) {
2402 wpa_printf(MSG_ERROR,
2403 "OpenSSL: failed: %s",
2404 ERR_error_string(ERR_get_error(), NULL));
2405 goto fail;
2406 }
2407
2408 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2409 goto fail;
2410 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2411 ret = 0;
2412 fail:
2413 EC_POINT_clear_free(l);
2414 EC_KEY_free(BI);
2415 EC_KEY_free(bR);
2416 EC_KEY_free(pR);
2417 BN_clear_free(lx);
2418 BN_clear_free(sum);
2419 BN_free(q);
2420 BN_CTX_free(bnctx);
2421 return ret;
2422 }
2423
2424
2425 static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2426 {
2427 const EC_GROUP *group;
2428 EC_POINT *l = NULL, *sum = NULL;
2429 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2430 const EC_POINT *BR_point, *PR_point;
2431 BN_CTX *bnctx;
2432 BIGNUM *lx;
2433 const BIGNUM *bI_bn;
2434 int ret = -1;
2435
2436 /* L = bI * (BR + PR) */
2437
2438 bnctx = BN_CTX_new();
2439 lx = BN_new();
2440 if (!bnctx || !lx)
2441 goto fail;
2442 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2443 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
2444 if (!BR || !PR)
2445 goto fail;
2446 BR_point = EC_KEY_get0_public_key(BR);
2447 PR_point = EC_KEY_get0_public_key(PR);
2448
2449 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2450 if (!bI)
2451 goto fail;
2452 group = EC_KEY_get0_group(bI);
2453 bI_bn = EC_KEY_get0_private_key(bI);
2454 if (!group || !bI_bn)
2455 goto fail;
2456 sum = EC_POINT_new(group);
2457 l = EC_POINT_new(group);
2458 if (!sum || !l ||
2459 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
2460 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
2461 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2462 bnctx) != 1) {
2463 wpa_printf(MSG_ERROR,
2464 "OpenSSL: failed: %s",
2465 ERR_error_string(ERR_get_error(), NULL));
2466 goto fail;
2467 }
2468
2469 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2470 goto fail;
2471 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2472 ret = 0;
2473 fail:
2474 EC_POINT_clear_free(l);
2475 EC_KEY_free(bI);
2476 EC_KEY_free(BR);
2477 EC_KEY_free(PR);
2478 BN_clear_free(lx);
2479 BN_CTX_free(bnctx);
2480 return ret;
2481 }
2482
2483
2484 static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
2485 {
2486 size_t nonce_len;
2487 EVP_PKEY_CTX *ctx = NULL;
2488 size_t secret_len;
2489 struct wpabuf *msg, *pr = NULL;
2490 u8 r_auth[4 + DPP_MAX_HASH_LEN];
2491 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
2492 size_t wrapped_r_auth_len;
2493 int ret = -1;
2494 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
2495 enum dpp_status_error status = DPP_STATUS_OK;
2496 #ifdef CONFIG_TESTING_OPTIONS
2497 u8 test_hash[SHA256_MAC_LEN];
2498 #endif /* CONFIG_TESTING_OPTIONS */
2499
2500 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2501 if (!auth->own_bi)
2502 return -1;
2503
2504 nonce_len = auth->curve->nonce_len;
2505 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2506 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
2507 goto fail;
2508 }
2509 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
2510
2511 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2512 if (!auth->own_protocol_key)
2513 goto fail;
2514
2515 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2516 if (!pr)
2517 goto fail;
2518
2519 /* ECDH: N = pR * PI */
2520 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2521 if (!ctx ||
2522 EVP_PKEY_derive_init(ctx) != 1 ||
2523 EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
2524 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2525 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2526 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
2527 wpa_printf(MSG_ERROR,
2528 "DPP: Failed to derive ECDH shared secret: %s",
2529 ERR_error_string(ERR_get_error(), NULL));
2530 goto fail;
2531 }
2532 EVP_PKEY_CTX_free(ctx);
2533 ctx = NULL;
2534
2535 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
2536 auth->Nx, auth->secret_len);
2537
2538 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2539 auth->curve->hash_len) < 0)
2540 goto fail;
2541
2542 if (auth->own_bi && auth->peer_bi) {
2543 /* Mutual authentication */
2544 if (dpp_auth_derive_l_responder(auth) < 0)
2545 goto fail;
2546 }
2547
2548 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2549 goto fail;
2550
2551 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2552 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
2553 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
2554 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
2555 goto fail;
2556 #ifdef CONFIG_TESTING_OPTIONS
2557 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
2558 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
2559 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
2560 }
2561 #endif /* CONFIG_TESTING_OPTIONS */
2562 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2563 r_auth, 4 + auth->curve->hash_len,
2564 0, NULL, NULL, wrapped_r_auth) < 0)
2565 goto fail;
2566 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
2567 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
2568 wrapped_r_auth, wrapped_r_auth_len);
2569 w_r_auth = wrapped_r_auth;
2570
2571 r_pubkey_hash = auth->own_bi->pubkey_hash;
2572 if (auth->peer_bi)
2573 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2574 else
2575 i_pubkey_hash = NULL;
2576
2577 i_nonce = auth->i_nonce;
2578 r_nonce = auth->r_nonce;
2579
2580 #ifdef CONFIG_TESTING_OPTIONS
2581 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2582 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2583 r_pubkey_hash = NULL;
2584 } else if (dpp_test ==
2585 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2586 wpa_printf(MSG_INFO,
2587 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2588 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2589 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2590 r_pubkey_hash = test_hash;
2591 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2592 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2593 i_pubkey_hash = NULL;
2594 } else if (dpp_test ==
2595 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2596 wpa_printf(MSG_INFO,
2597 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2598 if (i_pubkey_hash)
2599 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2600 else
2601 os_memset(test_hash, 0, SHA256_MAC_LEN);
2602 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2603 i_pubkey_hash = test_hash;
2604 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
2605 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
2606 wpabuf_free(pr);
2607 pr = NULL;
2608 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
2609 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
2610 wpabuf_free(pr);
2611 pr = wpabuf_alloc(2 * auth->curve->prime_len);
2612 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
2613 goto fail;
2614 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
2615 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
2616 w_r_auth = NULL;
2617 wrapped_r_auth_len = 0;
2618 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2619 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2620 status = 255;
2621 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
2622 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2623 status = 254;
2624 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
2625 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
2626 r_nonce = NULL;
2627 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2628 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2629 i_nonce = NULL;
2630 }
2631 #endif /* CONFIG_TESTING_OPTIONS */
2632
2633 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
2634 r_pubkey_hash, i_pubkey_hash,
2635 r_nonce, i_nonce,
2636 w_r_auth, wrapped_r_auth_len,
2637 auth->k2);
2638 if (!msg)
2639 goto fail;
2640 wpabuf_free(auth->resp_msg);
2641 auth->resp_msg = msg;
2642 ret = 0;
2643 fail:
2644 wpabuf_free(pr);
2645 return ret;
2646 }
2647
2648
2649 static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
2650 enum dpp_status_error status)
2651 {
2652 struct wpabuf *msg;
2653 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
2654 #ifdef CONFIG_TESTING_OPTIONS
2655 u8 test_hash[SHA256_MAC_LEN];
2656 #endif /* CONFIG_TESTING_OPTIONS */
2657
2658 if (!auth->own_bi)
2659 return -1;
2660 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2661
2662 r_pubkey_hash = auth->own_bi->pubkey_hash;
2663 if (auth->peer_bi)
2664 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2665 else
2666 i_pubkey_hash = NULL;
2667
2668 i_nonce = auth->i_nonce;
2669
2670 #ifdef CONFIG_TESTING_OPTIONS
2671 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2672 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2673 r_pubkey_hash = NULL;
2674 } else if (dpp_test ==
2675 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2676 wpa_printf(MSG_INFO,
2677 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2678 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2679 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2680 r_pubkey_hash = test_hash;
2681 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2682 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2683 i_pubkey_hash = NULL;
2684 } else if (dpp_test ==
2685 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2686 wpa_printf(MSG_INFO,
2687 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2688 if (i_pubkey_hash)
2689 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2690 else
2691 os_memset(test_hash, 0, SHA256_MAC_LEN);
2692 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2693 i_pubkey_hash = test_hash;
2694 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2695 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2696 status = -1;
2697 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2698 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2699 i_nonce = NULL;
2700 }
2701 #endif /* CONFIG_TESTING_OPTIONS */
2702
2703 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
2704 r_pubkey_hash, i_pubkey_hash,
2705 NULL, i_nonce, NULL, 0, auth->k1);
2706 if (!msg)
2707 return -1;
2708 wpabuf_free(auth->resp_msg);
2709 auth->resp_msg = msg;
2710 return 0;
2711 }
2712
2713
2714 struct dpp_authentication *
2715 dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
2716 struct dpp_bootstrap_info *peer_bi,
2717 struct dpp_bootstrap_info *own_bi,
2718 unsigned int freq, const u8 *hdr, const u8 *attr_start,
2719 size_t attr_len)
2720 {
2721 EVP_PKEY *pi = NULL;
2722 EVP_PKEY_CTX *ctx = NULL;
2723 size_t secret_len;
2724 const u8 *addr[2];
2725 size_t len[2];
2726 u8 *unwrapped = NULL;
2727 size_t unwrapped_len = 0;
2728 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
2729 *channel;
2730 u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
2731 i_bootstrap_len, channel_len;
2732 struct dpp_authentication *auth = NULL;
2733
2734 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2735 &wrapped_data_len);
2736 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
2737 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
2738 "Missing or invalid required Wrapped Data attribute");
2739 return NULL;
2740 }
2741 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
2742 wrapped_data, wrapped_data_len);
2743 attr_len = wrapped_data - 4 - attr_start;
2744
2745 auth = os_zalloc(sizeof(*auth));
2746 if (!auth)
2747 goto fail;
2748 auth->msg_ctx = msg_ctx;
2749 auth->peer_bi = peer_bi;
2750 auth->own_bi = own_bi;
2751 auth->curve = own_bi->curve;
2752 auth->curr_freq = freq;
2753
2754 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
2755 &channel_len);
2756 if (channel) {
2757 int neg_freq;
2758
2759 if (channel_len < 2) {
2760 dpp_auth_fail(auth, "Too short Channel attribute");
2761 goto fail;
2762 }
2763
2764 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
2765 wpa_printf(MSG_DEBUG,
2766 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2767 channel[0], channel[1], neg_freq);
2768 if (neg_freq < 0) {
2769 dpp_auth_fail(auth,
2770 "Unsupported Channel attribute value");
2771 goto fail;
2772 }
2773
2774 if (auth->curr_freq != (unsigned int) neg_freq) {
2775 wpa_printf(MSG_DEBUG,
2776 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2777 freq, neg_freq);
2778 auth->curr_freq = neg_freq;
2779 }
2780 }
2781
2782 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
2783 &i_proto_len);
2784 if (!i_proto) {
2785 dpp_auth_fail(auth,
2786 "Missing required Initiator Protocol Key attribute");
2787 goto fail;
2788 }
2789 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
2790 i_proto, i_proto_len);
2791
2792 /* M = bR * PI */
2793 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
2794 if (!pi) {
2795 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
2796 goto fail;
2797 }
2798 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
2799
2800 ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
2801 if (!ctx ||
2802 EVP_PKEY_derive_init(ctx) != 1 ||
2803 EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
2804 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2805 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2806 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
2807 wpa_printf(MSG_ERROR,
2808 "DPP: Failed to derive ECDH shared secret: %s",
2809 ERR_error_string(ERR_get_error(), NULL));
2810 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
2811 goto fail;
2812 }
2813 auth->secret_len = secret_len;
2814 EVP_PKEY_CTX_free(ctx);
2815 ctx = NULL;
2816
2817 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2818 auth->Mx, auth->secret_len);
2819
2820 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2821 auth->curve->hash_len) < 0)
2822 goto fail;
2823
2824 addr[0] = hdr;
2825 len[0] = DPP_HDR_LEN;
2826 addr[1] = attr_start;
2827 len[1] = attr_len;
2828 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2829 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
2830 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2831 wrapped_data, wrapped_data_len);
2832 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2833 unwrapped = os_malloc(unwrapped_len);
2834 if (!unwrapped)
2835 goto fail;
2836 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
2837 wrapped_data, wrapped_data_len,
2838 2, addr, len, unwrapped) < 0) {
2839 dpp_auth_fail(auth, "AES-SIV decryption failed");
2840 goto fail;
2841 }
2842 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2843 unwrapped, unwrapped_len);
2844
2845 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2846 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
2847 goto fail;
2848 }
2849
2850 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
2851 &i_nonce_len);
2852 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
2853 dpp_auth_fail(auth, "Missing or invalid I-nonce");
2854 goto fail;
2855 }
2856 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
2857 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
2858
2859 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
2860 DPP_ATTR_I_CAPABILITIES,
2861 &i_capab_len);
2862 if (!i_capab || i_capab_len < 1) {
2863 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
2864 goto fail;
2865 }
2866 auth->i_capab = i_capab[0];
2867 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
2868
2869 bin_clear_free(unwrapped, unwrapped_len);
2870 unwrapped = NULL;
2871
2872 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
2873 case DPP_CAPAB_ENROLLEE:
2874 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
2875 wpa_printf(MSG_DEBUG,
2876 "DPP: Local policy does not allow Configurator role");
2877 goto not_compatible;
2878 }
2879 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
2880 auth->configurator = 1;
2881 break;
2882 case DPP_CAPAB_CONFIGURATOR:
2883 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
2884 wpa_printf(MSG_DEBUG,
2885 "DPP: Local policy does not allow Enrollee role");
2886 goto not_compatible;
2887 }
2888 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
2889 auth->configurator = 0;
2890 break;
2891 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
2892 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
2893 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
2894 auth->configurator = 0;
2895 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
2896 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
2897 auth->configurator = 1;
2898 } else {
2899 wpa_printf(MSG_DEBUG,
2900 "DPP: Local policy does not allow Configurator/Enrollee role");
2901 goto not_compatible;
2902 }
2903 break;
2904 default:
2905 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
2906 wpa_msg(auth->msg_ctx, MSG_INFO,
2907 DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
2908 auth->i_capab & DPP_CAPAB_ROLE_MASK);
2909 goto fail;
2910 }
2911
2912 auth->peer_protocol_key = pi;
2913 pi = NULL;
2914 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
2915 char hex[SHA256_MAC_LEN * 2 + 1];
2916
2917 wpa_printf(MSG_DEBUG,
2918 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2919 if (dpp_auth_build_resp_status(auth,
2920 DPP_STATUS_RESPONSE_PENDING) < 0)
2921 goto fail;
2922 i_bootstrap = dpp_get_attr(attr_start, attr_len,
2923 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
2924 &i_bootstrap_len);
2925 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
2926 auth->response_pending = 1;
2927 os_memcpy(auth->waiting_pubkey_hash,
2928 i_bootstrap, i_bootstrap_len);
2929 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
2930 i_bootstrap_len);
2931 } else {
2932 hex[0] = '\0';
2933 }
2934
2935 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
2936 "%s", hex);
2937 return auth;
2938 }
2939 if (dpp_auth_build_resp_ok(auth) < 0)
2940 goto fail;
2941
2942 return auth;
2943
2944 not_compatible:
2945 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
2946 "i-capab=0x%02x", auth->i_capab);
2947 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
2948 auth->configurator = 1;
2949 else
2950 auth->configurator = 0;
2951 auth->peer_protocol_key = pi;
2952 pi = NULL;
2953 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
2954 goto fail;
2955
2956 auth->remove_on_tx_status = 1;
2957 return auth;
2958 fail:
2959 bin_clear_free(unwrapped, unwrapped_len);
2960 EVP_PKEY_free(pi);
2961 EVP_PKEY_CTX_free(ctx);
2962 dpp_auth_deinit(auth);
2963 return NULL;
2964 }
2965
2966
2967 int dpp_notify_new_qr_code(struct dpp_authentication *auth,
2968 struct dpp_bootstrap_info *peer_bi)
2969 {
2970 if (!auth || !auth->response_pending ||
2971 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
2972 SHA256_MAC_LEN) != 0)
2973 return 0;
2974
2975 wpa_printf(MSG_DEBUG,
2976 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2977 MACSTR, MAC2STR(auth->peer_mac_addr));
2978 auth->peer_bi = peer_bi;
2979
2980 if (dpp_auth_build_resp_ok(auth) < 0)
2981 return -1;
2982
2983 return 1;
2984 }
2985
2986
2987 static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
2988 enum dpp_status_error status)
2989 {
2990 struct wpabuf *msg;
2991 u8 i_auth[4 + DPP_MAX_HASH_LEN];
2992 size_t i_auth_len;
2993 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
2994 size_t r_nonce_len;
2995 const u8 *addr[2];
2996 size_t len[2], attr_len;
2997 u8 *wrapped_i_auth;
2998 u8 *wrapped_r_nonce;
2999 u8 *attr_start, *attr_end;
3000 const u8 *r_pubkey_hash, *i_pubkey_hash;
3001 #ifdef CONFIG_TESTING_OPTIONS
3002 u8 test_hash[SHA256_MAC_LEN];
3003 #endif /* CONFIG_TESTING_OPTIONS */
3004
3005 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3006
3007 i_auth_len = 4 + auth->curve->hash_len;
3008 r_nonce_len = 4 + auth->curve->nonce_len;
3009 /* Build DPP Authentication Confirmation frame attributes */
3010 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
3011 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
3012 #ifdef CONFIG_TESTING_OPTIONS
3013 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
3014 attr_len += 5;
3015 #endif /* CONFIG_TESTING_OPTIONS */
3016 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
3017 if (!msg)
3018 goto fail;
3019
3020 attr_start = wpabuf_put(msg, 0);
3021
3022 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3023 if (auth->own_bi)
3024 i_pubkey_hash = auth->own_bi->pubkey_hash;
3025 else
3026 i_pubkey_hash = NULL;
3027
3028 #ifdef CONFIG_TESTING_OPTIONS
3029 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3030 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3031 goto skip_status;
3032 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3033 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3034 status = 254;
3035 }
3036 #endif /* CONFIG_TESTING_OPTIONS */
3037
3038 /* DPP Status */
3039 dpp_build_attr_status(msg, status);
3040
3041 #ifdef CONFIG_TESTING_OPTIONS
3042 skip_status:
3043 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3044 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3045 r_pubkey_hash = NULL;
3046 } else if (dpp_test ==
3047 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3048 wpa_printf(MSG_INFO,
3049 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3050 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3051 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3052 r_pubkey_hash = test_hash;
3053 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3054 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3055 i_pubkey_hash = NULL;
3056 } else if (dpp_test ==
3057 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3058 wpa_printf(MSG_INFO,
3059 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3060 if (i_pubkey_hash)
3061 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3062 else
3063 os_memset(test_hash, 0, SHA256_MAC_LEN);
3064 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3065 i_pubkey_hash = test_hash;
3066 }
3067 #endif /* CONFIG_TESTING_OPTIONS */
3068
3069 /* Responder Bootstrapping Key Hash */
3070 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
3071
3072 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3073 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
3074
3075 #ifdef CONFIG_TESTING_OPTIONS
3076 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3077 goto skip_wrapped_data;
3078 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3079 i_auth_len = 0;
3080 #endif /* CONFIG_TESTING_OPTIONS */
3081
3082 attr_end = wpabuf_put(msg, 0);
3083
3084 /* OUI, OUI type, Crypto Suite, DPP frame type */
3085 addr[0] = wpabuf_head_u8(msg) + 2;
3086 len[0] = 3 + 1 + 1 + 1;
3087 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3088
3089 /* Attributes before Wrapped Data */
3090 addr[1] = attr_start;
3091 len[1] = attr_end - attr_start;
3092 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3093
3094 if (status == DPP_STATUS_OK) {
3095 /* I-auth wrapped with ke */
3096 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3097 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3098 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
3099
3100 #ifdef CONFIG_TESTING_OPTIONS
3101 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3102 goto skip_i_auth;
3103 #endif /* CONFIG_TESTING_OPTIONS */
3104
3105 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3106 * 1) */
3107 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3108 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3109 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3110 goto fail;
3111
3112 #ifdef CONFIG_TESTING_OPTIONS
3113 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3114 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3115 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3116 }
3117 skip_i_auth:
3118 #endif /* CONFIG_TESTING_OPTIONS */
3119 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3120 i_auth, i_auth_len,
3121 2, addr, len, wrapped_i_auth) < 0)
3122 goto fail;
3123 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3124 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3125 } else {
3126 /* R-nonce wrapped with k2 */
3127 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3128 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3129 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3130
3131 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3132 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3133 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3134
3135 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3136 r_nonce, r_nonce_len,
3137 2, addr, len, wrapped_r_nonce) < 0)
3138 goto fail;
3139 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3140 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3141 }
3142
3143 #ifdef CONFIG_TESTING_OPTIONS
3144 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3145 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
3146 dpp_build_attr_status(msg, DPP_STATUS_OK);
3147 }
3148 skip_wrapped_data:
3149 #endif /* CONFIG_TESTING_OPTIONS */
3150
3151 wpa_hexdump_buf(MSG_DEBUG,
3152 "DPP: Authentication Confirmation frame attributes",
3153 msg);
3154 if (status == DPP_STATUS_OK)
3155 dpp_auth_success(auth);
3156
3157 return msg;
3158
3159 fail:
3160 return NULL;
3161 }
3162
3163
3164 static void
3165 dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
3166 const u8 *attr_start, size_t attr_len,
3167 const u8 *wrapped_data, u16 wrapped_data_len,
3168 enum dpp_status_error status)
3169 {
3170 const u8 *addr[2];
3171 size_t len[2];
3172 u8 *unwrapped = NULL;
3173 size_t unwrapped_len = 0;
3174 const u8 *i_nonce, *r_capab;
3175 u16 i_nonce_len, r_capab_len;
3176
3177 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3178 wpa_printf(MSG_DEBUG,
3179 "DPP: Responder reported incompatible roles");
3180 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3181 wpa_printf(MSG_DEBUG,
3182 "DPP: Responder reported more time needed");
3183 } else {
3184 wpa_printf(MSG_DEBUG,
3185 "DPP: Responder reported failure (status %d)",
3186 status);
3187 dpp_auth_fail(auth, "Responder reported failure");
3188 return;
3189 }
3190
3191 addr[0] = hdr;
3192 len[0] = DPP_HDR_LEN;
3193 addr[1] = attr_start;
3194 len[1] = attr_len;
3195 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3196 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3197 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3198 wrapped_data, wrapped_data_len);
3199 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3200 unwrapped = os_malloc(unwrapped_len);
3201 if (!unwrapped)
3202 goto fail;
3203 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3204 wrapped_data, wrapped_data_len,
3205 2, addr, len, unwrapped) < 0) {
3206 dpp_auth_fail(auth, "AES-SIV decryption failed");
3207 goto fail;
3208 }
3209 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3210 unwrapped, unwrapped_len);
3211
3212 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3213 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3214 goto fail;
3215 }
3216
3217 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3218 &i_nonce_len);
3219 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3220 dpp_auth_fail(auth, "Missing or invalid I-nonce");
3221 goto fail;
3222 }
3223 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3224 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
3225 dpp_auth_fail(auth, "I-nonce mismatch");
3226 goto fail;
3227 }
3228
3229 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3230 DPP_ATTR_R_CAPABILITIES,
3231 &r_capab_len);
3232 if (!r_capab || r_capab_len < 1) {
3233 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
3234 goto fail;
3235 }
3236 auth->r_capab = r_capab[0];
3237 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3238 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3239 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3240 "r-capab=0x%02x", auth->r_capab);
3241 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3242 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3243
3244 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3245 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3246 wpa_msg(auth->msg_ctx, MSG_INFO,
3247 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3248 role);
3249 } else {
3250 wpa_printf(MSG_DEBUG,
3251 "DPP: Continue waiting for full DPP Authentication Response");
3252 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_RESPONSE_PENDING);
3253 }
3254 }
3255 fail:
3256 bin_clear_free(unwrapped, unwrapped_len);
3257 }
3258
3259
3260 struct wpabuf *
3261 dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3262 const u8 *attr_start, size_t attr_len)
3263 {
3264 EVP_PKEY *pr;
3265 EVP_PKEY_CTX *ctx = NULL;
3266 size_t secret_len;
3267 const u8 *addr[2];
3268 size_t len[2];
3269 u8 *unwrapped = NULL, *unwrapped2 = NULL;
3270 size_t unwrapped_len = 0, unwrapped2_len = 0;
3271 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3272 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3273 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3274 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3275 wrapped2_len, r_auth_len;
3276 u8 r_auth2[DPP_MAX_HASH_LEN];
3277 u8 role;
3278
3279 if (!auth->initiator) {
3280 dpp_auth_fail(auth, "Unexpected Authentication Response");
3281 return NULL;
3282 }
3283
3284 auth->waiting_auth_resp = 0;
3285
3286 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3287 &wrapped_data_len);
3288 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3289 dpp_auth_fail(auth,
3290 "Missing or invalid required Wrapped Data attribute");
3291 return NULL;
3292 }
3293 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3294 wrapped_data, wrapped_data_len);
3295
3296 attr_len = wrapped_data - 4 - attr_start;
3297
3298 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3299 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3300 &r_bootstrap_len);
3301 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3302 dpp_auth_fail(auth,
3303 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3304 return NULL;
3305 }
3306 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3307 r_bootstrap, r_bootstrap_len);
3308 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3309 SHA256_MAC_LEN) != 0) {
3310 dpp_auth_fail(auth,
3311 "Unexpected Responder Bootstrapping Key Hash value");
3312 wpa_hexdump(MSG_DEBUG,
3313 "DPP: Expected Responder Bootstrapping Key Hash",
3314 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3315 return NULL;
3316 }
3317
3318 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3319 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3320 &i_bootstrap_len);
3321 if (i_bootstrap) {
3322 if (i_bootstrap_len != SHA256_MAC_LEN) {
3323 dpp_auth_fail(auth,
3324 "Invalid Initiator Bootstrapping Key Hash attribute");
3325 return NULL;
3326 }
3327 wpa_hexdump(MSG_MSGDUMP,
3328 "DPP: Initiator Bootstrapping Key Hash",
3329 i_bootstrap, i_bootstrap_len);
3330 if (!auth->own_bi ||
3331 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3332 SHA256_MAC_LEN) != 0) {
3333 dpp_auth_fail(auth,
3334 "Initiator Bootstrapping Key Hash attribute did not match");
3335 return NULL;
3336 }
3337 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3338 /* PKEX bootstrapping mandates use of mutual authentication */
3339 dpp_auth_fail(auth,
3340 "Missing Initiator Bootstrapping Key Hash attribute");
3341 return NULL;
3342 }
3343
3344 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3345 &status_len);
3346 if (!status || status_len < 1) {
3347 dpp_auth_fail(auth,
3348 "Missing or invalid required DPP Status attribute");
3349 return NULL;
3350 }
3351 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3352 auth->auth_resp_status = status[0];
3353 if (status[0] != DPP_STATUS_OK) {
3354 dpp_auth_resp_rx_status(auth, hdr, attr_start,
3355 attr_len, wrapped_data,
3356 wrapped_data_len, status[0]);
3357 return NULL;
3358 }
3359
3360 if (!i_bootstrap && auth->own_bi) {
3361 wpa_printf(MSG_DEBUG,
3362 "DPP: Responder decided not to use mutual authentication");
3363 auth->own_bi = NULL;
3364 }
3365
3366 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3367 &r_proto_len);
3368 if (!r_proto) {
3369 dpp_auth_fail(auth,
3370 "Missing required Responder Protocol Key attribute");
3371 return NULL;
3372 }
3373 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3374 r_proto, r_proto_len);
3375
3376 /* N = pI * PR */
3377 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3378 if (!pr) {
3379 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
3380 return NULL;
3381 }
3382 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3383
3384 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
3385 if (!ctx ||
3386 EVP_PKEY_derive_init(ctx) != 1 ||
3387 EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
3388 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
3389 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
3390 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
3391 wpa_printf(MSG_ERROR,
3392 "DPP: Failed to derive ECDH shared secret: %s",
3393 ERR_error_string(ERR_get_error(), NULL));
3394 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
3395 goto fail;
3396 }
3397 EVP_PKEY_CTX_free(ctx);
3398 ctx = NULL;
3399 auth->peer_protocol_key = pr;
3400 pr = NULL;
3401
3402 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3403 auth->Nx, auth->secret_len);
3404
3405 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3406 auth->curve->hash_len) < 0)
3407 goto fail;
3408
3409 addr[0] = hdr;
3410 len[0] = DPP_HDR_LEN;
3411 addr[1] = attr_start;
3412 len[1] = attr_len;
3413 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3414 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3415 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3416 wrapped_data, wrapped_data_len);
3417 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3418 unwrapped = os_malloc(unwrapped_len);
3419 if (!unwrapped)
3420 goto fail;
3421 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3422 wrapped_data, wrapped_data_len,
3423 2, addr, len, unwrapped) < 0) {
3424 dpp_auth_fail(auth, "AES-SIV decryption failed");
3425 goto fail;
3426 }
3427 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3428 unwrapped, unwrapped_len);
3429
3430 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3431 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3432 goto fail;
3433 }
3434
3435 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3436 &r_nonce_len);
3437 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3438 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3439 goto fail;
3440 }
3441 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
3442 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
3443
3444 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3445 &i_nonce_len);
3446 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3447 dpp_auth_fail(auth, "Missing or invalid I-nonce");
3448 goto fail;
3449 }
3450 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3451 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
3452 dpp_auth_fail(auth, "I-nonce mismatch");
3453 goto fail;
3454 }
3455
3456 if (auth->own_bi && auth->peer_bi) {
3457 /* Mutual authentication */
3458 if (dpp_auth_derive_l_initiator(auth) < 0)
3459 goto fail;
3460 }
3461
3462 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3463 DPP_ATTR_R_CAPABILITIES,
3464 &r_capab_len);
3465 if (!r_capab || r_capab_len < 1) {
3466 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
3467 goto fail;
3468 }
3469 auth->r_capab = r_capab[0];
3470 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3471 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3472 if ((auth->allowed_roles ==
3473 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
3474 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
3475 /* Peer selected its role, so move from "either role" to the
3476 * role that is compatible with peer's selection. */
3477 auth->configurator = role == DPP_CAPAB_ENROLLEE;
3478 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
3479 auth->configurator ? "Configurator" : "Enrollee");
3480 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3481 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3482 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
3483 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3484 "Unexpected role in R-capabilities 0x%02x",
3485 role);
3486 if (role != DPP_CAPAB_ENROLLEE &&
3487 role != DPP_CAPAB_CONFIGURATOR)
3488 goto fail;
3489 bin_clear_free(unwrapped, unwrapped_len);
3490 auth->remove_on_tx_status = 1;
3491 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
3492 }
3493
3494 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
3495 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
3496 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
3497 dpp_auth_fail(auth,
3498 "Missing or invalid Secondary Wrapped Data");
3499 goto fail;
3500 }
3501
3502 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3503 wrapped2, wrapped2_len);
3504
3505 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3506 goto fail;
3507
3508 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
3509 unwrapped2 = os_malloc(unwrapped2_len);
3510 if (!unwrapped2)
3511 goto fail;
3512 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3513 wrapped2, wrapped2_len,
3514 0, NULL, NULL, unwrapped2) < 0) {
3515 dpp_auth_fail(auth, "AES-SIV decryption failed");
3516 goto fail;
3517 }
3518 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3519 unwrapped2, unwrapped2_len);
3520
3521 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
3522 dpp_auth_fail(auth,
3523 "Invalid attribute in secondary unwrapped data");
3524 goto fail;
3525 }
3526
3527 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
3528 &r_auth_len);
3529 if (!r_auth || r_auth_len != auth->curve->hash_len) {
3530 dpp_auth_fail(auth,
3531 "Missing or invalid Responder Authenticating Tag");
3532 goto fail;
3533 }
3534 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
3535 r_auth, r_auth_len);
3536 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3537 if (dpp_gen_r_auth(auth, r_auth2) < 0)
3538 goto fail;
3539 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
3540 r_auth2, r_auth_len);
3541 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
3542 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
3543 bin_clear_free(unwrapped, unwrapped_len);
3544 bin_clear_free(unwrapped2, unwrapped2_len);
3545 auth->remove_on_tx_status = 1;
3546 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
3547 }
3548
3549 bin_clear_free(unwrapped, unwrapped_len);
3550 bin_clear_free(unwrapped2, unwrapped2_len);
3551
3552 #ifdef CONFIG_TESTING_OPTIONS
3553 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
3554 wpa_printf(MSG_INFO,
3555 "DPP: TESTING - Authentication Response in place of Confirm");
3556 if (dpp_auth_build_resp_ok(auth) < 0)
3557 return NULL;
3558 return wpabuf_dup(auth->resp_msg);
3559 }
3560 #endif /* CONFIG_TESTING_OPTIONS */
3561
3562 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
3563
3564 fail:
3565 bin_clear_free(unwrapped, unwrapped_len);
3566 bin_clear_free(unwrapped2, unwrapped2_len);
3567 EVP_PKEY_free(pr);
3568 EVP_PKEY_CTX_free(ctx);
3569 return NULL;
3570 }
3571
3572
3573 static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
3574 const u8 *hdr,
3575 const u8 *attr_start, size_t attr_len,
3576 const u8 *wrapped_data,
3577 u16 wrapped_data_len,
3578 enum dpp_status_error status)
3579 {
3580 const u8 *addr[2];
3581 size_t len[2];
3582 u8 *unwrapped = NULL;
3583 size_t unwrapped_len = 0;
3584 const u8 *r_nonce;
3585 u16 r_nonce_len;
3586
3587 /* Authentication Confirm failure cases are expected to include
3588 * {R-nonce}k2 in the Wrapped Data attribute. */
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 dpp_auth_fail(auth, "Authentication failed");
3602 goto fail;
3603 }
3604 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3605 wrapped_data, wrapped_data_len,
3606 2, addr, len, unwrapped) < 0) {
3607 dpp_auth_fail(auth, "AES-SIV decryption failed");
3608 goto fail;
3609 }
3610 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3611 unwrapped, unwrapped_len);
3612
3613 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3614 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3615 goto fail;
3616 }
3617
3618 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3619 &r_nonce_len);
3620 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3621 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3622 goto fail;
3623 }
3624 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
3625 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
3626 r_nonce, r_nonce_len);
3627 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
3628 auth->r_nonce, r_nonce_len);
3629 dpp_auth_fail(auth, "R-nonce mismatch");
3630 goto fail;
3631 }
3632
3633 if (status == DPP_STATUS_NOT_COMPATIBLE)
3634 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
3635 else if (status == DPP_STATUS_AUTH_FAILURE)
3636 dpp_auth_fail(auth, "Peer reported authentication failure)");
3637
3638 fail:
3639 bin_clear_free(unwrapped, unwrapped_len);
3640 return -1;
3641 }
3642
3643
3644 int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
3645 const u8 *attr_start, size_t attr_len)
3646 {
3647 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
3648 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3649 i_auth_len;
3650 const u8 *addr[2];
3651 size_t len[2];
3652 u8 *unwrapped = NULL;
3653 size_t unwrapped_len = 0;
3654 u8 i_auth2[DPP_MAX_HASH_LEN];
3655
3656 if (auth->initiator) {
3657 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
3658 return NULL;
3659 }
3660
3661 auth->waiting_auth_conf = 0;
3662
3663 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3664 &wrapped_data_len);
3665 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3666 dpp_auth_fail(auth,
3667 "Missing or invalid required Wrapped Data attribute");
3668 return -1;
3669 }
3670 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3671 wrapped_data, wrapped_data_len);
3672
3673 attr_len = wrapped_data - 4 - attr_start;
3674
3675 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3676 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3677 &r_bootstrap_len);
3678 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3679 dpp_auth_fail(auth,
3680 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3681 return -1;
3682 }
3683 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3684 r_bootstrap, r_bootstrap_len);
3685 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
3686 SHA256_MAC_LEN) != 0) {
3687 wpa_hexdump(MSG_DEBUG,
3688 "DPP: Expected Responder Bootstrapping Key Hash",
3689 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3690 dpp_auth_fail(auth,
3691 "Responder Bootstrapping Key Hash mismatch");
3692 return -1;
3693 }
3694
3695 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3696 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3697 &i_bootstrap_len);
3698 if (i_bootstrap) {
3699 if (i_bootstrap_len != SHA256_MAC_LEN) {
3700 dpp_auth_fail(auth,
3701 "Invalid Initiator Bootstrapping Key Hash attribute");
3702 return -1;
3703 }
3704 wpa_hexdump(MSG_MSGDUMP,
3705 "DPP: Initiator Bootstrapping Key Hash",
3706 i_bootstrap, i_bootstrap_len);
3707 if (!auth->peer_bi ||
3708 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
3709 SHA256_MAC_LEN) != 0) {
3710 dpp_auth_fail(auth,
3711 "Initiator Bootstrapping Key Hash mismatch");
3712 return -1;
3713 }
3714 } else if (auth->own_bi && auth->peer_bi) {
3715 /* Mutual authentication and peer did not include its
3716 * Bootstrapping Key Hash attribute. */
3717 dpp_auth_fail(auth,
3718 "Missing Initiator Bootstrapping Key Hash attribute");
3719 return -1;
3720 }
3721
3722 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3723 &status_len);
3724 if (!status || status_len < 1) {
3725 dpp_auth_fail(auth,
3726 "Missing or invalid required DPP Status attribute");
3727 return -1;
3728 }
3729 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3730 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
3731 status[0] == DPP_STATUS_AUTH_FAILURE)
3732 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
3733 attr_len, wrapped_data,
3734 wrapped_data_len, status[0]);
3735
3736 if (status[0] != DPP_STATUS_OK) {
3737 dpp_auth_fail(auth, "Authentication failed");
3738 return -1;
3739 }
3740
3741 addr[0] = hdr;
3742 len[0] = DPP_HDR_LEN;
3743 addr[1] = attr_start;
3744 len[1] = attr_len;
3745 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3746 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3747 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3748 wrapped_data, wrapped_data_len);
3749 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3750 unwrapped = os_malloc(unwrapped_len);
3751 if (!unwrapped)
3752 return -1;
3753 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3754 wrapped_data, wrapped_data_len,
3755 2, addr, len, unwrapped) < 0) {
3756 dpp_auth_fail(auth, "AES-SIV decryption failed");
3757 goto fail;
3758 }
3759 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3760 unwrapped, unwrapped_len);
3761
3762 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3763 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3764 goto fail;
3765 }
3766
3767 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
3768 &i_auth_len);
3769 if (!i_auth || i_auth_len != auth->curve->hash_len) {
3770 dpp_auth_fail(auth,
3771 "Missing or invalid Initiator Authenticating Tag");
3772 goto fail;
3773 }
3774 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
3775 i_auth, i_auth_len);
3776 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3777 if (dpp_gen_i_auth(auth, i_auth2) < 0)
3778 goto fail;
3779 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
3780 i_auth2, i_auth_len);
3781 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
3782 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
3783 goto fail;
3784 }
3785
3786 bin_clear_free(unwrapped, unwrapped_len);
3787 dpp_auth_success(auth);
3788 return 0;
3789 fail:
3790 bin_clear_free(unwrapped, unwrapped_len);
3791 return -1;
3792 }
3793
3794
3795 void dpp_configuration_free(struct dpp_configuration *conf)
3796 {
3797 if (!conf)
3798 return;
3799 str_clear_free(conf->passphrase);
3800 bin_clear_free(conf, sizeof(*conf));
3801 }
3802
3803
3804 void dpp_auth_deinit(struct dpp_authentication *auth)
3805 {
3806 if (!auth)
3807 return;
3808 dpp_configuration_free(auth->conf_ap);
3809 dpp_configuration_free(auth->conf_sta);
3810 EVP_PKEY_free(auth->own_protocol_key);
3811 EVP_PKEY_free(auth->peer_protocol_key);
3812 wpabuf_free(auth->req_msg);
3813 wpabuf_free(auth->resp_msg);
3814 wpabuf_free(auth->conf_req);
3815 os_free(auth->connector);
3816 wpabuf_free(auth->net_access_key);
3817 wpabuf_free(auth->c_sign_key);
3818 #ifdef CONFIG_TESTING_OPTIONS
3819 os_free(auth->config_obj_override);
3820 os_free(auth->discovery_override);
3821 os_free(auth->groups_override);
3822 #endif /* CONFIG_TESTING_OPTIONS */
3823 bin_clear_free(auth, sizeof(*auth));
3824 }
3825
3826
3827 static struct wpabuf *
3828 dpp_build_conf_start(struct dpp_authentication *auth,
3829 struct dpp_configuration *conf, size_t tailroom)
3830 {
3831 struct wpabuf *buf;
3832 char ssid[6 * sizeof(conf->ssid) + 1];
3833
3834 #ifdef CONFIG_TESTING_OPTIONS
3835 if (auth->discovery_override)
3836 tailroom += os_strlen(auth->discovery_override);
3837 #endif /* CONFIG_TESTING_OPTIONS */
3838
3839 buf = wpabuf_alloc(200 + tailroom);
3840 if (!buf)
3841 return NULL;
3842 wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
3843 #ifdef CONFIG_TESTING_OPTIONS
3844 if (auth->discovery_override) {
3845 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
3846 auth->discovery_override);
3847 wpabuf_put_str(buf, auth->discovery_override);
3848 wpabuf_put_u8(buf, ',');
3849 return buf;
3850 }
3851 #endif /* CONFIG_TESTING_OPTIONS */
3852 wpabuf_put_str(buf, "{\"ssid\":\"");
3853 json_escape_string(ssid, sizeof(ssid),
3854 (const char *) conf->ssid, conf->ssid_len);
3855 wpabuf_put_str(buf, ssid);
3856 wpabuf_put_str(buf, "\"},");
3857
3858 return buf;
3859 }
3860
3861
3862 static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
3863 const char *kid, const struct dpp_curve_params *curve)
3864 {
3865 struct wpabuf *pub;
3866 const u8 *pos;
3867 char *x = NULL, *y = NULL;
3868 int ret = -1;
3869
3870 pub = dpp_get_pubkey_point(key, 0);
3871 if (!pub)
3872 goto fail;
3873 pos = wpabuf_head(pub);
3874 x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
3875 pos += curve->prime_len;
3876 y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
3877 if (!x || !y)
3878 goto fail;
3879
3880 wpabuf_put_str(buf, "\"");
3881 wpabuf_put_str(buf, name);
3882 wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
3883 wpabuf_put_str(buf, curve->jwk_crv);
3884 wpabuf_put_str(buf, "\",\"x\":\"");
3885 wpabuf_put_str(buf, x);
3886 wpabuf_put_str(buf, "\",\"y\":\"");
3887 wpabuf_put_str(buf, y);
3888 if (kid) {
3889 wpabuf_put_str(buf, "\",\"kid\":\"");
3890 wpabuf_put_str(buf, kid);
3891 }
3892 wpabuf_put_str(buf, "\"}");
3893 ret = 0;
3894 fail:
3895 wpabuf_free(pub);
3896 os_free(x);
3897 os_free(y);
3898 return ret;
3899 }
3900
3901
3902 static struct wpabuf *
3903 dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
3904 struct dpp_configuration *conf)
3905 {
3906 struct wpabuf *buf = NULL;
3907 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
3908 size_t tailroom;
3909 const struct dpp_curve_params *curve;
3910 char jws_prot_hdr[100];
3911 size_t signed1_len, signed2_len, signed3_len;
3912 struct wpabuf *dppcon = NULL;
3913 unsigned char *signature = NULL;
3914 const unsigned char *p;
3915 size_t signature_len;
3916 EVP_MD_CTX *md_ctx = NULL;
3917 ECDSA_SIG *sig = NULL;
3918 char *dot = ".";
3919 const EVP_MD *sign_md;
3920 const BIGNUM *r, *s;
3921 size_t extra_len = 1000;
3922
3923 if (!auth->conf) {
3924 wpa_printf(MSG_INFO,
3925 "DPP: No configurator specified - cannot generate DPP config object");
3926 goto fail;
3927 }
3928 curve = auth->conf->curve;
3929 if (curve->hash_len == SHA256_MAC_LEN) {
3930 sign_md = EVP_sha256();
3931 } else if (curve->hash_len == SHA384_MAC_LEN) {
3932 sign_md = EVP_sha384();
3933 } else if (curve->hash_len == SHA512_MAC_LEN) {
3934 sign_md = EVP_sha512();
3935 } else {
3936 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
3937 goto fail;
3938 }
3939
3940 #ifdef CONFIG_TESTING_OPTIONS
3941 if (auth->groups_override)
3942 extra_len += os_strlen(auth->groups_override);
3943 #endif /* CONFIG_TESTING_OPTIONS */
3944
3945 /* Connector (JSON dppCon object) */
3946 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
3947 if (!dppcon)
3948 goto fail;
3949 #ifdef CONFIG_TESTING_OPTIONS
3950 if (auth->groups_override) {
3951 wpabuf_put_u8(dppcon, '{');
3952 if (auth->groups_override) {
3953 wpa_printf(MSG_DEBUG,
3954 "DPP: TESTING - groups override: '%s'",
3955 auth->groups_override);
3956 wpabuf_put_str(dppcon, "\"groups\":");
3957 wpabuf_put_str(dppcon, auth->groups_override);
3958 wpabuf_put_u8(dppcon, ',');
3959 }
3960 goto skip_groups;
3961 }
3962 #endif /* CONFIG_TESTING_OPTIONS */
3963 wpabuf_put_str(dppcon, "{\"groups\":[{\"groupId\":\"*\",");
3964 wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
3965 #ifdef CONFIG_TESTING_OPTIONS
3966 skip_groups:
3967 #endif /* CONFIG_TESTING_OPTIONS */
3968 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
3969 auth->curve) < 0) {
3970 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
3971 goto fail;
3972 }
3973 if (conf->netaccesskey_expiry) {
3974 struct os_tm tm;
3975
3976 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
3977 wpa_printf(MSG_DEBUG,
3978 "DPP: Failed to generate expiry string");
3979 goto fail;
3980 }
3981 wpabuf_printf(dppcon,
3982 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3983 tm.year, tm.month, tm.day,
3984 tm.hour, tm.min, tm.sec);
3985 }
3986 wpabuf_put_u8(dppcon, '}');
3987 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
3988 (const char *) wpabuf_head(dppcon));
3989
3990 os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
3991 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
3992 auth->conf->kid, curve->jws_alg);
3993 signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
3994 os_strlen(jws_prot_hdr),
3995 &signed1_len, 0);
3996 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
3997 wpabuf_len(dppcon),
3998 &signed2_len, 0);
3999 if (!signed1 || !signed2)
4000 goto fail;
4001
4002 md_ctx = EVP_MD_CTX_create();
4003 if (!md_ctx)
4004 goto fail;
4005
4006 ERR_clear_error();
4007 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
4008 auth->conf->csign) != 1) {
4009 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
4010 ERR_error_string(ERR_get_error(), NULL));
4011 goto fail;
4012 }
4013 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
4014 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
4015 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
4016 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
4017 ERR_error_string(ERR_get_error(), NULL));
4018 goto fail;
4019 }
4020 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
4021 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4022 ERR_error_string(ERR_get_error(), NULL));
4023 goto fail;
4024 }
4025 signature = os_malloc(signature_len);
4026 if (!signature)
4027 goto fail;
4028 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
4029 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4030 ERR_error_string(ERR_get_error(), NULL));
4031 goto fail;
4032 }
4033 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
4034 signature, signature_len);
4035 /* Convert to raw coordinates r,s */
4036 p = signature;
4037 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
4038 if (!sig)
4039 goto fail;
4040 ECDSA_SIG_get0(sig, &r, &s);
4041 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4042 dpp_bn2bin_pad(s, signature + curve->prime_len,
4043 curve->prime_len) < 0)
4044 goto fail;
4045 signature_len = 2 * curve->prime_len;
4046 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4047 signature, signature_len);
4048 signed3 = (char *) base64_url_encode(signature, signature_len,
4049 &signed3_len, 0);
4050 if (!signed3)
4051 goto fail;
4052
4053 tailroom = 1000;
4054 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4055 tailroom += signed1_len + signed2_len + signed3_len;
4056 buf = dpp_build_conf_start(auth, conf, tailroom);
4057 if (!buf)
4058 return NULL;
4059
4060 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
4061 wpabuf_put_str(buf, signed1);
4062 wpabuf_put_u8(buf, '.');
4063 wpabuf_put_str(buf, signed2);
4064 wpabuf_put_u8(buf, '.');
4065 wpabuf_put_str(buf, signed3);
4066 wpabuf_put_str(buf, "\",");
4067 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4068 curve) < 0) {
4069 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4070 goto fail;
4071 }
4072
4073 wpabuf_put_str(buf, "}}");
4074
4075 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4076 wpabuf_head(buf), wpabuf_len(buf));
4077
4078 out:
4079 EVP_MD_CTX_destroy(md_ctx);
4080 ECDSA_SIG_free(sig);
4081 os_free(signed1);
4082 os_free(signed2);
4083 os_free(signed3);
4084 os_free(signature);
4085 wpabuf_free(dppcon);
4086 return buf;
4087 fail:
4088 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4089 wpabuf_free(buf);
4090 buf = NULL;
4091 goto out;
4092 }
4093
4094
4095 static struct wpabuf *
4096 dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
4097 struct dpp_configuration *conf)
4098 {
4099 struct wpabuf *buf;
4100
4101 buf = dpp_build_conf_start(auth, conf, 1000);
4102 if (!buf)
4103 return NULL;
4104
4105 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"psk\",");
4106 if (conf->passphrase) {
4107 char pass[63 * 6 + 1];
4108
4109 if (os_strlen(conf->passphrase) > 63) {
4110 wpabuf_free(buf);
4111 return NULL;
4112 }
4113
4114 json_escape_string(pass, sizeof(pass), conf->passphrase,
4115 os_strlen(conf->passphrase));
4116 wpabuf_put_str(buf, "\"pass\":\"");
4117 wpabuf_put_str(buf, pass);
4118 wpabuf_put_str(buf, "\"");
4119 } else {
4120 char psk[2 * sizeof(conf->psk) + 1];
4121
4122 wpa_snprintf_hex(psk, sizeof(psk),
4123 conf->psk, sizeof(conf->psk));
4124 wpabuf_put_str(buf, "\"psk_hex\":\"");
4125 wpabuf_put_str(buf, psk);
4126 wpabuf_put_str(buf, "\"");
4127 }
4128 wpabuf_put_str(buf, "}}");
4129
4130 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4131 wpabuf_head(buf), wpabuf_len(buf));
4132
4133 return buf;
4134 }
4135
4136
4137 static struct wpabuf *
4138 dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
4139 {
4140 struct dpp_configuration *conf;
4141
4142 #ifdef CONFIG_TESTING_OPTIONS
4143 if (auth->config_obj_override) {
4144 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
4145 return wpabuf_alloc_copy(auth->config_obj_override,
4146 os_strlen(auth->config_obj_override));
4147 }
4148 #endif /* CONFIG_TESTING_OPTIONS */
4149
4150 conf = ap ? auth->conf_ap : auth->conf_sta;
4151 if (!conf) {
4152 wpa_printf(MSG_DEBUG,
4153 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4154 ap ? "ap" : "sta");
4155 return NULL;
4156 }
4157
4158 if (conf->dpp)
4159 return dpp_build_conf_obj_dpp(auth, ap, conf);
4160 return dpp_build_conf_obj_legacy(auth, ap, conf);
4161 }
4162
4163
4164 static struct wpabuf *
4165 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4166 u16 e_nonce_len, int ap)
4167 {
4168 struct wpabuf *conf;
4169 size_t clear_len, attr_len;
4170 struct wpabuf *clear = NULL, *msg = NULL;
4171 u8 *wrapped;
4172 const u8 *addr[1];
4173 size_t len[1];
4174 enum dpp_status_error status;
4175
4176 conf = dpp_build_conf_obj(auth, ap);
4177 if (conf) {
4178 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4179 wpabuf_head(conf), wpabuf_len(conf));
4180 }
4181 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
4182
4183 /* { E-nonce, configurationObject}ke */
4184 clear_len = 4 + e_nonce_len;
4185 if (conf)
4186 clear_len += 4 + wpabuf_len(conf);
4187 clear = wpabuf_alloc(clear_len);
4188 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
4189 #ifdef CONFIG_TESTING_OPTIONS
4190 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
4191 attr_len += 5;
4192 #endif /* CONFIG_TESTING_OPTIONS */
4193 msg = wpabuf_alloc(attr_len);
4194 if (!clear || !msg)
4195 goto fail;
4196
4197 #ifdef CONFIG_TESTING_OPTIONS
4198 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
4199 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
4200 goto skip_e_nonce;
4201 }
4202 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
4203 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
4204 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4205 wpabuf_put_le16(clear, e_nonce_len);
4206 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
4207 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
4208 goto skip_e_nonce;
4209 }
4210 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
4211 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
4212 goto skip_wrapped_data;
4213 }
4214 #endif /* CONFIG_TESTING_OPTIONS */
4215
4216 /* E-nonce */
4217 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4218 wpabuf_put_le16(clear, e_nonce_len);
4219 wpabuf_put_data(clear, e_nonce, e_nonce_len);
4220
4221 #ifdef CONFIG_TESTING_OPTIONS
4222 skip_e_nonce:
4223 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
4224 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
4225 goto skip_config_obj;
4226 }
4227 #endif /* CONFIG_TESTING_OPTIONS */
4228
4229 if (conf) {
4230 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4231 wpabuf_put_le16(clear, wpabuf_len(conf));
4232 wpabuf_put_buf(clear, conf);
4233 }
4234
4235 #ifdef CONFIG_TESTING_OPTIONS
4236 skip_config_obj:
4237 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4238 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4239 goto skip_status;
4240 }
4241 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4242 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4243 status = 255;
4244 }
4245 #endif /* CONFIG_TESTING_OPTIONS */
4246
4247 /* DPP Status */
4248 dpp_build_attr_status(msg, status);
4249
4250 #ifdef CONFIG_TESTING_OPTIONS
4251 skip_status:
4252 #endif /* CONFIG_TESTING_OPTIONS */
4253
4254 addr[0] = wpabuf_head(msg);
4255 len[0] = wpabuf_len(msg);
4256 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4257
4258 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
4259 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4260 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4261
4262 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
4263 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
4264 wpabuf_head(clear), wpabuf_len(clear),
4265 1, addr, len, wrapped) < 0)
4266 goto fail;
4267 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4268 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
4269
4270 #ifdef CONFIG_TESTING_OPTIONS
4271 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
4272 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
4273 dpp_build_attr_status(msg, DPP_STATUS_OK);
4274 }
4275 skip_wrapped_data:
4276 #endif /* CONFIG_TESTING_OPTIONS */
4277
4278 wpa_hexdump_buf(MSG_DEBUG,
4279 "DPP: Configuration Response attributes", msg);
4280 out:
4281 wpabuf_free(conf);
4282 wpabuf_free(clear);
4283
4284 return msg;
4285 fail:
4286 wpabuf_free(msg);
4287 msg = NULL;
4288 goto out;
4289 }
4290
4291
4292 struct wpabuf *
4293 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4294 size_t attr_len)
4295 {
4296 const u8 *wrapped_data, *e_nonce, *config_attr;
4297 u16 wrapped_data_len, e_nonce_len, config_attr_len;
4298 u8 *unwrapped = NULL;
4299 size_t unwrapped_len = 0;
4300 struct wpabuf *resp = NULL;
4301 struct json_token *root = NULL, *token;
4302 int ap;
4303
4304 if (dpp_check_attrs(attr_start, attr_len) < 0) {
4305 dpp_auth_fail(auth, "Invalid attribute in config request");
4306 return NULL;
4307 }
4308
4309 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4310 &wrapped_data_len);
4311 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4312 dpp_auth_fail(auth,
4313 "Missing or invalid required Wrapped Data attribute");
4314 return NULL;
4315 }
4316
4317 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4318 wrapped_data, wrapped_data_len);
4319 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4320 unwrapped = os_malloc(unwrapped_len);
4321 if (!unwrapped)
4322 return NULL;
4323 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4324 wrapped_data, wrapped_data_len,
4325 0, NULL, NULL, unwrapped) < 0) {
4326 dpp_auth_fail(auth, "AES-SIV decryption failed");
4327 goto fail;
4328 }
4329 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4330 unwrapped, unwrapped_len);
4331
4332 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4333 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4334 goto fail;
4335 }
4336
4337 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4338 DPP_ATTR_ENROLLEE_NONCE,
4339 &e_nonce_len);
4340 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
4341 dpp_auth_fail(auth,
4342 "Missing or invalid Enrollee Nonce attribute");
4343 goto fail;
4344 }
4345 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4346
4347 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
4348 DPP_ATTR_CONFIG_ATTR_OBJ,
4349 &config_attr_len);
4350 if (!config_attr) {
4351 dpp_auth_fail(auth,
4352 "Missing or invalid Config Attributes attribute");
4353 goto fail;
4354 }
4355 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
4356 config_attr, config_attr_len);
4357
4358 root = json_parse((const char *) config_attr, config_attr_len);
4359 if (!root) {
4360 dpp_auth_fail(auth, "Could not parse Config Attributes");
4361 goto fail;
4362 }
4363
4364 token = json_get_member(root, "name");
4365 if (!token || token->type != JSON_STRING) {
4366 dpp_auth_fail(auth, "No Config Attributes - name");
4367 goto fail;
4368 }
4369 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
4370
4371 token = json_get_member(root, "wi-fi_tech");
4372 if (!token || token->type != JSON_STRING) {
4373 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
4374 goto fail;
4375 }
4376 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
4377 if (os_strcmp(token->string, "infra") != 0) {
4378 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
4379 token->string);
4380 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
4381 goto fail;
4382 }
4383
4384 token = json_get_member(root, "netRole");
4385 if (!token || token->type != JSON_STRING) {
4386 dpp_auth_fail(auth, "No Config Attributes - netRole");
4387 goto fail;
4388 }
4389 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
4390 if (os_strcmp(token->string, "sta") == 0) {
4391 ap = 0;
4392 } else if (os_strcmp(token->string, "ap") == 0) {
4393 ap = 1;
4394 } else {
4395 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
4396 token->string);
4397 dpp_auth_fail(auth, "Unsupported netRole");
4398 goto fail;
4399 }
4400
4401 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
4402
4403 fail:
4404 json_free(root);
4405 os_free(unwrapped);
4406 return resp;
4407 }
4408
4409
4410 static struct wpabuf *
4411 dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
4412 const u8 *prot_hdr, u16 prot_hdr_len,
4413 const EVP_MD **ret_md)
4414 {
4415 struct json_token *root, *token;
4416 struct wpabuf *kid = NULL;
4417
4418 root = json_parse((const char *) prot_hdr, prot_hdr_len);
4419 if (!root) {
4420 wpa_printf(MSG_DEBUG,
4421 "DPP: JSON parsing failed for JWS Protected Header");
4422 goto fail;
4423 }
4424
4425 if (root->type != JSON_OBJECT) {
4426 wpa_printf(MSG_DEBUG,
4427 "DPP: JWS Protected Header root is not an object");
4428 goto fail;
4429 }
4430
4431 token = json_get_member(root, "typ");
4432 if (!token || token->type != JSON_STRING) {
4433 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
4434 goto fail;
4435 }
4436 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
4437 token->string);
4438 if (os_strcmp(token->string, "dppCon") != 0) {
4439 wpa_printf(MSG_DEBUG,
4440 "DPP: Unsupported JWS Protected Header typ=%s",
4441 token->string);
4442 goto fail;
4443 }
4444
4445 token = json_get_member(root, "alg");
4446 if (!token || token->type != JSON_STRING) {
4447 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
4448 goto fail;
4449 }
4450 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
4451 token->string);
4452 if (os_strcmp(token->string, curve->jws_alg) != 0) {
4453 wpa_printf(MSG_DEBUG,
4454 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4455 token->string, curve->jws_alg);
4456 goto fail;
4457 }
4458 if (os_strcmp(token->string, "ES256") == 0 ||
4459 os_strcmp(token->string, "BS256") == 0)
4460 *ret_md = EVP_sha256();
4461 else if (os_strcmp(token->string, "ES384") == 0 ||
4462 os_strcmp(token->string, "BS384") == 0)
4463 *ret_md = EVP_sha384();
4464 else if (os_strcmp(token->string, "ES512") == 0 ||
4465 os_strcmp(token->string, "BS512") == 0)
4466 *ret_md = EVP_sha512();
4467 else
4468 *ret_md = NULL;
4469 if (!*ret_md) {
4470 wpa_printf(MSG_DEBUG,
4471 "DPP: Unsupported JWS Protected Header alg=%s",
4472 token->string);
4473 goto fail;
4474 }
4475
4476 kid = json_get_member_base64url(root, "kid");
4477 if (!kid) {
4478 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
4479 goto fail;
4480 }
4481 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
4482 kid);
4483
4484 fail:
4485 json_free(root);
4486 return kid;
4487 }
4488
4489
4490 static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
4491 struct json_token *cred)
4492 {
4493 struct json_token *pass, *psk_hex;
4494
4495 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
4496
4497 pass = json_get_member(cred, "pass");
4498 psk_hex = json_get_member(cred, "psk_hex");
4499
4500 if (pass && pass->type == JSON_STRING) {
4501 size_t len = os_strlen(pass->string);
4502
4503 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
4504 pass->string, len);
4505 if (len < 8 || len > 63)
4506 return -1;
4507 os_strlcpy(auth->passphrase, pass->string,
4508 sizeof(auth->passphrase));
4509 } else if (psk_hex && psk_hex->type == JSON_STRING) {
4510 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
4511 hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
4512 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
4513 return -1;
4514 }
4515 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
4516 auth->psk, PMK_LEN);
4517 auth->psk_set = 1;
4518 } else {
4519 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
4520 return -1;
4521 }
4522
4523 return 0;
4524 }
4525
4526
4527 static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
4528 const struct dpp_curve_params **key_curve)
4529 {
4530 struct json_token *token;
4531 const struct dpp_curve_params *curve;
4532 struct wpabuf *x = NULL, *y = NULL;
4533 EC_GROUP *group;
4534 EVP_PKEY *pkey = NULL;
4535
4536 token = json_get_member(jwk, "kty");
4537 if (!token || token->type != JSON_STRING) {
4538 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
4539 goto fail;
4540 }
4541 if (os_strcmp(token->string, "EC") != 0) {
4542 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s",
4543 token->string);
4544 goto fail;
4545 }
4546
4547 token = json_get_member(jwk, "crv");
4548 if (!token || token->type != JSON_STRING) {
4549 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
4550 goto fail;
4551 }
4552 curve = dpp_get_curve_jwk_crv(token->string);
4553 if (!curve) {
4554 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
4555 token->string);
4556 goto fail;
4557 }
4558
4559 x = json_get_member_base64url(jwk, "x");
4560 if (!x) {
4561 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
4562 goto fail;
4563 }
4564 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
4565 if (wpabuf_len(x) != curve->prime_len) {
4566 wpa_printf(MSG_DEBUG,
4567 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4568 (unsigned int) wpabuf_len(x),
4569 (unsigned int) curve->prime_len, curve->name);
4570 goto fail;
4571 }
4572
4573 y = json_get_member_base64url(jwk, "y");
4574 if (!y) {
4575 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
4576 goto fail;
4577 }
4578 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
4579 if (wpabuf_len(y) != curve->prime_len) {
4580 wpa_printf(MSG_DEBUG,
4581 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4582 (unsigned int) wpabuf_len(y),
4583 (unsigned int) curve->prime_len, curve->name);
4584 goto fail;
4585 }
4586
4587 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
4588 if (!group) {
4589 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
4590 goto fail;
4591 }
4592
4593 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
4594 wpabuf_len(x));
4595 *key_curve = curve;
4596
4597 fail:
4598 wpabuf_free(x);
4599 wpabuf_free(y);
4600
4601 return pkey;
4602 }
4603
4604
4605 int dpp_key_expired(const char *timestamp, os_time_t *expiry)
4606 {
4607 struct os_time now;
4608 unsigned int year, month, day, hour, min, sec;
4609 os_time_t utime;
4610 const char *pos;
4611
4612 /* ISO 8601 date and time:
4613 * <date>T<time>
4614 * YYYY-MM-DDTHH:MM:SSZ
4615 * YYYY-MM-DDTHH:MM:SS+03:00
4616 */
4617 if (os_strlen(timestamp) < 19) {
4618 wpa_printf(MSG_DEBUG,
4619 "DPP: Too short timestamp - assume expired key");
4620 return 1;
4621 }
4622 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
4623 &year, &month, &day, &hour, &min, &sec) != 6) {
4624 wpa_printf(MSG_DEBUG,
4625 "DPP: Failed to parse expiration day - assume expired key");
4626 return 1;
4627 }
4628
4629 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
4630 wpa_printf(MSG_DEBUG,
4631 "DPP: Invalid date/time information - assume expired key");
4632 return 1;
4633 }
4634
4635 pos = timestamp + 19;
4636 if (*pos == 'Z' || *pos == '\0') {
4637 /* In UTC - no need to adjust */
4638 } else if (*pos == '-' || *pos == '+') {
4639 int items;
4640
4641 /* Adjust local time to UTC */
4642 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
4643 if (items < 1) {
4644 wpa_printf(MSG_DEBUG,
4645 "DPP: Invalid time zone designator (%s) - assume expired key",
4646 pos);
4647 return 1;
4648 }
4649 if (*pos == '-')
4650 utime += 3600 * hour;
4651 if (*pos == '+')
4652 utime -= 3600 * hour;
4653 if (items > 1) {
4654 if (*pos == '-')
4655 utime += 60 * min;
4656 if (*pos == '+')
4657 utime -= 60 * min;
4658 }
4659 } else {
4660 wpa_printf(MSG_DEBUG,
4661 "DPP: Invalid time zone designator (%s) - assume expired key",
4662 pos);
4663 return 1;
4664 }
4665 if (expiry)
4666 *expiry = utime;
4667
4668 if (os_get_time(&now) < 0) {
4669 wpa_printf(MSG_DEBUG,
4670 "DPP: Cannot get current time - assume expired key");
4671 return 1;
4672 }
4673
4674 if (now.sec > utime) {
4675 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
4676 utime, now.sec);
4677 return 1;
4678 }
4679
4680 return 0;
4681 }
4682
4683
4684 static int dpp_parse_connector(struct dpp_authentication *auth,
4685 const unsigned char *payload,
4686 u16 payload_len)
4687 {
4688 struct json_token *root, *groups, *netkey, *token;
4689 int ret = -1;
4690 EVP_PKEY *key = NULL;
4691 const struct dpp_curve_params *curve;
4692 unsigned int rules = 0;
4693
4694 root = json_parse((const char *) payload, payload_len);
4695 if (!root) {
4696 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4697 goto fail;
4698 }
4699
4700 groups = json_get_member(root, "groups");
4701 if (!groups || groups->type != JSON_ARRAY) {
4702 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
4703 goto skip_groups;
4704 }
4705 for (token = groups->child; token; token = token->sibling) {
4706 struct json_token *id, *role;
4707
4708 id = json_get_member(token, "groupId");
4709 if (!id || id->type != JSON_STRING) {
4710 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
4711 goto fail;
4712 }
4713
4714 role = json_get_member(token, "netRole");
4715 if (!role || role->type != JSON_STRING) {
4716 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
4717 goto fail;
4718 }
4719 wpa_printf(MSG_DEBUG,
4720 "DPP: connector group: groupId='%s' netRole='%s'",
4721 id->string, role->string);
4722 rules++;
4723 }
4724 skip_groups:
4725
4726 if (!rules) {
4727 wpa_printf(MSG_DEBUG,
4728 "DPP: Connector includes no groups");
4729 goto fail;
4730 }
4731
4732 token = json_get_member(root, "expiry");
4733 if (!token || token->type != JSON_STRING) {
4734 wpa_printf(MSG_DEBUG,
4735 "DPP: No expiry string found - connector does not expire");
4736 } else {
4737 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4738 if (dpp_key_expired(token->string,
4739 &auth->net_access_key_expiry)) {
4740 wpa_printf(MSG_DEBUG,
4741 "DPP: Connector (netAccessKey) has expired");
4742 goto fail;
4743 }
4744 }
4745
4746 netkey = json_get_member(root, "netAccessKey");
4747 if (!netkey || netkey->type != JSON_OBJECT) {
4748 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4749 goto fail;
4750 }
4751
4752 key = dpp_parse_jwk(netkey, &curve);
4753 if (!key)
4754 goto fail;
4755 dpp_debug_print_key("DPP: Received netAccessKey", key);
4756
4757 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
4758 wpa_printf(MSG_DEBUG,
4759 "DPP: netAccessKey in connector does not match own protocol key");
4760 #ifdef CONFIG_TESTING_OPTIONS
4761 if (auth->ignore_netaccesskey_mismatch) {
4762 wpa_printf(MSG_DEBUG,
4763 "DPP: TESTING - skip netAccessKey mismatch");
4764 } else {
4765 goto fail;
4766 }
4767 #else /* CONFIG_TESTING_OPTIONS */
4768 goto fail;
4769 #endif /* CONFIG_TESTING_OPTIONS */
4770 }
4771
4772 ret = 0;
4773 fail:
4774 EVP_PKEY_free(key);
4775 json_free(root);
4776 return ret;
4777 }
4778
4779
4780 static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
4781 {
4782 struct wpabuf *uncomp;
4783 int res;
4784 u8 hash[SHA256_MAC_LEN];
4785 const u8 *addr[1];
4786 size_t len[1];
4787
4788 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
4789 return -1;
4790 uncomp = dpp_get_pubkey_point(pub, 1);
4791 if (!uncomp)
4792 return -1;
4793 addr[0] = wpabuf_head(uncomp);
4794 len[0] = wpabuf_len(uncomp);
4795 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
4796 addr[0], len[0]);
4797 res = sha256_vector(1, addr, len, hash);
4798 wpabuf_free(uncomp);
4799 if (res < 0)
4800 return -1;
4801 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
4802 wpa_printf(MSG_DEBUG,
4803 "DPP: Received hash value does not match calculated public key hash value");
4804 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
4805 hash, SHA256_MAC_LEN);
4806 return -1;
4807 }
4808 return 0;
4809 }
4810
4811
4812 static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
4813 {
4814 unsigned char *der = NULL;
4815 int der_len;
4816
4817 der_len = i2d_PUBKEY(csign, &der);
4818 if (der_len <= 0)
4819 return;
4820 wpabuf_free(auth->c_sign_key);
4821 auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
4822 OPENSSL_free(der);
4823 }
4824
4825
4826 static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
4827 {
4828 unsigned char *der = NULL;
4829 int der_len;
4830 EC_KEY *eckey;
4831
4832 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
4833 if (!eckey)
4834 return;
4835
4836 der_len = i2d_ECPrivateKey(eckey, &der);
4837 if (der_len <= 0) {
4838 EC_KEY_free(eckey);
4839 return;
4840 }
4841 wpabuf_free(auth->net_access_key);
4842 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
4843 OPENSSL_free(der);
4844 EC_KEY_free(eckey);
4845 }
4846
4847
4848 struct dpp_signed_connector_info {
4849 unsigned char *payload;
4850 size_t payload_len;
4851 };
4852
4853 static enum dpp_status_error
4854 dpp_process_signed_connector(struct dpp_signed_connector_info *info,
4855 EVP_PKEY *csign_pub, const char *connector)
4856 {
4857 enum dpp_status_error ret = 255;
4858 const char *pos, *end, *signed_start, *signed_end;
4859 struct wpabuf *kid = NULL;
4860 unsigned char *prot_hdr = NULL, *signature = NULL;
4861 size_t prot_hdr_len = 0, signature_len = 0;
4862 const EVP_MD *sign_md = NULL;
4863 unsigned char *der = NULL;
4864 int der_len;
4865 int res;
4866 EVP_MD_CTX *md_ctx = NULL;
4867 ECDSA_SIG *sig = NULL;
4868 BIGNUM *r = NULL, *s = NULL;
4869 const struct dpp_curve_params *curve;
4870 EC_KEY *eckey;
4871 const EC_GROUP *group;
4872 int nid;
4873
4874 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
4875 if (!eckey)
4876 goto fail;
4877 group = EC_KEY_get0_group(eckey);
4878 if (!group)
4879 goto fail;
4880 nid = EC_GROUP_get_curve_name(group);
4881 curve = dpp_get_curve_nid(nid);
4882 if (!curve)
4883 goto fail;
4884 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
4885 os_memset(info, 0, sizeof(*info));
4886
4887 signed_start = pos = connector;
4888 end = os_strchr(pos, '.');
4889 if (!end) {
4890 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
4891 ret = DPP_STATUS_INVALID_CONNECTOR;
4892 goto fail;
4893 }
4894 prot_hdr = base64_url_decode((const unsigned char *) pos,
4895 end - pos, &prot_hdr_len);
4896 if (!prot_hdr) {
4897 wpa_printf(MSG_DEBUG,
4898 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
4899 ret = DPP_STATUS_INVALID_CONNECTOR;
4900 goto fail;
4901 }
4902 wpa_hexdump_ascii(MSG_DEBUG,
4903 "DPP: signedConnector - JWS Protected Header",
4904 prot_hdr, prot_hdr_len);
4905 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
4906 if (!kid) {
4907 ret = DPP_STATUS_INVALID_CONNECTOR;
4908 goto fail;
4909 }
4910 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
4911 wpa_printf(MSG_DEBUG,
4912 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
4913 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
4914 ret = DPP_STATUS_INVALID_CONNECTOR;
4915 goto fail;
4916 }
4917
4918 pos = end + 1;
4919 end = os_strchr(pos, '.');
4920 if (!end) {
4921 wpa_printf(MSG_DEBUG,
4922 "DPP: Missing dot(2) in signedConnector");
4923 ret = DPP_STATUS_INVALID_CONNECTOR;
4924 goto fail;
4925 }
4926 signed_end = end - 1;
4927 info->payload = base64_url_decode((const unsigned char *) pos,
4928 end - pos, &info->payload_len);
4929 if (!info->payload) {
4930 wpa_printf(MSG_DEBUG,
4931 "DPP: Failed to base64url decode signedConnector JWS Payload");
4932 ret = DPP_STATUS_INVALID_CONNECTOR;
4933 goto fail;
4934 }
4935 wpa_hexdump_ascii(MSG_DEBUG,
4936 "DPP: signedConnector - JWS Payload",
4937 info->payload, info->payload_len);
4938 pos = end + 1;
4939 signature = base64_url_decode((const unsigned char *) pos,
4940 os_strlen(pos), &signature_len);
4941 if (!signature) {
4942 wpa_printf(MSG_DEBUG,
4943 "DPP: Failed to base64url decode signedConnector signature");
4944 ret = DPP_STATUS_INVALID_CONNECTOR;
4945 goto fail;
4946 }
4947 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
4948 signature, signature_len);
4949
4950 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
4951 ret = DPP_STATUS_NO_MATCH;
4952 goto fail;
4953 }
4954
4955 if (signature_len & 0x01) {
4956 wpa_printf(MSG_DEBUG,
4957 "DPP: Unexpected signedConnector signature length (%d)",
4958 (int) signature_len);
4959 ret = DPP_STATUS_INVALID_CONNECTOR;
4960 goto fail;
4961 }
4962
4963 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
4964 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
4965 r = BN_bin2bn(signature, signature_len / 2, NULL);
4966 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
4967 sig = ECDSA_SIG_new();
4968 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
4969 goto fail;
4970 r = NULL;
4971 s = NULL;
4972
4973 der_len = i2d_ECDSA_SIG(sig, &der);
4974 if (der_len <= 0) {
4975 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
4976 goto fail;
4977 }
4978 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
4979 md_ctx = EVP_MD_CTX_create();
4980 if (!md_ctx)
4981 goto fail;
4982
4983 ERR_clear_error();
4984 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
4985 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
4986 ERR_error_string(ERR_get_error(), NULL));
4987 goto fail;
4988 }
4989 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
4990 signed_end - signed_start + 1) != 1) {
4991 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
4992 ERR_error_string(ERR_get_error(), NULL));
4993 goto fail;
4994 }
4995 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
4996 if (res != 1) {
4997 wpa_printf(MSG_DEBUG,
4998 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
4999 res, ERR_error_string(ERR_get_error(), NULL));
5000 ret = DPP_STATUS_INVALID_CONNECTOR;
5001 goto fail;
5002 }
5003
5004 ret = DPP_STATUS_OK;
5005 fail:
5006 EC_KEY_free(eckey);
5007 EVP_MD_CTX_destroy(md_ctx);
5008 os_free(prot_hdr);
5009 wpabuf_free(kid);
5010 os_free(signature);
5011 ECDSA_SIG_free(sig);
5012 BN_free(r);
5013 BN_free(s);
5014 OPENSSL_free(der);
5015 return ret;
5016 }
5017
5018
5019 static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5020 struct json_token *cred)
5021 {
5022 struct dpp_signed_connector_info info;
5023 struct json_token *token, *csign;
5024 int ret = -1;
5025 EVP_PKEY *csign_pub = NULL;
5026 const struct dpp_curve_params *key_curve = NULL;
5027 const char *signed_connector;
5028
5029 os_memset(&info, 0, sizeof(info));
5030
5031 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5032
5033 csign = json_get_member(cred, "csign");
5034 if (!csign || csign->type != JSON_OBJECT) {
5035 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5036 goto fail;
5037 }
5038
5039 csign_pub = dpp_parse_jwk(csign, &key_curve);
5040 if (!csign_pub) {
5041 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5042 goto fail;
5043 }
5044 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5045
5046 token = json_get_member(cred, "signedConnector");
5047 if (!token || token->type != JSON_STRING) {
5048 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5049 goto fail;
5050 }
5051 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5052 token->string, os_strlen(token->string));
5053 signed_connector = token->string;
5054
5055 if (os_strchr(signed_connector, '"') ||
5056 os_strchr(signed_connector, '\n')) {
5057 wpa_printf(MSG_DEBUG,
5058 "DPP: Unexpected character in signedConnector");
5059 goto fail;
5060 }
5061
5062 if (dpp_process_signed_connector(&info, csign_pub,
5063 signed_connector) != DPP_STATUS_OK)
5064 goto fail;
5065
5066 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
5067 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5068 goto fail;
5069 }
5070
5071 os_free(auth->connector);
5072 auth->connector = os_strdup(signed_connector);
5073
5074 dpp_copy_csign(auth, csign_pub);
5075 dpp_copy_netaccesskey(auth);
5076
5077 ret = 0;
5078 fail:
5079 EVP_PKEY_free(csign_pub);
5080 os_free(info.payload);
5081 return ret;
5082 }
5083
5084
5085 static int dpp_parse_conf_obj(struct dpp_authentication *auth,
5086 const u8 *conf_obj, u16 conf_obj_len)
5087 {
5088 int ret = -1;
5089 struct json_token *root, *token, *discovery, *cred;
5090
5091 root = json_parse((const char *) conf_obj, conf_obj_len);
5092 if (!root)
5093 return -1;
5094 if (root->type != JSON_OBJECT) {
5095 dpp_auth_fail(auth, "JSON root is not an object");
5096 goto fail;
5097 }
5098
5099 token = json_get_member(root, "wi-fi_tech");
5100 if (!token || token->type != JSON_STRING) {
5101 dpp_auth_fail(auth, "No wi-fi_tech string value found");
5102 goto fail;
5103 }
5104 if (os_strcmp(token->string, "infra") != 0) {
5105 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5106 token->string);
5107 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
5108 goto fail;
5109 }
5110
5111 discovery = json_get_member(root, "discovery");
5112 if (!discovery || discovery->type != JSON_OBJECT) {
5113 dpp_auth_fail(auth, "No discovery object in JSON");
5114 goto fail;
5115 }
5116
5117 token = json_get_member(discovery, "ssid");
5118 if (!token || token->type != JSON_STRING) {
5119 dpp_auth_fail(auth, "No discovery::ssid string value found");
5120 goto fail;
5121 }
5122 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
5123 token->string, os_strlen(token->string));
5124 if (os_strlen(token->string) > SSID_MAX_LEN) {
5125 dpp_auth_fail(auth, "Too long discovery::ssid string value");
5126 goto fail;
5127 }
5128 auth->ssid_len = os_strlen(token->string);
5129 os_memcpy(auth->ssid, token->string, auth->ssid_len);
5130
5131 cred = json_get_member(root, "cred");
5132 if (!cred || cred->type != JSON_OBJECT) {
5133 dpp_auth_fail(auth, "No cred object in JSON");
5134 goto fail;
5135 }
5136
5137 token = json_get_member(cred, "akm");
5138 if (!token || token->type != JSON_STRING) {
5139 dpp_auth_fail(auth, "No cred::akm string value found");
5140 goto fail;
5141 }
5142 if (os_strcmp(token->string, "psk") == 0) {
5143 if (dpp_parse_cred_legacy(auth, cred) < 0)
5144 goto fail;
5145 } else if (os_strcmp(token->string, "dpp") == 0) {
5146 if (dpp_parse_cred_dpp(auth, cred) < 0)
5147 goto fail;
5148 } else {
5149 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5150 token->string);
5151 dpp_auth_fail(auth, "Unsupported akm");
5152 goto fail;
5153 }
5154
5155 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5156 ret = 0;
5157 fail:
5158 json_free(root);
5159 return ret;
5160 }
5161
5162
5163 int dpp_conf_resp_rx(struct dpp_authentication *auth,
5164 const struct wpabuf *resp)
5165 {
5166 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5167 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5168 const u8 *addr[1];
5169 size_t len[1];
5170 u8 *unwrapped = NULL;
5171 size_t unwrapped_len = 0;
5172 int ret = -1;
5173
5174 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
5175 dpp_auth_fail(auth, "Invalid attribute in config response");
5176 return -1;
5177 }
5178
5179 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5180 DPP_ATTR_WRAPPED_DATA,
5181 &wrapped_data_len);
5182 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
5183 dpp_auth_fail(auth,
5184 "Missing or invalid required Wrapped Data attribute");
5185 return -1;
5186 }
5187
5188 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5189 wrapped_data, wrapped_data_len);
5190 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5191 unwrapped = os_malloc(unwrapped_len);
5192 if (!unwrapped)
5193 return -1;
5194
5195 addr[0] = wpabuf_head(resp);
5196 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
5197 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5198
5199 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5200 wrapped_data, wrapped_data_len,
5201 1, addr, len, unwrapped) < 0) {
5202 dpp_auth_fail(auth, "AES-SIV decryption failed");
5203 goto fail;
5204 }
5205 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5206 unwrapped, unwrapped_len);
5207
5208 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
5209 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
5210 goto fail;
5211 }
5212
5213 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5214 DPP_ATTR_ENROLLEE_NONCE,
5215 &e_nonce_len);
5216 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
5217 dpp_auth_fail(auth,
5218 "Missing or invalid Enrollee Nonce attribute");
5219 goto fail;
5220 }
5221 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5222 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
5223 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
5224 goto fail;
5225 }
5226
5227 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5228 DPP_ATTR_STATUS, &status_len);
5229 if (!status || status_len < 1) {
5230 dpp_auth_fail(auth,
5231 "Missing or invalid required DPP Status attribute");
5232 goto fail;
5233 }
5234 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5235 if (status[0] != DPP_STATUS_OK) {
5236 dpp_auth_fail(auth, "Configurator rejected configuration");
5237 goto fail;
5238 }
5239
5240 conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
5241 DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
5242 if (!conf_obj) {
5243 dpp_auth_fail(auth,
5244 "Missing required Configuration Object attribute");
5245 goto fail;
5246 }
5247 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
5248 conf_obj, conf_obj_len);
5249 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
5250 goto fail;
5251
5252 ret = 0;
5253
5254 fail:
5255 os_free(unwrapped);
5256 return ret;
5257 }
5258
5259
5260 void dpp_configurator_free(struct dpp_configurator *conf)
5261 {
5262 if (!conf)
5263 return;
5264 EVP_PKEY_free(conf->csign);
5265 os_free(conf->kid);
5266 os_free(conf);
5267 }
5268
5269
5270 struct dpp_configurator *
5271 dpp_keygen_configurator(const char *curve, const u8 *privkey,
5272 size_t privkey_len)
5273 {
5274 struct dpp_configurator *conf;
5275 struct wpabuf *csign_pub = NULL;
5276 u8 kid_hash[SHA256_MAC_LEN];
5277 const u8 *addr[1];
5278 size_t len[1];
5279
5280 conf = os_zalloc(sizeof(*conf));
5281 if (!conf)
5282 return NULL;
5283
5284 if (!curve) {
5285 conf->curve = &dpp_curves[0];
5286 } else {
5287 conf->curve = dpp_get_curve_name(curve);
5288 if (!conf->curve) {
5289 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5290 curve);
5291 return NULL;
5292 }
5293 }
5294 if (privkey)
5295 conf->csign = dpp_set_keypair(&conf->curve, privkey,
5296 privkey_len);
5297 else
5298 conf->csign = dpp_gen_keypair(conf->curve);
5299 if (!conf->csign)
5300 goto fail;
5301 conf->own = 1;
5302
5303 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
5304 if (!csign_pub) {
5305 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
5306 goto fail;
5307 }
5308
5309 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5310 addr[0] = wpabuf_head(csign_pub);
5311 len[0] = wpabuf_len(csign_pub);
5312 if (sha256_vector(1, addr, len, kid_hash) < 0) {
5313 wpa_printf(MSG_DEBUG,
5314 "DPP: Failed to derive kid for C-sign-key");
5315 goto fail;
5316 }
5317
5318 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
5319 NULL, 0);
5320 if (!conf->kid)
5321 goto fail;
5322 out:
5323 wpabuf_free(csign_pub);
5324 return conf;
5325 fail:
5326 dpp_configurator_free(conf);
5327 conf = NULL;
5328 goto out;
5329 }
5330
5331
5332 int dpp_configurator_own_config(struct dpp_authentication *auth,
5333 const char *curve)
5334 {
5335 struct wpabuf *conf_obj;
5336 int ret = -1;
5337
5338 if (!auth->conf) {
5339 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
5340 return -1;
5341 }
5342
5343 if (!curve) {
5344 auth->curve = &dpp_curves[0];
5345 } else {
5346 auth->curve = dpp_get_curve_name(curve);
5347 if (!auth->curve) {
5348 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5349 curve);
5350 return -1;
5351 }
5352 }
5353 wpa_printf(MSG_DEBUG,
5354 "DPP: Building own configuration/connector with curve %s",
5355 auth->curve->name);
5356
5357 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
5358 if (!auth->own_protocol_key)
5359 return -1;
5360 dpp_copy_netaccesskey(auth);
5361 auth->peer_protocol_key = auth->own_protocol_key;
5362 dpp_copy_csign(auth, auth->conf->csign);
5363
5364 conf_obj = dpp_build_conf_obj(auth, 0);
5365 if (!conf_obj)
5366 goto fail;
5367 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
5368 wpabuf_len(conf_obj));
5369 fail:
5370 wpabuf_free(conf_obj);
5371 auth->peer_protocol_key = NULL;
5372 return ret;
5373 }
5374
5375
5376 static int dpp_compatible_netrole(const char *role1, const char *role2)
5377 {
5378 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
5379 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
5380 }
5381
5382
5383 static int dpp_connector_compatible_group(struct json_token *root,
5384 const char *group_id,
5385 const char *net_role)
5386 {
5387 struct json_token *groups, *token;
5388
5389 groups = json_get_member(root, "groups");
5390 if (!groups || groups->type != JSON_ARRAY)
5391 return 0;
5392
5393 for (token = groups->child; token; token = token->sibling) {
5394 struct json_token *id, *role;
5395
5396 id = json_get_member(token, "groupId");
5397 if (!id || id->type != JSON_STRING)
5398 continue;
5399
5400 role = json_get_member(token, "netRole");
5401 if (!role || role->type != JSON_STRING)
5402 continue;
5403
5404 if (os_strcmp(id->string, "*") != 0 &&
5405 os_strcmp(group_id, "*") != 0 &&
5406 os_strcmp(id->string, group_id) != 0)
5407 continue;
5408
5409 if (dpp_compatible_netrole(role->string, net_role))
5410 return 1;
5411 }
5412
5413 return 0;
5414 }
5415
5416
5417 static int dpp_connector_match_groups(struct json_token *own_root,
5418 struct json_token *peer_root)
5419 {
5420 struct json_token *groups, *token;
5421
5422 groups = json_get_member(peer_root, "groups");
5423 if (!groups || groups->type != JSON_ARRAY) {
5424 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
5425 return 0;
5426 }
5427
5428 for (token = groups->child; token; token = token->sibling) {
5429 struct json_token *id, *role;
5430
5431 id = json_get_member(token, "groupId");
5432 if (!id || id->type != JSON_STRING) {
5433 wpa_printf(MSG_DEBUG,
5434 "DPP: Missing peer groupId string");
5435 continue;
5436 }
5437
5438 role = json_get_member(token, "netRole");
5439 if (!role || role->type != JSON_STRING) {
5440 wpa_printf(MSG_DEBUG,
5441 "DPP: Missing peer groups::netRole string");
5442 continue;
5443 }
5444 wpa_printf(MSG_DEBUG,
5445 "DPP: peer connector group: groupId='%s' netRole='%s'",
5446 id->string, role->string);
5447 if (dpp_connector_compatible_group(own_root, id->string,
5448 role->string)) {
5449 wpa_printf(MSG_DEBUG,
5450 "DPP: Compatible group/netRole in own connector");
5451 return 1;
5452 }
5453 }
5454
5455 return 0;
5456 }
5457
5458
5459 static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
5460 unsigned int hash_len)
5461 {
5462 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5463 const char *info = "DPP PMK";
5464 int res;
5465
5466 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5467
5468 /* HKDF-Extract(<>, N.x) */
5469 os_memset(salt, 0, hash_len);
5470 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
5471 return -1;
5472 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5473 prk, hash_len);
5474
5475 /* HKDF-Expand(PRK, info, L) */
5476 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
5477 os_memset(prk, 0, hash_len);
5478 if (res < 0)
5479 return -1;
5480
5481 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5482 pmk, hash_len);
5483 return 0;
5484 }
5485
5486
5487 static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
5488 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
5489 {
5490 struct wpabuf *nkx, *pkx;
5491 int ret = -1, res;
5492 const u8 *addr[2];
5493 size_t len[2];
5494 u8 hash[SHA256_MAC_LEN];
5495
5496 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5497 nkx = dpp_get_pubkey_point(own_key, 0);
5498 pkx = dpp_get_pubkey_point(peer_key, 0);
5499 if (!nkx || !pkx)
5500 goto fail;
5501 addr[0] = wpabuf_head(nkx);
5502 len[0] = wpabuf_len(nkx) / 2;
5503 addr[1] = wpabuf_head(pkx);
5504 len[1] = wpabuf_len(pkx) / 2;
5505 if (len[0] != len[1])
5506 goto fail;
5507 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
5508 addr[0] = wpabuf_head(pkx);
5509 addr[1] = wpabuf_head(nkx);
5510 }
5511 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
5512 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
5513 res = sha256_vector(2, addr, len, hash);
5514 if (res < 0)
5515 goto fail;
5516 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
5517 os_memcpy(pmkid, hash, PMKID_LEN);
5518 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
5519 ret = 0;
5520 fail:
5521 wpabuf_free(nkx);
5522 wpabuf_free(pkx);
5523 return ret;
5524 }
5525
5526
5527 enum dpp_status_error
5528 dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
5529 const u8 *net_access_key, size_t net_access_key_len,
5530 const u8 *csign_key, size_t csign_key_len,
5531 const u8 *peer_connector, size_t peer_connector_len,
5532 os_time_t *expiry)
5533 {
5534 struct json_token *root = NULL, *netkey, *token;
5535 struct json_token *own_root = NULL;
5536 enum dpp_status_error ret = 255, res;
5537 EVP_PKEY *own_key = NULL, *peer_key = NULL;
5538 struct wpabuf *own_key_pub = NULL;
5539 const struct dpp_curve_params *curve, *own_curve;
5540 struct dpp_signed_connector_info info;
5541 const unsigned char *p;
5542 EVP_PKEY *csign = NULL;
5543 char *signed_connector = NULL;
5544 const char *pos, *end;
5545 unsigned char *own_conn = NULL;
5546 size_t own_conn_len;
5547 EVP_PKEY_CTX *ctx = NULL;
5548 size_t Nx_len;
5549 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
5550
5551 os_memset(intro, 0, sizeof(*intro));
5552 os_memset(&info, 0, sizeof(info));
5553 if (expiry)
5554 *expiry = 0;
5555
5556 p = csign_key;
5557 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
5558 if (!csign) {
5559 wpa_printf(MSG_ERROR,
5560 "DPP: Failed to parse local C-sign-key information");
5561 goto fail;
5562 }
5563
5564 own_key = dpp_set_keypair(&own_curve, net_access_key,
5565 net_access_key_len);
5566 if (!own_key) {
5567 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
5568 goto fail;
5569 }
5570
5571 pos = os_strchr(own_connector, '.');
5572 if (!pos) {
5573 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
5574 goto fail;
5575 }
5576 pos++;
5577 end = os_strchr(pos, '.');
5578 if (!end) {
5579 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
5580 goto fail;
5581 }
5582 own_conn = base64_url_decode((const unsigned char *) pos,
5583 end - pos, &own_conn_len);
5584 if (!own_conn) {
5585 wpa_printf(MSG_DEBUG,
5586 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5587 goto fail;
5588 }
5589
5590 own_root = json_parse((const char *) own_conn, own_conn_len);
5591 if (!own_root) {
5592 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
5593 goto fail;
5594 }
5595
5596 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
5597 peer_connector, peer_connector_len);
5598 signed_connector = os_malloc(peer_connector_len + 1);
5599 if (!signed_connector)
5600 goto fail;
5601 os_memcpy(signed_connector, peer_connector, peer_connector_len);
5602 signed_connector[peer_connector_len] = '\0';
5603
5604 res = dpp_process_signed_connector(&info, csign, signed_connector);
5605 if (res != DPP_STATUS_OK) {
5606 ret = res;
5607 goto fail;
5608 }
5609
5610 root = json_parse((const char *) info.payload, info.payload_len);
5611 if (!root) {
5612 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5613 ret = DPP_STATUS_INVALID_CONNECTOR;
5614 goto fail;
5615 }
5616
5617 if (!dpp_connector_match_groups(own_root, root)) {
5618 wpa_printf(MSG_DEBUG,
5619 "DPP: Peer connector does not include compatible group netrole with own connector");
5620 ret = DPP_STATUS_NO_MATCH;
5621 goto fail;
5622 }
5623
5624 token = json_get_member(root, "expiry");
5625 if (!token || token->type != JSON_STRING) {
5626 wpa_printf(MSG_DEBUG,
5627 "DPP: No expiry string found - connector does not expire");
5628 } else {
5629 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5630 if (dpp_key_expired(token->string, expiry)) {
5631 wpa_printf(MSG_DEBUG,
5632 "DPP: Connector (netAccessKey) has expired");
5633 ret = DPP_STATUS_INVALID_CONNECTOR;
5634 goto fail;
5635 }
5636 }
5637
5638 netkey = json_get_member(root, "netAccessKey");
5639 if (!netkey || netkey->type != JSON_OBJECT) {
5640 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
5641 ret = DPP_STATUS_INVALID_CONNECTOR;
5642 goto fail;
5643 }
5644
5645 peer_key = dpp_parse_jwk(netkey, &curve);
5646 if (!peer_key) {
5647 ret = DPP_STATUS_INVALID_CONNECTOR;
5648 goto fail;
5649 }
5650 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
5651
5652 if (own_curve != curve) {
5653 wpa_printf(MSG_DEBUG,
5654 "DPP: Mismatching netAccessKey curves (%s != %s)",
5655 own_curve->name, curve->name);
5656 ret = DPP_STATUS_INVALID_CONNECTOR;
5657 goto fail;
5658 }
5659
5660 /* ECDH: N = nk * PK */
5661 ctx = EVP_PKEY_CTX_new(own_key, NULL);
5662 if (!ctx ||
5663 EVP_PKEY_derive_init(ctx) != 1 ||
5664 EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
5665 EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
5666 Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
5667 EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
5668 wpa_printf(MSG_ERROR,
5669 "DPP: Failed to derive ECDH shared secret: %s",
5670 ERR_error_string(ERR_get_error(), NULL));
5671 goto fail;
5672 }
5673
5674 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
5675 Nx, Nx_len);
5676
5677 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5678 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
5679 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
5680 goto fail;
5681 }
5682 intro->pmk_len = curve->hash_len;
5683
5684 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5685 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
5686 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
5687 goto fail;
5688 }
5689
5690 ret = DPP_STATUS_OK;
5691 fail:
5692 if (ret != DPP_STATUS_OK)
5693 os_memset(intro, 0, sizeof(*intro));
5694 os_memset(Nx, 0, sizeof(Nx));
5695 EVP_PKEY_CTX_free(ctx);
5696 os_free(own_conn);
5697 os_free(signed_connector);
5698 os_free(info.payload);
5699 EVP_PKEY_free(own_key);
5700 wpabuf_free(own_key_pub);
5701 EVP_PKEY_free(peer_key);
5702 EVP_PKEY_free(csign);
5703 json_free(root);
5704 json_free(own_root);
5705 return ret;
5706 }
5707
5708
5709 static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
5710 int init)
5711 {
5712 EC_GROUP *group;
5713 size_t len = curve->prime_len;
5714 const u8 *x, *y;
5715
5716 switch (curve->ike_group) {
5717 case 19:
5718 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
5719 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
5720 break;
5721 case 20:
5722 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
5723 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
5724 break;
5725 case 21:
5726 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
5727 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
5728 break;
5729 case 28:
5730 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
5731 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
5732 break;
5733 case 29:
5734 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
5735 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
5736 break;
5737 case 30:
5738 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
5739 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
5740 break;
5741 default:
5742 return NULL;
5743 }
5744
5745 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5746 if (!group)
5747 return NULL;
5748 return dpp_set_pubkey_point_group(group, x, y, len);
5749 }
5750
5751
5752 static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
5753 const u8 *mac_init, const char *code,
5754 const char *identifier, BN_CTX *bnctx,
5755 const EC_GROUP **ret_group)
5756 {
5757 u8 hash[DPP_MAX_HASH_LEN];
5758 const u8 *addr[3];
5759 size_t len[3];
5760 unsigned int num_elem = 0;
5761 EC_POINT *Qi = NULL;
5762 EVP_PKEY *Pi = NULL;
5763 EC_KEY *Pi_ec = NULL;
5764 const EC_POINT *Pi_point;
5765 BIGNUM *hash_bn = NULL;
5766 const EC_GROUP *group = NULL;
5767 EC_GROUP *group2 = NULL;
5768
5769 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5770
5771 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
5772 addr[num_elem] = mac_init;
5773 len[num_elem] = ETH_ALEN;
5774 num_elem++;
5775 if (identifier) {
5776 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
5777 identifier);
5778 addr[num_elem] = (const u8 *) identifier;
5779 len[num_elem] = os_strlen(identifier);
5780 num_elem++;
5781 }
5782 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
5783 addr[num_elem] = (const u8 *) code;
5784 len[num_elem] = os_strlen(code);
5785 num_elem++;
5786 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
5787 goto fail;
5788 wpa_hexdump_key(MSG_DEBUG,
5789 "DPP: H(MAC-Initiator | [identifier |] code)",
5790 hash, curve->hash_len);
5791 Pi = dpp_pkex_get_role_elem(curve, 1);
5792 if (!Pi)
5793 goto fail;
5794 dpp_debug_print_key("DPP: Pi", Pi);
5795 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
5796 if (!Pi_ec)
5797 goto fail;
5798 Pi_point = EC_KEY_get0_public_key(Pi_ec);
5799
5800 group = EC_KEY_get0_group(Pi_ec);
5801 if (!group)
5802 goto fail;
5803 group2 = EC_GROUP_dup(group);
5804 if (!group2)
5805 goto fail;
5806 Qi = EC_POINT_new(group2);
5807 if (!Qi) {
5808 EC_GROUP_free(group2);
5809 goto fail;
5810 }
5811 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
5812 if (!hash_bn ||
5813 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
5814 goto fail;
5815 if (EC_POINT_is_at_infinity(group, Qi)) {
5816 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
5817 goto fail;
5818 }
5819 out:
5820 EC_KEY_free(Pi_ec);
5821 EVP_PKEY_free(Pi);
5822 BN_clear_free(hash_bn);
5823 if (ret_group)
5824 *ret_group = group2;
5825 return Qi;
5826 fail:
5827 EC_POINT_free(Qi);
5828 Qi = NULL;
5829 goto out;
5830 }
5831
5832
5833 static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
5834 const u8 *mac_resp, const char *code,
5835 const char *identifier, BN_CTX *bnctx,
5836 const EC_GROUP **ret_group)
5837 {
5838 u8 hash[DPP_MAX_HASH_LEN];
5839 const u8 *addr[3];
5840 size_t len[3];
5841 unsigned int num_elem = 0;
5842 EC_POINT *Qr = NULL;
5843 EVP_PKEY *Pr = NULL;
5844 EC_KEY *Pr_ec = NULL;
5845 const EC_POINT *Pr_point;
5846 BIGNUM *hash_bn = NULL;
5847 const EC_GROUP *group = NULL;
5848 EC_GROUP *group2 = NULL;
5849
5850 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5851
5852 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
5853 addr[num_elem] = mac_resp;
5854 len[num_elem] = ETH_ALEN;
5855 num_elem++;
5856 if (identifier) {
5857 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
5858 identifier);
5859 addr[num_elem] = (const u8 *) identifier;
5860 len[num_elem] = os_strlen(identifier);
5861 num_elem++;
5862 }
5863 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
5864 addr[num_elem] = (const u8 *) code;
5865 len[num_elem] = os_strlen(code);
5866 num_elem++;
5867 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
5868 goto fail;
5869 wpa_hexdump_key(MSG_DEBUG,
5870 "DPP: H(MAC-Responder | [identifier |] code)",
5871 hash, curve->hash_len);
5872 Pr = dpp_pkex_get_role_elem(curve, 0);
5873 if (!Pr)
5874 goto fail;
5875 dpp_debug_print_key("DPP: Pr", Pr);
5876 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
5877 if (!Pr_ec)
5878 goto fail;
5879 Pr_point = EC_KEY_get0_public_key(Pr_ec);
5880
5881 group = EC_KEY_get0_group(Pr_ec);
5882 if (!group)
5883 goto fail;
5884 group2 = EC_GROUP_dup(group);
5885 if (!group2)
5886 goto fail;
5887 Qr = EC_POINT_new(group2);
5888 if (!Qr) {
5889 EC_GROUP_free(group2);
5890 goto fail;
5891 }
5892 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
5893 if (!hash_bn ||
5894 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
5895 goto fail;
5896 if (EC_POINT_is_at_infinity(group, Qr)) {
5897 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
5898 goto fail;
5899 }
5900 out:
5901 EC_KEY_free(Pr_ec);
5902 EVP_PKEY_free(Pr);
5903 BN_clear_free(hash_bn);
5904 if (ret_group)
5905 *ret_group = group2;
5906 return Qr;
5907 fail:
5908 EC_POINT_free(Qr);
5909 Qr = NULL;
5910 goto out;
5911 }
5912
5913
5914 #ifdef CONFIG_TESTING_OPTIONS
5915 static int dpp_test_gen_invalid_key(struct wpabuf *msg,
5916 const struct dpp_curve_params *curve)
5917 {
5918 BN_CTX *ctx;
5919 BIGNUM *x, *y;
5920 int ret = -1;
5921 EC_GROUP *group;
5922 EC_POINT *point;
5923
5924 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5925 if (!group)
5926 return -1;
5927
5928 ctx = BN_CTX_new();
5929 point = EC_POINT_new(group);
5930 x = BN_new();
5931 y = BN_new();
5932 if (!ctx || !point || !x || !y)
5933 goto fail;
5934
5935 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
5936 goto fail;
5937
5938 /* Generate a random y coordinate that results in a point that is not
5939 * on the curve. */
5940 for (;;) {
5941 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
5942 goto fail;
5943
5944 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
5945 ctx) != 1) {
5946 #ifdef OPENSSL_IS_BORINGSSL
5947 /* Unlike OpenSSL, BoringSSL returns an error from
5948 * EC_POINT_set_affine_coordinates_GFp() is not on the curve. */
5949 break;
5950 #else /* OPENSSL_IS_BORINGSSL */
5951 goto fail;
5952 #endif /* OPENSSL_IS_BORINGSSL */
5953 }
5954
5955 if (!EC_POINT_is_on_curve(group, point, ctx))
5956 break;
5957 }
5958
5959 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
5960 curve->prime_len) < 0 ||
5961 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
5962 curve->prime_len) < 0)
5963 goto fail;
5964
5965 ret = 0;
5966 fail:
5967 if (ret < 0)
5968 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
5969 BN_free(x);
5970 BN_free(y);
5971 EC_POINT_free(point);
5972 BN_CTX_free(ctx);
5973
5974 return ret;
5975 }
5976 #endif /* CONFIG_TESTING_OPTIONS */
5977
5978
5979 static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
5980 {
5981 EC_KEY *X_ec = NULL;
5982 const EC_POINT *X_point;
5983 BN_CTX *bnctx = NULL;
5984 const EC_GROUP *group;
5985 EC_POINT *Qi = NULL, *M = NULL;
5986 struct wpabuf *M_buf = NULL;
5987 BIGNUM *Mx = NULL, *My = NULL;
5988 struct wpabuf *msg = NULL;
5989 size_t attr_len;
5990 const struct dpp_curve_params *curve = pkex->own_bi->curve;
5991
5992 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
5993
5994 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5995 bnctx = BN_CTX_new();
5996 if (!bnctx)
5997 goto fail;
5998 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
5999 pkex->identifier, bnctx, &group);
6000 if (!Qi)
6001 goto fail;
6002
6003 /* Generate a random ephemeral keypair x/X */
6004 pkex->x = dpp_gen_keypair(curve);
6005 if (!pkex->x)
6006 goto fail;
6007
6008 /* M = X + Qi */
6009 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
6010 if (!X_ec)
6011 goto fail;
6012 X_point = EC_KEY_get0_public_key(X_ec);
6013 if (!X_point)
6014 goto fail;
6015 M = EC_POINT_new(group);
6016 Mx = BN_new();
6017 My = BN_new();
6018 if (!M || !Mx || !My ||
6019 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
6020 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
6021 goto fail;
6022
6023 /* Initiator -> Responder: group, [identifier,] M */
6024 attr_len = 4 + 2;
6025 if (pkex->identifier)
6026 attr_len += 4 + os_strlen(pkex->identifier);
6027 attr_len += 4 + 2 * curve->prime_len;
6028 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
6029 if (!msg)
6030 goto fail;
6031
6032 #ifdef CONFIG_TESTING_OPTIONS
6033 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
6034 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
6035 goto skip_finite_cyclic_group;
6036 }
6037 #endif /* CONFIG_TESTING_OPTIONS */
6038
6039 /* Finite Cyclic Group attribute */
6040 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6041 wpabuf_put_le16(msg, 2);
6042 wpabuf_put_le16(msg, curve->ike_group);
6043
6044 #ifdef CONFIG_TESTING_OPTIONS
6045 skip_finite_cyclic_group:
6046 #endif /* CONFIG_TESTING_OPTIONS */
6047
6048 /* Code Identifier attribute */
6049 if (pkex->identifier) {
6050 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6051 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6052 wpabuf_put_str(msg, pkex->identifier);
6053 }
6054
6055 #ifdef CONFIG_TESTING_OPTIONS
6056 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6057 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6058 goto out;
6059 }
6060 #endif /* CONFIG_TESTING_OPTIONS */
6061
6062 /* M in Encrypted Key attribute */
6063 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6064 wpabuf_put_le16(msg, 2 * curve->prime_len);
6065
6066 #ifdef CONFIG_TESTING_OPTIONS
6067 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6068 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
6069 if (dpp_test_gen_invalid_key(msg, curve) < 0)
6070 goto fail;
6071 goto out;
6072 }
6073 #endif /* CONFIG_TESTING_OPTIONS */
6074
6075 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
6076 curve->prime_len) < 0 ||
6077 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
6078 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
6079 curve->prime_len) < 0)
6080 goto fail;
6081
6082 out:
6083 wpabuf_free(M_buf);
6084 EC_KEY_free(X_ec);
6085 EC_POINT_free(M);
6086 EC_POINT_free(Qi);
6087 BN_clear_free(Mx);
6088 BN_clear_free(My);
6089 BN_CTX_free(bnctx);
6090 return msg;
6091 fail:
6092 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
6093 wpabuf_free(msg);
6094 msg = NULL;
6095 goto out;
6096 }
6097
6098
6099 static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
6100 {
6101 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
6102 }
6103
6104
6105 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
6106 const u8 *own_mac,
6107 const char *identifier,
6108 const char *code)
6109 {
6110 struct dpp_pkex *pkex;
6111
6112 pkex = os_zalloc(sizeof(*pkex));
6113 if (!pkex)
6114 return NULL;
6115 pkex->msg_ctx = msg_ctx;
6116 pkex->initiator = 1;
6117 pkex->own_bi = bi;
6118 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6119 if (identifier) {
6120 pkex->identifier = os_strdup(identifier);
6121 if (!pkex->identifier)
6122 goto fail;
6123 }
6124 pkex->code = os_strdup(code);
6125 if (!pkex->code)
6126 goto fail;
6127 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
6128 if (!pkex->exchange_req)
6129 goto fail;
6130 return pkex;
6131 fail:
6132 dpp_pkex_free(pkex);
6133 return NULL;
6134 }
6135
6136
6137 static struct wpabuf *
6138 dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
6139 enum dpp_status_error status,
6140 const BIGNUM *Nx, const BIGNUM *Ny)
6141 {
6142 struct wpabuf *msg = NULL;
6143 size_t attr_len;
6144 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6145
6146 /* Initiator -> Responder: DPP Status, [identifier,] N */
6147 attr_len = 4 + 1;
6148 if (pkex->identifier)
6149 attr_len += 4 + os_strlen(pkex->identifier);
6150 attr_len += 4 + 2 * curve->prime_len;
6151 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
6152 if (!msg)
6153 goto fail;
6154
6155 #ifdef CONFIG_TESTING_OPTIONS
6156 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
6157 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
6158 goto skip_status;
6159 }
6160
6161 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
6162 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
6163 status = 255;
6164 }
6165 #endif /* CONFIG_TESTING_OPTIONS */
6166
6167 /* DPP Status */
6168 dpp_build_attr_status(msg, status);
6169
6170 #ifdef CONFIG_TESTING_OPTIONS
6171 skip_status:
6172 #endif /* CONFIG_TESTING_OPTIONS */
6173
6174 /* Code Identifier attribute */
6175 if (pkex->identifier) {
6176 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6177 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6178 wpabuf_put_str(msg, pkex->identifier);
6179 }
6180
6181 if (status != DPP_STATUS_OK)
6182 goto skip_encrypted_key;
6183
6184 #ifdef CONFIG_TESTING_OPTIONS
6185 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
6186 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6187 goto skip_encrypted_key;
6188 }
6189 #endif /* CONFIG_TESTING_OPTIONS */
6190
6191 /* N in Encrypted Key attribute */
6192 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6193 wpabuf_put_le16(msg, 2 * curve->prime_len);
6194
6195 #ifdef CONFIG_TESTING_OPTIONS
6196 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
6197 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
6198 if (dpp_test_gen_invalid_key(msg, curve) < 0)
6199 goto fail;
6200 goto skip_encrypted_key;
6201 }
6202 #endif /* CONFIG_TESTING_OPTIONS */
6203
6204 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
6205 curve->prime_len) < 0 ||
6206 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
6207 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
6208 curve->prime_len) < 0)
6209 goto fail;
6210
6211 skip_encrypted_key:
6212 if (status == DPP_STATUS_BAD_GROUP) {
6213 /* Finite Cyclic Group attribute */
6214 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6215 wpabuf_put_le16(msg, 2);
6216 wpabuf_put_le16(msg, curve->ike_group);
6217 }
6218
6219 return msg;
6220 fail:
6221 wpabuf_free(msg);
6222 return NULL;
6223 }
6224
6225
6226 static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
6227 const u8 *Mx, size_t Mx_len,
6228 const u8 *Nx, size_t Nx_len,
6229 const char *code,
6230 const u8 *Kx, size_t Kx_len,
6231 u8 *z, unsigned int hash_len)
6232 {
6233 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6234 int res;
6235 u8 *info, *pos;
6236 size_t info_len;
6237
6238 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6239 */
6240
6241 /* HKDF-Extract(<>, IKM=K.x) */
6242 os_memset(salt, 0, hash_len);
6243 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
6244 return -1;
6245 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
6246 prk, hash_len);
6247 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
6248 info = os_malloc(info_len);
6249 if (!info)
6250 return -1;
6251 pos = info;
6252 os_memcpy(pos, mac_init, ETH_ALEN);
6253 pos += ETH_ALEN;
6254 os_memcpy(pos, mac_resp, ETH_ALEN);
6255 pos += ETH_ALEN;
6256 os_memcpy(pos, Mx, Mx_len);
6257 pos += Mx_len;
6258 os_memcpy(pos, Nx, Nx_len);
6259 pos += Nx_len;
6260 os_memcpy(pos, code, os_strlen(code));
6261
6262 /* HKDF-Expand(PRK, info, L) */
6263 if (hash_len == 32)
6264 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
6265 z, hash_len);
6266 else if (hash_len == 48)
6267 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
6268 z, hash_len);
6269 else if (hash_len == 64)
6270 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
6271 z, hash_len);
6272 else
6273 res = -1;
6274 os_free(info);
6275 os_memset(prk, 0, hash_len);
6276 if (res < 0)
6277 return -1;
6278
6279 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
6280 z, hash_len);
6281 return 0;
6282 }
6283
6284
6285 struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
6286 struct dpp_bootstrap_info *bi,
6287 const u8 *own_mac,
6288 const u8 *peer_mac,
6289 const char *identifier,
6290 const char *code,
6291 const u8 *buf, size_t len)
6292 {
6293 const u8 *attr_group, *attr_id, *attr_key;
6294 u16 attr_group_len, attr_id_len, attr_key_len;
6295 const struct dpp_curve_params *curve = bi->curve;
6296 u16 ike_group;
6297 struct dpp_pkex *pkex = NULL;
6298 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
6299 BN_CTX *bnctx = NULL;
6300 const EC_GROUP *group;
6301 BIGNUM *Mx = NULL, *My = NULL;
6302 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
6303 const EC_POINT *Y_point;
6304 BIGNUM *Nx = NULL, *Ny = NULL;
6305 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
6306 size_t Kx_len;
6307 int res;
6308 EVP_PKEY_CTX *ctx = NULL;
6309
6310 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
6311 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6312 "PKEX counter t limit reached - ignore message");
6313 return NULL;
6314 }
6315
6316 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
6317 &attr_id_len);
6318 if (!attr_id && identifier) {
6319 wpa_printf(MSG_DEBUG,
6320 "DPP: No PKEX code identifier received, but expected one");
6321 return NULL;
6322 }
6323 if (attr_id && identifier &&
6324 (os_strlen(identifier) != attr_id_len ||
6325 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
6326 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
6327 return NULL;
6328 }
6329
6330 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
6331 &attr_group_len);
6332 if (!attr_group || attr_group_len != 2) {
6333 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6334 "Missing or invalid Finite Cyclic Group attribute");
6335 return NULL;
6336 }
6337 ike_group = WPA_GET_LE16(attr_group);
6338 if (ike_group != curve->ike_group) {
6339 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6340 "Mismatching PKEX curve: peer=%u own=%u",
6341 ike_group, curve->ike_group);
6342 pkex = os_zalloc(sizeof(*pkex));
6343 if (!pkex)
6344 goto fail;
6345 pkex->own_bi = bi;
6346 pkex->failed = 1;
6347 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
6348 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
6349 if (!pkex->exchange_resp)
6350 goto fail;
6351 return pkex;
6352 }
6353
6354 /* M in Encrypted Key attribute */
6355 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
6356 &attr_key_len);
6357 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
6358 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
6359 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6360 "Missing Encrypted Key attribute");
6361 return NULL;
6362 }
6363
6364 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6365 bnctx = BN_CTX_new();
6366 if (!bnctx)
6367 goto fail;
6368 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
6369 &group);
6370 if (!Qi)
6371 goto fail;
6372
6373 /* X' = M - Qi */
6374 X = EC_POINT_new(group);
6375 M = EC_POINT_new(group);
6376 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
6377 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
6378 if (!X || !M || !Mx || !My ||
6379 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
6380 EC_POINT_is_at_infinity(group, M) ||
6381 !EC_POINT_is_on_curve(group, M, bnctx) ||
6382 EC_POINT_invert(group, Qi, bnctx) != 1 ||
6383 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
6384 EC_POINT_is_at_infinity(group, X) ||
6385 !EC_POINT_is_on_curve(group, X, bnctx)) {
6386 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6387 "Invalid Encrypted Key value");
6388 bi->pkex_t++;
6389 goto fail;
6390 }
6391
6392 pkex = os_zalloc(sizeof(*pkex));
6393 if (!pkex)
6394 goto fail;
6395 pkex->t = bi->pkex_t;
6396 pkex->msg_ctx = msg_ctx;
6397 pkex->own_bi = bi;
6398 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6399 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
6400 if (identifier) {
6401 pkex->identifier = os_strdup(identifier);
6402 if (!pkex->identifier)
6403 goto fail;
6404 }
6405 pkex->code = os_strdup(code);
6406 if (!pkex->code)
6407 goto fail;
6408
6409 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
6410
6411 X_ec = EC_KEY_new();
6412 if (!X_ec ||
6413 EC_KEY_set_group(X_ec, group) != 1 ||
6414 EC_KEY_set_public_key(X_ec, X) != 1)
6415 goto fail;
6416 pkex->x = EVP_PKEY_new();
6417 if (!pkex->x ||
6418 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
6419 goto fail;
6420
6421 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6422 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
6423 if (!Qr)
6424 goto fail;
6425
6426 /* Generate a random ephemeral keypair y/Y */
6427 pkex->y = dpp_gen_keypair(curve);
6428 if (!pkex->y)
6429 goto fail;
6430
6431 /* N = Y + Qr */
6432 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
6433 if (!Y_ec)
6434 goto fail;
6435 Y_point = EC_KEY_get0_public_key(Y_ec);
6436 if (!Y_point)
6437 goto fail;
6438 N = EC_POINT_new(group);
6439 Nx = BN_new();
6440 Ny = BN_new();
6441 if (!N || !Nx || !Ny ||
6442 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
6443 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
6444 goto fail;
6445
6446 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
6447 Nx, Ny);
6448 if (!pkex->exchange_resp)
6449 goto fail;
6450
6451 /* K = y * X' */
6452 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
6453 if (!ctx ||
6454 EVP_PKEY_derive_init(ctx) != 1 ||
6455 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
6456 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
6457 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
6458 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
6459 wpa_printf(MSG_ERROR,
6460 "DPP: Failed to derive ECDH shared secret: %s",
6461 ERR_error_string(ERR_get_error(), NULL));
6462 goto fail;
6463 }
6464
6465 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6466 Kx, Kx_len);
6467
6468 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6469 */
6470 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
6471 pkex->Mx, curve->prime_len,
6472 pkex->Nx, curve->prime_len, pkex->code,
6473 Kx, Kx_len, pkex->z, curve->hash_len);
6474 os_memset(Kx, 0, Kx_len);
6475 if (res < 0)
6476 goto fail;
6477
6478 pkex->exchange_done = 1;
6479
6480 out:
6481 EVP_PKEY_CTX_free(ctx);
6482 BN_CTX_free(bnctx);
6483 EC_POINT_free(Qi);
6484 EC_POINT_free(Qr);
6485 BN_free(Mx);
6486 BN_free(My);
6487 BN_free(Nx);
6488 BN_free(Ny);
6489 EC_POINT_free(M);
6490 EC_POINT_free(N);
6491 EC_POINT_free(X);
6492 EC_KEY_free(X_ec);
6493 EC_KEY_free(Y_ec);
6494 return pkex;
6495 fail:
6496 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
6497 dpp_pkex_free(pkex);
6498 pkex = NULL;
6499 goto out;
6500 }
6501
6502
6503 static struct wpabuf *
6504 dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
6505 const struct wpabuf *A_pub, const u8 *u)
6506 {
6507 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6508 struct wpabuf *msg = NULL;
6509 size_t clear_len, attr_len;
6510 struct wpabuf *clear = NULL;
6511 u8 *wrapped;
6512 u8 octet;
6513 const u8 *addr[2];
6514 size_t len[2];
6515
6516 /* {A, u, [bootstrapping info]}z */
6517 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
6518 clear = wpabuf_alloc(clear_len);
6519 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6520 #ifdef CONFIG_TESTING_OPTIONS
6521 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
6522 attr_len += 5;
6523 #endif /* CONFIG_TESTING_OPTIONS */
6524 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
6525 if (!clear || !msg)
6526 goto fail;
6527
6528 #ifdef CONFIG_TESTING_OPTIONS
6529 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
6530 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
6531 goto skip_bootstrap_key;
6532 }
6533 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
6534 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
6535 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6536 wpabuf_put_le16(clear, 2 * curve->prime_len);
6537 if (dpp_test_gen_invalid_key(clear, curve) < 0)
6538 goto fail;
6539 goto skip_bootstrap_key;
6540 }
6541 #endif /* CONFIG_TESTING_OPTIONS */
6542
6543 /* A in Bootstrap Key attribute */
6544 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6545 wpabuf_put_le16(clear, wpabuf_len(A_pub));
6546 wpabuf_put_buf(clear, A_pub);
6547
6548 #ifdef CONFIG_TESTING_OPTIONS
6549 skip_bootstrap_key:
6550 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
6551 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
6552 goto skip_i_auth_tag;
6553 }
6554 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
6555 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
6556 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
6557 wpabuf_put_le16(clear, curve->hash_len);
6558 wpabuf_put_data(clear, u, curve->hash_len - 1);
6559 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
6560 goto skip_i_auth_tag;
6561 }
6562 #endif /* CONFIG_TESTING_OPTIONS */
6563
6564 /* u in I-Auth tag attribute */
6565 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
6566 wpabuf_put_le16(clear, curve->hash_len);
6567 wpabuf_put_data(clear, u, curve->hash_len);
6568
6569 #ifdef CONFIG_TESTING_OPTIONS
6570 skip_i_auth_tag:
6571 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
6572 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
6573 goto skip_wrapped_data;
6574 }
6575 #endif /* CONFIG_TESTING_OPTIONS */
6576
6577 addr[0] = wpabuf_head_u8(msg) + 2;
6578 len[0] = DPP_HDR_LEN;
6579 octet = 0;
6580 addr[1] = &octet;
6581 len[1] = sizeof(octet);
6582 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6583 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6584
6585 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6586 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6587 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6588
6589 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6590 if (aes_siv_encrypt(pkex->z, curve->hash_len,
6591 wpabuf_head(clear), wpabuf_len(clear),
6592 2, addr, len, wrapped) < 0)
6593 goto fail;
6594 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6595 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6596
6597 #ifdef CONFIG_TESTING_OPTIONS
6598 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
6599 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
6600 dpp_build_attr_status(msg, DPP_STATUS_OK);
6601 }
6602 skip_wrapped_data:
6603 #endif /* CONFIG_TESTING_OPTIONS */
6604
6605 out:
6606 wpabuf_free(clear);
6607 return msg;
6608
6609 fail:
6610 wpabuf_free(msg);
6611 msg = NULL;
6612 goto out;
6613 }
6614
6615
6616 struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
6617 const u8 *buf, size_t buflen)
6618 {
6619 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
6620 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
6621 const EC_GROUP *group;
6622 BN_CTX *bnctx = NULL;
6623 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6624 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6625 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
6626 BIGNUM *Nx = NULL, *Ny = NULL;
6627 EVP_PKEY_CTX *ctx = NULL;
6628 EC_KEY *Y_ec = NULL;
6629 size_t Jx_len, Kx_len;
6630 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
6631 const u8 *addr[4];
6632 size_t len[4];
6633 u8 u[DPP_MAX_HASH_LEN];
6634 int res;
6635
6636 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
6637 return NULL;
6638
6639 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
6640 &attr_status_len);
6641 if (!attr_status || attr_status_len != 1) {
6642 dpp_pkex_fail(pkex, "No DPP Status attribute");
6643 return NULL;
6644 }
6645 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
6646
6647 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
6648 attr_group = dpp_get_attr(buf, buflen,
6649 DPP_ATTR_FINITE_CYCLIC_GROUP,
6650 &attr_group_len);
6651 if (attr_group && attr_group_len == 2) {
6652 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6653 "Peer indicated mismatching PKEX group - proposed %u",
6654 WPA_GET_LE16(attr_group));
6655 return NULL;
6656 }
6657 }
6658
6659 if (attr_status[0] != DPP_STATUS_OK) {
6660 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
6661 return NULL;
6662 }
6663
6664 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
6665 &attr_id_len);
6666 if (!attr_id && pkex->identifier) {
6667 wpa_printf(MSG_DEBUG,
6668 "DPP: No PKEX code identifier received, but expected one");
6669 return NULL;
6670 }
6671 if (attr_id && pkex->identifier &&
6672 (os_strlen(pkex->identifier) != attr_id_len ||
6673 os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) {
6674 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
6675 return NULL;
6676 }
6677
6678 /* N in Encrypted Key attribute */
6679 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
6680 &attr_key_len);
6681 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
6682 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
6683 return NULL;
6684 }
6685
6686 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
6687 bnctx = BN_CTX_new();
6688 if (!bnctx)
6689 goto fail;
6690 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
6691 pkex->identifier, bnctx, &group);
6692 if (!Qr)
6693 goto fail;
6694
6695 /* Y' = N - Qr */
6696 Y = EC_POINT_new(group);
6697 N = EC_POINT_new(group);
6698 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
6699 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
6700 if (!Y || !N || !Nx || !Ny ||
6701 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
6702 EC_POINT_is_at_infinity(group, N) ||
6703 !EC_POINT_is_on_curve(group, N, bnctx) ||
6704 EC_POINT_invert(group, Qr, bnctx) != 1 ||
6705 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
6706 EC_POINT_is_at_infinity(group, Y) ||
6707 !EC_POINT_is_on_curve(group, Y, bnctx)) {
6708 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
6709 pkex->t++;
6710 goto fail;
6711 }
6712
6713 pkex->exchange_done = 1;
6714
6715 /* ECDH: J = a * Y’ */
6716 Y_ec = EC_KEY_new();
6717 if (!Y_ec ||
6718 EC_KEY_set_group(Y_ec, group) != 1 ||
6719 EC_KEY_set_public_key(Y_ec, Y) != 1)
6720 goto fail;
6721 pkex->y = EVP_PKEY_new();
6722 if (!pkex->y ||
6723 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
6724 goto fail;
6725 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
6726 if (!ctx ||
6727 EVP_PKEY_derive_init(ctx) != 1 ||
6728 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
6729 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
6730 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
6731 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
6732 wpa_printf(MSG_ERROR,
6733 "DPP: Failed to derive ECDH shared secret: %s",
6734 ERR_error_string(ERR_get_error(), NULL));
6735 goto fail;
6736 }
6737
6738 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
6739 Jx, Jx_len);
6740
6741 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
6742 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
6743 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
6744 X_pub = dpp_get_pubkey_point(pkex->x, 0);
6745 if (!A_pub || !Y_pub || !X_pub)
6746 goto fail;
6747 addr[0] = pkex->own_mac;
6748 len[0] = ETH_ALEN;
6749 addr[1] = wpabuf_head(A_pub);
6750 len[1] = wpabuf_len(A_pub) / 2;
6751 addr[2] = wpabuf_head(Y_pub);
6752 len[2] = wpabuf_len(Y_pub) / 2;
6753 addr[3] = wpabuf_head(X_pub);
6754 len[3] = wpabuf_len(X_pub) / 2;
6755 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
6756 goto fail;
6757 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
6758
6759 /* K = x * Y’ */
6760 EVP_PKEY_CTX_free(ctx);
6761 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
6762 if (!ctx ||
6763 EVP_PKEY_derive_init(ctx) != 1 ||
6764 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
6765 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
6766 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
6767 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
6768 wpa_printf(MSG_ERROR,
6769 "DPP: Failed to derive ECDH shared secret: %s",
6770 ERR_error_string(ERR_get_error(), NULL));
6771 goto fail;
6772 }
6773
6774 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6775 Kx, Kx_len);
6776
6777 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6778 */
6779 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
6780 pkex->Mx, curve->prime_len,
6781 attr_key /* N.x */, attr_key_len / 2,
6782 pkex->code, Kx, Kx_len,
6783 pkex->z, curve->hash_len);
6784 os_memset(Kx, 0, Kx_len);
6785 if (res < 0)
6786 goto fail;
6787
6788 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
6789 if (!msg)
6790 goto fail;
6791
6792 out:
6793 wpabuf_free(A_pub);
6794 wpabuf_free(X_pub);
6795 wpabuf_free(Y_pub);
6796 EC_POINT_free(Qr);
6797 EC_POINT_free(Y);
6798 EC_POINT_free(N);
6799 BN_free(Nx);
6800 BN_free(Ny);
6801 EC_KEY_free(Y_ec);
6802 EVP_PKEY_CTX_free(ctx);
6803 BN_CTX_free(bnctx);
6804 return msg;
6805 fail:
6806 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
6807 goto out;
6808 }
6809
6810
6811 static struct wpabuf *
6812 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
6813 const struct wpabuf *B_pub, const u8 *v)
6814 {
6815 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6816 struct wpabuf *msg = NULL;
6817 const u8 *addr[2];
6818 size_t len[2];
6819 u8 octet;
6820 u8 *wrapped;
6821 struct wpabuf *clear = NULL;
6822 size_t clear_len, attr_len;
6823
6824 /* {B, v [bootstrapping info]}z */
6825 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
6826 clear = wpabuf_alloc(clear_len);
6827 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6828 #ifdef CONFIG_TESTING_OPTIONS
6829 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
6830 attr_len += 5;
6831 #endif /* CONFIG_TESTING_OPTIONS */
6832 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
6833 if (!clear || !msg)
6834 goto fail;
6835
6836 #ifdef CONFIG_TESTING_OPTIONS
6837 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
6838 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
6839 goto skip_bootstrap_key;
6840 }
6841 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
6842 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
6843 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6844 wpabuf_put_le16(clear, 2 * curve->prime_len);
6845 if (dpp_test_gen_invalid_key(clear, curve) < 0)
6846 goto fail;
6847 goto skip_bootstrap_key;
6848 }
6849 #endif /* CONFIG_TESTING_OPTIONS */
6850
6851 /* B in Bootstrap Key attribute */
6852 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6853 wpabuf_put_le16(clear, wpabuf_len(B_pub));
6854 wpabuf_put_buf(clear, B_pub);
6855
6856 #ifdef CONFIG_TESTING_OPTIONS
6857 skip_bootstrap_key:
6858 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
6859 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
6860 goto skip_r_auth_tag;
6861 }
6862 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
6863 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
6864 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
6865 wpabuf_put_le16(clear, curve->hash_len);
6866 wpabuf_put_data(clear, v, curve->hash_len - 1);
6867 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
6868 goto skip_r_auth_tag;
6869 }
6870 #endif /* CONFIG_TESTING_OPTIONS */
6871
6872 /* v in R-Auth tag attribute */
6873 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
6874 wpabuf_put_le16(clear, curve->hash_len);
6875 wpabuf_put_data(clear, v, curve->hash_len);
6876
6877 #ifdef CONFIG_TESTING_OPTIONS
6878 skip_r_auth_tag:
6879 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
6880 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
6881 goto skip_wrapped_data;
6882 }
6883 #endif /* CONFIG_TESTING_OPTIONS */
6884
6885 addr[0] = wpabuf_head_u8(msg) + 2;
6886 len[0] = DPP_HDR_LEN;
6887 octet = 1;
6888 addr[1] = &octet;
6889 len[1] = sizeof(octet);
6890 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6891 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6892
6893 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6894 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6895 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6896
6897 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6898 if (aes_siv_encrypt(pkex->z, curve->hash_len,
6899 wpabuf_head(clear), wpabuf_len(clear),
6900 2, addr, len, wrapped) < 0)
6901 goto fail;
6902 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6903 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6904
6905 #ifdef CONFIG_TESTING_OPTIONS
6906 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
6907 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
6908 dpp_build_attr_status(msg, DPP_STATUS_OK);
6909 }
6910 skip_wrapped_data:
6911 #endif /* CONFIG_TESTING_OPTIONS */
6912
6913 out:
6914 wpabuf_free(clear);
6915 return msg;
6916
6917 fail:
6918 wpabuf_free(msg);
6919 msg = NULL;
6920 goto out;
6921 }
6922
6923
6924 struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
6925 const u8 *hdr,
6926 const u8 *buf, size_t buflen)
6927 {
6928 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6929 EVP_PKEY_CTX *ctx = NULL;
6930 size_t Jx_len, Lx_len;
6931 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
6932 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
6933 const u8 *wrapped_data, *b_key, *peer_u;
6934 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
6935 const u8 *addr[4];
6936 size_t len[4];
6937 u8 octet;
6938 u8 *unwrapped = NULL;
6939 size_t unwrapped_len = 0;
6940 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6941 struct wpabuf *B_pub = NULL;
6942 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
6943
6944 if (!pkex->exchange_done || pkex->failed ||
6945 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
6946 goto fail;
6947
6948 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
6949 &wrapped_data_len);
6950 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
6951 dpp_pkex_fail(pkex,
6952 "Missing or invalid required Wrapped Data attribute");
6953 goto fail;
6954 }
6955
6956 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6957 wrapped_data, wrapped_data_len);
6958 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6959 unwrapped = os_malloc(unwrapped_len);
6960 if (!unwrapped)
6961 goto fail;
6962
6963 addr[0] = hdr;
6964 len[0] = DPP_HDR_LEN;
6965 octet = 0;
6966 addr[1] = &octet;
6967 len[1] = sizeof(octet);
6968 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6969 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6970
6971 if (aes_siv_decrypt(pkex->z, curve->hash_len,
6972 wrapped_data, wrapped_data_len,
6973 2, addr, len, unwrapped) < 0) {
6974 dpp_pkex_fail(pkex,
6975 "AES-SIV decryption failed - possible PKEX code mismatch");
6976 pkex->failed = 1;
6977 pkex->t++;
6978 goto fail;
6979 }
6980 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6981 unwrapped, unwrapped_len);
6982
6983 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
6984 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
6985 goto fail;
6986 }
6987
6988 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
6989 &b_key_len);
6990 if (!b_key || b_key_len != 2 * curve->prime_len) {
6991 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
6992 goto fail;
6993 }
6994 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
6995 b_key_len);
6996 if (!pkex->peer_bootstrap_key) {
6997 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
6998 goto fail;
6999 }
7000 dpp_debug_print_key("DPP: Peer bootstrap public key",
7001 pkex->peer_bootstrap_key);
7002
7003 /* ECDH: J' = y * A' */
7004 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
7005 if (!ctx ||
7006 EVP_PKEY_derive_init(ctx) != 1 ||
7007 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
7008 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
7009 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
7010 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
7011 wpa_printf(MSG_ERROR,
7012 "DPP: Failed to derive ECDH shared secret: %s",
7013 ERR_error_string(ERR_get_error(), NULL));
7014 goto fail;
7015 }
7016
7017 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7018 Jx, Jx_len);
7019
7020 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7021 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7022 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7023 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7024 if (!A_pub || !Y_pub || !X_pub)
7025 goto fail;
7026 addr[0] = pkex->peer_mac;
7027 len[0] = ETH_ALEN;
7028 addr[1] = wpabuf_head(A_pub);
7029 len[1] = wpabuf_len(A_pub) / 2;
7030 addr[2] = wpabuf_head(Y_pub);
7031 len[2] = wpabuf_len(Y_pub) / 2;
7032 addr[3] = wpabuf_head(X_pub);
7033 len[3] = wpabuf_len(X_pub) / 2;
7034 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
7035 goto fail;
7036
7037 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
7038 &peer_u_len);
7039 if (!peer_u || peer_u_len != curve->hash_len ||
7040 os_memcmp(peer_u, u, curve->hash_len) != 0) {
7041 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
7042 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
7043 u, curve->hash_len);
7044 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
7045 pkex->t++;
7046 goto fail;
7047 }
7048 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
7049
7050 /* ECDH: L = b * X' */
7051 EVP_PKEY_CTX_free(ctx);
7052 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7053 if (!ctx ||
7054 EVP_PKEY_derive_init(ctx) != 1 ||
7055 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
7056 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
7057 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
7058 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
7059 wpa_printf(MSG_ERROR,
7060 "DPP: Failed to derive ECDH shared secret: %s",
7061 ERR_error_string(ERR_get_error(), NULL));
7062 goto fail;
7063 }
7064
7065 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7066 Lx, Lx_len);
7067
7068 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7069 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
7070 if (!B_pub)
7071 goto fail;
7072 addr[0] = pkex->own_mac;
7073 len[0] = ETH_ALEN;
7074 addr[1] = wpabuf_head(B_pub);
7075 len[1] = wpabuf_len(B_pub) / 2;
7076 addr[2] = wpabuf_head(X_pub);
7077 len[2] = wpabuf_len(X_pub) / 2;
7078 addr[3] = wpabuf_head(Y_pub);
7079 len[3] = wpabuf_len(Y_pub) / 2;
7080 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
7081 goto fail;
7082 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
7083
7084 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
7085 if (!msg)
7086 goto fail;
7087
7088 out:
7089 EVP_PKEY_CTX_free(ctx);
7090 os_free(unwrapped);
7091 wpabuf_free(A_pub);
7092 wpabuf_free(B_pub);
7093 wpabuf_free(X_pub);
7094 wpabuf_free(Y_pub);
7095 return msg;
7096 fail:
7097 wpa_printf(MSG_DEBUG,
7098 "DPP: PKEX Commit-Reveal Request processing failed");
7099 goto out;
7100 }
7101
7102
7103 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
7104 const u8 *buf, size_t buflen)
7105 {
7106 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7107 const u8 *wrapped_data, *b_key, *peer_v;
7108 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
7109 const u8 *addr[4];
7110 size_t len[4];
7111 u8 octet;
7112 u8 *unwrapped = NULL;
7113 size_t unwrapped_len = 0;
7114 int ret = -1;
7115 u8 v[DPP_MAX_HASH_LEN];
7116 size_t Lx_len;
7117 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
7118 EVP_PKEY_CTX *ctx = NULL;
7119 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7120
7121 if (!pkex->exchange_done || pkex->failed ||
7122 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
7123 goto fail;
7124
7125 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7126 &wrapped_data_len);
7127 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7128 dpp_pkex_fail(pkex,
7129 "Missing or invalid required Wrapped Data attribute");
7130 goto fail;
7131 }
7132
7133 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7134 wrapped_data, wrapped_data_len);
7135 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7136 unwrapped = os_malloc(unwrapped_len);
7137 if (!unwrapped)
7138 goto fail;
7139
7140 addr[0] = hdr;
7141 len[0] = DPP_HDR_LEN;
7142 octet = 1;
7143 addr[1] = &octet;
7144 len[1] = sizeof(octet);
7145 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7146 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7147
7148 if (aes_siv_decrypt(pkex->z, curve->hash_len,
7149 wrapped_data, wrapped_data_len,
7150 2, addr, len, unwrapped) < 0) {
7151 dpp_pkex_fail(pkex,
7152 "AES-SIV decryption failed - possible PKEX code mismatch");
7153 pkex->t++;
7154 goto fail;
7155 }
7156 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7157 unwrapped, unwrapped_len);
7158
7159 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7160 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
7161 goto fail;
7162 }
7163
7164 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7165 &b_key_len);
7166 if (!b_key || b_key_len != 2 * curve->prime_len) {
7167 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
7168 goto fail;
7169 }
7170 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7171 b_key_len);
7172 if (!pkex->peer_bootstrap_key) {
7173 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
7174 goto fail;
7175 }
7176 dpp_debug_print_key("DPP: Peer bootstrap public key",
7177 pkex->peer_bootstrap_key);
7178
7179 /* ECDH: L' = x * B' */
7180 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
7181 if (!ctx ||
7182 EVP_PKEY_derive_init(ctx) != 1 ||
7183 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
7184 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
7185 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
7186 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
7187 wpa_printf(MSG_ERROR,
7188 "DPP: Failed to derive ECDH shared secret: %s",
7189 ERR_error_string(ERR_get_error(), NULL));
7190 goto fail;
7191 }
7192
7193 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7194 Lx, Lx_len);
7195
7196 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
7197 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7198 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7199 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7200 if (!B_pub || !X_pub || !Y_pub)
7201 goto fail;
7202 addr[0] = pkex->peer_mac;
7203 len[0] = ETH_ALEN;
7204 addr[1] = wpabuf_head(B_pub);
7205 len[1] = wpabuf_len(B_pub) / 2;
7206 addr[2] = wpabuf_head(X_pub);
7207 len[2] = wpabuf_len(X_pub) / 2;
7208 addr[3] = wpabuf_head(Y_pub);
7209 len[3] = wpabuf_len(Y_pub) / 2;
7210 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
7211 goto fail;
7212
7213 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
7214 &peer_v_len);
7215 if (!peer_v || peer_v_len != curve->hash_len ||
7216 os_memcmp(peer_v, v, curve->hash_len) != 0) {
7217 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
7218 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
7219 v, curve->hash_len);
7220 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
7221 pkex->t++;
7222 goto fail;
7223 }
7224 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
7225
7226 ret = 0;
7227 out:
7228 wpabuf_free(B_pub);
7229 wpabuf_free(X_pub);
7230 wpabuf_free(Y_pub);
7231 EVP_PKEY_CTX_free(ctx);
7232 os_free(unwrapped);
7233 return ret;
7234 fail:
7235 goto out;
7236 }
7237
7238
7239 void dpp_pkex_free(struct dpp_pkex *pkex)
7240 {
7241 if (!pkex)
7242 return;
7243
7244 os_free(pkex->identifier);
7245 os_free(pkex->code);
7246 EVP_PKEY_free(pkex->x);
7247 EVP_PKEY_free(pkex->y);
7248 EVP_PKEY_free(pkex->peer_bootstrap_key);
7249 wpabuf_free(pkex->exchange_req);
7250 wpabuf_free(pkex->exchange_resp);
7251 os_free(pkex);
7252 }
7253
7254
7255 #ifdef CONFIG_TESTING_OPTIONS
7256 char * dpp_corrupt_connector_signature(const char *connector)
7257 {
7258 char *tmp, *pos, *signed3 = NULL;
7259 unsigned char *signature = NULL;
7260 size_t signature_len = 0, signed3_len;
7261
7262 tmp = os_zalloc(os_strlen(connector) + 5);
7263 if (!tmp)
7264 goto fail;
7265 os_memcpy(tmp, connector, os_strlen(connector));
7266
7267 pos = os_strchr(tmp, '.');
7268 if (!pos)
7269 goto fail;
7270
7271 pos = os_strchr(pos + 1, '.');
7272 if (!pos)
7273 goto fail;
7274 pos++;
7275
7276 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
7277 pos);
7278 signature = base64_url_decode((const unsigned char *) pos,
7279 os_strlen(pos), &signature_len);
7280 if (!signature || signature_len == 0)
7281 goto fail;
7282 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
7283 signature, signature_len);
7284 signature[signature_len - 1] ^= 0x01;
7285 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
7286 signature, signature_len);
7287 signed3 = (char *) base64_url_encode(signature, signature_len,
7288 &signed3_len, 0);
7289 if (!signed3)
7290 goto fail;
7291 os_memcpy(pos, signed3, signed3_len);
7292 pos[signed3_len] = '\0';
7293 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
7294 pos);
7295
7296 out:
7297 os_free(signature);
7298 os_free(signed3);
7299 return tmp;
7300 fail:
7301 os_free(tmp);
7302 tmp = NULL;
7303 goto out;
7304 }
7305 #endif /* CONFIG_TESTING_OPTIONS */