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