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