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