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