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