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