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