]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/common/dpp.c
tests: DPP protocol testing - invalid I-nonce in Auth Req
[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
9efa5314
JM
1449static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1450 const u8 *hash)
1451{
1452 if (hash) {
1453 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1454 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1455 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1456 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1457 }
1458}
1459
1460
1461static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1462 const u8 *hash)
1463{
1464 if (hash) {
1465 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1466 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1467 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1468 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1469 }
1470}
1471
1472
606a8e8d
JM
1473static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1474 const struct wpabuf *pi,
1475 size_t nonce_len,
1476 const u8 *r_pubkey_hash,
d2709206
JM
1477 const u8 *i_pubkey_hash,
1478 unsigned int neg_freq)
30d27b04 1479{
606a8e8d 1480 struct wpabuf *msg;
30d27b04
JM
1481 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1482 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1483 u8 *pos;
dc4d271c
JM
1484 const u8 *addr[2];
1485 size_t len[2], siv_len, attr_len;
1486 u8 *attr_start, *attr_end;
30d27b04 1487
30d27b04 1488 /* Build DPP Authentication Request frame attributes */
606a8e8d 1489 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
dc4d271c 1490 4 + sizeof(wrapped_data);
d2709206
JM
1491 if (neg_freq > 0)
1492 attr_len += 4 + 2;
60239f60
JM
1493#ifdef CONFIG_TESTING_OPTIONS
1494 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
acdf703d 1495 attr_len += 5;
60239f60 1496#endif /* CONFIG_TESTING_OPTIONS */
dc4d271c 1497 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
30d27b04 1498 if (!msg)
606a8e8d 1499 return NULL;
dc4d271c
JM
1500
1501 attr_start = wpabuf_put(msg, 0);
30d27b04
JM
1502
1503 /* Responder Bootstrapping Key Hash */
9efa5314 1504 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
30d27b04
JM
1505
1506 /* Initiator Bootstrapping Key Hash */
9efa5314 1507 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
30d27b04
JM
1508
1509 /* Initiator Protocol Key */
606a8e8d
JM
1510 if (pi) {
1511 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1512 wpabuf_put_le16(msg, wpabuf_len(pi));
1513 wpabuf_put_buf(msg, pi);
1514 }
30d27b04 1515
d2709206
JM
1516 /* Channel */
1517 if (neg_freq > 0) {
1518 u8 op_class, channel;
1519
1520 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1521 &channel) ==
1522 NUM_HOSTAPD_MODES) {
1523 wpa_printf(MSG_INFO,
1524 "DPP: Unsupported negotiation frequency request: %d",
1525 neg_freq);
1526 wpabuf_free(msg);
1527 return NULL;
1528 }
1529 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1530 wpabuf_put_le16(msg, 2);
1531 wpabuf_put_u8(msg, op_class);
1532 wpabuf_put_u8(msg, channel);
1533 }
1534
0e7cb8c6
JM
1535#ifdef CONFIG_TESTING_OPTIONS
1536 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1537 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1538 goto skip_wrapped_data;
1539 }
1540#endif /* CONFIG_TESTING_OPTIONS */
1541
30d27b04
JM
1542 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1543 pos = clear;
606a8e8d 1544
0e7cb8c6
JM
1545#ifdef CONFIG_TESTING_OPTIONS
1546 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1547 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1548 goto skip_i_nonce;
1549 }
a4446739
JM
1550 if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1551 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1552 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1553 pos += 2;
1554 WPA_PUT_LE16(pos, nonce_len - 1);
1555 pos += 2;
1556 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1557 pos += nonce_len - 1;
1558 goto skip_i_nonce;
1559 }
0e7cb8c6
JM
1560#endif /* CONFIG_TESTING_OPTIONS */
1561
30d27b04
JM
1562 /* I-nonce */
1563 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1564 pos += 2;
1565 WPA_PUT_LE16(pos, nonce_len);
1566 pos += 2;
1567 os_memcpy(pos, auth->i_nonce, nonce_len);
1568 pos += nonce_len;
606a8e8d 1569
0e7cb8c6
JM
1570#ifdef CONFIG_TESTING_OPTIONS
1571skip_i_nonce:
1572 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1573 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1574 goto skip_i_capab;
1575 }
1576#endif /* CONFIG_TESTING_OPTIONS */
1577
30d27b04
JM
1578 /* I-capabilities */
1579 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1580 pos += 2;
1581 WPA_PUT_LE16(pos, 1);
1582 pos += 2;
d1f08264 1583 auth->i_capab = auth->allowed_roles;
30d27b04 1584 *pos++ = auth->i_capab;
60239f60
JM
1585#ifdef CONFIG_TESTING_OPTIONS
1586 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1587 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1588 pos[-1] = 0;
1589 }
0e7cb8c6 1590skip_i_capab:
60239f60 1591#endif /* CONFIG_TESTING_OPTIONS */
30d27b04 1592
dc4d271c
JM
1593 attr_end = wpabuf_put(msg, 0);
1594
1595 /* OUI, OUI type, Crypto Suite, DPP frame type */
1596 addr[0] = wpabuf_head_u8(msg) + 2;
1597 len[0] = 3 + 1 + 1 + 1;
1598 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1599
1600 /* Attributes before Wrapped Data */
1601 addr[1] = attr_start;
1602 len[1] = attr_end - attr_start;
1603 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1604
30d27b04
JM
1605 siv_len = pos - clear;
1606 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1607 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
606a8e8d
JM
1608 2, addr, len, wrapped_data) < 0) {
1609 wpabuf_free(msg);
1610 return NULL;
1611 }
30d27b04
JM
1612 siv_len += AES_BLOCK_SIZE;
1613 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1614 wrapped_data, siv_len);
1615
1616 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1617 wpabuf_put_le16(msg, siv_len);
1618 wpabuf_put_data(msg, wrapped_data, siv_len);
1619
60239f60
JM
1620#ifdef CONFIG_TESTING_OPTIONS
1621 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1622 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 1623 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 1624 }
0e7cb8c6 1625skip_wrapped_data:
60239f60
JM
1626#endif /* CONFIG_TESTING_OPTIONS */
1627
30d27b04
JM
1628 wpa_hexdump_buf(MSG_DEBUG,
1629 "DPP: Authentication Request frame attributes", msg);
1630
606a8e8d
JM
1631 return msg;
1632}
1633
1634
a03406db
JM
1635static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1636 enum dpp_status_error status,
1637 const struct wpabuf *pr,
1638 size_t nonce_len,
1639 const u8 *r_pubkey_hash,
1640 const u8 *i_pubkey_hash,
1641 const u8 *r_nonce, const u8 *i_nonce,
1642 const u8 *wrapped_r_auth,
1643 size_t wrapped_r_auth_len,
1644 const u8 *siv_key)
1645{
1646 struct wpabuf *msg;
1647#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1648 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1649 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1650 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1651 const u8 *addr[2];
1652 size_t len[2], siv_len, attr_len;
1653 u8 *attr_start, *attr_end, *pos;
1654
95b0104a
JM
1655 auth->waiting_auth_conf = 1;
1656 auth->auth_resp_tries = 0;
1657
a03406db
JM
1658 /* Build DPP Authentication Response frame attributes */
1659 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1660 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
1661#ifdef CONFIG_TESTING_OPTIONS
1662 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
acdf703d 1663 attr_len += 5;
a03406db
JM
1664#endif /* CONFIG_TESTING_OPTIONS */
1665 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1666 if (!msg)
1667 return NULL;
a03406db
JM
1668
1669 attr_start = wpabuf_put(msg, 0);
1670
1671 /* DPP Status */
56f24d1d
JM
1672 if (status != 255)
1673 dpp_build_attr_status(msg, status);
a03406db
JM
1674
1675 /* Responder Bootstrapping Key Hash */
9efa5314 1676 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
a03406db 1677
9efa5314
JM
1678 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1679 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
a03406db
JM
1680
1681 /* Responder Protocol Key */
1682 if (pr) {
1683 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1684 wpabuf_put_le16(msg, wpabuf_len(pr));
1685 wpabuf_put_buf(msg, pr);
1686 }
1687
1688 attr_end = wpabuf_put(msg, 0);
1689
ce9acce0
JM
1690#ifdef CONFIG_TESTING_OPTIONS
1691 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
1692 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1693 goto skip_wrapped_data;
1694 }
1695#endif /* CONFIG_TESTING_OPTIONS */
1696
a03406db
JM
1697 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1698 pos = clear;
1699
1700 if (r_nonce) {
1701 /* R-nonce */
1702 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1703 pos += 2;
1704 WPA_PUT_LE16(pos, nonce_len);
1705 pos += 2;
1706 os_memcpy(pos, r_nonce, nonce_len);
1707 pos += nonce_len;
1708 }
1709
1710 if (i_nonce) {
1711 /* I-nonce */
1712 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1713 pos += 2;
1714 WPA_PUT_LE16(pos, nonce_len);
1715 pos += 2;
1716 os_memcpy(pos, i_nonce, nonce_len);
978bc3f2
JM
1717#ifdef CONFIG_TESTING_OPTIONS
1718 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
1719 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
1720 pos[nonce_len / 2] ^= 0x01;
1721 }
1722#endif /* CONFIG_TESTING_OPTIONS */
a03406db
JM
1723 pos += nonce_len;
1724 }
1725
ce9acce0
JM
1726#ifdef CONFIG_TESTING_OPTIONS
1727 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
1728 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
1729 goto skip_r_capab;
1730 }
1731#endif /* CONFIG_TESTING_OPTIONS */
1732
a03406db
JM
1733 /* R-capabilities */
1734 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1735 pos += 2;
1736 WPA_PUT_LE16(pos, 1);
1737 pos += 2;
1738 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1739 DPP_CAPAB_ENROLLEE;
1740 *pos++ = auth->r_capab;
1741#ifdef CONFIG_TESTING_OPTIONS
1742 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
1743 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
1744 pos[-1] = 0;
978bc3f2
JM
1745 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
1746 wpa_printf(MSG_INFO,
1747 "DPP: TESTING - incompatible R-capabilities");
d1f08264
JM
1748 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
1749 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
1750 pos[-1] = 0;
1751 else
1752 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
1753 DPP_CAPAB_CONFIGURATOR;
a03406db 1754 }
ce9acce0 1755skip_r_capab:
a03406db
JM
1756#endif /* CONFIG_TESTING_OPTIONS */
1757
1758 if (wrapped_r_auth) {
1759 /* {R-auth}ke */
1760 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1761 pos += 2;
1762 WPA_PUT_LE16(pos, wrapped_r_auth_len);
1763 pos += 2;
1764 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1765 pos += wrapped_r_auth_len;
1766 }
1767
1768 /* OUI, OUI type, Crypto Suite, DPP frame type */
1769 addr[0] = wpabuf_head_u8(msg) + 2;
1770 len[0] = 3 + 1 + 1 + 1;
1771 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1772
1773 /* Attributes before Wrapped Data */
1774 addr[1] = attr_start;
1775 len[1] = attr_end - attr_start;
1776 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1777
1778 siv_len = pos - clear;
1779 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1780 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
1781 2, addr, len, wrapped_data) < 0) {
1782 wpabuf_free(msg);
1783 return NULL;
1784 }
1785 siv_len += AES_BLOCK_SIZE;
1786 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1787 wrapped_data, siv_len);
1788
1789 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1790 wpabuf_put_le16(msg, siv_len);
1791 wpabuf_put_data(msg, wrapped_data, siv_len);
1792
1793#ifdef CONFIG_TESTING_OPTIONS
1794 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
1795 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 1796 dpp_build_attr_status(msg, DPP_STATUS_OK);
a03406db 1797 }
ce9acce0 1798skip_wrapped_data:
a03406db
JM
1799#endif /* CONFIG_TESTING_OPTIONS */
1800
1801 wpa_hexdump_buf(MSG_DEBUG,
1802 "DPP: Authentication Response frame attributes", msg);
1803 return msg;
1804}
1805
1806
f97ace34
JM
1807static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
1808 u16 num_modes, unsigned int freq)
1809{
1810 u16 m;
1811 int c, flag;
1812
1813 if (!own_modes || !num_modes)
1814 return 1;
1815
1816 for (m = 0; m < num_modes; m++) {
1817 for (c = 0; c < own_modes[m].num_channels; c++) {
1818 if ((unsigned int) own_modes[m].channels[c].freq !=
1819 freq)
1820 continue;
1821 flag = own_modes[m].channels[c].flag;
1822 if (!(flag & (HOSTAPD_CHAN_DISABLED |
1823 HOSTAPD_CHAN_NO_IR |
1824 HOSTAPD_CHAN_RADAR)))
1825 return 1;
1826 }
1827 }
1828
1829 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
1830 return 0;
1831}
1832
1833
1834static int freq_included(const unsigned int freqs[], unsigned int num,
1835 unsigned int freq)
1836{
1837 while (num > 0) {
1838 if (freqs[--num] == freq)
1839 return 1;
1840 }
1841 return 0;
1842}
1843
1844
1845static void freq_to_start(unsigned int freqs[], unsigned int num,
1846 unsigned int freq)
1847{
1848 unsigned int i;
1849
1850 for (i = 0; i < num; i++) {
1851 if (freqs[i] == freq)
1852 break;
1853 }
1854 if (i == 0 || i >= num)
1855 return;
1856 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
1857 freqs[0] = freq;
1858}
1859
1860
1861static int dpp_channel_intersect(struct dpp_authentication *auth,
1862 struct hostapd_hw_modes *own_modes,
1863 u16 num_modes)
1864{
1865 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
1866 unsigned int i, freq;
1867
1868 for (i = 0; i < peer_bi->num_freq; i++) {
1869 freq = peer_bi->freq[i];
1870 if (freq_included(auth->freq, auth->num_freq, freq))
1871 continue;
1872 if (dpp_channel_ok_init(own_modes, num_modes, freq))
1873 auth->freq[auth->num_freq++] = freq;
1874 }
1875 if (!auth->num_freq) {
1876 wpa_printf(MSG_INFO,
1877 "DPP: No available channels for initiating DPP Authentication");
1878 return -1;
1879 }
1880 auth->curr_freq = auth->freq[0];
1881 return 0;
1882}
1883
1884
1885static int dpp_channel_local_list(struct dpp_authentication *auth,
1886 struct hostapd_hw_modes *own_modes,
1887 u16 num_modes)
1888{
1889 u16 m;
1890 int c, flag;
1891 unsigned int freq;
1892
1893 auth->num_freq = 0;
1894
1895 if (!own_modes || !num_modes) {
1896 auth->freq[0] = 2412;
1897 auth->freq[1] = 2437;
1898 auth->freq[2] = 2462;
1899 auth->num_freq = 3;
1900 return 0;
1901 }
1902
1903 for (m = 0; m < num_modes; m++) {
1904 for (c = 0; c < own_modes[m].num_channels; c++) {
1905 freq = own_modes[m].channels[c].freq;
1906 flag = own_modes[m].channels[c].flag;
1907 if (flag & (HOSTAPD_CHAN_DISABLED |
1908 HOSTAPD_CHAN_NO_IR |
1909 HOSTAPD_CHAN_RADAR))
1910 continue;
1911 if (freq_included(auth->freq, auth->num_freq, freq))
1912 continue;
1913 auth->freq[auth->num_freq++] = freq;
1914 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
1915 m = num_modes;
1916 break;
1917 }
1918 }
1919 }
1920
1921 return auth->num_freq == 0 ? -1 : 0;
1922}
1923
1924
1925static int dpp_prepare_channel_list(struct dpp_authentication *auth,
1926 struct hostapd_hw_modes *own_modes,
1927 u16 num_modes)
1928{
1929 int res;
1930 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
1931 unsigned int i;
1932
1933 if (auth->peer_bi->num_freq > 0)
1934 res = dpp_channel_intersect(auth, own_modes, num_modes);
1935 else
1936 res = dpp_channel_local_list(auth, own_modes, num_modes);
1937 if (res < 0)
1938 return res;
1939
1940 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1941 * likely channels first. */
1942 freq_to_start(auth->freq, auth->num_freq, 2462);
1943 freq_to_start(auth->freq, auth->num_freq, 2412);
1944 freq_to_start(auth->freq, auth->num_freq, 2437);
1945
1946 auth->freq_idx = 0;
1947 auth->curr_freq = auth->freq[0];
1948
1949 pos = freqs;
1950 end = pos + sizeof(freqs);
1951 for (i = 0; i < auth->num_freq; i++) {
1952 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
1953 if (os_snprintf_error(end - pos, res))
1954 break;
1955 pos += res;
1956 }
1957 *pos = '\0';
1958 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
1959 freqs);
1960
1961 return 0;
1962}
1963
1964
606a8e8d
JM
1965struct dpp_authentication * dpp_auth_init(void *msg_ctx,
1966 struct dpp_bootstrap_info *peer_bi,
1967 struct dpp_bootstrap_info *own_bi,
d1f08264 1968 u8 dpp_allowed_roles,
f97ace34
JM
1969 unsigned int neg_freq,
1970 struct hostapd_hw_modes *own_modes,
1971 u16 num_modes)
606a8e8d
JM
1972{
1973 struct dpp_authentication *auth;
1974 size_t nonce_len;
1975 EVP_PKEY_CTX *ctx = NULL;
1976 size_t secret_len;
1977 struct wpabuf *pi = NULL;
1978 u8 zero[SHA256_MAC_LEN];
1979 const u8 *r_pubkey_hash, *i_pubkey_hash;
65ecce87
JM
1980#ifdef CONFIG_TESTING_OPTIONS
1981 u8 test_hash[SHA256_MAC_LEN];
1982#endif /* CONFIG_TESTING_OPTIONS */
606a8e8d
JM
1983
1984 auth = os_zalloc(sizeof(*auth));
1985 if (!auth)
1986 return NULL;
1987 auth->msg_ctx = msg_ctx;
1988 auth->initiator = 1;
f97ace34 1989 auth->waiting_auth_resp = 1;
d1f08264
JM
1990 auth->allowed_roles = dpp_allowed_roles;
1991 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
606a8e8d
JM
1992 auth->peer_bi = peer_bi;
1993 auth->own_bi = own_bi;
1994 auth->curve = peer_bi->curve;
1995
f97ace34
JM
1996 if (dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
1997 goto fail;
1998
606a8e8d
JM
1999 nonce_len = auth->curve->nonce_len;
2000 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2001 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
2002 goto fail;
2003 }
2004 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2005
2006 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2007 if (!auth->own_protocol_key)
2008 goto fail;
2009
2010 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2011 if (!pi)
2012 goto fail;
2013
2014 /* ECDH: M = pI * BR */
2015 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2016 if (!ctx ||
2017 EVP_PKEY_derive_init(ctx) != 1 ||
2018 EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
2019 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2020 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2021 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
2022 wpa_printf(MSG_ERROR,
2023 "DPP: Failed to derive ECDH shared secret: %s",
2024 ERR_error_string(ERR_get_error(), NULL));
2025 goto fail;
2026 }
2027 auth->secret_len = secret_len;
2028 EVP_PKEY_CTX_free(ctx);
2029 ctx = NULL;
2030
2031 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2032 auth->Mx, auth->secret_len);
2033
2034 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2035 auth->curve->hash_len) < 0)
2036 goto fail;
2037
2038 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2039
2040 if (auth->own_bi) {
2041 i_pubkey_hash = auth->own_bi->pubkey_hash;
2042 } else {
2043 os_memset(zero, 0, SHA256_MAC_LEN);
2044 i_pubkey_hash = zero;
2045 }
2046
0e7cb8c6
JM
2047#ifdef CONFIG_TESTING_OPTIONS
2048 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2049 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2050 r_pubkey_hash = NULL;
65ecce87
JM
2051 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2052 wpa_printf(MSG_INFO,
2053 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2054 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2055 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2056 r_pubkey_hash = test_hash;
0e7cb8c6
JM
2057 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2058 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2059 i_pubkey_hash = NULL;
65ecce87
JM
2060 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2061 wpa_printf(MSG_INFO,
2062 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2063 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2064 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2065 i_pubkey_hash = test_hash;
0e7cb8c6
JM
2066 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2067 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2068 wpabuf_free(pi);
2069 pi = NULL;
b6b4226b
JM
2070 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2071 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2072 wpabuf_free(pi);
2073 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2074 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2075 goto fail;
0e7cb8c6
JM
2076 }
2077#endif /* CONFIG_TESTING_OPTIONS */
2078
606a8e8d 2079 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
d2709206 2080 i_pubkey_hash, neg_freq);
606a8e8d
JM
2081 if (!auth->req_msg)
2082 goto fail;
2083
2084out:
30d27b04
JM
2085 wpabuf_free(pi);
2086 EVP_PKEY_CTX_free(ctx);
606a8e8d
JM
2087 return auth;
2088fail:
30d27b04 2089 dpp_auth_deinit(auth);
606a8e8d
JM
2090 auth = NULL;
2091 goto out;
30d27b04
JM
2092}
2093
2094
461d39af
JM
2095struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2096 const char *json)
2097{
2098 size_t nonce_len;
2099 size_t json_len, clear_len;
2100 struct wpabuf *clear = NULL, *msg = NULL;
2101 u8 *wrapped;
60239f60 2102 size_t attr_len;
461d39af
JM
2103
2104 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2105
2106 nonce_len = auth->curve->nonce_len;
2107 if (random_get_bytes(auth->e_nonce, nonce_len)) {
2108 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2109 goto fail;
2110 }
2111 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2112 json_len = os_strlen(json);
2113 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
2114
2115 /* { E-nonce, configAttrib }ke */
2116 clear_len = 4 + nonce_len + 4 + json_len;
2117 clear = wpabuf_alloc(clear_len);
60239f60
JM
2118 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2119#ifdef CONFIG_TESTING_OPTIONS
2120 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
acdf703d 2121 attr_len += 5;
60239f60
JM
2122#endif /* CONFIG_TESTING_OPTIONS */
2123 msg = wpabuf_alloc(attr_len);
461d39af
JM
2124 if (!clear || !msg)
2125 goto fail;
2126
f411ad1b
JM
2127#ifdef CONFIG_TESTING_OPTIONS
2128 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2129 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2130 goto skip_e_nonce;
2131 }
2132 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2133 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2134 goto skip_wrapped_data;
2135 }
2136#endif /* CONFIG_TESTING_OPTIONS */
2137
461d39af
JM
2138 /* E-nonce */
2139 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2140 wpabuf_put_le16(clear, nonce_len);
2141 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2142
f411ad1b
JM
2143#ifdef CONFIG_TESTING_OPTIONS
2144skip_e_nonce:
2145 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2146 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2147 goto skip_conf_attr_obj;
2148 }
2149#endif /* CONFIG_TESTING_OPTIONS */
2150
461d39af
JM
2151 /* configAttrib */
2152 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2153 wpabuf_put_le16(clear, json_len);
2154 wpabuf_put_data(clear, json, json_len);
2155
f411ad1b
JM
2156#ifdef CONFIG_TESTING_OPTIONS
2157skip_conf_attr_obj:
2158#endif /* CONFIG_TESTING_OPTIONS */
2159
461d39af
JM
2160 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2161 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2162 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2163
2164 /* No AES-SIV AD */
2165 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2166 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2167 wpabuf_head(clear), wpabuf_len(clear),
2168 0, NULL, NULL, wrapped) < 0)
2169 goto fail;
2170 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2171 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2172
60239f60
JM
2173#ifdef CONFIG_TESTING_OPTIONS
2174 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2175 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 2176 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 2177 }
f411ad1b 2178skip_wrapped_data:
60239f60
JM
2179#endif /* CONFIG_TESTING_OPTIONS */
2180
461d39af
JM
2181 wpa_hexdump_buf(MSG_DEBUG,
2182 "DPP: Configuration Request frame attributes", msg);
2183 wpabuf_free(clear);
2184 return msg;
2185
2186fail:
2187 wpabuf_free(clear);
2188 wpabuf_free(msg);
2189 return NULL;
2190}
2191
2192
30d27b04
JM
2193static void dpp_auth_success(struct dpp_authentication *auth)
2194{
2195 wpa_printf(MSG_DEBUG,
2196 "DPP: Authentication success - clear temporary keys");
2197 os_memset(auth->Mx, 0, sizeof(auth->Mx));
2198 os_memset(auth->Nx, 0, sizeof(auth->Nx));
2199 os_memset(auth->Lx, 0, sizeof(auth->Lx));
2200 os_memset(auth->k1, 0, sizeof(auth->k1));
2201 os_memset(auth->k2, 0, sizeof(auth->k2));
2202
2203 auth->auth_success = 1;
2204}
2205
2206
2207static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2208{
2209 struct wpabuf *pix, *prx, *bix, *brx;
2210 const u8 *addr[7];
2211 size_t len[7];
2212 size_t i, num_elem = 0;
2213 size_t nonce_len;
2214 u8 zero = 0;
2215 int res = -1;
2216
2217 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2218 nonce_len = auth->curve->nonce_len;
2219
2220 if (auth->initiator) {
2221 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2222 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2223 if (auth->own_bi)
2224 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2225 else
2226 bix = NULL;
2227 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2228 } else {
2229 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2230 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2231 if (auth->peer_bi)
2232 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2233 else
2234 bix = NULL;
2235 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2236 }
2237 if (!pix || !prx || !brx)
2238 goto fail;
2239
2240 addr[num_elem] = auth->i_nonce;
2241 len[num_elem] = nonce_len;
2242 num_elem++;
2243
2244 addr[num_elem] = auth->r_nonce;
2245 len[num_elem] = nonce_len;
2246 num_elem++;
2247
2248 addr[num_elem] = wpabuf_head(pix);
2249 len[num_elem] = wpabuf_len(pix) / 2;
2250 num_elem++;
2251
2252 addr[num_elem] = wpabuf_head(prx);
2253 len[num_elem] = wpabuf_len(prx) / 2;
2254 num_elem++;
2255
2256 if (bix) {
2257 addr[num_elem] = wpabuf_head(bix);
2258 len[num_elem] = wpabuf_len(bix) / 2;
2259 num_elem++;
2260 }
2261
2262 addr[num_elem] = wpabuf_head(brx);
2263 len[num_elem] = wpabuf_len(brx) / 2;
2264 num_elem++;
2265
2266 addr[num_elem] = &zero;
2267 len[num_elem] = 1;
2268 num_elem++;
2269
2270 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2271 for (i = 0; i < num_elem; i++)
2272 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
b9d47b48 2273 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
30d27b04
JM
2274 if (res == 0)
2275 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2276 auth->curve->hash_len);
2277fail:
2278 wpabuf_free(pix);
2279 wpabuf_free(prx);
2280 wpabuf_free(bix);
2281 wpabuf_free(brx);
2282 return res;
2283}
2284
2285
2286static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2287{
2288 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2289 const u8 *addr[7];
2290 size_t len[7];
2291 size_t i, num_elem = 0;
2292 size_t nonce_len;
2293 u8 one = 1;
2294 int res = -1;
2295
2296 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2297 nonce_len = auth->curve->nonce_len;
2298
2299 if (auth->initiator) {
2300 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2301 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2302 if (auth->own_bi)
2303 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2304 else
2305 bix = NULL;
2306 if (!auth->peer_bi)
2307 goto fail;
2308 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2309 } else {
2310 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2311 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2312 if (auth->peer_bi)
2313 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2314 else
2315 bix = NULL;
2316 if (!auth->own_bi)
2317 goto fail;
2318 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2319 }
2320 if (!pix || !prx || !brx)
2321 goto fail;
2322
2323 addr[num_elem] = auth->r_nonce;
2324 len[num_elem] = nonce_len;
2325 num_elem++;
2326
2327 addr[num_elem] = auth->i_nonce;
2328 len[num_elem] = nonce_len;
2329 num_elem++;
2330
2331 addr[num_elem] = wpabuf_head(prx);
2332 len[num_elem] = wpabuf_len(prx) / 2;
2333 num_elem++;
2334
2335 addr[num_elem] = wpabuf_head(pix);
2336 len[num_elem] = wpabuf_len(pix) / 2;
2337 num_elem++;
2338
2339 addr[num_elem] = wpabuf_head(brx);
2340 len[num_elem] = wpabuf_len(brx) / 2;
2341 num_elem++;
2342
2343 if (bix) {
2344 addr[num_elem] = wpabuf_head(bix);
2345 len[num_elem] = wpabuf_len(bix) / 2;
2346 num_elem++;
2347 }
2348
2349 addr[num_elem] = &one;
2350 len[num_elem] = 1;
2351 num_elem++;
2352
2353 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2354 for (i = 0; i < num_elem; i++)
2355 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
b9d47b48 2356 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
30d27b04
JM
2357 if (res == 0)
2358 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2359 auth->curve->hash_len);
2360fail:
2361 wpabuf_free(pix);
2362 wpabuf_free(prx);
2363 wpabuf_free(bix);
2364 wpabuf_free(brx);
2365 return res;
2366}
2367
2368
2369static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2370{
2371 const EC_GROUP *group;
2372 EC_POINT *l = NULL;
2373 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2374 const EC_POINT *BI_point;
2375 BN_CTX *bnctx;
2376 BIGNUM *lx, *sum, *q;
2377 const BIGNUM *bR_bn, *pR_bn;
2378 int ret = -1;
30d27b04
JM
2379
2380 /* L = ((bR + pR) modulo q) * BI */
2381
2382 bnctx = BN_CTX_new();
2383 sum = BN_new();
2384 q = BN_new();
2385 lx = BN_new();
2386 if (!bnctx || !sum || !q || !lx)
2387 goto fail;
2388 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2389 if (!BI)
2390 goto fail;
2391 BI_point = EC_KEY_get0_public_key(BI);
2392 group = EC_KEY_get0_group(BI);
2393 if (!group)
2394 goto fail;
2395
2396 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2397 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2398 if (!bR || !pR)
2399 goto fail;
2400 bR_bn = EC_KEY_get0_private_key(bR);
2401 pR_bn = EC_KEY_get0_private_key(pR);
2402 if (!bR_bn || !pR_bn)
2403 goto fail;
2404 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2405 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2406 goto fail;
2407 l = EC_POINT_new(group);
2408 if (!l ||
2409 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2410 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2411 bnctx) != 1) {
2412 wpa_printf(MSG_ERROR,
2413 "OpenSSL: failed: %s",
2414 ERR_error_string(ERR_get_error(), NULL));
2415 goto fail;
2416 }
2417
fc0efa2a 2418 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
30d27b04 2419 goto fail;
30d27b04
JM
2420 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2421 ret = 0;
2422fail:
2423 EC_POINT_clear_free(l);
2424 EC_KEY_free(BI);
2425 EC_KEY_free(bR);
2426 EC_KEY_free(pR);
2427 BN_clear_free(lx);
2428 BN_clear_free(sum);
2429 BN_free(q);
2430 BN_CTX_free(bnctx);
2431 return ret;
2432}
2433
2434
2435static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2436{
2437 const EC_GROUP *group;
2438 EC_POINT *l = NULL, *sum = NULL;
2439 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2440 const EC_POINT *BR_point, *PR_point;
2441 BN_CTX *bnctx;
2442 BIGNUM *lx;
2443 const BIGNUM *bI_bn;
2444 int ret = -1;
30d27b04
JM
2445
2446 /* L = bI * (BR + PR) */
2447
2448 bnctx = BN_CTX_new();
2449 lx = BN_new();
2450 if (!bnctx || !lx)
2451 goto fail;
2452 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2453 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
2454 if (!BR || !PR)
2455 goto fail;
2456 BR_point = EC_KEY_get0_public_key(BR);
2457 PR_point = EC_KEY_get0_public_key(PR);
2458
2459 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2460 if (!bI)
2461 goto fail;
2462 group = EC_KEY_get0_group(bI);
2463 bI_bn = EC_KEY_get0_private_key(bI);
2464 if (!group || !bI_bn)
2465 goto fail;
2466 sum = EC_POINT_new(group);
2467 l = EC_POINT_new(group);
2468 if (!sum || !l ||
2469 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
2470 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
2471 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2472 bnctx) != 1) {
2473 wpa_printf(MSG_ERROR,
2474 "OpenSSL: failed: %s",
2475 ERR_error_string(ERR_get_error(), NULL));
2476 goto fail;
2477 }
2478
fc0efa2a 2479 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
30d27b04 2480 goto fail;
30d27b04
JM
2481 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2482 ret = 0;
2483fail:
2484 EC_POINT_clear_free(l);
2485 EC_KEY_free(bI);
2486 EC_KEY_free(BR);
2487 EC_KEY_free(PR);
2488 BN_clear_free(lx);
2489 BN_CTX_free(bnctx);
2490 return ret;
2491}
2492
2493
a03406db 2494static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
30d27b04
JM
2495{
2496 size_t nonce_len;
2497 EVP_PKEY_CTX *ctx = NULL;
2498 size_t secret_len;
2499 struct wpabuf *msg, *pr = NULL;
2500 u8 r_auth[4 + DPP_MAX_HASH_LEN];
ce9acce0 2501 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
30d27b04 2502 size_t wrapped_r_auth_len;
a03406db 2503 int ret = -1;
ce9acce0
JM
2504 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
2505 enum dpp_status_error status = DPP_STATUS_OK;
65ecce87
JM
2506#ifdef CONFIG_TESTING_OPTIONS
2507 u8 test_hash[SHA256_MAC_LEN];
2508#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
2509
2510 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
762fb4f0
JM
2511 if (!auth->own_bi)
2512 return -1;
30d27b04
JM
2513
2514 nonce_len = auth->curve->nonce_len;
2515 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2516 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
2517 goto fail;
2518 }
2519 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
2520
2521 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2522 if (!auth->own_protocol_key)
2523 goto fail;
2524
2525 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2526 if (!pr)
2527 goto fail;
2528
2529 /* ECDH: N = pR * PI */
2530 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2531 if (!ctx ||
2532 EVP_PKEY_derive_init(ctx) != 1 ||
2533 EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
2534 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2535 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2536 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
2537 wpa_printf(MSG_ERROR,
2538 "DPP: Failed to derive ECDH shared secret: %s",
2539 ERR_error_string(ERR_get_error(), NULL));
2540 goto fail;
2541 }
2542 EVP_PKEY_CTX_free(ctx);
2543 ctx = NULL;
2544
2545 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
2546 auth->Nx, auth->secret_len);
2547
2548 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2549 auth->curve->hash_len) < 0)
2550 goto fail;
2551
2552 if (auth->own_bi && auth->peer_bi) {
2553 /* Mutual authentication */
2554 if (dpp_auth_derive_l_responder(auth) < 0)
2555 goto fail;
2556 }
2557
2558 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2559 goto fail;
2560
2561 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2562 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
2563 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
978bc3f2
JM
2564 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
2565 goto fail;
2566#ifdef CONFIG_TESTING_OPTIONS
2567 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
2568 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
2569 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
2570 }
2571#endif /* CONFIG_TESTING_OPTIONS */
2572 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
30d27b04
JM
2573 r_auth, 4 + auth->curve->hash_len,
2574 0, NULL, NULL, wrapped_r_auth) < 0)
2575 goto fail;
2576 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
2577 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
2578 wrapped_r_auth, wrapped_r_auth_len);
ce9acce0 2579 w_r_auth = wrapped_r_auth;
30d27b04 2580
a03406db
JM
2581 r_pubkey_hash = auth->own_bi->pubkey_hash;
2582 if (auth->peer_bi)
2583 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2584 else
2585 i_pubkey_hash = NULL;
2586
ce9acce0
JM
2587 i_nonce = auth->i_nonce;
2588 r_nonce = auth->r_nonce;
2589
2590#ifdef CONFIG_TESTING_OPTIONS
2591 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2592 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2593 r_pubkey_hash = NULL;
65ecce87
JM
2594 } else if (dpp_test ==
2595 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2596 wpa_printf(MSG_INFO,
2597 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2598 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2599 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2600 r_pubkey_hash = test_hash;
ce9acce0
JM
2601 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2602 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2603 i_pubkey_hash = NULL;
65ecce87
JM
2604 } else if (dpp_test ==
2605 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2606 wpa_printf(MSG_INFO,
2607 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2608 if (i_pubkey_hash)
2609 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2610 else
2611 os_memset(test_hash, 0, SHA256_MAC_LEN);
2612 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2613 i_pubkey_hash = test_hash;
ce9acce0
JM
2614 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
2615 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
2616 wpabuf_free(pr);
2617 pr = NULL;
b6b4226b
JM
2618 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
2619 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
2620 wpabuf_free(pr);
2621 pr = wpabuf_alloc(2 * auth->curve->prime_len);
2622 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
2623 goto fail;
ce9acce0
JM
2624 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
2625 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
2626 w_r_auth = NULL;
2627 wrapped_r_auth_len = 0;
2628 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2629 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2630 status = 255;
3f35ec2d
JM
2631 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
2632 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2633 status = 254;
ce9acce0
JM
2634 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
2635 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
2636 r_nonce = NULL;
2637 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2638 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2639 i_nonce = NULL;
2640 }
2641#endif /* CONFIG_TESTING_OPTIONS */
2642
2643 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
a03406db 2644 r_pubkey_hash, i_pubkey_hash,
ce9acce0
JM
2645 r_nonce, i_nonce,
2646 w_r_auth, wrapped_r_auth_len,
a03406db 2647 auth->k2);
30d27b04
JM
2648 if (!msg)
2649 goto fail;
95b0104a 2650 wpabuf_free(auth->resp_msg);
dc4d271c 2651 auth->resp_msg = msg;
a03406db 2652 ret = 0;
30d27b04
JM
2653fail:
2654 wpabuf_free(pr);
a03406db 2655 return ret;
30d27b04
JM
2656}
2657
2658
2659static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
2660 enum dpp_status_error status)
2661{
30d27b04 2662 struct wpabuf *msg;
ce9acce0 2663 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
65ecce87
JM
2664#ifdef CONFIG_TESTING_OPTIONS
2665 u8 test_hash[SHA256_MAC_LEN];
2666#endif /* CONFIG_TESTING_OPTIONS */
30d27b04 2667
762fb4f0
JM
2668 if (!auth->own_bi)
2669 return -1;
30d27b04
JM
2670 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2671
a03406db
JM
2672 r_pubkey_hash = auth->own_bi->pubkey_hash;
2673 if (auth->peer_bi)
2674 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2675 else
2676 i_pubkey_hash = NULL;
2677
ce9acce0
JM
2678 i_nonce = auth->i_nonce;
2679
2680#ifdef CONFIG_TESTING_OPTIONS
2681 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2682 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2683 r_pubkey_hash = NULL;
65ecce87
JM
2684 } else if (dpp_test ==
2685 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2686 wpa_printf(MSG_INFO,
2687 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2688 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2689 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2690 r_pubkey_hash = test_hash;
ce9acce0
JM
2691 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2692 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2693 i_pubkey_hash = NULL;
65ecce87
JM
2694 } else if (dpp_test ==
2695 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2696 wpa_printf(MSG_INFO,
2697 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2698 if (i_pubkey_hash)
2699 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2700 else
2701 os_memset(test_hash, 0, SHA256_MAC_LEN);
2702 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2703 i_pubkey_hash = test_hash;
ce9acce0
JM
2704 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2705 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2706 status = -1;
2707 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2708 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2709 i_nonce = NULL;
2710 }
2711#endif /* CONFIG_TESTING_OPTIONS */
2712
a03406db
JM
2713 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
2714 r_pubkey_hash, i_pubkey_hash,
ce9acce0 2715 NULL, i_nonce, NULL, 0, auth->k1);
30d27b04 2716 if (!msg)
a03406db 2717 return -1;
95b0104a 2718 wpabuf_free(auth->resp_msg);
dc4d271c 2719 auth->resp_msg = msg;
30d27b04 2720 return 0;
30d27b04
JM
2721}
2722
2723
2724struct dpp_authentication *
2725dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
2726 struct dpp_bootstrap_info *peer_bi,
2727 struct dpp_bootstrap_info *own_bi,
dc4d271c 2728 unsigned int freq, const u8 *hdr, const u8 *attr_start,
27fefbbb 2729 size_t attr_len)
30d27b04
JM
2730{
2731 EVP_PKEY *pi = NULL;
2732 EVP_PKEY_CTX *ctx = NULL;
2733 size_t secret_len;
dc4d271c
JM
2734 const u8 *addr[2];
2735 size_t len[2];
30d27b04
JM
2736 u8 *unwrapped = NULL;
2737 size_t unwrapped_len = 0;
d2709206
JM
2738 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
2739 *channel;
27fefbbb 2740 u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
d2709206 2741 i_bootstrap_len, channel_len;
30d27b04 2742 struct dpp_authentication *auth = NULL;
30d27b04 2743
27fefbbb
JM
2744 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2745 &wrapped_data_len);
2746 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
26806abe
JM
2747 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
2748 "Missing or invalid required Wrapped Data attribute");
30d27b04 2749 return NULL;
27fefbbb
JM
2750 }
2751 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
2752 wrapped_data, wrapped_data_len);
30d27b04
JM
2753 attr_len = wrapped_data - 4 - attr_start;
2754
2755 auth = os_zalloc(sizeof(*auth));
2756 if (!auth)
2757 goto fail;
2758 auth->msg_ctx = msg_ctx;
2759 auth->peer_bi = peer_bi;
2760 auth->own_bi = own_bi;
2761 auth->curve = own_bi->curve;
2762 auth->curr_freq = freq;
2763
d2709206
JM
2764 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
2765 &channel_len);
2766 if (channel) {
2767 int neg_freq;
2768
2769 if (channel_len < 2) {
2770 dpp_auth_fail(auth, "Too short Channel attribute");
2771 goto fail;
2772 }
2773
2774 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
2775 wpa_printf(MSG_DEBUG,
2776 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2777 channel[0], channel[1], neg_freq);
2778 if (neg_freq < 0) {
2779 dpp_auth_fail(auth,
2780 "Unsupported Channel attribute value");
2781 goto fail;
2782 }
2783
2784 if (auth->curr_freq != (unsigned int) neg_freq) {
2785 wpa_printf(MSG_DEBUG,
2786 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2787 freq, neg_freq);
2788 auth->curr_freq = neg_freq;
2789 }
2790 }
2791
30d27b04
JM
2792 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
2793 &i_proto_len);
2794 if (!i_proto) {
26806abe
JM
2795 dpp_auth_fail(auth,
2796 "Missing required Initiator Protocol Key attribute");
30d27b04
JM
2797 goto fail;
2798 }
2799 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
2800 i_proto, i_proto_len);
2801
2802 /* M = bR * PI */
2803 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
2804 if (!pi) {
26806abe 2805 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
30d27b04
JM
2806 goto fail;
2807 }
2808 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
2809
2810 ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
2811 if (!ctx ||
2812 EVP_PKEY_derive_init(ctx) != 1 ||
2813 EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
2814 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2815 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2816 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
2817 wpa_printf(MSG_ERROR,
2818 "DPP: Failed to derive ECDH shared secret: %s",
2819 ERR_error_string(ERR_get_error(), NULL));
26806abe 2820 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
30d27b04
JM
2821 goto fail;
2822 }
2823 auth->secret_len = secret_len;
2824 EVP_PKEY_CTX_free(ctx);
2825 ctx = NULL;
2826
2827 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2828 auth->Mx, auth->secret_len);
2829
2830 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2831 auth->curve->hash_len) < 0)
2832 goto fail;
2833
dc4d271c
JM
2834 addr[0] = hdr;
2835 len[0] = DPP_HDR_LEN;
2836 addr[1] = attr_start;
2837 len[1] = attr_len;
2838 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2839 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
2840 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2841 wrapped_data, wrapped_data_len);
2842 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2843 unwrapped = os_malloc(unwrapped_len);
2844 if (!unwrapped)
2845 goto fail;
2846 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
2847 wrapped_data, wrapped_data_len,
dc4d271c 2848 2, addr, len, unwrapped) < 0) {
26806abe 2849 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
2850 goto fail;
2851 }
2852 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2853 unwrapped, unwrapped_len);
2854
2855 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
26806abe 2856 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
2857 goto fail;
2858 }
2859
2860 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
2861 &i_nonce_len);
2862 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
26806abe 2863 dpp_auth_fail(auth, "Missing or invalid I-nonce");
30d27b04
JM
2864 goto fail;
2865 }
2866 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
2867 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
2868
2869 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
2870 DPP_ATTR_I_CAPABILITIES,
2871 &i_capab_len);
2872 if (!i_capab || i_capab_len < 1) {
26806abe 2873 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
30d27b04
JM
2874 goto fail;
2875 }
2876 auth->i_capab = i_capab[0];
2877 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
2878
2879 bin_clear_free(unwrapped, unwrapped_len);
2880 unwrapped = NULL;
2881
2882 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
2883 case DPP_CAPAB_ENROLLEE:
2884 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
2885 wpa_printf(MSG_DEBUG,
2886 "DPP: Local policy does not allow Configurator role");
2887 goto not_compatible;
2888 }
2889 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
2890 auth->configurator = 1;
2891 break;
2892 case DPP_CAPAB_CONFIGURATOR:
2893 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
2894 wpa_printf(MSG_DEBUG,
2895 "DPP: Local policy does not allow Enrollee role");
2896 goto not_compatible;
2897 }
2898 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
2899 auth->configurator = 0;
2900 break;
d1f08264
JM
2901 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
2902 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
2903 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
2904 auth->configurator = 0;
2905 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
2906 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
2907 auth->configurator = 1;
2908 } else {
2909 wpa_printf(MSG_DEBUG,
2910 "DPP: Local policy does not allow Configurator/Enrollee role");
2911 goto not_compatible;
2912 }
2913 break;
30d27b04
JM
2914 default:
2915 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
3749ad0e
JM
2916 wpa_msg(auth->msg_ctx, MSG_INFO,
2917 DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
2918 auth->i_capab & DPP_CAPAB_ROLE_MASK);
2919 goto fail;
30d27b04
JM
2920 }
2921
2922 auth->peer_protocol_key = pi;
2923 pi = NULL;
2924 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
2925 char hex[SHA256_MAC_LEN * 2 + 1];
2926
2927 wpa_printf(MSG_DEBUG,
2928 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2929 if (dpp_auth_build_resp_status(auth,
2930 DPP_STATUS_RESPONSE_PENDING) < 0)
2931 goto fail;
2932 i_bootstrap = dpp_get_attr(attr_start, attr_len,
2933 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
2934 &i_bootstrap_len);
2935 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
2936 auth->response_pending = 1;
2937 os_memcpy(auth->waiting_pubkey_hash,
2938 i_bootstrap, i_bootstrap_len);
2939 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
2940 i_bootstrap_len);
2941 } else {
2942 hex[0] = '\0';
2943 }
2944
2945 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
2946 "%s", hex);
2947 return auth;
2948 }
a03406db 2949 if (dpp_auth_build_resp_ok(auth) < 0)
30d27b04
JM
2950 goto fail;
2951
2952 return auth;
2953
2954not_compatible:
2955 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
2956 "i-capab=0x%02x", auth->i_capab);
2957 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
2958 auth->configurator = 1;
2959 else
2960 auth->configurator = 0;
2961 auth->peer_protocol_key = pi;
2962 pi = NULL;
2963 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
2964 goto fail;
2965
2966 auth->remove_on_tx_status = 1;
2967 return auth;
2968fail:
2969 bin_clear_free(unwrapped, unwrapped_len);
2970 EVP_PKEY_free(pi);
2971 EVP_PKEY_CTX_free(ctx);
2972 dpp_auth_deinit(auth);
2973 return NULL;
2974}
2975
2976
2977int dpp_notify_new_qr_code(struct dpp_authentication *auth,
2978 struct dpp_bootstrap_info *peer_bi)
2979{
2980 if (!auth || !auth->response_pending ||
2981 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
2982 SHA256_MAC_LEN) != 0)
2983 return 0;
2984
2985 wpa_printf(MSG_DEBUG,
2986 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2987 MACSTR, MAC2STR(auth->peer_mac_addr));
2988 auth->peer_bi = peer_bi;
2989
a03406db 2990 if (dpp_auth_build_resp_ok(auth) < 0)
30d27b04
JM
2991 return -1;
2992
2993 return 1;
2994}
2995
2996
7d917ab0
JM
2997static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
2998 enum dpp_status_error status)
30d27b04
JM
2999{
3000 struct wpabuf *msg;
3001 u8 i_auth[4 + DPP_MAX_HASH_LEN];
3002 size_t i_auth_len;
7d917ab0
JM
3003 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3004 size_t r_nonce_len;
dc4d271c
JM
3005 const u8 *addr[2];
3006 size_t len[2], attr_len;
30d27b04 3007 u8 *wrapped_i_auth;
7d917ab0 3008 u8 *wrapped_r_nonce;
dc4d271c 3009 u8 *attr_start, *attr_end;
65ecce87
JM
3010 const u8 *r_pubkey_hash, *i_pubkey_hash;
3011#ifdef CONFIG_TESTING_OPTIONS
3012 u8 test_hash[SHA256_MAC_LEN];
3013#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
3014
3015 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3016
3017 i_auth_len = 4 + auth->curve->hash_len;
7d917ab0 3018 r_nonce_len = 4 + auth->curve->nonce_len;
30d27b04 3019 /* Build DPP Authentication Confirmation frame attributes */
dc4d271c 3020 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
7d917ab0 3021 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
60239f60
JM
3022#ifdef CONFIG_TESTING_OPTIONS
3023 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
acdf703d 3024 attr_len += 5;
60239f60 3025#endif /* CONFIG_TESTING_OPTIONS */
dc4d271c 3026 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
30d27b04
JM
3027 if (!msg)
3028 goto fail;
3029
dc4d271c
JM
3030 attr_start = wpabuf_put(msg, 0);
3031
65ecce87
JM
3032 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3033 if (auth->own_bi)
3034 i_pubkey_hash = auth->own_bi->pubkey_hash;
3035 else
3036 i_pubkey_hash = NULL;
3037
f9c7d770 3038#ifdef CONFIG_TESTING_OPTIONS
3f35ec2d
JM
3039 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3040 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
f9c7d770 3041 goto skip_status;
3f35ec2d
JM
3042 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3043 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3044 status = 254;
3045 }
f9c7d770
JM
3046#endif /* CONFIG_TESTING_OPTIONS */
3047
30d27b04 3048 /* DPP Status */
56f24d1d 3049 dpp_build_attr_status(msg, status);
30d27b04 3050
f9c7d770
JM
3051#ifdef CONFIG_TESTING_OPTIONS
3052skip_status:
65ecce87
JM
3053 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3054 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3055 r_pubkey_hash = NULL;
3056 } else if (dpp_test ==
3057 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3058 wpa_printf(MSG_INFO,
3059 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3060 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3061 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3062 r_pubkey_hash = test_hash;
3063 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3064 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3065 i_pubkey_hash = NULL;
3066 } else if (dpp_test ==
3067 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3068 wpa_printf(MSG_INFO,
3069 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3070 if (i_pubkey_hash)
3071 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3072 else
3073 os_memset(test_hash, 0, SHA256_MAC_LEN);
3074 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3075 i_pubkey_hash = test_hash;
3076 }
f9c7d770
JM
3077#endif /* CONFIG_TESTING_OPTIONS */
3078
30d27b04 3079 /* Responder Bootstrapping Key Hash */
9efa5314 3080 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
f9c7d770 3081
9efa5314
JM
3082 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3083 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
30d27b04 3084
f9c7d770 3085#ifdef CONFIG_TESTING_OPTIONS
f9c7d770
JM
3086 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3087 goto skip_wrapped_data;
3088 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3089 i_auth_len = 0;
3090#endif /* CONFIG_TESTING_OPTIONS */
3091
dc4d271c
JM
3092 attr_end = wpabuf_put(msg, 0);
3093
3094 /* OUI, OUI type, Crypto Suite, DPP frame type */
3095 addr[0] = wpabuf_head_u8(msg) + 2;
3096 len[0] = 3 + 1 + 1 + 1;
3097 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3098
3099 /* Attributes before Wrapped Data */
3100 addr[1] = attr_start;
3101 len[1] = attr_end - attr_start;
3102 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3103
7d917ab0
JM
3104 if (status == DPP_STATUS_OK) {
3105 /* I-auth wrapped with ke */
3106 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3107 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3108 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
f9c7d770
JM
3109
3110#ifdef CONFIG_TESTING_OPTIONS
7d917ab0
JM
3111 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3112 goto skip_i_auth;
f9c7d770
JM
3113#endif /* CONFIG_TESTING_OPTIONS */
3114
7d917ab0
JM
3115 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3116 * 1) */
3117 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3118 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3119 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3120 goto fail;
f9c7d770
JM
3121
3122#ifdef CONFIG_TESTING_OPTIONS
7d917ab0
JM
3123 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3124 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3125 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3126 }
f9c7d770
JM
3127skip_i_auth:
3128#endif /* CONFIG_TESTING_OPTIONS */
7d917ab0
JM
3129 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3130 i_auth, i_auth_len,
3131 2, addr, len, wrapped_i_auth) < 0)
3132 goto fail;
3133 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3134 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3135 } else {
3136 /* R-nonce wrapped with k2 */
3137 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3138 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3139 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3140
3141 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3142 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3143 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3144
3145 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3146 r_nonce, r_nonce_len,
3147 2, addr, len, wrapped_r_nonce) < 0)
3148 goto fail;
3149 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3150 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3151 }
30d27b04 3152
60239f60
JM
3153#ifdef CONFIG_TESTING_OPTIONS
3154 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3155 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 3156 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 3157 }
f9c7d770 3158skip_wrapped_data:
60239f60
JM
3159#endif /* CONFIG_TESTING_OPTIONS */
3160
30d27b04
JM
3161 wpa_hexdump_buf(MSG_DEBUG,
3162 "DPP: Authentication Confirmation frame attributes",
3163 msg);
7d917ab0
JM
3164 if (status == DPP_STATUS_OK)
3165 dpp_auth_success(auth);
30d27b04
JM
3166
3167 return msg;
3168
3169fail:
3170 return NULL;
3171}
3172
3173
3174static void
dc4d271c 3175dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
30d27b04
JM
3176 const u8 *attr_start, size_t attr_len,
3177 const u8 *wrapped_data, u16 wrapped_data_len,
3178 enum dpp_status_error status)
3179{
dc4d271c
JM
3180 const u8 *addr[2];
3181 size_t len[2];
30d27b04
JM
3182 u8 *unwrapped = NULL;
3183 size_t unwrapped_len = 0;
3184 const u8 *i_nonce, *r_capab;
3185 u16 i_nonce_len, r_capab_len;
3186
3187 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3188 wpa_printf(MSG_DEBUG,
3189 "DPP: Responder reported incompatible roles");
3190 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3191 wpa_printf(MSG_DEBUG,
3192 "DPP: Responder reported more time needed");
3193 } else {
3194 wpa_printf(MSG_DEBUG,
3195 "DPP: Responder reported failure (status %d)",
3196 status);
26806abe 3197 dpp_auth_fail(auth, "Responder reported failure");
30d27b04
JM
3198 return;
3199 }
3200
dc4d271c
JM
3201 addr[0] = hdr;
3202 len[0] = DPP_HDR_LEN;
3203 addr[1] = attr_start;
3204 len[1] = attr_len;
3205 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3206 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
3207 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3208 wrapped_data, wrapped_data_len);
3209 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3210 unwrapped = os_malloc(unwrapped_len);
3211 if (!unwrapped)
3212 goto fail;
3213 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3214 wrapped_data, wrapped_data_len,
dc4d271c 3215 2, addr, len, unwrapped) < 0) {
26806abe 3216 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
3217 goto fail;
3218 }
3219 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3220 unwrapped, unwrapped_len);
3221
3222 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
26806abe 3223 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
3224 goto fail;
3225 }
3226
3227 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3228 &i_nonce_len);
3229 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
26806abe 3230 dpp_auth_fail(auth, "Missing or invalid I-nonce");
30d27b04
JM
3231 goto fail;
3232 }
3233 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3234 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
26806abe 3235 dpp_auth_fail(auth, "I-nonce mismatch");
30d27b04
JM
3236 goto fail;
3237 }
3238
3239 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3240 DPP_ATTR_R_CAPABILITIES,
3241 &r_capab_len);
3242 if (!r_capab || r_capab_len < 1) {
26806abe 3243 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
30d27b04
JM
3244 goto fail;
3245 }
3246 auth->r_capab = r_capab[0];
3247 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3248 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3249 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3250 "r-capab=0x%02x", auth->r_capab);
3251 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3749ad0e
JM
3252 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3253
3254 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3255 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3256 wpa_msg(auth->msg_ctx, MSG_INFO,
3257 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3258 role);
3259 } else {
3260 wpa_printf(MSG_DEBUG,
3261 "DPP: Continue waiting for full DPP Authentication Response");
3262 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_RESPONSE_PENDING);
3263 }
30d27b04
JM
3264 }
3265fail:
3266 bin_clear_free(unwrapped, unwrapped_len);
3267}
3268
3269
3270struct wpabuf *
dc4d271c
JM
3271dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3272 const u8 *attr_start, size_t attr_len)
30d27b04
JM
3273{
3274 EVP_PKEY *pr;
3275 EVP_PKEY_CTX *ctx = NULL;
3276 size_t secret_len;
dc4d271c
JM
3277 const u8 *addr[2];
3278 size_t len[2];
30d27b04
JM
3279 u8 *unwrapped = NULL, *unwrapped2 = NULL;
3280 size_t unwrapped_len = 0, unwrapped2_len = 0;
3281 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3282 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3283 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3284 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3285 wrapped2_len, r_auth_len;
3286 u8 r_auth2[DPP_MAX_HASH_LEN];
3749ad0e 3287 u8 role;
30d27b04 3288
03abb6b5
JM
3289 if (!auth->initiator) {
3290 dpp_auth_fail(auth, "Unexpected Authentication Response");
3291 return NULL;
3292 }
3293
f97ace34
JM
3294 auth->waiting_auth_resp = 0;
3295
30d27b04
JM
3296 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3297 &wrapped_data_len);
26806abe
JM
3298 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3299 dpp_auth_fail(auth,
3300 "Missing or invalid required Wrapped Data attribute");
30d27b04
JM
3301 return NULL;
3302 }
3303 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3304 wrapped_data, wrapped_data_len);
3305
30d27b04
JM
3306 attr_len = wrapped_data - 4 - attr_start;
3307
3308 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3309 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3310 &r_bootstrap_len);
3311 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
26806abe
JM
3312 dpp_auth_fail(auth,
3313 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
30d27b04
JM
3314 return NULL;
3315 }
3316 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3317 r_bootstrap, r_bootstrap_len);
3318 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3319 SHA256_MAC_LEN) != 0) {
26806abe
JM
3320 dpp_auth_fail(auth,
3321 "Unexpected Responder Bootstrapping Key Hash value");
30d27b04
JM
3322 wpa_hexdump(MSG_DEBUG,
3323 "DPP: Expected Responder Bootstrapping Key Hash",
3324 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3325 return NULL;
3326 }
3327
3328 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3329 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3330 &i_bootstrap_len);
3331 if (i_bootstrap) {
3332 if (i_bootstrap_len != SHA256_MAC_LEN) {
26806abe
JM
3333 dpp_auth_fail(auth,
3334 "Invalid Initiator Bootstrapping Key Hash attribute");
30d27b04
JM
3335 return NULL;
3336 }
3337 wpa_hexdump(MSG_MSGDUMP,
3338 "DPP: Initiator Bootstrapping Key Hash",
3339 i_bootstrap, i_bootstrap_len);
3340 if (!auth->own_bi ||
3341 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3342 SHA256_MAC_LEN) != 0) {
26806abe
JM
3343 dpp_auth_fail(auth,
3344 "Initiator Bootstrapping Key Hash attribute did not match");
30d27b04
JM
3345 return NULL;
3346 }
9b511120
JM
3347 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3348 /* PKEX bootstrapping mandates use of mutual authentication */
3349 dpp_auth_fail(auth,
3350 "Missing Initiator Bootstrapping Key Hash attribute");
3351 return NULL;
30d27b04
JM
3352 }
3353
3354 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3355 &status_len);
3356 if (!status || status_len < 1) {
26806abe
JM
3357 dpp_auth_fail(auth,
3358 "Missing or invalid required DPP Status attribute");
30d27b04
JM
3359 return NULL;
3360 }
3361 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3362 auth->auth_resp_status = status[0];
3363 if (status[0] != DPP_STATUS_OK) {
dc4d271c 3364 dpp_auth_resp_rx_status(auth, hdr, attr_start,
30d27b04
JM
3365 attr_len, wrapped_data,
3366 wrapped_data_len, status[0]);
3367 return NULL;
3368 }
3369
9b511120
JM
3370 if (!i_bootstrap && auth->own_bi) {
3371 wpa_printf(MSG_DEBUG,
3372 "DPP: Responder decided not to use mutual authentication");
3373 auth->own_bi = NULL;
3374 }
3375
30d27b04
JM
3376 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3377 &r_proto_len);
3378 if (!r_proto) {
26806abe
JM
3379 dpp_auth_fail(auth,
3380 "Missing required Responder Protocol Key attribute");
30d27b04
JM
3381 return NULL;
3382 }
3383 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3384 r_proto, r_proto_len);
3385
3386 /* N = pI * PR */
3387 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3388 if (!pr) {
26806abe 3389 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
30d27b04
JM
3390 return NULL;
3391 }
3392 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3393
3394 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
3395 if (!ctx ||
3396 EVP_PKEY_derive_init(ctx) != 1 ||
3397 EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
3398 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
3399 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
3400 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
3401 wpa_printf(MSG_ERROR,
3402 "DPP: Failed to derive ECDH shared secret: %s",
3403 ERR_error_string(ERR_get_error(), NULL));
26806abe 3404 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
30d27b04
JM
3405 goto fail;
3406 }
3407 EVP_PKEY_CTX_free(ctx);
3408 ctx = NULL;
3409 auth->peer_protocol_key = pr;
3410 pr = NULL;
3411
3412 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3413 auth->Nx, auth->secret_len);
3414
3415 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3416 auth->curve->hash_len) < 0)
3417 goto fail;
3418
dc4d271c
JM
3419 addr[0] = hdr;
3420 len[0] = DPP_HDR_LEN;
3421 addr[1] = attr_start;
3422 len[1] = attr_len;
3423 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3424 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
3425 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3426 wrapped_data, wrapped_data_len);
3427 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3428 unwrapped = os_malloc(unwrapped_len);
3429 if (!unwrapped)
3430 goto fail;
3431 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3432 wrapped_data, wrapped_data_len,
dc4d271c 3433 2, addr, len, unwrapped) < 0) {
26806abe 3434 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
3435 goto fail;
3436 }
3437 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3438 unwrapped, unwrapped_len);
3439
3440 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
26806abe 3441 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
3442 goto fail;
3443 }
3444
3445 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3446 &r_nonce_len);
3447 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
26806abe 3448 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
30d27b04
JM
3449 goto fail;
3450 }
3451 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
3452 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
3453
3454 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3455 &i_nonce_len);
3456 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
26806abe 3457 dpp_auth_fail(auth, "Missing or invalid I-nonce");
30d27b04
JM
3458 goto fail;
3459 }
3460 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3461 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
26806abe 3462 dpp_auth_fail(auth, "I-nonce mismatch");
30d27b04
JM
3463 goto fail;
3464 }
3465
3466 if (auth->own_bi && auth->peer_bi) {
3467 /* Mutual authentication */
3468 if (dpp_auth_derive_l_initiator(auth) < 0)
3469 goto fail;
3470 }
3471
30d27b04
JM
3472 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3473 DPP_ATTR_R_CAPABILITIES,
3474 &r_capab_len);
3475 if (!r_capab || r_capab_len < 1) {
26806abe 3476 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
30d27b04
JM
3477 goto fail;
3478 }
3479 auth->r_capab = r_capab[0];
3480 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3749ad0e 3481 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
d1f08264
JM
3482 if ((auth->allowed_roles ==
3483 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
3484 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
3485 /* Peer selected its role, so move from "either role" to the
3486 * role that is compatible with peer's selection. */
3487 auth->configurator = role == DPP_CAPAB_ENROLLEE;
3488 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
3489 auth->configurator ? "Configurator" : "Enrollee");
3490 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3491 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
30d27b04 3492 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
3749ad0e
JM
3493 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3494 "Unexpected role in R-capabilities 0x%02x",
3495 role);
7d917ab0
JM
3496 if (role != DPP_CAPAB_ENROLLEE &&
3497 role != DPP_CAPAB_CONFIGURATOR)
3498 goto fail;
3499 bin_clear_free(unwrapped, unwrapped_len);
3500 auth->remove_on_tx_status = 1;
3501 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
30d27b04
JM
3502 }
3503
3504 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
3505 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
3506 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
26806abe
JM
3507 dpp_auth_fail(auth,
3508 "Missing or invalid Secondary Wrapped Data");
30d27b04
JM
3509 goto fail;
3510 }
3511
3512 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3513 wrapped2, wrapped2_len);
7d917ab0
JM
3514
3515 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3516 goto fail;
3517
30d27b04
JM
3518 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
3519 unwrapped2 = os_malloc(unwrapped2_len);
3520 if (!unwrapped2)
3521 goto fail;
3522 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3523 wrapped2, wrapped2_len,
3524 0, NULL, NULL, unwrapped2) < 0) {
26806abe 3525 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
3526 goto fail;
3527 }
3528 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3529 unwrapped2, unwrapped2_len);
3530
3531 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
26806abe
JM
3532 dpp_auth_fail(auth,
3533 "Invalid attribute in secondary unwrapped data");
30d27b04
JM
3534 goto fail;
3535 }
3536
3537 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
3538 &r_auth_len);
3539 if (!r_auth || r_auth_len != auth->curve->hash_len) {
26806abe
JM
3540 dpp_auth_fail(auth,
3541 "Missing or invalid Responder Authenticating Tag");
30d27b04
JM
3542 goto fail;
3543 }
3544 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
3545 r_auth, r_auth_len);
3546 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3547 if (dpp_gen_r_auth(auth, r_auth2) < 0)
3548 goto fail;
3549 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
3550 r_auth2, r_auth_len);
3551 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
26806abe 3552 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
7d917ab0
JM
3553 bin_clear_free(unwrapped, unwrapped_len);
3554 bin_clear_free(unwrapped2, unwrapped2_len);
3555 auth->remove_on_tx_status = 1;
3556 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
30d27b04
JM
3557 }
3558
3559 bin_clear_free(unwrapped, unwrapped_len);
3560 bin_clear_free(unwrapped2, unwrapped2_len);
3561
762fb4f0
JM
3562#ifdef CONFIG_TESTING_OPTIONS
3563 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
3564 wpa_printf(MSG_INFO,
3565 "DPP: TESTING - Authentication Response in place of Confirm");
3566 if (dpp_auth_build_resp_ok(auth) < 0)
3567 return NULL;
3568 return wpabuf_dup(auth->resp_msg);
3569 }
3570#endif /* CONFIG_TESTING_OPTIONS */
3571
7d917ab0 3572 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
30d27b04
JM
3573
3574fail:
3575 bin_clear_free(unwrapped, unwrapped_len);
3576 bin_clear_free(unwrapped2, unwrapped2_len);
3577 EVP_PKEY_free(pr);
3578 EVP_PKEY_CTX_free(ctx);
3579 return NULL;
3580}
3581
3582
19ef4289
JM
3583static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
3584 const u8 *hdr,
3585 const u8 *attr_start, size_t attr_len,
3586 const u8 *wrapped_data,
3587 u16 wrapped_data_len,
3588 enum dpp_status_error status)
3589{
3590 const u8 *addr[2];
3591 size_t len[2];
3592 u8 *unwrapped = NULL;
3593 size_t unwrapped_len = 0;
3594 const u8 *r_nonce;
3595 u16 r_nonce_len;
3596
3597 /* Authentication Confirm failure cases are expected to include
3598 * {R-nonce}k2 in the Wrapped Data attribute. */
3599
3600 addr[0] = hdr;
3601 len[0] = DPP_HDR_LEN;
3602 addr[1] = attr_start;
3603 len[1] = attr_len;
3604 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3605 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3606 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3607 wrapped_data, wrapped_data_len);
3608 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3609 unwrapped = os_malloc(unwrapped_len);
3610 if (!unwrapped) {
3611 dpp_auth_fail(auth, "Authentication failed");
3612 goto fail;
3613 }
3614 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3615 wrapped_data, wrapped_data_len,
3616 2, addr, len, unwrapped) < 0) {
3617 dpp_auth_fail(auth, "AES-SIV decryption failed");
3618 goto fail;
3619 }
3620 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3621 unwrapped, unwrapped_len);
3622
3623 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3624 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3625 goto fail;
3626 }
3627
3628 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3629 &r_nonce_len);
3630 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3631 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3632 goto fail;
3633 }
3634 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
3635 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
3636 r_nonce, r_nonce_len);
3637 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
3638 auth->r_nonce, r_nonce_len);
3639 dpp_auth_fail(auth, "R-nonce mismatch");
3640 goto fail;
3641 }
3642
3643 if (status == DPP_STATUS_NOT_COMPATIBLE)
3644 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
3645 else if (status == DPP_STATUS_AUTH_FAILURE)
3646 dpp_auth_fail(auth, "Peer reported authentication failure)");
3647
3648fail:
3649 bin_clear_free(unwrapped, unwrapped_len);
3650 return -1;
3651}
3652
3653
dc4d271c
JM
3654int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
3655 const u8 *attr_start, size_t attr_len)
30d27b04
JM
3656{
3657 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
3658 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3659 i_auth_len;
dc4d271c
JM
3660 const u8 *addr[2];
3661 size_t len[2];
30d27b04
JM
3662 u8 *unwrapped = NULL;
3663 size_t unwrapped_len = 0;
3664 u8 i_auth2[DPP_MAX_HASH_LEN];
3665
03abb6b5
JM
3666 if (auth->initiator) {
3667 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
3668 return NULL;
3669 }
3670
95b0104a
JM
3671 auth->waiting_auth_conf = 0;
3672
30d27b04
JM
3673 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3674 &wrapped_data_len);
dcdaeab7
JM
3675 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3676 dpp_auth_fail(auth,
3677 "Missing or invalid required Wrapped Data attribute");
30d27b04
JM
3678 return -1;
3679 }
3680 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3681 wrapped_data, wrapped_data_len);
3682
30d27b04
JM
3683 attr_len = wrapped_data - 4 - attr_start;
3684
3685 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3686 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3687 &r_bootstrap_len);
dcdaeab7
JM
3688 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3689 dpp_auth_fail(auth,
3690 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
30d27b04
JM
3691 return -1;
3692 }
3693 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3694 r_bootstrap, r_bootstrap_len);
3695 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
3696 SHA256_MAC_LEN) != 0) {
3697 wpa_hexdump(MSG_DEBUG,
3698 "DPP: Expected Responder Bootstrapping Key Hash",
3699 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
dcdaeab7
JM
3700 dpp_auth_fail(auth,
3701 "Responder Bootstrapping Key Hash mismatch");
30d27b04
JM
3702 return -1;
3703 }
3704
3705 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3706 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3707 &i_bootstrap_len);
3708 if (i_bootstrap) {
dcdaeab7
JM
3709 if (i_bootstrap_len != SHA256_MAC_LEN) {
3710 dpp_auth_fail(auth,
3711 "Invalid Initiator Bootstrapping Key Hash attribute");
30d27b04
JM
3712 return -1;
3713 }
3714 wpa_hexdump(MSG_MSGDUMP,
3715 "DPP: Initiator Bootstrapping Key Hash",
3716 i_bootstrap, i_bootstrap_len);
3717 if (!auth->peer_bi ||
3718 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
3719 SHA256_MAC_LEN) != 0) {
dcdaeab7
JM
3720 dpp_auth_fail(auth,
3721 "Initiator Bootstrapping Key Hash mismatch");
30d27b04
JM
3722 return -1;
3723 }
9b511120
JM
3724 } else if (auth->own_bi && auth->peer_bi) {
3725 /* Mutual authentication and peer did not include its
3726 * Bootstrapping Key Hash attribute. */
3727 dpp_auth_fail(auth,
3728 "Missing Initiator Bootstrapping Key Hash attribute");
3729 return -1;
30d27b04
JM
3730 }
3731
3732 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3733 &status_len);
3734 if (!status || status_len < 1) {
dcdaeab7
JM
3735 dpp_auth_fail(auth,
3736 "Missing or invalid required DPP Status attribute");
30d27b04
JM
3737 return -1;
3738 }
3739 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
19ef4289
JM
3740 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
3741 status[0] == DPP_STATUS_AUTH_FAILURE)
3742 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
3743 attr_len, wrapped_data,
3744 wrapped_data_len, status[0]);
3745
30d27b04 3746 if (status[0] != DPP_STATUS_OK) {
dcdaeab7 3747 dpp_auth_fail(auth, "Authentication failed");
30d27b04
JM
3748 return -1;
3749 }
3750
dc4d271c
JM
3751 addr[0] = hdr;
3752 len[0] = DPP_HDR_LEN;
3753 addr[1] = attr_start;
3754 len[1] = attr_len;
3755 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3756 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
3757 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3758 wrapped_data, wrapped_data_len);
3759 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3760 unwrapped = os_malloc(unwrapped_len);
3761 if (!unwrapped)
3762 return -1;
3763 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3764 wrapped_data, wrapped_data_len,
dc4d271c 3765 2, addr, len, unwrapped) < 0) {
dcdaeab7 3766 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
3767 goto fail;
3768 }
3769 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3770 unwrapped, unwrapped_len);
3771
3772 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
dcdaeab7 3773 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
3774 goto fail;
3775 }
3776
3777 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
3778 &i_auth_len);
3779 if (!i_auth || i_auth_len != auth->curve->hash_len) {
dcdaeab7
JM
3780 dpp_auth_fail(auth,
3781 "Missing or invalid Initiator Authenticating Tag");
30d27b04
JM
3782 goto fail;
3783 }
3784 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
3785 i_auth, i_auth_len);
3786 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3787 if (dpp_gen_i_auth(auth, i_auth2) < 0)
3788 goto fail;
3789 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
3790 i_auth2, i_auth_len);
3791 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
dcdaeab7 3792 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
30d27b04
JM
3793 goto fail;
3794 }
3795
3796 bin_clear_free(unwrapped, unwrapped_len);
3797 dpp_auth_success(auth);
3798 return 0;
3799fail:
3800 bin_clear_free(unwrapped, unwrapped_len);
3801 return -1;
3802}
3803
3804
461d39af
JM
3805void dpp_configuration_free(struct dpp_configuration *conf)
3806{
3807 if (!conf)
3808 return;
3809 str_clear_free(conf->passphrase);
3810 bin_clear_free(conf, sizeof(*conf));
3811}
3812
3813
30d27b04
JM
3814void dpp_auth_deinit(struct dpp_authentication *auth)
3815{
3816 if (!auth)
3817 return;
461d39af
JM
3818 dpp_configuration_free(auth->conf_ap);
3819 dpp_configuration_free(auth->conf_sta);
30d27b04
JM
3820 EVP_PKEY_free(auth->own_protocol_key);
3821 EVP_PKEY_free(auth->peer_protocol_key);
dc4d271c
JM
3822 wpabuf_free(auth->req_msg);
3823 wpabuf_free(auth->resp_msg);
461d39af
JM
3824 wpabuf_free(auth->conf_req);
3825 os_free(auth->connector);
3826 wpabuf_free(auth->net_access_key);
3827 wpabuf_free(auth->c_sign_key);
3828#ifdef CONFIG_TESTING_OPTIONS
3829 os_free(auth->config_obj_override);
3830 os_free(auth->discovery_override);
3831 os_free(auth->groups_override);
461d39af 3832#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
3833 bin_clear_free(auth, sizeof(*auth));
3834}
461d39af
JM
3835
3836
3837static struct wpabuf *
3838dpp_build_conf_start(struct dpp_authentication *auth,
3839 struct dpp_configuration *conf, size_t tailroom)
3840{
3841 struct wpabuf *buf;
3842 char ssid[6 * sizeof(conf->ssid) + 1];
3843
3844#ifdef CONFIG_TESTING_OPTIONS
3845 if (auth->discovery_override)
3846 tailroom += os_strlen(auth->discovery_override);
3847#endif /* CONFIG_TESTING_OPTIONS */
3848
3849 buf = wpabuf_alloc(200 + tailroom);
3850 if (!buf)
3851 return NULL;
3852 wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
3853#ifdef CONFIG_TESTING_OPTIONS
3854 if (auth->discovery_override) {
3855 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
3856 auth->discovery_override);
3857 wpabuf_put_str(buf, auth->discovery_override);
3858 wpabuf_put_u8(buf, ',');
3859 return buf;
3860 }
3861#endif /* CONFIG_TESTING_OPTIONS */
3862 wpabuf_put_str(buf, "{\"ssid\":\"");
3863 json_escape_string(ssid, sizeof(ssid),
3864 (const char *) conf->ssid, conf->ssid_len);
3865 wpabuf_put_str(buf, ssid);
2265353a 3866 wpabuf_put_str(buf, "\"},");
461d39af
JM
3867
3868 return buf;
3869}
3870
3871
461d39af
JM
3872static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
3873 const char *kid, const struct dpp_curve_params *curve)
3874{
3875 struct wpabuf *pub;
3876 const u8 *pos;
3877 char *x = NULL, *y = NULL;
3878 int ret = -1;
3879
3880 pub = dpp_get_pubkey_point(key, 0);
3881 if (!pub)
3882 goto fail;
3883 pos = wpabuf_head(pub);
3884 x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
3885 pos += curve->prime_len;
3886 y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
58efbcbc
JM
3887 if (!x || !y)
3888 goto fail;
461d39af
JM
3889
3890 wpabuf_put_str(buf, "\"");
3891 wpabuf_put_str(buf, name);
3892 wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
3893 wpabuf_put_str(buf, curve->jwk_crv);
3894 wpabuf_put_str(buf, "\",\"x\":\"");
3895 wpabuf_put_str(buf, x);
3896 wpabuf_put_str(buf, "\",\"y\":\"");
3897 wpabuf_put_str(buf, y);
3898 if (kid) {
3899 wpabuf_put_str(buf, "\",\"kid\":\"");
3900 wpabuf_put_str(buf, kid);
3901 }
3902 wpabuf_put_str(buf, "\"}");
3903 ret = 0;
58efbcbc 3904fail:
461d39af
JM
3905 wpabuf_free(pub);
3906 os_free(x);
3907 os_free(y);
3908 return ret;
461d39af
JM
3909}
3910
3911
3912static struct wpabuf *
3913dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
3914 struct dpp_configuration *conf)
3915{
3916 struct wpabuf *buf = NULL;
3917 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
3918 size_t tailroom;
3919 const struct dpp_curve_params *curve;
3920 char jws_prot_hdr[100];
3921 size_t signed1_len, signed2_len, signed3_len;
3922 struct wpabuf *dppcon = NULL;
3923 unsigned char *signature = NULL;
3924 const unsigned char *p;
3925 size_t signature_len;
3926 EVP_MD_CTX *md_ctx = NULL;
3927 ECDSA_SIG *sig = NULL;
3928 char *dot = ".";
461d39af
JM
3929 const EVP_MD *sign_md;
3930 const BIGNUM *r, *s;
3931 size_t extra_len = 1000;
3932
3933 if (!auth->conf) {
3934 wpa_printf(MSG_INFO,
3935 "DPP: No configurator specified - cannot generate DPP config object");
3936 goto fail;
3937 }
3938 curve = auth->conf->curve;
3939 if (curve->hash_len == SHA256_MAC_LEN) {
461d39af
JM
3940 sign_md = EVP_sha256();
3941 } else if (curve->hash_len == SHA384_MAC_LEN) {
461d39af
JM
3942 sign_md = EVP_sha384();
3943 } else if (curve->hash_len == SHA512_MAC_LEN) {
461d39af
JM
3944 sign_md = EVP_sha512();
3945 } else {
3946 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
3947 goto fail;
3948 }
3949
3950#ifdef CONFIG_TESTING_OPTIONS
3951 if (auth->groups_override)
3952 extra_len += os_strlen(auth->groups_override);
461d39af
JM
3953#endif /* CONFIG_TESTING_OPTIONS */
3954
3955 /* Connector (JSON dppCon object) */
3956 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
3957 if (!dppcon)
3958 goto fail;
3959#ifdef CONFIG_TESTING_OPTIONS
a4bf0078 3960 if (auth->groups_override) {
461d39af
JM
3961 wpabuf_put_u8(dppcon, '{');
3962 if (auth->groups_override) {
3963 wpa_printf(MSG_DEBUG,
3964 "DPP: TESTING - groups override: '%s'",
3965 auth->groups_override);
3966 wpabuf_put_str(dppcon, "\"groups\":");
3967 wpabuf_put_str(dppcon, auth->groups_override);
3968 wpabuf_put_u8(dppcon, ',');
3969 }
461d39af
JM
3970 goto skip_groups;
3971 }
3972#endif /* CONFIG_TESTING_OPTIONS */
3973 wpabuf_put_str(dppcon, "{\"groups\":[{\"groupId\":\"*\",");
3974 wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
3975#ifdef CONFIG_TESTING_OPTIONS
3976skip_groups:
3977#endif /* CONFIG_TESTING_OPTIONS */
3978 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
3979 auth->curve) < 0) {
3980 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
3981 goto fail;
3982 }
3983 if (conf->netaccesskey_expiry) {
3984 struct os_tm tm;
3985
3986 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
3987 wpa_printf(MSG_DEBUG,
3988 "DPP: Failed to generate expiry string");
3989 goto fail;
3990 }
3991 wpabuf_printf(dppcon,
3992 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3993 tm.year, tm.month, tm.day,
3994 tm.hour, tm.min, tm.sec);
3995 }
3996 wpabuf_put_u8(dppcon, '}');
3997 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
3998 (const char *) wpabuf_head(dppcon));
3999
4000 os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
4001 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
31f03cb0 4002 auth->conf->kid, curve->jws_alg);
461d39af
JM
4003 signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
4004 os_strlen(jws_prot_hdr),
4005 &signed1_len, 0);
4006 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
4007 wpabuf_len(dppcon),
4008 &signed2_len, 0);
4009 if (!signed1 || !signed2)
4010 goto fail;
4011
4012 md_ctx = EVP_MD_CTX_create();
4013 if (!md_ctx)
4014 goto fail;
4015
4016 ERR_clear_error();
4017 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
4018 auth->conf->csign) != 1) {
4019 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
4020 ERR_error_string(ERR_get_error(), NULL));
4021 goto fail;
4022 }
4023 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
4024 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
4025 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
4026 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
4027 ERR_error_string(ERR_get_error(), NULL));
4028 goto fail;
4029 }
4030 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
4031 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4032 ERR_error_string(ERR_get_error(), NULL));
4033 goto fail;
4034 }
4035 signature = os_malloc(signature_len);
4036 if (!signature)
4037 goto fail;
4038 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
4039 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4040 ERR_error_string(ERR_get_error(), NULL));
4041 goto fail;
4042 }
4043 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
4044 signature, signature_len);
4045 /* Convert to raw coordinates r,s */
4046 p = signature;
4047 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
4048 if (!sig)
4049 goto fail;
4050 ECDSA_SIG_get0(sig, &r, &s);
4051 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4052 dpp_bn2bin_pad(s, signature + curve->prime_len,
4053 curve->prime_len) < 0)
4054 goto fail;
4055 signature_len = 2 * curve->prime_len;
4056 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4057 signature, signature_len);
4058 signed3 = (char *) base64_url_encode(signature, signature_len,
4059 &signed3_len, 0);
4060 if (!signed3)
4061 goto fail;
4062
4063 tailroom = 1000;
4064 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4065 tailroom += signed1_len + signed2_len + signed3_len;
4066 buf = dpp_build_conf_start(auth, conf, tailroom);
4067 if (!buf)
4068 return NULL;
4069
4070 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
4071 wpabuf_put_str(buf, signed1);
4072 wpabuf_put_u8(buf, '.');
4073 wpabuf_put_str(buf, signed2);
4074 wpabuf_put_u8(buf, '.');
4075 wpabuf_put_str(buf, signed3);
4076 wpabuf_put_str(buf, "\",");
4077 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4078 curve) < 0) {
4079 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4080 goto fail;
4081 }
461d39af
JM
4082
4083 wpabuf_put_str(buf, "}}");
4084
4085 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4086 wpabuf_head(buf), wpabuf_len(buf));
4087
4088out:
4089 EVP_MD_CTX_destroy(md_ctx);
4090 ECDSA_SIG_free(sig);
4091 os_free(signed1);
4092 os_free(signed2);
4093 os_free(signed3);
4094 os_free(signature);
4095 wpabuf_free(dppcon);
4096 return buf;
4097fail:
4098 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4099 wpabuf_free(buf);
4100 buf = NULL;
4101 goto out;
4102}
4103
4104
4105static struct wpabuf *
4106dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
4107 struct dpp_configuration *conf)
4108{
4109 struct wpabuf *buf;
4110
4111 buf = dpp_build_conf_start(auth, conf, 1000);
4112 if (!buf)
4113 return NULL;
4114
4115 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"psk\",");
4116 if (conf->passphrase) {
4117 char pass[63 * 6 + 1];
4118
4119 if (os_strlen(conf->passphrase) > 63) {
4120 wpabuf_free(buf);
4121 return NULL;
4122 }
4123
4124 json_escape_string(pass, sizeof(pass), conf->passphrase,
4125 os_strlen(conf->passphrase));
4126 wpabuf_put_str(buf, "\"pass\":\"");
4127 wpabuf_put_str(buf, pass);
4128 wpabuf_put_str(buf, "\"");
4129 } else {
4130 char psk[2 * sizeof(conf->psk) + 1];
4131
4132 wpa_snprintf_hex(psk, sizeof(psk),
4133 conf->psk, sizeof(conf->psk));
4134 wpabuf_put_str(buf, "\"psk_hex\":\"");
4135 wpabuf_put_str(buf, psk);
4136 wpabuf_put_str(buf, "\"");
4137 }
4138 wpabuf_put_str(buf, "}}");
4139
4140 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4141 wpabuf_head(buf), wpabuf_len(buf));
4142
4143 return buf;
4144}
4145
4146
4147static struct wpabuf *
4148dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
4149{
4150 struct dpp_configuration *conf;
4151
4152#ifdef CONFIG_TESTING_OPTIONS
4153 if (auth->config_obj_override) {
4154 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
4155 return wpabuf_alloc_copy(auth->config_obj_override,
4156 os_strlen(auth->config_obj_override));
4157 }
4158#endif /* CONFIG_TESTING_OPTIONS */
4159
4160 conf = ap ? auth->conf_ap : auth->conf_sta;
4161 if (!conf) {
4162 wpa_printf(MSG_DEBUG,
4163 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4164 ap ? "ap" : "sta");
4165 return NULL;
4166 }
4167
4168 if (conf->dpp)
4169 return dpp_build_conf_obj_dpp(auth, ap, conf);
4170 return dpp_build_conf_obj_legacy(auth, ap, conf);
4171}
4172
4173
4174static struct wpabuf *
4175dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4176 u16 e_nonce_len, int ap)
4177{
4178 struct wpabuf *conf;
60239f60 4179 size_t clear_len, attr_len;
461d39af
JM
4180 struct wpabuf *clear = NULL, *msg = NULL;
4181 u8 *wrapped;
4182 const u8 *addr[1];
4183 size_t len[1];
4184 enum dpp_status_error status;
4185
4186 conf = dpp_build_conf_obj(auth, ap);
4187 if (conf) {
4188 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4189 wpabuf_head(conf), wpabuf_len(conf));
4190 }
4191 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
4192
4193 /* { E-nonce, configurationObject}ke */
4194 clear_len = 4 + e_nonce_len;
4195 if (conf)
4196 clear_len += 4 + wpabuf_len(conf);
4197 clear = wpabuf_alloc(clear_len);
60239f60
JM
4198 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
4199#ifdef CONFIG_TESTING_OPTIONS
4200 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
acdf703d 4201 attr_len += 5;
60239f60
JM
4202#endif /* CONFIG_TESTING_OPTIONS */
4203 msg = wpabuf_alloc(attr_len);
461d39af
JM
4204 if (!clear || !msg)
4205 goto fail;
4206
f411ad1b
JM
4207#ifdef CONFIG_TESTING_OPTIONS
4208 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
4209 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
4210 goto skip_e_nonce;
4211 }
af7f10fc
JM
4212 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
4213 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
4214 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4215 wpabuf_put_le16(clear, e_nonce_len);
4216 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
4217 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
4218 goto skip_e_nonce;
4219 }
f411ad1b
JM
4220 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
4221 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
4222 goto skip_wrapped_data;
4223 }
4224#endif /* CONFIG_TESTING_OPTIONS */
4225
461d39af
JM
4226 /* E-nonce */
4227 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4228 wpabuf_put_le16(clear, e_nonce_len);
4229 wpabuf_put_data(clear, e_nonce, e_nonce_len);
4230
f411ad1b
JM
4231#ifdef CONFIG_TESTING_OPTIONS
4232skip_e_nonce:
4233 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
4234 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
4235 goto skip_config_obj;
4236 }
4237#endif /* CONFIG_TESTING_OPTIONS */
4238
461d39af
JM
4239 if (conf) {
4240 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4241 wpabuf_put_le16(clear, wpabuf_len(conf));
4242 wpabuf_put_buf(clear, conf);
461d39af
JM
4243 }
4244
f411ad1b
JM
4245#ifdef CONFIG_TESTING_OPTIONS
4246skip_config_obj:
4247 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4248 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4249 goto skip_status;
4250 }
af7f10fc
JM
4251 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4252 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4253 status = 255;
4254 }
f411ad1b
JM
4255#endif /* CONFIG_TESTING_OPTIONS */
4256
461d39af 4257 /* DPP Status */
56f24d1d 4258 dpp_build_attr_status(msg, status);
461d39af 4259
f411ad1b
JM
4260#ifdef CONFIG_TESTING_OPTIONS
4261skip_status:
4262#endif /* CONFIG_TESTING_OPTIONS */
4263
461d39af
JM
4264 addr[0] = wpabuf_head(msg);
4265 len[0] = wpabuf_len(msg);
4266 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4267
4268 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
4269 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4270 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4271
4272 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
4273 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
4274 wpabuf_head(clear), wpabuf_len(clear),
4275 1, addr, len, wrapped) < 0)
4276 goto fail;
4277 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4278 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
461d39af 4279
60239f60
JM
4280#ifdef CONFIG_TESTING_OPTIONS
4281 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
4282 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 4283 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 4284 }
f411ad1b 4285skip_wrapped_data:
60239f60
JM
4286#endif /* CONFIG_TESTING_OPTIONS */
4287
461d39af
JM
4288 wpa_hexdump_buf(MSG_DEBUG,
4289 "DPP: Configuration Response attributes", msg);
f411ad1b 4290out:
461d39af
JM
4291 wpabuf_free(conf);
4292 wpabuf_free(clear);
f411ad1b
JM
4293
4294 return msg;
4295fail:
461d39af 4296 wpabuf_free(msg);
f411ad1b
JM
4297 msg = NULL;
4298 goto out;
461d39af
JM
4299}
4300
4301
4302struct wpabuf *
4303dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4304 size_t attr_len)
4305{
4306 const u8 *wrapped_data, *e_nonce, *config_attr;
4307 u16 wrapped_data_len, e_nonce_len, config_attr_len;
4308 u8 *unwrapped = NULL;
4309 size_t unwrapped_len = 0;
4310 struct wpabuf *resp = NULL;
4311 struct json_token *root = NULL, *token;
4312 int ap;
4313
4314 if (dpp_check_attrs(attr_start, attr_len) < 0) {
8c99e626 4315 dpp_auth_fail(auth, "Invalid attribute in config request");
461d39af
JM
4316 return NULL;
4317 }
4318
4319 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4320 &wrapped_data_len);
4321 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
8c99e626
JM
4322 dpp_auth_fail(auth,
4323 "Missing or invalid required Wrapped Data attribute");
461d39af
JM
4324 return NULL;
4325 }
4326
4327 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4328 wrapped_data, wrapped_data_len);
4329 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4330 unwrapped = os_malloc(unwrapped_len);
4331 if (!unwrapped)
4332 return NULL;
4333 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4334 wrapped_data, wrapped_data_len,
4335 0, NULL, NULL, unwrapped) < 0) {
8c99e626 4336 dpp_auth_fail(auth, "AES-SIV decryption failed");
461d39af
JM
4337 goto fail;
4338 }
4339 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4340 unwrapped, unwrapped_len);
4341
4342 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8c99e626 4343 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
461d39af
JM
4344 goto fail;
4345 }
4346
4347 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4348 DPP_ATTR_ENROLLEE_NONCE,
4349 &e_nonce_len);
4350 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8c99e626
JM
4351 dpp_auth_fail(auth,
4352 "Missing or invalid Enrollee Nonce attribute");
461d39af
JM
4353 goto fail;
4354 }
4355 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4356
4357 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
4358 DPP_ATTR_CONFIG_ATTR_OBJ,
4359 &config_attr_len);
4360 if (!config_attr) {
8c99e626
JM
4361 dpp_auth_fail(auth,
4362 "Missing or invalid Config Attributes attribute");
461d39af
JM
4363 goto fail;
4364 }
4365 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
4366 config_attr, config_attr_len);
4367
4368 root = json_parse((const char *) config_attr, config_attr_len);
4369 if (!root) {
8c99e626 4370 dpp_auth_fail(auth, "Could not parse Config Attributes");
461d39af
JM
4371 goto fail;
4372 }
4373
4374 token = json_get_member(root, "name");
4375 if (!token || token->type != JSON_STRING) {
8c99e626 4376 dpp_auth_fail(auth, "No Config Attributes - name");
461d39af
JM
4377 goto fail;
4378 }
4379 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
4380
4381 token = json_get_member(root, "wi-fi_tech");
4382 if (!token || token->type != JSON_STRING) {
8c99e626 4383 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
461d39af
JM
4384 goto fail;
4385 }
4386 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
4387 if (os_strcmp(token->string, "infra") != 0) {
4388 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
4389 token->string);
8c99e626 4390 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
461d39af
JM
4391 goto fail;
4392 }
4393
4394 token = json_get_member(root, "netRole");
4395 if (!token || token->type != JSON_STRING) {
8c99e626 4396 dpp_auth_fail(auth, "No Config Attributes - netRole");
461d39af
JM
4397 goto fail;
4398 }
4399 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
4400 if (os_strcmp(token->string, "sta") == 0) {
4401 ap = 0;
4402 } else if (os_strcmp(token->string, "ap") == 0) {
4403 ap = 1;
4404 } else {
4405 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
4406 token->string);
8c99e626 4407 dpp_auth_fail(auth, "Unsupported netRole");
461d39af
JM
4408 goto fail;
4409 }
4410
4411 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
4412
4413fail:
4414 json_free(root);
4415 os_free(unwrapped);
4416 return resp;
4417}
4418
4419
4420static struct wpabuf *
6095b479
JM
4421dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
4422 const u8 *prot_hdr, u16 prot_hdr_len,
461d39af
JM
4423 const EVP_MD **ret_md)
4424{
4425 struct json_token *root, *token;
4426 struct wpabuf *kid = NULL;
4427
4428 root = json_parse((const char *) prot_hdr, prot_hdr_len);
4429 if (!root) {
4430 wpa_printf(MSG_DEBUG,
4431 "DPP: JSON parsing failed for JWS Protected Header");
4432 goto fail;
4433 }
4434
4435 if (root->type != JSON_OBJECT) {
4436 wpa_printf(MSG_DEBUG,
4437 "DPP: JWS Protected Header root is not an object");
4438 goto fail;
4439 }
4440
4441 token = json_get_member(root, "typ");
4442 if (!token || token->type != JSON_STRING) {
4443 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
4444 goto fail;
4445 }
4446 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
4447 token->string);
4448 if (os_strcmp(token->string, "dppCon") != 0) {
4449 wpa_printf(MSG_DEBUG,
4450 "DPP: Unsupported JWS Protected Header typ=%s",
4451 token->string);
4452 goto fail;
4453 }
4454
4455 token = json_get_member(root, "alg");
4456 if (!token || token->type != JSON_STRING) {
4457 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
4458 goto fail;
4459 }
4460 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
4461 token->string);
6095b479
JM
4462 if (os_strcmp(token->string, curve->jws_alg) != 0) {
4463 wpa_printf(MSG_DEBUG,
4464 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4465 token->string, curve->jws_alg);
4466 goto fail;
4467 }
31f03cb0
JM
4468 if (os_strcmp(token->string, "ES256") == 0 ||
4469 os_strcmp(token->string, "BS256") == 0)
461d39af 4470 *ret_md = EVP_sha256();
31f03cb0
JM
4471 else if (os_strcmp(token->string, "ES384") == 0 ||
4472 os_strcmp(token->string, "BS384") == 0)
461d39af 4473 *ret_md = EVP_sha384();
31f03cb0
JM
4474 else if (os_strcmp(token->string, "ES512") == 0 ||
4475 os_strcmp(token->string, "BS512") == 0)
461d39af
JM
4476 *ret_md = EVP_sha512();
4477 else
4478 *ret_md = NULL;
4479 if (!*ret_md) {
4480 wpa_printf(MSG_DEBUG,
4481 "DPP: Unsupported JWS Protected Header alg=%s",
4482 token->string);
4483 goto fail;
4484 }
4485
4486 kid = json_get_member_base64url(root, "kid");
4487 if (!kid) {
4488 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
4489 goto fail;
4490 }
4491 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
4492 kid);
4493
4494fail:
4495 json_free(root);
4496 return kid;
4497}
4498
4499
4500static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
4501 struct json_token *cred)
4502{
4503 struct json_token *pass, *psk_hex;
461d39af
JM
4504
4505 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
4506
4507 pass = json_get_member(cred, "pass");
4508 psk_hex = json_get_member(cred, "psk_hex");
4509
4510 if (pass && pass->type == JSON_STRING) {
8528994e
JM
4511 size_t len = os_strlen(pass->string);
4512
461d39af 4513 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
8528994e
JM
4514 pass->string, len);
4515 if (len < 8 || len > 63)
4516 return -1;
4517 os_strlcpy(auth->passphrase, pass->string,
4518 sizeof(auth->passphrase));
461d39af 4519 } else if (psk_hex && psk_hex->type == JSON_STRING) {
8528994e
JM
4520 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
4521 hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
461d39af
JM
4522 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
4523 return -1;
4524 }
8528994e
JM
4525 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
4526 auth->psk, PMK_LEN);
4527 auth->psk_set = 1;
461d39af
JM
4528 } else {
4529 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
4530 return -1;
4531 }
4532
4533 return 0;
4534}
4535
4536
4537static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
4538 const struct dpp_curve_params **key_curve)
4539{
4540 struct json_token *token;
4541 const struct dpp_curve_params *curve;
4542 struct wpabuf *x = NULL, *y = NULL;
4543 EC_GROUP *group;
4544 EVP_PKEY *pkey = NULL;
4545
4546 token = json_get_member(jwk, "kty");
4547 if (!token || token->type != JSON_STRING) {
4548 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
4549 goto fail;
4550 }
4551 if (os_strcmp(token->string, "EC") != 0) {
4552 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s",
4553 token->string);
4554 goto fail;
4555 }
4556
4557 token = json_get_member(jwk, "crv");
4558 if (!token || token->type != JSON_STRING) {
4559 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
4560 goto fail;
4561 }
4562 curve = dpp_get_curve_jwk_crv(token->string);
4563 if (!curve) {
4564 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
4565 token->string);
4566 goto fail;
4567 }
4568
4569 x = json_get_member_base64url(jwk, "x");
4570 if (!x) {
4571 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
4572 goto fail;
4573 }
f1f4fa79 4574 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
461d39af
JM
4575 if (wpabuf_len(x) != curve->prime_len) {
4576 wpa_printf(MSG_DEBUG,
f1f4fa79 4577 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
461d39af
JM
4578 (unsigned int) wpabuf_len(x),
4579 (unsigned int) curve->prime_len, curve->name);
4580 goto fail;
4581 }
4582
4583 y = json_get_member_base64url(jwk, "y");
4584 if (!y) {
4585 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
4586 goto fail;
4587 }
f1f4fa79 4588 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
461d39af
JM
4589 if (wpabuf_len(y) != curve->prime_len) {
4590 wpa_printf(MSG_DEBUG,
f1f4fa79 4591 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
461d39af
JM
4592 (unsigned int) wpabuf_len(y),
4593 (unsigned int) curve->prime_len, curve->name);
4594 goto fail;
4595 }
4596
4597 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
4598 if (!group) {
4599 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
4600 goto fail;
4601 }
4602
4603 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
4604 wpabuf_len(x));
4605 *key_curve = curve;
4606
4607fail:
4608 wpabuf_free(x);
4609 wpabuf_free(y);
4610
4611 return pkey;
4612}
4613
4614
4615int dpp_key_expired(const char *timestamp, os_time_t *expiry)
4616{
4617 struct os_time now;
4618 unsigned int year, month, day, hour, min, sec;
4619 os_time_t utime;
4620 const char *pos;
4621
4622 /* ISO 8601 date and time:
4623 * <date>T<time>
4624 * YYYY-MM-DDTHH:MM:SSZ
4625 * YYYY-MM-DDTHH:MM:SS+03:00
4626 */
4627 if (os_strlen(timestamp) < 19) {
4628 wpa_printf(MSG_DEBUG,
4629 "DPP: Too short timestamp - assume expired key");
4630 return 1;
4631 }
4632 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
4633 &year, &month, &day, &hour, &min, &sec) != 6) {
4634 wpa_printf(MSG_DEBUG,
4635 "DPP: Failed to parse expiration day - assume expired key");
4636 return 1;
4637 }
4638
4639 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
4640 wpa_printf(MSG_DEBUG,
4641 "DPP: Invalid date/time information - assume expired key");
4642 return 1;
4643 }
4644
4645 pos = timestamp + 19;
4646 if (*pos == 'Z' || *pos == '\0') {
4647 /* In UTC - no need to adjust */
4648 } else if (*pos == '-' || *pos == '+') {
4649 int items;
4650
4651 /* Adjust local time to UTC */
4652 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
4653 if (items < 1) {
4654 wpa_printf(MSG_DEBUG,
4655 "DPP: Invalid time zone designator (%s) - assume expired key",
4656 pos);
4657 return 1;
4658 }
4659 if (*pos == '-')
4660 utime += 3600 * hour;
4661 if (*pos == '+')
4662 utime -= 3600 * hour;
4663 if (items > 1) {
4664 if (*pos == '-')
4665 utime += 60 * min;
4666 if (*pos == '+')
4667 utime -= 60 * min;
4668 }
4669 } else {
4670 wpa_printf(MSG_DEBUG,
4671 "DPP: Invalid time zone designator (%s) - assume expired key",
4672 pos);
4673 return 1;
4674 }
4675 if (expiry)
4676 *expiry = utime;
4677
4678 if (os_get_time(&now) < 0) {
4679 wpa_printf(MSG_DEBUG,
4680 "DPP: Cannot get current time - assume expired key");
4681 return 1;
4682 }
4683
4684 if (now.sec > utime) {
4685 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
4686 utime, now.sec);
4687 return 1;
4688 }
4689
4690 return 0;
4691}
4692
4693
4694static int dpp_parse_connector(struct dpp_authentication *auth,
4695 const unsigned char *payload,
4696 u16 payload_len)
4697{
a4bf0078 4698 struct json_token *root, *groups, *netkey, *token;
461d39af
JM
4699 int ret = -1;
4700 EVP_PKEY *key = NULL;
4701 const struct dpp_curve_params *curve;
4702 unsigned int rules = 0;
4703
4704 root = json_parse((const char *) payload, payload_len);
4705 if (!root) {
4706 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4707 goto fail;
4708 }
4709
4710 groups = json_get_member(root, "groups");
4711 if (!groups || groups->type != JSON_ARRAY) {
4712 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
4713 goto skip_groups;
4714 }
4715 for (token = groups->child; token; token = token->sibling) {
4716 struct json_token *id, *role;
4717
4718 id = json_get_member(token, "groupId");
4719 if (!id || id->type != JSON_STRING) {
4720 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
4721 goto fail;
4722 }
4723
4724 role = json_get_member(token, "netRole");
4725 if (!role || role->type != JSON_STRING) {
4726 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
4727 goto fail;
4728 }
4729 wpa_printf(MSG_DEBUG,
4730 "DPP: connector group: groupId='%s' netRole='%s'",
4731 id->string, role->string);
4732 rules++;
4733 }
4734skip_groups:
4735
461d39af
JM
4736 if (!rules) {
4737 wpa_printf(MSG_DEBUG,
a4bf0078 4738 "DPP: Connector includes no groups");
461d39af
JM
4739 goto fail;
4740 }
4741
4742 token = json_get_member(root, "expiry");
4743 if (!token || token->type != JSON_STRING) {
4744 wpa_printf(MSG_DEBUG,
4745 "DPP: No expiry string found - connector does not expire");
4746 } else {
4747 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4748 if (dpp_key_expired(token->string,
4749 &auth->net_access_key_expiry)) {
4750 wpa_printf(MSG_DEBUG,
4751 "DPP: Connector (netAccessKey) has expired");
4752 goto fail;
4753 }
4754 }
4755
4756 netkey = json_get_member(root, "netAccessKey");
4757 if (!netkey || netkey->type != JSON_OBJECT) {
4758 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4759 goto fail;
4760 }
4761
4762 key = dpp_parse_jwk(netkey, &curve);
4763 if (!key)
4764 goto fail;
4765 dpp_debug_print_key("DPP: Received netAccessKey", key);
4766
4767 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
4768 wpa_printf(MSG_DEBUG,
4769 "DPP: netAccessKey in connector does not match own protocol key");
4770#ifdef CONFIG_TESTING_OPTIONS
4771 if (auth->ignore_netaccesskey_mismatch) {
4772 wpa_printf(MSG_DEBUG,
4773 "DPP: TESTING - skip netAccessKey mismatch");
4774 } else {
4775 goto fail;
4776 }
4777#else /* CONFIG_TESTING_OPTIONS */
4778 goto fail;
4779#endif /* CONFIG_TESTING_OPTIONS */
4780 }
4781
4782 ret = 0;
4783fail:
4784 EVP_PKEY_free(key);
4785 json_free(root);
4786 return ret;
4787}
4788
4789
4790static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
4791{
4792 struct wpabuf *uncomp;
4793 int res;
4794 u8 hash[SHA256_MAC_LEN];
4795 const u8 *addr[1];
4796 size_t len[1];
4797
4798 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
4799 return -1;
4800 uncomp = dpp_get_pubkey_point(pub, 1);
4801 if (!uncomp)
4802 return -1;
4803 addr[0] = wpabuf_head(uncomp);
4804 len[0] = wpabuf_len(uncomp);
4805 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
4806 addr[0], len[0]);
4807 res = sha256_vector(1, addr, len, hash);
4808 wpabuf_free(uncomp);
4809 if (res < 0)
4810 return -1;
4811 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
4812 wpa_printf(MSG_DEBUG,
4813 "DPP: Received hash value does not match calculated public key hash value");
4814 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
4815 hash, SHA256_MAC_LEN);
4816 return -1;
4817 }
4818 return 0;
4819}
4820
4821
4822static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
4823{
4824 unsigned char *der = NULL;
4825 int der_len;
4826
4827 der_len = i2d_PUBKEY(csign, &der);
4828 if (der_len <= 0)
4829 return;
4830 wpabuf_free(auth->c_sign_key);
4831 auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
4832 OPENSSL_free(der);
4833}
4834
4835
4836static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
4837{
4838 unsigned char *der = NULL;
4839 int der_len;
4840 EC_KEY *eckey;
4841
4842 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
4843 if (!eckey)
4844 return;
4845
4846 der_len = i2d_ECPrivateKey(eckey, &der);
4847 if (der_len <= 0) {
4848 EC_KEY_free(eckey);
4849 return;
4850 }
4851 wpabuf_free(auth->net_access_key);
4852 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
4853 OPENSSL_free(der);
4854 EC_KEY_free(eckey);
4855}
4856
4857
4858struct dpp_signed_connector_info {
4859 unsigned char *payload;
4860 size_t payload_len;
4861};
4862
e85b6601 4863static enum dpp_status_error
461d39af
JM
4864dpp_process_signed_connector(struct dpp_signed_connector_info *info,
4865 EVP_PKEY *csign_pub, const char *connector)
4866{
e85b6601 4867 enum dpp_status_error ret = 255;
461d39af
JM
4868 const char *pos, *end, *signed_start, *signed_end;
4869 struct wpabuf *kid = NULL;
4870 unsigned char *prot_hdr = NULL, *signature = NULL;
4871 size_t prot_hdr_len = 0, signature_len = 0;
4872 const EVP_MD *sign_md = NULL;
4873 unsigned char *der = NULL;
4874 int der_len;
4875 int res;
4876 EVP_MD_CTX *md_ctx = NULL;
4877 ECDSA_SIG *sig = NULL;
4878 BIGNUM *r = NULL, *s = NULL;
6095b479
JM
4879 const struct dpp_curve_params *curve;
4880 EC_KEY *eckey;
4881 const EC_GROUP *group;
4882 int nid;
461d39af 4883
6095b479
JM
4884 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
4885 if (!eckey)
4886 goto fail;
4887 group = EC_KEY_get0_group(eckey);
4888 if (!group)
4889 goto fail;
4890 nid = EC_GROUP_get_curve_name(group);
4891 curve = dpp_get_curve_nid(nid);
4892 if (!curve)
4893 goto fail;
4894 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
461d39af
JM
4895 os_memset(info, 0, sizeof(*info));
4896
4897 signed_start = pos = connector;
4898 end = os_strchr(pos, '.');
4899 if (!end) {
4900 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
e85b6601 4901 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4902 goto fail;
4903 }
4904 prot_hdr = base64_url_decode((const unsigned char *) pos,
4905 end - pos, &prot_hdr_len);
4906 if (!prot_hdr) {
4907 wpa_printf(MSG_DEBUG,
4908 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
e85b6601 4909 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4910 goto fail;
4911 }
4912 wpa_hexdump_ascii(MSG_DEBUG,
4913 "DPP: signedConnector - JWS Protected Header",
4914 prot_hdr, prot_hdr_len);
6095b479 4915 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
e85b6601
JM
4916 if (!kid) {
4917 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af 4918 goto fail;
e85b6601 4919 }
461d39af
JM
4920 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
4921 wpa_printf(MSG_DEBUG,
4922 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
4923 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
e85b6601 4924 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4925 goto fail;
4926 }
4927
4928 pos = end + 1;
4929 end = os_strchr(pos, '.');
4930 if (!end) {
4931 wpa_printf(MSG_DEBUG,
4932 "DPP: Missing dot(2) in signedConnector");
e85b6601 4933 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4934 goto fail;
4935 }
4936 signed_end = end - 1;
4937 info->payload = base64_url_decode((const unsigned char *) pos,
4938 end - pos, &info->payload_len);
4939 if (!info->payload) {
4940 wpa_printf(MSG_DEBUG,
4941 "DPP: Failed to base64url decode signedConnector JWS Payload");
e85b6601 4942 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4943 goto fail;
4944 }
4945 wpa_hexdump_ascii(MSG_DEBUG,
4946 "DPP: signedConnector - JWS Payload",
4947 info->payload, info->payload_len);
4948 pos = end + 1;
4949 signature = base64_url_decode((const unsigned char *) pos,
4950 os_strlen(pos), &signature_len);
4951 if (!signature) {
4952 wpa_printf(MSG_DEBUG,
4953 "DPP: Failed to base64url decode signedConnector signature");
e85b6601 4954 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4955 goto fail;
4956 }
4957 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
4958 signature, signature_len);
4959
e85b6601
JM
4960 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
4961 ret = DPP_STATUS_NO_MATCH;
461d39af 4962 goto fail;
e85b6601 4963 }
461d39af
JM
4964
4965 if (signature_len & 0x01) {
4966 wpa_printf(MSG_DEBUG,
4967 "DPP: Unexpected signedConnector signature length (%d)",
4968 (int) signature_len);
e85b6601 4969 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4970 goto fail;
4971 }
4972
4973 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
4974 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
4975 r = BN_bin2bn(signature, signature_len / 2, NULL);
4976 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
4977 sig = ECDSA_SIG_new();
4978 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
4979 goto fail;
4980 r = NULL;
4981 s = NULL;
4982
4983 der_len = i2d_ECDSA_SIG(sig, &der);
4984 if (der_len <= 0) {
4985 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
4986 goto fail;
4987 }
4988 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
4989 md_ctx = EVP_MD_CTX_create();
4990 if (!md_ctx)
4991 goto fail;
4992
4993 ERR_clear_error();
4994 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
4995 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
4996 ERR_error_string(ERR_get_error(), NULL));
4997 goto fail;
4998 }
4999 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
5000 signed_end - signed_start + 1) != 1) {
5001 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
5002 ERR_error_string(ERR_get_error(), NULL));
5003 goto fail;
5004 }
5005 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
5006 if (res != 1) {
5007 wpa_printf(MSG_DEBUG,
5008 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5009 res, ERR_error_string(ERR_get_error(), NULL));
e85b6601 5010 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5011 goto fail;
5012 }
5013
e85b6601 5014 ret = DPP_STATUS_OK;
461d39af 5015fail:
6095b479 5016 EC_KEY_free(eckey);
461d39af
JM
5017 EVP_MD_CTX_destroy(md_ctx);
5018 os_free(prot_hdr);
5019 wpabuf_free(kid);
5020 os_free(signature);
5021 ECDSA_SIG_free(sig);
5022 BN_free(r);
5023 BN_free(s);
5024 OPENSSL_free(der);
5025 return ret;
5026}
5027
5028
5029static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5030 struct json_token *cred)
5031{
5032 struct dpp_signed_connector_info info;
5033 struct json_token *token, *csign;
5034 int ret = -1;
5035 EVP_PKEY *csign_pub = NULL;
5036 const struct dpp_curve_params *key_curve = NULL;
5037 const char *signed_connector;
5038
5039 os_memset(&info, 0, sizeof(info));
5040
5041 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5042
5043 csign = json_get_member(cred, "csign");
5044 if (!csign || csign->type != JSON_OBJECT) {
5045 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5046 goto fail;
5047 }
5048
5049 csign_pub = dpp_parse_jwk(csign, &key_curve);
5050 if (!csign_pub) {
5051 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5052 goto fail;
5053 }
5054 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5055
461d39af
JM
5056 token = json_get_member(cred, "signedConnector");
5057 if (!token || token->type != JSON_STRING) {
5058 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5059 goto fail;
5060 }
5061 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5062 token->string, os_strlen(token->string));
5063 signed_connector = token->string;
5064
5065 if (os_strchr(signed_connector, '"') ||
5066 os_strchr(signed_connector, '\n')) {
5067 wpa_printf(MSG_DEBUG,
5068 "DPP: Unexpected character in signedConnector");
5069 goto fail;
5070 }
5071
5072 if (dpp_process_signed_connector(&info, csign_pub,
e85b6601 5073 signed_connector) != DPP_STATUS_OK)
461d39af
JM
5074 goto fail;
5075
5076 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
5077 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5078 goto fail;
5079 }
5080
5081 os_free(auth->connector);
5082 auth->connector = os_strdup(signed_connector);
5083
5084 dpp_copy_csign(auth, csign_pub);
5085 dpp_copy_netaccesskey(auth);
5086
5087 ret = 0;
5088fail:
5089 EVP_PKEY_free(csign_pub);
5090 os_free(info.payload);
5091 return ret;
5092}
5093
5094
5095static int dpp_parse_conf_obj(struct dpp_authentication *auth,
5096 const u8 *conf_obj, u16 conf_obj_len)
5097{
5098 int ret = -1;
5099 struct json_token *root, *token, *discovery, *cred;
5100
5101 root = json_parse((const char *) conf_obj, conf_obj_len);
5102 if (!root)
5103 return -1;
5104 if (root->type != JSON_OBJECT) {
8c99e626 5105 dpp_auth_fail(auth, "JSON root is not an object");
461d39af
JM
5106 goto fail;
5107 }
5108
5109 token = json_get_member(root, "wi-fi_tech");
5110 if (!token || token->type != JSON_STRING) {
8c99e626 5111 dpp_auth_fail(auth, "No wi-fi_tech string value found");
461d39af
JM
5112 goto fail;
5113 }
5114 if (os_strcmp(token->string, "infra") != 0) {
5115 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5116 token->string);
8c99e626 5117 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
461d39af
JM
5118 goto fail;
5119 }
5120
5121 discovery = json_get_member(root, "discovery");
5122 if (!discovery || discovery->type != JSON_OBJECT) {
8c99e626 5123 dpp_auth_fail(auth, "No discovery object in JSON");
461d39af
JM
5124 goto fail;
5125 }
5126
5127 token = json_get_member(discovery, "ssid");
5128 if (!token || token->type != JSON_STRING) {
8c99e626 5129 dpp_auth_fail(auth, "No discovery::ssid string value found");
461d39af
JM
5130 goto fail;
5131 }
5132 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
5133 token->string, os_strlen(token->string));
5134 if (os_strlen(token->string) > SSID_MAX_LEN) {
8c99e626 5135 dpp_auth_fail(auth, "Too long discovery::ssid string value");
461d39af
JM
5136 goto fail;
5137 }
5138 auth->ssid_len = os_strlen(token->string);
5139 os_memcpy(auth->ssid, token->string, auth->ssid_len);
5140
5141 cred = json_get_member(root, "cred");
5142 if (!cred || cred->type != JSON_OBJECT) {
8c99e626 5143 dpp_auth_fail(auth, "No cred object in JSON");
461d39af
JM
5144 goto fail;
5145 }
5146
5147 token = json_get_member(cred, "akm");
5148 if (!token || token->type != JSON_STRING) {
8c99e626 5149 dpp_auth_fail(auth, "No cred::akm string value found");
461d39af
JM
5150 goto fail;
5151 }
5152 if (os_strcmp(token->string, "psk") == 0) {
5153 if (dpp_parse_cred_legacy(auth, cred) < 0)
5154 goto fail;
5155 } else if (os_strcmp(token->string, "dpp") == 0) {
5156 if (dpp_parse_cred_dpp(auth, cred) < 0)
5157 goto fail;
5158 } else {
5159 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5160 token->string);
8c99e626 5161 dpp_auth_fail(auth, "Unsupported akm");
461d39af
JM
5162 goto fail;
5163 }
5164
5165 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5166 ret = 0;
5167fail:
5168 json_free(root);
5169 return ret;
5170}
5171
5172
5173int dpp_conf_resp_rx(struct dpp_authentication *auth,
5174 const struct wpabuf *resp)
5175{
5176 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5177 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5178 const u8 *addr[1];
5179 size_t len[1];
5180 u8 *unwrapped = NULL;
5181 size_t unwrapped_len = 0;
5182 int ret = -1;
5183
5184 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
8c99e626 5185 dpp_auth_fail(auth, "Invalid attribute in config response");
461d39af
JM
5186 return -1;
5187 }
5188
5189 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5190 DPP_ATTR_WRAPPED_DATA,
5191 &wrapped_data_len);
5192 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
8c99e626
JM
5193 dpp_auth_fail(auth,
5194 "Missing or invalid required Wrapped Data attribute");
461d39af
JM
5195 return -1;
5196 }
5197
5198 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5199 wrapped_data, wrapped_data_len);
5200 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5201 unwrapped = os_malloc(unwrapped_len);
5202 if (!unwrapped)
5203 return -1;
5204
5205 addr[0] = wpabuf_head(resp);
5206 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
5207 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5208
5209 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5210 wrapped_data, wrapped_data_len,
5211 1, addr, len, unwrapped) < 0) {
8c99e626 5212 dpp_auth_fail(auth, "AES-SIV decryption failed");
461d39af
JM
5213 goto fail;
5214 }
5215 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5216 unwrapped, unwrapped_len);
5217
5218 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8c99e626 5219 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
461d39af
JM
5220 goto fail;
5221 }
5222
5223 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5224 DPP_ATTR_ENROLLEE_NONCE,
5225 &e_nonce_len);
5226 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8c99e626
JM
5227 dpp_auth_fail(auth,
5228 "Missing or invalid Enrollee Nonce attribute");
461d39af
JM
5229 goto fail;
5230 }
5231 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5232 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
8c99e626 5233 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
461d39af
JM
5234 goto fail;
5235 }
5236
5237 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5238 DPP_ATTR_STATUS, &status_len);
5239 if (!status || status_len < 1) {
8c99e626
JM
5240 dpp_auth_fail(auth,
5241 "Missing or invalid required DPP Status attribute");
461d39af
JM
5242 goto fail;
5243 }
5244 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5245 if (status[0] != DPP_STATUS_OK) {
8c99e626 5246 dpp_auth_fail(auth, "Configurator rejected configuration");
461d39af
JM
5247 goto fail;
5248 }
5249
5250 conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
5251 DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
5252 if (!conf_obj) {
8c99e626
JM
5253 dpp_auth_fail(auth,
5254 "Missing required Configuration Object attribute");
461d39af
JM
5255 goto fail;
5256 }
5257 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
5258 conf_obj, conf_obj_len);
5259 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
5260 goto fail;
5261
5262 ret = 0;
5263
5264fail:
5265 os_free(unwrapped);
5266 return ret;
5267}
5268
5269
5270void dpp_configurator_free(struct dpp_configurator *conf)
5271{
5272 if (!conf)
5273 return;
5274 EVP_PKEY_free(conf->csign);
5275 os_free(conf->kid);
5276 os_free(conf);
5277}
5278
5279
5280struct dpp_configurator *
5281dpp_keygen_configurator(const char *curve, const u8 *privkey,
5282 size_t privkey_len)
5283{
5284 struct dpp_configurator *conf;
5285 struct wpabuf *csign_pub = NULL;
5286 u8 kid_hash[SHA256_MAC_LEN];
5287 const u8 *addr[1];
5288 size_t len[1];
5289
5290 conf = os_zalloc(sizeof(*conf));
5291 if (!conf)
5292 return NULL;
5293
5294 if (!curve) {
5295 conf->curve = &dpp_curves[0];
5296 } else {
5297 conf->curve = dpp_get_curve_name(curve);
5298 if (!conf->curve) {
5299 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5300 curve);
5301 return NULL;
5302 }
5303 }
5304 if (privkey)
5305 conf->csign = dpp_set_keypair(&conf->curve, privkey,
5306 privkey_len);
5307 else
5308 conf->csign = dpp_gen_keypair(conf->curve);
5309 if (!conf->csign)
5310 goto fail;
5311 conf->own = 1;
5312
5313 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
5314 if (!csign_pub) {
5315 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
5316 goto fail;
5317 }
5318
5319 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5320 addr[0] = wpabuf_head(csign_pub);
5321 len[0] = wpabuf_len(csign_pub);
5322 if (sha256_vector(1, addr, len, kid_hash) < 0) {
5323 wpa_printf(MSG_DEBUG,
5324 "DPP: Failed to derive kid for C-sign-key");
5325 goto fail;
5326 }
5327
5328 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
5329 NULL, 0);
5330 if (!conf->kid)
5331 goto fail;
5332out:
5333 wpabuf_free(csign_pub);
5334 return conf;
5335fail:
5336 dpp_configurator_free(conf);
5337 conf = NULL;
5338 goto out;
5339}
650a70a7
JM
5340
5341
f522bb23
JM
5342int dpp_configurator_own_config(struct dpp_authentication *auth,
5343 const char *curve)
5344{
5345 struct wpabuf *conf_obj;
5346 int ret = -1;
5347
5348 if (!auth->conf) {
5349 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
5350 return -1;
5351 }
5352
5353 if (!curve) {
5354 auth->curve = &dpp_curves[0];
5355 } else {
5356 auth->curve = dpp_get_curve_name(curve);
5357 if (!auth->curve) {
5358 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5359 curve);
5360 return -1;
5361 }
5362 }
5363 wpa_printf(MSG_DEBUG,
5364 "DPP: Building own configuration/connector with curve %s",
5365 auth->curve->name);
5366
5367 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
5368 if (!auth->own_protocol_key)
5369 return -1;
5370 dpp_copy_netaccesskey(auth);
5371 auth->peer_protocol_key = auth->own_protocol_key;
5372 dpp_copy_csign(auth, auth->conf->csign);
5373
5374 conf_obj = dpp_build_conf_obj(auth, 0);
5375 if (!conf_obj)
5376 goto fail;
5377 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
5378 wpabuf_len(conf_obj));
5379fail:
5380 wpabuf_free(conf_obj);
5381 auth->peer_protocol_key = NULL;
5382 return ret;
5383}
5384
5385
650a70a7
JM
5386static int dpp_compatible_netrole(const char *role1, const char *role2)
5387{
5388 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
5389 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
5390}
5391
5392
5393static int dpp_connector_compatible_group(struct json_token *root,
5394 const char *group_id,
5395 const char *net_role)
5396{
5397 struct json_token *groups, *token;
5398
5399 groups = json_get_member(root, "groups");
5400 if (!groups || groups->type != JSON_ARRAY)
5401 return 0;
5402
5403 for (token = groups->child; token; token = token->sibling) {
5404 struct json_token *id, *role;
5405
5406 id = json_get_member(token, "groupId");
5407 if (!id || id->type != JSON_STRING)
5408 continue;
5409
5410 role = json_get_member(token, "netRole");
5411 if (!role || role->type != JSON_STRING)
5412 continue;
5413
5414 if (os_strcmp(id->string, "*") != 0 &&
5415 os_strcmp(group_id, "*") != 0 &&
5416 os_strcmp(id->string, group_id) != 0)
5417 continue;
5418
5419 if (dpp_compatible_netrole(role->string, net_role))
5420 return 1;
5421 }
5422
5423 return 0;
5424}
5425
5426
5427static int dpp_connector_match_groups(struct json_token *own_root,
5428 struct json_token *peer_root)
5429{
5430 struct json_token *groups, *token;
5431
5432 groups = json_get_member(peer_root, "groups");
5433 if (!groups || groups->type != JSON_ARRAY) {
5434 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
5435 return 0;
5436 }
5437
5438 for (token = groups->child; token; token = token->sibling) {
5439 struct json_token *id, *role;
5440
5441 id = json_get_member(token, "groupId");
5442 if (!id || id->type != JSON_STRING) {
5443 wpa_printf(MSG_DEBUG,
5444 "DPP: Missing peer groupId string");
5445 continue;
5446 }
5447
5448 role = json_get_member(token, "netRole");
5449 if (!role || role->type != JSON_STRING) {
5450 wpa_printf(MSG_DEBUG,
5451 "DPP: Missing peer groups::netRole string");
5452 continue;
5453 }
5454 wpa_printf(MSG_DEBUG,
5455 "DPP: peer connector group: groupId='%s' netRole='%s'",
5456 id->string, role->string);
5457 if (dpp_connector_compatible_group(own_root, id->string,
5458 role->string)) {
5459 wpa_printf(MSG_DEBUG,
5460 "DPP: Compatible group/netRole in own connector");
5461 return 1;
5462 }
5463 }
5464
5465 return 0;
5466}
5467
5468
650a70a7
JM
5469static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
5470 unsigned int hash_len)
5471{
5472 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5473 const char *info = "DPP PMK";
b9d47b48 5474 int res;
650a70a7
JM
5475
5476 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5477
5478 /* HKDF-Extract(<>, N.x) */
5479 os_memset(salt, 0, hash_len);
b9d47b48 5480 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
650a70a7 5481 return -1;
650a70a7
JM
5482 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5483 prk, hash_len);
5484
5485 /* HKDF-Expand(PRK, info, L) */
b9d47b48 5486 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
650a70a7
JM
5487 os_memset(prk, 0, hash_len);
5488 if (res < 0)
5489 return -1;
5490
5491 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5492 pmk, hash_len);
5493 return 0;
5494}
5495
5496
5497static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
5498 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
5499{
5500 struct wpabuf *nkx, *pkx;
5501 int ret = -1, res;
5502 const u8 *addr[2];
5503 size_t len[2];
c2d4f2eb 5504 u8 hash[SHA256_MAC_LEN];
650a70a7
JM
5505
5506 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5507 nkx = dpp_get_pubkey_point(own_key, 0);
5508 pkx = dpp_get_pubkey_point(peer_key, 0);
5509 if (!nkx || !pkx)
5510 goto fail;
5511 addr[0] = wpabuf_head(nkx);
5512 len[0] = wpabuf_len(nkx) / 2;
5513 addr[1] = wpabuf_head(pkx);
5514 len[1] = wpabuf_len(pkx) / 2;
5515 if (len[0] != len[1])
5516 goto fail;
5517 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
5518 addr[0] = wpabuf_head(pkx);
5519 addr[1] = wpabuf_head(nkx);
5520 }
650a70a7
JM
5521 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
5522 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
c2d4f2eb 5523 res = sha256_vector(2, addr, len, hash);
650a70a7
JM
5524 if (res < 0)
5525 goto fail;
c2d4f2eb 5526 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
650a70a7
JM
5527 os_memcpy(pmkid, hash, PMKID_LEN);
5528 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
5529 ret = 0;
5530fail:
5531 wpabuf_free(nkx);
5532 wpabuf_free(pkx);
5533 return ret;
5534}
5535
5536
e85b6601
JM
5537enum dpp_status_error
5538dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
5539 const u8 *net_access_key, size_t net_access_key_len,
5540 const u8 *csign_key, size_t csign_key_len,
5541 const u8 *peer_connector, size_t peer_connector_len,
5542 os_time_t *expiry)
650a70a7
JM
5543{
5544 struct json_token *root = NULL, *netkey, *token;
5545 struct json_token *own_root = NULL;
e85b6601 5546 enum dpp_status_error ret = 255, res;
650a70a7
JM
5547 EVP_PKEY *own_key = NULL, *peer_key = NULL;
5548 struct wpabuf *own_key_pub = NULL;
650a70a7
JM
5549 const struct dpp_curve_params *curve, *own_curve;
5550 struct dpp_signed_connector_info info;
5551 const unsigned char *p;
5552 EVP_PKEY *csign = NULL;
5553 char *signed_connector = NULL;
5554 const char *pos, *end;
5555 unsigned char *own_conn = NULL;
5556 size_t own_conn_len;
5557 EVP_PKEY_CTX *ctx = NULL;
5558 size_t Nx_len;
5559 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
650a70a7
JM
5560
5561 os_memset(intro, 0, sizeof(*intro));
5562 os_memset(&info, 0, sizeof(info));
787615b3
JM
5563 if (expiry)
5564 *expiry = 0;
650a70a7
JM
5565
5566 p = csign_key;
5567 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
5568 if (!csign) {
5569 wpa_printf(MSG_ERROR,
5570 "DPP: Failed to parse local C-sign-key information");
5571 goto fail;
5572 }
5573
5574 own_key = dpp_set_keypair(&own_curve, net_access_key,
5575 net_access_key_len);
5576 if (!own_key) {
5577 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
5578 goto fail;
5579 }
650a70a7
JM
5580
5581 pos = os_strchr(own_connector, '.');
43fbb8db
JM
5582 if (!pos) {
5583 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
650a70a7 5584 goto fail;
43fbb8db 5585 }
650a70a7
JM
5586 pos++;
5587 end = os_strchr(pos, '.');
43fbb8db
JM
5588 if (!end) {
5589 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
650a70a7 5590 goto fail;
43fbb8db 5591 }
650a70a7
JM
5592 own_conn = base64_url_decode((const unsigned char *) pos,
5593 end - pos, &own_conn_len);
5594 if (!own_conn) {
5595 wpa_printf(MSG_DEBUG,
5596 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5597 goto fail;
5598 }
5599
5600 own_root = json_parse((const char *) own_conn, own_conn_len);
5601 if (!own_root) {
5602 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
5603 goto fail;
5604 }
5605
5606 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
5607 peer_connector, peer_connector_len);
5608 signed_connector = os_malloc(peer_connector_len + 1);
5609 if (!signed_connector)
5610 goto fail;
5611 os_memcpy(signed_connector, peer_connector, peer_connector_len);
5612 signed_connector[peer_connector_len] = '\0';
5613
e85b6601
JM
5614 res = dpp_process_signed_connector(&info, csign, signed_connector);
5615 if (res != DPP_STATUS_OK) {
5616 ret = res;
650a70a7 5617 goto fail;
e85b6601 5618 }
650a70a7
JM
5619
5620 root = json_parse((const char *) info.payload, info.payload_len);
5621 if (!root) {
5622 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
e85b6601 5623 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5624 goto fail;
5625 }
5626
a4bf0078 5627 if (!dpp_connector_match_groups(own_root, root)) {
650a70a7 5628 wpa_printf(MSG_DEBUG,
a4bf0078 5629 "DPP: Peer connector does not include compatible group netrole with own connector");
e85b6601 5630 ret = DPP_STATUS_NO_MATCH;
650a70a7
JM
5631 goto fail;
5632 }
5633
5634 token = json_get_member(root, "expiry");
5635 if (!token || token->type != JSON_STRING) {
5636 wpa_printf(MSG_DEBUG,
5637 "DPP: No expiry string found - connector does not expire");
5638 } else {
5639 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
787615b3 5640 if (dpp_key_expired(token->string, expiry)) {
650a70a7
JM
5641 wpa_printf(MSG_DEBUG,
5642 "DPP: Connector (netAccessKey) has expired");
e85b6601 5643 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5644 goto fail;
5645 }
5646 }
5647
5648 netkey = json_get_member(root, "netAccessKey");
5649 if (!netkey || netkey->type != JSON_OBJECT) {
5650 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
e85b6601 5651 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5652 goto fail;
5653 }
5654
5655 peer_key = dpp_parse_jwk(netkey, &curve);
e85b6601
JM
5656 if (!peer_key) {
5657 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7 5658 goto fail;
e85b6601 5659 }
650a70a7
JM
5660 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
5661
5662 if (own_curve != curve) {
5663 wpa_printf(MSG_DEBUG,
5664 "DPP: Mismatching netAccessKey curves (%s != %s)",
5665 own_curve->name, curve->name);
e85b6601 5666 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5667 goto fail;
5668 }
5669
5670 /* ECDH: N = nk * PK */
5671 ctx = EVP_PKEY_CTX_new(own_key, NULL);
5672 if (!ctx ||
5673 EVP_PKEY_derive_init(ctx) != 1 ||
5674 EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
5675 EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
5676 Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
5677 EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
5678 wpa_printf(MSG_ERROR,
5679 "DPP: Failed to derive ECDH shared secret: %s",
5680 ERR_error_string(ERR_get_error(), NULL));
5681 goto fail;
5682 }
5683
5684 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
5685 Nx, Nx_len);
5686
5687 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5688 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
5689 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
5690 goto fail;
5691 }
5692 intro->pmk_len = curve->hash_len;
5693
5694 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5695 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
5696 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
5697 goto fail;
5698 }
5699
e85b6601 5700 ret = DPP_STATUS_OK;
650a70a7 5701fail:
e85b6601 5702 if (ret != DPP_STATUS_OK)
650a70a7
JM
5703 os_memset(intro, 0, sizeof(*intro));
5704 os_memset(Nx, 0, sizeof(Nx));
5705 EVP_PKEY_CTX_free(ctx);
5706 os_free(own_conn);
5707 os_free(signed_connector);
5708 os_free(info.payload);
5709 EVP_PKEY_free(own_key);
5710 wpabuf_free(own_key_pub);
650a70a7
JM
5711 EVP_PKEY_free(peer_key);
5712 EVP_PKEY_free(csign);
5713 json_free(root);
5714 json_free(own_root);
5715 return ret;
5716}
500ed7f0
JM
5717
5718
5719static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
5720 int init)
5721{
5722 EC_GROUP *group;
5723 size_t len = curve->prime_len;
5724 const u8 *x, *y;
5725
5726 switch (curve->ike_group) {
5727 case 19:
5728 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
5729 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
5730 break;
5731 case 20:
5732 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
5733 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
5734 break;
5735 case 21:
5736 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
5737 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
5738 break;
5739 case 28:
5740 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
5741 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
5742 break;
5743 case 29:
5744 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
5745 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
5746 break;
5747 case 30:
5748 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
5749 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
5750 break;
5751 default:
5752 return NULL;
5753 }
5754
5755 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5756 if (!group)
5757 return NULL;
5758 return dpp_set_pubkey_point_group(group, x, y, len);
5759}
5760
5761
5762static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
5763 const u8 *mac_init, const char *code,
5764 const char *identifier, BN_CTX *bnctx,
5765 const EC_GROUP **ret_group)
5766{
5767 u8 hash[DPP_MAX_HASH_LEN];
5768 const u8 *addr[3];
5769 size_t len[3];
5770 unsigned int num_elem = 0;
5771 EC_POINT *Qi = NULL;
5772 EVP_PKEY *Pi = NULL;
5773 EC_KEY *Pi_ec = NULL;
5774 const EC_POINT *Pi_point;
5775 BIGNUM *hash_bn = NULL;
5776 const EC_GROUP *group = NULL;
5777 EC_GROUP *group2 = NULL;
5778
5779 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5780
5781 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
5782 addr[num_elem] = mac_init;
5783 len[num_elem] = ETH_ALEN;
5784 num_elem++;
5785 if (identifier) {
5786 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
5787 identifier);
5788 addr[num_elem] = (const u8 *) identifier;
5789 len[num_elem] = os_strlen(identifier);
5790 num_elem++;
5791 }
5792 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
5793 addr[num_elem] = (const u8 *) code;
5794 len[num_elem] = os_strlen(code);
5795 num_elem++;
5796 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
5797 goto fail;
5798 wpa_hexdump_key(MSG_DEBUG,
5799 "DPP: H(MAC-Initiator | [identifier |] code)",
5800 hash, curve->hash_len);
5801 Pi = dpp_pkex_get_role_elem(curve, 1);
5802 if (!Pi)
5803 goto fail;
5804 dpp_debug_print_key("DPP: Pi", Pi);
5805 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
5806 if (!Pi_ec)
5807 goto fail;
5808 Pi_point = EC_KEY_get0_public_key(Pi_ec);
5809
5810 group = EC_KEY_get0_group(Pi_ec);
5811 if (!group)
5812 goto fail;
5813 group2 = EC_GROUP_dup(group);
5814 if (!group2)
5815 goto fail;
5816 Qi = EC_POINT_new(group2);
5817 if (!Qi) {
5818 EC_GROUP_free(group2);
5819 goto fail;
5820 }
5821 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
5822 if (!hash_bn ||
5823 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
5824 goto fail;
65731717 5825 if (EC_POINT_is_at_infinity(group, Qi)) {
578c9ea1 5826 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
65731717
JM
5827 goto fail;
5828 }
500ed7f0
JM
5829out:
5830 EC_KEY_free(Pi_ec);
5831 EVP_PKEY_free(Pi);
5832 BN_clear_free(hash_bn);
5833 if (ret_group)
5834 *ret_group = group2;
5835 return Qi;
5836fail:
5837 EC_POINT_free(Qi);
5838 Qi = NULL;
5839 goto out;
5840}
5841
5842
5843static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
5844 const u8 *mac_resp, const char *code,
5845 const char *identifier, BN_CTX *bnctx,
5846 const EC_GROUP **ret_group)
5847{
5848 u8 hash[DPP_MAX_HASH_LEN];
5849 const u8 *addr[3];
5850 size_t len[3];
5851 unsigned int num_elem = 0;
5852 EC_POINT *Qr = NULL;
5853 EVP_PKEY *Pr = NULL;
5854 EC_KEY *Pr_ec = NULL;
5855 const EC_POINT *Pr_point;
5856 BIGNUM *hash_bn = NULL;
5857 const EC_GROUP *group = NULL;
5858 EC_GROUP *group2 = NULL;
5859
5860 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5861
5862 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
5863 addr[num_elem] = mac_resp;
5864 len[num_elem] = ETH_ALEN;
5865 num_elem++;
5866 if (identifier) {
5867 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
5868 identifier);
5869 addr[num_elem] = (const u8 *) identifier;
5870 len[num_elem] = os_strlen(identifier);
5871 num_elem++;
5872 }
5873 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
5874 addr[num_elem] = (const u8 *) code;
5875 len[num_elem] = os_strlen(code);
5876 num_elem++;
5877 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
5878 goto fail;
5879 wpa_hexdump_key(MSG_DEBUG,
5880 "DPP: H(MAC-Responder | [identifier |] code)",
5881 hash, curve->hash_len);
5882 Pr = dpp_pkex_get_role_elem(curve, 0);
5883 if (!Pr)
5884 goto fail;
5885 dpp_debug_print_key("DPP: Pr", Pr);
5886 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
5887 if (!Pr_ec)
5888 goto fail;
5889 Pr_point = EC_KEY_get0_public_key(Pr_ec);
5890
5891 group = EC_KEY_get0_group(Pr_ec);
5892 if (!group)
5893 goto fail;
5894 group2 = EC_GROUP_dup(group);
5895 if (!group2)
5896 goto fail;
5897 Qr = EC_POINT_new(group2);
5898 if (!Qr) {
5899 EC_GROUP_free(group2);
5900 goto fail;
5901 }
5902 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
5903 if (!hash_bn ||
5904 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
5905 goto fail;
5f5fff43
JM
5906 if (EC_POINT_is_at_infinity(group, Qr)) {
5907 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
5908 goto fail;
5909 }
500ed7f0
JM
5910out:
5911 EC_KEY_free(Pr_ec);
5912 EVP_PKEY_free(Pr);
5913 BN_clear_free(hash_bn);
5914 if (ret_group)
5915 *ret_group = group2;
5916 return Qr;
5917fail:
5918 EC_POINT_free(Qr);
5919 Qr = NULL;
5920 goto out;
5921}
5922
5923
1cfcbd32
JM
5924#ifdef CONFIG_TESTING_OPTIONS
5925static int dpp_test_gen_invalid_key(struct wpabuf *msg,
5926 const struct dpp_curve_params *curve)
5927{
5928 BN_CTX *ctx;
5929 BIGNUM *x, *y;
1cfcbd32
JM
5930 int ret = -1;
5931 EC_GROUP *group;
5932 EC_POINT *point;
5933
5934 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5935 if (!group)
4109555e 5936 return -1;
1cfcbd32
JM
5937
5938 ctx = BN_CTX_new();
5939 point = EC_POINT_new(group);
5940 x = BN_new();
5941 y = BN_new();
5942 if (!ctx || !point || !x || !y)
5943 goto fail;
5944
5945 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
5946 goto fail;
5947
5948 /* Generate a random y coordinate that results in a point that is not
5949 * on the curve. */
5950 for (;;) {
5951 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
5952 goto fail;
5953
5954 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
94619905
JM
5955 ctx) != 1) {
5956#ifdef OPENSSL_IS_BORINGSSL
5957 /* Unlike OpenSSL, BoringSSL returns an error from
5958 * EC_POINT_set_affine_coordinates_GFp() is not on the curve. */
5959 break;
5960#else /* OPENSSL_IS_BORINGSSL */
1cfcbd32 5961 goto fail;
94619905
JM
5962#endif /* OPENSSL_IS_BORINGSSL */
5963 }
1cfcbd32
JM
5964
5965 if (!EC_POINT_is_on_curve(group, point, ctx))
5966 break;
5967 }
5968
fc0efa2a
JM
5969 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
5970 curve->prime_len) < 0 ||
5971 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
5972 curve->prime_len) < 0)
1cfcbd32 5973 goto fail;
1cfcbd32
JM
5974
5975 ret = 0;
5976fail:
94619905
JM
5977 if (ret < 0)
5978 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
1cfcbd32
JM
5979 BN_free(x);
5980 BN_free(y);
5981 EC_POINT_free(point);
5982 BN_CTX_free(ctx);
5983
5984 return ret;
5985}
5986#endif /* CONFIG_TESTING_OPTIONS */
5987
5988
500ed7f0
JM
5989static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
5990{
5991 EC_KEY *X_ec = NULL;
5992 const EC_POINT *X_point;
5993 BN_CTX *bnctx = NULL;
5994 const EC_GROUP *group;
5995 EC_POINT *Qi = NULL, *M = NULL;
5996 struct wpabuf *M_buf = NULL;
5997 BIGNUM *Mx = NULL, *My = NULL;
5998 struct wpabuf *msg = NULL;
5999 size_t attr_len;
6000 const struct dpp_curve_params *curve = pkex->own_bi->curve;
500ed7f0
JM
6001
6002 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
6003
6004 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6005 bnctx = BN_CTX_new();
6006 if (!bnctx)
6007 goto fail;
6008 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
6009 pkex->identifier, bnctx, &group);
6010 if (!Qi)
6011 goto fail;
6012
6013 /* Generate a random ephemeral keypair x/X */
6014 pkex->x = dpp_gen_keypair(curve);
6015 if (!pkex->x)
6016 goto fail;
6017
6018 /* M = X + Qi */
6019 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
6020 if (!X_ec)
6021 goto fail;
6022 X_point = EC_KEY_get0_public_key(X_ec);
6023 if (!X_point)
6024 goto fail;
6025 M = EC_POINT_new(group);
6026 Mx = BN_new();
6027 My = BN_new();
6028 if (!M || !Mx || !My ||
6029 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
6030 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
6031 goto fail;
6032
6033 /* Initiator -> Responder: group, [identifier,] M */
6034 attr_len = 4 + 2;
6035 if (pkex->identifier)
6036 attr_len += 4 + os_strlen(pkex->identifier);
6037 attr_len += 4 + 2 * curve->prime_len;
6038 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
6039 if (!msg)
6040 goto fail;
6041
61f9f27f
JM
6042#ifdef CONFIG_TESTING_OPTIONS
6043 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
6044 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
6045 goto skip_finite_cyclic_group;
6046 }
6047#endif /* CONFIG_TESTING_OPTIONS */
6048
500ed7f0
JM
6049 /* Finite Cyclic Group attribute */
6050 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6051 wpabuf_put_le16(msg, 2);
6052 wpabuf_put_le16(msg, curve->ike_group);
6053
61f9f27f
JM
6054#ifdef CONFIG_TESTING_OPTIONS
6055skip_finite_cyclic_group:
6056#endif /* CONFIG_TESTING_OPTIONS */
6057
500ed7f0
JM
6058 /* Code Identifier attribute */
6059 if (pkex->identifier) {
6060 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6061 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6062 wpabuf_put_str(msg, pkex->identifier);
6063 }
6064
61f9f27f
JM
6065#ifdef CONFIG_TESTING_OPTIONS
6066 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6067 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6068 goto out;
6069 }
6070#endif /* CONFIG_TESTING_OPTIONS */
6071
500ed7f0
JM
6072 /* M in Encrypted Key attribute */
6073 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6074 wpabuf_put_le16(msg, 2 * curve->prime_len);
6075
1cfcbd32
JM
6076#ifdef CONFIG_TESTING_OPTIONS
6077 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6078 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
6079 if (dpp_test_gen_invalid_key(msg, curve) < 0)
6080 goto fail;
6081 goto out;
6082 }
6083#endif /* CONFIG_TESTING_OPTIONS */
6084
fc0efa2a
JM
6085 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
6086 curve->prime_len) < 0 ||
6087 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
6088 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
6089 curve->prime_len) < 0)
500ed7f0 6090 goto fail;
500ed7f0
JM
6091
6092out:
6093 wpabuf_free(M_buf);
6094 EC_KEY_free(X_ec);
6095 EC_POINT_free(M);
6096 EC_POINT_free(Qi);
6097 BN_clear_free(Mx);
6098 BN_clear_free(My);
6099 BN_CTX_free(bnctx);
6100 return msg;
6101fail:
6102 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
6103 wpabuf_free(msg);
6104 msg = NULL;
6105 goto out;
6106}
6107
6108
219d4c9f
JM
6109static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
6110{
6111 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
6112}
6113
6114
6115struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
500ed7f0
JM
6116 const u8 *own_mac,
6117 const char *identifier,
6118 const char *code)
6119{
6120 struct dpp_pkex *pkex;
6121
6122 pkex = os_zalloc(sizeof(*pkex));
6123 if (!pkex)
6124 return NULL;
219d4c9f 6125 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
6126 pkex->initiator = 1;
6127 pkex->own_bi = bi;
6128 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6129 if (identifier) {
6130 pkex->identifier = os_strdup(identifier);
6131 if (!pkex->identifier)
6132 goto fail;
6133 }
6134 pkex->code = os_strdup(code);
6135 if (!pkex->code)
6136 goto fail;
6137 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
6138 if (!pkex->exchange_req)
6139 goto fail;
6140 return pkex;
6141fail:
6142 dpp_pkex_free(pkex);
6143 return NULL;
6144}
6145
6146
e0247e79
JM
6147static struct wpabuf *
6148dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
6149 enum dpp_status_error status,
6150 const BIGNUM *Nx, const BIGNUM *Ny)
a5c3b41b
JM
6151{
6152 struct wpabuf *msg = NULL;
6153 size_t attr_len;
a5c3b41b
JM
6154 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6155
6156 /* Initiator -> Responder: DPP Status, [identifier,] N */
6157 attr_len = 4 + 1;
e0247e79
JM
6158 if (pkex->identifier)
6159 attr_len += 4 + os_strlen(pkex->identifier);
a5c3b41b
JM
6160 attr_len += 4 + 2 * curve->prime_len;
6161 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
6162 if (!msg)
6163 goto fail;
6164
61f9f27f
JM
6165#ifdef CONFIG_TESTING_OPTIONS
6166 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
6167 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
6168 goto skip_status;
6169 }
f31ef96d
JM
6170
6171 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
6172 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
6173 status = 255;
6174 }
61f9f27f
JM
6175#endif /* CONFIG_TESTING_OPTIONS */
6176
a5c3b41b 6177 /* DPP Status */
56f24d1d 6178 dpp_build_attr_status(msg, status);
a5c3b41b 6179
61f9f27f
JM
6180#ifdef CONFIG_TESTING_OPTIONS
6181skip_status:
6182#endif /* CONFIG_TESTING_OPTIONS */
6183
a5c3b41b
JM
6184 /* Code Identifier attribute */
6185 if (pkex->identifier) {
6186 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6187 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6188 wpabuf_put_str(msg, pkex->identifier);
6189 }
6190
e0247e79
JM
6191 if (status != DPP_STATUS_OK)
6192 goto skip_encrypted_key;
6193
61f9f27f
JM
6194#ifdef CONFIG_TESTING_OPTIONS
6195 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
6196 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6197 goto skip_encrypted_key;
6198 }
6199#endif /* CONFIG_TESTING_OPTIONS */
6200
a5c3b41b
JM
6201 /* N in Encrypted Key attribute */
6202 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6203 wpabuf_put_le16(msg, 2 * curve->prime_len);
6204
1cfcbd32
JM
6205#ifdef CONFIG_TESTING_OPTIONS
6206 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
6207 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
6208 if (dpp_test_gen_invalid_key(msg, curve) < 0)
6209 goto fail;
6210 goto skip_encrypted_key;
6211 }
6212#endif /* CONFIG_TESTING_OPTIONS */
6213
fc0efa2a
JM
6214 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
6215 curve->prime_len) < 0 ||
6216 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
6217 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
6218 curve->prime_len) < 0)
a5c3b41b 6219 goto fail;
a5c3b41b 6220
61f9f27f 6221skip_encrypted_key:
e0247e79
JM
6222 if (status == DPP_STATUS_BAD_GROUP) {
6223 /* Finite Cyclic Group attribute */
6224 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6225 wpabuf_put_le16(msg, 2);
6226 wpabuf_put_le16(msg, curve->ike_group);
6227 }
6228
a5c3b41b
JM
6229 return msg;
6230fail:
6231 wpabuf_free(msg);
6232 return NULL;
6233}
6234
6235
d05c82c4
JM
6236static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
6237 const u8 *Mx, size_t Mx_len,
6238 const u8 *Nx, size_t Nx_len,
6239 const char *code,
6240 const u8 *Kx, size_t Kx_len,
6241 u8 *z, unsigned int hash_len)
6242{
6243 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6244 int res;
6245 u8 *info, *pos;
6246 size_t info_len;
6247
6248 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6249 */
6250
6251 /* HKDF-Extract(<>, IKM=K.x) */
6252 os_memset(salt, 0, hash_len);
6253 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
6254 return -1;
6255 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
6256 prk, hash_len);
6257 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
6258 info = os_malloc(info_len);
6259 if (!info)
6260 return -1;
6261 pos = info;
6262 os_memcpy(pos, mac_init, ETH_ALEN);
6263 pos += ETH_ALEN;
6264 os_memcpy(pos, mac_resp, ETH_ALEN);
6265 pos += ETH_ALEN;
6266 os_memcpy(pos, Mx, Mx_len);
6267 pos += Mx_len;
6268 os_memcpy(pos, Nx, Nx_len);
6269 pos += Nx_len;
6270 os_memcpy(pos, code, os_strlen(code));
6271
6272 /* HKDF-Expand(PRK, info, L) */
6273 if (hash_len == 32)
6274 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
6275 z, hash_len);
6276 else if (hash_len == 48)
6277 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
6278 z, hash_len);
6279 else if (hash_len == 64)
6280 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
6281 z, hash_len);
6282 else
6283 res = -1;
6284 os_free(info);
6285 os_memset(prk, 0, hash_len);
6286 if (res < 0)
6287 return -1;
6288
6289 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
6290 z, hash_len);
6291 return 0;
6292}
6293
6294
219d4c9f
JM
6295struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
6296 struct dpp_bootstrap_info *bi,
500ed7f0
JM
6297 const u8 *own_mac,
6298 const u8 *peer_mac,
6299 const char *identifier,
6300 const char *code,
6301 const u8 *buf, size_t len)
6302{
6303 const u8 *attr_group, *attr_id, *attr_key;
6304 u16 attr_group_len, attr_id_len, attr_key_len;
6305 const struct dpp_curve_params *curve = bi->curve;
6306 u16 ike_group;
6307 struct dpp_pkex *pkex = NULL;
6308 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
6309 BN_CTX *bnctx = NULL;
6310 const EC_GROUP *group;
6311 BIGNUM *Mx = NULL, *My = NULL;
6312 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
6313 const EC_POINT *Y_point;
6314 BIGNUM *Nx = NULL, *Ny = NULL;
d05c82c4
JM
6315 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
6316 size_t Kx_len;
6317 int res;
6318 EVP_PKEY_CTX *ctx = NULL;
500ed7f0 6319
29ab69e4
JM
6320 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
6321 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6322 "PKEX counter t limit reached - ignore message");
6323 return NULL;
6324 }
6325
500ed7f0
JM
6326 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
6327 &attr_id_len);
6328 if (!attr_id && identifier) {
6329 wpa_printf(MSG_DEBUG,
6330 "DPP: No PKEX code identifier received, but expected one");
6331 return NULL;
6332 }
6333 if (attr_id && identifier &&
6334 (os_strlen(identifier) != attr_id_len ||
6335 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
6336 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
6337 return NULL;
6338 }
6339
6340 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
6341 &attr_group_len);
6342 if (!attr_group || attr_group_len != 2) {
d7e7b712
JM
6343 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6344 "Missing or invalid Finite Cyclic Group attribute");
500ed7f0
JM
6345 return NULL;
6346 }
6347 ike_group = WPA_GET_LE16(attr_group);
6348 if (ike_group != curve->ike_group) {
d7e7b712
JM
6349 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6350 "Mismatching PKEX curve: peer=%u own=%u",
6351 ike_group, curve->ike_group);
e0247e79
JM
6352 pkex = os_zalloc(sizeof(*pkex));
6353 if (!pkex)
6354 goto fail;
6355 pkex->own_bi = bi;
6356 pkex->failed = 1;
6357 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
6358 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
6359 if (!pkex->exchange_resp)
6360 goto fail;
6361 return pkex;
500ed7f0
JM
6362 }
6363
6364 /* M in Encrypted Key attribute */
6365 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
6366 &attr_key_len);
6367 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
6368 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
d7e7b712
JM
6369 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6370 "Missing Encrypted Key attribute");
500ed7f0
JM
6371 return NULL;
6372 }
6373
6374 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6375 bnctx = BN_CTX_new();
6376 if (!bnctx)
6377 goto fail;
6378 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
6379 &group);
6380 if (!Qi)
6381 goto fail;
6382
6383 /* X' = M - Qi */
6384 X = EC_POINT_new(group);
6385 M = EC_POINT_new(group);
6386 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
6387 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
6388 if (!X || !M || !Mx || !My ||
6389 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
6390 EC_POINT_is_at_infinity(group, M) ||
6391 !EC_POINT_is_on_curve(group, M, bnctx) ||
6392 EC_POINT_invert(group, Qi, bnctx) != 1 ||
6393 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
6394 EC_POINT_is_at_infinity(group, X) ||
d7e7b712
JM
6395 !EC_POINT_is_on_curve(group, X, bnctx)) {
6396 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6397 "Invalid Encrypted Key value");
29ab69e4 6398 bi->pkex_t++;
500ed7f0 6399 goto fail;
d7e7b712 6400 }
500ed7f0
JM
6401
6402 pkex = os_zalloc(sizeof(*pkex));
6403 if (!pkex)
6404 goto fail;
29ab69e4 6405 pkex->t = bi->pkex_t;
219d4c9f 6406 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
6407 pkex->own_bi = bi;
6408 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6409 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
6410 if (identifier) {
6411 pkex->identifier = os_strdup(identifier);
6412 if (!pkex->identifier)
6413 goto fail;
6414 }
6415 pkex->code = os_strdup(code);
6416 if (!pkex->code)
6417 goto fail;
6418
6419 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
6420
6421 X_ec = EC_KEY_new();
6422 if (!X_ec ||
6423 EC_KEY_set_group(X_ec, group) != 1 ||
6424 EC_KEY_set_public_key(X_ec, X) != 1)
6425 goto fail;
6426 pkex->x = EVP_PKEY_new();
6427 if (!pkex->x ||
6428 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
6429 goto fail;
6430
6431 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6432 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
6433 if (!Qr)
6434 goto fail;
6435
6436 /* Generate a random ephemeral keypair y/Y */
6437 pkex->y = dpp_gen_keypair(curve);
6438 if (!pkex->y)
6439 goto fail;
6440
6441 /* N = Y + Qr */
6442 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
6443 if (!Y_ec)
6444 goto fail;
6445 Y_point = EC_KEY_get0_public_key(Y_ec);
6446 if (!Y_point)
6447 goto fail;
6448 N = EC_POINT_new(group);
6449 Nx = BN_new();
6450 Ny = BN_new();
6451 if (!N || !Nx || !Ny ||
6452 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
6453 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
6454 goto fail;
6455
e0247e79 6456 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
a5c3b41b
JM
6457 Nx, Ny);
6458 if (!pkex->exchange_resp)
500ed7f0
JM
6459 goto fail;
6460
d05c82c4
JM
6461 /* K = y * X' */
6462 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
6463 if (!ctx ||
6464 EVP_PKEY_derive_init(ctx) != 1 ||
6465 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
6466 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
6467 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
6468 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
6469 wpa_printf(MSG_ERROR,
6470 "DPP: Failed to derive ECDH shared secret: %s",
6471 ERR_error_string(ERR_get_error(), NULL));
6472 goto fail;
6473 }
6474
6475 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6476 Kx, Kx_len);
6477
6478 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6479 */
6480 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
6481 pkex->Mx, curve->prime_len,
6482 pkex->Nx, curve->prime_len, pkex->code,
6483 Kx, Kx_len, pkex->z, curve->hash_len);
6484 os_memset(Kx, 0, Kx_len);
6485 if (res < 0)
6486 goto fail;
6487
500ed7f0
JM
6488 pkex->exchange_done = 1;
6489
6490out:
d05c82c4 6491 EVP_PKEY_CTX_free(ctx);
500ed7f0
JM
6492 BN_CTX_free(bnctx);
6493 EC_POINT_free(Qi);
6494 EC_POINT_free(Qr);
6495 BN_free(Mx);
6496 BN_free(My);
6497 BN_free(Nx);
6498 BN_free(Ny);
6499 EC_POINT_free(M);
6500 EC_POINT_free(N);
6501 EC_POINT_free(X);
6502 EC_KEY_free(X_ec);
6503 EC_KEY_free(Y_ec);
6504 return pkex;
6505fail:
60b9dd86 6506 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
500ed7f0
JM
6507 dpp_pkex_free(pkex);
6508 pkex = NULL;
6509 goto out;
6510}
6511
6512
b0626c2a
JM
6513static struct wpabuf *
6514dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
6515 const struct wpabuf *A_pub, const u8 *u)
6516{
6517 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6518 struct wpabuf *msg = NULL;
6519 size_t clear_len, attr_len;
6520 struct wpabuf *clear = NULL;
6521 u8 *wrapped;
6522 u8 octet;
6523 const u8 *addr[2];
6524 size_t len[2];
6525
6526 /* {A, u, [bootstrapping info]}z */
6527 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
6528 clear = wpabuf_alloc(clear_len);
6529 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6530#ifdef CONFIG_TESTING_OPTIONS
6531 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
acdf703d 6532 attr_len += 5;
b0626c2a
JM
6533#endif /* CONFIG_TESTING_OPTIONS */
6534 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
6535 if (!clear || !msg)
6536 goto fail;
6537
61f9f27f
JM
6538#ifdef CONFIG_TESTING_OPTIONS
6539 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
6540 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
6541 goto skip_bootstrap_key;
6542 }
89d0bf67
JM
6543 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
6544 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
6545 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6546 wpabuf_put_le16(clear, 2 * curve->prime_len);
6547 if (dpp_test_gen_invalid_key(clear, curve) < 0)
6548 goto fail;
6549 goto skip_bootstrap_key;
6550 }
61f9f27f
JM
6551#endif /* CONFIG_TESTING_OPTIONS */
6552
b0626c2a
JM
6553 /* A in Bootstrap Key attribute */
6554 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6555 wpabuf_put_le16(clear, wpabuf_len(A_pub));
6556 wpabuf_put_buf(clear, A_pub);
6557
61f9f27f
JM
6558#ifdef CONFIG_TESTING_OPTIONS
6559skip_bootstrap_key:
6560 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
6561 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
6562 goto skip_i_auth_tag;
6563 }
7e0ebe21
JM
6564 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
6565 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
6566 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
6567 wpabuf_put_le16(clear, curve->hash_len);
6568 wpabuf_put_data(clear, u, curve->hash_len - 1);
6569 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
6570 goto skip_i_auth_tag;
6571 }
61f9f27f
JM
6572#endif /* CONFIG_TESTING_OPTIONS */
6573
b0626c2a
JM
6574 /* u in I-Auth tag attribute */
6575 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
6576 wpabuf_put_le16(clear, curve->hash_len);
6577 wpabuf_put_data(clear, u, curve->hash_len);
6578
61f9f27f
JM
6579#ifdef CONFIG_TESTING_OPTIONS
6580skip_i_auth_tag:
6581 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
6582 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
6583 goto skip_wrapped_data;
6584 }
6585#endif /* CONFIG_TESTING_OPTIONS */
6586
b0626c2a
JM
6587 addr[0] = wpabuf_head_u8(msg) + 2;
6588 len[0] = DPP_HDR_LEN;
6589 octet = 0;
6590 addr[1] = &octet;
6591 len[1] = sizeof(octet);
6592 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6593 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6594
6595 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6596 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6597 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6598
6599 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6600 if (aes_siv_encrypt(pkex->z, curve->hash_len,
6601 wpabuf_head(clear), wpabuf_len(clear),
6602 2, addr, len, wrapped) < 0)
6603 goto fail;
6604 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6605 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6606
6607#ifdef CONFIG_TESTING_OPTIONS
6608 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
6609 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 6610 dpp_build_attr_status(msg, DPP_STATUS_OK);
b0626c2a 6611 }
61f9f27f 6612skip_wrapped_data:
b0626c2a
JM
6613#endif /* CONFIG_TESTING_OPTIONS */
6614
6615out:
6616 wpabuf_free(clear);
6617 return msg;
6618
6619fail:
6620 wpabuf_free(msg);
6621 msg = NULL;
6622 goto out;
6623}
6624
6625
500ed7f0
JM
6626struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
6627 const u8 *buf, size_t buflen)
6628{
e0247e79
JM
6629 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
6630 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
500ed7f0
JM
6631 const EC_GROUP *group;
6632 BN_CTX *bnctx = NULL;
500ed7f0
JM
6633 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6634 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6635 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
6636 BIGNUM *Nx = NULL, *Ny = NULL;
6637 EVP_PKEY_CTX *ctx = NULL;
6638 EC_KEY *Y_ec = NULL;
0e6709a4
JM
6639 size_t Jx_len, Kx_len;
6640 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
6641 const u8 *addr[4];
6642 size_t len[4];
6643 u8 u[DPP_MAX_HASH_LEN];
6254045a 6644 int res;
500ed7f0 6645
03abb6b5 6646 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
e0247e79
JM
6647 return NULL;
6648
500ed7f0
JM
6649 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
6650 &attr_status_len);
6651 if (!attr_status || attr_status_len != 1) {
d7e7b712 6652 dpp_pkex_fail(pkex, "No DPP Status attribute");
500ed7f0
JM
6653 return NULL;
6654 }
6655 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
e0247e79
JM
6656
6657 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
6658 attr_group = dpp_get_attr(buf, buflen,
6659 DPP_ATTR_FINITE_CYCLIC_GROUP,
6660 &attr_group_len);
6661 if (attr_group && attr_group_len == 2) {
6662 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6663 "Peer indicated mismatching PKEX group - proposed %u",
6664 WPA_GET_LE16(attr_group));
6665 return NULL;
6666 }
6667 }
6668
500ed7f0 6669 if (attr_status[0] != DPP_STATUS_OK) {
d7e7b712 6670 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
500ed7f0
JM
6671 return NULL;
6672 }
6673
6674 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
6675 &attr_id_len);
6676 if (!attr_id && pkex->identifier) {
6677 wpa_printf(MSG_DEBUG,
6678 "DPP: No PKEX code identifier received, but expected one");
6679 return NULL;
6680 }
6681 if (attr_id && pkex->identifier &&
6682 (os_strlen(pkex->identifier) != attr_id_len ||
6683 os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) {
d7e7b712 6684 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
500ed7f0
JM
6685 return NULL;
6686 }
6687
6688 /* N in Encrypted Key attribute */
6689 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
6690 &attr_key_len);
6691 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
d7e7b712 6692 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
500ed7f0
JM
6693 return NULL;
6694 }
6695
6696 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
6697 bnctx = BN_CTX_new();
6698 if (!bnctx)
6699 goto fail;
6700 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
6701 pkex->identifier, bnctx, &group);
6702 if (!Qr)
6703 goto fail;
6704
6705 /* Y' = N - Qr */
6706 Y = EC_POINT_new(group);
6707 N = EC_POINT_new(group);
6708 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
6709 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
6710 if (!Y || !N || !Nx || !Ny ||
6711 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
6712 EC_POINT_is_at_infinity(group, N) ||
6713 !EC_POINT_is_on_curve(group, N, bnctx) ||
6714 EC_POINT_invert(group, Qr, bnctx) != 1 ||
6715 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
6716 EC_POINT_is_at_infinity(group, Y) ||
d7e7b712
JM
6717 !EC_POINT_is_on_curve(group, Y, bnctx)) {
6718 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
29ab69e4 6719 pkex->t++;
500ed7f0 6720 goto fail;
d7e7b712 6721 }
500ed7f0
JM
6722
6723 pkex->exchange_done = 1;
6724
6725 /* ECDH: J = a * Y’ */
6726 Y_ec = EC_KEY_new();
6727 if (!Y_ec ||
6728 EC_KEY_set_group(Y_ec, group) != 1 ||
6729 EC_KEY_set_public_key(Y_ec, Y) != 1)
6730 goto fail;
6731 pkex->y = EVP_PKEY_new();
6732 if (!pkex->y ||
6733 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
6734 goto fail;
6735 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
6736 if (!ctx ||
6737 EVP_PKEY_derive_init(ctx) != 1 ||
6738 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
6739 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
6740 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
6741 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
6742 wpa_printf(MSG_ERROR,
6743 "DPP: Failed to derive ECDH shared secret: %s",
6744 ERR_error_string(ERR_get_error(), NULL));
6745 goto fail;
6746 }
6747
6748 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
6749 Jx, Jx_len);
6750
6751 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
6752 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
6753 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
6754 X_pub = dpp_get_pubkey_point(pkex->x, 0);
6755 if (!A_pub || !Y_pub || !X_pub)
6756 goto fail;
6757 addr[0] = pkex->own_mac;
6758 len[0] = ETH_ALEN;
6759 addr[1] = wpabuf_head(A_pub);
6760 len[1] = wpabuf_len(A_pub) / 2;
6761 addr[2] = wpabuf_head(Y_pub);
6762 len[2] = wpabuf_len(Y_pub) / 2;
6763 addr[3] = wpabuf_head(X_pub);
6764 len[3] = wpabuf_len(X_pub) / 2;
6765 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
6766 goto fail;
6767 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
6768
0e6709a4 6769 /* K = x * Y’ */
500ed7f0
JM
6770 EVP_PKEY_CTX_free(ctx);
6771 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
6772 if (!ctx ||
6773 EVP_PKEY_derive_init(ctx) != 1 ||
6774 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
0e6709a4
JM
6775 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
6776 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
6777 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
500ed7f0
JM
6778 wpa_printf(MSG_ERROR,
6779 "DPP: Failed to derive ECDH shared secret: %s",
6780 ERR_error_string(ERR_get_error(), NULL));
6781 goto fail;
6782 }
6783
0e6709a4
JM
6784 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6785 Kx, Kx_len);
500ed7f0 6786
0e6709a4 6787 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
500ed7f0 6788 */
6254045a
JM
6789 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
6790 pkex->Mx, curve->prime_len,
6791 attr_key /* N.x */, attr_key_len / 2,
6792 pkex->code, Kx, Kx_len,
6793 pkex->z, curve->hash_len);
6794 os_memset(Kx, 0, Kx_len);
6795 if (res < 0)
500ed7f0
JM
6796 goto fail;
6797
b0626c2a
JM
6798 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
6799 if (!msg)
500ed7f0 6800 goto fail;
60239f60 6801
500ed7f0 6802out:
500ed7f0
JM
6803 wpabuf_free(A_pub);
6804 wpabuf_free(X_pub);
6805 wpabuf_free(Y_pub);
6806 EC_POINT_free(Qr);
6807 EC_POINT_free(Y);
6808 EC_POINT_free(N);
6809 BN_free(Nx);
6810 BN_free(Ny);
6811 EC_KEY_free(Y_ec);
6812 EVP_PKEY_CTX_free(ctx);
6813 BN_CTX_free(bnctx);
6814 return msg;
6815fail:
60b9dd86 6816 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
500ed7f0
JM
6817 goto out;
6818}
6819
6820
b3e4cc5c
JM
6821static struct wpabuf *
6822dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
6823 const struct wpabuf *B_pub, const u8 *v)
6824{
6825 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6826 struct wpabuf *msg = NULL;
6827 const u8 *addr[2];
6828 size_t len[2];
6829 u8 octet;
6830 u8 *wrapped;
6831 struct wpabuf *clear = NULL;
6832 size_t clear_len, attr_len;
6833
6834 /* {B, v [bootstrapping info]}z */
6835 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
6836 clear = wpabuf_alloc(clear_len);
6837 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6838#ifdef CONFIG_TESTING_OPTIONS
6839 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
acdf703d 6840 attr_len += 5;
b3e4cc5c
JM
6841#endif /* CONFIG_TESTING_OPTIONS */
6842 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
6843 if (!clear || !msg)
6844 goto fail;
6845
61f9f27f
JM
6846#ifdef CONFIG_TESTING_OPTIONS
6847 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
6848 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
6849 goto skip_bootstrap_key;
6850 }
89d0bf67
JM
6851 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
6852 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
6853 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6854 wpabuf_put_le16(clear, 2 * curve->prime_len);
6855 if (dpp_test_gen_invalid_key(clear, curve) < 0)
6856 goto fail;
6857 goto skip_bootstrap_key;
6858 }
61f9f27f
JM
6859#endif /* CONFIG_TESTING_OPTIONS */
6860
6861 /* B in Bootstrap Key attribute */
b3e4cc5c
JM
6862 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6863 wpabuf_put_le16(clear, wpabuf_len(B_pub));
6864 wpabuf_put_buf(clear, B_pub);
6865
61f9f27f
JM
6866#ifdef CONFIG_TESTING_OPTIONS
6867skip_bootstrap_key:
6868 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
6869 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
6870 goto skip_r_auth_tag;
6871 }
7e0ebe21
JM
6872 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
6873 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
6874 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
6875 wpabuf_put_le16(clear, curve->hash_len);
6876 wpabuf_put_data(clear, v, curve->hash_len - 1);
6877 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
6878 goto skip_r_auth_tag;
6879 }
61f9f27f
JM
6880#endif /* CONFIG_TESTING_OPTIONS */
6881
b3e4cc5c
JM
6882 /* v in R-Auth tag attribute */
6883 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
6884 wpabuf_put_le16(clear, curve->hash_len);
6885 wpabuf_put_data(clear, v, curve->hash_len);
6886
61f9f27f
JM
6887#ifdef CONFIG_TESTING_OPTIONS
6888skip_r_auth_tag:
6889 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
6890 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
6891 goto skip_wrapped_data;
6892 }
6893#endif /* CONFIG_TESTING_OPTIONS */
6894
b3e4cc5c
JM
6895 addr[0] = wpabuf_head_u8(msg) + 2;
6896 len[0] = DPP_HDR_LEN;
6897 octet = 1;
6898 addr[1] = &octet;
6899 len[1] = sizeof(octet);
6900 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6901 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6902
6903 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6904 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6905 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6906
6907 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6908 if (aes_siv_encrypt(pkex->z, curve->hash_len,
6909 wpabuf_head(clear), wpabuf_len(clear),
6910 2, addr, len, wrapped) < 0)
6911 goto fail;
6912 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6913 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6914
6915#ifdef CONFIG_TESTING_OPTIONS
6916 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
6917 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 6918 dpp_build_attr_status(msg, DPP_STATUS_OK);
b3e4cc5c 6919 }
61f9f27f 6920skip_wrapped_data:
b3e4cc5c
JM
6921#endif /* CONFIG_TESTING_OPTIONS */
6922
6923out:
6924 wpabuf_free(clear);
6925 return msg;
6926
6927fail:
6928 wpabuf_free(msg);
6929 msg = NULL;
6930 goto out;
6931}
6932
6933
500ed7f0 6934struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
4be5bc98 6935 const u8 *hdr,
500ed7f0
JM
6936 const u8 *buf, size_t buflen)
6937{
6938 const struct dpp_curve_params *curve = pkex->own_bi->curve;
e0247e79 6939 EVP_PKEY_CTX *ctx = NULL;
d05c82c4
JM
6940 size_t Jx_len, Lx_len;
6941 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
6942 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
6943 const u8 *wrapped_data, *b_key, *peer_u;
6944 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
6945 const u8 *addr[4];
6946 size_t len[4];
6947 u8 octet;
6948 u8 *unwrapped = NULL;
6949 size_t unwrapped_len = 0;
6950 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6951 struct wpabuf *B_pub = NULL;
6952 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
500ed7f0 6953
29ab69e4 6954 if (!pkex->exchange_done || pkex->failed ||
03abb6b5 6955 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
e0247e79
JM
6956 goto fail;
6957
500ed7f0
JM
6958 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
6959 &wrapped_data_len);
6960 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
6961 dpp_pkex_fail(pkex,
6962 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
6963 goto fail;
6964 }
6965
6966 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6967 wrapped_data, wrapped_data_len);
6968 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6969 unwrapped = os_malloc(unwrapped_len);
6970 if (!unwrapped)
6971 goto fail;
6972
4be5bc98
JM
6973 addr[0] = hdr;
6974 len[0] = DPP_HDR_LEN;
500ed7f0 6975 octet = 0;
4be5bc98
JM
6976 addr[1] = &octet;
6977 len[1] = sizeof(octet);
6978 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6979 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
6980
6981 if (aes_siv_decrypt(pkex->z, curve->hash_len,
6982 wrapped_data, wrapped_data_len,
4be5bc98 6983 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
6984 dpp_pkex_fail(pkex,
6985 "AES-SIV decryption failed - possible PKEX code mismatch");
039b8e73 6986 pkex->failed = 1;
29ab69e4 6987 pkex->t++;
500ed7f0
JM
6988 goto fail;
6989 }
6990 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6991 unwrapped, unwrapped_len);
6992
6993 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 6994 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
6995 goto fail;
6996 }
6997
6998 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
6999 &b_key_len);
7000 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 7001 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
7002 goto fail;
7003 }
7004 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7005 b_key_len);
d7e7b712
JM
7006 if (!pkex->peer_bootstrap_key) {
7007 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 7008 goto fail;
d7e7b712 7009 }
500ed7f0
JM
7010 dpp_debug_print_key("DPP: Peer bootstrap public key",
7011 pkex->peer_bootstrap_key);
7012
7013 /* ECDH: J' = y * A' */
500ed7f0
JM
7014 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
7015 if (!ctx ||
7016 EVP_PKEY_derive_init(ctx) != 1 ||
7017 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
7018 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
7019 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
7020 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
7021 wpa_printf(MSG_ERROR,
7022 "DPP: Failed to derive ECDH shared secret: %s",
7023 ERR_error_string(ERR_get_error(), NULL));
7024 goto fail;
7025 }
7026
7027 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7028 Jx, Jx_len);
7029
7030 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7031 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7032 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7033 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7034 if (!A_pub || !Y_pub || !X_pub)
7035 goto fail;
7036 addr[0] = pkex->peer_mac;
7037 len[0] = ETH_ALEN;
7038 addr[1] = wpabuf_head(A_pub);
7039 len[1] = wpabuf_len(A_pub) / 2;
7040 addr[2] = wpabuf_head(Y_pub);
7041 len[2] = wpabuf_len(Y_pub) / 2;
7042 addr[3] = wpabuf_head(X_pub);
7043 len[3] = wpabuf_len(X_pub) / 2;
7044 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
7045 goto fail;
7046
7047 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
7048 &peer_u_len);
7049 if (!peer_u || peer_u_len != curve->hash_len ||
7050 os_memcmp(peer_u, u, curve->hash_len) != 0) {
d7e7b712 7051 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
500ed7f0
JM
7052 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
7053 u, curve->hash_len);
7054 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
29ab69e4 7055 pkex->t++;
500ed7f0
JM
7056 goto fail;
7057 }
7058 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
7059
7060 /* ECDH: L = b * X' */
7061 EVP_PKEY_CTX_free(ctx);
7062 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7063 if (!ctx ||
7064 EVP_PKEY_derive_init(ctx) != 1 ||
7065 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
7066 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
7067 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
7068 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
7069 wpa_printf(MSG_ERROR,
7070 "DPP: Failed to derive ECDH shared secret: %s",
7071 ERR_error_string(ERR_get_error(), NULL));
7072 goto fail;
7073 }
7074
7075 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7076 Lx, Lx_len);
7077
7078 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7079 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
7080 if (!B_pub)
7081 goto fail;
7082 addr[0] = pkex->own_mac;
7083 len[0] = ETH_ALEN;
7084 addr[1] = wpabuf_head(B_pub);
7085 len[1] = wpabuf_len(B_pub) / 2;
7086 addr[2] = wpabuf_head(X_pub);
7087 len[2] = wpabuf_len(X_pub) / 2;
7088 addr[3] = wpabuf_head(Y_pub);
7089 len[3] = wpabuf_len(Y_pub) / 2;
7090 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
7091 goto fail;
7092 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
7093
b3e4cc5c
JM
7094 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
7095 if (!msg)
500ed7f0 7096 goto fail;
60239f60 7097
500ed7f0
JM
7098out:
7099 EVP_PKEY_CTX_free(ctx);
7100 os_free(unwrapped);
7101 wpabuf_free(A_pub);
7102 wpabuf_free(B_pub);
7103 wpabuf_free(X_pub);
7104 wpabuf_free(Y_pub);
500ed7f0
JM
7105 return msg;
7106fail:
b3e4cc5c
JM
7107 wpa_printf(MSG_DEBUG,
7108 "DPP: PKEX Commit-Reveal Request processing failed");
500ed7f0
JM
7109 goto out;
7110}
7111
7112
4be5bc98 7113int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
500ed7f0
JM
7114 const u8 *buf, size_t buflen)
7115{
7116 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7117 const u8 *wrapped_data, *b_key, *peer_v;
7118 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
7119 const u8 *addr[4];
7120 size_t len[4];
7121 u8 octet;
7122 u8 *unwrapped = NULL;
7123 size_t unwrapped_len = 0;
7124 int ret = -1;
7125 u8 v[DPP_MAX_HASH_LEN];
7126 size_t Lx_len;
7127 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
7128 EVP_PKEY_CTX *ctx = NULL;
7129 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7130
29ab69e4 7131 if (!pkex->exchange_done || pkex->failed ||
03abb6b5 7132 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
e0247e79
JM
7133 goto fail;
7134
500ed7f0
JM
7135 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7136 &wrapped_data_len);
7137 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
7138 dpp_pkex_fail(pkex,
7139 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
7140 goto fail;
7141 }
7142
7143 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7144 wrapped_data, wrapped_data_len);
7145 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7146 unwrapped = os_malloc(unwrapped_len);
7147 if (!unwrapped)
7148 goto fail;
7149
4be5bc98
JM
7150 addr[0] = hdr;
7151 len[0] = DPP_HDR_LEN;
500ed7f0 7152 octet = 1;
4be5bc98
JM
7153 addr[1] = &octet;
7154 len[1] = sizeof(octet);
7155 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7156 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
7157
7158 if (aes_siv_decrypt(pkex->z, curve->hash_len,
7159 wrapped_data, wrapped_data_len,
4be5bc98 7160 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
7161 dpp_pkex_fail(pkex,
7162 "AES-SIV decryption failed - possible PKEX code mismatch");
29ab69e4 7163 pkex->t++;
500ed7f0
JM
7164 goto fail;
7165 }
7166 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7167 unwrapped, unwrapped_len);
7168
7169 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 7170 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
7171 goto fail;
7172 }
7173
7174 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7175 &b_key_len);
7176 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 7177 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
7178 goto fail;
7179 }
7180 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7181 b_key_len);
d7e7b712
JM
7182 if (!pkex->peer_bootstrap_key) {
7183 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 7184 goto fail;
d7e7b712 7185 }
500ed7f0
JM
7186 dpp_debug_print_key("DPP: Peer bootstrap public key",
7187 pkex->peer_bootstrap_key);
7188
7189 /* ECDH: L' = x * B' */
7190 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
7191 if (!ctx ||
7192 EVP_PKEY_derive_init(ctx) != 1 ||
7193 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
7194 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
7195 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
7196 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
7197 wpa_printf(MSG_ERROR,
7198 "DPP: Failed to derive ECDH shared secret: %s",
7199 ERR_error_string(ERR_get_error(), NULL));
7200 goto fail;
7201 }
7202
7203 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7204 Lx, Lx_len);
7205
7206 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
7207 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7208 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7209 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7210 if (!B_pub || !X_pub || !Y_pub)
7211 goto fail;
7212 addr[0] = pkex->peer_mac;
7213 len[0] = ETH_ALEN;
7214 addr[1] = wpabuf_head(B_pub);
7215 len[1] = wpabuf_len(B_pub) / 2;
7216 addr[2] = wpabuf_head(X_pub);
7217 len[2] = wpabuf_len(X_pub) / 2;
7218 addr[3] = wpabuf_head(Y_pub);
7219 len[3] = wpabuf_len(Y_pub) / 2;
7220 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
7221 goto fail;
7222
7223 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
7224 &peer_v_len);
7225 if (!peer_v || peer_v_len != curve->hash_len ||
7226 os_memcmp(peer_v, v, curve->hash_len) != 0) {
d7e7b712 7227 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
500ed7f0
JM
7228 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
7229 v, curve->hash_len);
7230 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
29ab69e4 7231 pkex->t++;
500ed7f0
JM
7232 goto fail;
7233 }
7234 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
7235
7236 ret = 0;
7237out:
7238 wpabuf_free(B_pub);
7239 wpabuf_free(X_pub);
7240 wpabuf_free(Y_pub);
7241 EVP_PKEY_CTX_free(ctx);
7242 os_free(unwrapped);
7243 return ret;
7244fail:
7245 goto out;
7246}
7247
7248
7249void dpp_pkex_free(struct dpp_pkex *pkex)
7250{
7251 if (!pkex)
7252 return;
7253
7254 os_free(pkex->identifier);
7255 os_free(pkex->code);
7256 EVP_PKEY_free(pkex->x);
7257 EVP_PKEY_free(pkex->y);
7258 EVP_PKEY_free(pkex->peer_bootstrap_key);
7259 wpabuf_free(pkex->exchange_req);
7260 wpabuf_free(pkex->exchange_resp);
7261 os_free(pkex);
7262}
4b8de0c9
JM
7263
7264
7265#ifdef CONFIG_TESTING_OPTIONS
7266char * dpp_corrupt_connector_signature(const char *connector)
7267{
7268 char *tmp, *pos, *signed3 = NULL;
7269 unsigned char *signature = NULL;
7270 size_t signature_len = 0, signed3_len;
7271
7272 tmp = os_zalloc(os_strlen(connector) + 5);
7273 if (!tmp)
7274 goto fail;
7275 os_memcpy(tmp, connector, os_strlen(connector));
7276
7277 pos = os_strchr(tmp, '.');
7278 if (!pos)
7279 goto fail;
7280
7281 pos = os_strchr(pos + 1, '.');
7282 if (!pos)
7283 goto fail;
7284 pos++;
7285
7286 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
7287 pos);
7288 signature = base64_url_decode((const unsigned char *) pos,
7289 os_strlen(pos), &signature_len);
7290 if (!signature || signature_len == 0)
7291 goto fail;
7292 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
7293 signature, signature_len);
7294 signature[signature_len - 1] ^= 0x01;
7295 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
7296 signature, signature_len);
7297 signed3 = (char *) base64_url_encode(signature, signature_len,
7298 &signed3_len, 0);
7299 if (!signed3)
7300 goto fail;
7301 os_memcpy(pos, signed3, signed3_len);
7302 pos[signed3_len] = '\0';
7303 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
7304 pos);
7305
7306out:
7307 os_free(signature);
7308 os_free(signed3);
7309 return tmp;
7310fail:
7311 os_free(tmp);
7312 tmp = NULL;
7313 goto out;
7314}
7315#endif /* CONFIG_TESTING_OPTIONS */