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