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