]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/common/dpp.c
Clean up base64_url_{encode,decode} pointer types
[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);
b2260842 4682 x = base64_url_encode(pos, curve->prime_len, NULL);
461d39af 4683 pos += curve->prime_len;
b2260842 4684 y = 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);
b2260842
JM
4854 signed1 = base64_url_encode(jws_prot_hdr, os_strlen(jws_prot_hdr),
4855 &signed1_len);
4856 signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
4857 &signed2_len);
461d39af
JM
4858 if (!signed1 || !signed2)
4859 goto fail;
4860
4861 md_ctx = EVP_MD_CTX_create();
4862 if (!md_ctx)
4863 goto fail;
4864
4865 ERR_clear_error();
4866 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
4867 auth->conf->csign) != 1) {
4868 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
4869 ERR_error_string(ERR_get_error(), NULL));
4870 goto fail;
4871 }
4872 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
4873 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
4874 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
4875 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
4876 ERR_error_string(ERR_get_error(), NULL));
4877 goto fail;
4878 }
4879 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
4880 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4881 ERR_error_string(ERR_get_error(), NULL));
4882 goto fail;
4883 }
4884 signature = os_malloc(signature_len);
4885 if (!signature)
4886 goto fail;
4887 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
4888 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4889 ERR_error_string(ERR_get_error(), NULL));
4890 goto fail;
4891 }
4892 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
4893 signature, signature_len);
4894 /* Convert to raw coordinates r,s */
4895 p = signature;
4896 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
4897 if (!sig)
4898 goto fail;
4899 ECDSA_SIG_get0(sig, &r, &s);
4900 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4901 dpp_bn2bin_pad(s, signature + curve->prime_len,
4902 curve->prime_len) < 0)
4903 goto fail;
4904 signature_len = 2 * curve->prime_len;
4905 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4906 signature, signature_len);
b2260842 4907 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
461d39af
JM
4908 if (!signed3)
4909 goto fail;
4910
18015fc8 4911 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
461d39af
JM
4912 tailroom = 1000;
4913 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4914 tailroom += signed1_len + signed2_len + signed3_len;
18015fc8
JM
4915 if (incl_legacy)
4916 tailroom += 1000;
461d39af
JM
4917 buf = dpp_build_conf_start(auth, conf, tailroom);
4918 if (!buf)
62293412 4919 goto fail;
461d39af 4920
68fea960
JM
4921 if (auth->akm_use_selector && dpp_akm_ver2(akm))
4922 akm_str = dpp_akm_selector_str(akm);
4923 else
4924 akm_str = dpp_akm_str(akm);
4925 wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
18015fc8
JM
4926 if (incl_legacy) {
4927 dpp_build_legacy_cred_params(buf, conf);
4928 wpabuf_put_str(buf, ",");
4929 }
4930 wpabuf_put_str(buf, "\"signedConnector\":\"");
461d39af
JM
4931 wpabuf_put_str(buf, signed1);
4932 wpabuf_put_u8(buf, '.');
4933 wpabuf_put_str(buf, signed2);
4934 wpabuf_put_u8(buf, '.');
4935 wpabuf_put_str(buf, signed3);
4936 wpabuf_put_str(buf, "\",");
4937 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4938 curve) < 0) {
4939 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4940 goto fail;
4941 }
461d39af
JM
4942
4943 wpabuf_put_str(buf, "}}");
4944
4945 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4946 wpabuf_head(buf), wpabuf_len(buf));
4947
4948out:
4949 EVP_MD_CTX_destroy(md_ctx);
4950 ECDSA_SIG_free(sig);
4951 os_free(signed1);
4952 os_free(signed2);
4953 os_free(signed3);
4954 os_free(signature);
4955 wpabuf_free(dppcon);
4956 return buf;
4957fail:
4958 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4959 wpabuf_free(buf);
4960 buf = NULL;
4961 goto out;
4962}
4963
4964
4965static struct wpabuf *
99918e06 4966dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
461d39af
JM
4967 struct dpp_configuration *conf)
4968{
4969 struct wpabuf *buf;
68fea960 4970 const char *akm_str;
461d39af
JM
4971
4972 buf = dpp_build_conf_start(auth, conf, 1000);
4973 if (!buf)
4974 return NULL;
4975
68fea960
JM
4976 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
4977 akm_str = dpp_akm_selector_str(conf->akm);
4978 else
4979 akm_str = dpp_akm_str(conf->akm);
4980 wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
18015fc8 4981 dpp_build_legacy_cred_params(buf, conf);
461d39af
JM
4982 wpabuf_put_str(buf, "}}");
4983
4984 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4985 wpabuf_head(buf), wpabuf_len(buf));
4986
4987 return buf;
4988}
4989
4990
4991static struct wpabuf *
7eb06a33 4992dpp_build_conf_obj(struct dpp_authentication *auth, int ap, int idx)
461d39af
JM
4993{
4994 struct dpp_configuration *conf;
4995
4996#ifdef CONFIG_TESTING_OPTIONS
4997 if (auth->config_obj_override) {
7eb06a33
JM
4998 if (idx != 0)
4999 return NULL;
461d39af
JM
5000 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
5001 return wpabuf_alloc_copy(auth->config_obj_override,
5002 os_strlen(auth->config_obj_override));
5003 }
5004#endif /* CONFIG_TESTING_OPTIONS */
5005
7eb06a33
JM
5006 if (idx == 0)
5007 conf = ap ? auth->conf_ap : auth->conf_sta;
5008 else if (idx == 1)
5009 conf = ap ? auth->conf2_ap : auth->conf2_sta;
5010 else
5011 conf = NULL;
461d39af 5012 if (!conf) {
9c08bfbd 5013 if (idx == 0)
7eb06a33
JM
5014 wpa_printf(MSG_DEBUG,
5015 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
5016 ap ? "ap" : "sta");
461d39af
JM
5017 return NULL;
5018 }
5019
18015fc8 5020 if (dpp_akm_dpp(conf->akm))
99918e06
JM
5021 return dpp_build_conf_obj_dpp(auth, conf);
5022 return dpp_build_conf_obj_legacy(auth, conf);
461d39af
JM
5023}
5024
5025
5026static struct wpabuf *
5027dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
5028 u16 e_nonce_len, int ap)
5029{
7eb06a33 5030 struct wpabuf *conf, *conf2 = NULL;
60239f60 5031 size_t clear_len, attr_len;
461d39af
JM
5032 struct wpabuf *clear = NULL, *msg = NULL;
5033 u8 *wrapped;
5034 const u8 *addr[1];
5035 size_t len[1];
5036 enum dpp_status_error status;
5037
7eb06a33 5038 conf = dpp_build_conf_obj(auth, ap, 0);
461d39af
JM
5039 if (conf) {
5040 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
5041 wpabuf_head(conf), wpabuf_len(conf));
7eb06a33 5042 conf2 = dpp_build_conf_obj(auth, ap, 1);
461d39af
JM
5043 }
5044 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
22f90b32 5045 auth->conf_resp_status = status;
461d39af 5046
b10e01a7 5047 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
461d39af
JM
5048 clear_len = 4 + e_nonce_len;
5049 if (conf)
5050 clear_len += 4 + wpabuf_len(conf);
7eb06a33
JM
5051 if (conf2)
5052 clear_len += 4 + wpabuf_len(conf2);
b10e01a7
JM
5053 if (auth->peer_version >= 2 && auth->send_conn_status && !ap)
5054 clear_len += 4;
461d39af 5055 clear = wpabuf_alloc(clear_len);
60239f60
JM
5056 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
5057#ifdef CONFIG_TESTING_OPTIONS
5058 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
acdf703d 5059 attr_len += 5;
60239f60
JM
5060#endif /* CONFIG_TESTING_OPTIONS */
5061 msg = wpabuf_alloc(attr_len);
461d39af
JM
5062 if (!clear || !msg)
5063 goto fail;
5064
f411ad1b
JM
5065#ifdef CONFIG_TESTING_OPTIONS
5066 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
5067 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
5068 goto skip_e_nonce;
5069 }
af7f10fc
JM
5070 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
5071 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
5072 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5073 wpabuf_put_le16(clear, e_nonce_len);
5074 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
5075 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
5076 goto skip_e_nonce;
5077 }
f411ad1b
JM
5078 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
5079 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
5080 goto skip_wrapped_data;
5081 }
5082#endif /* CONFIG_TESTING_OPTIONS */
5083
461d39af
JM
5084 /* E-nonce */
5085 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5086 wpabuf_put_le16(clear, e_nonce_len);
5087 wpabuf_put_data(clear, e_nonce, e_nonce_len);
5088
f411ad1b
JM
5089#ifdef CONFIG_TESTING_OPTIONS
5090skip_e_nonce:
5091 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
5092 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
5093 goto skip_config_obj;
5094 }
5095#endif /* CONFIG_TESTING_OPTIONS */
5096
461d39af
JM
5097 if (conf) {
5098 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5099 wpabuf_put_le16(clear, wpabuf_len(conf));
5100 wpabuf_put_buf(clear, conf);
461d39af 5101 }
7eb06a33
JM
5102 if (auth->peer_version >= 2 && conf2) {
5103 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5104 wpabuf_put_le16(clear, wpabuf_len(conf2));
5105 wpabuf_put_buf(clear, conf2);
5106 } else if (conf2) {
5107 wpa_printf(MSG_DEBUG,
5108 "DPP: Second Config Object available, but peer does not support more than one");
5109 }
461d39af 5110
b10e01a7
JM
5111 if (auth->peer_version >= 2 && auth->send_conn_status && !ap) {
5112 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
5113 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
5114 wpabuf_put_le16(clear, 0);
5115 }
5116
f411ad1b
JM
5117#ifdef CONFIG_TESTING_OPTIONS
5118skip_config_obj:
5119 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
5120 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
5121 goto skip_status;
5122 }
af7f10fc
JM
5123 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
5124 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
5125 status = 255;
5126 }
f411ad1b
JM
5127#endif /* CONFIG_TESTING_OPTIONS */
5128
461d39af 5129 /* DPP Status */
56f24d1d 5130 dpp_build_attr_status(msg, status);
461d39af 5131
f411ad1b
JM
5132#ifdef CONFIG_TESTING_OPTIONS
5133skip_status:
5134#endif /* CONFIG_TESTING_OPTIONS */
5135
461d39af
JM
5136 addr[0] = wpabuf_head(msg);
5137 len[0] = wpabuf_len(msg);
5138 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5139
5140 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
5141 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5142 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5143
5144 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
5145 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
5146 wpabuf_head(clear), wpabuf_len(clear),
5147 1, addr, len, wrapped) < 0)
5148 goto fail;
5149 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5150 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
461d39af 5151
60239f60
JM
5152#ifdef CONFIG_TESTING_OPTIONS
5153 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
5154 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 5155 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 5156 }
f411ad1b 5157skip_wrapped_data:
60239f60
JM
5158#endif /* CONFIG_TESTING_OPTIONS */
5159
461d39af
JM
5160 wpa_hexdump_buf(MSG_DEBUG,
5161 "DPP: Configuration Response attributes", msg);
f411ad1b 5162out:
461d39af 5163 wpabuf_free(conf);
7eb06a33 5164 wpabuf_free(conf2);
461d39af 5165 wpabuf_free(clear);
f411ad1b
JM
5166
5167 return msg;
5168fail:
461d39af 5169 wpabuf_free(msg);
f411ad1b
JM
5170 msg = NULL;
5171 goto out;
461d39af
JM
5172}
5173
5174
5175struct wpabuf *
5176dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
5177 size_t attr_len)
5178{
5179 const u8 *wrapped_data, *e_nonce, *config_attr;
5180 u16 wrapped_data_len, e_nonce_len, config_attr_len;
5181 u8 *unwrapped = NULL;
5182 size_t unwrapped_len = 0;
5183 struct wpabuf *resp = NULL;
5184 struct json_token *root = NULL, *token;
5185 int ap;
5186
34603767
JM
5187#ifdef CONFIG_TESTING_OPTIONS
5188 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
5189 wpa_printf(MSG_INFO,
5190 "DPP: TESTING - stop at Config Request");
5191 return NULL;
5192 }
5193#endif /* CONFIG_TESTING_OPTIONS */
5194
461d39af 5195 if (dpp_check_attrs(attr_start, attr_len) < 0) {
8c99e626 5196 dpp_auth_fail(auth, "Invalid attribute in config request");
461d39af
JM
5197 return NULL;
5198 }
5199
5200 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
5201 &wrapped_data_len);
5202 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
8c99e626
JM
5203 dpp_auth_fail(auth,
5204 "Missing or invalid required Wrapped Data attribute");
461d39af
JM
5205 return NULL;
5206 }
5207
5208 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5209 wrapped_data, wrapped_data_len);
5210 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5211 unwrapped = os_malloc(unwrapped_len);
5212 if (!unwrapped)
5213 return NULL;
5214 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5215 wrapped_data, wrapped_data_len,
5216 0, NULL, NULL, unwrapped) < 0) {
8c99e626 5217 dpp_auth_fail(auth, "AES-SIV decryption failed");
461d39af
JM
5218 goto fail;
5219 }
5220 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5221 unwrapped, unwrapped_len);
5222
5223 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8c99e626 5224 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
461d39af
JM
5225 goto fail;
5226 }
5227
5228 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5229 DPP_ATTR_ENROLLEE_NONCE,
5230 &e_nonce_len);
5231 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8c99e626
JM
5232 dpp_auth_fail(auth,
5233 "Missing or invalid Enrollee Nonce attribute");
461d39af
JM
5234 goto fail;
5235 }
5236 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
22f90b32 5237 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
461d39af
JM
5238
5239 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
5240 DPP_ATTR_CONFIG_ATTR_OBJ,
5241 &config_attr_len);
5242 if (!config_attr) {
8c99e626
JM
5243 dpp_auth_fail(auth,
5244 "Missing or invalid Config Attributes attribute");
461d39af
JM
5245 goto fail;
5246 }
5247 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
5248 config_attr, config_attr_len);
5249
5250 root = json_parse((const char *) config_attr, config_attr_len);
5251 if (!root) {
8c99e626 5252 dpp_auth_fail(auth, "Could not parse Config Attributes");
461d39af
JM
5253 goto fail;
5254 }
5255
5256 token = json_get_member(root, "name");
5257 if (!token || token->type != JSON_STRING) {
8c99e626 5258 dpp_auth_fail(auth, "No Config Attributes - name");
461d39af
JM
5259 goto fail;
5260 }
5261 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
5262
5263 token = json_get_member(root, "wi-fi_tech");
5264 if (!token || token->type != JSON_STRING) {
8c99e626 5265 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
461d39af
JM
5266 goto fail;
5267 }
5268 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
5269 if (os_strcmp(token->string, "infra") != 0) {
5270 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
5271 token->string);
8c99e626 5272 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
461d39af
JM
5273 goto fail;
5274 }
5275
5276 token = json_get_member(root, "netRole");
5277 if (!token || token->type != JSON_STRING) {
8c99e626 5278 dpp_auth_fail(auth, "No Config Attributes - netRole");
461d39af
JM
5279 goto fail;
5280 }
5281 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
5282 if (os_strcmp(token->string, "sta") == 0) {
5283 ap = 0;
5284 } else if (os_strcmp(token->string, "ap") == 0) {
5285 ap = 1;
5286 } else {
5287 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
5288 token->string);
8c99e626 5289 dpp_auth_fail(auth, "Unsupported netRole");
461d39af
JM
5290 goto fail;
5291 }
5292
5a5639b0
JM
5293 token = json_get_member(root, "mudurl");
5294 if (token && token->type == JSON_STRING)
5295 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
5296
f32aa244
JM
5297 token = json_get_member(root, "bandSupport");
5298 if (token && token->type == JSON_ARRAY) {
5299 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
5300 token = token->child;
5301 while (token) {
5302 if (token->type != JSON_NUMBER)
5303 wpa_printf(MSG_DEBUG,
5304 "DPP: Invalid bandSupport array member type");
5305 else
5306 wpa_printf(MSG_DEBUG,
5307 "DPP: Supported global operating class: %d",
5308 token->number);
5309 token = token->sibling;
5310 }
5311 }
5312
461d39af
JM
5313 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
5314
5315fail:
5316 json_free(root);
5317 os_free(unwrapped);
5318 return resp;
5319}
5320
5321
5322static struct wpabuf *
6095b479
JM
5323dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
5324 const u8 *prot_hdr, u16 prot_hdr_len,
461d39af
JM
5325 const EVP_MD **ret_md)
5326{
5327 struct json_token *root, *token;
5328 struct wpabuf *kid = NULL;
5329
5330 root = json_parse((const char *) prot_hdr, prot_hdr_len);
5331 if (!root) {
5332 wpa_printf(MSG_DEBUG,
5333 "DPP: JSON parsing failed for JWS Protected Header");
5334 goto fail;
5335 }
5336
5337 if (root->type != JSON_OBJECT) {
5338 wpa_printf(MSG_DEBUG,
5339 "DPP: JWS Protected Header root is not an object");
5340 goto fail;
5341 }
5342
5343 token = json_get_member(root, "typ");
5344 if (!token || token->type != JSON_STRING) {
5345 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
5346 goto fail;
5347 }
5348 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
5349 token->string);
5350 if (os_strcmp(token->string, "dppCon") != 0) {
5351 wpa_printf(MSG_DEBUG,
5352 "DPP: Unsupported JWS Protected Header typ=%s",
5353 token->string);
5354 goto fail;
5355 }
5356
5357 token = json_get_member(root, "alg");
5358 if (!token || token->type != JSON_STRING) {
5359 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
5360 goto fail;
5361 }
5362 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
5363 token->string);
6095b479
JM
5364 if (os_strcmp(token->string, curve->jws_alg) != 0) {
5365 wpa_printf(MSG_DEBUG,
5366 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5367 token->string, curve->jws_alg);
5368 goto fail;
5369 }
31f03cb0
JM
5370 if (os_strcmp(token->string, "ES256") == 0 ||
5371 os_strcmp(token->string, "BS256") == 0)
461d39af 5372 *ret_md = EVP_sha256();
31f03cb0
JM
5373 else if (os_strcmp(token->string, "ES384") == 0 ||
5374 os_strcmp(token->string, "BS384") == 0)
461d39af 5375 *ret_md = EVP_sha384();
31f03cb0
JM
5376 else if (os_strcmp(token->string, "ES512") == 0 ||
5377 os_strcmp(token->string, "BS512") == 0)
461d39af
JM
5378 *ret_md = EVP_sha512();
5379 else
5380 *ret_md = NULL;
5381 if (!*ret_md) {
5382 wpa_printf(MSG_DEBUG,
5383 "DPP: Unsupported JWS Protected Header alg=%s",
5384 token->string);
5385 goto fail;
5386 }
5387
5388 kid = json_get_member_base64url(root, "kid");
5389 if (!kid) {
5390 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
5391 goto fail;
5392 }
5393 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
5394 kid);
5395
5396fail:
5397 json_free(root);
5398 return kid;
5399}
5400
5401
52d469de 5402static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
461d39af
JM
5403 struct json_token *cred)
5404{
5405 struct json_token *pass, *psk_hex;
461d39af
JM
5406
5407 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
5408
5409 pass = json_get_member(cred, "pass");
5410 psk_hex = json_get_member(cred, "psk_hex");
5411
5412 if (pass && pass->type == JSON_STRING) {
8528994e
JM
5413 size_t len = os_strlen(pass->string);
5414
461d39af 5415 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
8528994e
JM
5416 pass->string, len);
5417 if (len < 8 || len > 63)
5418 return -1;
52d469de
JM
5419 os_strlcpy(conf->passphrase, pass->string,
5420 sizeof(conf->passphrase));
461d39af 5421 } else if (psk_hex && psk_hex->type == JSON_STRING) {
52d469de 5422 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
5dd745b7
JM
5423 wpa_printf(MSG_DEBUG,
5424 "DPP: Unexpected psk_hex with akm=sae");
5425 return -1;
5426 }
8528994e 5427 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
52d469de 5428 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
461d39af
JM
5429 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
5430 return -1;
5431 }
8528994e 5432 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
52d469de
JM
5433 conf->psk, PMK_LEN);
5434 conf->psk_set = 1;
461d39af
JM
5435 } else {
5436 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
5437 return -1;
5438 }
5439
52d469de 5440 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
5dd745b7
JM
5441 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
5442 return -1;
5443 }
5444
461d39af
JM
5445 return 0;
5446}
5447
5448
5449static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
5450 const struct dpp_curve_params **key_curve)
5451{
5452 struct json_token *token;
5453 const struct dpp_curve_params *curve;
5454 struct wpabuf *x = NULL, *y = NULL;
5455 EC_GROUP *group;
5456 EVP_PKEY *pkey = NULL;
5457
5458 token = json_get_member(jwk, "kty");
5459 if (!token || token->type != JSON_STRING) {
5460 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
5461 goto fail;
5462 }
5463 if (os_strcmp(token->string, "EC") != 0) {
06e62e11 5464 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
461d39af
JM
5465 token->string);
5466 goto fail;
5467 }
5468
5469 token = json_get_member(jwk, "crv");
5470 if (!token || token->type != JSON_STRING) {
5471 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
5472 goto fail;
5473 }
5474 curve = dpp_get_curve_jwk_crv(token->string);
5475 if (!curve) {
5476 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
5477 token->string);
5478 goto fail;
5479 }
5480
5481 x = json_get_member_base64url(jwk, "x");
5482 if (!x) {
5483 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
5484 goto fail;
5485 }
f1f4fa79 5486 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
461d39af
JM
5487 if (wpabuf_len(x) != curve->prime_len) {
5488 wpa_printf(MSG_DEBUG,
f1f4fa79 5489 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
461d39af
JM
5490 (unsigned int) wpabuf_len(x),
5491 (unsigned int) curve->prime_len, curve->name);
5492 goto fail;
5493 }
5494
5495 y = json_get_member_base64url(jwk, "y");
5496 if (!y) {
5497 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
5498 goto fail;
5499 }
f1f4fa79 5500 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
461d39af
JM
5501 if (wpabuf_len(y) != curve->prime_len) {
5502 wpa_printf(MSG_DEBUG,
f1f4fa79 5503 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
461d39af
JM
5504 (unsigned int) wpabuf_len(y),
5505 (unsigned int) curve->prime_len, curve->name);
5506 goto fail;
5507 }
5508
5509 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5510 if (!group) {
5511 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
5512 goto fail;
5513 }
5514
5515 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
5516 wpabuf_len(x));
57ec74ea 5517 EC_GROUP_free(group);
461d39af
JM
5518 *key_curve = curve;
5519
5520fail:
5521 wpabuf_free(x);
5522 wpabuf_free(y);
5523
5524 return pkey;
5525}
5526
5527
5528int dpp_key_expired(const char *timestamp, os_time_t *expiry)
5529{
5530 struct os_time now;
5531 unsigned int year, month, day, hour, min, sec;
5532 os_time_t utime;
5533 const char *pos;
5534
5535 /* ISO 8601 date and time:
5536 * <date>T<time>
5537 * YYYY-MM-DDTHH:MM:SSZ
5538 * YYYY-MM-DDTHH:MM:SS+03:00
5539 */
5540 if (os_strlen(timestamp) < 19) {
5541 wpa_printf(MSG_DEBUG,
5542 "DPP: Too short timestamp - assume expired key");
5543 return 1;
5544 }
5545 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
5546 &year, &month, &day, &hour, &min, &sec) != 6) {
5547 wpa_printf(MSG_DEBUG,
5548 "DPP: Failed to parse expiration day - assume expired key");
5549 return 1;
5550 }
5551
5552 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
5553 wpa_printf(MSG_DEBUG,
5554 "DPP: Invalid date/time information - assume expired key");
5555 return 1;
5556 }
5557
5558 pos = timestamp + 19;
5559 if (*pos == 'Z' || *pos == '\0') {
5560 /* In UTC - no need to adjust */
5561 } else if (*pos == '-' || *pos == '+') {
5562 int items;
5563
5564 /* Adjust local time to UTC */
5565 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
5566 if (items < 1) {
5567 wpa_printf(MSG_DEBUG,
5568 "DPP: Invalid time zone designator (%s) - assume expired key",
5569 pos);
5570 return 1;
5571 }
5572 if (*pos == '-')
5573 utime += 3600 * hour;
5574 if (*pos == '+')
5575 utime -= 3600 * hour;
5576 if (items > 1) {
5577 if (*pos == '-')
5578 utime += 60 * min;
5579 if (*pos == '+')
5580 utime -= 60 * min;
5581 }
5582 } else {
5583 wpa_printf(MSG_DEBUG,
5584 "DPP: Invalid time zone designator (%s) - assume expired key",
5585 pos);
5586 return 1;
5587 }
5588 if (expiry)
5589 *expiry = utime;
5590
5591 if (os_get_time(&now) < 0) {
5592 wpa_printf(MSG_DEBUG,
5593 "DPP: Cannot get current time - assume expired key");
5594 return 1;
5595 }
5596
5597 if (now.sec > utime) {
5598 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
5599 utime, now.sec);
5600 return 1;
5601 }
5602
5603 return 0;
5604}
5605
5606
5607static int dpp_parse_connector(struct dpp_authentication *auth,
52d469de 5608 struct dpp_config_obj *conf,
461d39af
JM
5609 const unsigned char *payload,
5610 u16 payload_len)
5611{
a4bf0078 5612 struct json_token *root, *groups, *netkey, *token;
461d39af
JM
5613 int ret = -1;
5614 EVP_PKEY *key = NULL;
5615 const struct dpp_curve_params *curve;
5616 unsigned int rules = 0;
5617
5618 root = json_parse((const char *) payload, payload_len);
5619 if (!root) {
5620 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5621 goto fail;
5622 }
5623
5624 groups = json_get_member(root, "groups");
5625 if (!groups || groups->type != JSON_ARRAY) {
5626 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
5627 goto skip_groups;
5628 }
5629 for (token = groups->child; token; token = token->sibling) {
5630 struct json_token *id, *role;
5631
5632 id = json_get_member(token, "groupId");
5633 if (!id || id->type != JSON_STRING) {
5634 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
5635 goto fail;
5636 }
5637
5638 role = json_get_member(token, "netRole");
5639 if (!role || role->type != JSON_STRING) {
5640 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
5641 goto fail;
5642 }
5643 wpa_printf(MSG_DEBUG,
5644 "DPP: connector group: groupId='%s' netRole='%s'",
5645 id->string, role->string);
5646 rules++;
5647 }
5648skip_groups:
5649
461d39af
JM
5650 if (!rules) {
5651 wpa_printf(MSG_DEBUG,
a4bf0078 5652 "DPP: Connector includes no groups");
461d39af
JM
5653 goto fail;
5654 }
5655
5656 token = json_get_member(root, "expiry");
5657 if (!token || token->type != JSON_STRING) {
5658 wpa_printf(MSG_DEBUG,
5659 "DPP: No expiry string found - connector does not expire");
5660 } else {
5661 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5662 if (dpp_key_expired(token->string,
5663 &auth->net_access_key_expiry)) {
5664 wpa_printf(MSG_DEBUG,
5665 "DPP: Connector (netAccessKey) has expired");
5666 goto fail;
5667 }
5668 }
5669
5670 netkey = json_get_member(root, "netAccessKey");
5671 if (!netkey || netkey->type != JSON_OBJECT) {
5672 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
5673 goto fail;
5674 }
5675
5676 key = dpp_parse_jwk(netkey, &curve);
5677 if (!key)
5678 goto fail;
5679 dpp_debug_print_key("DPP: Received netAccessKey", key);
5680
5681 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
5682 wpa_printf(MSG_DEBUG,
5683 "DPP: netAccessKey in connector does not match own protocol key");
5684#ifdef CONFIG_TESTING_OPTIONS
5685 if (auth->ignore_netaccesskey_mismatch) {
5686 wpa_printf(MSG_DEBUG,
5687 "DPP: TESTING - skip netAccessKey mismatch");
5688 } else {
5689 goto fail;
5690 }
5691#else /* CONFIG_TESTING_OPTIONS */
5692 goto fail;
5693#endif /* CONFIG_TESTING_OPTIONS */
5694 }
5695
5696 ret = 0;
5697fail:
5698 EVP_PKEY_free(key);
5699 json_free(root);
5700 return ret;
5701}
5702
5703
5704static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
5705{
5706 struct wpabuf *uncomp;
5707 int res;
5708 u8 hash[SHA256_MAC_LEN];
5709 const u8 *addr[1];
5710 size_t len[1];
5711
5712 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
5713 return -1;
5714 uncomp = dpp_get_pubkey_point(pub, 1);
5715 if (!uncomp)
5716 return -1;
5717 addr[0] = wpabuf_head(uncomp);
5718 len[0] = wpabuf_len(uncomp);
5719 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
5720 addr[0], len[0]);
5721 res = sha256_vector(1, addr, len, hash);
5722 wpabuf_free(uncomp);
5723 if (res < 0)
5724 return -1;
5725 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
5726 wpa_printf(MSG_DEBUG,
5727 "DPP: Received hash value does not match calculated public key hash value");
5728 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
5729 hash, SHA256_MAC_LEN);
5730 return -1;
5731 }
5732 return 0;
5733}
5734
5735
52d469de 5736static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
461d39af
JM
5737{
5738 unsigned char *der = NULL;
5739 int der_len;
5740
5741 der_len = i2d_PUBKEY(csign, &der);
5742 if (der_len <= 0)
5743 return;
52d469de
JM
5744 wpabuf_free(conf->c_sign_key);
5745 conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
461d39af
JM
5746 OPENSSL_free(der);
5747}
5748
5749
52d469de
JM
5750static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
5751 struct dpp_config_obj *conf)
461d39af
JM
5752{
5753 unsigned char *der = NULL;
5754 int der_len;
5755 EC_KEY *eckey;
5756
5757 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
5758 if (!eckey)
5759 return;
5760
5761 der_len = i2d_ECPrivateKey(eckey, &der);
5762 if (der_len <= 0) {
5763 EC_KEY_free(eckey);
5764 return;
5765 }
5766 wpabuf_free(auth->net_access_key);
5767 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
5768 OPENSSL_free(der);
5769 EC_KEY_free(eckey);
5770}
5771
5772
5773struct dpp_signed_connector_info {
5774 unsigned char *payload;
5775 size_t payload_len;
5776};
5777
e85b6601 5778static enum dpp_status_error
461d39af
JM
5779dpp_process_signed_connector(struct dpp_signed_connector_info *info,
5780 EVP_PKEY *csign_pub, const char *connector)
5781{
e85b6601 5782 enum dpp_status_error ret = 255;
461d39af
JM
5783 const char *pos, *end, *signed_start, *signed_end;
5784 struct wpabuf *kid = NULL;
5785 unsigned char *prot_hdr = NULL, *signature = NULL;
5786 size_t prot_hdr_len = 0, signature_len = 0;
5787 const EVP_MD *sign_md = NULL;
5788 unsigned char *der = NULL;
5789 int der_len;
5790 int res;
5791 EVP_MD_CTX *md_ctx = NULL;
5792 ECDSA_SIG *sig = NULL;
5793 BIGNUM *r = NULL, *s = NULL;
6095b479
JM
5794 const struct dpp_curve_params *curve;
5795 EC_KEY *eckey;
5796 const EC_GROUP *group;
5797 int nid;
461d39af 5798
6095b479
JM
5799 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
5800 if (!eckey)
5801 goto fail;
5802 group = EC_KEY_get0_group(eckey);
5803 if (!group)
5804 goto fail;
5805 nid = EC_GROUP_get_curve_name(group);
5806 curve = dpp_get_curve_nid(nid);
5807 if (!curve)
5808 goto fail;
5809 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
461d39af
JM
5810 os_memset(info, 0, sizeof(*info));
5811
5812 signed_start = pos = connector;
5813 end = os_strchr(pos, '.');
5814 if (!end) {
5815 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
e85b6601 5816 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5817 goto fail;
5818 }
b2260842 5819 prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
461d39af
JM
5820 if (!prot_hdr) {
5821 wpa_printf(MSG_DEBUG,
5822 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
e85b6601 5823 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5824 goto fail;
5825 }
5826 wpa_hexdump_ascii(MSG_DEBUG,
5827 "DPP: signedConnector - JWS Protected Header",
5828 prot_hdr, prot_hdr_len);
6095b479 5829 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
e85b6601
JM
5830 if (!kid) {
5831 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af 5832 goto fail;
e85b6601 5833 }
461d39af
JM
5834 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
5835 wpa_printf(MSG_DEBUG,
5836 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5837 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
e85b6601 5838 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5839 goto fail;
5840 }
5841
5842 pos = end + 1;
5843 end = os_strchr(pos, '.');
5844 if (!end) {
5845 wpa_printf(MSG_DEBUG,
5846 "DPP: Missing dot(2) in signedConnector");
e85b6601 5847 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5848 goto fail;
5849 }
5850 signed_end = end - 1;
b2260842 5851 info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
461d39af
JM
5852 if (!info->payload) {
5853 wpa_printf(MSG_DEBUG,
5854 "DPP: Failed to base64url decode signedConnector JWS Payload");
e85b6601 5855 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5856 goto fail;
5857 }
5858 wpa_hexdump_ascii(MSG_DEBUG,
5859 "DPP: signedConnector - JWS Payload",
5860 info->payload, info->payload_len);
5861 pos = end + 1;
b2260842 5862 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
461d39af
JM
5863 if (!signature) {
5864 wpa_printf(MSG_DEBUG,
5865 "DPP: Failed to base64url decode signedConnector signature");
e85b6601 5866 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5867 goto fail;
5868 }
5869 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5870 signature, signature_len);
5871
e85b6601
JM
5872 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5873 ret = DPP_STATUS_NO_MATCH;
461d39af 5874 goto fail;
e85b6601 5875 }
461d39af
JM
5876
5877 if (signature_len & 0x01) {
5878 wpa_printf(MSG_DEBUG,
5879 "DPP: Unexpected signedConnector signature length (%d)",
5880 (int) signature_len);
e85b6601 5881 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5882 goto fail;
5883 }
5884
5885 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5886 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5887 r = BN_bin2bn(signature, signature_len / 2, NULL);
5888 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
5889 sig = ECDSA_SIG_new();
5890 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
5891 goto fail;
5892 r = NULL;
5893 s = NULL;
5894
5895 der_len = i2d_ECDSA_SIG(sig, &der);
5896 if (der_len <= 0) {
5897 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
5898 goto fail;
5899 }
5900 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
5901 md_ctx = EVP_MD_CTX_create();
5902 if (!md_ctx)
5903 goto fail;
5904
5905 ERR_clear_error();
5906 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
5907 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
5908 ERR_error_string(ERR_get_error(), NULL));
5909 goto fail;
5910 }
5911 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
5912 signed_end - signed_start + 1) != 1) {
5913 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
5914 ERR_error_string(ERR_get_error(), NULL));
5915 goto fail;
5916 }
5917 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
5918 if (res != 1) {
5919 wpa_printf(MSG_DEBUG,
5920 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5921 res, ERR_error_string(ERR_get_error(), NULL));
e85b6601 5922 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
5923 goto fail;
5924 }
5925
e85b6601 5926 ret = DPP_STATUS_OK;
461d39af 5927fail:
6095b479 5928 EC_KEY_free(eckey);
461d39af
JM
5929 EVP_MD_CTX_destroy(md_ctx);
5930 os_free(prot_hdr);
5931 wpabuf_free(kid);
5932 os_free(signature);
5933 ECDSA_SIG_free(sig);
5934 BN_free(r);
5935 BN_free(s);
5936 OPENSSL_free(der);
5937 return ret;
5938}
5939
5940
5941static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
52d469de 5942 struct dpp_config_obj *conf,
461d39af
JM
5943 struct json_token *cred)
5944{
5945 struct dpp_signed_connector_info info;
5946 struct json_token *token, *csign;
5947 int ret = -1;
5948 EVP_PKEY *csign_pub = NULL;
5949 const struct dpp_curve_params *key_curve = NULL;
5950 const char *signed_connector;
5951
5952 os_memset(&info, 0, sizeof(info));
5953
52d469de 5954 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
18015fc8
JM
5955 wpa_printf(MSG_DEBUG,
5956 "DPP: Legacy credential included in Connector credential");
52d469de 5957 if (dpp_parse_cred_legacy(conf, cred) < 0)
18015fc8
JM
5958 return -1;
5959 }
5960
461d39af
JM
5961 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5962
5963 csign = json_get_member(cred, "csign");
5964 if (!csign || csign->type != JSON_OBJECT) {
5965 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5966 goto fail;
5967 }
5968
5969 csign_pub = dpp_parse_jwk(csign, &key_curve);
5970 if (!csign_pub) {
5971 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5972 goto fail;
5973 }
5974 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5975
461d39af
JM
5976 token = json_get_member(cred, "signedConnector");
5977 if (!token || token->type != JSON_STRING) {
5978 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5979 goto fail;
5980 }
5981 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5982 token->string, os_strlen(token->string));
5983 signed_connector = token->string;
5984
5985 if (os_strchr(signed_connector, '"') ||
5986 os_strchr(signed_connector, '\n')) {
5987 wpa_printf(MSG_DEBUG,
5988 "DPP: Unexpected character in signedConnector");
5989 goto fail;
5990 }
5991
5992 if (dpp_process_signed_connector(&info, csign_pub,
e85b6601 5993 signed_connector) != DPP_STATUS_OK)
461d39af
JM
5994 goto fail;
5995
52d469de
JM
5996 if (dpp_parse_connector(auth, conf,
5997 info.payload, info.payload_len) < 0) {
461d39af
JM
5998 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5999 goto fail;
6000 }
6001
52d469de
JM
6002 os_free(conf->connector);
6003 conf->connector = os_strdup(signed_connector);
461d39af 6004
52d469de
JM
6005 dpp_copy_csign(conf, csign_pub);
6006 dpp_copy_netaccesskey(auth, conf);
461d39af
JM
6007
6008 ret = 0;
6009fail:
6010 EVP_PKEY_free(csign_pub);
6011 os_free(info.payload);
6012 return ret;
6013}
6014
6015
5dd745b7
JM
6016const char * dpp_akm_str(enum dpp_akm akm)
6017{
6018 switch (akm) {
6019 case DPP_AKM_DPP:
6020 return "dpp";
6021 case DPP_AKM_PSK:
6022 return "psk";
6023 case DPP_AKM_SAE:
6024 return "sae";
6025 case DPP_AKM_PSK_SAE:
6026 return "psk+sae";
18015fc8
JM
6027 case DPP_AKM_SAE_DPP:
6028 return "dpp+sae";
6029 case DPP_AKM_PSK_SAE_DPP:
6030 return "dpp+psk+sae";
5dd745b7
JM
6031 default:
6032 return "??";
6033 }
6034}
6035
6036
68fea960
JM
6037const char * dpp_akm_selector_str(enum dpp_akm akm)
6038{
6039 switch (akm) {
6040 case DPP_AKM_DPP:
6041 return "506F9A02";
6042 case DPP_AKM_PSK:
6043 return "000FAC02+000FAC06";
6044 case DPP_AKM_SAE:
6045 return "000FAC08";
6046 case DPP_AKM_PSK_SAE:
6047 return "000FAC02+000FAC06+000FAC08";
6048 case DPP_AKM_SAE_DPP:
6049 return "506F9A02+000FAC08";
6050 case DPP_AKM_PSK_SAE_DPP:
6051 return "506F9A02+000FAC08+000FAC02+000FAC06";
6052 default:
6053 return "??";
6054 }
6055}
6056
6057
5dd745b7
JM
6058static enum dpp_akm dpp_akm_from_str(const char *akm)
6059{
b719a156
JM
6060 const char *pos;
6061 int dpp = 0, psk = 0, sae = 0;
6062
5dd745b7
JM
6063 if (os_strcmp(akm, "psk") == 0)
6064 return DPP_AKM_PSK;
6065 if (os_strcmp(akm, "sae") == 0)
6066 return DPP_AKM_SAE;
6067 if (os_strcmp(akm, "psk+sae") == 0)
6068 return DPP_AKM_PSK_SAE;
6069 if (os_strcmp(akm, "dpp") == 0)
6070 return DPP_AKM_DPP;
18015fc8
JM
6071 if (os_strcmp(akm, "dpp+sae") == 0)
6072 return DPP_AKM_SAE_DPP;
6073 if (os_strcmp(akm, "dpp+psk+sae") == 0)
6074 return DPP_AKM_PSK_SAE_DPP;
b719a156
JM
6075
6076 pos = akm;
6077 while (*pos) {
6078 if (os_strlen(pos) < 8)
6079 break;
6080 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
6081 dpp = 1;
6082 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
6083 psk = 1;
6084 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
6085 psk = 1;
6086 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
6087 sae = 1;
6088 pos += 8;
6089 if (*pos != '+')
6090 break;
6091 pos++;
6092 }
6093
6094 if (dpp && psk && sae)
6095 return DPP_AKM_PSK_SAE_DPP;
6096 if (dpp && sae)
6097 return DPP_AKM_SAE_DPP;
6098 if (dpp)
6099 return DPP_AKM_DPP;
6100 if (psk && sae)
6101 return DPP_AKM_PSK_SAE;
6102 if (sae)
6103 return DPP_AKM_SAE;
6104 if (psk)
6105 return DPP_AKM_PSK;
6106
5dd745b7
JM
6107 return DPP_AKM_UNKNOWN;
6108}
6109
6110
461d39af
JM
6111static int dpp_parse_conf_obj(struct dpp_authentication *auth,
6112 const u8 *conf_obj, u16 conf_obj_len)
6113{
6114 int ret = -1;
6115 struct json_token *root, *token, *discovery, *cred;
52d469de 6116 struct dpp_config_obj *conf;
461d39af
JM
6117
6118 root = json_parse((const char *) conf_obj, conf_obj_len);
6119 if (!root)
6120 return -1;
6121 if (root->type != JSON_OBJECT) {
8c99e626 6122 dpp_auth_fail(auth, "JSON root is not an object");
461d39af
JM
6123 goto fail;
6124 }
6125
6126 token = json_get_member(root, "wi-fi_tech");
6127 if (!token || token->type != JSON_STRING) {
8c99e626 6128 dpp_auth_fail(auth, "No wi-fi_tech string value found");
461d39af
JM
6129 goto fail;
6130 }
6131 if (os_strcmp(token->string, "infra") != 0) {
6132 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
6133 token->string);
8c99e626 6134 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
461d39af
JM
6135 goto fail;
6136 }
6137
6138 discovery = json_get_member(root, "discovery");
6139 if (!discovery || discovery->type != JSON_OBJECT) {
8c99e626 6140 dpp_auth_fail(auth, "No discovery object in JSON");
461d39af
JM
6141 goto fail;
6142 }
6143
6144 token = json_get_member(discovery, "ssid");
6145 if (!token || token->type != JSON_STRING) {
8c99e626 6146 dpp_auth_fail(auth, "No discovery::ssid string value found");
461d39af
JM
6147 goto fail;
6148 }
6149 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
6150 token->string, os_strlen(token->string));
6151 if (os_strlen(token->string) > SSID_MAX_LEN) {
8c99e626 6152 dpp_auth_fail(auth, "Too long discovery::ssid string value");
461d39af
JM
6153 goto fail;
6154 }
52d469de
JM
6155
6156 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
6157 wpa_printf(MSG_DEBUG,
6158 "DPP: No room for this many Config Objects - ignore this one");
6159 json_free(root);
6160 return 0;
6161 }
6162 conf = &auth->conf_obj[auth->num_conf_obj++];
6163
6164 conf->ssid_len = os_strlen(token->string);
6165 os_memcpy(conf->ssid, token->string, conf->ssid_len);
461d39af
JM
6166
6167 cred = json_get_member(root, "cred");
6168 if (!cred || cred->type != JSON_OBJECT) {
8c99e626 6169 dpp_auth_fail(auth, "No cred object in JSON");
461d39af
JM
6170 goto fail;
6171 }
6172
6173 token = json_get_member(cred, "akm");
6174 if (!token || token->type != JSON_STRING) {
8c99e626 6175 dpp_auth_fail(auth, "No cred::akm string value found");
461d39af
JM
6176 goto fail;
6177 }
52d469de 6178 conf->akm = dpp_akm_from_str(token->string);
5dd745b7 6179
52d469de
JM
6180 if (dpp_akm_legacy(conf->akm)) {
6181 if (dpp_parse_cred_legacy(conf, cred) < 0)
461d39af 6182 goto fail;
52d469de
JM
6183 } else if (dpp_akm_dpp(conf->akm)) {
6184 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
461d39af
JM
6185 goto fail;
6186 } else {
6187 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
6188 token->string);
8c99e626 6189 dpp_auth_fail(auth, "Unsupported akm");
461d39af
JM
6190 goto fail;
6191 }
6192
6193 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
6194 ret = 0;
6195fail:
6196 json_free(root);
6197 return ret;
6198}
6199
6200
6201int dpp_conf_resp_rx(struct dpp_authentication *auth,
6202 const struct wpabuf *resp)
6203{
6204 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
6205 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
6206 const u8 *addr[1];
6207 size_t len[1];
6208 u8 *unwrapped = NULL;
6209 size_t unwrapped_len = 0;
6210 int ret = -1;
6211
22f90b32
JM
6212 auth->conf_resp_status = 255;
6213
461d39af 6214 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
8c99e626 6215 dpp_auth_fail(auth, "Invalid attribute in config response");
461d39af
JM
6216 return -1;
6217 }
6218
6219 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
6220 DPP_ATTR_WRAPPED_DATA,
6221 &wrapped_data_len);
6222 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
8c99e626
JM
6223 dpp_auth_fail(auth,
6224 "Missing or invalid required Wrapped Data attribute");
461d39af
JM
6225 return -1;
6226 }
6227
6228 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6229 wrapped_data, wrapped_data_len);
6230 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6231 unwrapped = os_malloc(unwrapped_len);
6232 if (!unwrapped)
6233 return -1;
6234
6235 addr[0] = wpabuf_head(resp);
6236 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
6237 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
6238
6239 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
6240 wrapped_data, wrapped_data_len,
6241 1, addr, len, unwrapped) < 0) {
8c99e626 6242 dpp_auth_fail(auth, "AES-SIV decryption failed");
461d39af
JM
6243 goto fail;
6244 }
6245 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6246 unwrapped, unwrapped_len);
6247
6248 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8c99e626 6249 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
461d39af
JM
6250 goto fail;
6251 }
6252
6253 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
6254 DPP_ATTR_ENROLLEE_NONCE,
6255 &e_nonce_len);
6256 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8c99e626
JM
6257 dpp_auth_fail(auth,
6258 "Missing or invalid Enrollee Nonce attribute");
461d39af
JM
6259 goto fail;
6260 }
6261 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
6262 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
8c99e626 6263 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
461d39af
JM
6264 goto fail;
6265 }
6266
6267 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
6268 DPP_ATTR_STATUS, &status_len);
6269 if (!status || status_len < 1) {
8c99e626
JM
6270 dpp_auth_fail(auth,
6271 "Missing or invalid required DPP Status attribute");
461d39af
JM
6272 goto fail;
6273 }
22f90b32 6274 auth->conf_resp_status = status[0];
461d39af
JM
6275 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
6276 if (status[0] != DPP_STATUS_OK) {
8c99e626 6277 dpp_auth_fail(auth, "Configurator rejected configuration");
461d39af
JM
6278 goto fail;
6279 }
6280
52d469de
JM
6281 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
6282 &conf_obj_len);
461d39af 6283 if (!conf_obj) {
8c99e626
JM
6284 dpp_auth_fail(auth,
6285 "Missing required Configuration Object attribute");
461d39af
JM
6286 goto fail;
6287 }
52d469de
JM
6288 while (conf_obj) {
6289 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
6290 conf_obj, conf_obj_len);
6291 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
6292 goto fail;
6293 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
6294 DPP_ATTR_CONFIG_OBJ,
6295 &conf_obj_len);
6296 }
461d39af 6297
16ef233b
JM
6298#ifdef CONFIG_DPP2
6299 status = dpp_get_attr(unwrapped, unwrapped_len,
6300 DPP_ATTR_SEND_CONN_STATUS, &status_len);
6301 if (status) {
6302 wpa_printf(MSG_DEBUG,
6303 "DPP: Configurator requested connection status result");
6304 auth->conn_status_requested = 1;
6305 }
6306#endif /* CONFIG_DPP2 */
6307
461d39af
JM
6308 ret = 0;
6309
6310fail:
6311 os_free(unwrapped);
6312 return ret;
6313}
6314
6315
22f90b32 6316#ifdef CONFIG_DPP2
cc839952 6317
22f90b32
JM
6318enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
6319 const u8 *hdr,
6320 const u8 *attr_start, size_t attr_len)
6321{
6322 const u8 *wrapped_data, *status, *e_nonce;
6323 u16 wrapped_data_len, status_len, e_nonce_len;
6324 const u8 *addr[2];
6325 size_t len[2];
6326 u8 *unwrapped = NULL;
6327 size_t unwrapped_len = 0;
6328 enum dpp_status_error ret = 256;
6329
6330 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
6331 &wrapped_data_len);
6332 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
6333 dpp_auth_fail(auth,
6334 "Missing or invalid required Wrapped Data attribute");
6335 goto fail;
6336 }
6337 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
6338 wrapped_data, wrapped_data_len);
6339
6340 attr_len = wrapped_data - 4 - attr_start;
6341
6342 addr[0] = hdr;
6343 len[0] = DPP_HDR_LEN;
6344 addr[1] = attr_start;
6345 len[1] = attr_len;
6346 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6347 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6348 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6349 wrapped_data, wrapped_data_len);
6350 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6351 unwrapped = os_malloc(unwrapped_len);
6352 if (!unwrapped)
6353 goto fail;
6354 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
6355 wrapped_data, wrapped_data_len,
6356 2, addr, len, unwrapped) < 0) {
6357 dpp_auth_fail(auth, "AES-SIV decryption failed");
6358 goto fail;
6359 }
6360 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6361 unwrapped, unwrapped_len);
6362
6363 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
6364 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
6365 goto fail;
6366 }
6367
6368 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
6369 DPP_ATTR_ENROLLEE_NONCE,
6370 &e_nonce_len);
6371 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
6372 dpp_auth_fail(auth,
6373 "Missing or invalid Enrollee Nonce attribute");
6374 goto fail;
6375 }
6376 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
6377 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
6378 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
6379 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
6380 auth->e_nonce, e_nonce_len);
6381 goto fail;
6382 }
6383
6384 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
6385 &status_len);
6386 if (!status || status_len < 1) {
6387 dpp_auth_fail(auth,
6388 "Missing or invalid required DPP Status attribute");
6389 goto fail;
6390 }
6391 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
6392 ret = status[0];
6393
6394fail:
6395 bin_clear_free(unwrapped, unwrapped_len);
6396 return ret;
6397}
22f90b32
JM
6398
6399
6400struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
6401 enum dpp_status_error status)
6402{
6403 struct wpabuf *msg, *clear;
6404 size_t nonce_len, clear_len, attr_len;
6405 const u8 *addr[2];
6406 size_t len[2];
6407 u8 *wrapped;
6408
6409 nonce_len = auth->curve->nonce_len;
6410 clear_len = 5 + 4 + nonce_len;
6411 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6412 clear = wpabuf_alloc(clear_len);
6413 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
6414 if (!clear || !msg)
3a6736fe 6415 goto fail;
22f90b32
JM
6416
6417 /* DPP Status */
6418 dpp_build_attr_status(clear, status);
6419
6420 /* E-nonce */
6421 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
6422 wpabuf_put_le16(clear, nonce_len);
6423 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
6424
6425 /* OUI, OUI type, Crypto Suite, DPP frame type */
6426 addr[0] = wpabuf_head_u8(msg) + 2;
6427 len[0] = 3 + 1 + 1 + 1;
6428 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6429
6430 /* Attributes before Wrapped Data (none) */
6431 addr[1] = wpabuf_put(msg, 0);
6432 len[1] = 0;
6433 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6434
6435 /* Wrapped Data */
6436 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6437 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6438 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6439
6440 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6441 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
6442 wpabuf_head(clear), wpabuf_len(clear),
6443 2, addr, len, wrapped) < 0)
6444 goto fail;
6445
6446 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
6447 wpabuf_free(clear);
6448 return msg;
6449fail:
6450 wpabuf_free(clear);
6451 wpabuf_free(msg);
6452 return NULL;
6453}
6454
b10e01a7
JM
6455
6456static int valid_channel_list(const char *val)
6457{
6458 while (*val) {
6459 if (!((*val >= '0' && *val <= '9') ||
6460 *val == '/' || *val == ','))
6461 return 0;
6462 val++;
6463 }
6464
6465 return 1;
6466}
6467
6468
6469enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
6470 const u8 *hdr,
6471 const u8 *attr_start,
6472 size_t attr_len,
6473 u8 *ssid, size_t *ssid_len,
6474 char **channel_list)
6475{
6476 const u8 *wrapped_data, *status, *e_nonce;
6477 u16 wrapped_data_len, status_len, e_nonce_len;
6478 const u8 *addr[2];
6479 size_t len[2];
6480 u8 *unwrapped = NULL;
6481 size_t unwrapped_len = 0;
6482 enum dpp_status_error ret = 256;
6483 struct json_token *root = NULL, *token;
c54227c2 6484 struct wpabuf *ssid64;
b10e01a7
JM
6485
6486 *ssid_len = 0;
6487 *channel_list = NULL;
6488
6489 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
6490 &wrapped_data_len);
6491 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
6492 dpp_auth_fail(auth,
6493 "Missing or invalid required Wrapped Data attribute");
6494 goto fail;
6495 }
6496 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
6497 wrapped_data, wrapped_data_len);
6498
6499 attr_len = wrapped_data - 4 - attr_start;
6500
6501 addr[0] = hdr;
6502 len[0] = DPP_HDR_LEN;
6503 addr[1] = attr_start;
6504 len[1] = attr_len;
6505 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6506 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6507 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6508 wrapped_data, wrapped_data_len);
6509 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6510 unwrapped = os_malloc(unwrapped_len);
6511 if (!unwrapped)
6512 goto fail;
6513 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
6514 wrapped_data, wrapped_data_len,
6515 2, addr, len, unwrapped) < 0) {
6516 dpp_auth_fail(auth, "AES-SIV decryption failed");
6517 goto fail;
6518 }
6519 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6520 unwrapped, unwrapped_len);
6521
6522 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
6523 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
6524 goto fail;
6525 }
6526
6527 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
6528 DPP_ATTR_ENROLLEE_NONCE,
6529 &e_nonce_len);
6530 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
6531 dpp_auth_fail(auth,
6532 "Missing or invalid Enrollee Nonce attribute");
6533 goto fail;
6534 }
6535 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
6536 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
6537 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
6538 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
6539 auth->e_nonce, e_nonce_len);
6540 goto fail;
6541 }
6542
6543 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
6544 &status_len);
6545 if (!status) {
6546 dpp_auth_fail(auth,
6547 "Missing required DPP Connection Status attribute");
6548 goto fail;
6549 }
6550 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
6551 status, status_len);
6552
6553 root = json_parse((const char *) status, status_len);
6554 if (!root) {
6555 dpp_auth_fail(auth, "Could not parse connStatus");
6556 goto fail;
6557 }
6558
c54227c2
JM
6559 ssid64 = json_get_member_base64url(root, "ssid64");
6560 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
6561 *ssid_len = wpabuf_len(ssid64);
6562 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
b10e01a7 6563 }
c54227c2 6564 wpabuf_free(ssid64);
b10e01a7
JM
6565
6566 token = json_get_member(root, "channelList");
6567 if (token && token->type == JSON_STRING &&
6568 valid_channel_list(token->string))
6569 *channel_list = os_strdup(token->string);
6570
6571 token = json_get_member(root, "result");
6572 if (!token || token->type != JSON_NUMBER) {
6573 dpp_auth_fail(auth, "No connStatus - result");
6574 goto fail;
6575 }
6576 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
6577 ret = token->number;
6578
6579fail:
6580 json_free(root);
6581 bin_clear_free(unwrapped, unwrapped_len);
6582 return ret;
6583}
6584
16ef233b
JM
6585
6586struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
6587 enum dpp_status_error result,
6588 const u8 *ssid, size_t ssid_len,
6589 const char *channel_list)
6590{
c54227c2 6591 struct wpabuf *msg = NULL, *clear = NULL, *json;
16ef233b
JM
6592 size_t nonce_len, clear_len, attr_len;
6593 const u8 *addr[2];
6594 size_t len[2];
6595 u8 *wrapped;
6596
6597 json = wpabuf_alloc(1000);
6598 if (!json)
6599 return NULL;
6600 wpabuf_printf(json, "{\"result\":%d", result);
6601 if (ssid) {
b2260842 6602 char *ssid64;
16ef233b 6603
a4255a20 6604 ssid64 = base64_url_encode(ssid, ssid_len, NULL);
c54227c2
JM
6605 if (!ssid64)
6606 goto fail;
6607 wpabuf_put_str(json, ",\"ssid64\":\"");
b2260842 6608 wpabuf_put_str(json, ssid64);
c54227c2 6609 os_free(ssid64);
16ef233b
JM
6610 wpabuf_put_str(json, "\"");
6611 }
6612 if (channel_list)
6613 wpabuf_printf(json, ",\"channelList\":\"%s\"", channel_list);
6614 wpabuf_put_str(json, "}");
6615 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
6616 wpabuf_head(json), wpabuf_len(json));
6617
6618 nonce_len = auth->curve->nonce_len;
6619 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
6620 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6621 clear = wpabuf_alloc(clear_len);
6622 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
6623 if (!clear || !msg)
6624 goto fail;
6625
6626 /* E-nonce */
6627 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
6628 wpabuf_put_le16(clear, nonce_len);
6629 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
6630
6631 /* DPP Connection Status */
6632 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
6633 wpabuf_put_le16(clear, wpabuf_len(json));
6634 wpabuf_put_buf(clear, json);
6635
6636 /* OUI, OUI type, Crypto Suite, DPP frame type */
6637 addr[0] = wpabuf_head_u8(msg) + 2;
6638 len[0] = 3 + 1 + 1 + 1;
6639 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6640
6641 /* Attributes before Wrapped Data (none) */
6642 addr[1] = wpabuf_put(msg, 0);
6643 len[1] = 0;
6644 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6645
6646 /* Wrapped Data */
6647 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6648 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6649 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6650
6651 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6652 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
6653 wpabuf_head(clear), wpabuf_len(clear),
6654 2, addr, len, wrapped) < 0)
6655 goto fail;
6656
6657 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
6658 msg);
6659 wpabuf_free(json);
6660 wpabuf_free(clear);
6661 return msg;
6662fail:
6663 wpabuf_free(json);
6664 wpabuf_free(clear);
6665 wpabuf_free(msg);
6666 return NULL;
6667}
6668
cc839952
JM
6669#endif /* CONFIG_DPP2 */
6670
22f90b32 6671
461d39af
JM
6672void dpp_configurator_free(struct dpp_configurator *conf)
6673{
6674 if (!conf)
6675 return;
6676 EVP_PKEY_free(conf->csign);
6677 os_free(conf->kid);
6678 os_free(conf);
6679}
6680
6681
8179ae3a
PK
6682int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
6683 size_t buflen)
6684{
6685 EC_KEY *eckey;
6686 int key_len, ret = -1;
6687 unsigned char *key = NULL;
6688
6689 if (!conf->csign)
6690 return -1;
6691
6692 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
6693 if (!eckey)
6694 return -1;
6695
6696 key_len = i2d_ECPrivateKey(eckey, &key);
6697 if (key_len > 0)
6698 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
6699
6700 EC_KEY_free(eckey);
6701 OPENSSL_free(key);
6702 return ret;
6703}
6704
6705
461d39af
JM
6706struct dpp_configurator *
6707dpp_keygen_configurator(const char *curve, const u8 *privkey,
6708 size_t privkey_len)
6709{
6710 struct dpp_configurator *conf;
6711 struct wpabuf *csign_pub = NULL;
6712 u8 kid_hash[SHA256_MAC_LEN];
6713 const u8 *addr[1];
6714 size_t len[1];
6715
6716 conf = os_zalloc(sizeof(*conf));
6717 if (!conf)
6718 return NULL;
6719
6720 if (!curve) {
6721 conf->curve = &dpp_curves[0];
6722 } else {
6723 conf->curve = dpp_get_curve_name(curve);
6724 if (!conf->curve) {
6725 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6726 curve);
820ea0ba 6727 os_free(conf);
461d39af
JM
6728 return NULL;
6729 }
6730 }
6731 if (privkey)
6732 conf->csign = dpp_set_keypair(&conf->curve, privkey,
6733 privkey_len);
6734 else
6735 conf->csign = dpp_gen_keypair(conf->curve);
6736 if (!conf->csign)
6737 goto fail;
6738 conf->own = 1;
6739
6740 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
6741 if (!csign_pub) {
6742 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
6743 goto fail;
6744 }
6745
6746 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6747 addr[0] = wpabuf_head(csign_pub);
6748 len[0] = wpabuf_len(csign_pub);
6749 if (sha256_vector(1, addr, len, kid_hash) < 0) {
6750 wpa_printf(MSG_DEBUG,
6751 "DPP: Failed to derive kid for C-sign-key");
6752 goto fail;
6753 }
6754
b2260842 6755 conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
461d39af
JM
6756 if (!conf->kid)
6757 goto fail;
6758out:
6759 wpabuf_free(csign_pub);
6760 return conf;
6761fail:
6762 dpp_configurator_free(conf);
6763 conf = NULL;
6764 goto out;
6765}
650a70a7
JM
6766
6767
f522bb23 6768int dpp_configurator_own_config(struct dpp_authentication *auth,
a2588be8 6769 const char *curve, int ap)
f522bb23
JM
6770{
6771 struct wpabuf *conf_obj;
6772 int ret = -1;
6773
6774 if (!auth->conf) {
6775 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
6776 return -1;
6777 }
6778
6779 if (!curve) {
6780 auth->curve = &dpp_curves[0];
6781 } else {
6782 auth->curve = dpp_get_curve_name(curve);
6783 if (!auth->curve) {
6784 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6785 curve);
6786 return -1;
6787 }
6788 }
6789 wpa_printf(MSG_DEBUG,
6790 "DPP: Building own configuration/connector with curve %s",
6791 auth->curve->name);
6792
6793 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
6794 if (!auth->own_protocol_key)
6795 return -1;
52d469de 6796 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
f522bb23 6797 auth->peer_protocol_key = auth->own_protocol_key;
52d469de 6798 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
f522bb23 6799
7eb06a33 6800 conf_obj = dpp_build_conf_obj(auth, ap, 0);
f522bb23
JM
6801 if (!conf_obj)
6802 goto fail;
6803 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
6804 wpabuf_len(conf_obj));
6805fail:
6806 wpabuf_free(conf_obj);
6807 auth->peer_protocol_key = NULL;
6808 return ret;
6809}
6810
6811
650a70a7
JM
6812static int dpp_compatible_netrole(const char *role1, const char *role2)
6813{
6814 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
6815 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
6816}
6817
6818
6819static int dpp_connector_compatible_group(struct json_token *root,
6820 const char *group_id,
6821 const char *net_role)
6822{
6823 struct json_token *groups, *token;
6824
6825 groups = json_get_member(root, "groups");
6826 if (!groups || groups->type != JSON_ARRAY)
6827 return 0;
6828
6829 for (token = groups->child; token; token = token->sibling) {
6830 struct json_token *id, *role;
6831
6832 id = json_get_member(token, "groupId");
6833 if (!id || id->type != JSON_STRING)
6834 continue;
6835
6836 role = json_get_member(token, "netRole");
6837 if (!role || role->type != JSON_STRING)
6838 continue;
6839
6840 if (os_strcmp(id->string, "*") != 0 &&
6841 os_strcmp(group_id, "*") != 0 &&
6842 os_strcmp(id->string, group_id) != 0)
6843 continue;
6844
6845 if (dpp_compatible_netrole(role->string, net_role))
6846 return 1;
6847 }
6848
6849 return 0;
6850}
6851
6852
6853static int dpp_connector_match_groups(struct json_token *own_root,
6854 struct json_token *peer_root)
6855{
6856 struct json_token *groups, *token;
6857
6858 groups = json_get_member(peer_root, "groups");
6859 if (!groups || groups->type != JSON_ARRAY) {
6860 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
6861 return 0;
6862 }
6863
6864 for (token = groups->child; token; token = token->sibling) {
6865 struct json_token *id, *role;
6866
6867 id = json_get_member(token, "groupId");
6868 if (!id || id->type != JSON_STRING) {
6869 wpa_printf(MSG_DEBUG,
6870 "DPP: Missing peer groupId string");
6871 continue;
6872 }
6873
6874 role = json_get_member(token, "netRole");
6875 if (!role || role->type != JSON_STRING) {
6876 wpa_printf(MSG_DEBUG,
6877 "DPP: Missing peer groups::netRole string");
6878 continue;
6879 }
6880 wpa_printf(MSG_DEBUG,
6881 "DPP: peer connector group: groupId='%s' netRole='%s'",
6882 id->string, role->string);
6883 if (dpp_connector_compatible_group(own_root, id->string,
6884 role->string)) {
6885 wpa_printf(MSG_DEBUG,
6886 "DPP: Compatible group/netRole in own connector");
6887 return 1;
6888 }
6889 }
6890
6891 return 0;
6892}
6893
6894
650a70a7
JM
6895static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
6896 unsigned int hash_len)
6897{
6898 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6899 const char *info = "DPP PMK";
b9d47b48 6900 int res;
650a70a7
JM
6901
6902 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6903
6904 /* HKDF-Extract(<>, N.x) */
6905 os_memset(salt, 0, hash_len);
b9d47b48 6906 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
650a70a7 6907 return -1;
650a70a7
JM
6908 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6909 prk, hash_len);
6910
6911 /* HKDF-Expand(PRK, info, L) */
b9d47b48 6912 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
650a70a7
JM
6913 os_memset(prk, 0, hash_len);
6914 if (res < 0)
6915 return -1;
6916
6917 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6918 pmk, hash_len);
6919 return 0;
6920}
6921
6922
6923static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
6924 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
6925{
6926 struct wpabuf *nkx, *pkx;
6927 int ret = -1, res;
6928 const u8 *addr[2];
6929 size_t len[2];
c2d4f2eb 6930 u8 hash[SHA256_MAC_LEN];
650a70a7
JM
6931
6932 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6933 nkx = dpp_get_pubkey_point(own_key, 0);
6934 pkx = dpp_get_pubkey_point(peer_key, 0);
6935 if (!nkx || !pkx)
6936 goto fail;
6937 addr[0] = wpabuf_head(nkx);
6938 len[0] = wpabuf_len(nkx) / 2;
6939 addr[1] = wpabuf_head(pkx);
6940 len[1] = wpabuf_len(pkx) / 2;
6941 if (len[0] != len[1])
6942 goto fail;
6943 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
6944 addr[0] = wpabuf_head(pkx);
6945 addr[1] = wpabuf_head(nkx);
6946 }
650a70a7
JM
6947 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
6948 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
c2d4f2eb 6949 res = sha256_vector(2, addr, len, hash);
650a70a7
JM
6950 if (res < 0)
6951 goto fail;
c2d4f2eb 6952 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
650a70a7
JM
6953 os_memcpy(pmkid, hash, PMKID_LEN);
6954 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
6955 ret = 0;
6956fail:
6957 wpabuf_free(nkx);
6958 wpabuf_free(pkx);
6959 return ret;
6960}
6961
6962
e85b6601
JM
6963enum dpp_status_error
6964dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
6965 const u8 *net_access_key, size_t net_access_key_len,
6966 const u8 *csign_key, size_t csign_key_len,
6967 const u8 *peer_connector, size_t peer_connector_len,
6968 os_time_t *expiry)
650a70a7
JM
6969{
6970 struct json_token *root = NULL, *netkey, *token;
6971 struct json_token *own_root = NULL;
e85b6601 6972 enum dpp_status_error ret = 255, res;
650a70a7
JM
6973 EVP_PKEY *own_key = NULL, *peer_key = NULL;
6974 struct wpabuf *own_key_pub = NULL;
650a70a7
JM
6975 const struct dpp_curve_params *curve, *own_curve;
6976 struct dpp_signed_connector_info info;
6977 const unsigned char *p;
6978 EVP_PKEY *csign = NULL;
6979 char *signed_connector = NULL;
6980 const char *pos, *end;
6981 unsigned char *own_conn = NULL;
6982 size_t own_conn_len;
650a70a7
JM
6983 size_t Nx_len;
6984 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
650a70a7
JM
6985
6986 os_memset(intro, 0, sizeof(*intro));
6987 os_memset(&info, 0, sizeof(info));
787615b3
JM
6988 if (expiry)
6989 *expiry = 0;
650a70a7
JM
6990
6991 p = csign_key;
6992 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
6993 if (!csign) {
6994 wpa_printf(MSG_ERROR,
6995 "DPP: Failed to parse local C-sign-key information");
6996 goto fail;
6997 }
6998
6999 own_key = dpp_set_keypair(&own_curve, net_access_key,
7000 net_access_key_len);
7001 if (!own_key) {
7002 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
7003 goto fail;
7004 }
650a70a7
JM
7005
7006 pos = os_strchr(own_connector, '.');
43fbb8db
JM
7007 if (!pos) {
7008 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
650a70a7 7009 goto fail;
43fbb8db 7010 }
650a70a7
JM
7011 pos++;
7012 end = os_strchr(pos, '.');
43fbb8db
JM
7013 if (!end) {
7014 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
650a70a7 7015 goto fail;
43fbb8db 7016 }
b2260842 7017 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
650a70a7
JM
7018 if (!own_conn) {
7019 wpa_printf(MSG_DEBUG,
7020 "DPP: Failed to base64url decode own signedConnector JWS Payload");
7021 goto fail;
7022 }
7023
7024 own_root = json_parse((const char *) own_conn, own_conn_len);
7025 if (!own_root) {
7026 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
7027 goto fail;
7028 }
7029
7030 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
7031 peer_connector, peer_connector_len);
7032 signed_connector = os_malloc(peer_connector_len + 1);
7033 if (!signed_connector)
7034 goto fail;
7035 os_memcpy(signed_connector, peer_connector, peer_connector_len);
7036 signed_connector[peer_connector_len] = '\0';
7037
e85b6601
JM
7038 res = dpp_process_signed_connector(&info, csign, signed_connector);
7039 if (res != DPP_STATUS_OK) {
7040 ret = res;
650a70a7 7041 goto fail;
e85b6601 7042 }
650a70a7
JM
7043
7044 root = json_parse((const char *) info.payload, info.payload_len);
7045 if (!root) {
7046 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
e85b6601 7047 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
7048 goto fail;
7049 }
7050
a4bf0078 7051 if (!dpp_connector_match_groups(own_root, root)) {
650a70a7 7052 wpa_printf(MSG_DEBUG,
a4bf0078 7053 "DPP: Peer connector does not include compatible group netrole with own connector");
e85b6601 7054 ret = DPP_STATUS_NO_MATCH;
650a70a7
JM
7055 goto fail;
7056 }
7057
7058 token = json_get_member(root, "expiry");
7059 if (!token || token->type != JSON_STRING) {
7060 wpa_printf(MSG_DEBUG,
7061 "DPP: No expiry string found - connector does not expire");
7062 } else {
7063 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
787615b3 7064 if (dpp_key_expired(token->string, expiry)) {
650a70a7
JM
7065 wpa_printf(MSG_DEBUG,
7066 "DPP: Connector (netAccessKey) has expired");
e85b6601 7067 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
7068 goto fail;
7069 }
7070 }
7071
7072 netkey = json_get_member(root, "netAccessKey");
7073 if (!netkey || netkey->type != JSON_OBJECT) {
7074 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
e85b6601 7075 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
7076 goto fail;
7077 }
7078
7079 peer_key = dpp_parse_jwk(netkey, &curve);
e85b6601
JM
7080 if (!peer_key) {
7081 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7 7082 goto fail;
e85b6601 7083 }
650a70a7
JM
7084 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
7085
7086 if (own_curve != curve) {
7087 wpa_printf(MSG_DEBUG,
7088 "DPP: Mismatching netAccessKey curves (%s != %s)",
7089 own_curve->name, curve->name);
e85b6601 7090 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
7091 goto fail;
7092 }
7093
7094 /* ECDH: N = nk * PK */
29ef1c5e 7095 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
650a70a7 7096 goto fail;
650a70a7
JM
7097
7098 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
7099 Nx, Nx_len);
7100
7101 /* PMK = HKDF(<>, "DPP PMK", N.x) */
7102 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
7103 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
7104 goto fail;
7105 }
7106 intro->pmk_len = curve->hash_len;
7107
7108 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
7109 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
7110 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
7111 goto fail;
7112 }
7113
e85b6601 7114 ret = DPP_STATUS_OK;
650a70a7 7115fail:
e85b6601 7116 if (ret != DPP_STATUS_OK)
650a70a7
JM
7117 os_memset(intro, 0, sizeof(*intro));
7118 os_memset(Nx, 0, sizeof(Nx));
650a70a7
JM
7119 os_free(own_conn);
7120 os_free(signed_connector);
7121 os_free(info.payload);
7122 EVP_PKEY_free(own_key);
7123 wpabuf_free(own_key_pub);
650a70a7
JM
7124 EVP_PKEY_free(peer_key);
7125 EVP_PKEY_free(csign);
7126 json_free(root);
7127 json_free(own_root);
7128 return ret;
7129}
500ed7f0
JM
7130
7131
7132static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
7133 int init)
7134{
7135 EC_GROUP *group;
7136 size_t len = curve->prime_len;
7137 const u8 *x, *y;
57ec74ea 7138 EVP_PKEY *res;
500ed7f0
JM
7139
7140 switch (curve->ike_group) {
7141 case 19:
7142 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
7143 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
7144 break;
7145 case 20:
7146 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
7147 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
7148 break;
7149 case 21:
7150 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
7151 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
7152 break;
7153 case 28:
7154 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
7155 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
7156 break;
7157 case 29:
7158 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
7159 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
7160 break;
7161 case 30:
7162 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
7163 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
7164 break;
7165 default:
7166 return NULL;
7167 }
7168
7169 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
7170 if (!group)
7171 return NULL;
57ec74ea
JM
7172 res = dpp_set_pubkey_point_group(group, x, y, len);
7173 EC_GROUP_free(group);
7174 return res;
500ed7f0
JM
7175}
7176
7177
7178static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
7179 const u8 *mac_init, const char *code,
7180 const char *identifier, BN_CTX *bnctx,
1cdfe8d2 7181 EC_GROUP **ret_group)
500ed7f0
JM
7182{
7183 u8 hash[DPP_MAX_HASH_LEN];
7184 const u8 *addr[3];
7185 size_t len[3];
7186 unsigned int num_elem = 0;
7187 EC_POINT *Qi = NULL;
7188 EVP_PKEY *Pi = NULL;
7189 EC_KEY *Pi_ec = NULL;
7190 const EC_POINT *Pi_point;
7191 BIGNUM *hash_bn = NULL;
7192 const EC_GROUP *group = NULL;
7193 EC_GROUP *group2 = NULL;
7194
7195 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7196
7197 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
7198 addr[num_elem] = mac_init;
7199 len[num_elem] = ETH_ALEN;
7200 num_elem++;
7201 if (identifier) {
7202 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
7203 identifier);
7204 addr[num_elem] = (const u8 *) identifier;
7205 len[num_elem] = os_strlen(identifier);
7206 num_elem++;
7207 }
7208 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
7209 addr[num_elem] = (const u8 *) code;
7210 len[num_elem] = os_strlen(code);
7211 num_elem++;
7212 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
7213 goto fail;
7214 wpa_hexdump_key(MSG_DEBUG,
7215 "DPP: H(MAC-Initiator | [identifier |] code)",
7216 hash, curve->hash_len);
7217 Pi = dpp_pkex_get_role_elem(curve, 1);
7218 if (!Pi)
7219 goto fail;
7220 dpp_debug_print_key("DPP: Pi", Pi);
7221 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
7222 if (!Pi_ec)
7223 goto fail;
7224 Pi_point = EC_KEY_get0_public_key(Pi_ec);
7225
7226 group = EC_KEY_get0_group(Pi_ec);
7227 if (!group)
7228 goto fail;
7229 group2 = EC_GROUP_dup(group);
7230 if (!group2)
7231 goto fail;
7232 Qi = EC_POINT_new(group2);
7233 if (!Qi) {
7234 EC_GROUP_free(group2);
7235 goto fail;
7236 }
7237 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
7238 if (!hash_bn ||
7239 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
7240 goto fail;
65731717 7241 if (EC_POINT_is_at_infinity(group, Qi)) {
578c9ea1 7242 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
65731717
JM
7243 goto fail;
7244 }
d722c50d 7245 dpp_debug_print_point("DPP: Qi", group, Qi);
500ed7f0
JM
7246out:
7247 EC_KEY_free(Pi_ec);
7248 EVP_PKEY_free(Pi);
7249 BN_clear_free(hash_bn);
1cdfe8d2 7250 if (ret_group && Qi)
500ed7f0 7251 *ret_group = group2;
1cdfe8d2
JM
7252 else
7253 EC_GROUP_free(group2);
500ed7f0
JM
7254 return Qi;
7255fail:
7256 EC_POINT_free(Qi);
7257 Qi = NULL;
7258 goto out;
7259}
7260
7261
7262static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
7263 const u8 *mac_resp, const char *code,
7264 const char *identifier, BN_CTX *bnctx,
1cdfe8d2 7265 EC_GROUP **ret_group)
500ed7f0
JM
7266{
7267 u8 hash[DPP_MAX_HASH_LEN];
7268 const u8 *addr[3];
7269 size_t len[3];
7270 unsigned int num_elem = 0;
7271 EC_POINT *Qr = NULL;
7272 EVP_PKEY *Pr = NULL;
7273 EC_KEY *Pr_ec = NULL;
7274 const EC_POINT *Pr_point;
7275 BIGNUM *hash_bn = NULL;
7276 const EC_GROUP *group = NULL;
7277 EC_GROUP *group2 = NULL;
7278
7279 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7280
7281 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
7282 addr[num_elem] = mac_resp;
7283 len[num_elem] = ETH_ALEN;
7284 num_elem++;
7285 if (identifier) {
7286 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
7287 identifier);
7288 addr[num_elem] = (const u8 *) identifier;
7289 len[num_elem] = os_strlen(identifier);
7290 num_elem++;
7291 }
7292 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
7293 addr[num_elem] = (const u8 *) code;
7294 len[num_elem] = os_strlen(code);
7295 num_elem++;
7296 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
7297 goto fail;
7298 wpa_hexdump_key(MSG_DEBUG,
7299 "DPP: H(MAC-Responder | [identifier |] code)",
7300 hash, curve->hash_len);
7301 Pr = dpp_pkex_get_role_elem(curve, 0);
7302 if (!Pr)
7303 goto fail;
7304 dpp_debug_print_key("DPP: Pr", Pr);
7305 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
7306 if (!Pr_ec)
7307 goto fail;
7308 Pr_point = EC_KEY_get0_public_key(Pr_ec);
7309
7310 group = EC_KEY_get0_group(Pr_ec);
7311 if (!group)
7312 goto fail;
7313 group2 = EC_GROUP_dup(group);
7314 if (!group2)
7315 goto fail;
7316 Qr = EC_POINT_new(group2);
7317 if (!Qr) {
7318 EC_GROUP_free(group2);
7319 goto fail;
7320 }
7321 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
7322 if (!hash_bn ||
7323 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
7324 goto fail;
5f5fff43
JM
7325 if (EC_POINT_is_at_infinity(group, Qr)) {
7326 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
7327 goto fail;
7328 }
d722c50d 7329 dpp_debug_print_point("DPP: Qr", group, Qr);
500ed7f0
JM
7330out:
7331 EC_KEY_free(Pr_ec);
7332 EVP_PKEY_free(Pr);
7333 BN_clear_free(hash_bn);
1cdfe8d2 7334 if (ret_group && Qr)
500ed7f0 7335 *ret_group = group2;
1cdfe8d2
JM
7336 else
7337 EC_GROUP_free(group2);
500ed7f0
JM
7338 return Qr;
7339fail:
7340 EC_POINT_free(Qr);
7341 Qr = NULL;
7342 goto out;
7343}
7344
7345
1cfcbd32
JM
7346#ifdef CONFIG_TESTING_OPTIONS
7347static int dpp_test_gen_invalid_key(struct wpabuf *msg,
7348 const struct dpp_curve_params *curve)
7349{
7350 BN_CTX *ctx;
7351 BIGNUM *x, *y;
1cfcbd32
JM
7352 int ret = -1;
7353 EC_GROUP *group;
7354 EC_POINT *point;
7355
7356 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
7357 if (!group)
4109555e 7358 return -1;
1cfcbd32
JM
7359
7360 ctx = BN_CTX_new();
7361 point = EC_POINT_new(group);
7362 x = BN_new();
7363 y = BN_new();
7364 if (!ctx || !point || !x || !y)
7365 goto fail;
7366
7367 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
7368 goto fail;
7369
7370 /* Generate a random y coordinate that results in a point that is not
7371 * on the curve. */
7372 for (;;) {
7373 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
7374 goto fail;
7375
7376 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
94619905 7377 ctx) != 1) {
2b92c4f3 7378#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
2439714f
JM
7379 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
7380 * return an error from EC_POINT_set_affine_coordinates_GFp()
7381 * when the point is not on the curve. */
94619905 7382 break;
2b92c4f3 7383#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
1cfcbd32 7384 goto fail;
2b92c4f3 7385#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
94619905 7386 }
1cfcbd32
JM
7387
7388 if (!EC_POINT_is_on_curve(group, point, ctx))
7389 break;
7390 }
7391
fc0efa2a
JM
7392 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
7393 curve->prime_len) < 0 ||
7394 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
7395 curve->prime_len) < 0)
1cfcbd32 7396 goto fail;
1cfcbd32
JM
7397
7398 ret = 0;
7399fail:
94619905
JM
7400 if (ret < 0)
7401 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
1cfcbd32
JM
7402 BN_free(x);
7403 BN_free(y);
7404 EC_POINT_free(point);
7405 BN_CTX_free(ctx);
57ec74ea 7406 EC_GROUP_free(group);
1cfcbd32
JM
7407
7408 return ret;
7409}
7410#endif /* CONFIG_TESTING_OPTIONS */
7411
7412
500ed7f0
JM
7413static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
7414{
7415 EC_KEY *X_ec = NULL;
7416 const EC_POINT *X_point;
7417 BN_CTX *bnctx = NULL;
1cdfe8d2 7418 EC_GROUP *group = NULL;
500ed7f0
JM
7419 EC_POINT *Qi = NULL, *M = NULL;
7420 struct wpabuf *M_buf = NULL;
7421 BIGNUM *Mx = NULL, *My = NULL;
7422 struct wpabuf *msg = NULL;
7423 size_t attr_len;
7424 const struct dpp_curve_params *curve = pkex->own_bi->curve;
500ed7f0
JM
7425
7426 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
7427
7428 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7429 bnctx = BN_CTX_new();
7430 if (!bnctx)
7431 goto fail;
7432 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
7433 pkex->identifier, bnctx, &group);
7434 if (!Qi)
7435 goto fail;
7436
7437 /* Generate a random ephemeral keypair x/X */
acc555f9
JM
7438#ifdef CONFIG_TESTING_OPTIONS
7439 if (dpp_pkex_ephemeral_key_override_len) {
7440 const struct dpp_curve_params *tmp_curve;
7441
7442 wpa_printf(MSG_INFO,
7443 "DPP: TESTING - override ephemeral key x/X");
7444 pkex->x = dpp_set_keypair(&tmp_curve,
7445 dpp_pkex_ephemeral_key_override,
7446 dpp_pkex_ephemeral_key_override_len);
7447 } else {
7448 pkex->x = dpp_gen_keypair(curve);
7449 }
7450#else /* CONFIG_TESTING_OPTIONS */
500ed7f0 7451 pkex->x = dpp_gen_keypair(curve);
acc555f9 7452#endif /* CONFIG_TESTING_OPTIONS */
500ed7f0
JM
7453 if (!pkex->x)
7454 goto fail;
7455
7456 /* M = X + Qi */
7457 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
7458 if (!X_ec)
7459 goto fail;
7460 X_point = EC_KEY_get0_public_key(X_ec);
7461 if (!X_point)
7462 goto fail;
d722c50d 7463 dpp_debug_print_point("DPP: X", group, X_point);
500ed7f0
JM
7464 M = EC_POINT_new(group);
7465 Mx = BN_new();
7466 My = BN_new();
7467 if (!M || !Mx || !My ||
7468 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
7469 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
7470 goto fail;
d722c50d 7471 dpp_debug_print_point("DPP: M", group, M);
500ed7f0
JM
7472
7473 /* Initiator -> Responder: group, [identifier,] M */
7474 attr_len = 4 + 2;
7475 if (pkex->identifier)
7476 attr_len += 4 + os_strlen(pkex->identifier);
7477 attr_len += 4 + 2 * curve->prime_len;
7478 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
7479 if (!msg)
7480 goto fail;
7481
61f9f27f
JM
7482#ifdef CONFIG_TESTING_OPTIONS
7483 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
7484 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
7485 goto skip_finite_cyclic_group;
7486 }
7487#endif /* CONFIG_TESTING_OPTIONS */
7488
500ed7f0
JM
7489 /* Finite Cyclic Group attribute */
7490 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
7491 wpabuf_put_le16(msg, 2);
7492 wpabuf_put_le16(msg, curve->ike_group);
7493
61f9f27f
JM
7494#ifdef CONFIG_TESTING_OPTIONS
7495skip_finite_cyclic_group:
7496#endif /* CONFIG_TESTING_OPTIONS */
7497
500ed7f0
JM
7498 /* Code Identifier attribute */
7499 if (pkex->identifier) {
7500 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
7501 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
7502 wpabuf_put_str(msg, pkex->identifier);
7503 }
7504
61f9f27f
JM
7505#ifdef CONFIG_TESTING_OPTIONS
7506 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
7507 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
7508 goto out;
7509 }
7510#endif /* CONFIG_TESTING_OPTIONS */
7511
500ed7f0
JM
7512 /* M in Encrypted Key attribute */
7513 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
7514 wpabuf_put_le16(msg, 2 * curve->prime_len);
7515
1cfcbd32
JM
7516#ifdef CONFIG_TESTING_OPTIONS
7517 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
7518 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
7519 if (dpp_test_gen_invalid_key(msg, curve) < 0)
7520 goto fail;
7521 goto out;
7522 }
7523#endif /* CONFIG_TESTING_OPTIONS */
7524
fc0efa2a
JM
7525 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
7526 curve->prime_len) < 0 ||
7527 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
7528 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
7529 curve->prime_len) < 0)
500ed7f0 7530 goto fail;
500ed7f0
JM
7531
7532out:
7533 wpabuf_free(M_buf);
7534 EC_KEY_free(X_ec);
7535 EC_POINT_free(M);
7536 EC_POINT_free(Qi);
7537 BN_clear_free(Mx);
7538 BN_clear_free(My);
7539 BN_CTX_free(bnctx);
1cdfe8d2 7540 EC_GROUP_free(group);
500ed7f0
JM
7541 return msg;
7542fail:
7543 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
7544 wpabuf_free(msg);
7545 msg = NULL;
7546 goto out;
7547}
7548
7549
219d4c9f
JM
7550static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
7551{
7552 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
7553}
7554
7555
7556struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
500ed7f0
JM
7557 const u8 *own_mac,
7558 const char *identifier,
7559 const char *code)
7560{
7561 struct dpp_pkex *pkex;
7562
2bdc47a9
JM
7563#ifdef CONFIG_TESTING_OPTIONS
7564 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
7565 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
7566 MAC2STR(dpp_pkex_own_mac_override));
7567 own_mac = dpp_pkex_own_mac_override;
7568 }
7569#endif /* CONFIG_TESTING_OPTIONS */
7570
500ed7f0
JM
7571 pkex = os_zalloc(sizeof(*pkex));
7572 if (!pkex)
7573 return NULL;
219d4c9f 7574 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
7575 pkex->initiator = 1;
7576 pkex->own_bi = bi;
7577 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
7578 if (identifier) {
7579 pkex->identifier = os_strdup(identifier);
7580 if (!pkex->identifier)
7581 goto fail;
7582 }
7583 pkex->code = os_strdup(code);
7584 if (!pkex->code)
7585 goto fail;
7586 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
7587 if (!pkex->exchange_req)
7588 goto fail;
7589 return pkex;
7590fail:
7591 dpp_pkex_free(pkex);
7592 return NULL;
7593}
7594
7595
e0247e79
JM
7596static struct wpabuf *
7597dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
7598 enum dpp_status_error status,
7599 const BIGNUM *Nx, const BIGNUM *Ny)
a5c3b41b
JM
7600{
7601 struct wpabuf *msg = NULL;
7602 size_t attr_len;
a5c3b41b
JM
7603 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7604
7605 /* Initiator -> Responder: DPP Status, [identifier,] N */
7606 attr_len = 4 + 1;
e0247e79
JM
7607 if (pkex->identifier)
7608 attr_len += 4 + os_strlen(pkex->identifier);
a5c3b41b
JM
7609 attr_len += 4 + 2 * curve->prime_len;
7610 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
7611 if (!msg)
7612 goto fail;
7613
61f9f27f
JM
7614#ifdef CONFIG_TESTING_OPTIONS
7615 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
7616 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
7617 goto skip_status;
7618 }
f31ef96d
JM
7619
7620 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
7621 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
7622 status = 255;
7623 }
61f9f27f
JM
7624#endif /* CONFIG_TESTING_OPTIONS */
7625
a5c3b41b 7626 /* DPP Status */
56f24d1d 7627 dpp_build_attr_status(msg, status);
a5c3b41b 7628
61f9f27f
JM
7629#ifdef CONFIG_TESTING_OPTIONS
7630skip_status:
7631#endif /* CONFIG_TESTING_OPTIONS */
7632
a5c3b41b
JM
7633 /* Code Identifier attribute */
7634 if (pkex->identifier) {
7635 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
7636 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
7637 wpabuf_put_str(msg, pkex->identifier);
7638 }
7639
e0247e79
JM
7640 if (status != DPP_STATUS_OK)
7641 goto skip_encrypted_key;
7642
61f9f27f
JM
7643#ifdef CONFIG_TESTING_OPTIONS
7644 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7645 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
7646 goto skip_encrypted_key;
7647 }
7648#endif /* CONFIG_TESTING_OPTIONS */
7649
a5c3b41b
JM
7650 /* N in Encrypted Key attribute */
7651 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
7652 wpabuf_put_le16(msg, 2 * curve->prime_len);
7653
1cfcbd32
JM
7654#ifdef CONFIG_TESTING_OPTIONS
7655 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7656 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
7657 if (dpp_test_gen_invalid_key(msg, curve) < 0)
7658 goto fail;
7659 goto skip_encrypted_key;
7660 }
7661#endif /* CONFIG_TESTING_OPTIONS */
7662
fc0efa2a
JM
7663 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
7664 curve->prime_len) < 0 ||
7665 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
7666 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
7667 curve->prime_len) < 0)
a5c3b41b 7668 goto fail;
a5c3b41b 7669
61f9f27f 7670skip_encrypted_key:
e0247e79
JM
7671 if (status == DPP_STATUS_BAD_GROUP) {
7672 /* Finite Cyclic Group attribute */
7673 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
7674 wpabuf_put_le16(msg, 2);
7675 wpabuf_put_le16(msg, curve->ike_group);
7676 }
7677
a5c3b41b
JM
7678 return msg;
7679fail:
7680 wpabuf_free(msg);
7681 return NULL;
7682}
7683
7684
d05c82c4
JM
7685static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
7686 const u8 *Mx, size_t Mx_len,
7687 const u8 *Nx, size_t Nx_len,
7688 const char *code,
7689 const u8 *Kx, size_t Kx_len,
7690 u8 *z, unsigned int hash_len)
7691{
7692 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
7693 int res;
7694 u8 *info, *pos;
7695 size_t info_len;
7696
7697 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7698 */
7699
7700 /* HKDF-Extract(<>, IKM=K.x) */
7701 os_memset(salt, 0, hash_len);
7702 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
7703 return -1;
7704 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
7705 prk, hash_len);
7706 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
7707 info = os_malloc(info_len);
7708 if (!info)
7709 return -1;
7710 pos = info;
7711 os_memcpy(pos, mac_init, ETH_ALEN);
7712 pos += ETH_ALEN;
7713 os_memcpy(pos, mac_resp, ETH_ALEN);
7714 pos += ETH_ALEN;
7715 os_memcpy(pos, Mx, Mx_len);
7716 pos += Mx_len;
7717 os_memcpy(pos, Nx, Nx_len);
7718 pos += Nx_len;
7719 os_memcpy(pos, code, os_strlen(code));
7720
7721 /* HKDF-Expand(PRK, info, L) */
7722 if (hash_len == 32)
7723 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
7724 z, hash_len);
7725 else if (hash_len == 48)
7726 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
7727 z, hash_len);
7728 else if (hash_len == 64)
7729 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
7730 z, hash_len);
7731 else
7732 res = -1;
7733 os_free(info);
7734 os_memset(prk, 0, hash_len);
7735 if (res < 0)
7736 return -1;
7737
7738 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
7739 z, hash_len);
7740 return 0;
7741}
7742
7743
4a450ba2
JM
7744static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
7745 const char *identifier)
7746{
7747 if (!attr_id && identifier) {
7748 wpa_printf(MSG_DEBUG,
7749 "DPP: No PKEX code identifier received, but expected one");
7750 return 0;
7751 }
7752
7753 if (attr_id && !identifier) {
7754 wpa_printf(MSG_DEBUG,
7755 "DPP: PKEX code identifier received, but not expecting one");
7756 return 0;
7757 }
7758
7759 if (attr_id && identifier &&
7760 (os_strlen(identifier) != attr_id_len ||
7761 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
7762 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
7763 return 0;
7764 }
7765
7766 return 1;
7767}
7768
7769
219d4c9f
JM
7770struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
7771 struct dpp_bootstrap_info *bi,
500ed7f0
JM
7772 const u8 *own_mac,
7773 const u8 *peer_mac,
7774 const char *identifier,
7775 const char *code,
7776 const u8 *buf, size_t len)
7777{
7778 const u8 *attr_group, *attr_id, *attr_key;
7779 u16 attr_group_len, attr_id_len, attr_key_len;
7780 const struct dpp_curve_params *curve = bi->curve;
7781 u16 ike_group;
7782 struct dpp_pkex *pkex = NULL;
7783 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
7784 BN_CTX *bnctx = NULL;
1cdfe8d2 7785 EC_GROUP *group = NULL;
500ed7f0
JM
7786 BIGNUM *Mx = NULL, *My = NULL;
7787 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
7788 const EC_POINT *Y_point;
7789 BIGNUM *Nx = NULL, *Ny = NULL;
d05c82c4
JM
7790 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
7791 size_t Kx_len;
7792 int res;
500ed7f0 7793
29ab69e4
JM
7794 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
7795 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7796 "PKEX counter t limit reached - ignore message");
7797 return NULL;
7798 }
7799
2bdc47a9
JM
7800#ifdef CONFIG_TESTING_OPTIONS
7801 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
7802 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
7803 MAC2STR(dpp_pkex_peer_mac_override));
7804 peer_mac = dpp_pkex_peer_mac_override;
7805 }
7806 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
7807 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
7808 MAC2STR(dpp_pkex_own_mac_override));
7809 own_mac = dpp_pkex_own_mac_override;
7810 }
7811#endif /* CONFIG_TESTING_OPTIONS */
7812
4a450ba2 7813 attr_id_len = 0;
500ed7f0
JM
7814 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
7815 &attr_id_len);
4a450ba2 7816 if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
500ed7f0 7817 return NULL;
500ed7f0
JM
7818
7819 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
7820 &attr_group_len);
7821 if (!attr_group || attr_group_len != 2) {
d7e7b712
JM
7822 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7823 "Missing or invalid Finite Cyclic Group attribute");
500ed7f0
JM
7824 return NULL;
7825 }
7826 ike_group = WPA_GET_LE16(attr_group);
7827 if (ike_group != curve->ike_group) {
d7e7b712
JM
7828 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7829 "Mismatching PKEX curve: peer=%u own=%u",
7830 ike_group, curve->ike_group);
e0247e79
JM
7831 pkex = os_zalloc(sizeof(*pkex));
7832 if (!pkex)
7833 goto fail;
7834 pkex->own_bi = bi;
7835 pkex->failed = 1;
7836 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
7837 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
7838 if (!pkex->exchange_resp)
7839 goto fail;
7840 return pkex;
500ed7f0
JM
7841 }
7842
7843 /* M in Encrypted Key attribute */
7844 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
7845 &attr_key_len);
7846 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
7847 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
d7e7b712
JM
7848 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7849 "Missing Encrypted Key attribute");
500ed7f0
JM
7850 return NULL;
7851 }
7852
7853 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7854 bnctx = BN_CTX_new();
7855 if (!bnctx)
7856 goto fail;
7857 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
7858 &group);
7859 if (!Qi)
7860 goto fail;
7861
7862 /* X' = M - Qi */
7863 X = EC_POINT_new(group);
7864 M = EC_POINT_new(group);
7865 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
7866 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
7867 if (!X || !M || !Mx || !My ||
7868 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
7869 EC_POINT_is_at_infinity(group, M) ||
7870 !EC_POINT_is_on_curve(group, M, bnctx) ||
7871 EC_POINT_invert(group, Qi, bnctx) != 1 ||
7872 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
7873 EC_POINT_is_at_infinity(group, X) ||
d7e7b712
JM
7874 !EC_POINT_is_on_curve(group, X, bnctx)) {
7875 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7876 "Invalid Encrypted Key value");
29ab69e4 7877 bi->pkex_t++;
500ed7f0 7878 goto fail;
d7e7b712 7879 }
d722c50d
JM
7880 dpp_debug_print_point("DPP: M", group, M);
7881 dpp_debug_print_point("DPP: X'", group, X);
500ed7f0
JM
7882
7883 pkex = os_zalloc(sizeof(*pkex));
7884 if (!pkex)
7885 goto fail;
29ab69e4 7886 pkex->t = bi->pkex_t;
219d4c9f 7887 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
7888 pkex->own_bi = bi;
7889 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
7890 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
7891 if (identifier) {
7892 pkex->identifier = os_strdup(identifier);
7893 if (!pkex->identifier)
7894 goto fail;
7895 }
7896 pkex->code = os_strdup(code);
7897 if (!pkex->code)
7898 goto fail;
7899
7900 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
7901
7902 X_ec = EC_KEY_new();
7903 if (!X_ec ||
7904 EC_KEY_set_group(X_ec, group) != 1 ||
7905 EC_KEY_set_public_key(X_ec, X) != 1)
7906 goto fail;
7907 pkex->x = EVP_PKEY_new();
7908 if (!pkex->x ||
7909 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
7910 goto fail;
7911
7912 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7913 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
7914 if (!Qr)
7915 goto fail;
7916
7917 /* Generate a random ephemeral keypair y/Y */
acc555f9
JM
7918#ifdef CONFIG_TESTING_OPTIONS
7919 if (dpp_pkex_ephemeral_key_override_len) {
7920 const struct dpp_curve_params *tmp_curve;
7921
7922 wpa_printf(MSG_INFO,
7923 "DPP: TESTING - override ephemeral key y/Y");
7924 pkex->y = dpp_set_keypair(&tmp_curve,
7925 dpp_pkex_ephemeral_key_override,
7926 dpp_pkex_ephemeral_key_override_len);
7927 } else {
7928 pkex->y = dpp_gen_keypair(curve);
7929 }
7930#else /* CONFIG_TESTING_OPTIONS */
500ed7f0 7931 pkex->y = dpp_gen_keypair(curve);
acc555f9 7932#endif /* CONFIG_TESTING_OPTIONS */
500ed7f0
JM
7933 if (!pkex->y)
7934 goto fail;
7935
7936 /* N = Y + Qr */
7937 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
7938 if (!Y_ec)
7939 goto fail;
7940 Y_point = EC_KEY_get0_public_key(Y_ec);
7941 if (!Y_point)
7942 goto fail;
d722c50d 7943 dpp_debug_print_point("DPP: Y", group, Y_point);
500ed7f0
JM
7944 N = EC_POINT_new(group);
7945 Nx = BN_new();
7946 Ny = BN_new();
7947 if (!N || !Nx || !Ny ||
7948 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
7949 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
7950 goto fail;
d722c50d 7951 dpp_debug_print_point("DPP: N", group, N);
500ed7f0 7952
e0247e79 7953 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
a5c3b41b
JM
7954 Nx, Ny);
7955 if (!pkex->exchange_resp)
500ed7f0
JM
7956 goto fail;
7957
d05c82c4 7958 /* K = y * X' */
29ef1c5e 7959 if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
d05c82c4 7960 goto fail;
d05c82c4
JM
7961
7962 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7963 Kx, Kx_len);
7964
7965 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7966 */
7967 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
7968 pkex->Mx, curve->prime_len,
7969 pkex->Nx, curve->prime_len, pkex->code,
7970 Kx, Kx_len, pkex->z, curve->hash_len);
7971 os_memset(Kx, 0, Kx_len);
7972 if (res < 0)
7973 goto fail;
7974
500ed7f0
JM
7975 pkex->exchange_done = 1;
7976
7977out:
500ed7f0
JM
7978 BN_CTX_free(bnctx);
7979 EC_POINT_free(Qi);
7980 EC_POINT_free(Qr);
7981 BN_free(Mx);
7982 BN_free(My);
7983 BN_free(Nx);
7984 BN_free(Ny);
7985 EC_POINT_free(M);
7986 EC_POINT_free(N);
7987 EC_POINT_free(X);
7988 EC_KEY_free(X_ec);
7989 EC_KEY_free(Y_ec);
1cdfe8d2 7990 EC_GROUP_free(group);
500ed7f0
JM
7991 return pkex;
7992fail:
60b9dd86 7993 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
500ed7f0
JM
7994 dpp_pkex_free(pkex);
7995 pkex = NULL;
7996 goto out;
7997}
7998
7999
b0626c2a
JM
8000static struct wpabuf *
8001dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
8002 const struct wpabuf *A_pub, const u8 *u)
8003{
8004 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8005 struct wpabuf *msg = NULL;
8006 size_t clear_len, attr_len;
8007 struct wpabuf *clear = NULL;
8008 u8 *wrapped;
8009 u8 octet;
8010 const u8 *addr[2];
8011 size_t len[2];
8012
8013 /* {A, u, [bootstrapping info]}z */
8014 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
8015 clear = wpabuf_alloc(clear_len);
8016 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
8017#ifdef CONFIG_TESTING_OPTIONS
8018 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
acdf703d 8019 attr_len += 5;
b0626c2a
JM
8020#endif /* CONFIG_TESTING_OPTIONS */
8021 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
8022 if (!clear || !msg)
8023 goto fail;
8024
61f9f27f
JM
8025#ifdef CONFIG_TESTING_OPTIONS
8026 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
8027 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
8028 goto skip_bootstrap_key;
8029 }
89d0bf67
JM
8030 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
8031 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
8032 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8033 wpabuf_put_le16(clear, 2 * curve->prime_len);
8034 if (dpp_test_gen_invalid_key(clear, curve) < 0)
8035 goto fail;
8036 goto skip_bootstrap_key;
8037 }
61f9f27f
JM
8038#endif /* CONFIG_TESTING_OPTIONS */
8039
b0626c2a
JM
8040 /* A in Bootstrap Key attribute */
8041 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8042 wpabuf_put_le16(clear, wpabuf_len(A_pub));
8043 wpabuf_put_buf(clear, A_pub);
8044
61f9f27f
JM
8045#ifdef CONFIG_TESTING_OPTIONS
8046skip_bootstrap_key:
8047 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
8048 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
8049 goto skip_i_auth_tag;
8050 }
7e0ebe21
JM
8051 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
8052 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
8053 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
8054 wpabuf_put_le16(clear, curve->hash_len);
8055 wpabuf_put_data(clear, u, curve->hash_len - 1);
8056 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
8057 goto skip_i_auth_tag;
8058 }
61f9f27f
JM
8059#endif /* CONFIG_TESTING_OPTIONS */
8060
b0626c2a
JM
8061 /* u in I-Auth tag attribute */
8062 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
8063 wpabuf_put_le16(clear, curve->hash_len);
8064 wpabuf_put_data(clear, u, curve->hash_len);
8065
61f9f27f
JM
8066#ifdef CONFIG_TESTING_OPTIONS
8067skip_i_auth_tag:
8068 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
8069 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
8070 goto skip_wrapped_data;
8071 }
8072#endif /* CONFIG_TESTING_OPTIONS */
8073
b0626c2a
JM
8074 addr[0] = wpabuf_head_u8(msg) + 2;
8075 len[0] = DPP_HDR_LEN;
8076 octet = 0;
8077 addr[1] = &octet;
8078 len[1] = sizeof(octet);
8079 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8080 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8081
8082 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
8083 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8084 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8085
8086 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
8087 if (aes_siv_encrypt(pkex->z, curve->hash_len,
8088 wpabuf_head(clear), wpabuf_len(clear),
8089 2, addr, len, wrapped) < 0)
8090 goto fail;
8091 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8092 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
8093
8094#ifdef CONFIG_TESTING_OPTIONS
8095 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
8096 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 8097 dpp_build_attr_status(msg, DPP_STATUS_OK);
b0626c2a 8098 }
61f9f27f 8099skip_wrapped_data:
b0626c2a
JM
8100#endif /* CONFIG_TESTING_OPTIONS */
8101
8102out:
8103 wpabuf_free(clear);
8104 return msg;
8105
8106fail:
8107 wpabuf_free(msg);
8108 msg = NULL;
8109 goto out;
8110}
8111
8112
500ed7f0 8113struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
af4103e5 8114 const u8 *peer_mac,
500ed7f0
JM
8115 const u8 *buf, size_t buflen)
8116{
e0247e79
JM
8117 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
8118 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
1cdfe8d2 8119 EC_GROUP *group = NULL;
500ed7f0 8120 BN_CTX *bnctx = NULL;
500ed7f0
JM
8121 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8122 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8123 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
8124 BIGNUM *Nx = NULL, *Ny = NULL;
500ed7f0 8125 EC_KEY *Y_ec = NULL;
0e6709a4
JM
8126 size_t Jx_len, Kx_len;
8127 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
8128 const u8 *addr[4];
8129 size_t len[4];
8130 u8 u[DPP_MAX_HASH_LEN];
6254045a 8131 int res;
500ed7f0 8132
03abb6b5 8133 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
e0247e79
JM
8134 return NULL;
8135
2bdc47a9 8136#ifdef CONFIG_TESTING_OPTIONS
34603767
JM
8137 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
8138 wpa_printf(MSG_INFO,
8139 "DPP: TESTING - stop at PKEX Exchange Response");
8140 pkex->failed = 1;
8141 return NULL;
8142 }
8143
2bdc47a9
JM
8144 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
8145 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
8146 MAC2STR(dpp_pkex_peer_mac_override));
8147 peer_mac = dpp_pkex_peer_mac_override;
8148 }
8149#endif /* CONFIG_TESTING_OPTIONS */
8150
af4103e5
JM
8151 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
8152
500ed7f0
JM
8153 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
8154 &attr_status_len);
8155 if (!attr_status || attr_status_len != 1) {
d7e7b712 8156 dpp_pkex_fail(pkex, "No DPP Status attribute");
500ed7f0
JM
8157 return NULL;
8158 }
8159 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
e0247e79
JM
8160
8161 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
8162 attr_group = dpp_get_attr(buf, buflen,
8163 DPP_ATTR_FINITE_CYCLIC_GROUP,
8164 &attr_group_len);
8165 if (attr_group && attr_group_len == 2) {
8166 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
8167 "Peer indicated mismatching PKEX group - proposed %u",
8168 WPA_GET_LE16(attr_group));
8169 return NULL;
8170 }
8171 }
8172
500ed7f0 8173 if (attr_status[0] != DPP_STATUS_OK) {
d7e7b712 8174 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
500ed7f0
JM
8175 return NULL;
8176 }
8177
4a450ba2 8178 attr_id_len = 0;
500ed7f0
JM
8179 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
8180 &attr_id_len);
4a450ba2
JM
8181 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
8182 pkex->identifier)) {
d7e7b712 8183 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
500ed7f0
JM
8184 return NULL;
8185 }
8186
8187 /* N in Encrypted Key attribute */
8188 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
8189 &attr_key_len);
8190 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
d7e7b712 8191 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
500ed7f0
JM
8192 return NULL;
8193 }
8194
8195 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
8196 bnctx = BN_CTX_new();
8197 if (!bnctx)
8198 goto fail;
8199 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
8200 pkex->identifier, bnctx, &group);
8201 if (!Qr)
8202 goto fail;
8203
8204 /* Y' = N - Qr */
8205 Y = EC_POINT_new(group);
8206 N = EC_POINT_new(group);
8207 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
8208 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
8209 if (!Y || !N || !Nx || !Ny ||
8210 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
8211 EC_POINT_is_at_infinity(group, N) ||
8212 !EC_POINT_is_on_curve(group, N, bnctx) ||
8213 EC_POINT_invert(group, Qr, bnctx) != 1 ||
8214 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
8215 EC_POINT_is_at_infinity(group, Y) ||
d7e7b712
JM
8216 !EC_POINT_is_on_curve(group, Y, bnctx)) {
8217 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
29ab69e4 8218 pkex->t++;
500ed7f0 8219 goto fail;
d7e7b712 8220 }
d722c50d
JM
8221 dpp_debug_print_point("DPP: N", group, N);
8222 dpp_debug_print_point("DPP: Y'", group, Y);
500ed7f0
JM
8223
8224 pkex->exchange_done = 1;
8225
8226 /* ECDH: J = a * Y’ */
8227 Y_ec = EC_KEY_new();
8228 if (!Y_ec ||
8229 EC_KEY_set_group(Y_ec, group) != 1 ||
8230 EC_KEY_set_public_key(Y_ec, Y) != 1)
8231 goto fail;
8232 pkex->y = EVP_PKEY_new();
8233 if (!pkex->y ||
8234 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
8235 goto fail;
29ef1c5e 8236 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
500ed7f0 8237 goto fail;
500ed7f0
JM
8238
8239 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
8240 Jx, Jx_len);
8241
8242 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
8243 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
8244 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8245 X_pub = dpp_get_pubkey_point(pkex->x, 0);
8246 if (!A_pub || !Y_pub || !X_pub)
8247 goto fail;
8248 addr[0] = pkex->own_mac;
8249 len[0] = ETH_ALEN;
8250 addr[1] = wpabuf_head(A_pub);
8251 len[1] = wpabuf_len(A_pub) / 2;
8252 addr[2] = wpabuf_head(Y_pub);
8253 len[2] = wpabuf_len(Y_pub) / 2;
8254 addr[3] = wpabuf_head(X_pub);
8255 len[3] = wpabuf_len(X_pub) / 2;
8256 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
8257 goto fail;
8258 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
8259
0e6709a4 8260 /* K = x * Y’ */
29ef1c5e 8261 if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
500ed7f0 8262 goto fail;
500ed7f0 8263
0e6709a4
JM
8264 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
8265 Kx, Kx_len);
500ed7f0 8266
0e6709a4 8267 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
500ed7f0 8268 */
6254045a
JM
8269 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
8270 pkex->Mx, curve->prime_len,
8271 attr_key /* N.x */, attr_key_len / 2,
8272 pkex->code, Kx, Kx_len,
8273 pkex->z, curve->hash_len);
8274 os_memset(Kx, 0, Kx_len);
8275 if (res < 0)
500ed7f0
JM
8276 goto fail;
8277
b0626c2a
JM
8278 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
8279 if (!msg)
500ed7f0 8280 goto fail;
60239f60 8281
500ed7f0 8282out:
500ed7f0
JM
8283 wpabuf_free(A_pub);
8284 wpabuf_free(X_pub);
8285 wpabuf_free(Y_pub);
8286 EC_POINT_free(Qr);
8287 EC_POINT_free(Y);
8288 EC_POINT_free(N);
8289 BN_free(Nx);
8290 BN_free(Ny);
8291 EC_KEY_free(Y_ec);
500ed7f0 8292 BN_CTX_free(bnctx);
1cdfe8d2 8293 EC_GROUP_free(group);
500ed7f0
JM
8294 return msg;
8295fail:
60b9dd86 8296 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
500ed7f0
JM
8297 goto out;
8298}
8299
8300
b3e4cc5c
JM
8301static struct wpabuf *
8302dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
8303 const struct wpabuf *B_pub, const u8 *v)
8304{
8305 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8306 struct wpabuf *msg = NULL;
8307 const u8 *addr[2];
8308 size_t len[2];
8309 u8 octet;
8310 u8 *wrapped;
8311 struct wpabuf *clear = NULL;
8312 size_t clear_len, attr_len;
8313
8314 /* {B, v [bootstrapping info]}z */
8315 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
8316 clear = wpabuf_alloc(clear_len);
8317 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
8318#ifdef CONFIG_TESTING_OPTIONS
8319 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
acdf703d 8320 attr_len += 5;
b3e4cc5c
JM
8321#endif /* CONFIG_TESTING_OPTIONS */
8322 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
8323 if (!clear || !msg)
8324 goto fail;
8325
61f9f27f
JM
8326#ifdef CONFIG_TESTING_OPTIONS
8327 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
8328 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
8329 goto skip_bootstrap_key;
8330 }
89d0bf67
JM
8331 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
8332 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
8333 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8334 wpabuf_put_le16(clear, 2 * curve->prime_len);
8335 if (dpp_test_gen_invalid_key(clear, curve) < 0)
8336 goto fail;
8337 goto skip_bootstrap_key;
8338 }
61f9f27f
JM
8339#endif /* CONFIG_TESTING_OPTIONS */
8340
8341 /* B in Bootstrap Key attribute */
b3e4cc5c
JM
8342 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8343 wpabuf_put_le16(clear, wpabuf_len(B_pub));
8344 wpabuf_put_buf(clear, B_pub);
8345
61f9f27f
JM
8346#ifdef CONFIG_TESTING_OPTIONS
8347skip_bootstrap_key:
8348 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
8349 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
8350 goto skip_r_auth_tag;
8351 }
7e0ebe21
JM
8352 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
8353 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
8354 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
8355 wpabuf_put_le16(clear, curve->hash_len);
8356 wpabuf_put_data(clear, v, curve->hash_len - 1);
8357 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
8358 goto skip_r_auth_tag;
8359 }
61f9f27f
JM
8360#endif /* CONFIG_TESTING_OPTIONS */
8361
b3e4cc5c
JM
8362 /* v in R-Auth tag attribute */
8363 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
8364 wpabuf_put_le16(clear, curve->hash_len);
8365 wpabuf_put_data(clear, v, curve->hash_len);
8366
61f9f27f
JM
8367#ifdef CONFIG_TESTING_OPTIONS
8368skip_r_auth_tag:
8369 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
8370 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
8371 goto skip_wrapped_data;
8372 }
8373#endif /* CONFIG_TESTING_OPTIONS */
8374
b3e4cc5c
JM
8375 addr[0] = wpabuf_head_u8(msg) + 2;
8376 len[0] = DPP_HDR_LEN;
8377 octet = 1;
8378 addr[1] = &octet;
8379 len[1] = sizeof(octet);
8380 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8381 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8382
8383 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
8384 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8385 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8386
8387 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
8388 if (aes_siv_encrypt(pkex->z, curve->hash_len,
8389 wpabuf_head(clear), wpabuf_len(clear),
8390 2, addr, len, wrapped) < 0)
8391 goto fail;
8392 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8393 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
8394
8395#ifdef CONFIG_TESTING_OPTIONS
8396 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
8397 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 8398 dpp_build_attr_status(msg, DPP_STATUS_OK);
b3e4cc5c 8399 }
61f9f27f 8400skip_wrapped_data:
b3e4cc5c
JM
8401#endif /* CONFIG_TESTING_OPTIONS */
8402
8403out:
8404 wpabuf_free(clear);
8405 return msg;
8406
8407fail:
8408 wpabuf_free(msg);
8409 msg = NULL;
8410 goto out;
8411}
8412
8413
500ed7f0 8414struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
4be5bc98 8415 const u8 *hdr,
500ed7f0
JM
8416 const u8 *buf, size_t buflen)
8417{
8418 const struct dpp_curve_params *curve = pkex->own_bi->curve;
d05c82c4
JM
8419 size_t Jx_len, Lx_len;
8420 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
8421 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
8422 const u8 *wrapped_data, *b_key, *peer_u;
8423 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
8424 const u8 *addr[4];
8425 size_t len[4];
8426 u8 octet;
8427 u8 *unwrapped = NULL;
8428 size_t unwrapped_len = 0;
8429 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8430 struct wpabuf *B_pub = NULL;
8431 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
500ed7f0 8432
34603767
JM
8433#ifdef CONFIG_TESTING_OPTIONS
8434 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
8435 wpa_printf(MSG_INFO,
8436 "DPP: TESTING - stop at PKEX CR Request");
8437 pkex->failed = 1;
8438 return NULL;
8439 }
8440#endif /* CONFIG_TESTING_OPTIONS */
8441
29ab69e4 8442 if (!pkex->exchange_done || pkex->failed ||
03abb6b5 8443 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
e0247e79
JM
8444 goto fail;
8445
500ed7f0
JM
8446 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
8447 &wrapped_data_len);
8448 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
8449 dpp_pkex_fail(pkex,
8450 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
8451 goto fail;
8452 }
8453
8454 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8455 wrapped_data, wrapped_data_len);
8456 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
8457 unwrapped = os_malloc(unwrapped_len);
8458 if (!unwrapped)
8459 goto fail;
8460
4be5bc98
JM
8461 addr[0] = hdr;
8462 len[0] = DPP_HDR_LEN;
500ed7f0 8463 octet = 0;
4be5bc98
JM
8464 addr[1] = &octet;
8465 len[1] = sizeof(octet);
8466 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8467 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
8468
8469 if (aes_siv_decrypt(pkex->z, curve->hash_len,
8470 wrapped_data, wrapped_data_len,
4be5bc98 8471 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
8472 dpp_pkex_fail(pkex,
8473 "AES-SIV decryption failed - possible PKEX code mismatch");
039b8e73 8474 pkex->failed = 1;
29ab69e4 8475 pkex->t++;
500ed7f0
JM
8476 goto fail;
8477 }
8478 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
8479 unwrapped, unwrapped_len);
8480
8481 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 8482 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
8483 goto fail;
8484 }
8485
8486 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
8487 &b_key_len);
8488 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 8489 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
8490 goto fail;
8491 }
8492 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
8493 b_key_len);
d7e7b712
JM
8494 if (!pkex->peer_bootstrap_key) {
8495 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 8496 goto fail;
d7e7b712 8497 }
500ed7f0
JM
8498 dpp_debug_print_key("DPP: Peer bootstrap public key",
8499 pkex->peer_bootstrap_key);
8500
8501 /* ECDH: J' = y * A' */
29ef1c5e 8502 if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
500ed7f0 8503 goto fail;
500ed7f0
JM
8504
8505 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
8506 Jx, Jx_len);
8507
8508 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
8509 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
8510 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8511 X_pub = dpp_get_pubkey_point(pkex->x, 0);
8512 if (!A_pub || !Y_pub || !X_pub)
8513 goto fail;
8514 addr[0] = pkex->peer_mac;
8515 len[0] = ETH_ALEN;
8516 addr[1] = wpabuf_head(A_pub);
8517 len[1] = wpabuf_len(A_pub) / 2;
8518 addr[2] = wpabuf_head(Y_pub);
8519 len[2] = wpabuf_len(Y_pub) / 2;
8520 addr[3] = wpabuf_head(X_pub);
8521 len[3] = wpabuf_len(X_pub) / 2;
8522 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
8523 goto fail;
8524
8525 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
8526 &peer_u_len);
8527 if (!peer_u || peer_u_len != curve->hash_len ||
8528 os_memcmp(peer_u, u, curve->hash_len) != 0) {
d7e7b712 8529 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
500ed7f0
JM
8530 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
8531 u, curve->hash_len);
8532 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
29ab69e4 8533 pkex->t++;
500ed7f0
JM
8534 goto fail;
8535 }
8536 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
8537
8538 /* ECDH: L = b * X' */
29ef1c5e 8539 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
500ed7f0 8540 goto fail;
500ed7f0
JM
8541
8542 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
8543 Lx, Lx_len);
8544
8545 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
8546 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
8547 if (!B_pub)
8548 goto fail;
8549 addr[0] = pkex->own_mac;
8550 len[0] = ETH_ALEN;
8551 addr[1] = wpabuf_head(B_pub);
8552 len[1] = wpabuf_len(B_pub) / 2;
8553 addr[2] = wpabuf_head(X_pub);
8554 len[2] = wpabuf_len(X_pub) / 2;
8555 addr[3] = wpabuf_head(Y_pub);
8556 len[3] = wpabuf_len(Y_pub) / 2;
8557 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8558 goto fail;
8559 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
8560
b3e4cc5c
JM
8561 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
8562 if (!msg)
500ed7f0 8563 goto fail;
60239f60 8564
500ed7f0 8565out:
500ed7f0
JM
8566 os_free(unwrapped);
8567 wpabuf_free(A_pub);
8568 wpabuf_free(B_pub);
8569 wpabuf_free(X_pub);
8570 wpabuf_free(Y_pub);
500ed7f0
JM
8571 return msg;
8572fail:
b3e4cc5c
JM
8573 wpa_printf(MSG_DEBUG,
8574 "DPP: PKEX Commit-Reveal Request processing failed");
500ed7f0
JM
8575 goto out;
8576}
8577
8578
4be5bc98 8579int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
500ed7f0
JM
8580 const u8 *buf, size_t buflen)
8581{
8582 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8583 const u8 *wrapped_data, *b_key, *peer_v;
8584 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
8585 const u8 *addr[4];
8586 size_t len[4];
8587 u8 octet;
8588 u8 *unwrapped = NULL;
8589 size_t unwrapped_len = 0;
8590 int ret = -1;
8591 u8 v[DPP_MAX_HASH_LEN];
8592 size_t Lx_len;
8593 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
8594 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8595
34603767
JM
8596#ifdef CONFIG_TESTING_OPTIONS
8597 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
8598 wpa_printf(MSG_INFO,
8599 "DPP: TESTING - stop at PKEX CR Response");
8600 pkex->failed = 1;
8601 goto fail;
8602 }
8603#endif /* CONFIG_TESTING_OPTIONS */
8604
29ab69e4 8605 if (!pkex->exchange_done || pkex->failed ||
03abb6b5 8606 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
e0247e79
JM
8607 goto fail;
8608
500ed7f0
JM
8609 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
8610 &wrapped_data_len);
8611 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
8612 dpp_pkex_fail(pkex,
8613 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
8614 goto fail;
8615 }
8616
8617 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8618 wrapped_data, wrapped_data_len);
8619 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
8620 unwrapped = os_malloc(unwrapped_len);
8621 if (!unwrapped)
8622 goto fail;
8623
4be5bc98
JM
8624 addr[0] = hdr;
8625 len[0] = DPP_HDR_LEN;
500ed7f0 8626 octet = 1;
4be5bc98
JM
8627 addr[1] = &octet;
8628 len[1] = sizeof(octet);
8629 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8630 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
8631
8632 if (aes_siv_decrypt(pkex->z, curve->hash_len,
8633 wrapped_data, wrapped_data_len,
4be5bc98 8634 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
8635 dpp_pkex_fail(pkex,
8636 "AES-SIV decryption failed - possible PKEX code mismatch");
29ab69e4 8637 pkex->t++;
500ed7f0
JM
8638 goto fail;
8639 }
8640 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
8641 unwrapped, unwrapped_len);
8642
8643 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 8644 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
8645 goto fail;
8646 }
8647
8648 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
8649 &b_key_len);
8650 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 8651 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
8652 goto fail;
8653 }
8654 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
8655 b_key_len);
d7e7b712
JM
8656 if (!pkex->peer_bootstrap_key) {
8657 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 8658 goto fail;
d7e7b712 8659 }
500ed7f0
JM
8660 dpp_debug_print_key("DPP: Peer bootstrap public key",
8661 pkex->peer_bootstrap_key);
8662
8663 /* ECDH: L' = x * B' */
29ef1c5e 8664 if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
500ed7f0 8665 goto fail;
500ed7f0
JM
8666
8667 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
8668 Lx, Lx_len);
8669
8670 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8671 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
8672 X_pub = dpp_get_pubkey_point(pkex->x, 0);
8673 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8674 if (!B_pub || !X_pub || !Y_pub)
8675 goto fail;
8676 addr[0] = pkex->peer_mac;
8677 len[0] = ETH_ALEN;
8678 addr[1] = wpabuf_head(B_pub);
8679 len[1] = wpabuf_len(B_pub) / 2;
8680 addr[2] = wpabuf_head(X_pub);
8681 len[2] = wpabuf_len(X_pub) / 2;
8682 addr[3] = wpabuf_head(Y_pub);
8683 len[3] = wpabuf_len(Y_pub) / 2;
8684 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8685 goto fail;
8686
8687 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
8688 &peer_v_len);
8689 if (!peer_v || peer_v_len != curve->hash_len ||
8690 os_memcmp(peer_v, v, curve->hash_len) != 0) {
d7e7b712 8691 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
500ed7f0
JM
8692 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
8693 v, curve->hash_len);
8694 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
29ab69e4 8695 pkex->t++;
500ed7f0
JM
8696 goto fail;
8697 }
8698 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
8699
8700 ret = 0;
8701out:
8702 wpabuf_free(B_pub);
8703 wpabuf_free(X_pub);
8704 wpabuf_free(Y_pub);
500ed7f0
JM
8705 os_free(unwrapped);
8706 return ret;
8707fail:
8708 goto out;
8709}
8710
8711
8712void dpp_pkex_free(struct dpp_pkex *pkex)
8713{
8714 if (!pkex)
8715 return;
8716
8717 os_free(pkex->identifier);
8718 os_free(pkex->code);
8719 EVP_PKEY_free(pkex->x);
8720 EVP_PKEY_free(pkex->y);
8721 EVP_PKEY_free(pkex->peer_bootstrap_key);
8722 wpabuf_free(pkex->exchange_req);
8723 wpabuf_free(pkex->exchange_resp);
8724 os_free(pkex);
8725}
4b8de0c9
JM
8726
8727
8728#ifdef CONFIG_TESTING_OPTIONS
8729char * dpp_corrupt_connector_signature(const char *connector)
8730{
8731 char *tmp, *pos, *signed3 = NULL;
8732 unsigned char *signature = NULL;
8733 size_t signature_len = 0, signed3_len;
8734
8735 tmp = os_zalloc(os_strlen(connector) + 5);
8736 if (!tmp)
8737 goto fail;
8738 os_memcpy(tmp, connector, os_strlen(connector));
8739
8740 pos = os_strchr(tmp, '.');
8741 if (!pos)
8742 goto fail;
8743
8744 pos = os_strchr(pos + 1, '.');
8745 if (!pos)
8746 goto fail;
8747 pos++;
8748
8749 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
8750 pos);
b2260842 8751 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
4b8de0c9
JM
8752 if (!signature || signature_len == 0)
8753 goto fail;
8754 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
8755 signature, signature_len);
8756 signature[signature_len - 1] ^= 0x01;
8757 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
8758 signature, signature_len);
b2260842 8759 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
4b8de0c9
JM
8760 if (!signed3)
8761 goto fail;
8762 os_memcpy(pos, signed3, signed3_len);
8763 pos[signed3_len] = '\0';
8764 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
8765 pos);
8766
8767out:
8768 os_free(signature);
8769 os_free(signed3);
8770 return tmp;
8771fail:
8772 os_free(tmp);
8773 tmp = NULL;
8774 goto out;
8775}
8776#endif /* CONFIG_TESTING_OPTIONS */
10ec6a5f
JM
8777
8778
8779#ifdef CONFIG_DPP2
8780
8781struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
8782 size_t net_access_key_len)
8783{
8784 struct wpabuf *pub = NULL;
8785 EVP_PKEY *own_key;
8786 struct dpp_pfs *pfs;
8787
8788 pfs = os_zalloc(sizeof(*pfs));
8789 if (!pfs)
8790 return NULL;
8791
8792 own_key = dpp_set_keypair(&pfs->curve, net_access_key,
8793 net_access_key_len);
8794 if (!own_key) {
8795 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
8796 goto fail;
8797 }
8798 EVP_PKEY_free(own_key);
8799
8800 pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
8801 if (!pfs->ecdh)
8802 goto fail;
8803
8804 pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
8805 pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
8806 if (!pub)
8807 goto fail;
8808
8809 pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
8810 if (!pfs->ie)
8811 goto fail;
8812 wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
8813 wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
8814 wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
8815 wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
8816 wpabuf_put_buf(pfs->ie, pub);
8817 wpabuf_free(pub);
8818 wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
8819 pfs->ie);
8820
8821 return pfs;
8822fail:
8823 wpabuf_free(pub);
8824 dpp_pfs_free(pfs);
8825 return NULL;
8826}
8827
8828
8829int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
8830{
8831 if (peer_ie_len < 2)
8832 return -1;
8833 if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
8834 wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
8835 return -1;
8836 }
8837
8838 pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
8839 peer_ie_len - 2);
8840 pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
8841 if (!pfs->secret) {
8842 wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
8843 return -1;
8844 }
8845 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
8846 return 0;
8847}
8848
8849
8850void dpp_pfs_free(struct dpp_pfs *pfs)
8851{
8852 if (!pfs)
8853 return;
8854 crypto_ecdh_deinit(pfs->ecdh);
8855 wpabuf_free(pfs->ie);
8856 wpabuf_clear_free(pfs->secret);
8857 os_free(pfs);
8858}
8859
8860#endif /* CONFIG_DPP2 */
87d8435c
JM
8861
8862
8863static unsigned int dpp_next_id(struct dpp_global *dpp)
8864{
8865 struct dpp_bootstrap_info *bi;
8866 unsigned int max_id = 0;
8867
8868 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8869 if (bi->id > max_id)
8870 max_id = bi->id;
8871 }
8872 return max_id + 1;
8873}
8874
8875
8876static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
8877{
8878 struct dpp_bootstrap_info *bi, *tmp;
8879 int found = 0;
8880
8881 if (!dpp)
8882 return -1;
8883
8884 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
8885 struct dpp_bootstrap_info, list) {
8886 if (id && bi->id != id)
8887 continue;
8888 found = 1;
8889 dl_list_del(&bi->list);
8890 dpp_bootstrap_info_free(bi);
8891 }
8892
8893 if (id == 0)
8894 return 0; /* flush succeeds regardless of entries found */
8895 return found ? 0 : -1;
8896}
8897
8898
8899struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
8900 const char *uri)
8901{
8902 struct dpp_bootstrap_info *bi;
8903
8904 if (!dpp)
8905 return NULL;
8906
8907 bi = dpp_parse_qr_code(uri);
8908 if (!bi)
8909 return NULL;
8910
8911 bi->id = dpp_next_id(dpp);
8912 dl_list_add(&dpp->bootstrap, &bi->list);
8913 return bi;
8914}
8915
8916
8917int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
8918{
8919 char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
8920 char *key = NULL;
8921 u8 *privkey = NULL;
8922 size_t privkey_len = 0;
8923 size_t len;
8924 int ret = -1;
8925 struct dpp_bootstrap_info *bi;
8926
8927 if (!dpp)
8928 return -1;
8929
8930 bi = os_zalloc(sizeof(*bi));
8931 if (!bi)
8932 goto fail;
8933
8934 if (os_strstr(cmd, "type=qrcode"))
8935 bi->type = DPP_BOOTSTRAP_QR_CODE;
8936 else if (os_strstr(cmd, "type=pkex"))
8937 bi->type = DPP_BOOTSTRAP_PKEX;
8938 else
8939 goto fail;
8940
8941 chan = get_param(cmd, " chan=");
8942 mac = get_param(cmd, " mac=");
8943 info = get_param(cmd, " info=");
8944 curve = get_param(cmd, " curve=");
8945 key = get_param(cmd, " key=");
8946
8947 if (key) {
8948 privkey_len = os_strlen(key) / 2;
8949 privkey = os_malloc(privkey_len);
8950 if (!privkey ||
8951 hexstr2bin(key, privkey, privkey_len) < 0)
8952 goto fail;
8953 }
8954
8955 pk = dpp_keygen(bi, curve, privkey, privkey_len);
8956 if (!pk)
8957 goto fail;
8958
8959 len = 4; /* "DPP:" */
8960 if (chan) {
8961 if (dpp_parse_uri_chan_list(bi, chan) < 0)
8962 goto fail;
8963 len += 3 + os_strlen(chan); /* C:...; */
8964 }
8965 if (mac) {
8966 if (dpp_parse_uri_mac(bi, mac) < 0)
8967 goto fail;
8968 len += 3 + os_strlen(mac); /* M:...; */
8969 }
8970 if (info) {
8971 if (dpp_parse_uri_info(bi, info) < 0)
8972 goto fail;
8973 len += 3 + os_strlen(info); /* I:...; */
8974 }
8975 len += 4 + os_strlen(pk);
8976 bi->uri = os_malloc(len + 1);
8977 if (!bi->uri)
8978 goto fail;
8979 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8980 chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
8981 mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
8982 info ? "I:" : "", info ? info : "", info ? ";" : "",
8983 pk);
8984 bi->id = dpp_next_id(dpp);
8985 dl_list_add(&dpp->bootstrap, &bi->list);
8986 ret = bi->id;
8987 bi = NULL;
8988fail:
8989 os_free(curve);
8990 os_free(pk);
8991 os_free(chan);
8992 os_free(mac);
8993 os_free(info);
8994 str_clear_free(key);
8995 bin_clear_free(privkey, privkey_len);
8996 dpp_bootstrap_info_free(bi);
8997 return ret;
8998}
8999
9000
9001struct dpp_bootstrap_info *
9002dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
9003{
9004 struct dpp_bootstrap_info *bi;
9005
9006 if (!dpp)
9007 return NULL;
9008
9009 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
9010 if (bi->id == id)
9011 return bi;
9012 }
9013 return NULL;
9014}
9015
9016
9017int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
9018{
9019 unsigned int id_val;
9020
9021 if (os_strcmp(id, "*") == 0) {
9022 id_val = 0;
9023 } else {
9024 id_val = atoi(id);
9025 if (id_val == 0)
9026 return -1;
9027 }
9028
9029 return dpp_bootstrap_del(dpp, id_val);
9030}
9031
9032
9033struct dpp_bootstrap_info *
9034dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
9035 unsigned int freq)
9036{
9037 struct dpp_bootstrap_info *bi;
9038
9039 bi = os_zalloc(sizeof(*bi));
9040 if (!bi)
9041 return NULL;
9042 bi->id = dpp_next_id(dpp);
9043 bi->type = DPP_BOOTSTRAP_PKEX;
9044 os_memcpy(bi->mac_addr, peer, ETH_ALEN);
9045 bi->num_freq = 1;
9046 bi->freq[0] = freq;
9047 bi->curve = pkex->own_bi->curve;
9048 bi->pubkey = pkex->peer_bootstrap_key;
9049 pkex->peer_bootstrap_key = NULL;
9050 if (dpp_bootstrap_key_hash(bi) < 0) {
9051 dpp_bootstrap_info_free(bi);
9052 return NULL;
9053 }
9054 dpp_pkex_free(pkex);
9055 dl_list_add(&dpp->bootstrap, &bi->list);
9056 return bi;
9057}
9058
9059
9060const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
9061{
9062 struct dpp_bootstrap_info *bi;
9063
9064 bi = dpp_bootstrap_get_id(dpp, id);
9065 if (!bi)
9066 return NULL;
9067 return bi->uri;
9068}
9069
9070
9071int dpp_bootstrap_info(struct dpp_global *dpp, int id,
9072 char *reply, int reply_size)
9073{
9074 struct dpp_bootstrap_info *bi;
9ffec2e8 9075 char pkhash[2 * SHA256_MAC_LEN + 1];
87d8435c
JM
9076
9077 bi = dpp_bootstrap_get_id(dpp, id);
9078 if (!bi)
9079 return -1;
9ffec2e8
JM
9080 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
9081 SHA256_MAC_LEN);
87d8435c
JM
9082 return os_snprintf(reply, reply_size, "type=%s\n"
9083 "mac_addr=" MACSTR "\n"
9084 "info=%s\n"
9085 "num_freq=%u\n"
9ffec2e8
JM
9086 "curve=%s\n"
9087 "pkhash=%s\n",
87d8435c
JM
9088 dpp_bootstrap_type_txt(bi->type),
9089 MAC2STR(bi->mac_addr),
9090 bi->info ? bi->info : "",
9091 bi->num_freq,
9ffec2e8
JM
9092 bi->curve->name,
9093 pkhash);
87d8435c
JM
9094}
9095
9096
9097void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
9098 const u8 *r_bootstrap,
9099 struct dpp_bootstrap_info **own_bi,
9100 struct dpp_bootstrap_info **peer_bi)
9101{
9102 struct dpp_bootstrap_info *bi;
9103
9104 *own_bi = NULL;
9105 *peer_bi = NULL;
9106 if (!dpp)
9107 return;
9108
9109 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
9110 if (!*own_bi && bi->own &&
9111 os_memcmp(bi->pubkey_hash, r_bootstrap,
9112 SHA256_MAC_LEN) == 0) {
9113 wpa_printf(MSG_DEBUG,
9114 "DPP: Found matching own bootstrapping information");
9115 *own_bi = bi;
9116 }
9117
9118 if (!*peer_bi && !bi->own &&
9119 os_memcmp(bi->pubkey_hash, i_bootstrap,
9120 SHA256_MAC_LEN) == 0) {
9121 wpa_printf(MSG_DEBUG,
9122 "DPP: Found matching peer bootstrapping information");
9123 *peer_bi = bi;
9124 }
9125
9126 if (*own_bi && *peer_bi)
9127 break;
9128 }
9129
9130}
9131
9132
9133static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
9134{
9135 struct dpp_configurator *conf;
9136 unsigned int max_id = 0;
9137
9138 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
9139 list) {
9140 if (conf->id > max_id)
9141 max_id = conf->id;
9142 }
9143 return max_id + 1;
9144}
9145
9146
9147int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
9148{
9149 char *curve = NULL;
9150 char *key = NULL;
9151 u8 *privkey = NULL;
9152 size_t privkey_len = 0;
9153 int ret = -1;
9154 struct dpp_configurator *conf = NULL;
9155
9156 curve = get_param(cmd, " curve=");
9157 key = get_param(cmd, " key=");
9158
9159 if (key) {
9160 privkey_len = os_strlen(key) / 2;
9161 privkey = os_malloc(privkey_len);
9162 if (!privkey ||
9163 hexstr2bin(key, privkey, privkey_len) < 0)
9164 goto fail;
9165 }
9166
9167 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
9168 if (!conf)
9169 goto fail;
9170
9171 conf->id = dpp_next_configurator_id(dpp);
9172 dl_list_add(&dpp->configurator, &conf->list);
9173 ret = conf->id;
9174 conf = NULL;
9175fail:
9176 os_free(curve);
9177 str_clear_free(key);
9178 bin_clear_free(privkey, privkey_len);
9179 dpp_configurator_free(conf);
9180 return ret;
9181}
9182
9183
9184static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
9185{
9186 struct dpp_configurator *conf, *tmp;
9187 int found = 0;
9188
9189 if (!dpp)
9190 return -1;
9191
9192 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
9193 struct dpp_configurator, list) {
9194 if (id && conf->id != id)
9195 continue;
9196 found = 1;
9197 dl_list_del(&conf->list);
9198 dpp_configurator_free(conf);
9199 }
9200
9201 if (id == 0)
9202 return 0; /* flush succeeds regardless of entries found */
9203 return found ? 0 : -1;
9204}
9205
9206
9207int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
9208{
9209 unsigned int id_val;
9210
9211 if (os_strcmp(id, "*") == 0) {
9212 id_val = 0;
9213 } else {
9214 id_val = atoi(id);
9215 if (id_val == 0)
9216 return -1;
9217 }
9218
9219 return dpp_configurator_del(dpp, id_val);
9220}
9221
9222
9223int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
9224 char *buf, size_t buflen)
9225{
9226 struct dpp_configurator *conf;
9227
9228 conf = dpp_configurator_get_id(dpp, id);
9229 if (!conf)
9230 return -1;
9231
9232 return dpp_configurator_get_key(conf, buf, buflen);
9233}
9234
9235
88a78bdd
JM
9236#ifdef CONFIG_DPP2
9237
b10e01a7
JM
9238static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
9239 void *timeout_ctx);
9240
9241
88a78bdd
JM
9242static void dpp_connection_free(struct dpp_connection *conn)
9243{
9244 if (conn->sock >= 0) {
9245 wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
9246 conn->sock);
9247 eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
9248 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
9249 close(conn->sock);
9250 }
b10e01a7
JM
9251 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
9252 conn, NULL);
88a78bdd
JM
9253 wpabuf_free(conn->msg);
9254 wpabuf_free(conn->msg_out);
9255 dpp_auth_deinit(conn->auth);
9256 os_free(conn);
9257}
9258
9259
9260static void dpp_connection_remove(struct dpp_connection *conn)
9261{
9262 dl_list_del(&conn->list);
9263 dpp_connection_free(conn);
9264}
9265
9266
9267static void dpp_tcp_init_flush(struct dpp_global *dpp)
9268{
9269 struct dpp_connection *conn, *tmp;
9270
9271 dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
9272 list)
9273 dpp_connection_remove(conn);
9274}
9275
9276
9277static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
9278{
9279 struct dpp_connection *conn, *tmp;
9280
9281 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
9282 list)
9283 dpp_connection_remove(conn);
9284 os_free(ctrl);
9285}
9286
9287
9288static void dpp_relay_flush_controllers(struct dpp_global *dpp)
9289{
9290 struct dpp_relay_controller *ctrl, *tmp;
9291
9292 if (!dpp)
9293 return;
9294
9295 dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
9296 struct dpp_relay_controller, list) {
9297 dl_list_del(&ctrl->list);
9298 dpp_relay_controller_free(ctrl);
9299 }
9300}
9301
9302#endif /* CONFIG_DPP2 */
9303
9304
2ed2b52f 9305struct dpp_global * dpp_global_init(struct dpp_global_config *config)
87d8435c
JM
9306{
9307 struct dpp_global *dpp;
9308
9309 dpp = os_zalloc(sizeof(*dpp));
9310 if (!dpp)
9311 return NULL;
2ed2b52f 9312 dpp->msg_ctx = config->msg_ctx;
88a78bdd
JM
9313#ifdef CONFIG_DPP2
9314 dpp->cb_ctx = config->cb_ctx;
9315 dpp->process_conf_obj = config->process_conf_obj;
9316#endif /* CONFIG_DPP2 */
87d8435c
JM
9317
9318 dl_list_init(&dpp->bootstrap);
9319 dl_list_init(&dpp->configurator);
88a78bdd
JM
9320#ifdef CONFIG_DPP2
9321 dl_list_init(&dpp->controllers);
9322 dl_list_init(&dpp->tcp_init);
9323#endif /* CONFIG_DPP2 */
87d8435c
JM
9324
9325 return dpp;
9326}
9327
9328
9329void dpp_global_clear(struct dpp_global *dpp)
9330{
9331 if (!dpp)
9332 return;
9333
9334 dpp_bootstrap_del(dpp, 0);
9335 dpp_configurator_del(dpp, 0);
88a78bdd
JM
9336#ifdef CONFIG_DPP2
9337 dpp_tcp_init_flush(dpp);
9338 dpp_relay_flush_controllers(dpp);
9339 dpp_controller_stop(dpp);
9340#endif /* CONFIG_DPP2 */
87d8435c
JM
9341}
9342
9343
9344void dpp_global_deinit(struct dpp_global *dpp)
9345{
9346 dpp_global_clear(dpp);
9347 os_free(dpp);
9348}
88a78bdd
JM
9349
9350
9351#ifdef CONFIG_DPP2
9352
9353static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
9354static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
9355static void dpp_controller_auth_success(struct dpp_connection *conn,
9356 int initiator);
9357
9358
9359int dpp_relay_add_controller(struct dpp_global *dpp,
9360 struct dpp_relay_config *config)
9361{
9362 struct dpp_relay_controller *ctrl;
9363
9364 if (!dpp)
9365 return -1;
9366
9367 ctrl = os_zalloc(sizeof(*ctrl));
9368 if (!ctrl)
9369 return -1;
9370 dl_list_init(&ctrl->conn);
9371 ctrl->global = dpp;
9372 os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
9373 os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
9374 ctrl->cb_ctx = config->cb_ctx;
9375 ctrl->tx = config->tx;
9376 ctrl->gas_resp_tx = config->gas_resp_tx;
9377 dl_list_add(&dpp->controllers, &ctrl->list);
9378 return 0;
9379}
9380
9381
9382static struct dpp_relay_controller *
9383dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
9384{
9385 struct dpp_relay_controller *ctrl;
9386
9387 if (!dpp)
9388 return NULL;
9389
9390 dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
9391 list) {
9392 if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
9393 return ctrl;
9394 }
9395
9396 return NULL;
9397}
9398
9399
9400static void dpp_controller_gas_done(struct dpp_connection *conn)
9401{
9402 struct dpp_authentication *auth = conn->auth;
9403
9404 if (auth->peer_version >= 2 &&
9405 auth->conf_resp_status == DPP_STATUS_OK) {
9406 wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
9407 auth->waiting_conf_result = 1;
9408 return;
9409 }
9410
9411 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
9412 dpp_connection_remove(conn);
9413}
9414
9415
9416static int dpp_tcp_send(struct dpp_connection *conn)
9417{
9418 int res;
9419
9420 if (!conn->msg_out) {
9421 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
9422 conn->write_eloop = 0;
9423 return -1;
9424 }
9425 res = send(conn->sock,
9426 wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
9427 wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
9428 if (res < 0) {
9429 wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
9430 strerror(errno));
9431 dpp_connection_remove(conn);
9432 return -1;
9433 }
9434
9435 conn->msg_out_pos += res;
9436 if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
9437 wpa_printf(MSG_DEBUG,
9438 "DPP: %u/%u bytes of message sent to Controller",
9439 (unsigned int) conn->msg_out_pos,
9440 (unsigned int) wpabuf_len(conn->msg_out));
9441 if (!conn->write_eloop &&
9442 eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9443 dpp_conn_tx_ready, conn, NULL) == 0)
9444 conn->write_eloop = 1;
9445 return 1;
9446 }
9447
9448 wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
9449 wpabuf_free(conn->msg_out);
9450 conn->msg_out = NULL;
9451 conn->msg_out_pos = 0;
9452 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
9453 conn->write_eloop = 0;
9454 if (!conn->read_eloop &&
9455 eloop_register_sock(conn->sock, EVENT_TYPE_READ,
9456 dpp_controller_rx, conn, NULL) == 0)
9457 conn->read_eloop = 1;
9458 if (conn->on_tcp_tx_complete_remove) {
9459 dpp_connection_remove(conn);
9460 } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
9461 conn->auth) {
9462 dpp_controller_gas_done(conn);
9463 } else if (conn->on_tcp_tx_complete_auth_ok) {
9464 conn->on_tcp_tx_complete_auth_ok = 0;
9465 dpp_controller_auth_success(conn, 1);
9466 }
9467
9468 return 0;
9469}
9470
9471
9472static void dpp_controller_start_gas_client(struct dpp_connection *conn)
9473{
9474 struct dpp_authentication *auth = conn->auth;
9475 struct wpabuf *buf;
88a78bdd
JM
9476 int netrole_ap = 0; /* TODO: make this configurable */
9477
8f8c423a 9478 buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
88a78bdd
JM
9479 if (!buf) {
9480 wpa_printf(MSG_DEBUG,
9481 "DPP: No configuration request data available");
9482 return;
9483 }
9484
9485 wpabuf_free(conn->msg_out);
9486 conn->msg_out_pos = 0;
9487 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1);
9488 if (!conn->msg_out) {
9489 wpabuf_free(buf);
9490 return;
9491 }
9492 wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
fc03ea2c 9493 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
88a78bdd
JM
9494 wpabuf_len(buf) - 1);
9495 wpabuf_free(buf);
9496
9497 if (dpp_tcp_send(conn) == 1) {
9498 if (!conn->write_eloop) {
9499 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9500 dpp_conn_tx_ready,
9501 conn, NULL) < 0)
9502 return;
9503 conn->write_eloop = 1;
9504 }
9505 }
9506}
9507
9508
9509static void dpp_controller_auth_success(struct dpp_connection *conn,
9510 int initiator)
9511{
9512 struct dpp_authentication *auth = conn->auth;
9513
9514 if (!auth)
9515 return;
9516
9517 wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
9518 wpa_msg(conn->global->msg_ctx, MSG_INFO,
9519 DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
9520#ifdef CONFIG_TESTING_OPTIONS
9521 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
9522 wpa_printf(MSG_INFO,
9523 "DPP: TESTING - stop at Authentication Confirm");
9524 if (auth->configurator) {
9525 /* Prevent GAS response */
9526 auth->auth_success = 0;
9527 }
9528 return;
9529 }
9530#endif /* CONFIG_TESTING_OPTIONS */
9531
9532 if (!auth->configurator)
9533 dpp_controller_start_gas_client(conn);
9534}
9535
9536
9537static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
9538{
9539 struct dpp_connection *conn = eloop_ctx;
9540
9541 wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
9542 dpp_tcp_send(conn);
9543}
9544
9545
9546static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
9547 const struct hostapd_ip_addr *ipaddr,
9548 int port)
9549{
9550 struct sockaddr_in *dst;
9551#ifdef CONFIG_IPV6
9552 struct sockaddr_in6 *dst6;
9553#endif /* CONFIG_IPV6 */
9554
9555 switch (ipaddr->af) {
9556 case AF_INET:
9557 dst = (struct sockaddr_in *) addr;
9558 os_memset(dst, 0, sizeof(*dst));
9559 dst->sin_family = AF_INET;
9560 dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
9561 dst->sin_port = htons(port);
9562 *addrlen = sizeof(*dst);
9563 break;
9564#ifdef CONFIG_IPV6
9565 case AF_INET6:
9566 dst6 = (struct sockaddr_in6 *) addr;
9567 os_memset(dst6, 0, sizeof(*dst6));
9568 dst6->sin6_family = AF_INET6;
9569 os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
9570 sizeof(struct in6_addr));
9571 dst6->sin6_port = htons(port);
9572 *addrlen = sizeof(*dst6);
9573 break;
9574#endif /* CONFIG_IPV6 */
9575 default:
9576 return -1;
9577 }
9578
9579 return 0;
9580}
9581
9582
9583static struct dpp_connection *
9584dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
9585 unsigned int freq)
9586{
9587 struct dpp_connection *conn;
9588 struct sockaddr_storage addr;
9589 socklen_t addrlen;
9590 char txt[100];
9591
9592 if (dl_list_len(&ctrl->conn) >= 15) {
9593 wpa_printf(MSG_DEBUG,
9594 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
9595 return NULL;
9596 }
9597
9598 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
9599 &ctrl->ipaddr, DPP_TCP_PORT) < 0)
9600 return NULL;
9601
9602 conn = os_zalloc(sizeof(*conn));
9603 if (!conn)
9604 return NULL;
9605
9606 conn->global = ctrl->global;
9607 conn->relay = ctrl;
9608 os_memcpy(conn->mac_addr, src, ETH_ALEN);
9609 conn->freq = freq;
9610
9611 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
9612 if (conn->sock < 0)
9613 goto fail;
9614 wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
9615 conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
9616
9617 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
9618 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
9619 strerror(errno));
9620 goto fail;
9621 }
9622
9623 if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
9624 if (errno != EINPROGRESS) {
9625 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
9626 strerror(errno));
9627 goto fail;
9628 }
9629
9630 /*
9631 * Continue connecting in the background; eloop will call us
9632 * once the connection is ready (or failed).
9633 */
9634 }
9635
9636 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9637 dpp_conn_tx_ready, conn, NULL) < 0)
9638 goto fail;
9639 conn->write_eloop = 1;
9640
9641 /* TODO: eloop timeout to clear a connection if it does not complete
9642 * properly */
9643
9644 dl_list_add(&ctrl->conn, &conn->list);
9645 return conn;
9646fail:
9647 dpp_connection_free(conn);
9648 return NULL;
9649}
9650
9651
9652static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
9653{
9654 struct wpabuf *msg;
9655
9656 msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
9657 if (!msg)
9658 return NULL;
9659 wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
9660 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
9661 wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
9662 wpabuf_put_data(msg, buf, len);
9663 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
9664 return msg;
9665}
9666
9667
9668static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
9669 const u8 *buf, size_t len)
9670{
9671 u8 type = hdr[DPP_HDR_LEN - 1];
9672
9673 wpa_printf(MSG_DEBUG,
9674 "DPP: Continue already established Relay/Controller connection for this session");
9675 wpabuf_free(conn->msg_out);
9676 conn->msg_out_pos = 0;
9677 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
9678 if (!conn->msg_out) {
9679 dpp_connection_remove(conn);
9680 return -1;
9681 }
9682
9683 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
9684 * TX status */
9685 if (type == DPP_PA_CONFIGURATION_RESULT)
9686 conn->on_tcp_tx_complete_remove = 1;
9687 dpp_tcp_send(conn);
9688 return 0;
9689}
9690
9691
9692int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
9693 const u8 *buf, size_t len, unsigned int freq,
9694 const u8 *i_bootstrap, const u8 *r_bootstrap)
9695{
9696 struct dpp_relay_controller *ctrl;
9697 struct dpp_connection *conn;
9698 u8 type = hdr[DPP_HDR_LEN - 1];
9699
9700 /* Check if there is an already started session for this peer and if so,
9701 * continue that session (send this over TCP) and return 0.
9702 */
9703 if (type != DPP_PA_PEER_DISCOVERY_REQ &&
9704 type != DPP_PA_PEER_DISCOVERY_RESP) {
9705 dl_list_for_each(ctrl, &dpp->controllers,
9706 struct dpp_relay_controller, list) {
9707 dl_list_for_each(conn, &ctrl->conn,
9708 struct dpp_connection, list) {
9709 if (os_memcmp(src, conn->mac_addr,
9710 ETH_ALEN) == 0)
9711 return dpp_relay_tx(conn, hdr, buf, len);
9712 }
9713 }
9714 }
9715
9716 if (!r_bootstrap)
9717 return -1;
9718
9719 ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
9720 if (!ctrl)
9721 return -1;
9722
9723 wpa_printf(MSG_DEBUG,
9724 "DPP: Authentication Request for a configured Controller");
9725 conn = dpp_relay_new_conn(ctrl, src, freq);
9726 if (!conn)
9727 return -1;
9728
9729 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
9730 if (!conn->msg_out) {
9731 dpp_connection_remove(conn);
9732 return -1;
9733 }
9734 /* Message will be sent in dpp_conn_tx_ready() */
9735
9736 return 0;
9737}
9738
9739
9740int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
9741 size_t data_len)
9742{
9743 struct dpp_relay_controller *ctrl;
9744 struct dpp_connection *conn, *found = NULL;
9745 struct wpabuf *msg;
9746
9747 /* Check if there is a successfully completed authentication for this
9748 * and if so, continue that session (send this over TCP) and return 0.
9749 */
9750 dl_list_for_each(ctrl, &dpp->controllers,
9751 struct dpp_relay_controller, list) {
9752 if (found)
9753 break;
9754 dl_list_for_each(conn, &ctrl->conn,
9755 struct dpp_connection, list) {
9756 if (os_memcmp(src, conn->mac_addr,
9757 ETH_ALEN) == 0) {
9758 found = conn;
9759 break;
9760 }
9761 }
9762 }
9763
9764 if (!found)
9765 return -1;
9766
9767 msg = wpabuf_alloc(4 + 1 + data_len);
9768 if (!msg)
9769 return -1;
9770 wpabuf_put_be32(msg, 1 + data_len);
9771 wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
9772 wpabuf_put_data(msg, data, data_len);
9773 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
9774
9775 wpabuf_free(conn->msg_out);
9776 conn->msg_out_pos = 0;
9777 conn->msg_out = msg;
9778 dpp_tcp_send(conn);
9779 return 0;
9780}
9781
9782
9783static void dpp_controller_free(struct dpp_controller *ctrl)
9784{
9785 struct dpp_connection *conn, *tmp;
9786
9787 if (!ctrl)
9788 return;
9789
9790 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
9791 list)
9792 dpp_connection_remove(conn);
9793
9794 if (ctrl->sock >= 0) {
9795 close(ctrl->sock);
9796 eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
9797 }
9798 os_free(ctrl->configurator_params);
9799 os_free(ctrl);
9800}
9801
9802
9803static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
9804 const u8 *hdr, const u8 *buf, size_t len)
9805{
9806 const u8 *r_bootstrap, *i_bootstrap;
9807 u16 r_bootstrap_len, i_bootstrap_len;
9808 struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
9809
b93a0ce7
JM
9810 if (!conn->ctrl)
9811 return 0;
9812
88a78bdd
JM
9813 wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
9814
9815 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
9816 &r_bootstrap_len);
9817 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
9818 wpa_printf(MSG_INFO,
9819 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
9820 return -1;
9821 }
9822 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
9823 r_bootstrap, r_bootstrap_len);
9824
9825 i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
9826 &i_bootstrap_len);
9827 if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
9828 wpa_printf(MSG_INFO,
9829 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
9830 return -1;
9831 }
9832 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
9833 i_bootstrap, i_bootstrap_len);
9834
9835 /* Try to find own and peer bootstrapping key matches based on the
9836 * received hash values */
9837 dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
9838 &own_bi, &peer_bi);
9839 if (!own_bi) {
9840 wpa_printf(MSG_INFO,
9841 "No matching own bootstrapping key found - ignore message");
9842 return -1;
9843 }
9844
9845 if (conn->auth) {
9846 wpa_printf(MSG_INFO,
9847 "Already in DPP authentication exchange - ignore new one");
9848 return 0;
9849 }
9850
9851 conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx,
9852 conn->ctrl->allowed_roles,
9853 conn->ctrl->qr_mutual,
9854 peer_bi, own_bi, -1, hdr, buf, len);
9855 if (!conn->auth) {
9856 wpa_printf(MSG_DEBUG, "DPP: No response generated");
9857 return -1;
9858 }
9859
b93a0ce7 9860 if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx,
88a78bdd
JM
9861 conn->auth,
9862 conn->ctrl->configurator_params) < 0) {
9863 dpp_connection_remove(conn);
9864 return -1;
9865 }
9866
9867 wpabuf_free(conn->msg_out);
9868 conn->msg_out_pos = 0;
9869 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1);
9870 if (!conn->msg_out)
9871 return -1;
9872 wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
fc03ea2c 9873 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
88a78bdd
JM
9874 wpabuf_len(conn->auth->resp_msg) - 1);
9875
9876 if (dpp_tcp_send(conn) == 1) {
9877 if (!conn->write_eloop) {
9878 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9879 dpp_conn_tx_ready,
9880 conn, NULL) < 0)
9881 return -1;
9882 conn->write_eloop = 1;
9883 }
9884 }
9885
9886 return 0;
9887}
9888
9889
9890static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
9891 const u8 *hdr, const u8 *buf, size_t len)
9892{
9893 struct dpp_authentication *auth = conn->auth;
9894 struct wpabuf *msg;
9895
9896 if (!auth)
9897 return -1;
9898
9899 wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
9900
9901 msg = dpp_auth_resp_rx(auth, hdr, buf, len);
9902 if (!msg) {
9903 if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
9904 wpa_printf(MSG_DEBUG,
9905 "DPP: Start wait for full response");
9906 return -1;
9907 }
9908 wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
9909 dpp_connection_remove(conn);
9910 return -1;
9911 }
9912
9913 wpabuf_free(conn->msg_out);
9914 conn->msg_out_pos = 0;
9915 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
9916 if (!conn->msg_out) {
9917 wpabuf_free(msg);
9918 return -1;
9919 }
9920 wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
fc03ea2c 9921 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
88a78bdd
JM
9922 wpabuf_len(msg) - 1);
9923 wpabuf_free(msg);
9924
9925 conn->on_tcp_tx_complete_auth_ok = 1;
9926 if (dpp_tcp_send(conn) == 1) {
9927 if (!conn->write_eloop) {
9928 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9929 dpp_conn_tx_ready,
9930 conn, NULL) < 0)
9931 return -1;
9932 conn->write_eloop = 1;
9933 }
9934 }
9935
9936 return 0;
9937}
9938
9939
9940static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
9941 const u8 *hdr, const u8 *buf, size_t len)
9942{
9943 struct dpp_authentication *auth = conn->auth;
9944
9945 wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
9946
9947 if (!auth) {
9948 wpa_printf(MSG_DEBUG,
9949 "DPP: No DPP Authentication in progress - drop");
9950 return -1;
9951 }
9952
9953 if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
9954 wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
9955 return -1;
9956 }
9957
9958 dpp_controller_auth_success(conn, 0);
9959 return 0;
9960}
9961
9962
b10e01a7
JM
9963static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
9964 void *timeout_ctx)
9965{
9966 struct dpp_connection *conn = eloop_ctx;
9967
9968 if (!conn->auth->waiting_conf_result)
9969 return;
9970
9971 wpa_printf(MSG_DEBUG,
9972 "DPP: Timeout while waiting for Connection Status Result");
9973 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
9974 DPP_EVENT_CONN_STATUS_RESULT "timeout");
9975 dpp_connection_remove(conn);
9976}
9977
9978
88a78bdd
JM
9979static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
9980 const u8 *hdr, const u8 *buf,
9981 size_t len)
9982{
9983 struct dpp_authentication *auth = conn->auth;
9984 enum dpp_status_error status;
9985
9986 if (!conn->ctrl)
9987 return 0;
9988
9989 wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
9990
9991 if (!auth || !auth->waiting_conf_result) {
9992 wpa_printf(MSG_DEBUG,
9993 "DPP: No DPP Configuration waiting for result - drop");
9994 return -1;
9995 }
9996
9997 status = dpp_conf_result_rx(auth, hdr, buf, len);
b10e01a7
JM
9998 if (status == DPP_STATUS_OK && auth->send_conn_status) {
9999 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10000 DPP_EVENT_CONF_SENT "wait_conn_status=1");
10001 wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
10002 eloop_cancel_timeout(
10003 dpp_controller_conn_status_result_wait_timeout,
10004 conn, NULL);
10005 eloop_register_timeout(
10006 16, 0, dpp_controller_conn_status_result_wait_timeout,
10007 conn, NULL);
10008 return 0;
10009 }
88a78bdd
JM
10010 if (status == DPP_STATUS_OK)
10011 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10012 DPP_EVENT_CONF_SENT);
10013 else
10014 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10015 DPP_EVENT_CONF_FAILED);
10016 return -1; /* to remove the completed connection */
10017}
10018
10019
b10e01a7
JM
10020static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
10021 const u8 *hdr, const u8 *buf,
10022 size_t len)
10023{
10024 struct dpp_authentication *auth = conn->auth;
10025 enum dpp_status_error status;
10026 u8 ssid[SSID_MAX_LEN];
10027 size_t ssid_len = 0;
10028 char *channel_list = NULL;
10029
10030 if (!conn->ctrl)
10031 return 0;
10032
10033 wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
10034
10035 if (!auth || !auth->waiting_conn_status_result) {
10036 wpa_printf(MSG_DEBUG,
10037 "DPP: No DPP Configuration waiting for connection status result - drop");
10038 return -1;
10039 }
10040
10041 status = dpp_conn_status_result_rx(auth, hdr, buf, len,
10042 ssid, &ssid_len, &channel_list);
10043 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10044 DPP_EVENT_CONN_STATUS_RESULT
10045 "result=%d ssid=%s channel_list=%s",
10046 status, wpa_ssid_txt(ssid, ssid_len),
10047 channel_list ? channel_list : "N/A");
10048 os_free(channel_list);
10049 return -1; /* to remove the completed connection */
10050}
10051
10052
88a78bdd
JM
10053static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
10054 size_t len)
10055{
10056 const u8 *pos, *end;
10057 u8 type;
10058
10059 wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
10060 pos = msg;
10061 end = msg + len;
10062
10063 if (end - pos < DPP_HDR_LEN ||
10064 WPA_GET_BE24(pos) != OUI_WFA ||
10065 pos[3] != DPP_OUI_TYPE) {
10066 wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
10067 return -1;
10068 }
10069
10070 if (pos[4] != 1) {
10071 wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
10072 pos[4]);
10073 return -1;
10074 }
10075 type = pos[5];
10076 wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
10077 pos += DPP_HDR_LEN;
10078
10079 wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
10080 pos, end - pos);
10081 if (dpp_check_attrs(pos, end - pos) < 0)
10082 return -1;
10083
10084 if (conn->relay) {
10085 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
10086 conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
10087 conn->freq, msg, len);
10088 return 0;
10089 }
10090
10091 switch (type) {
10092 case DPP_PA_AUTHENTICATION_REQ:
10093 return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
10094 case DPP_PA_AUTHENTICATION_RESP:
10095 return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
10096 case DPP_PA_AUTHENTICATION_CONF:
10097 return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
10098 case DPP_PA_CONFIGURATION_RESULT:
10099 return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
b10e01a7
JM
10100 case DPP_PA_CONNECTION_STATUS_RESULT:
10101 return dpp_controller_rx_conn_status_result(conn, msg, pos,
10102 end - pos);
88a78bdd
JM
10103 default:
10104 /* TODO: missing messages types */
10105 wpa_printf(MSG_DEBUG,
10106 "DPP: Unsupported frame subtype %d", type);
10107 return -1;
10108 }
10109}
10110
10111
10112static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
10113 size_t len)
10114{
10115 const u8 *pos, *end, *next;
10116 u8 dialog_token;
10117 const u8 *adv_proto;
10118 u16 slen;
10119 struct wpabuf *resp, *buf;
10120 struct dpp_authentication *auth = conn->auth;
10121
10122 if (len < 1 + 2)
10123 return -1;
10124
10125 wpa_printf(MSG_DEBUG,
10126 "DPP: Received DPP Configuration Request over TCP");
10127
10128 if (!conn->ctrl || !auth || !auth->auth_success) {
10129 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
10130 return -1;
10131 }
10132
10133 pos = msg;
10134 end = msg + len;
10135
10136 dialog_token = *pos++;
10137 adv_proto = pos++;
10138 slen = *pos++;
10139 if (*adv_proto != WLAN_EID_ADV_PROTO ||
10140 slen > end - pos || slen < 2)
10141 return -1;
10142
10143 next = pos + slen;
10144 pos++; /* skip QueryRespLenLimit and PAME-BI */
10145
10146 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
10147 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
10148 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
10149 return -1;
10150
10151 pos = next;
10152 /* Query Request */
10153 if (end - pos < 2)
10154 return -1;
10155 slen = WPA_GET_LE16(pos);
10156 pos += 2;
10157 if (slen > end - pos)
10158 return -1;
10159
10160 resp = dpp_conf_req_rx(auth, pos, slen);
10161 if (!resp)
10162 return -1;
10163
10164 buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
10165 if (!buf) {
10166 wpabuf_free(resp);
10167 return -1;
10168 }
10169
10170 wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
10171
10172 wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
10173 wpabuf_put_u8(buf, dialog_token);
10174 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
10175 wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
10176
10177 dpp_write_adv_proto(buf);
10178 dpp_write_gas_query(buf, resp);
10179 wpabuf_free(resp);
10180
10181 /* Send Config Response over TCP; GAS fragmentation is taken care of by
10182 * the Relay */
10183 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
10184 wpabuf_free(conn->msg_out);
10185 conn->msg_out_pos = 0;
10186 conn->msg_out = buf;
10187 conn->on_tcp_tx_complete_gas_done = 1;
10188 dpp_tcp_send(conn);
10189 return 0;
10190}
10191
10192
10193static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
10194{
10195 struct dpp_authentication *auth = conn->auth;
10196 int res;
10197 struct wpabuf *msg, *encaps;
10198 enum dpp_status_error status;
10199
10200 wpa_printf(MSG_DEBUG,
10201 "DPP: Configuration Response for local stack from TCP");
10202
10203 res = dpp_conf_resp_rx(auth, resp);
10204 wpabuf_free(resp);
10205 if (res < 0) {
10206 wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
10207 return -1;
10208 }
10209
10210 if (conn->global->process_conf_obj)
10211 res = conn->global->process_conf_obj(conn->global->cb_ctx,
10212 auth);
10213 else
10214 res = 0;
10215
10216 if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
10217 return -1;
10218
cc839952 10219#ifdef CONFIG_DPP2
88a78bdd
JM
10220 wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
10221 status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
10222 msg = dpp_build_conf_result(auth, status);
10223 if (!msg)
10224 return -1;
10225
10226 encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
10227 if (!encaps) {
10228 wpabuf_free(msg);
10229 return -1;
10230 }
10231 wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
fc03ea2c 10232 wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
88a78bdd
JM
10233 wpabuf_free(msg);
10234 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
10235
10236 wpabuf_free(conn->msg_out);
10237 conn->msg_out_pos = 0;
10238 conn->msg_out = encaps;
10239 conn->on_tcp_tx_complete_remove = 1;
10240 dpp_tcp_send(conn);
10241
10242 /* This exchange will be terminated in the TX status handler */
10243
10244 return 0;
cc839952
JM
10245#else /* CONFIG_DPP2 */
10246 return -1;
10247#endif /* CONFIG_DPP2 */
88a78bdd
JM
10248}
10249
10250
10251static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
10252 size_t len)
10253{
10254 struct wpabuf *buf;
10255 u8 dialog_token;
10256 const u8 *pos, *end, *next, *adv_proto;
10257 u16 status, slen;
10258
10259 if (len < 5 + 2)
10260 return -1;
10261
10262 wpa_printf(MSG_DEBUG,
10263 "DPP: Received DPP Configuration Response over TCP");
10264
10265 pos = msg;
10266 end = msg + len;
10267
10268 dialog_token = *pos++;
10269 status = WPA_GET_LE16(pos);
10270 if (status != WLAN_STATUS_SUCCESS) {
10271 wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
10272 return -1;
10273 }
10274 pos += 2;
10275 pos += 2; /* ignore GAS Comeback Delay */
10276
10277 adv_proto = pos++;
10278 slen = *pos++;
10279 if (*adv_proto != WLAN_EID_ADV_PROTO ||
10280 slen > end - pos || slen < 2)
10281 return -1;
10282
10283 next = pos + slen;
10284 pos++; /* skip QueryRespLenLimit and PAME-BI */
10285
10286 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
10287 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
10288 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
10289 return -1;
10290
10291 pos = next;
10292 /* Query Response */
10293 if (end - pos < 2)
10294 return -1;
10295 slen = WPA_GET_LE16(pos);
10296 pos += 2;
10297 if (slen > end - pos)
10298 return -1;
10299
10300 buf = wpabuf_alloc(slen);
10301 if (!buf)
10302 return -1;
10303 wpabuf_put_data(buf, pos, slen);
10304
10305 if (!conn->relay && !conn->ctrl)
10306 return dpp_tcp_rx_gas_resp(conn, buf);
10307
10308 if (!conn->relay) {
10309 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
10310 wpabuf_free(buf);
10311 return -1;
10312 }
10313 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
10314 conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
10315 dialog_token, 0, buf);
10316
10317 return 0;
10318}
10319
10320
10321static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
10322{
10323 struct dpp_connection *conn = eloop_ctx;
10324 int res;
10325 const u8 *pos;
10326
10327 wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
10328 sd);
10329
10330 if (conn->msg_len_octets < 4) {
10331 u32 msglen;
10332
10333 res = recv(sd, &conn->msg_len[conn->msg_len_octets],
10334 4 - conn->msg_len_octets, 0);
10335 if (res < 0) {
10336 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
10337 strerror(errno));
10338 dpp_connection_remove(conn);
10339 return;
10340 }
10341 if (res == 0) {
10342 wpa_printf(MSG_DEBUG,
10343 "DPP: No more data available over TCP");
10344 dpp_connection_remove(conn);
10345 return;
10346 }
10347 wpa_printf(MSG_DEBUG,
10348 "DPP: Received %d/%d octet(s) of message length field",
10349 res, (int) (4 - conn->msg_len_octets));
10350 conn->msg_len_octets += res;
10351
10352 if (conn->msg_len_octets < 4) {
10353 wpa_printf(MSG_DEBUG,
10354 "DPP: Need %d more octets of message length field",
10355 (int) (4 - conn->msg_len_octets));
10356 return;
10357 }
10358
10359 msglen = WPA_GET_BE32(conn->msg_len);
10360 wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
10361 if (msglen > 65535) {
10362 wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
10363 dpp_connection_remove(conn);
10364 return;
10365 }
10366
10367 wpabuf_free(conn->msg);
10368 conn->msg = wpabuf_alloc(msglen);
10369 }
10370
10371 if (!conn->msg) {
10372 wpa_printf(MSG_DEBUG,
10373 "DPP: No buffer available for receiving the message");
10374 dpp_connection_remove(conn);
10375 return;
10376 }
10377
10378 wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
10379 (unsigned int) wpabuf_tailroom(conn->msg));
10380
10381 res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
10382 if (res < 0) {
10383 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
10384 dpp_connection_remove(conn);
10385 return;
10386 }
10387 if (res == 0) {
10388 wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
10389 dpp_connection_remove(conn);
10390 return;
10391 }
10392 wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
10393 wpabuf_put(conn->msg, res);
10394
10395 if (wpabuf_tailroom(conn->msg) > 0) {
10396 wpa_printf(MSG_DEBUG,
10397 "DPP: Need %u more octets of message payload",
10398 (unsigned int) wpabuf_tailroom(conn->msg));
10399 return;
10400 }
10401
10402 conn->msg_len_octets = 0;
10403 wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
10404 if (wpabuf_len(conn->msg) < 1) {
10405 dpp_connection_remove(conn);
10406 return;
10407 }
10408
10409 pos = wpabuf_head(conn->msg);
10410 switch (*pos) {
10411 case WLAN_PA_VENDOR_SPECIFIC:
10412 if (dpp_controller_rx_action(conn, pos + 1,
10413 wpabuf_len(conn->msg) - 1) < 0)
10414 dpp_connection_remove(conn);
10415 break;
10416 case WLAN_PA_GAS_INITIAL_REQ:
10417 if (dpp_controller_rx_gas_req(conn, pos + 1,
10418 wpabuf_len(conn->msg) - 1) < 0)
10419 dpp_connection_remove(conn);
10420 break;
10421 case WLAN_PA_GAS_INITIAL_RESP:
10422 if (dpp_rx_gas_resp(conn, pos + 1,
10423 wpabuf_len(conn->msg) - 1) < 0)
10424 dpp_connection_remove(conn);
10425 break;
10426 default:
10427 wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
10428 *pos);
10429 break;
10430 }
10431}
10432
10433
10434static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
10435{
10436 struct dpp_controller *ctrl = eloop_ctx;
10437 struct sockaddr_in addr;
10438 socklen_t addr_len = sizeof(addr);
10439 int fd;
10440 struct dpp_connection *conn;
10441
10442 wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
10443
10444 fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
10445 if (fd < 0) {
10446 wpa_printf(MSG_DEBUG,
10447 "DPP: Failed to accept new connection: %s",
10448 strerror(errno));
10449 return;
10450 }
10451 wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
10452 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
10453
10454 conn = os_zalloc(sizeof(*conn));
10455 if (!conn)
10456 goto fail;
10457
10458 conn->global = ctrl->global;
10459 conn->ctrl = ctrl;
10460 conn->sock = fd;
10461
10462 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
10463 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
10464 strerror(errno));
10465 goto fail;
10466 }
10467
10468 if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
10469 dpp_controller_rx, conn, NULL) < 0)
10470 goto fail;
10471 conn->read_eloop = 1;
10472
10473 /* TODO: eloop timeout to expire connections that do not complete in
10474 * reasonable time */
10475 dl_list_add(&ctrl->conn, &conn->list);
10476 return;
10477
10478fail:
10479 close(fd);
10480 os_free(conn);
10481}
10482
10483
10484int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
10485 const struct hostapd_ip_addr *addr, int port)
10486{
10487 struct dpp_connection *conn;
10488 struct sockaddr_storage saddr;
10489 socklen_t addrlen;
10490 const u8 *hdr, *pos, *end;
10491 char txt[100];
10492
10493 wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
10494 hostapd_ip_txt(addr, txt, sizeof(txt)), port);
10495 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
10496 addr, port) < 0) {
10497 dpp_auth_deinit(auth);
10498 return -1;
10499 }
10500
10501 conn = os_zalloc(sizeof(*conn));
10502 if (!conn) {
10503 dpp_auth_deinit(auth);
10504 return -1;
10505 }
10506
10507 conn->global = dpp;
10508 conn->auth = auth;
10509 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
10510 if (conn->sock < 0)
10511 goto fail;
10512
10513 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
10514 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
10515 strerror(errno));
10516 goto fail;
10517 }
10518
10519 if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
10520 if (errno != EINPROGRESS) {
10521 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
10522 strerror(errno));
10523 goto fail;
10524 }
10525
10526 /*
10527 * Continue connecting in the background; eloop will call us
10528 * once the connection is ready (or failed).
10529 */
10530 }
10531
10532 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
10533 dpp_conn_tx_ready, conn, NULL) < 0)
10534 goto fail;
10535 conn->write_eloop = 1;
10536
10537 hdr = wpabuf_head(auth->req_msg);
10538 end = hdr + wpabuf_len(auth->req_msg);
10539 hdr += 2; /* skip Category and Actiom */
10540 pos = hdr + DPP_HDR_LEN;
10541 conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
10542 if (!conn->msg_out)
10543 goto fail;
10544 /* Message will be sent in dpp_conn_tx_ready() */
10545
10546 /* TODO: eloop timeout to clear a connection if it does not complete
10547 * properly */
10548 dl_list_add(&dpp->tcp_init, &conn->list);
10549 return 0;
10550fail:
10551 dpp_connection_free(conn);
10552 return -1;
10553}
10554
10555
10556int dpp_controller_start(struct dpp_global *dpp,
10557 struct dpp_controller_config *config)
10558{
10559 struct dpp_controller *ctrl;
10560 int on = 1;
10561 struct sockaddr_in sin;
10562 int port;
10563
10564 if (!dpp || dpp->controller)
10565 return -1;
10566
10567 ctrl = os_zalloc(sizeof(*ctrl));
10568 if (!ctrl)
10569 return -1;
10570 ctrl->global = dpp;
10571 if (config->configurator_params)
10572 ctrl->configurator_params =
10573 os_strdup(config->configurator_params);
10574 dl_list_init(&ctrl->conn);
10575 /* TODO: configure these somehow */
10576 ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
10577 ctrl->qr_mutual = 0;
10578
10579 ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
10580 if (ctrl->sock < 0)
10581 goto fail;
10582
10583 if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
10584 &on, sizeof(on)) < 0) {
10585 wpa_printf(MSG_DEBUG,
10586 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
10587 strerror(errno));
10588 /* try to continue anyway */
10589 }
10590
10591 if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
10592 wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
10593 strerror(errno));
10594 goto fail;
10595 }
10596
10597 /* TODO: IPv6 */
10598 os_memset(&sin, 0, sizeof(sin));
10599 sin.sin_family = AF_INET;
10600 sin.sin_addr.s_addr = INADDR_ANY;
10601 port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
10602 sin.sin_port = htons(port);
10603 if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
10604 wpa_printf(MSG_INFO,
10605 "DPP: Failed to bind Controller TCP port: %s",
10606 strerror(errno));
10607 goto fail;
10608 }
10609 if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
10610 fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
10611 eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
10612 dpp_controller_tcp_cb, ctrl, NULL))
10613 goto fail;
10614
10615 dpp->controller = ctrl;
10616 wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
10617 return 0;
10618fail:
10619 dpp_controller_free(ctrl);
10620 return -1;
10621}
10622
10623
10624void dpp_controller_stop(struct dpp_global *dpp)
10625{
10626 if (dpp) {
10627 dpp_controller_free(dpp->controller);
10628 dpp->controller = NULL;
10629 }
10630}
10631
10632#endif /* CONFIG_DPP2 */