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