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