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