blob: 44cb910012b01931eca7965204b47e44820081a9 [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");
Hai Shalom06768112019-12-04 15:49:43 -08005301 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07005302 if (token && token->type == JSON_ARRAY) {
Hai Shalom06768112019-12-04 15:49:43 -08005303 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07005304 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
5305 token = token->child;
5306 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08005307 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07005308 wpa_printf(MSG_DEBUG,
5309 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08005310 } else {
5311 if (auth->band_list_size < DPP_MAX_CHANNELS) {
5312 auth->band_list[auth->band_list_size++] = token->number;
5313 }
Hai Shalomc3565922019-10-28 11:58:20 -07005314 wpa_printf(MSG_DEBUG,
5315 "DPP: Supported global operating class: %d",
5316 token->number);
Hai Shalom06768112019-12-04 15:49:43 -08005317 }
Hai Shalomc3565922019-10-28 11:58:20 -07005318 token = token->sibling;
5319 }
5320 }
5321
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005322 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
5323
5324fail:
5325 json_free(root);
5326 os_free(unwrapped);
5327 return resp;
5328}
5329
5330
5331static struct wpabuf *
5332dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
5333 const u8 *prot_hdr, u16 prot_hdr_len,
5334 const EVP_MD **ret_md)
5335{
5336 struct json_token *root, *token;
5337 struct wpabuf *kid = NULL;
5338
5339 root = json_parse((const char *) prot_hdr, prot_hdr_len);
5340 if (!root) {
5341 wpa_printf(MSG_DEBUG,
5342 "DPP: JSON parsing failed for JWS Protected Header");
5343 goto fail;
5344 }
5345
5346 if (root->type != JSON_OBJECT) {
5347 wpa_printf(MSG_DEBUG,
5348 "DPP: JWS Protected Header root is not an object");
5349 goto fail;
5350 }
5351
5352 token = json_get_member(root, "typ");
5353 if (!token || token->type != JSON_STRING) {
5354 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
5355 goto fail;
5356 }
5357 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
5358 token->string);
5359 if (os_strcmp(token->string, "dppCon") != 0) {
5360 wpa_printf(MSG_DEBUG,
5361 "DPP: Unsupported JWS Protected Header typ=%s",
5362 token->string);
5363 goto fail;
5364 }
5365
5366 token = json_get_member(root, "alg");
5367 if (!token || token->type != JSON_STRING) {
5368 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
5369 goto fail;
5370 }
5371 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
5372 token->string);
5373 if (os_strcmp(token->string, curve->jws_alg) != 0) {
5374 wpa_printf(MSG_DEBUG,
5375 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5376 token->string, curve->jws_alg);
5377 goto fail;
5378 }
5379 if (os_strcmp(token->string, "ES256") == 0 ||
5380 os_strcmp(token->string, "BS256") == 0)
5381 *ret_md = EVP_sha256();
5382 else if (os_strcmp(token->string, "ES384") == 0 ||
5383 os_strcmp(token->string, "BS384") == 0)
5384 *ret_md = EVP_sha384();
5385 else if (os_strcmp(token->string, "ES512") == 0 ||
5386 os_strcmp(token->string, "BS512") == 0)
5387 *ret_md = EVP_sha512();
5388 else
5389 *ret_md = NULL;
5390 if (!*ret_md) {
5391 wpa_printf(MSG_DEBUG,
5392 "DPP: Unsupported JWS Protected Header alg=%s",
5393 token->string);
5394 goto fail;
5395 }
5396
5397 kid = json_get_member_base64url(root, "kid");
5398 if (!kid) {
5399 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
5400 goto fail;
5401 }
5402 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
5403 kid);
5404
5405fail:
5406 json_free(root);
5407 return kid;
5408}
5409
5410
Hai Shalomc3565922019-10-28 11:58:20 -07005411static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005412 struct json_token *cred)
5413{
5414 struct json_token *pass, *psk_hex;
5415
5416 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
5417
5418 pass = json_get_member(cred, "pass");
5419 psk_hex = json_get_member(cred, "psk_hex");
5420
5421 if (pass && pass->type == JSON_STRING) {
5422 size_t len = os_strlen(pass->string);
5423
5424 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
5425 pass->string, len);
5426 if (len < 8 || len > 63)
5427 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07005428 os_strlcpy(conf->passphrase, pass->string,
5429 sizeof(conf->passphrase));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005430 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07005431 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005432 wpa_printf(MSG_DEBUG,
5433 "DPP: Unexpected psk_hex with akm=sae");
5434 return -1;
5435 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005436 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07005437 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005438 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
5439 return -1;
5440 }
5441 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07005442 conf->psk, PMK_LEN);
5443 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005444 } else {
5445 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
5446 return -1;
5447 }
5448
Hai Shalomc3565922019-10-28 11:58:20 -07005449 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005450 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
5451 return -1;
5452 }
5453
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005454 return 0;
5455}
5456
5457
5458static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
5459 const struct dpp_curve_params **key_curve)
5460{
5461 struct json_token *token;
5462 const struct dpp_curve_params *curve;
5463 struct wpabuf *x = NULL, *y = NULL;
5464 EC_GROUP *group;
5465 EVP_PKEY *pkey = NULL;
5466
5467 token = json_get_member(jwk, "kty");
5468 if (!token || token->type != JSON_STRING) {
5469 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
5470 goto fail;
5471 }
5472 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08005473 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005474 token->string);
5475 goto fail;
5476 }
5477
5478 token = json_get_member(jwk, "crv");
5479 if (!token || token->type != JSON_STRING) {
5480 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
5481 goto fail;
5482 }
5483 curve = dpp_get_curve_jwk_crv(token->string);
5484 if (!curve) {
5485 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
5486 token->string);
5487 goto fail;
5488 }
5489
5490 x = json_get_member_base64url(jwk, "x");
5491 if (!x) {
5492 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
5493 goto fail;
5494 }
5495 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
5496 if (wpabuf_len(x) != curve->prime_len) {
5497 wpa_printf(MSG_DEBUG,
5498 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5499 (unsigned int) wpabuf_len(x),
5500 (unsigned int) curve->prime_len, curve->name);
5501 goto fail;
5502 }
5503
5504 y = json_get_member_base64url(jwk, "y");
5505 if (!y) {
5506 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
5507 goto fail;
5508 }
5509 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
5510 if (wpabuf_len(y) != curve->prime_len) {
5511 wpa_printf(MSG_DEBUG,
5512 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5513 (unsigned int) wpabuf_len(y),
5514 (unsigned int) curve->prime_len, curve->name);
5515 goto fail;
5516 }
5517
5518 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5519 if (!group) {
5520 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
5521 goto fail;
5522 }
5523
5524 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
5525 wpabuf_len(x));
Hai Shalom81f62d82019-07-22 12:10:00 -07005526 EC_GROUP_free(group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005527 *key_curve = curve;
5528
5529fail:
5530 wpabuf_free(x);
5531 wpabuf_free(y);
5532
5533 return pkey;
5534}
5535
5536
5537int dpp_key_expired(const char *timestamp, os_time_t *expiry)
5538{
5539 struct os_time now;
5540 unsigned int year, month, day, hour, min, sec;
5541 os_time_t utime;
5542 const char *pos;
5543
5544 /* ISO 8601 date and time:
5545 * <date>T<time>
5546 * YYYY-MM-DDTHH:MM:SSZ
5547 * YYYY-MM-DDTHH:MM:SS+03:00
5548 */
5549 if (os_strlen(timestamp) < 19) {
5550 wpa_printf(MSG_DEBUG,
5551 "DPP: Too short timestamp - assume expired key");
5552 return 1;
5553 }
5554 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
5555 &year, &month, &day, &hour, &min, &sec) != 6) {
5556 wpa_printf(MSG_DEBUG,
5557 "DPP: Failed to parse expiration day - assume expired key");
5558 return 1;
5559 }
5560
5561 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
5562 wpa_printf(MSG_DEBUG,
5563 "DPP: Invalid date/time information - assume expired key");
5564 return 1;
5565 }
5566
5567 pos = timestamp + 19;
5568 if (*pos == 'Z' || *pos == '\0') {
5569 /* In UTC - no need to adjust */
5570 } else if (*pos == '-' || *pos == '+') {
5571 int items;
5572
5573 /* Adjust local time to UTC */
5574 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
5575 if (items < 1) {
5576 wpa_printf(MSG_DEBUG,
5577 "DPP: Invalid time zone designator (%s) - assume expired key",
5578 pos);
5579 return 1;
5580 }
5581 if (*pos == '-')
5582 utime += 3600 * hour;
5583 if (*pos == '+')
5584 utime -= 3600 * hour;
5585 if (items > 1) {
5586 if (*pos == '-')
5587 utime += 60 * min;
5588 if (*pos == '+')
5589 utime -= 60 * min;
5590 }
5591 } else {
5592 wpa_printf(MSG_DEBUG,
5593 "DPP: Invalid time zone designator (%s) - assume expired key",
5594 pos);
5595 return 1;
5596 }
5597 if (expiry)
5598 *expiry = utime;
5599
5600 if (os_get_time(&now) < 0) {
5601 wpa_printf(MSG_DEBUG,
5602 "DPP: Cannot get current time - assume expired key");
5603 return 1;
5604 }
5605
5606 if (now.sec > utime) {
5607 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
5608 utime, now.sec);
5609 return 1;
5610 }
5611
5612 return 0;
5613}
5614
5615
5616static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07005617 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005618 const unsigned char *payload,
5619 u16 payload_len)
5620{
5621 struct json_token *root, *groups, *netkey, *token;
5622 int ret = -1;
5623 EVP_PKEY *key = NULL;
5624 const struct dpp_curve_params *curve;
5625 unsigned int rules = 0;
5626
5627 root = json_parse((const char *) payload, payload_len);
5628 if (!root) {
5629 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5630 goto fail;
5631 }
5632
5633 groups = json_get_member(root, "groups");
5634 if (!groups || groups->type != JSON_ARRAY) {
5635 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
5636 goto skip_groups;
5637 }
5638 for (token = groups->child; token; token = token->sibling) {
5639 struct json_token *id, *role;
5640
5641 id = json_get_member(token, "groupId");
5642 if (!id || id->type != JSON_STRING) {
5643 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
5644 goto fail;
5645 }
5646
5647 role = json_get_member(token, "netRole");
5648 if (!role || role->type != JSON_STRING) {
5649 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
5650 goto fail;
5651 }
5652 wpa_printf(MSG_DEBUG,
5653 "DPP: connector group: groupId='%s' netRole='%s'",
5654 id->string, role->string);
5655 rules++;
5656 }
5657skip_groups:
5658
5659 if (!rules) {
5660 wpa_printf(MSG_DEBUG,
5661 "DPP: Connector includes no groups");
5662 goto fail;
5663 }
5664
5665 token = json_get_member(root, "expiry");
5666 if (!token || token->type != JSON_STRING) {
5667 wpa_printf(MSG_DEBUG,
5668 "DPP: No expiry string found - connector does not expire");
5669 } else {
5670 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5671 if (dpp_key_expired(token->string,
5672 &auth->net_access_key_expiry)) {
5673 wpa_printf(MSG_DEBUG,
5674 "DPP: Connector (netAccessKey) has expired");
5675 goto fail;
5676 }
5677 }
5678
5679 netkey = json_get_member(root, "netAccessKey");
5680 if (!netkey || netkey->type != JSON_OBJECT) {
5681 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
5682 goto fail;
5683 }
5684
5685 key = dpp_parse_jwk(netkey, &curve);
5686 if (!key)
5687 goto fail;
5688 dpp_debug_print_key("DPP: Received netAccessKey", key);
5689
5690 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
5691 wpa_printf(MSG_DEBUG,
5692 "DPP: netAccessKey in connector does not match own protocol key");
5693#ifdef CONFIG_TESTING_OPTIONS
5694 if (auth->ignore_netaccesskey_mismatch) {
5695 wpa_printf(MSG_DEBUG,
5696 "DPP: TESTING - skip netAccessKey mismatch");
5697 } else {
5698 goto fail;
5699 }
5700#else /* CONFIG_TESTING_OPTIONS */
5701 goto fail;
5702#endif /* CONFIG_TESTING_OPTIONS */
5703 }
5704
5705 ret = 0;
5706fail:
5707 EVP_PKEY_free(key);
5708 json_free(root);
5709 return ret;
5710}
5711
5712
5713static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
5714{
5715 struct wpabuf *uncomp;
5716 int res;
5717 u8 hash[SHA256_MAC_LEN];
5718 const u8 *addr[1];
5719 size_t len[1];
5720
5721 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
5722 return -1;
5723 uncomp = dpp_get_pubkey_point(pub, 1);
5724 if (!uncomp)
5725 return -1;
5726 addr[0] = wpabuf_head(uncomp);
5727 len[0] = wpabuf_len(uncomp);
5728 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
5729 addr[0], len[0]);
5730 res = sha256_vector(1, addr, len, hash);
5731 wpabuf_free(uncomp);
5732 if (res < 0)
5733 return -1;
5734 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
5735 wpa_printf(MSG_DEBUG,
5736 "DPP: Received hash value does not match calculated public key hash value");
5737 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
5738 hash, SHA256_MAC_LEN);
5739 return -1;
5740 }
5741 return 0;
5742}
5743
5744
Hai Shalomc3565922019-10-28 11:58:20 -07005745static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005746{
5747 unsigned char *der = NULL;
5748 int der_len;
5749
5750 der_len = i2d_PUBKEY(csign, &der);
5751 if (der_len <= 0)
5752 return;
Hai Shalomc3565922019-10-28 11:58:20 -07005753 wpabuf_free(conf->c_sign_key);
5754 conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005755 OPENSSL_free(der);
5756}
5757
5758
Hai Shalomc3565922019-10-28 11:58:20 -07005759static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
5760 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005761{
5762 unsigned char *der = NULL;
5763 int der_len;
5764 EC_KEY *eckey;
5765
5766 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
5767 if (!eckey)
5768 return;
5769
5770 der_len = i2d_ECPrivateKey(eckey, &der);
5771 if (der_len <= 0) {
5772 EC_KEY_free(eckey);
5773 return;
5774 }
5775 wpabuf_free(auth->net_access_key);
5776 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
5777 OPENSSL_free(der);
5778 EC_KEY_free(eckey);
5779}
5780
5781
5782struct dpp_signed_connector_info {
5783 unsigned char *payload;
5784 size_t payload_len;
5785};
5786
Roshan Pius3a1667e2018-07-03 15:17:14 -07005787static enum dpp_status_error
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005788dpp_process_signed_connector(struct dpp_signed_connector_info *info,
5789 EVP_PKEY *csign_pub, const char *connector)
5790{
Roshan Pius3a1667e2018-07-03 15:17:14 -07005791 enum dpp_status_error ret = 255;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005792 const char *pos, *end, *signed_start, *signed_end;
5793 struct wpabuf *kid = NULL;
5794 unsigned char *prot_hdr = NULL, *signature = NULL;
5795 size_t prot_hdr_len = 0, signature_len = 0;
5796 const EVP_MD *sign_md = NULL;
5797 unsigned char *der = NULL;
5798 int der_len;
5799 int res;
5800 EVP_MD_CTX *md_ctx = NULL;
5801 ECDSA_SIG *sig = NULL;
5802 BIGNUM *r = NULL, *s = NULL;
5803 const struct dpp_curve_params *curve;
5804 EC_KEY *eckey;
5805 const EC_GROUP *group;
5806 int nid;
5807
5808 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
5809 if (!eckey)
5810 goto fail;
5811 group = EC_KEY_get0_group(eckey);
5812 if (!group)
5813 goto fail;
5814 nid = EC_GROUP_get_curve_name(group);
5815 curve = dpp_get_curve_nid(nid);
5816 if (!curve)
5817 goto fail;
5818 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
5819 os_memset(info, 0, sizeof(*info));
5820
5821 signed_start = pos = connector;
5822 end = os_strchr(pos, '.');
5823 if (!end) {
5824 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005825 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005826 goto fail;
5827 }
5828 prot_hdr = base64_url_decode((const unsigned char *) pos,
5829 end - pos, &prot_hdr_len);
5830 if (!prot_hdr) {
5831 wpa_printf(MSG_DEBUG,
5832 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005833 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005834 goto fail;
5835 }
5836 wpa_hexdump_ascii(MSG_DEBUG,
5837 "DPP: signedConnector - JWS Protected Header",
5838 prot_hdr, prot_hdr_len);
5839 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005840 if (!kid) {
5841 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005842 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005843 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005844 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
5845 wpa_printf(MSG_DEBUG,
5846 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5847 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005848 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005849 goto fail;
5850 }
5851
5852 pos = end + 1;
5853 end = os_strchr(pos, '.');
5854 if (!end) {
5855 wpa_printf(MSG_DEBUG,
5856 "DPP: Missing dot(2) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005857 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005858 goto fail;
5859 }
5860 signed_end = end - 1;
5861 info->payload = base64_url_decode((const unsigned char *) pos,
5862 end - pos, &info->payload_len);
5863 if (!info->payload) {
5864 wpa_printf(MSG_DEBUG,
5865 "DPP: Failed to base64url decode signedConnector JWS Payload");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005866 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005867 goto fail;
5868 }
5869 wpa_hexdump_ascii(MSG_DEBUG,
5870 "DPP: signedConnector - JWS Payload",
5871 info->payload, info->payload_len);
5872 pos = end + 1;
5873 signature = base64_url_decode((const unsigned char *) pos,
5874 os_strlen(pos), &signature_len);
5875 if (!signature) {
5876 wpa_printf(MSG_DEBUG,
5877 "DPP: Failed to base64url decode signedConnector signature");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005878 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005879 goto fail;
5880 }
5881 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5882 signature, signature_len);
5883
Roshan Pius3a1667e2018-07-03 15:17:14 -07005884 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5885 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005886 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005887 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005888
5889 if (signature_len & 0x01) {
5890 wpa_printf(MSG_DEBUG,
5891 "DPP: Unexpected signedConnector signature length (%d)",
5892 (int) signature_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005893 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005894 goto fail;
5895 }
5896
5897 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5898 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5899 r = BN_bin2bn(signature, signature_len / 2, NULL);
5900 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
5901 sig = ECDSA_SIG_new();
5902 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
5903 goto fail;
5904 r = NULL;
5905 s = NULL;
5906
5907 der_len = i2d_ECDSA_SIG(sig, &der);
5908 if (der_len <= 0) {
5909 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
5910 goto fail;
5911 }
5912 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
5913 md_ctx = EVP_MD_CTX_create();
5914 if (!md_ctx)
5915 goto fail;
5916
5917 ERR_clear_error();
5918 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
5919 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
5920 ERR_error_string(ERR_get_error(), NULL));
5921 goto fail;
5922 }
5923 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
5924 signed_end - signed_start + 1) != 1) {
5925 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
5926 ERR_error_string(ERR_get_error(), NULL));
5927 goto fail;
5928 }
5929 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
5930 if (res != 1) {
5931 wpa_printf(MSG_DEBUG,
5932 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5933 res, ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07005934 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005935 goto fail;
5936 }
5937
Roshan Pius3a1667e2018-07-03 15:17:14 -07005938 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005939fail:
5940 EC_KEY_free(eckey);
5941 EVP_MD_CTX_destroy(md_ctx);
5942 os_free(prot_hdr);
5943 wpabuf_free(kid);
5944 os_free(signature);
5945 ECDSA_SIG_free(sig);
5946 BN_free(r);
5947 BN_free(s);
5948 OPENSSL_free(der);
5949 return ret;
5950}
5951
5952
5953static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07005954 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005955 struct json_token *cred)
5956{
5957 struct dpp_signed_connector_info info;
5958 struct json_token *token, *csign;
5959 int ret = -1;
5960 EVP_PKEY *csign_pub = NULL;
5961 const struct dpp_curve_params *key_curve = NULL;
5962 const char *signed_connector;
5963
5964 os_memset(&info, 0, sizeof(info));
5965
Hai Shalomc3565922019-10-28 11:58:20 -07005966 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07005967 wpa_printf(MSG_DEBUG,
5968 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07005969 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07005970 return -1;
5971 }
5972
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005973 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5974
5975 csign = json_get_member(cred, "csign");
5976 if (!csign || csign->type != JSON_OBJECT) {
5977 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5978 goto fail;
5979 }
5980
5981 csign_pub = dpp_parse_jwk(csign, &key_curve);
5982 if (!csign_pub) {
5983 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5984 goto fail;
5985 }
5986 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5987
5988 token = json_get_member(cred, "signedConnector");
5989 if (!token || token->type != JSON_STRING) {
5990 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5991 goto fail;
5992 }
5993 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5994 token->string, os_strlen(token->string));
5995 signed_connector = token->string;
5996
5997 if (os_strchr(signed_connector, '"') ||
5998 os_strchr(signed_connector, '\n')) {
5999 wpa_printf(MSG_DEBUG,
6000 "DPP: Unexpected character in signedConnector");
6001 goto fail;
6002 }
6003
6004 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006005 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006006 goto fail;
6007
Hai Shalomc3565922019-10-28 11:58:20 -07006008 if (dpp_parse_connector(auth, conf,
6009 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006010 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
6011 goto fail;
6012 }
6013
Hai Shalomc3565922019-10-28 11:58:20 -07006014 os_free(conf->connector);
6015 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006016
Hai Shalomc3565922019-10-28 11:58:20 -07006017 dpp_copy_csign(conf, csign_pub);
6018 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006019
6020 ret = 0;
6021fail:
6022 EVP_PKEY_free(csign_pub);
6023 os_free(info.payload);
6024 return ret;
6025}
6026
6027
Roshan Pius3a1667e2018-07-03 15:17:14 -07006028const char * dpp_akm_str(enum dpp_akm akm)
6029{
6030 switch (akm) {
6031 case DPP_AKM_DPP:
6032 return "dpp";
6033 case DPP_AKM_PSK:
6034 return "psk";
6035 case DPP_AKM_SAE:
6036 return "sae";
6037 case DPP_AKM_PSK_SAE:
6038 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07006039 case DPP_AKM_SAE_DPP:
6040 return "dpp+sae";
6041 case DPP_AKM_PSK_SAE_DPP:
6042 return "dpp+psk+sae";
Roshan Pius3a1667e2018-07-03 15:17:14 -07006043 default:
6044 return "??";
6045 }
6046}
6047
6048
Hai Shalomc3565922019-10-28 11:58:20 -07006049const char * dpp_akm_selector_str(enum dpp_akm akm)
6050{
6051 switch (akm) {
6052 case DPP_AKM_DPP:
6053 return "506F9A02";
6054 case DPP_AKM_PSK:
6055 return "000FAC02+000FAC06";
6056 case DPP_AKM_SAE:
6057 return "000FAC08";
6058 case DPP_AKM_PSK_SAE:
6059 return "000FAC02+000FAC06+000FAC08";
6060 case DPP_AKM_SAE_DPP:
6061 return "506F9A02+000FAC08";
6062 case DPP_AKM_PSK_SAE_DPP:
6063 return "506F9A02+000FAC08+000FAC02+000FAC06";
6064 default:
6065 return "??";
6066 }
6067}
6068
6069
Roshan Pius3a1667e2018-07-03 15:17:14 -07006070static enum dpp_akm dpp_akm_from_str(const char *akm)
6071{
Hai Shalomc3565922019-10-28 11:58:20 -07006072 const char *pos;
6073 int dpp = 0, psk = 0, sae = 0;
6074
Roshan Pius3a1667e2018-07-03 15:17:14 -07006075 if (os_strcmp(akm, "psk") == 0)
6076 return DPP_AKM_PSK;
6077 if (os_strcmp(akm, "sae") == 0)
6078 return DPP_AKM_SAE;
6079 if (os_strcmp(akm, "psk+sae") == 0)
6080 return DPP_AKM_PSK_SAE;
6081 if (os_strcmp(akm, "dpp") == 0)
6082 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07006083 if (os_strcmp(akm, "dpp+sae") == 0)
6084 return DPP_AKM_SAE_DPP;
6085 if (os_strcmp(akm, "dpp+psk+sae") == 0)
6086 return DPP_AKM_PSK_SAE_DPP;
Hai Shalomc3565922019-10-28 11:58:20 -07006087
6088 pos = akm;
6089 while (*pos) {
6090 if (os_strlen(pos) < 8)
6091 break;
6092 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
6093 dpp = 1;
6094 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
6095 psk = 1;
6096 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
6097 psk = 1;
6098 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
6099 sae = 1;
6100 pos += 8;
6101 if (*pos != '+')
6102 break;
6103 pos++;
6104 }
6105
6106 if (dpp && psk && sae)
6107 return DPP_AKM_PSK_SAE_DPP;
6108 if (dpp && sae)
6109 return DPP_AKM_SAE_DPP;
6110 if (dpp)
6111 return DPP_AKM_DPP;
6112 if (psk && sae)
6113 return DPP_AKM_PSK_SAE;
6114 if (sae)
6115 return DPP_AKM_SAE;
6116 if (psk)
6117 return DPP_AKM_PSK;
6118
Roshan Pius3a1667e2018-07-03 15:17:14 -07006119 return DPP_AKM_UNKNOWN;
6120}
6121
6122
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006123static int dpp_parse_conf_obj(struct dpp_authentication *auth,
6124 const u8 *conf_obj, u16 conf_obj_len)
6125{
6126 int ret = -1;
6127 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07006128 struct dpp_config_obj *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006129
6130 root = json_parse((const char *) conf_obj, conf_obj_len);
6131 if (!root)
6132 return -1;
6133 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006134 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006135 goto fail;
6136 }
6137
6138 token = json_get_member(root, "wi-fi_tech");
6139 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006140 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006141 goto fail;
6142 }
6143 if (os_strcmp(token->string, "infra") != 0) {
6144 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
6145 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006146 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006147 goto fail;
6148 }
6149
6150 discovery = json_get_member(root, "discovery");
6151 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006152 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006153 goto fail;
6154 }
6155
6156 token = json_get_member(discovery, "ssid");
6157 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006158 dpp_auth_fail(auth, "No discovery::ssid string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006159 goto fail;
6160 }
6161 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
6162 token->string, os_strlen(token->string));
6163 if (os_strlen(token->string) > SSID_MAX_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006164 dpp_auth_fail(auth, "Too long discovery::ssid string value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006165 goto fail;
6166 }
Hai Shalomc3565922019-10-28 11:58:20 -07006167
6168 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
6169 wpa_printf(MSG_DEBUG,
6170 "DPP: No room for this many Config Objects - ignore this one");
6171 json_free(root);
6172 return 0;
6173 }
6174 conf = &auth->conf_obj[auth->num_conf_obj++];
6175
6176 conf->ssid_len = os_strlen(token->string);
6177 os_memcpy(conf->ssid, token->string, conf->ssid_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006178
6179 cred = json_get_member(root, "cred");
6180 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006181 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006182 goto fail;
6183 }
6184
6185 token = json_get_member(cred, "akm");
6186 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006187 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006188 goto fail;
6189 }
Hai Shalomc3565922019-10-28 11:58:20 -07006190 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006191
Hai Shalomc3565922019-10-28 11:58:20 -07006192 if (dpp_akm_legacy(conf->akm)) {
6193 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006194 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07006195 } else if (dpp_akm_dpp(conf->akm)) {
6196 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006197 goto fail;
6198 } else {
6199 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
6200 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006201 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006202 goto fail;
6203 }
6204
6205 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
6206 ret = 0;
6207fail:
6208 json_free(root);
6209 return ret;
6210}
6211
6212
6213int dpp_conf_resp_rx(struct dpp_authentication *auth,
6214 const struct wpabuf *resp)
6215{
6216 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
6217 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
6218 const u8 *addr[1];
6219 size_t len[1];
6220 u8 *unwrapped = NULL;
6221 size_t unwrapped_len = 0;
6222 int ret = -1;
6223
Hai Shalom021b0b52019-04-10 11:17:58 -07006224 auth->conf_resp_status = 255;
6225
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006226 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006227 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006228 return -1;
6229 }
6230
6231 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
6232 DPP_ATTR_WRAPPED_DATA,
6233 &wrapped_data_len);
6234 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006235 dpp_auth_fail(auth,
6236 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006237 return -1;
6238 }
6239
6240 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6241 wrapped_data, wrapped_data_len);
6242 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6243 unwrapped = os_malloc(unwrapped_len);
6244 if (!unwrapped)
6245 return -1;
6246
6247 addr[0] = wpabuf_head(resp);
6248 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
6249 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
6250
6251 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
6252 wrapped_data, wrapped_data_len,
6253 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006254 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006255 goto fail;
6256 }
6257 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6258 unwrapped, unwrapped_len);
6259
6260 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006261 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006262 goto fail;
6263 }
6264
6265 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
6266 DPP_ATTR_ENROLLEE_NONCE,
6267 &e_nonce_len);
6268 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006269 dpp_auth_fail(auth,
6270 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006271 goto fail;
6272 }
6273 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
6274 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006275 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006276 goto fail;
6277 }
6278
6279 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
6280 DPP_ATTR_STATUS, &status_len);
6281 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006282 dpp_auth_fail(auth,
6283 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006284 goto fail;
6285 }
Hai Shalom021b0b52019-04-10 11:17:58 -07006286 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006287 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
6288 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006289 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006290 goto fail;
6291 }
6292
Hai Shalomc3565922019-10-28 11:58:20 -07006293 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
6294 &conf_obj_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006295 if (!conf_obj) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006296 dpp_auth_fail(auth,
6297 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006298 goto fail;
6299 }
Hai Shalomc3565922019-10-28 11:58:20 -07006300 while (conf_obj) {
6301 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
6302 conf_obj, conf_obj_len);
6303 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
6304 goto fail;
6305 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
6306 DPP_ATTR_CONFIG_OBJ,
6307 &conf_obj_len);
6308 }
6309
6310#ifdef CONFIG_DPP2
6311 status = dpp_get_attr(unwrapped, unwrapped_len,
6312 DPP_ATTR_SEND_CONN_STATUS, &status_len);
6313 if (status) {
6314 wpa_printf(MSG_DEBUG,
6315 "DPP: Configurator requested connection status result");
6316 auth->conn_status_requested = 1;
6317 }
6318#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006319
6320 ret = 0;
6321
6322fail:
6323 os_free(unwrapped);
6324 return ret;
6325}
6326
6327
Hai Shalom021b0b52019-04-10 11:17:58 -07006328#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07006329
Hai Shalom021b0b52019-04-10 11:17:58 -07006330enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
6331 const u8 *hdr,
6332 const u8 *attr_start, size_t attr_len)
6333{
6334 const u8 *wrapped_data, *status, *e_nonce;
6335 u16 wrapped_data_len, status_len, e_nonce_len;
6336 const u8 *addr[2];
6337 size_t len[2];
6338 u8 *unwrapped = NULL;
6339 size_t unwrapped_len = 0;
6340 enum dpp_status_error ret = 256;
6341
6342 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
6343 &wrapped_data_len);
6344 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
6345 dpp_auth_fail(auth,
6346 "Missing or invalid required Wrapped Data attribute");
6347 goto fail;
6348 }
6349 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
6350 wrapped_data, wrapped_data_len);
6351
6352 attr_len = wrapped_data - 4 - attr_start;
6353
6354 addr[0] = hdr;
6355 len[0] = DPP_HDR_LEN;
6356 addr[1] = attr_start;
6357 len[1] = attr_len;
6358 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6359 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6360 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6361 wrapped_data, wrapped_data_len);
6362 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6363 unwrapped = os_malloc(unwrapped_len);
6364 if (!unwrapped)
6365 goto fail;
6366 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
6367 wrapped_data, wrapped_data_len,
6368 2, addr, len, unwrapped) < 0) {
6369 dpp_auth_fail(auth, "AES-SIV decryption failed");
6370 goto fail;
6371 }
6372 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6373 unwrapped, unwrapped_len);
6374
6375 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
6376 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
6377 goto fail;
6378 }
6379
6380 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
6381 DPP_ATTR_ENROLLEE_NONCE,
6382 &e_nonce_len);
6383 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
6384 dpp_auth_fail(auth,
6385 "Missing or invalid Enrollee Nonce attribute");
6386 goto fail;
6387 }
6388 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
6389 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
6390 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
6391 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
6392 auth->e_nonce, e_nonce_len);
6393 goto fail;
6394 }
6395
6396 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
6397 &status_len);
6398 if (!status || status_len < 1) {
6399 dpp_auth_fail(auth,
6400 "Missing or invalid required DPP Status attribute");
6401 goto fail;
6402 }
6403 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
6404 ret = status[0];
6405
6406fail:
6407 bin_clear_free(unwrapped, unwrapped_len);
6408 return ret;
6409}
Hai Shalom021b0b52019-04-10 11:17:58 -07006410
6411
6412struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
6413 enum dpp_status_error status)
6414{
6415 struct wpabuf *msg, *clear;
6416 size_t nonce_len, clear_len, attr_len;
6417 const u8 *addr[2];
6418 size_t len[2];
6419 u8 *wrapped;
6420
6421 nonce_len = auth->curve->nonce_len;
6422 clear_len = 5 + 4 + nonce_len;
6423 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6424 clear = wpabuf_alloc(clear_len);
6425 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
6426 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07006427 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07006428
6429 /* DPP Status */
6430 dpp_build_attr_status(clear, status);
6431
6432 /* E-nonce */
6433 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
6434 wpabuf_put_le16(clear, nonce_len);
6435 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
6436
6437 /* OUI, OUI type, Crypto Suite, DPP frame type */
6438 addr[0] = wpabuf_head_u8(msg) + 2;
6439 len[0] = 3 + 1 + 1 + 1;
6440 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6441
6442 /* Attributes before Wrapped Data (none) */
6443 addr[1] = wpabuf_put(msg, 0);
6444 len[1] = 0;
6445 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6446
6447 /* Wrapped Data */
6448 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6449 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6450 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6451
6452 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6453 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
6454 wpabuf_head(clear), wpabuf_len(clear),
6455 2, addr, len, wrapped) < 0)
6456 goto fail;
6457
6458 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
6459 wpabuf_free(clear);
6460 return msg;
6461fail:
6462 wpabuf_free(clear);
6463 wpabuf_free(msg);
6464 return NULL;
6465}
6466
6467
Hai Shalomc3565922019-10-28 11:58:20 -07006468static int valid_channel_list(const char *val)
6469{
6470 while (*val) {
6471 if (!((*val >= '0' && *val <= '9') ||
6472 *val == '/' || *val == ','))
6473 return 0;
6474 val++;
6475 }
6476
6477 return 1;
6478}
6479
6480
6481enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
6482 const u8 *hdr,
6483 const u8 *attr_start,
6484 size_t attr_len,
6485 u8 *ssid, size_t *ssid_len,
6486 char **channel_list)
6487{
6488 const u8 *wrapped_data, *status, *e_nonce;
6489 u16 wrapped_data_len, status_len, e_nonce_len;
6490 const u8 *addr[2];
6491 size_t len[2];
6492 u8 *unwrapped = NULL;
6493 size_t unwrapped_len = 0;
6494 enum dpp_status_error ret = 256;
6495 struct json_token *root = NULL, *token;
6496
6497 *ssid_len = 0;
6498 *channel_list = NULL;
6499
6500 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
6501 &wrapped_data_len);
6502 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
6503 dpp_auth_fail(auth,
6504 "Missing or invalid required Wrapped Data attribute");
6505 goto fail;
6506 }
6507 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
6508 wrapped_data, wrapped_data_len);
6509
6510 attr_len = wrapped_data - 4 - attr_start;
6511
6512 addr[0] = hdr;
6513 len[0] = DPP_HDR_LEN;
6514 addr[1] = attr_start;
6515 len[1] = attr_len;
6516 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6517 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6518 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6519 wrapped_data, wrapped_data_len);
6520 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6521 unwrapped = os_malloc(unwrapped_len);
6522 if (!unwrapped)
6523 goto fail;
6524 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
6525 wrapped_data, wrapped_data_len,
6526 2, addr, len, unwrapped) < 0) {
6527 dpp_auth_fail(auth, "AES-SIV decryption failed");
6528 goto fail;
6529 }
6530 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6531 unwrapped, unwrapped_len);
6532
6533 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
6534 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
6535 goto fail;
6536 }
6537
6538 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
6539 DPP_ATTR_ENROLLEE_NONCE,
6540 &e_nonce_len);
6541 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
6542 dpp_auth_fail(auth,
6543 "Missing or invalid Enrollee Nonce attribute");
6544 goto fail;
6545 }
6546 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
6547 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
6548 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
6549 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
6550 auth->e_nonce, e_nonce_len);
6551 goto fail;
6552 }
6553
6554 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
6555 &status_len);
6556 if (!status) {
6557 dpp_auth_fail(auth,
6558 "Missing required DPP Connection Status attribute");
6559 goto fail;
6560 }
6561 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
6562 status, status_len);
6563
6564 root = json_parse((const char *) status, status_len);
6565 if (!root) {
6566 dpp_auth_fail(auth, "Could not parse connStatus");
6567 goto fail;
6568 }
6569
6570 token = json_get_member(root, "ssid");
6571 if (token && token->type == JSON_STRING &&
6572 os_strlen(token->string) <= SSID_MAX_LEN) {
6573 *ssid_len = os_strlen(token->string);
6574 os_memcpy(ssid, token->string, *ssid_len);
6575 }
6576
6577 token = json_get_member(root, "channelList");
6578 if (token && token->type == JSON_STRING &&
6579 valid_channel_list(token->string))
6580 *channel_list = os_strdup(token->string);
6581
6582 token = json_get_member(root, "result");
6583 if (!token || token->type != JSON_NUMBER) {
6584 dpp_auth_fail(auth, "No connStatus - result");
6585 goto fail;
6586 }
6587 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
6588 ret = token->number;
6589
6590fail:
6591 json_free(root);
6592 bin_clear_free(unwrapped, unwrapped_len);
6593 return ret;
6594}
6595
6596
6597struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
6598 enum dpp_status_error result,
6599 const u8 *ssid, size_t ssid_len,
6600 const char *channel_list)
6601{
6602 struct wpabuf *msg, *clear, *json;
6603 size_t nonce_len, clear_len, attr_len;
6604 const u8 *addr[2];
6605 size_t len[2];
6606 u8 *wrapped;
6607
6608 json = wpabuf_alloc(1000);
6609 if (!json)
6610 return NULL;
6611 wpabuf_printf(json, "{\"result\":%d", result);
6612 if (ssid) {
6613 char ssid_str[6 * SSID_MAX_LEN + 1];
6614
6615 wpabuf_put_str(json, ",\"ssid\":\"");
6616 json_escape_string(ssid_str, sizeof(ssid_str),
6617 (const char *) ssid, ssid_len);
6618 wpabuf_put_str(json, ssid_str);
6619 wpabuf_put_str(json, "\"");
6620 }
6621 if (channel_list)
6622 wpabuf_printf(json, ",\"channelList\":\"%s\"", channel_list);
6623 wpabuf_put_str(json, "}");
6624 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
6625 wpabuf_head(json), wpabuf_len(json));
6626
6627 nonce_len = auth->curve->nonce_len;
6628 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
6629 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6630 clear = wpabuf_alloc(clear_len);
6631 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
6632 if (!clear || !msg)
6633 goto fail;
6634
6635 /* E-nonce */
6636 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
6637 wpabuf_put_le16(clear, nonce_len);
6638 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
6639
6640 /* DPP Connection Status */
6641 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
6642 wpabuf_put_le16(clear, wpabuf_len(json));
6643 wpabuf_put_buf(clear, json);
6644
6645 /* OUI, OUI type, Crypto Suite, DPP frame type */
6646 addr[0] = wpabuf_head_u8(msg) + 2;
6647 len[0] = 3 + 1 + 1 + 1;
6648 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6649
6650 /* Attributes before Wrapped Data (none) */
6651 addr[1] = wpabuf_put(msg, 0);
6652 len[1] = 0;
6653 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6654
6655 /* Wrapped Data */
6656 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6657 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6658 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6659
6660 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6661 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
6662 wpabuf_head(clear), wpabuf_len(clear),
6663 2, addr, len, wrapped) < 0)
6664 goto fail;
6665
6666 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
6667 msg);
6668 wpabuf_free(json);
6669 wpabuf_free(clear);
6670 return msg;
6671fail:
6672 wpabuf_free(json);
6673 wpabuf_free(clear);
6674 wpabuf_free(msg);
6675 return NULL;
6676}
6677
6678#endif /* CONFIG_DPP2 */
6679
6680
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006681void dpp_configurator_free(struct dpp_configurator *conf)
6682{
6683 if (!conf)
6684 return;
6685 EVP_PKEY_free(conf->csign);
6686 os_free(conf->kid);
6687 os_free(conf);
6688}
6689
6690
Roshan Pius3a1667e2018-07-03 15:17:14 -07006691int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
6692 size_t buflen)
6693{
6694 EC_KEY *eckey;
6695 int key_len, ret = -1;
6696 unsigned char *key = NULL;
6697
6698 if (!conf->csign)
6699 return -1;
6700
6701 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
6702 if (!eckey)
6703 return -1;
6704
6705 key_len = i2d_ECPrivateKey(eckey, &key);
6706 if (key_len > 0)
6707 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
6708
6709 EC_KEY_free(eckey);
6710 OPENSSL_free(key);
6711 return ret;
6712}
6713
6714
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006715struct dpp_configurator *
6716dpp_keygen_configurator(const char *curve, const u8 *privkey,
6717 size_t privkey_len)
6718{
6719 struct dpp_configurator *conf;
6720 struct wpabuf *csign_pub = NULL;
6721 u8 kid_hash[SHA256_MAC_LEN];
6722 const u8 *addr[1];
6723 size_t len[1];
6724
6725 conf = os_zalloc(sizeof(*conf));
6726 if (!conf)
6727 return NULL;
6728
6729 if (!curve) {
6730 conf->curve = &dpp_curves[0];
6731 } else {
6732 conf->curve = dpp_get_curve_name(curve);
6733 if (!conf->curve) {
6734 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6735 curve);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006736 os_free(conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006737 return NULL;
6738 }
6739 }
6740 if (privkey)
6741 conf->csign = dpp_set_keypair(&conf->curve, privkey,
6742 privkey_len);
6743 else
6744 conf->csign = dpp_gen_keypair(conf->curve);
6745 if (!conf->csign)
6746 goto fail;
6747 conf->own = 1;
6748
6749 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
6750 if (!csign_pub) {
6751 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
6752 goto fail;
6753 }
6754
6755 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6756 addr[0] = wpabuf_head(csign_pub);
6757 len[0] = wpabuf_len(csign_pub);
6758 if (sha256_vector(1, addr, len, kid_hash) < 0) {
6759 wpa_printf(MSG_DEBUG,
6760 "DPP: Failed to derive kid for C-sign-key");
6761 goto fail;
6762 }
6763
6764 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
6765 NULL, 0);
6766 if (!conf->kid)
6767 goto fail;
6768out:
6769 wpabuf_free(csign_pub);
6770 return conf;
6771fail:
6772 dpp_configurator_free(conf);
6773 conf = NULL;
6774 goto out;
6775}
6776
6777
6778int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006779 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006780{
6781 struct wpabuf *conf_obj;
6782 int ret = -1;
6783
6784 if (!auth->conf) {
6785 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
6786 return -1;
6787 }
6788
6789 if (!curve) {
6790 auth->curve = &dpp_curves[0];
6791 } else {
6792 auth->curve = dpp_get_curve_name(curve);
6793 if (!auth->curve) {
6794 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6795 curve);
6796 return -1;
6797 }
6798 }
6799 wpa_printf(MSG_DEBUG,
6800 "DPP: Building own configuration/connector with curve %s",
6801 auth->curve->name);
6802
6803 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
6804 if (!auth->own_protocol_key)
6805 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07006806 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006807 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07006808 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006809
Hai Shalomc3565922019-10-28 11:58:20 -07006810 conf_obj = dpp_build_conf_obj(auth, ap, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006811 if (!conf_obj)
6812 goto fail;
6813 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
6814 wpabuf_len(conf_obj));
6815fail:
6816 wpabuf_free(conf_obj);
6817 auth->peer_protocol_key = NULL;
6818 return ret;
6819}
6820
6821
6822static int dpp_compatible_netrole(const char *role1, const char *role2)
6823{
6824 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
6825 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
6826}
6827
6828
6829static int dpp_connector_compatible_group(struct json_token *root,
6830 const char *group_id,
6831 const char *net_role)
6832{
6833 struct json_token *groups, *token;
6834
6835 groups = json_get_member(root, "groups");
6836 if (!groups || groups->type != JSON_ARRAY)
6837 return 0;
6838
6839 for (token = groups->child; token; token = token->sibling) {
6840 struct json_token *id, *role;
6841
6842 id = json_get_member(token, "groupId");
6843 if (!id || id->type != JSON_STRING)
6844 continue;
6845
6846 role = json_get_member(token, "netRole");
6847 if (!role || role->type != JSON_STRING)
6848 continue;
6849
6850 if (os_strcmp(id->string, "*") != 0 &&
6851 os_strcmp(group_id, "*") != 0 &&
6852 os_strcmp(id->string, group_id) != 0)
6853 continue;
6854
6855 if (dpp_compatible_netrole(role->string, net_role))
6856 return 1;
6857 }
6858
6859 return 0;
6860}
6861
6862
6863static int dpp_connector_match_groups(struct json_token *own_root,
6864 struct json_token *peer_root)
6865{
6866 struct json_token *groups, *token;
6867
6868 groups = json_get_member(peer_root, "groups");
6869 if (!groups || groups->type != JSON_ARRAY) {
6870 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
6871 return 0;
6872 }
6873
6874 for (token = groups->child; token; token = token->sibling) {
6875 struct json_token *id, *role;
6876
6877 id = json_get_member(token, "groupId");
6878 if (!id || id->type != JSON_STRING) {
6879 wpa_printf(MSG_DEBUG,
6880 "DPP: Missing peer groupId string");
6881 continue;
6882 }
6883
6884 role = json_get_member(token, "netRole");
6885 if (!role || role->type != JSON_STRING) {
6886 wpa_printf(MSG_DEBUG,
6887 "DPP: Missing peer groups::netRole string");
6888 continue;
6889 }
6890 wpa_printf(MSG_DEBUG,
6891 "DPP: peer connector group: groupId='%s' netRole='%s'",
6892 id->string, role->string);
6893 if (dpp_connector_compatible_group(own_root, id->string,
6894 role->string)) {
6895 wpa_printf(MSG_DEBUG,
6896 "DPP: Compatible group/netRole in own connector");
6897 return 1;
6898 }
6899 }
6900
6901 return 0;
6902}
6903
6904
6905static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
6906 unsigned int hash_len)
6907{
6908 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6909 const char *info = "DPP PMK";
6910 int res;
6911
6912 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6913
6914 /* HKDF-Extract(<>, N.x) */
6915 os_memset(salt, 0, hash_len);
6916 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
6917 return -1;
6918 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6919 prk, hash_len);
6920
6921 /* HKDF-Expand(PRK, info, L) */
6922 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
6923 os_memset(prk, 0, hash_len);
6924 if (res < 0)
6925 return -1;
6926
6927 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6928 pmk, hash_len);
6929 return 0;
6930}
6931
6932
6933static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
6934 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
6935{
6936 struct wpabuf *nkx, *pkx;
6937 int ret = -1, res;
6938 const u8 *addr[2];
6939 size_t len[2];
6940 u8 hash[SHA256_MAC_LEN];
6941
6942 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6943 nkx = dpp_get_pubkey_point(own_key, 0);
6944 pkx = dpp_get_pubkey_point(peer_key, 0);
6945 if (!nkx || !pkx)
6946 goto fail;
6947 addr[0] = wpabuf_head(nkx);
6948 len[0] = wpabuf_len(nkx) / 2;
6949 addr[1] = wpabuf_head(pkx);
6950 len[1] = wpabuf_len(pkx) / 2;
6951 if (len[0] != len[1])
6952 goto fail;
6953 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
6954 addr[0] = wpabuf_head(pkx);
6955 addr[1] = wpabuf_head(nkx);
6956 }
6957 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
6958 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
6959 res = sha256_vector(2, addr, len, hash);
6960 if (res < 0)
6961 goto fail;
6962 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
6963 os_memcpy(pmkid, hash, PMKID_LEN);
6964 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
6965 ret = 0;
6966fail:
6967 wpabuf_free(nkx);
6968 wpabuf_free(pkx);
6969 return ret;
6970}
6971
6972
Roshan Pius3a1667e2018-07-03 15:17:14 -07006973enum dpp_status_error
6974dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
6975 const u8 *net_access_key, size_t net_access_key_len,
6976 const u8 *csign_key, size_t csign_key_len,
6977 const u8 *peer_connector, size_t peer_connector_len,
6978 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006979{
6980 struct json_token *root = NULL, *netkey, *token;
6981 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006982 enum dpp_status_error ret = 255, res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006983 EVP_PKEY *own_key = NULL, *peer_key = NULL;
6984 struct wpabuf *own_key_pub = NULL;
6985 const struct dpp_curve_params *curve, *own_curve;
6986 struct dpp_signed_connector_info info;
6987 const unsigned char *p;
6988 EVP_PKEY *csign = NULL;
6989 char *signed_connector = NULL;
6990 const char *pos, *end;
6991 unsigned char *own_conn = NULL;
6992 size_t own_conn_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006993 size_t Nx_len;
6994 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
6995
6996 os_memset(intro, 0, sizeof(*intro));
6997 os_memset(&info, 0, sizeof(info));
6998 if (expiry)
6999 *expiry = 0;
7000
7001 p = csign_key;
7002 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
7003 if (!csign) {
7004 wpa_printf(MSG_ERROR,
7005 "DPP: Failed to parse local C-sign-key information");
7006 goto fail;
7007 }
7008
7009 own_key = dpp_set_keypair(&own_curve, net_access_key,
7010 net_access_key_len);
7011 if (!own_key) {
7012 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
7013 goto fail;
7014 }
7015
7016 pos = os_strchr(own_connector, '.');
7017 if (!pos) {
7018 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
7019 goto fail;
7020 }
7021 pos++;
7022 end = os_strchr(pos, '.');
7023 if (!end) {
7024 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
7025 goto fail;
7026 }
7027 own_conn = base64_url_decode((const unsigned char *) pos,
7028 end - pos, &own_conn_len);
7029 if (!own_conn) {
7030 wpa_printf(MSG_DEBUG,
7031 "DPP: Failed to base64url decode own signedConnector JWS Payload");
7032 goto fail;
7033 }
7034
7035 own_root = json_parse((const char *) own_conn, own_conn_len);
7036 if (!own_root) {
7037 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
7038 goto fail;
7039 }
7040
7041 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
7042 peer_connector, peer_connector_len);
7043 signed_connector = os_malloc(peer_connector_len + 1);
7044 if (!signed_connector)
7045 goto fail;
7046 os_memcpy(signed_connector, peer_connector, peer_connector_len);
7047 signed_connector[peer_connector_len] = '\0';
7048
Roshan Pius3a1667e2018-07-03 15:17:14 -07007049 res = dpp_process_signed_connector(&info, csign, signed_connector);
7050 if (res != DPP_STATUS_OK) {
7051 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007052 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007053 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007054
7055 root = json_parse((const char *) info.payload, info.payload_len);
7056 if (!root) {
7057 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07007058 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007059 goto fail;
7060 }
7061
7062 if (!dpp_connector_match_groups(own_root, root)) {
7063 wpa_printf(MSG_DEBUG,
7064 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07007065 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007066 goto fail;
7067 }
7068
7069 token = json_get_member(root, "expiry");
7070 if (!token || token->type != JSON_STRING) {
7071 wpa_printf(MSG_DEBUG,
7072 "DPP: No expiry string found - connector does not expire");
7073 } else {
7074 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
7075 if (dpp_key_expired(token->string, expiry)) {
7076 wpa_printf(MSG_DEBUG,
7077 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07007078 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007079 goto fail;
7080 }
7081 }
7082
7083 netkey = json_get_member(root, "netAccessKey");
7084 if (!netkey || netkey->type != JSON_OBJECT) {
7085 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07007086 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007087 goto fail;
7088 }
7089
7090 peer_key = dpp_parse_jwk(netkey, &curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007091 if (!peer_key) {
7092 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007093 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007094 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007095 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
7096
7097 if (own_curve != curve) {
7098 wpa_printf(MSG_DEBUG,
7099 "DPP: Mismatching netAccessKey curves (%s != %s)",
7100 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007101 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007102 goto fail;
7103 }
7104
7105 /* ECDH: N = nk * PK */
Hai Shalomc3565922019-10-28 11:58:20 -07007106 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007107 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007108
7109 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
7110 Nx, Nx_len);
7111
7112 /* PMK = HKDF(<>, "DPP PMK", N.x) */
7113 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
7114 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
7115 goto fail;
7116 }
7117 intro->pmk_len = curve->hash_len;
7118
7119 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
7120 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
7121 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
7122 goto fail;
7123 }
7124
Roshan Pius3a1667e2018-07-03 15:17:14 -07007125 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007126fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07007127 if (ret != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007128 os_memset(intro, 0, sizeof(*intro));
7129 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007130 os_free(own_conn);
7131 os_free(signed_connector);
7132 os_free(info.payload);
7133 EVP_PKEY_free(own_key);
7134 wpabuf_free(own_key_pub);
7135 EVP_PKEY_free(peer_key);
7136 EVP_PKEY_free(csign);
7137 json_free(root);
7138 json_free(own_root);
7139 return ret;
7140}
7141
7142
7143static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
7144 int init)
7145{
7146 EC_GROUP *group;
7147 size_t len = curve->prime_len;
7148 const u8 *x, *y;
Hai Shalom81f62d82019-07-22 12:10:00 -07007149 EVP_PKEY *res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007150
7151 switch (curve->ike_group) {
7152 case 19:
7153 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
7154 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
7155 break;
7156 case 20:
7157 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
7158 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
7159 break;
7160 case 21:
7161 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
7162 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
7163 break;
7164 case 28:
7165 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
7166 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
7167 break;
7168 case 29:
7169 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
7170 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
7171 break;
7172 case 30:
7173 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
7174 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
7175 break;
7176 default:
7177 return NULL;
7178 }
7179
7180 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
7181 if (!group)
7182 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07007183 res = dpp_set_pubkey_point_group(group, x, y, len);
7184 EC_GROUP_free(group);
7185 return res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007186}
7187
7188
7189static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
7190 const u8 *mac_init, const char *code,
7191 const char *identifier, BN_CTX *bnctx,
Hai Shalom81f62d82019-07-22 12:10:00 -07007192 EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007193{
7194 u8 hash[DPP_MAX_HASH_LEN];
7195 const u8 *addr[3];
7196 size_t len[3];
7197 unsigned int num_elem = 0;
7198 EC_POINT *Qi = NULL;
7199 EVP_PKEY *Pi = NULL;
7200 EC_KEY *Pi_ec = NULL;
7201 const EC_POINT *Pi_point;
7202 BIGNUM *hash_bn = NULL;
7203 const EC_GROUP *group = NULL;
7204 EC_GROUP *group2 = NULL;
7205
7206 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7207
7208 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
7209 addr[num_elem] = mac_init;
7210 len[num_elem] = ETH_ALEN;
7211 num_elem++;
7212 if (identifier) {
7213 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
7214 identifier);
7215 addr[num_elem] = (const u8 *) identifier;
7216 len[num_elem] = os_strlen(identifier);
7217 num_elem++;
7218 }
7219 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
7220 addr[num_elem] = (const u8 *) code;
7221 len[num_elem] = os_strlen(code);
7222 num_elem++;
7223 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
7224 goto fail;
7225 wpa_hexdump_key(MSG_DEBUG,
7226 "DPP: H(MAC-Initiator | [identifier |] code)",
7227 hash, curve->hash_len);
7228 Pi = dpp_pkex_get_role_elem(curve, 1);
7229 if (!Pi)
7230 goto fail;
7231 dpp_debug_print_key("DPP: Pi", Pi);
7232 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
7233 if (!Pi_ec)
7234 goto fail;
7235 Pi_point = EC_KEY_get0_public_key(Pi_ec);
7236
7237 group = EC_KEY_get0_group(Pi_ec);
7238 if (!group)
7239 goto fail;
7240 group2 = EC_GROUP_dup(group);
7241 if (!group2)
7242 goto fail;
7243 Qi = EC_POINT_new(group2);
7244 if (!Qi) {
7245 EC_GROUP_free(group2);
7246 goto fail;
7247 }
7248 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
7249 if (!hash_bn ||
7250 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
7251 goto fail;
7252 if (EC_POINT_is_at_infinity(group, Qi)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007253 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007254 goto fail;
7255 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07007256 dpp_debug_print_point("DPP: Qi", group, Qi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007257out:
7258 EC_KEY_free(Pi_ec);
7259 EVP_PKEY_free(Pi);
7260 BN_clear_free(hash_bn);
Hai Shalom81f62d82019-07-22 12:10:00 -07007261 if (ret_group && Qi)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007262 *ret_group = group2;
Hai Shalom81f62d82019-07-22 12:10:00 -07007263 else
7264 EC_GROUP_free(group2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007265 return Qi;
7266fail:
7267 EC_POINT_free(Qi);
7268 Qi = NULL;
7269 goto out;
7270}
7271
7272
7273static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
7274 const u8 *mac_resp, const char *code,
7275 const char *identifier, BN_CTX *bnctx,
Hai Shalom81f62d82019-07-22 12:10:00 -07007276 EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007277{
7278 u8 hash[DPP_MAX_HASH_LEN];
7279 const u8 *addr[3];
7280 size_t len[3];
7281 unsigned int num_elem = 0;
7282 EC_POINT *Qr = NULL;
7283 EVP_PKEY *Pr = NULL;
7284 EC_KEY *Pr_ec = NULL;
7285 const EC_POINT *Pr_point;
7286 BIGNUM *hash_bn = NULL;
7287 const EC_GROUP *group = NULL;
7288 EC_GROUP *group2 = NULL;
7289
7290 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7291
7292 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
7293 addr[num_elem] = mac_resp;
7294 len[num_elem] = ETH_ALEN;
7295 num_elem++;
7296 if (identifier) {
7297 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
7298 identifier);
7299 addr[num_elem] = (const u8 *) identifier;
7300 len[num_elem] = os_strlen(identifier);
7301 num_elem++;
7302 }
7303 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
7304 addr[num_elem] = (const u8 *) code;
7305 len[num_elem] = os_strlen(code);
7306 num_elem++;
7307 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
7308 goto fail;
7309 wpa_hexdump_key(MSG_DEBUG,
7310 "DPP: H(MAC-Responder | [identifier |] code)",
7311 hash, curve->hash_len);
7312 Pr = dpp_pkex_get_role_elem(curve, 0);
7313 if (!Pr)
7314 goto fail;
7315 dpp_debug_print_key("DPP: Pr", Pr);
7316 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
7317 if (!Pr_ec)
7318 goto fail;
7319 Pr_point = EC_KEY_get0_public_key(Pr_ec);
7320
7321 group = EC_KEY_get0_group(Pr_ec);
7322 if (!group)
7323 goto fail;
7324 group2 = EC_GROUP_dup(group);
7325 if (!group2)
7326 goto fail;
7327 Qr = EC_POINT_new(group2);
7328 if (!Qr) {
7329 EC_GROUP_free(group2);
7330 goto fail;
7331 }
7332 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
7333 if (!hash_bn ||
7334 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
7335 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007336 if (EC_POINT_is_at_infinity(group, Qr)) {
7337 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
7338 goto fail;
7339 }
7340 dpp_debug_print_point("DPP: Qr", group, Qr);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007341out:
7342 EC_KEY_free(Pr_ec);
7343 EVP_PKEY_free(Pr);
7344 BN_clear_free(hash_bn);
Hai Shalom81f62d82019-07-22 12:10:00 -07007345 if (ret_group && Qr)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007346 *ret_group = group2;
Hai Shalom81f62d82019-07-22 12:10:00 -07007347 else
7348 EC_GROUP_free(group2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007349 return Qr;
7350fail:
7351 EC_POINT_free(Qr);
7352 Qr = NULL;
7353 goto out;
7354}
7355
7356
Roshan Pius3a1667e2018-07-03 15:17:14 -07007357#ifdef CONFIG_TESTING_OPTIONS
7358static int dpp_test_gen_invalid_key(struct wpabuf *msg,
7359 const struct dpp_curve_params *curve)
7360{
7361 BN_CTX *ctx;
7362 BIGNUM *x, *y;
7363 int ret = -1;
7364 EC_GROUP *group;
7365 EC_POINT *point;
7366
7367 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
7368 if (!group)
7369 return -1;
7370
7371 ctx = BN_CTX_new();
7372 point = EC_POINT_new(group);
7373 x = BN_new();
7374 y = BN_new();
7375 if (!ctx || !point || !x || !y)
7376 goto fail;
7377
7378 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
7379 goto fail;
7380
7381 /* Generate a random y coordinate that results in a point that is not
7382 * on the curve. */
7383 for (;;) {
7384 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
7385 goto fail;
7386
7387 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
7388 ctx) != 1) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007389#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
Roshan Pius3a1667e2018-07-03 15:17:14 -07007390 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
7391 * return an error from EC_POINT_set_affine_coordinates_GFp()
7392 * when the point is not on the curve. */
7393 break;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007394#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07007395 goto fail;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007396#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07007397 }
7398
7399 if (!EC_POINT_is_on_curve(group, point, ctx))
7400 break;
7401 }
7402
7403 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
7404 curve->prime_len) < 0 ||
7405 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
7406 curve->prime_len) < 0)
7407 goto fail;
7408
7409 ret = 0;
7410fail:
7411 if (ret < 0)
7412 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
7413 BN_free(x);
7414 BN_free(y);
7415 EC_POINT_free(point);
7416 BN_CTX_free(ctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07007417 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007418
7419 return ret;
7420}
7421#endif /* CONFIG_TESTING_OPTIONS */
7422
7423
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007424static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
7425{
7426 EC_KEY *X_ec = NULL;
7427 const EC_POINT *X_point;
7428 BN_CTX *bnctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07007429 EC_GROUP *group = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007430 EC_POINT *Qi = NULL, *M = NULL;
7431 struct wpabuf *M_buf = NULL;
7432 BIGNUM *Mx = NULL, *My = NULL;
7433 struct wpabuf *msg = NULL;
7434 size_t attr_len;
7435 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007436
7437 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
7438
7439 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7440 bnctx = BN_CTX_new();
7441 if (!bnctx)
7442 goto fail;
7443 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
7444 pkex->identifier, bnctx, &group);
7445 if (!Qi)
7446 goto fail;
7447
7448 /* Generate a random ephemeral keypair x/X */
Roshan Pius3a1667e2018-07-03 15:17:14 -07007449#ifdef CONFIG_TESTING_OPTIONS
7450 if (dpp_pkex_ephemeral_key_override_len) {
7451 const struct dpp_curve_params *tmp_curve;
7452
7453 wpa_printf(MSG_INFO,
7454 "DPP: TESTING - override ephemeral key x/X");
7455 pkex->x = dpp_set_keypair(&tmp_curve,
7456 dpp_pkex_ephemeral_key_override,
7457 dpp_pkex_ephemeral_key_override_len);
7458 } else {
7459 pkex->x = dpp_gen_keypair(curve);
7460 }
7461#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007462 pkex->x = dpp_gen_keypair(curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007463#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007464 if (!pkex->x)
7465 goto fail;
7466
7467 /* M = X + Qi */
7468 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
7469 if (!X_ec)
7470 goto fail;
7471 X_point = EC_KEY_get0_public_key(X_ec);
7472 if (!X_point)
7473 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007474 dpp_debug_print_point("DPP: X", group, X_point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007475 M = EC_POINT_new(group);
7476 Mx = BN_new();
7477 My = BN_new();
7478 if (!M || !Mx || !My ||
7479 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
7480 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
7481 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007482 dpp_debug_print_point("DPP: M", group, M);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007483
7484 /* Initiator -> Responder: group, [identifier,] M */
7485 attr_len = 4 + 2;
7486 if (pkex->identifier)
7487 attr_len += 4 + os_strlen(pkex->identifier);
7488 attr_len += 4 + 2 * curve->prime_len;
7489 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
7490 if (!msg)
7491 goto fail;
7492
Roshan Pius3a1667e2018-07-03 15:17:14 -07007493#ifdef CONFIG_TESTING_OPTIONS
7494 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
7495 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
7496 goto skip_finite_cyclic_group;
7497 }
7498#endif /* CONFIG_TESTING_OPTIONS */
7499
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007500 /* Finite Cyclic Group attribute */
7501 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
7502 wpabuf_put_le16(msg, 2);
7503 wpabuf_put_le16(msg, curve->ike_group);
7504
Roshan Pius3a1667e2018-07-03 15:17:14 -07007505#ifdef CONFIG_TESTING_OPTIONS
7506skip_finite_cyclic_group:
7507#endif /* CONFIG_TESTING_OPTIONS */
7508
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007509 /* Code Identifier attribute */
7510 if (pkex->identifier) {
7511 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
7512 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
7513 wpabuf_put_str(msg, pkex->identifier);
7514 }
7515
Roshan Pius3a1667e2018-07-03 15:17:14 -07007516#ifdef CONFIG_TESTING_OPTIONS
7517 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
7518 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
7519 goto out;
7520 }
7521#endif /* CONFIG_TESTING_OPTIONS */
7522
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007523 /* M in Encrypted Key attribute */
7524 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
7525 wpabuf_put_le16(msg, 2 * curve->prime_len);
7526
Roshan Pius3a1667e2018-07-03 15:17:14 -07007527#ifdef CONFIG_TESTING_OPTIONS
7528 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
7529 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
7530 if (dpp_test_gen_invalid_key(msg, curve) < 0)
7531 goto fail;
7532 goto out;
7533 }
7534#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007535
Roshan Pius3a1667e2018-07-03 15:17:14 -07007536 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
7537 curve->prime_len) < 0 ||
7538 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
7539 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
7540 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007541 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007542
7543out:
7544 wpabuf_free(M_buf);
7545 EC_KEY_free(X_ec);
7546 EC_POINT_free(M);
7547 EC_POINT_free(Qi);
7548 BN_clear_free(Mx);
7549 BN_clear_free(My);
7550 BN_CTX_free(bnctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07007551 EC_GROUP_free(group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007552 return msg;
7553fail:
7554 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
7555 wpabuf_free(msg);
7556 msg = NULL;
7557 goto out;
7558}
7559
7560
Roshan Pius3a1667e2018-07-03 15:17:14 -07007561static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
7562{
7563 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
7564}
7565
7566
7567struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007568 const u8 *own_mac,
7569 const char *identifier,
7570 const char *code)
7571{
7572 struct dpp_pkex *pkex;
7573
Roshan Pius3a1667e2018-07-03 15:17:14 -07007574#ifdef CONFIG_TESTING_OPTIONS
7575 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
7576 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
7577 MAC2STR(dpp_pkex_own_mac_override));
7578 own_mac = dpp_pkex_own_mac_override;
7579 }
7580#endif /* CONFIG_TESTING_OPTIONS */
7581
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007582 pkex = os_zalloc(sizeof(*pkex));
7583 if (!pkex)
7584 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007585 pkex->msg_ctx = msg_ctx;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007586 pkex->initiator = 1;
7587 pkex->own_bi = bi;
7588 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
7589 if (identifier) {
7590 pkex->identifier = os_strdup(identifier);
7591 if (!pkex->identifier)
7592 goto fail;
7593 }
7594 pkex->code = os_strdup(code);
7595 if (!pkex->code)
7596 goto fail;
7597 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
7598 if (!pkex->exchange_req)
7599 goto fail;
7600 return pkex;
7601fail:
7602 dpp_pkex_free(pkex);
7603 return NULL;
7604}
7605
7606
Roshan Pius3a1667e2018-07-03 15:17:14 -07007607static struct wpabuf *
7608dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
7609 enum dpp_status_error status,
7610 const BIGNUM *Nx, const BIGNUM *Ny)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007611{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007612 struct wpabuf *msg = NULL;
7613 size_t attr_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007614 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007615
7616 /* Initiator -> Responder: DPP Status, [identifier,] N */
7617 attr_len = 4 + 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007618 if (pkex->identifier)
7619 attr_len += 4 + os_strlen(pkex->identifier);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007620 attr_len += 4 + 2 * curve->prime_len;
7621 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
7622 if (!msg)
7623 goto fail;
7624
Roshan Pius3a1667e2018-07-03 15:17:14 -07007625#ifdef CONFIG_TESTING_OPTIONS
7626 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
7627 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
7628 goto skip_status;
7629 }
7630
7631 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
7632 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
7633 status = 255;
7634 }
7635#endif /* CONFIG_TESTING_OPTIONS */
7636
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007637 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07007638 dpp_build_attr_status(msg, status);
7639
7640#ifdef CONFIG_TESTING_OPTIONS
7641skip_status:
7642#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007643
7644 /* Code Identifier attribute */
7645 if (pkex->identifier) {
7646 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
7647 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
7648 wpabuf_put_str(msg, pkex->identifier);
7649 }
7650
Roshan Pius3a1667e2018-07-03 15:17:14 -07007651 if (status != DPP_STATUS_OK)
7652 goto skip_encrypted_key;
7653
7654#ifdef CONFIG_TESTING_OPTIONS
7655 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7656 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
7657 goto skip_encrypted_key;
7658 }
7659#endif /* CONFIG_TESTING_OPTIONS */
7660
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007661 /* N in Encrypted Key attribute */
7662 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
7663 wpabuf_put_le16(msg, 2 * curve->prime_len);
7664
Roshan Pius3a1667e2018-07-03 15:17:14 -07007665#ifdef CONFIG_TESTING_OPTIONS
7666 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7667 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
7668 if (dpp_test_gen_invalid_key(msg, curve) < 0)
7669 goto fail;
7670 goto skip_encrypted_key;
7671 }
7672#endif /* CONFIG_TESTING_OPTIONS */
7673
7674 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
7675 curve->prime_len) < 0 ||
7676 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
7677 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
7678 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007679 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007680
Roshan Pius3a1667e2018-07-03 15:17:14 -07007681skip_encrypted_key:
7682 if (status == DPP_STATUS_BAD_GROUP) {
7683 /* Finite Cyclic Group attribute */
7684 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
7685 wpabuf_put_le16(msg, 2);
7686 wpabuf_put_le16(msg, curve->ike_group);
7687 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007688
Roshan Pius3a1667e2018-07-03 15:17:14 -07007689 return msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007690fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07007691 wpabuf_free(msg);
7692 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007693}
7694
7695
7696static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
7697 const u8 *Mx, size_t Mx_len,
7698 const u8 *Nx, size_t Nx_len,
7699 const char *code,
7700 const u8 *Kx, size_t Kx_len,
7701 u8 *z, unsigned int hash_len)
7702{
7703 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
7704 int res;
7705 u8 *info, *pos;
7706 size_t info_len;
7707
7708 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7709 */
7710
7711 /* HKDF-Extract(<>, IKM=K.x) */
7712 os_memset(salt, 0, hash_len);
7713 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
7714 return -1;
7715 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
7716 prk, hash_len);
7717 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
7718 info = os_malloc(info_len);
7719 if (!info)
7720 return -1;
7721 pos = info;
7722 os_memcpy(pos, mac_init, ETH_ALEN);
7723 pos += ETH_ALEN;
7724 os_memcpy(pos, mac_resp, ETH_ALEN);
7725 pos += ETH_ALEN;
7726 os_memcpy(pos, Mx, Mx_len);
7727 pos += Mx_len;
7728 os_memcpy(pos, Nx, Nx_len);
7729 pos += Nx_len;
7730 os_memcpy(pos, code, os_strlen(code));
7731
7732 /* HKDF-Expand(PRK, info, L) */
7733 if (hash_len == 32)
7734 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
7735 z, hash_len);
7736 else if (hash_len == 48)
7737 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
7738 z, hash_len);
7739 else if (hash_len == 64)
7740 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
7741 z, hash_len);
7742 else
7743 res = -1;
7744 os_free(info);
7745 os_memset(prk, 0, hash_len);
7746 if (res < 0)
7747 return -1;
7748
7749 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
7750 z, hash_len);
7751 return 0;
7752}
7753
7754
Hai Shalom74f70d42019-02-11 14:42:39 -08007755static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
7756 const char *identifier)
7757{
7758 if (!attr_id && identifier) {
7759 wpa_printf(MSG_DEBUG,
7760 "DPP: No PKEX code identifier received, but expected one");
7761 return 0;
7762 }
7763
7764 if (attr_id && !identifier) {
7765 wpa_printf(MSG_DEBUG,
7766 "DPP: PKEX code identifier received, but not expecting one");
7767 return 0;
7768 }
7769
7770 if (attr_id && identifier &&
7771 (os_strlen(identifier) != attr_id_len ||
7772 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
7773 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
7774 return 0;
7775 }
7776
7777 return 1;
7778}
7779
7780
Roshan Pius3a1667e2018-07-03 15:17:14 -07007781struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
7782 struct dpp_bootstrap_info *bi,
7783 const u8 *own_mac,
7784 const u8 *peer_mac,
7785 const char *identifier,
7786 const char *code,
7787 const u8 *buf, size_t len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007788{
Roshan Pius3a1667e2018-07-03 15:17:14 -07007789 const u8 *attr_group, *attr_id, *attr_key;
7790 u16 attr_group_len, attr_id_len, attr_key_len;
7791 const struct dpp_curve_params *curve = bi->curve;
7792 u16 ike_group;
7793 struct dpp_pkex *pkex = NULL;
7794 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007795 BN_CTX *bnctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07007796 EC_GROUP *group = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007797 BIGNUM *Mx = NULL, *My = NULL;
7798 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
7799 const EC_POINT *Y_point;
7800 BIGNUM *Nx = NULL, *Ny = NULL;
7801 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
7802 size_t Kx_len;
7803 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007804
7805 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
7806 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7807 "PKEX counter t limit reached - ignore message");
7808 return NULL;
7809 }
7810
7811#ifdef CONFIG_TESTING_OPTIONS
7812 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
7813 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
7814 MAC2STR(dpp_pkex_peer_mac_override));
7815 peer_mac = dpp_pkex_peer_mac_override;
7816 }
7817 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
7818 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
7819 MAC2STR(dpp_pkex_own_mac_override));
7820 own_mac = dpp_pkex_own_mac_override;
7821 }
7822#endif /* CONFIG_TESTING_OPTIONS */
7823
Hai Shalom74f70d42019-02-11 14:42:39 -08007824 attr_id_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007825 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
7826 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08007827 if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
Roshan Pius3a1667e2018-07-03 15:17:14 -07007828 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007829
7830 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
7831 &attr_group_len);
7832 if (!attr_group || attr_group_len != 2) {
7833 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7834 "Missing or invalid Finite Cyclic Group attribute");
7835 return NULL;
7836 }
7837 ike_group = WPA_GET_LE16(attr_group);
7838 if (ike_group != curve->ike_group) {
7839 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7840 "Mismatching PKEX curve: peer=%u own=%u",
7841 ike_group, curve->ike_group);
7842 pkex = os_zalloc(sizeof(*pkex));
7843 if (!pkex)
7844 goto fail;
7845 pkex->own_bi = bi;
7846 pkex->failed = 1;
7847 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
7848 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
7849 if (!pkex->exchange_resp)
7850 goto fail;
7851 return pkex;
7852 }
7853
7854 /* M in Encrypted Key attribute */
7855 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
7856 &attr_key_len);
7857 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
7858 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
7859 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7860 "Missing Encrypted Key attribute");
7861 return NULL;
7862 }
7863
7864 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7865 bnctx = BN_CTX_new();
7866 if (!bnctx)
7867 goto fail;
7868 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
7869 &group);
7870 if (!Qi)
7871 goto fail;
7872
7873 /* X' = M - Qi */
7874 X = EC_POINT_new(group);
7875 M = EC_POINT_new(group);
7876 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
7877 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
7878 if (!X || !M || !Mx || !My ||
7879 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
7880 EC_POINT_is_at_infinity(group, M) ||
7881 !EC_POINT_is_on_curve(group, M, bnctx) ||
7882 EC_POINT_invert(group, Qi, bnctx) != 1 ||
7883 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
7884 EC_POINT_is_at_infinity(group, X) ||
7885 !EC_POINT_is_on_curve(group, X, bnctx)) {
7886 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7887 "Invalid Encrypted Key value");
7888 bi->pkex_t++;
7889 goto fail;
7890 }
7891 dpp_debug_print_point("DPP: M", group, M);
7892 dpp_debug_print_point("DPP: X'", group, X);
7893
7894 pkex = os_zalloc(sizeof(*pkex));
7895 if (!pkex)
7896 goto fail;
7897 pkex->t = bi->pkex_t;
7898 pkex->msg_ctx = msg_ctx;
7899 pkex->own_bi = bi;
7900 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
7901 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
7902 if (identifier) {
7903 pkex->identifier = os_strdup(identifier);
7904 if (!pkex->identifier)
7905 goto fail;
7906 }
7907 pkex->code = os_strdup(code);
7908 if (!pkex->code)
7909 goto fail;
7910
7911 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
7912
7913 X_ec = EC_KEY_new();
7914 if (!X_ec ||
7915 EC_KEY_set_group(X_ec, group) != 1 ||
7916 EC_KEY_set_public_key(X_ec, X) != 1)
7917 goto fail;
7918 pkex->x = EVP_PKEY_new();
7919 if (!pkex->x ||
7920 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
7921 goto fail;
7922
7923 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7924 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
7925 if (!Qr)
7926 goto fail;
7927
7928 /* Generate a random ephemeral keypair y/Y */
7929#ifdef CONFIG_TESTING_OPTIONS
7930 if (dpp_pkex_ephemeral_key_override_len) {
7931 const struct dpp_curve_params *tmp_curve;
7932
7933 wpa_printf(MSG_INFO,
7934 "DPP: TESTING - override ephemeral key y/Y");
7935 pkex->y = dpp_set_keypair(&tmp_curve,
7936 dpp_pkex_ephemeral_key_override,
7937 dpp_pkex_ephemeral_key_override_len);
7938 } else {
7939 pkex->y = dpp_gen_keypair(curve);
7940 }
7941#else /* CONFIG_TESTING_OPTIONS */
7942 pkex->y = dpp_gen_keypair(curve);
7943#endif /* CONFIG_TESTING_OPTIONS */
7944 if (!pkex->y)
7945 goto fail;
7946
7947 /* N = Y + Qr */
7948 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
7949 if (!Y_ec)
7950 goto fail;
7951 Y_point = EC_KEY_get0_public_key(Y_ec);
7952 if (!Y_point)
7953 goto fail;
7954 dpp_debug_print_point("DPP: Y", group, Y_point);
7955 N = EC_POINT_new(group);
7956 Nx = BN_new();
7957 Ny = BN_new();
7958 if (!N || !Nx || !Ny ||
7959 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
7960 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
7961 goto fail;
7962 dpp_debug_print_point("DPP: N", group, N);
7963
7964 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
7965 Nx, Ny);
7966 if (!pkex->exchange_resp)
7967 goto fail;
7968
7969 /* K = y * X' */
Hai Shalomc3565922019-10-28 11:58:20 -07007970 if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07007971 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007972
7973 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7974 Kx, Kx_len);
7975
7976 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7977 */
7978 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
7979 pkex->Mx, curve->prime_len,
7980 pkex->Nx, curve->prime_len, pkex->code,
7981 Kx, Kx_len, pkex->z, curve->hash_len);
7982 os_memset(Kx, 0, Kx_len);
7983 if (res < 0)
7984 goto fail;
7985
7986 pkex->exchange_done = 1;
7987
7988out:
Roshan Pius3a1667e2018-07-03 15:17:14 -07007989 BN_CTX_free(bnctx);
7990 EC_POINT_free(Qi);
7991 EC_POINT_free(Qr);
7992 BN_free(Mx);
7993 BN_free(My);
7994 BN_free(Nx);
7995 BN_free(Ny);
7996 EC_POINT_free(M);
7997 EC_POINT_free(N);
7998 EC_POINT_free(X);
7999 EC_KEY_free(X_ec);
8000 EC_KEY_free(Y_ec);
Hai Shalom81f62d82019-07-22 12:10:00 -07008001 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008002 return pkex;
8003fail:
8004 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
8005 dpp_pkex_free(pkex);
8006 pkex = NULL;
8007 goto out;
8008}
8009
8010
8011static struct wpabuf *
8012dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
8013 const struct wpabuf *A_pub, const u8 *u)
8014{
8015 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8016 struct wpabuf *msg = NULL;
8017 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008018 struct wpabuf *clear = NULL;
8019 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008020 u8 octet;
8021 const u8 *addr[2];
8022 size_t len[2];
8023
8024 /* {A, u, [bootstrapping info]}z */
8025 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
8026 clear = wpabuf_alloc(clear_len);
8027 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
8028#ifdef CONFIG_TESTING_OPTIONS
8029 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
8030 attr_len += 5;
8031#endif /* CONFIG_TESTING_OPTIONS */
8032 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
8033 if (!clear || !msg)
8034 goto fail;
8035
8036#ifdef CONFIG_TESTING_OPTIONS
8037 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
8038 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
8039 goto skip_bootstrap_key;
8040 }
8041 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
8042 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
8043 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8044 wpabuf_put_le16(clear, 2 * curve->prime_len);
8045 if (dpp_test_gen_invalid_key(clear, curve) < 0)
8046 goto fail;
8047 goto skip_bootstrap_key;
8048 }
8049#endif /* CONFIG_TESTING_OPTIONS */
8050
8051 /* A in Bootstrap Key attribute */
8052 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8053 wpabuf_put_le16(clear, wpabuf_len(A_pub));
8054 wpabuf_put_buf(clear, A_pub);
8055
8056#ifdef CONFIG_TESTING_OPTIONS
8057skip_bootstrap_key:
8058 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
8059 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
8060 goto skip_i_auth_tag;
8061 }
8062 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
8063 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
8064 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
8065 wpabuf_put_le16(clear, curve->hash_len);
8066 wpabuf_put_data(clear, u, curve->hash_len - 1);
8067 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
8068 goto skip_i_auth_tag;
8069 }
8070#endif /* CONFIG_TESTING_OPTIONS */
8071
8072 /* u in I-Auth tag attribute */
8073 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
8074 wpabuf_put_le16(clear, curve->hash_len);
8075 wpabuf_put_data(clear, u, curve->hash_len);
8076
8077#ifdef CONFIG_TESTING_OPTIONS
8078skip_i_auth_tag:
8079 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
8080 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
8081 goto skip_wrapped_data;
8082 }
8083#endif /* CONFIG_TESTING_OPTIONS */
8084
8085 addr[0] = wpabuf_head_u8(msg) + 2;
8086 len[0] = DPP_HDR_LEN;
8087 octet = 0;
8088 addr[1] = &octet;
8089 len[1] = sizeof(octet);
8090 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8091 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8092
8093 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
8094 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8095 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8096
8097 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
8098 if (aes_siv_encrypt(pkex->z, curve->hash_len,
8099 wpabuf_head(clear), wpabuf_len(clear),
8100 2, addr, len, wrapped) < 0)
8101 goto fail;
8102 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8103 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
8104
8105#ifdef CONFIG_TESTING_OPTIONS
8106 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
8107 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
8108 dpp_build_attr_status(msg, DPP_STATUS_OK);
8109 }
8110skip_wrapped_data:
8111#endif /* CONFIG_TESTING_OPTIONS */
8112
8113out:
8114 wpabuf_free(clear);
8115 return msg;
8116
8117fail:
8118 wpabuf_free(msg);
8119 msg = NULL;
8120 goto out;
8121}
8122
8123
8124struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
8125 const u8 *peer_mac,
8126 const u8 *buf, size_t buflen)
8127{
8128 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
8129 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
Hai Shalom81f62d82019-07-22 12:10:00 -07008130 EC_GROUP *group = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008131 BN_CTX *bnctx = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008132 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8133 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8134 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
8135 BIGNUM *Nx = NULL, *Ny = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008136 EC_KEY *Y_ec = NULL;
8137 size_t Jx_len, Kx_len;
8138 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
8139 const u8 *addr[4];
8140 size_t len[4];
8141 u8 u[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008142 int res;
8143
Roshan Pius3a1667e2018-07-03 15:17:14 -07008144 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
8145 return NULL;
8146
8147#ifdef CONFIG_TESTING_OPTIONS
8148 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
8149 wpa_printf(MSG_INFO,
8150 "DPP: TESTING - stop at PKEX Exchange Response");
8151 pkex->failed = 1;
8152 return NULL;
8153 }
8154
8155 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
8156 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
8157 MAC2STR(dpp_pkex_peer_mac_override));
8158 peer_mac = dpp_pkex_peer_mac_override;
8159 }
8160#endif /* CONFIG_TESTING_OPTIONS */
8161
8162 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
8163
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008164 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
8165 &attr_status_len);
8166 if (!attr_status || attr_status_len != 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008167 dpp_pkex_fail(pkex, "No DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008168 return NULL;
8169 }
8170 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008171
8172 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
8173 attr_group = dpp_get_attr(buf, buflen,
8174 DPP_ATTR_FINITE_CYCLIC_GROUP,
8175 &attr_group_len);
8176 if (attr_group && attr_group_len == 2) {
8177 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
8178 "Peer indicated mismatching PKEX group - proposed %u",
8179 WPA_GET_LE16(attr_group));
8180 return NULL;
8181 }
8182 }
8183
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008184 if (attr_status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008185 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008186 return NULL;
8187 }
8188
Hai Shalom74f70d42019-02-11 14:42:39 -08008189 attr_id_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008190 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
8191 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08008192 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
8193 pkex->identifier)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008194 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008195 return NULL;
8196 }
8197
8198 /* N in Encrypted Key attribute */
8199 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
8200 &attr_key_len);
8201 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008202 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008203 return NULL;
8204 }
8205
8206 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
8207 bnctx = BN_CTX_new();
8208 if (!bnctx)
8209 goto fail;
8210 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
8211 pkex->identifier, bnctx, &group);
8212 if (!Qr)
8213 goto fail;
8214
8215 /* Y' = N - Qr */
8216 Y = EC_POINT_new(group);
8217 N = EC_POINT_new(group);
8218 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
8219 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
8220 if (!Y || !N || !Nx || !Ny ||
8221 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
8222 EC_POINT_is_at_infinity(group, N) ||
8223 !EC_POINT_is_on_curve(group, N, bnctx) ||
8224 EC_POINT_invert(group, Qr, bnctx) != 1 ||
8225 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
8226 EC_POINT_is_at_infinity(group, Y) ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07008227 !EC_POINT_is_on_curve(group, Y, bnctx)) {
8228 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
8229 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008230 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008231 }
8232 dpp_debug_print_point("DPP: N", group, N);
8233 dpp_debug_print_point("DPP: Y'", group, Y);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008234
8235 pkex->exchange_done = 1;
8236
8237 /* ECDH: J = a * Y’ */
8238 Y_ec = EC_KEY_new();
8239 if (!Y_ec ||
8240 EC_KEY_set_group(Y_ec, group) != 1 ||
8241 EC_KEY_set_public_key(Y_ec, Y) != 1)
8242 goto fail;
8243 pkex->y = EVP_PKEY_new();
8244 if (!pkex->y ||
8245 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
8246 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07008247 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008248 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008249
8250 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
8251 Jx, Jx_len);
8252
8253 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
8254 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
8255 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8256 X_pub = dpp_get_pubkey_point(pkex->x, 0);
8257 if (!A_pub || !Y_pub || !X_pub)
8258 goto fail;
8259 addr[0] = pkex->own_mac;
8260 len[0] = ETH_ALEN;
8261 addr[1] = wpabuf_head(A_pub);
8262 len[1] = wpabuf_len(A_pub) / 2;
8263 addr[2] = wpabuf_head(Y_pub);
8264 len[2] = wpabuf_len(Y_pub) / 2;
8265 addr[3] = wpabuf_head(X_pub);
8266 len[3] = wpabuf_len(X_pub) / 2;
8267 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
8268 goto fail;
8269 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
8270
8271 /* K = x * Y’ */
Hai Shalomc3565922019-10-28 11:58:20 -07008272 if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008273 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008274
8275 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
8276 Kx, Kx_len);
8277
8278 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
8279 */
8280 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
8281 pkex->Mx, curve->prime_len,
8282 attr_key /* N.x */, attr_key_len / 2,
8283 pkex->code, Kx, Kx_len,
8284 pkex->z, curve->hash_len);
8285 os_memset(Kx, 0, Kx_len);
8286 if (res < 0)
8287 goto fail;
8288
Roshan Pius3a1667e2018-07-03 15:17:14 -07008289 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
8290 if (!msg)
8291 goto fail;
8292
8293out:
8294 wpabuf_free(A_pub);
8295 wpabuf_free(X_pub);
8296 wpabuf_free(Y_pub);
8297 EC_POINT_free(Qr);
8298 EC_POINT_free(Y);
8299 EC_POINT_free(N);
8300 BN_free(Nx);
8301 BN_free(Ny);
8302 EC_KEY_free(Y_ec);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008303 BN_CTX_free(bnctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07008304 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008305 return msg;
8306fail:
8307 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
8308 goto out;
8309}
8310
8311
8312static struct wpabuf *
8313dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
8314 const struct wpabuf *B_pub, const u8 *v)
8315{
8316 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8317 struct wpabuf *msg = NULL;
8318 const u8 *addr[2];
8319 size_t len[2];
8320 u8 octet;
8321 u8 *wrapped;
8322 struct wpabuf *clear = NULL;
8323 size_t clear_len, attr_len;
8324
8325 /* {B, v [bootstrapping info]}z */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008326 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
8327 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008328 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
8329#ifdef CONFIG_TESTING_OPTIONS
8330 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
8331 attr_len += 5;
8332#endif /* CONFIG_TESTING_OPTIONS */
8333 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008334 if (!clear || !msg)
8335 goto fail;
8336
Roshan Pius3a1667e2018-07-03 15:17:14 -07008337#ifdef CONFIG_TESTING_OPTIONS
8338 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
8339 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
8340 goto skip_bootstrap_key;
8341 }
8342 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
8343 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
8344 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8345 wpabuf_put_le16(clear, 2 * curve->prime_len);
8346 if (dpp_test_gen_invalid_key(clear, curve) < 0)
8347 goto fail;
8348 goto skip_bootstrap_key;
8349 }
8350#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008351
Roshan Pius3a1667e2018-07-03 15:17:14 -07008352 /* B in Bootstrap Key attribute */
8353 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
8354 wpabuf_put_le16(clear, wpabuf_len(B_pub));
8355 wpabuf_put_buf(clear, B_pub);
8356
8357#ifdef CONFIG_TESTING_OPTIONS
8358skip_bootstrap_key:
8359 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
8360 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
8361 goto skip_r_auth_tag;
8362 }
8363 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
8364 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
8365 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
8366 wpabuf_put_le16(clear, curve->hash_len);
8367 wpabuf_put_data(clear, v, curve->hash_len - 1);
8368 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
8369 goto skip_r_auth_tag;
8370 }
8371#endif /* CONFIG_TESTING_OPTIONS */
8372
8373 /* v in R-Auth tag attribute */
8374 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008375 wpabuf_put_le16(clear, curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008376 wpabuf_put_data(clear, v, curve->hash_len);
8377
8378#ifdef CONFIG_TESTING_OPTIONS
8379skip_r_auth_tag:
8380 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
8381 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
8382 goto skip_wrapped_data;
8383 }
8384#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008385
8386 addr[0] = wpabuf_head_u8(msg) + 2;
8387 len[0] = DPP_HDR_LEN;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008388 octet = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008389 addr[1] = &octet;
8390 len[1] = sizeof(octet);
8391 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8392 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8393
8394 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
8395 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8396 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8397
8398 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
8399 if (aes_siv_encrypt(pkex->z, curve->hash_len,
8400 wpabuf_head(clear), wpabuf_len(clear),
8401 2, addr, len, wrapped) < 0)
8402 goto fail;
8403 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8404 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
8405
Roshan Pius3a1667e2018-07-03 15:17:14 -07008406#ifdef CONFIG_TESTING_OPTIONS
8407 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
8408 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
8409 dpp_build_attr_status(msg, DPP_STATUS_OK);
8410 }
8411skip_wrapped_data:
8412#endif /* CONFIG_TESTING_OPTIONS */
8413
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008414out:
8415 wpabuf_free(clear);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008416 return msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008417
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008418fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008419 wpabuf_free(msg);
8420 msg = NULL;
8421 goto out;
8422}
8423
8424
8425struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
8426 const u8 *hdr,
8427 const u8 *buf, size_t buflen)
8428{
8429 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008430 size_t Jx_len, Lx_len;
8431 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008432 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
8433 const u8 *wrapped_data, *b_key, *peer_u;
8434 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
8435 const u8 *addr[4];
8436 size_t len[4];
8437 u8 octet;
8438 u8 *unwrapped = NULL;
8439 size_t unwrapped_len = 0;
8440 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8441 struct wpabuf *B_pub = NULL;
8442 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008443
Roshan Pius3a1667e2018-07-03 15:17:14 -07008444#ifdef CONFIG_TESTING_OPTIONS
8445 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
8446 wpa_printf(MSG_INFO,
8447 "DPP: TESTING - stop at PKEX CR Request");
8448 pkex->failed = 1;
8449 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008450 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07008451#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008452
Roshan Pius3a1667e2018-07-03 15:17:14 -07008453 if (!pkex->exchange_done || pkex->failed ||
8454 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008455 goto fail;
8456
8457 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
8458 &wrapped_data_len);
8459 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008460 dpp_pkex_fail(pkex,
8461 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008462 goto fail;
8463 }
8464
8465 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8466 wrapped_data, wrapped_data_len);
8467 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
8468 unwrapped = os_malloc(unwrapped_len);
8469 if (!unwrapped)
8470 goto fail;
8471
8472 addr[0] = hdr;
8473 len[0] = DPP_HDR_LEN;
8474 octet = 0;
8475 addr[1] = &octet;
8476 len[1] = sizeof(octet);
8477 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8478 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8479
8480 if (aes_siv_decrypt(pkex->z, curve->hash_len,
8481 wrapped_data, wrapped_data_len,
8482 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008483 dpp_pkex_fail(pkex,
8484 "AES-SIV decryption failed - possible PKEX code mismatch");
8485 pkex->failed = 1;
8486 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008487 goto fail;
8488 }
8489 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
8490 unwrapped, unwrapped_len);
8491
8492 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008493 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008494 goto fail;
8495 }
8496
8497 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
8498 &b_key_len);
8499 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008500 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008501 goto fail;
8502 }
8503 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
8504 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008505 if (!pkex->peer_bootstrap_key) {
8506 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008507 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008508 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008509 dpp_debug_print_key("DPP: Peer bootstrap public key",
8510 pkex->peer_bootstrap_key);
8511
8512 /* ECDH: J' = y * A' */
Hai Shalomc3565922019-10-28 11:58:20 -07008513 if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008514 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008515
8516 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
8517 Jx, Jx_len);
8518
8519 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
8520 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
8521 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8522 X_pub = dpp_get_pubkey_point(pkex->x, 0);
8523 if (!A_pub || !Y_pub || !X_pub)
8524 goto fail;
8525 addr[0] = pkex->peer_mac;
8526 len[0] = ETH_ALEN;
8527 addr[1] = wpabuf_head(A_pub);
8528 len[1] = wpabuf_len(A_pub) / 2;
8529 addr[2] = wpabuf_head(Y_pub);
8530 len[2] = wpabuf_len(Y_pub) / 2;
8531 addr[3] = wpabuf_head(X_pub);
8532 len[3] = wpabuf_len(X_pub) / 2;
8533 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
8534 goto fail;
8535
8536 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
8537 &peer_u_len);
8538 if (!peer_u || peer_u_len != curve->hash_len ||
8539 os_memcmp(peer_u, u, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008540 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008541 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
8542 u, curve->hash_len);
8543 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008544 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008545 goto fail;
8546 }
8547 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
8548
8549 /* ECDH: L = b * X' */
Hai Shalomc3565922019-10-28 11:58:20 -07008550 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008551 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008552
8553 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
8554 Lx, Lx_len);
8555
8556 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
8557 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
8558 if (!B_pub)
8559 goto fail;
8560 addr[0] = pkex->own_mac;
8561 len[0] = ETH_ALEN;
8562 addr[1] = wpabuf_head(B_pub);
8563 len[1] = wpabuf_len(B_pub) / 2;
8564 addr[2] = wpabuf_head(X_pub);
8565 len[2] = wpabuf_len(X_pub) / 2;
8566 addr[3] = wpabuf_head(Y_pub);
8567 len[3] = wpabuf_len(Y_pub) / 2;
8568 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8569 goto fail;
8570 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
8571
Roshan Pius3a1667e2018-07-03 15:17:14 -07008572 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
8573 if (!msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008574 goto fail;
8575
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008576out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008577 os_free(unwrapped);
8578 wpabuf_free(A_pub);
8579 wpabuf_free(B_pub);
8580 wpabuf_free(X_pub);
8581 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008582 return msg;
8583fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07008584 wpa_printf(MSG_DEBUG,
8585 "DPP: PKEX Commit-Reveal Request processing failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008586 goto out;
8587}
8588
8589
8590int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
8591 const u8 *buf, size_t buflen)
8592{
8593 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8594 const u8 *wrapped_data, *b_key, *peer_v;
8595 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
8596 const u8 *addr[4];
8597 size_t len[4];
8598 u8 octet;
8599 u8 *unwrapped = NULL;
8600 size_t unwrapped_len = 0;
8601 int ret = -1;
8602 u8 v[DPP_MAX_HASH_LEN];
8603 size_t Lx_len;
8604 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008605 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8606
Roshan Pius3a1667e2018-07-03 15:17:14 -07008607#ifdef CONFIG_TESTING_OPTIONS
8608 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
8609 wpa_printf(MSG_INFO,
8610 "DPP: TESTING - stop at PKEX CR Response");
8611 pkex->failed = 1;
8612 goto fail;
8613 }
8614#endif /* CONFIG_TESTING_OPTIONS */
8615
8616 if (!pkex->exchange_done || pkex->failed ||
8617 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
8618 goto fail;
8619
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008620 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
8621 &wrapped_data_len);
8622 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008623 dpp_pkex_fail(pkex,
8624 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008625 goto fail;
8626 }
8627
8628 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8629 wrapped_data, wrapped_data_len);
8630 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
8631 unwrapped = os_malloc(unwrapped_len);
8632 if (!unwrapped)
8633 goto fail;
8634
8635 addr[0] = hdr;
8636 len[0] = DPP_HDR_LEN;
8637 octet = 1;
8638 addr[1] = &octet;
8639 len[1] = sizeof(octet);
8640 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8641 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8642
8643 if (aes_siv_decrypt(pkex->z, curve->hash_len,
8644 wrapped_data, wrapped_data_len,
8645 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008646 dpp_pkex_fail(pkex,
8647 "AES-SIV decryption failed - possible PKEX code mismatch");
8648 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008649 goto fail;
8650 }
8651 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
8652 unwrapped, unwrapped_len);
8653
8654 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008655 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008656 goto fail;
8657 }
8658
8659 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
8660 &b_key_len);
8661 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008662 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008663 goto fail;
8664 }
8665 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
8666 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008667 if (!pkex->peer_bootstrap_key) {
8668 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008669 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008670 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008671 dpp_debug_print_key("DPP: Peer bootstrap public key",
8672 pkex->peer_bootstrap_key);
8673
8674 /* ECDH: L' = x * B' */
Hai Shalomc3565922019-10-28 11:58:20 -07008675 if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008676 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008677
8678 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
8679 Lx, Lx_len);
8680
8681 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8682 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
8683 X_pub = dpp_get_pubkey_point(pkex->x, 0);
8684 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8685 if (!B_pub || !X_pub || !Y_pub)
8686 goto fail;
8687 addr[0] = pkex->peer_mac;
8688 len[0] = ETH_ALEN;
8689 addr[1] = wpabuf_head(B_pub);
8690 len[1] = wpabuf_len(B_pub) / 2;
8691 addr[2] = wpabuf_head(X_pub);
8692 len[2] = wpabuf_len(X_pub) / 2;
8693 addr[3] = wpabuf_head(Y_pub);
8694 len[3] = wpabuf_len(Y_pub) / 2;
8695 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8696 goto fail;
8697
8698 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
8699 &peer_v_len);
8700 if (!peer_v || peer_v_len != curve->hash_len ||
8701 os_memcmp(peer_v, v, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008702 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008703 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
8704 v, curve->hash_len);
8705 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008706 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008707 goto fail;
8708 }
8709 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
8710
8711 ret = 0;
8712out:
8713 wpabuf_free(B_pub);
8714 wpabuf_free(X_pub);
8715 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008716 os_free(unwrapped);
8717 return ret;
8718fail:
8719 goto out;
8720}
8721
8722
8723void dpp_pkex_free(struct dpp_pkex *pkex)
8724{
8725 if (!pkex)
8726 return;
8727
8728 os_free(pkex->identifier);
8729 os_free(pkex->code);
8730 EVP_PKEY_free(pkex->x);
8731 EVP_PKEY_free(pkex->y);
8732 EVP_PKEY_free(pkex->peer_bootstrap_key);
8733 wpabuf_free(pkex->exchange_req);
8734 wpabuf_free(pkex->exchange_resp);
8735 os_free(pkex);
8736}
Roshan Pius3a1667e2018-07-03 15:17:14 -07008737
8738
8739#ifdef CONFIG_TESTING_OPTIONS
8740char * dpp_corrupt_connector_signature(const char *connector)
8741{
8742 char *tmp, *pos, *signed3 = NULL;
8743 unsigned char *signature = NULL;
8744 size_t signature_len = 0, signed3_len;
8745
8746 tmp = os_zalloc(os_strlen(connector) + 5);
8747 if (!tmp)
8748 goto fail;
8749 os_memcpy(tmp, connector, os_strlen(connector));
8750
8751 pos = os_strchr(tmp, '.');
8752 if (!pos)
8753 goto fail;
8754
8755 pos = os_strchr(pos + 1, '.');
8756 if (!pos)
8757 goto fail;
8758 pos++;
8759
8760 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
8761 pos);
8762 signature = base64_url_decode((const unsigned char *) pos,
8763 os_strlen(pos), &signature_len);
8764 if (!signature || signature_len == 0)
8765 goto fail;
8766 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
8767 signature, signature_len);
8768 signature[signature_len - 1] ^= 0x01;
8769 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
8770 signature, signature_len);
8771 signed3 = (char *) base64_url_encode(signature, signature_len,
8772 &signed3_len, 0);
8773 if (!signed3)
8774 goto fail;
8775 os_memcpy(pos, signed3, signed3_len);
8776 pos[signed3_len] = '\0';
8777 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
8778 pos);
8779
8780out:
8781 os_free(signature);
8782 os_free(signed3);
8783 return tmp;
8784fail:
8785 os_free(tmp);
8786 tmp = NULL;
8787 goto out;
8788}
8789#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom021b0b52019-04-10 11:17:58 -07008790
8791
8792#ifdef CONFIG_DPP2
8793
8794struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
8795 size_t net_access_key_len)
8796{
8797 struct wpabuf *pub = NULL;
8798 EVP_PKEY *own_key;
8799 struct dpp_pfs *pfs;
8800
8801 pfs = os_zalloc(sizeof(*pfs));
8802 if (!pfs)
8803 return NULL;
8804
8805 own_key = dpp_set_keypair(&pfs->curve, net_access_key,
8806 net_access_key_len);
8807 if (!own_key) {
8808 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
8809 goto fail;
8810 }
8811 EVP_PKEY_free(own_key);
8812
8813 pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
8814 if (!pfs->ecdh)
8815 goto fail;
8816
8817 pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
8818 pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
8819 if (!pub)
8820 goto fail;
8821
8822 pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
8823 if (!pfs->ie)
8824 goto fail;
8825 wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
8826 wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
8827 wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
8828 wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
8829 wpabuf_put_buf(pfs->ie, pub);
8830 wpabuf_free(pub);
8831 wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
8832 pfs->ie);
8833
8834 return pfs;
8835fail:
8836 wpabuf_free(pub);
8837 dpp_pfs_free(pfs);
8838 return NULL;
8839}
8840
8841
8842int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
8843{
8844 if (peer_ie_len < 2)
8845 return -1;
8846 if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
8847 wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
8848 return -1;
8849 }
8850
8851 pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
8852 peer_ie_len - 2);
8853 pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
8854 if (!pfs->secret) {
8855 wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
8856 return -1;
8857 }
8858 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
8859 return 0;
8860}
8861
8862
8863void dpp_pfs_free(struct dpp_pfs *pfs)
8864{
8865 if (!pfs)
8866 return;
8867 crypto_ecdh_deinit(pfs->ecdh);
8868 wpabuf_free(pfs->ie);
8869 wpabuf_clear_free(pfs->secret);
8870 os_free(pfs);
8871}
8872
8873#endif /* CONFIG_DPP2 */
8874
8875
8876static unsigned int dpp_next_id(struct dpp_global *dpp)
8877{
8878 struct dpp_bootstrap_info *bi;
8879 unsigned int max_id = 0;
8880
8881 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8882 if (bi->id > max_id)
8883 max_id = bi->id;
8884 }
8885 return max_id + 1;
8886}
8887
8888
8889static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
8890{
8891 struct dpp_bootstrap_info *bi, *tmp;
8892 int found = 0;
8893
8894 if (!dpp)
8895 return -1;
8896
8897 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
8898 struct dpp_bootstrap_info, list) {
8899 if (id && bi->id != id)
8900 continue;
8901 found = 1;
8902 dl_list_del(&bi->list);
8903 dpp_bootstrap_info_free(bi);
8904 }
8905
8906 if (id == 0)
8907 return 0; /* flush succeeds regardless of entries found */
8908 return found ? 0 : -1;
8909}
8910
8911
8912struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
8913 const char *uri)
8914{
8915 struct dpp_bootstrap_info *bi;
8916
8917 if (!dpp)
8918 return NULL;
8919
8920 bi = dpp_parse_qr_code(uri);
8921 if (!bi)
8922 return NULL;
8923
8924 bi->id = dpp_next_id(dpp);
8925 dl_list_add(&dpp->bootstrap, &bi->list);
8926 return bi;
8927}
8928
8929
8930int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
8931{
8932 char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
8933 char *key = NULL;
8934 u8 *privkey = NULL;
8935 size_t privkey_len = 0;
8936 size_t len;
8937 int ret = -1;
8938 struct dpp_bootstrap_info *bi;
8939
8940 if (!dpp)
8941 return -1;
8942
8943 bi = os_zalloc(sizeof(*bi));
8944 if (!bi)
8945 goto fail;
8946
8947 if (os_strstr(cmd, "type=qrcode"))
8948 bi->type = DPP_BOOTSTRAP_QR_CODE;
8949 else if (os_strstr(cmd, "type=pkex"))
8950 bi->type = DPP_BOOTSTRAP_PKEX;
8951 else
8952 goto fail;
8953
8954 chan = get_param(cmd, " chan=");
8955 mac = get_param(cmd, " mac=");
8956 info = get_param(cmd, " info=");
8957 curve = get_param(cmd, " curve=");
8958 key = get_param(cmd, " key=");
8959
8960 if (key) {
8961 privkey_len = os_strlen(key) / 2;
8962 privkey = os_malloc(privkey_len);
8963 if (!privkey ||
8964 hexstr2bin(key, privkey, privkey_len) < 0)
8965 goto fail;
8966 }
8967
8968 pk = dpp_keygen(bi, curve, privkey, privkey_len);
8969 if (!pk)
8970 goto fail;
8971
8972 len = 4; /* "DPP:" */
8973 if (chan) {
8974 if (dpp_parse_uri_chan_list(bi, chan) < 0)
8975 goto fail;
8976 len += 3 + os_strlen(chan); /* C:...; */
8977 }
8978 if (mac) {
8979 if (dpp_parse_uri_mac(bi, mac) < 0)
8980 goto fail;
8981 len += 3 + os_strlen(mac); /* M:...; */
8982 }
8983 if (info) {
8984 if (dpp_parse_uri_info(bi, info) < 0)
8985 goto fail;
8986 len += 3 + os_strlen(info); /* I:...; */
8987 }
8988 len += 4 + os_strlen(pk);
8989 bi->uri = os_malloc(len + 1);
8990 if (!bi->uri)
8991 goto fail;
8992 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8993 chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
8994 mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
8995 info ? "I:" : "", info ? info : "", info ? ";" : "",
8996 pk);
8997 bi->id = dpp_next_id(dpp);
8998 dl_list_add(&dpp->bootstrap, &bi->list);
8999 ret = bi->id;
9000 bi = NULL;
9001fail:
9002 os_free(curve);
9003 os_free(pk);
9004 os_free(chan);
9005 os_free(mac);
9006 os_free(info);
9007 str_clear_free(key);
9008 bin_clear_free(privkey, privkey_len);
9009 dpp_bootstrap_info_free(bi);
9010 return ret;
9011}
9012
9013
9014struct dpp_bootstrap_info *
9015dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
9016{
9017 struct dpp_bootstrap_info *bi;
9018
9019 if (!dpp)
9020 return NULL;
9021
9022 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
9023 if (bi->id == id)
9024 return bi;
9025 }
9026 return NULL;
9027}
9028
9029
9030int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
9031{
9032 unsigned int id_val;
9033
9034 if (os_strcmp(id, "*") == 0) {
9035 id_val = 0;
9036 } else {
9037 id_val = atoi(id);
9038 if (id_val == 0)
9039 return -1;
9040 }
9041
9042 return dpp_bootstrap_del(dpp, id_val);
9043}
9044
9045
9046struct dpp_bootstrap_info *
9047dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
9048 unsigned int freq)
9049{
9050 struct dpp_bootstrap_info *bi;
9051
9052 bi = os_zalloc(sizeof(*bi));
9053 if (!bi)
9054 return NULL;
9055 bi->id = dpp_next_id(dpp);
9056 bi->type = DPP_BOOTSTRAP_PKEX;
9057 os_memcpy(bi->mac_addr, peer, ETH_ALEN);
9058 bi->num_freq = 1;
9059 bi->freq[0] = freq;
9060 bi->curve = pkex->own_bi->curve;
9061 bi->pubkey = pkex->peer_bootstrap_key;
9062 pkex->peer_bootstrap_key = NULL;
9063 if (dpp_bootstrap_key_hash(bi) < 0) {
9064 dpp_bootstrap_info_free(bi);
9065 return NULL;
9066 }
9067 dpp_pkex_free(pkex);
9068 dl_list_add(&dpp->bootstrap, &bi->list);
9069 return bi;
9070}
9071
9072
9073const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
9074{
9075 struct dpp_bootstrap_info *bi;
9076
9077 bi = dpp_bootstrap_get_id(dpp, id);
9078 if (!bi)
9079 return NULL;
9080 return bi->uri;
9081}
9082
9083
9084int dpp_bootstrap_info(struct dpp_global *dpp, int id,
9085 char *reply, int reply_size)
9086{
9087 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07009088 char pkhash[2 * SHA256_MAC_LEN + 1];
Hai Shalom021b0b52019-04-10 11:17:58 -07009089
9090 bi = dpp_bootstrap_get_id(dpp, id);
9091 if (!bi)
9092 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07009093 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
9094 SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -07009095 return os_snprintf(reply, reply_size, "type=%s\n"
9096 "mac_addr=" MACSTR "\n"
9097 "info=%s\n"
9098 "num_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -07009099 "curve=%s\n"
9100 "pkhash=%s\n",
Hai Shalom021b0b52019-04-10 11:17:58 -07009101 dpp_bootstrap_type_txt(bi->type),
9102 MAC2STR(bi->mac_addr),
9103 bi->info ? bi->info : "",
9104 bi->num_freq,
Hai Shalom81f62d82019-07-22 12:10:00 -07009105 bi->curve->name,
9106 pkhash);
Hai Shalom021b0b52019-04-10 11:17:58 -07009107}
9108
9109
9110void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
9111 const u8 *r_bootstrap,
9112 struct dpp_bootstrap_info **own_bi,
9113 struct dpp_bootstrap_info **peer_bi)
9114{
9115 struct dpp_bootstrap_info *bi;
9116
9117 *own_bi = NULL;
9118 *peer_bi = NULL;
9119 if (!dpp)
9120 return;
9121
9122 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
9123 if (!*own_bi && bi->own &&
9124 os_memcmp(bi->pubkey_hash, r_bootstrap,
9125 SHA256_MAC_LEN) == 0) {
9126 wpa_printf(MSG_DEBUG,
9127 "DPP: Found matching own bootstrapping information");
9128 *own_bi = bi;
9129 }
9130
9131 if (!*peer_bi && !bi->own &&
9132 os_memcmp(bi->pubkey_hash, i_bootstrap,
9133 SHA256_MAC_LEN) == 0) {
9134 wpa_printf(MSG_DEBUG,
9135 "DPP: Found matching peer bootstrapping information");
9136 *peer_bi = bi;
9137 }
9138
9139 if (*own_bi && *peer_bi)
9140 break;
9141 }
9142
9143}
9144
9145
9146static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
9147{
9148 struct dpp_configurator *conf;
9149 unsigned int max_id = 0;
9150
9151 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
9152 list) {
9153 if (conf->id > max_id)
9154 max_id = conf->id;
9155 }
9156 return max_id + 1;
9157}
9158
9159
9160int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
9161{
9162 char *curve = NULL;
9163 char *key = NULL;
9164 u8 *privkey = NULL;
9165 size_t privkey_len = 0;
9166 int ret = -1;
9167 struct dpp_configurator *conf = NULL;
9168
9169 curve = get_param(cmd, " curve=");
9170 key = get_param(cmd, " key=");
9171
9172 if (key) {
9173 privkey_len = os_strlen(key) / 2;
9174 privkey = os_malloc(privkey_len);
9175 if (!privkey ||
9176 hexstr2bin(key, privkey, privkey_len) < 0)
9177 goto fail;
9178 }
9179
9180 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
9181 if (!conf)
9182 goto fail;
9183
9184 conf->id = dpp_next_configurator_id(dpp);
9185 dl_list_add(&dpp->configurator, &conf->list);
9186 ret = conf->id;
9187 conf = NULL;
9188fail:
9189 os_free(curve);
9190 str_clear_free(key);
9191 bin_clear_free(privkey, privkey_len);
9192 dpp_configurator_free(conf);
9193 return ret;
9194}
9195
9196
9197static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
9198{
9199 struct dpp_configurator *conf, *tmp;
9200 int found = 0;
9201
9202 if (!dpp)
9203 return -1;
9204
9205 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
9206 struct dpp_configurator, list) {
9207 if (id && conf->id != id)
9208 continue;
9209 found = 1;
9210 dl_list_del(&conf->list);
9211 dpp_configurator_free(conf);
9212 }
9213
9214 if (id == 0)
9215 return 0; /* flush succeeds regardless of entries found */
9216 return found ? 0 : -1;
9217}
9218
9219
9220int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
9221{
9222 unsigned int id_val;
9223
9224 if (os_strcmp(id, "*") == 0) {
9225 id_val = 0;
9226 } else {
9227 id_val = atoi(id);
9228 if (id_val == 0)
9229 return -1;
9230 }
9231
9232 return dpp_configurator_del(dpp, id_val);
9233}
9234
9235
9236int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
9237 char *buf, size_t buflen)
9238{
9239 struct dpp_configurator *conf;
9240
9241 conf = dpp_configurator_get_id(dpp, id);
9242 if (!conf)
9243 return -1;
9244
9245 return dpp_configurator_get_key(conf, buf, buflen);
9246}
9247
9248
Hai Shalom81f62d82019-07-22 12:10:00 -07009249#ifdef CONFIG_DPP2
9250
Hai Shalomc3565922019-10-28 11:58:20 -07009251static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
9252 void *timeout_ctx);
9253
9254
Hai Shalom81f62d82019-07-22 12:10:00 -07009255static void dpp_connection_free(struct dpp_connection *conn)
9256{
9257 if (conn->sock >= 0) {
9258 wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
9259 conn->sock);
9260 eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
9261 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
9262 close(conn->sock);
9263 }
Hai Shalomc3565922019-10-28 11:58:20 -07009264 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
9265 conn, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -07009266 wpabuf_free(conn->msg);
9267 wpabuf_free(conn->msg_out);
9268 dpp_auth_deinit(conn->auth);
9269 os_free(conn);
9270}
9271
9272
9273static void dpp_connection_remove(struct dpp_connection *conn)
9274{
9275 dl_list_del(&conn->list);
9276 dpp_connection_free(conn);
9277}
9278
9279
9280static void dpp_tcp_init_flush(struct dpp_global *dpp)
9281{
9282 struct dpp_connection *conn, *tmp;
9283
9284 dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
9285 list)
9286 dpp_connection_remove(conn);
9287}
9288
9289
9290static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
9291{
9292 struct dpp_connection *conn, *tmp;
9293
9294 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
9295 list)
9296 dpp_connection_remove(conn);
9297 os_free(ctrl);
9298}
9299
9300
9301static void dpp_relay_flush_controllers(struct dpp_global *dpp)
9302{
9303 struct dpp_relay_controller *ctrl, *tmp;
9304
9305 if (!dpp)
9306 return;
9307
9308 dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
9309 struct dpp_relay_controller, list) {
9310 dl_list_del(&ctrl->list);
9311 dpp_relay_controller_free(ctrl);
9312 }
9313}
9314
9315#endif /* CONFIG_DPP2 */
9316
9317
9318struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -07009319{
9320 struct dpp_global *dpp;
9321
9322 dpp = os_zalloc(sizeof(*dpp));
9323 if (!dpp)
9324 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07009325 dpp->msg_ctx = config->msg_ctx;
9326#ifdef CONFIG_DPP2
9327 dpp->cb_ctx = config->cb_ctx;
9328 dpp->process_conf_obj = config->process_conf_obj;
9329#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07009330
9331 dl_list_init(&dpp->bootstrap);
9332 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -07009333#ifdef CONFIG_DPP2
9334 dl_list_init(&dpp->controllers);
9335 dl_list_init(&dpp->tcp_init);
9336#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07009337
9338 return dpp;
9339}
9340
9341
9342void dpp_global_clear(struct dpp_global *dpp)
9343{
9344 if (!dpp)
9345 return;
9346
9347 dpp_bootstrap_del(dpp, 0);
9348 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -07009349#ifdef CONFIG_DPP2
9350 dpp_tcp_init_flush(dpp);
9351 dpp_relay_flush_controllers(dpp);
9352 dpp_controller_stop(dpp);
9353#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07009354}
9355
9356
9357void dpp_global_deinit(struct dpp_global *dpp)
9358{
9359 dpp_global_clear(dpp);
9360 os_free(dpp);
9361}
Hai Shalom81f62d82019-07-22 12:10:00 -07009362
9363
9364#ifdef CONFIG_DPP2
9365
9366static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
9367static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
9368static void dpp_controller_auth_success(struct dpp_connection *conn,
9369 int initiator);
9370
9371
9372int dpp_relay_add_controller(struct dpp_global *dpp,
9373 struct dpp_relay_config *config)
9374{
9375 struct dpp_relay_controller *ctrl;
9376
9377 if (!dpp)
9378 return -1;
9379
9380 ctrl = os_zalloc(sizeof(*ctrl));
9381 if (!ctrl)
9382 return -1;
9383 dl_list_init(&ctrl->conn);
9384 ctrl->global = dpp;
9385 os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
9386 os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
9387 ctrl->cb_ctx = config->cb_ctx;
9388 ctrl->tx = config->tx;
9389 ctrl->gas_resp_tx = config->gas_resp_tx;
9390 dl_list_add(&dpp->controllers, &ctrl->list);
9391 return 0;
9392}
9393
9394
9395static struct dpp_relay_controller *
9396dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
9397{
9398 struct dpp_relay_controller *ctrl;
9399
9400 if (!dpp)
9401 return NULL;
9402
9403 dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
9404 list) {
9405 if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
9406 return ctrl;
9407 }
9408
9409 return NULL;
9410}
9411
9412
9413static void dpp_controller_gas_done(struct dpp_connection *conn)
9414{
9415 struct dpp_authentication *auth = conn->auth;
9416
9417 if (auth->peer_version >= 2 &&
9418 auth->conf_resp_status == DPP_STATUS_OK) {
9419 wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
9420 auth->waiting_conf_result = 1;
9421 return;
9422 }
9423
9424 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
9425 dpp_connection_remove(conn);
9426}
9427
9428
9429static int dpp_tcp_send(struct dpp_connection *conn)
9430{
9431 int res;
9432
9433 if (!conn->msg_out) {
9434 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
9435 conn->write_eloop = 0;
9436 return -1;
9437 }
9438 res = send(conn->sock,
9439 wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
9440 wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
9441 if (res < 0) {
9442 wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
9443 strerror(errno));
9444 dpp_connection_remove(conn);
9445 return -1;
9446 }
9447
9448 conn->msg_out_pos += res;
9449 if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
9450 wpa_printf(MSG_DEBUG,
9451 "DPP: %u/%u bytes of message sent to Controller",
9452 (unsigned int) conn->msg_out_pos,
9453 (unsigned int) wpabuf_len(conn->msg_out));
9454 if (!conn->write_eloop &&
9455 eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9456 dpp_conn_tx_ready, conn, NULL) == 0)
9457 conn->write_eloop = 1;
9458 return 1;
9459 }
9460
9461 wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
9462 wpabuf_free(conn->msg_out);
9463 conn->msg_out = NULL;
9464 conn->msg_out_pos = 0;
9465 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
9466 conn->write_eloop = 0;
9467 if (!conn->read_eloop &&
9468 eloop_register_sock(conn->sock, EVENT_TYPE_READ,
9469 dpp_controller_rx, conn, NULL) == 0)
9470 conn->read_eloop = 1;
9471 if (conn->on_tcp_tx_complete_remove) {
9472 dpp_connection_remove(conn);
9473 } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
9474 conn->auth) {
9475 dpp_controller_gas_done(conn);
9476 } else if (conn->on_tcp_tx_complete_auth_ok) {
9477 conn->on_tcp_tx_complete_auth_ok = 0;
9478 dpp_controller_auth_success(conn, 1);
9479 }
9480
9481 return 0;
9482}
9483
9484
9485static void dpp_controller_start_gas_client(struct dpp_connection *conn)
9486{
9487 struct dpp_authentication *auth = conn->auth;
9488 struct wpabuf *buf;
Hai Shalom81f62d82019-07-22 12:10:00 -07009489 int netrole_ap = 0; /* TODO: make this configurable */
9490
Hai Shalomc3565922019-10-28 11:58:20 -07009491 buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -07009492 if (!buf) {
9493 wpa_printf(MSG_DEBUG,
9494 "DPP: No configuration request data available");
9495 return;
9496 }
9497
9498 wpabuf_free(conn->msg_out);
9499 conn->msg_out_pos = 0;
9500 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1);
9501 if (!conn->msg_out) {
9502 wpabuf_free(buf);
9503 return;
9504 }
9505 wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
Hai Shalomc3565922019-10-28 11:58:20 -07009506 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07009507 wpabuf_len(buf) - 1);
9508 wpabuf_free(buf);
9509
9510 if (dpp_tcp_send(conn) == 1) {
9511 if (!conn->write_eloop) {
9512 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9513 dpp_conn_tx_ready,
9514 conn, NULL) < 0)
9515 return;
9516 conn->write_eloop = 1;
9517 }
9518 }
9519}
9520
9521
9522static void dpp_controller_auth_success(struct dpp_connection *conn,
9523 int initiator)
9524{
9525 struct dpp_authentication *auth = conn->auth;
9526
9527 if (!auth)
9528 return;
9529
9530 wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
9531 wpa_msg(conn->global->msg_ctx, MSG_INFO,
9532 DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
9533#ifdef CONFIG_TESTING_OPTIONS
9534 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
9535 wpa_printf(MSG_INFO,
9536 "DPP: TESTING - stop at Authentication Confirm");
9537 if (auth->configurator) {
9538 /* Prevent GAS response */
9539 auth->auth_success = 0;
9540 }
9541 return;
9542 }
9543#endif /* CONFIG_TESTING_OPTIONS */
9544
9545 if (!auth->configurator)
9546 dpp_controller_start_gas_client(conn);
9547}
9548
9549
9550static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
9551{
9552 struct dpp_connection *conn = eloop_ctx;
9553
9554 wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
9555 dpp_tcp_send(conn);
9556}
9557
9558
9559static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
9560 const struct hostapd_ip_addr *ipaddr,
9561 int port)
9562{
9563 struct sockaddr_in *dst;
9564#ifdef CONFIG_IPV6
9565 struct sockaddr_in6 *dst6;
9566#endif /* CONFIG_IPV6 */
9567
9568 switch (ipaddr->af) {
9569 case AF_INET:
9570 dst = (struct sockaddr_in *) addr;
9571 os_memset(dst, 0, sizeof(*dst));
9572 dst->sin_family = AF_INET;
9573 dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
9574 dst->sin_port = htons(port);
9575 *addrlen = sizeof(*dst);
9576 break;
9577#ifdef CONFIG_IPV6
9578 case AF_INET6:
9579 dst6 = (struct sockaddr_in6 *) addr;
9580 os_memset(dst6, 0, sizeof(*dst6));
9581 dst6->sin6_family = AF_INET6;
9582 os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
9583 sizeof(struct in6_addr));
9584 dst6->sin6_port = htons(port);
9585 *addrlen = sizeof(*dst6);
9586 break;
9587#endif /* CONFIG_IPV6 */
9588 default:
9589 return -1;
9590 }
9591
9592 return 0;
9593}
9594
9595
9596static struct dpp_connection *
9597dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
9598 unsigned int freq)
9599{
9600 struct dpp_connection *conn;
9601 struct sockaddr_storage addr;
9602 socklen_t addrlen;
9603 char txt[100];
9604
9605 if (dl_list_len(&ctrl->conn) >= 15) {
9606 wpa_printf(MSG_DEBUG,
9607 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
9608 return NULL;
9609 }
9610
9611 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
9612 &ctrl->ipaddr, DPP_TCP_PORT) < 0)
9613 return NULL;
9614
9615 conn = os_zalloc(sizeof(*conn));
9616 if (!conn)
9617 return NULL;
9618
9619 conn->global = ctrl->global;
9620 conn->relay = ctrl;
9621 os_memcpy(conn->mac_addr, src, ETH_ALEN);
9622 conn->freq = freq;
9623
9624 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
9625 if (conn->sock < 0)
9626 goto fail;
9627 wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
9628 conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
9629
9630 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
9631 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
9632 strerror(errno));
9633 goto fail;
9634 }
9635
9636 if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
9637 if (errno != EINPROGRESS) {
9638 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
9639 strerror(errno));
9640 goto fail;
9641 }
9642
9643 /*
9644 * Continue connecting in the background; eloop will call us
9645 * once the connection is ready (or failed).
9646 */
9647 }
9648
9649 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9650 dpp_conn_tx_ready, conn, NULL) < 0)
9651 goto fail;
9652 conn->write_eloop = 1;
9653
9654 /* TODO: eloop timeout to clear a connection if it does not complete
9655 * properly */
9656
9657 dl_list_add(&ctrl->conn, &conn->list);
9658 return conn;
9659fail:
9660 dpp_connection_free(conn);
9661 return NULL;
9662}
9663
9664
9665static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
9666{
9667 struct wpabuf *msg;
9668
9669 msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
9670 if (!msg)
9671 return NULL;
9672 wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
9673 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
9674 wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
9675 wpabuf_put_data(msg, buf, len);
9676 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
9677 return msg;
9678}
9679
9680
9681static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
9682 const u8 *buf, size_t len)
9683{
9684 u8 type = hdr[DPP_HDR_LEN - 1];
9685
9686 wpa_printf(MSG_DEBUG,
9687 "DPP: Continue already established Relay/Controller connection for this session");
9688 wpabuf_free(conn->msg_out);
9689 conn->msg_out_pos = 0;
9690 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
9691 if (!conn->msg_out) {
9692 dpp_connection_remove(conn);
9693 return -1;
9694 }
9695
9696 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
9697 * TX status */
9698 if (type == DPP_PA_CONFIGURATION_RESULT)
9699 conn->on_tcp_tx_complete_remove = 1;
9700 dpp_tcp_send(conn);
9701 return 0;
9702}
9703
9704
9705int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
9706 const u8 *buf, size_t len, unsigned int freq,
9707 const u8 *i_bootstrap, const u8 *r_bootstrap)
9708{
9709 struct dpp_relay_controller *ctrl;
9710 struct dpp_connection *conn;
9711 u8 type = hdr[DPP_HDR_LEN - 1];
9712
9713 /* Check if there is an already started session for this peer and if so,
9714 * continue that session (send this over TCP) and return 0.
9715 */
9716 if (type != DPP_PA_PEER_DISCOVERY_REQ &&
9717 type != DPP_PA_PEER_DISCOVERY_RESP) {
9718 dl_list_for_each(ctrl, &dpp->controllers,
9719 struct dpp_relay_controller, list) {
9720 dl_list_for_each(conn, &ctrl->conn,
9721 struct dpp_connection, list) {
9722 if (os_memcmp(src, conn->mac_addr,
9723 ETH_ALEN) == 0)
9724 return dpp_relay_tx(conn, hdr, buf, len);
9725 }
9726 }
9727 }
9728
9729 if (!r_bootstrap)
9730 return -1;
9731
9732 ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
9733 if (!ctrl)
9734 return -1;
9735
9736 wpa_printf(MSG_DEBUG,
9737 "DPP: Authentication Request for a configured Controller");
9738 conn = dpp_relay_new_conn(ctrl, src, freq);
9739 if (!conn)
9740 return -1;
9741
9742 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
9743 if (!conn->msg_out) {
9744 dpp_connection_remove(conn);
9745 return -1;
9746 }
9747 /* Message will be sent in dpp_conn_tx_ready() */
9748
9749 return 0;
9750}
9751
9752
9753int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
9754 size_t data_len)
9755{
9756 struct dpp_relay_controller *ctrl;
9757 struct dpp_connection *conn, *found = NULL;
9758 struct wpabuf *msg;
9759
9760 /* Check if there is a successfully completed authentication for this
9761 * and if so, continue that session (send this over TCP) and return 0.
9762 */
9763 dl_list_for_each(ctrl, &dpp->controllers,
9764 struct dpp_relay_controller, list) {
9765 if (found)
9766 break;
9767 dl_list_for_each(conn, &ctrl->conn,
9768 struct dpp_connection, list) {
9769 if (os_memcmp(src, conn->mac_addr,
9770 ETH_ALEN) == 0) {
9771 found = conn;
9772 break;
9773 }
9774 }
9775 }
9776
9777 if (!found)
9778 return -1;
9779
9780 msg = wpabuf_alloc(4 + 1 + data_len);
9781 if (!msg)
9782 return -1;
9783 wpabuf_put_be32(msg, 1 + data_len);
9784 wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
9785 wpabuf_put_data(msg, data, data_len);
9786 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
9787
9788 wpabuf_free(conn->msg_out);
9789 conn->msg_out_pos = 0;
9790 conn->msg_out = msg;
9791 dpp_tcp_send(conn);
9792 return 0;
9793}
9794
9795
9796static void dpp_controller_free(struct dpp_controller *ctrl)
9797{
9798 struct dpp_connection *conn, *tmp;
9799
9800 if (!ctrl)
9801 return;
9802
9803 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
9804 list)
9805 dpp_connection_remove(conn);
9806
9807 if (ctrl->sock >= 0) {
9808 close(ctrl->sock);
9809 eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
9810 }
9811 os_free(ctrl->configurator_params);
9812 os_free(ctrl);
9813}
9814
9815
9816static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
9817 const u8 *hdr, const u8 *buf, size_t len)
9818{
9819 const u8 *r_bootstrap, *i_bootstrap;
9820 u16 r_bootstrap_len, i_bootstrap_len;
9821 struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
9822
9823 if (!conn->ctrl)
9824 return 0;
9825
9826 wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
9827
9828 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
9829 &r_bootstrap_len);
9830 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
9831 wpa_printf(MSG_INFO,
9832 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
9833 return -1;
9834 }
9835 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
9836 r_bootstrap, r_bootstrap_len);
9837
9838 i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
9839 &i_bootstrap_len);
9840 if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
9841 wpa_printf(MSG_INFO,
9842 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
9843 return -1;
9844 }
9845 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
9846 i_bootstrap, i_bootstrap_len);
9847
9848 /* Try to find own and peer bootstrapping key matches based on the
9849 * received hash values */
9850 dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
9851 &own_bi, &peer_bi);
9852 if (!own_bi) {
9853 wpa_printf(MSG_INFO,
9854 "No matching own bootstrapping key found - ignore message");
9855 return -1;
9856 }
9857
9858 if (conn->auth) {
9859 wpa_printf(MSG_INFO,
9860 "Already in DPP authentication exchange - ignore new one");
9861 return 0;
9862 }
9863
9864 conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx,
9865 conn->ctrl->allowed_roles,
9866 conn->ctrl->qr_mutual,
9867 peer_bi, own_bi, -1, hdr, buf, len);
9868 if (!conn->auth) {
9869 wpa_printf(MSG_DEBUG, "DPP: No response generated");
9870 return -1;
9871 }
9872
9873 if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx,
9874 conn->auth,
9875 conn->ctrl->configurator_params) < 0) {
9876 dpp_connection_remove(conn);
9877 return -1;
9878 }
9879
9880 wpabuf_free(conn->msg_out);
9881 conn->msg_out_pos = 0;
9882 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1);
9883 if (!conn->msg_out)
9884 return -1;
9885 wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
Hai Shalomc3565922019-10-28 11:58:20 -07009886 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07009887 wpabuf_len(conn->auth->resp_msg) - 1);
9888
9889 if (dpp_tcp_send(conn) == 1) {
9890 if (!conn->write_eloop) {
9891 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9892 dpp_conn_tx_ready,
9893 conn, NULL) < 0)
9894 return -1;
9895 conn->write_eloop = 1;
9896 }
9897 }
9898
9899 return 0;
9900}
9901
9902
9903static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
9904 const u8 *hdr, const u8 *buf, size_t len)
9905{
9906 struct dpp_authentication *auth = conn->auth;
9907 struct wpabuf *msg;
9908
9909 if (!auth)
9910 return -1;
9911
9912 wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
9913
9914 msg = dpp_auth_resp_rx(auth, hdr, buf, len);
9915 if (!msg) {
9916 if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
9917 wpa_printf(MSG_DEBUG,
9918 "DPP: Start wait for full response");
9919 return -1;
9920 }
9921 wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
9922 dpp_connection_remove(conn);
9923 return -1;
9924 }
9925
9926 wpabuf_free(conn->msg_out);
9927 conn->msg_out_pos = 0;
9928 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
9929 if (!conn->msg_out) {
9930 wpabuf_free(msg);
9931 return -1;
9932 }
9933 wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
Hai Shalomc3565922019-10-28 11:58:20 -07009934 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07009935 wpabuf_len(msg) - 1);
9936 wpabuf_free(msg);
9937
9938 conn->on_tcp_tx_complete_auth_ok = 1;
9939 if (dpp_tcp_send(conn) == 1) {
9940 if (!conn->write_eloop) {
9941 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9942 dpp_conn_tx_ready,
9943 conn, NULL) < 0)
9944 return -1;
9945 conn->write_eloop = 1;
9946 }
9947 }
9948
9949 return 0;
9950}
9951
9952
9953static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
9954 const u8 *hdr, const u8 *buf, size_t len)
9955{
9956 struct dpp_authentication *auth = conn->auth;
9957
9958 wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
9959
9960 if (!auth) {
9961 wpa_printf(MSG_DEBUG,
9962 "DPP: No DPP Authentication in progress - drop");
9963 return -1;
9964 }
9965
9966 if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
9967 wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
9968 return -1;
9969 }
9970
9971 dpp_controller_auth_success(conn, 0);
9972 return 0;
9973}
9974
9975
Hai Shalomc3565922019-10-28 11:58:20 -07009976static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
9977 void *timeout_ctx)
9978{
9979 struct dpp_connection *conn = eloop_ctx;
9980
9981 if (!conn->auth->waiting_conf_result)
9982 return;
9983
9984 wpa_printf(MSG_DEBUG,
9985 "DPP: Timeout while waiting for Connection Status Result");
9986 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
9987 DPP_EVENT_CONN_STATUS_RESULT "timeout");
9988 dpp_connection_remove(conn);
9989}
9990
9991
Hai Shalom81f62d82019-07-22 12:10:00 -07009992static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
9993 const u8 *hdr, const u8 *buf,
9994 size_t len)
9995{
9996 struct dpp_authentication *auth = conn->auth;
9997 enum dpp_status_error status;
9998
9999 if (!conn->ctrl)
10000 return 0;
10001
10002 wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
10003
10004 if (!auth || !auth->waiting_conf_result) {
10005 wpa_printf(MSG_DEBUG,
10006 "DPP: No DPP Configuration waiting for result - drop");
10007 return -1;
10008 }
10009
10010 status = dpp_conf_result_rx(auth, hdr, buf, len);
Hai Shalomc3565922019-10-28 11:58:20 -070010011 if (status == DPP_STATUS_OK && auth->send_conn_status) {
10012 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10013 DPP_EVENT_CONF_SENT "wait_conn_status=1");
10014 wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
10015 eloop_cancel_timeout(
10016 dpp_controller_conn_status_result_wait_timeout,
10017 conn, NULL);
10018 eloop_register_timeout(
10019 16, 0, dpp_controller_conn_status_result_wait_timeout,
10020 conn, NULL);
10021 return 0;
10022 }
Hai Shalom81f62d82019-07-22 12:10:00 -070010023 if (status == DPP_STATUS_OK)
10024 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10025 DPP_EVENT_CONF_SENT);
10026 else
10027 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10028 DPP_EVENT_CONF_FAILED);
10029 return -1; /* to remove the completed connection */
10030}
10031
10032
Hai Shalomc3565922019-10-28 11:58:20 -070010033static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
10034 const u8 *hdr, const u8 *buf,
10035 size_t len)
10036{
10037 struct dpp_authentication *auth = conn->auth;
10038 enum dpp_status_error status;
10039 u8 ssid[SSID_MAX_LEN];
10040 size_t ssid_len = 0;
10041 char *channel_list = NULL;
10042
10043 if (!conn->ctrl)
10044 return 0;
10045
10046 wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
10047
10048 if (!auth || !auth->waiting_conn_status_result) {
10049 wpa_printf(MSG_DEBUG,
10050 "DPP: No DPP Configuration waiting for connection status result - drop");
10051 return -1;
10052 }
10053
10054 status = dpp_conn_status_result_rx(auth, hdr, buf, len,
10055 ssid, &ssid_len, &channel_list);
10056 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
10057 DPP_EVENT_CONN_STATUS_RESULT
10058 "result=%d ssid=%s channel_list=%s",
10059 status, wpa_ssid_txt(ssid, ssid_len),
10060 channel_list ? channel_list : "N/A");
10061 os_free(channel_list);
10062 return -1; /* to remove the completed connection */
10063}
10064
10065
Hai Shalom81f62d82019-07-22 12:10:00 -070010066static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
10067 size_t len)
10068{
10069 const u8 *pos, *end;
10070 u8 type;
10071
10072 wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
10073 pos = msg;
10074 end = msg + len;
10075
10076 if (end - pos < DPP_HDR_LEN ||
10077 WPA_GET_BE24(pos) != OUI_WFA ||
10078 pos[3] != DPP_OUI_TYPE) {
10079 wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
10080 return -1;
10081 }
10082
10083 if (pos[4] != 1) {
10084 wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
10085 pos[4]);
10086 return -1;
10087 }
10088 type = pos[5];
10089 wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
10090 pos += DPP_HDR_LEN;
10091
10092 wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
10093 pos, end - pos);
10094 if (dpp_check_attrs(pos, end - pos) < 0)
10095 return -1;
10096
10097 if (conn->relay) {
10098 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
10099 conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
10100 conn->freq, msg, len);
10101 return 0;
10102 }
10103
10104 switch (type) {
10105 case DPP_PA_AUTHENTICATION_REQ:
10106 return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
10107 case DPP_PA_AUTHENTICATION_RESP:
10108 return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
10109 case DPP_PA_AUTHENTICATION_CONF:
10110 return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
10111 case DPP_PA_CONFIGURATION_RESULT:
10112 return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
Hai Shalomc3565922019-10-28 11:58:20 -070010113 case DPP_PA_CONNECTION_STATUS_RESULT:
10114 return dpp_controller_rx_conn_status_result(conn, msg, pos,
10115 end - pos);
Hai Shalom81f62d82019-07-22 12:10:00 -070010116 default:
10117 /* TODO: missing messages types */
10118 wpa_printf(MSG_DEBUG,
10119 "DPP: Unsupported frame subtype %d", type);
10120 return -1;
10121 }
10122}
10123
10124
10125static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
10126 size_t len)
10127{
10128 const u8 *pos, *end, *next;
10129 u8 dialog_token;
10130 const u8 *adv_proto;
10131 u16 slen;
10132 struct wpabuf *resp, *buf;
10133 struct dpp_authentication *auth = conn->auth;
10134
10135 if (len < 1 + 2)
10136 return -1;
10137
10138 wpa_printf(MSG_DEBUG,
10139 "DPP: Received DPP Configuration Request over TCP");
10140
10141 if (!conn->ctrl || !auth || !auth->auth_success) {
10142 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
10143 return -1;
10144 }
10145
10146 pos = msg;
10147 end = msg + len;
10148
10149 dialog_token = *pos++;
10150 adv_proto = pos++;
10151 slen = *pos++;
10152 if (*adv_proto != WLAN_EID_ADV_PROTO ||
10153 slen > end - pos || slen < 2)
10154 return -1;
10155
10156 next = pos + slen;
10157 pos++; /* skip QueryRespLenLimit and PAME-BI */
10158
10159 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
10160 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
10161 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
10162 return -1;
10163
10164 pos = next;
10165 /* Query Request */
10166 if (end - pos < 2)
10167 return -1;
10168 slen = WPA_GET_LE16(pos);
10169 pos += 2;
10170 if (slen > end - pos)
10171 return -1;
10172
10173 resp = dpp_conf_req_rx(auth, pos, slen);
10174 if (!resp)
10175 return -1;
10176
10177 buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
10178 if (!buf) {
10179 wpabuf_free(resp);
10180 return -1;
10181 }
10182
10183 wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
10184
10185 wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
10186 wpabuf_put_u8(buf, dialog_token);
10187 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
10188 wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
10189
10190 dpp_write_adv_proto(buf);
10191 dpp_write_gas_query(buf, resp);
10192 wpabuf_free(resp);
10193
10194 /* Send Config Response over TCP; GAS fragmentation is taken care of by
10195 * the Relay */
10196 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
10197 wpabuf_free(conn->msg_out);
10198 conn->msg_out_pos = 0;
10199 conn->msg_out = buf;
10200 conn->on_tcp_tx_complete_gas_done = 1;
10201 dpp_tcp_send(conn);
10202 return 0;
10203}
10204
10205
10206static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
10207{
10208 struct dpp_authentication *auth = conn->auth;
10209 int res;
10210 struct wpabuf *msg, *encaps;
10211 enum dpp_status_error status;
10212
10213 wpa_printf(MSG_DEBUG,
10214 "DPP: Configuration Response for local stack from TCP");
10215
10216 res = dpp_conf_resp_rx(auth, resp);
10217 wpabuf_free(resp);
10218 if (res < 0) {
10219 wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
10220 return -1;
10221 }
10222
10223 if (conn->global->process_conf_obj)
10224 res = conn->global->process_conf_obj(conn->global->cb_ctx,
10225 auth);
10226 else
10227 res = 0;
10228
10229 if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
10230 return -1;
10231
Hai Shalomc3565922019-10-28 11:58:20 -070010232#ifdef CONFIG_DPP2
Hai Shalom81f62d82019-07-22 12:10:00 -070010233 wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
10234 status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
10235 msg = dpp_build_conf_result(auth, status);
10236 if (!msg)
10237 return -1;
10238
10239 encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
10240 if (!encaps) {
10241 wpabuf_free(msg);
10242 return -1;
10243 }
10244 wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
Hai Shalomc3565922019-10-28 11:58:20 -070010245 wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
Hai Shalom81f62d82019-07-22 12:10:00 -070010246 wpabuf_free(msg);
10247 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
10248
10249 wpabuf_free(conn->msg_out);
10250 conn->msg_out_pos = 0;
10251 conn->msg_out = encaps;
10252 conn->on_tcp_tx_complete_remove = 1;
10253 dpp_tcp_send(conn);
10254
10255 /* This exchange will be terminated in the TX status handler */
10256
10257 return 0;
Hai Shalomc3565922019-10-28 11:58:20 -070010258#else /* CONFIG_DPP2 */
10259 return -1;
10260#endif /* CONFIG_DPP2 */
Hai Shalom81f62d82019-07-22 12:10:00 -070010261}
10262
10263
10264static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
10265 size_t len)
10266{
10267 struct wpabuf *buf;
10268 u8 dialog_token;
10269 const u8 *pos, *end, *next, *adv_proto;
10270 u16 status, slen;
10271
10272 if (len < 5 + 2)
10273 return -1;
10274
10275 wpa_printf(MSG_DEBUG,
10276 "DPP: Received DPP Configuration Response over TCP");
10277
10278 pos = msg;
10279 end = msg + len;
10280
10281 dialog_token = *pos++;
10282 status = WPA_GET_LE16(pos);
10283 if (status != WLAN_STATUS_SUCCESS) {
10284 wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
10285 return -1;
10286 }
10287 pos += 2;
10288 pos += 2; /* ignore GAS Comeback Delay */
10289
10290 adv_proto = pos++;
10291 slen = *pos++;
10292 if (*adv_proto != WLAN_EID_ADV_PROTO ||
10293 slen > end - pos || slen < 2)
10294 return -1;
10295
10296 next = pos + slen;
10297 pos++; /* skip QueryRespLenLimit and PAME-BI */
10298
10299 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
10300 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
10301 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
10302 return -1;
10303
10304 pos = next;
10305 /* Query Response */
10306 if (end - pos < 2)
10307 return -1;
10308 slen = WPA_GET_LE16(pos);
10309 pos += 2;
10310 if (slen > end - pos)
10311 return -1;
10312
10313 buf = wpabuf_alloc(slen);
10314 if (!buf)
10315 return -1;
10316 wpabuf_put_data(buf, pos, slen);
10317
10318 if (!conn->relay && !conn->ctrl)
10319 return dpp_tcp_rx_gas_resp(conn, buf);
10320
10321 if (!conn->relay) {
10322 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
10323 wpabuf_free(buf);
10324 return -1;
10325 }
10326 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
10327 conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
10328 dialog_token, 0, buf);
10329
10330 return 0;
10331}
10332
10333
10334static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
10335{
10336 struct dpp_connection *conn = eloop_ctx;
10337 int res;
10338 const u8 *pos;
10339
10340 wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
10341 sd);
10342
10343 if (conn->msg_len_octets < 4) {
10344 u32 msglen;
10345
10346 res = recv(sd, &conn->msg_len[conn->msg_len_octets],
10347 4 - conn->msg_len_octets, 0);
10348 if (res < 0) {
10349 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
10350 strerror(errno));
10351 dpp_connection_remove(conn);
10352 return;
10353 }
10354 if (res == 0) {
10355 wpa_printf(MSG_DEBUG,
10356 "DPP: No more data available over TCP");
10357 dpp_connection_remove(conn);
10358 return;
10359 }
10360 wpa_printf(MSG_DEBUG,
10361 "DPP: Received %d/%d octet(s) of message length field",
10362 res, (int) (4 - conn->msg_len_octets));
10363 conn->msg_len_octets += res;
10364
10365 if (conn->msg_len_octets < 4) {
10366 wpa_printf(MSG_DEBUG,
10367 "DPP: Need %d more octets of message length field",
10368 (int) (4 - conn->msg_len_octets));
10369 return;
10370 }
10371
10372 msglen = WPA_GET_BE32(conn->msg_len);
10373 wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
10374 if (msglen > 65535) {
10375 wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
10376 dpp_connection_remove(conn);
10377 return;
10378 }
10379
10380 wpabuf_free(conn->msg);
10381 conn->msg = wpabuf_alloc(msglen);
10382 }
10383
10384 if (!conn->msg) {
10385 wpa_printf(MSG_DEBUG,
10386 "DPP: No buffer available for receiving the message");
10387 dpp_connection_remove(conn);
10388 return;
10389 }
10390
10391 wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
10392 (unsigned int) wpabuf_tailroom(conn->msg));
10393
10394 res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
10395 if (res < 0) {
10396 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
10397 dpp_connection_remove(conn);
10398 return;
10399 }
10400 if (res == 0) {
10401 wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
10402 dpp_connection_remove(conn);
10403 return;
10404 }
10405 wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
10406 wpabuf_put(conn->msg, res);
10407
10408 if (wpabuf_tailroom(conn->msg) > 0) {
10409 wpa_printf(MSG_DEBUG,
10410 "DPP: Need %u more octets of message payload",
10411 (unsigned int) wpabuf_tailroom(conn->msg));
10412 return;
10413 }
10414
10415 conn->msg_len_octets = 0;
10416 wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
10417 if (wpabuf_len(conn->msg) < 1) {
10418 dpp_connection_remove(conn);
10419 return;
10420 }
10421
10422 pos = wpabuf_head(conn->msg);
10423 switch (*pos) {
10424 case WLAN_PA_VENDOR_SPECIFIC:
10425 if (dpp_controller_rx_action(conn, pos + 1,
10426 wpabuf_len(conn->msg) - 1) < 0)
10427 dpp_connection_remove(conn);
10428 break;
10429 case WLAN_PA_GAS_INITIAL_REQ:
10430 if (dpp_controller_rx_gas_req(conn, pos + 1,
10431 wpabuf_len(conn->msg) - 1) < 0)
10432 dpp_connection_remove(conn);
10433 break;
10434 case WLAN_PA_GAS_INITIAL_RESP:
10435 if (dpp_rx_gas_resp(conn, pos + 1,
10436 wpabuf_len(conn->msg) - 1) < 0)
10437 dpp_connection_remove(conn);
10438 break;
10439 default:
10440 wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
10441 *pos);
10442 break;
10443 }
10444}
10445
10446
10447static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
10448{
10449 struct dpp_controller *ctrl = eloop_ctx;
10450 struct sockaddr_in addr;
10451 socklen_t addr_len = sizeof(addr);
10452 int fd;
10453 struct dpp_connection *conn;
10454
10455 wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
10456
10457 fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
10458 if (fd < 0) {
10459 wpa_printf(MSG_DEBUG,
10460 "DPP: Failed to accept new connection: %s",
10461 strerror(errno));
10462 return;
10463 }
10464 wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
10465 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
10466
10467 conn = os_zalloc(sizeof(*conn));
10468 if (!conn)
10469 goto fail;
10470
10471 conn->global = ctrl->global;
10472 conn->ctrl = ctrl;
10473 conn->sock = fd;
10474
10475 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
10476 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
10477 strerror(errno));
10478 goto fail;
10479 }
10480
10481 if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
10482 dpp_controller_rx, conn, NULL) < 0)
10483 goto fail;
10484 conn->read_eloop = 1;
10485
10486 /* TODO: eloop timeout to expire connections that do not complete in
10487 * reasonable time */
10488 dl_list_add(&ctrl->conn, &conn->list);
10489 return;
10490
10491fail:
10492 close(fd);
10493 os_free(conn);
10494}
10495
10496
10497int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
10498 const struct hostapd_ip_addr *addr, int port)
10499{
10500 struct dpp_connection *conn;
10501 struct sockaddr_storage saddr;
10502 socklen_t addrlen;
10503 const u8 *hdr, *pos, *end;
10504 char txt[100];
10505
10506 wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
10507 hostapd_ip_txt(addr, txt, sizeof(txt)), port);
10508 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
10509 addr, port) < 0) {
10510 dpp_auth_deinit(auth);
10511 return -1;
10512 }
10513
10514 conn = os_zalloc(sizeof(*conn));
10515 if (!conn) {
10516 dpp_auth_deinit(auth);
10517 return -1;
10518 }
10519
10520 conn->global = dpp;
10521 conn->auth = auth;
10522 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
10523 if (conn->sock < 0)
10524 goto fail;
10525
10526 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
10527 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
10528 strerror(errno));
10529 goto fail;
10530 }
10531
10532 if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
10533 if (errno != EINPROGRESS) {
10534 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
10535 strerror(errno));
10536 goto fail;
10537 }
10538
10539 /*
10540 * Continue connecting in the background; eloop will call us
10541 * once the connection is ready (or failed).
10542 */
10543 }
10544
10545 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
10546 dpp_conn_tx_ready, conn, NULL) < 0)
10547 goto fail;
10548 conn->write_eloop = 1;
10549
10550 hdr = wpabuf_head(auth->req_msg);
10551 end = hdr + wpabuf_len(auth->req_msg);
10552 hdr += 2; /* skip Category and Actiom */
10553 pos = hdr + DPP_HDR_LEN;
10554 conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
10555 if (!conn->msg_out)
10556 goto fail;
10557 /* Message will be sent in dpp_conn_tx_ready() */
10558
10559 /* TODO: eloop timeout to clear a connection if it does not complete
10560 * properly */
10561 dl_list_add(&dpp->tcp_init, &conn->list);
10562 return 0;
10563fail:
10564 dpp_connection_free(conn);
10565 return -1;
10566}
10567
10568
10569int dpp_controller_start(struct dpp_global *dpp,
10570 struct dpp_controller_config *config)
10571{
10572 struct dpp_controller *ctrl;
10573 int on = 1;
10574 struct sockaddr_in sin;
10575 int port;
10576
10577 if (!dpp || dpp->controller)
10578 return -1;
10579
10580 ctrl = os_zalloc(sizeof(*ctrl));
10581 if (!ctrl)
10582 return -1;
10583 ctrl->global = dpp;
10584 if (config->configurator_params)
10585 ctrl->configurator_params =
10586 os_strdup(config->configurator_params);
10587 dl_list_init(&ctrl->conn);
10588 /* TODO: configure these somehow */
10589 ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
10590 ctrl->qr_mutual = 0;
10591
10592 ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
10593 if (ctrl->sock < 0)
10594 goto fail;
10595
10596 if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
10597 &on, sizeof(on)) < 0) {
10598 wpa_printf(MSG_DEBUG,
10599 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
10600 strerror(errno));
10601 /* try to continue anyway */
10602 }
10603
10604 if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
10605 wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
10606 strerror(errno));
10607 goto fail;
10608 }
10609
10610 /* TODO: IPv6 */
10611 os_memset(&sin, 0, sizeof(sin));
10612 sin.sin_family = AF_INET;
10613 sin.sin_addr.s_addr = INADDR_ANY;
10614 port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
10615 sin.sin_port = htons(port);
10616 if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
10617 wpa_printf(MSG_INFO,
10618 "DPP: Failed to bind Controller TCP port: %s",
10619 strerror(errno));
10620 goto fail;
10621 }
10622 if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
10623 fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
10624 eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
10625 dpp_controller_tcp_cb, ctrl, NULL))
10626 goto fail;
10627
10628 dpp->controller = ctrl;
10629 wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
10630 return 0;
10631fail:
10632 dpp_controller_free(ctrl);
10633 return -1;
10634}
10635
10636
10637void dpp_controller_stop(struct dpp_global *dpp)
10638{
10639 if (dpp) {
10640 dpp_controller_free(dpp->controller);
10641 dpp->controller = NULL;
10642 }
10643}
10644
10645#endif /* CONFIG_DPP2 */