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