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