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