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