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