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