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