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