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