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