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