blob: d8690ad577b8c736e8d151fb53849112f541f9b1 [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 Shalomfdcde762020-04-02 11:19:20 -07004 * Copyright (c) 2018-2020, 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"
Hai Shalomfdcde762020-04-02 11:19:20 -070032#include "tls/asn1.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070033#include "drivers/driver.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070034#include "dpp.h"
35
36
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080037static const char * dpp_netrole_str(enum dpp_netrole netrole);
38
Roshan Pius3a1667e2018-07-03 15:17:14 -070039#ifdef CONFIG_TESTING_OPTIONS
40enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
41u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
42u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
43u8 dpp_pkex_ephemeral_key_override[600];
44size_t dpp_pkex_ephemeral_key_override_len = 0;
45u8 dpp_protocol_key_override[600];
46size_t dpp_protocol_key_override_len = 0;
47u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
48size_t dpp_nonce_override_len = 0;
49
50static int dpp_test_gen_invalid_key(struct wpabuf *msg,
51 const struct dpp_curve_params *curve);
52#endif /* CONFIG_TESTING_OPTIONS */
53
54#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
55 (defined(LIBRESSL_VERSION_NUMBER) && \
56 LIBRESSL_VERSION_NUMBER < 0x20700000L)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070057/* Compatibility wrappers for older versions. */
58
59static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
60{
61 sig->r = r;
62 sig->s = s;
63 return 1;
64}
65
66
67static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
68 const BIGNUM **ps)
69{
70 if (pr)
71 *pr = sig->r;
72 if (ps)
73 *ps = sig->s;
74}
75
Hai Shalomfdcde762020-04-02 11:19:20 -070076
77static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
78{
79 if (pkey->type != EVP_PKEY_EC)
80 return NULL;
81 return pkey->pkey.ec;
82}
83
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070084#endif
85
86
Hai Shalom81f62d82019-07-22 12:10:00 -070087struct dpp_connection {
88 struct dl_list list;
89 struct dpp_controller *ctrl;
90 struct dpp_relay_controller *relay;
91 struct dpp_global *global;
92 struct dpp_authentication *auth;
93 int sock;
94 u8 mac_addr[ETH_ALEN];
95 unsigned int freq;
96 u8 msg_len[4];
97 size_t msg_len_octets;
98 struct wpabuf *msg;
99 struct wpabuf *msg_out;
100 size_t msg_out_pos;
101 unsigned int read_eloop:1;
102 unsigned int write_eloop:1;
103 unsigned int on_tcp_tx_complete_gas_done:1;
104 unsigned int on_tcp_tx_complete_remove:1;
105 unsigned int on_tcp_tx_complete_auth_ok:1;
106};
107
108/* Remote Controller */
109struct dpp_relay_controller {
110 struct dl_list list;
111 struct dpp_global *global;
112 u8 pkhash[SHA256_MAC_LEN];
113 struct hostapd_ip_addr ipaddr;
114 void *cb_ctx;
115 void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
116 size_t len);
117 void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
118 int prot, struct wpabuf *buf);
119 struct dl_list conn; /* struct dpp_connection */
120};
121
122/* Local Controller */
123struct dpp_controller {
124 struct dpp_global *global;
125 u8 allowed_roles;
126 int qr_mutual;
127 int sock;
128 struct dl_list conn; /* struct dpp_connection */
129 char *configurator_params;
130};
131
Hai Shalom021b0b52019-04-10 11:17:58 -0700132struct dpp_global {
Hai Shalom81f62d82019-07-22 12:10:00 -0700133 void *msg_ctx;
Hai Shalom021b0b52019-04-10 11:17:58 -0700134 struct dl_list bootstrap; /* struct dpp_bootstrap_info */
135 struct dl_list configurator; /* struct dpp_configurator */
Hai Shalom81f62d82019-07-22 12:10:00 -0700136#ifdef CONFIG_DPP2
137 struct dl_list controllers; /* struct dpp_relay_controller */
138 struct dpp_controller *controller;
139 struct dl_list tcp_init; /* struct dpp_connection */
140 void *cb_ctx;
141 int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
Hai Shalomfdcde762020-04-02 11:19:20 -0700142 void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
Hai Shalom81f62d82019-07-22 12:10:00 -0700143#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -0700144};
145
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700146static const struct dpp_curve_params dpp_curves[] = {
147 /* The mandatory to support and the default NIST P-256 curve needs to
148 * be the first entry on this list. */
149 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
150 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
151 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
152 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
153 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
154 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
155 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
156};
157
158
159/* Role-specific elements for PKEX */
160
161/* NIST P-256 */
162static const u8 pkex_init_x_p256[32] = {
163 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
164 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
165 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
166 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
167 };
168static const u8 pkex_init_y_p256[32] = {
169 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
170 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
171 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
172 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
173 };
174static const u8 pkex_resp_x_p256[32] = {
175 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
176 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
177 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
178 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
179};
180static const u8 pkex_resp_y_p256[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700181 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
182 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
183 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
184 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700185};
186
187/* NIST P-384 */
188static const u8 pkex_init_x_p384[48] = {
189 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
190 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
191 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
192 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
193 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
194 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
195};
196static const u8 pkex_init_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700197 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
198 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
199 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
200 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
201 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
202 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700203};
204static const u8 pkex_resp_x_p384[48] = {
205 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
206 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
207 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
208 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
209 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
210 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
211};
212static const u8 pkex_resp_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700213 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
214 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
215 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
216 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
217 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
218 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700219};
220
221/* NIST P-521 */
222static const u8 pkex_init_x_p521[66] = {
223 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
224 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
225 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
226 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
227 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
228 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
229 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
230 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
231 0x97, 0x76
232};
233static const u8 pkex_init_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700234 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
235 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
236 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
237 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
238 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
239 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
240 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
241 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
242 0x03, 0xa8
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700243};
244static const u8 pkex_resp_x_p521[66] = {
245 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
246 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
247 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
248 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
249 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
250 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
251 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
252 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
253 0x84, 0xb4
254};
255static const u8 pkex_resp_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700256 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
257 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
258 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
259 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
260 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
261 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
262 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
263 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
264 0xce, 0xe1
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700265};
266
267/* Brainpool P-256r1 */
268static const u8 pkex_init_x_bp_p256r1[32] = {
269 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
270 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
271 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
272 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
273};
274static const u8 pkex_init_y_bp_p256r1[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700275 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
276 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
277 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
278 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700279};
280static const u8 pkex_resp_x_bp_p256r1[32] = {
281 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
282 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
283 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
284 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
285};
286static const u8 pkex_resp_y_bp_p256r1[32] = {
287 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
288 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
289 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
290 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
291};
292
293/* Brainpool P-384r1 */
294static const u8 pkex_init_x_bp_p384r1[48] = {
295 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
296 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
297 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
298 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
299 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
300 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
301};
302static const u8 pkex_init_y_bp_p384r1[48] = {
303 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
304 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
305 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
306 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
307 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
308 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
309};
310static const u8 pkex_resp_x_bp_p384r1[48] = {
311 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
312 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
313 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
314 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
315 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
316 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
317};
318static const u8 pkex_resp_y_bp_p384r1[48] = {
319 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
320 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
321 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
322 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
323 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
324 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
325};
326
327/* Brainpool P-512r1 */
328static const u8 pkex_init_x_bp_p512r1[64] = {
329 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
330 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
331 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
332 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
333 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
334 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
335 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
336 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
337};
338static const u8 pkex_init_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700339 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
340 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
341 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
342 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
343 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
344 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
345 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
346 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700347};
348static const u8 pkex_resp_x_bp_p512r1[64] = {
349 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
350 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
351 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
352 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
353 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
354 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
355 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
356 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
357};
358static const u8 pkex_resp_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700359 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
360 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
361 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
362 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
363 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
364 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
365 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
366 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700367};
368
369
Roshan Pius3a1667e2018-07-03 15:17:14 -0700370static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
371 const EC_POINT *point)
372{
373 BIGNUM *x, *y;
374 BN_CTX *ctx;
375 char *x_str = NULL, *y_str = NULL;
376
377 if (!wpa_debug_show_keys)
378 return;
379
380 ctx = BN_CTX_new();
381 x = BN_new();
382 y = BN_new();
383 if (!ctx || !x || !y ||
384 EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
385 goto fail;
386
387 x_str = BN_bn2hex(x);
388 y_str = BN_bn2hex(y);
389 if (!x_str || !y_str)
390 goto fail;
391
392 wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
393
394fail:
395 OPENSSL_free(x_str);
396 OPENSSL_free(y_str);
397 BN_free(x);
398 BN_free(y);
399 BN_CTX_free(ctx);
400}
401
402
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700403static int dpp_hash_vector(const struct dpp_curve_params *curve,
404 size_t num_elem, const u8 *addr[], const size_t *len,
405 u8 *mac)
406{
407 if (curve->hash_len == 32)
408 return sha256_vector(num_elem, addr, len, mac);
409 if (curve->hash_len == 48)
410 return sha384_vector(num_elem, addr, len, mac);
411 if (curve->hash_len == 64)
412 return sha512_vector(num_elem, addr, len, mac);
413 return -1;
414}
415
416
417static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
418 const char *label, u8 *out, size_t outlen)
419{
420 if (hash_len == 32)
421 return hmac_sha256_kdf(secret, secret_len, NULL,
422 (const u8 *) label, os_strlen(label),
423 out, outlen);
424 if (hash_len == 48)
425 return hmac_sha384_kdf(secret, secret_len, NULL,
426 (const u8 *) label, os_strlen(label),
427 out, outlen);
428 if (hash_len == 64)
429 return hmac_sha512_kdf(secret, secret_len, NULL,
430 (const u8 *) label, os_strlen(label),
431 out, outlen);
432 return -1;
433}
434
435
436static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
437 size_t num_elem, const u8 *addr[],
438 const size_t *len, u8 *mac)
439{
440 if (hash_len == 32)
441 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
442 mac);
443 if (hash_len == 48)
444 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
445 mac);
446 if (hash_len == 64)
447 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
448 mac);
449 return -1;
450}
451
452
453static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
454 const u8 *data, size_t data_len, u8 *mac)
455{
456 if (hash_len == 32)
457 return hmac_sha256(key, key_len, data, data_len, mac);
458 if (hash_len == 48)
459 return hmac_sha384(key, key_len, data, data_len, mac);
460 if (hash_len == 64)
461 return hmac_sha512(key, key_len, data, data_len, mac);
462 return -1;
463}
464
465
Hai Shalomfdcde762020-04-02 11:19:20 -0700466#ifdef CONFIG_DPP2
467
468static int dpp_pbkdf2_f(size_t hash_len,
469 const u8 *password, size_t password_len,
470 const u8 *salt, size_t salt_len,
471 unsigned int iterations, unsigned int count, u8 *digest)
472{
473 unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
474 unsigned int i;
475 size_t j;
476 u8 count_buf[4];
477 const u8 *addr[2];
478 size_t len[2];
479
480 addr[0] = salt;
481 len[0] = salt_len;
482 addr[1] = count_buf;
483 len[1] = 4;
484
485 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
486 * U1 = PRF(P, S || i)
487 * U2 = PRF(P, U1)
488 * Uc = PRF(P, Uc-1)
489 */
490
491 WPA_PUT_BE32(count_buf, count);
492 if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
493 tmp))
494 return -1;
495 os_memcpy(digest, tmp, hash_len);
496
497 for (i = 1; i < iterations; i++) {
498 if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
499 tmp2))
500 return -1;
501 os_memcpy(tmp, tmp2, hash_len);
502 for (j = 0; j < hash_len; j++)
503 digest[j] ^= tmp2[j];
504 }
505
506 return 0;
507}
508
509
510static int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
511 const u8 *salt, size_t salt_len, unsigned int iterations,
512 u8 *buf, size_t buflen)
513{
514 unsigned int count = 0;
515 unsigned char *pos = buf;
516 size_t left = buflen, plen;
517 unsigned char digest[DPP_MAX_HASH_LEN];
518
519 while (left > 0) {
520 count++;
521 if (dpp_pbkdf2_f(hash_len, password, password_len,
522 salt, salt_len, iterations, count, digest))
523 return -1;
524 plen = left > hash_len ? hash_len : left;
525 os_memcpy(pos, digest, plen);
526 pos += plen;
527 left -= plen;
528 }
529
530 return 0;
531}
532
533#endif /* CONFIG_DPP2 */
534
535
Roshan Pius3a1667e2018-07-03 15:17:14 -0700536static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
537{
538 int num_bytes, offset;
539
540 num_bytes = BN_num_bytes(bn);
541 if ((size_t) num_bytes > len)
542 return -1;
543 offset = len - num_bytes;
544 os_memset(pos, 0, offset);
545 BN_bn2bin(bn, pos + offset);
546 return 0;
547}
548
549
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700550static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
551{
552 int len, res;
553 EC_KEY *eckey;
554 struct wpabuf *buf;
555 unsigned char *pos;
556
557 eckey = EVP_PKEY_get1_EC_KEY(pkey);
558 if (!eckey)
559 return NULL;
560 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
561 len = i2o_ECPublicKey(eckey, NULL);
562 if (len <= 0) {
563 wpa_printf(MSG_ERROR,
564 "DDP: Failed to determine public key encoding length");
565 EC_KEY_free(eckey);
566 return NULL;
567 }
568
569 buf = wpabuf_alloc(len);
570 if (!buf) {
571 EC_KEY_free(eckey);
572 return NULL;
573 }
574
575 pos = wpabuf_put(buf, len);
576 res = i2o_ECPublicKey(eckey, &pos);
577 EC_KEY_free(eckey);
578 if (res != len) {
579 wpa_printf(MSG_ERROR,
580 "DDP: Failed to encode public key (res=%d/%d)",
581 res, len);
582 wpabuf_free(buf);
583 return NULL;
584 }
585
586 if (!prefix) {
587 /* Remove 0x04 prefix to match DPP definition */
588 pos = wpabuf_mhead(buf);
589 os_memmove(pos, pos + 1, len - 1);
590 buf->used--;
591 }
592
593 return buf;
594}
595
596
597static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
598 const u8 *buf_x, const u8 *buf_y,
599 size_t len)
600{
601 EC_KEY *eckey = NULL;
602 BN_CTX *ctx;
603 EC_POINT *point = NULL;
604 BIGNUM *x = NULL, *y = NULL;
605 EVP_PKEY *pkey = NULL;
606
607 ctx = BN_CTX_new();
608 if (!ctx) {
609 wpa_printf(MSG_ERROR, "DPP: Out of memory");
610 return NULL;
611 }
612
613 point = EC_POINT_new(group);
614 x = BN_bin2bn(buf_x, len, NULL);
615 y = BN_bin2bn(buf_y, len, NULL);
616 if (!point || !x || !y) {
617 wpa_printf(MSG_ERROR, "DPP: Out of memory");
618 goto fail;
619 }
620
621 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
622 wpa_printf(MSG_ERROR,
623 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
624 ERR_error_string(ERR_get_error(), NULL));
625 goto fail;
626 }
627
628 if (!EC_POINT_is_on_curve(group, point, ctx) ||
629 EC_POINT_is_at_infinity(group, point)) {
630 wpa_printf(MSG_ERROR, "DPP: Invalid point");
631 goto fail;
632 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700633 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700634
635 eckey = EC_KEY_new();
636 if (!eckey ||
637 EC_KEY_set_group(eckey, group) != 1 ||
638 EC_KEY_set_public_key(eckey, point) != 1) {
639 wpa_printf(MSG_ERROR,
640 "DPP: Failed to set EC_KEY: %s",
641 ERR_error_string(ERR_get_error(), NULL));
642 goto fail;
643 }
644 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
645
646 pkey = EVP_PKEY_new();
647 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
648 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
649 goto fail;
650 }
651
652out:
653 BN_free(x);
654 BN_free(y);
655 EC_KEY_free(eckey);
656 EC_POINT_free(point);
657 BN_CTX_free(ctx);
658 return pkey;
659fail:
660 EVP_PKEY_free(pkey);
661 pkey = NULL;
662 goto out;
663}
664
665
666static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
667 const u8 *buf, size_t len)
668{
669 EC_KEY *eckey;
670 const EC_GROUP *group;
671 EVP_PKEY *pkey = NULL;
672
673 if (len & 1)
674 return NULL;
675
676 eckey = EVP_PKEY_get1_EC_KEY(group_key);
677 if (!eckey) {
678 wpa_printf(MSG_ERROR,
679 "DPP: Could not get EC_KEY from group_key");
680 return NULL;
681 }
682
683 group = EC_KEY_get0_group(eckey);
684 if (group)
685 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
686 len / 2);
687 else
688 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
689
690 EC_KEY_free(eckey);
691 return pkey;
692}
693
694
Hai Shalomc3565922019-10-28 11:58:20 -0700695static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
696 u8 *secret, size_t *secret_len)
697{
698 EVP_PKEY_CTX *ctx;
699 int ret = -1;
700
701 ERR_clear_error();
702 *secret_len = 0;
703
704 ctx = EVP_PKEY_CTX_new(own, NULL);
705 if (!ctx) {
706 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
707 ERR_error_string(ERR_get_error(), NULL));
708 return -1;
709 }
710
711 if (EVP_PKEY_derive_init(ctx) != 1) {
712 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
713 ERR_error_string(ERR_get_error(), NULL));
714 goto fail;
715 }
716
717 if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
718 wpa_printf(MSG_ERROR,
719 "DPP: EVP_PKEY_derive_set_peet failed: %s",
720 ERR_error_string(ERR_get_error(), NULL));
721 goto fail;
722 }
723
724 if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
725 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
726 ERR_error_string(ERR_get_error(), NULL));
727 goto fail;
728 }
729
730 if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
731 u8 buf[200];
732 int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
733
734 /* It looks like OpenSSL can return unexpectedly large buffer
735 * need for shared secret from EVP_PKEY_derive(NULL) in some
736 * cases. For example, group 19 has shown cases where secret_len
737 * is set to 72 even though the actual length ends up being
738 * updated to 32 when EVP_PKEY_derive() is called with a buffer
739 * for the value. Work around this by trying to fetch the value
740 * and continue if it is within supported range even when the
741 * initial buffer need is claimed to be larger. */
742 wpa_printf(level,
743 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
744 (int) *secret_len);
745 if (*secret_len > 200)
746 goto fail;
747 if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
748 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
749 ERR_error_string(ERR_get_error(), NULL));
750 goto fail;
751 }
752 if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
753 wpa_printf(MSG_ERROR,
754 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
755 (int) *secret_len);
756 goto fail;
757 }
758 wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
759 buf, *secret_len);
760 os_memcpy(secret, buf, *secret_len);
761 forced_memzero(buf, sizeof(buf));
762 goto done;
763 }
764
765 if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
766 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
767 ERR_error_string(ERR_get_error(), NULL));
768 goto fail;
769 }
770
771done:
772 ret = 0;
773
774fail:
775 EVP_PKEY_CTX_free(ctx);
776 return ret;
777}
778
779
Roshan Pius3a1667e2018-07-03 15:17:14 -0700780static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
781{
782 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
783}
784
785
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700786struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
787 size_t len)
788{
789 struct wpabuf *msg;
790
791 msg = wpabuf_alloc(8 + len);
792 if (!msg)
793 return NULL;
794 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
795 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
796 wpabuf_put_be24(msg, OUI_WFA);
797 wpabuf_put_u8(msg, DPP_OUI_TYPE);
798 wpabuf_put_u8(msg, 1); /* Crypto Suite */
799 wpabuf_put_u8(msg, type);
800 return msg;
801}
802
803
804const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
805{
806 u16 id, alen;
807 const u8 *pos = buf, *end = buf + len;
808
809 while (end - pos >= 4) {
810 id = WPA_GET_LE16(pos);
811 pos += 2;
812 alen = WPA_GET_LE16(pos);
813 pos += 2;
814 if (alen > end - pos)
815 return NULL;
816 if (id == req_id) {
817 *ret_len = alen;
818 return pos;
819 }
820 pos += alen;
821 }
822
823 return NULL;
824}
825
826
Hai Shalomc3565922019-10-28 11:58:20 -0700827static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
828 u16 req_id, u16 *ret_len)
829{
830 u16 id, alen;
831 const u8 *pos, *end = buf + len;
832
833 if (!prev)
834 pos = buf;
835 else
836 pos = prev + WPA_GET_LE16(prev - 2);
837 while (end - pos >= 4) {
838 id = WPA_GET_LE16(pos);
839 pos += 2;
840 alen = WPA_GET_LE16(pos);
841 pos += 2;
842 if (alen > end - pos)
843 return NULL;
844 if (id == req_id) {
845 *ret_len = alen;
846 return pos;
847 }
848 pos += alen;
849 }
850
851 return NULL;
852}
853
854
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700855int dpp_check_attrs(const u8 *buf, size_t len)
856{
857 const u8 *pos, *end;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700858 int wrapped_data = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700859
860 pos = buf;
861 end = buf + len;
862 while (end - pos >= 4) {
863 u16 id, alen;
864
865 id = WPA_GET_LE16(pos);
866 pos += 2;
867 alen = WPA_GET_LE16(pos);
868 pos += 2;
869 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
870 id, alen);
871 if (alen > end - pos) {
872 wpa_printf(MSG_DEBUG,
873 "DPP: Truncated message - not enough room for the attribute - dropped");
874 return -1;
875 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700876 if (wrapped_data) {
877 wpa_printf(MSG_DEBUG,
878 "DPP: An unexpected attribute included after the Wrapped Data attribute");
879 return -1;
880 }
881 if (id == DPP_ATTR_WRAPPED_DATA)
882 wrapped_data = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700883 pos += alen;
884 }
885
886 if (end != pos) {
887 wpa_printf(MSG_DEBUG,
888 "DPP: Unexpected octets (%d) after the last attribute",
889 (int) (end - pos));
890 return -1;
891 }
892
893 return 0;
894}
895
896
897void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
898{
899 if (!info)
900 return;
901 os_free(info->uri);
902 os_free(info->info);
Hai Shalomfdcde762020-04-02 11:19:20 -0700903 os_free(info->chan);
904 os_free(info->pk);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700905 EVP_PKEY_free(info->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -0700906 str_clear_free(info->configurator_params);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700907 os_free(info);
908}
909
910
911const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
912{
913 switch (type) {
914 case DPP_BOOTSTRAP_QR_CODE:
915 return "QRCODE";
916 case DPP_BOOTSTRAP_PKEX:
917 return "PKEX";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800918 case DPP_BOOTSTRAP_NFC_URI:
919 return "NFC-URI";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700920 }
921 return "??";
922}
923
924
925static int dpp_uri_valid_info(const char *info)
926{
927 while (*info) {
928 unsigned char val = *info++;
929
930 if (val < 0x20 || val > 0x7e || val == 0x3b)
931 return 0;
932 }
933
934 return 1;
935}
936
937
938static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
939{
940 bi->uri = os_strdup(uri);
941 return bi->uri ? 0 : -1;
942}
943
944
945int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
946 const char *chan_list)
947{
Hai Shalom81f62d82019-07-22 12:10:00 -0700948 const char *pos = chan_list, *pos2;
949 int opclass = -1, channel, freq;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700950
951 while (pos && *pos && *pos != ';') {
Hai Shalom81f62d82019-07-22 12:10:00 -0700952 pos2 = pos;
953 while (*pos2 >= '0' && *pos2 <= '9')
954 pos2++;
955 if (*pos2 == '/') {
956 opclass = atoi(pos);
957 pos = pos2 + 1;
958 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700959 if (opclass <= 0)
960 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700961 channel = atoi(pos);
962 if (channel <= 0)
963 goto fail;
964 while (*pos >= '0' && *pos <= '9')
965 pos++;
966 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
967 wpa_printf(MSG_DEBUG,
968 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
969 opclass, channel, freq);
970 if (freq < 0) {
971 wpa_printf(MSG_DEBUG,
972 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
973 opclass, channel);
974 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
975 wpa_printf(MSG_DEBUG,
976 "DPP: Too many channels in URI channel-list - ignore list");
977 bi->num_freq = 0;
978 break;
979 } else {
980 bi->freq[bi->num_freq++] = freq;
981 }
982
983 if (*pos == ';' || *pos == '\0')
984 break;
985 if (*pos != ',')
986 goto fail;
987 pos++;
988 }
989
990 return 0;
991fail:
992 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
993 return -1;
994}
995
996
997int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
998{
999 if (!mac)
1000 return 0;
1001
1002 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
1003 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
1004 return -1;
1005 }
1006
1007 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
1008
1009 return 0;
1010}
1011
1012
1013int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
1014{
1015 const char *end;
1016
1017 if (!info)
1018 return 0;
1019
1020 end = os_strchr(info, ';');
1021 if (!end)
1022 end = info + os_strlen(info);
1023 bi->info = os_malloc(end - info + 1);
1024 if (!bi->info)
1025 return -1;
1026 os_memcpy(bi->info, info, end - info);
1027 bi->info[end - info] = '\0';
1028 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
1029 if (!dpp_uri_valid_info(bi->info)) {
1030 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
1031 return -1;
1032 }
1033
1034 return 0;
1035}
1036
1037
1038static const struct dpp_curve_params *
1039dpp_get_curve_oid(const ASN1_OBJECT *poid)
1040{
1041 ASN1_OBJECT *oid;
1042 int i;
1043
1044 for (i = 0; dpp_curves[i].name; i++) {
1045 oid = OBJ_txt2obj(dpp_curves[i].name, 0);
1046 if (oid && OBJ_cmp(poid, oid) == 0)
1047 return &dpp_curves[i];
1048 }
1049 return NULL;
1050}
1051
1052
1053static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
1054{
1055 int i, tmp;
1056
1057 if (!nid)
1058 return NULL;
1059 for (i = 0; dpp_curves[i].name; i++) {
1060 tmp = OBJ_txt2nid(dpp_curves[i].name);
1061 if (tmp == nid)
1062 return &dpp_curves[i];
1063 }
1064 return NULL;
1065}
1066
1067
Hai Shalomfdcde762020-04-02 11:19:20 -07001068static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
1069 const u8 *data, size_t data_len)
1070{
1071 const u8 *addr[2];
1072 size_t len[2];
1073
1074 addr[0] = data;
1075 len[0] = data_len;
1076 if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
1077 return -1;
1078 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
1079 bi->pubkey_hash, SHA256_MAC_LEN);
1080
1081 addr[0] = (const u8 *) "chirp";
1082 len[0] = 5;
1083 addr[1] = data;
1084 len[1] = data_len;
1085 if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
1086 return -1;
1087 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
1088 bi->pubkey_hash_chirp, SHA256_MAC_LEN);
1089
1090 return 0;
1091}
1092
1093
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001094static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
1095{
1096 const char *end;
1097 u8 *data;
1098 size_t data_len;
1099 EVP_PKEY *pkey;
1100 const unsigned char *p;
1101 int res;
1102 X509_PUBKEY *pub = NULL;
1103 ASN1_OBJECT *ppkalg;
1104 const unsigned char *pk;
1105 int ppklen;
1106 X509_ALGOR *pa;
Hai Shalom74f70d42019-02-11 14:42:39 -08001107#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1108 (defined(LIBRESSL_VERSION_NUMBER) && \
1109 LIBRESSL_VERSION_NUMBER < 0x20800000L)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001110 ASN1_OBJECT *pa_oid;
1111#else
1112 const ASN1_OBJECT *pa_oid;
1113#endif
1114 const void *pval;
1115 int ptype;
1116 const ASN1_OBJECT *poid;
1117 char buf[100];
1118
1119 end = os_strchr(info, ';');
1120 if (!end)
1121 return -1;
1122
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001123 data = base64_decode(info, end - info, &data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001124 if (!data) {
1125 wpa_printf(MSG_DEBUG,
1126 "DPP: Invalid base64 encoding on URI public-key");
1127 return -1;
1128 }
1129 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
1130 data, data_len);
1131
Hai Shalomfdcde762020-04-02 11:19:20 -07001132 if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001133 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001134 os_free(data);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001135 return -1;
1136 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001137
1138 /* DER encoded ASN.1 SubjectPublicKeyInfo
1139 *
1140 * SubjectPublicKeyInfo ::= SEQUENCE {
1141 * algorithm AlgorithmIdentifier,
1142 * subjectPublicKey BIT STRING }
1143 *
1144 * AlgorithmIdentifier ::= SEQUENCE {
1145 * algorithm OBJECT IDENTIFIER,
1146 * parameters ANY DEFINED BY algorithm OPTIONAL }
1147 *
1148 * subjectPublicKey = compressed format public key per ANSI X9.63
1149 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1150 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1151 * prime256v1 (1.2.840.10045.3.1.7)
1152 */
1153
1154 p = data;
1155 pkey = d2i_PUBKEY(NULL, &p, data_len);
1156 os_free(data);
1157
1158 if (!pkey) {
1159 wpa_printf(MSG_DEBUG,
1160 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1161 return -1;
1162 }
1163
1164 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
1165 wpa_printf(MSG_DEBUG,
1166 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1167 EVP_PKEY_free(pkey);
1168 return -1;
1169 }
1170
1171 res = X509_PUBKEY_set(&pub, pkey);
1172 if (res != 1) {
1173 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
1174 goto fail;
1175 }
1176
1177 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
1178 if (res != 1) {
1179 wpa_printf(MSG_DEBUG,
1180 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1181 goto fail;
1182 }
1183 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
1184 if (res < 0 || (size_t) res >= sizeof(buf)) {
1185 wpa_printf(MSG_DEBUG,
1186 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1187 goto fail;
1188 }
1189 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
1190 if (os_strcmp(buf, "id-ecPublicKey") != 0) {
1191 wpa_printf(MSG_DEBUG,
1192 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1193 goto fail;
1194 }
1195
1196 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
1197 if (ptype != V_ASN1_OBJECT) {
1198 wpa_printf(MSG_DEBUG,
1199 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1200 goto fail;
1201 }
1202 poid = pval;
1203 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
1204 if (res < 0 || (size_t) res >= sizeof(buf)) {
1205 wpa_printf(MSG_DEBUG,
1206 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1207 goto fail;
1208 }
1209 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
1210 bi->curve = dpp_get_curve_oid(poid);
1211 if (!bi->curve) {
1212 wpa_printf(MSG_DEBUG,
1213 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1214 buf);
1215 goto fail;
1216 }
1217
1218 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
1219
1220 X509_PUBKEY_free(pub);
1221 bi->pubkey = pkey;
1222 return 0;
1223fail:
1224 X509_PUBKEY_free(pub);
1225 EVP_PKEY_free(pkey);
1226 return -1;
1227}
1228
1229
1230static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
1231{
1232 const char *pos = uri;
1233 const char *end;
1234 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
1235 struct dpp_bootstrap_info *bi;
1236
1237 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
1238
1239 if (os_strncmp(pos, "DPP:", 4) != 0) {
1240 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
1241 return NULL;
1242 }
1243 pos += 4;
1244
1245 for (;;) {
1246 end = os_strchr(pos, ';');
1247 if (!end)
1248 break;
1249
1250 if (end == pos) {
1251 /* Handle terminating ";;" and ignore unexpected ";"
1252 * for parsing robustness. */
1253 pos++;
1254 continue;
1255 }
1256
1257 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
1258 chan_list = pos + 2;
1259 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
1260 mac = pos + 2;
1261 else if (pos[0] == 'I' && pos[1] == ':' && !info)
1262 info = pos + 2;
1263 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
1264 pk = pos + 2;
1265 else
1266 wpa_hexdump_ascii(MSG_DEBUG,
1267 "DPP: Ignore unrecognized URI parameter",
1268 pos, end - pos);
1269 pos = end + 1;
1270 }
1271
1272 if (!pk) {
1273 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
1274 return NULL;
1275 }
1276
1277 bi = os_zalloc(sizeof(*bi));
1278 if (!bi)
1279 return NULL;
1280
1281 if (dpp_clone_uri(bi, uri) < 0 ||
1282 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
1283 dpp_parse_uri_mac(bi, mac) < 0 ||
1284 dpp_parse_uri_info(bi, info) < 0 ||
1285 dpp_parse_uri_pk(bi, pk) < 0) {
1286 dpp_bootstrap_info_free(bi);
1287 bi = NULL;
1288 }
1289
1290 return bi;
1291}
1292
1293
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001294static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
1295{
1296 EC_KEY *eckey;
1297 BIO *out;
1298 size_t rlen;
1299 char *txt;
1300 int res;
1301 unsigned char *der = NULL;
1302 int der_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001303 const EC_GROUP *group;
1304 const EC_POINT *point;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001305
1306 out = BIO_new(BIO_s_mem());
1307 if (!out)
1308 return;
1309
1310 EVP_PKEY_print_private(out, key, 0, NULL);
1311 rlen = BIO_ctrl_pending(out);
1312 txt = os_malloc(rlen + 1);
1313 if (txt) {
1314 res = BIO_read(out, txt, rlen);
1315 if (res > 0) {
1316 txt[res] = '\0';
1317 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
1318 }
1319 os_free(txt);
1320 }
1321 BIO_free(out);
1322
1323 eckey = EVP_PKEY_get1_EC_KEY(key);
1324 if (!eckey)
1325 return;
1326
Roshan Pius3a1667e2018-07-03 15:17:14 -07001327 group = EC_KEY_get0_group(eckey);
1328 point = EC_KEY_get0_public_key(eckey);
1329 if (group && point)
1330 dpp_debug_print_point(title, group, point);
1331
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001332 der_len = i2d_ECPrivateKey(eckey, &der);
1333 if (der_len > 0)
1334 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1335 OPENSSL_free(der);
1336 if (der_len <= 0) {
1337 der = NULL;
1338 der_len = i2d_EC_PUBKEY(eckey, &der);
1339 if (der_len > 0)
1340 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1341 OPENSSL_free(der);
1342 }
1343
1344 EC_KEY_free(eckey);
1345}
1346
1347
1348static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1349{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001350 EVP_PKEY_CTX *kctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07001351 EC_KEY *ec_params = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001352 EVP_PKEY *params = NULL, *key = NULL;
1353 int nid;
1354
1355 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1356
1357 nid = OBJ_txt2nid(curve->name);
1358 if (nid == NID_undef) {
1359 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1360 return NULL;
1361 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001362
1363 ec_params = EC_KEY_new_by_curve_name(nid);
1364 if (!ec_params) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001365 wpa_printf(MSG_ERROR,
1366 "DPP: Failed to generate EC_KEY parameters");
1367 goto fail;
1368 }
1369 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
1370 params = EVP_PKEY_new();
1371 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
1372 wpa_printf(MSG_ERROR,
1373 "DPP: Failed to generate EVP_PKEY parameters");
1374 goto fail;
1375 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001376
1377 kctx = EVP_PKEY_CTX_new(params, NULL);
1378 if (!kctx ||
1379 EVP_PKEY_keygen_init(kctx) != 1 ||
1380 EVP_PKEY_keygen(kctx, &key) != 1) {
1381 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
Hai Shalom81f62d82019-07-22 12:10:00 -07001382 key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001383 goto fail;
1384 }
1385
1386 if (wpa_debug_show_keys)
1387 dpp_debug_print_key("Own generated key", key);
1388
Hai Shalom81f62d82019-07-22 12:10:00 -07001389fail:
1390 EC_KEY_free(ec_params);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001391 EVP_PKEY_free(params);
1392 EVP_PKEY_CTX_free(kctx);
1393 return key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001394}
1395
1396
1397static const struct dpp_curve_params *
1398dpp_get_curve_name(const char *name)
1399{
1400 int i;
1401
1402 for (i = 0; dpp_curves[i].name; i++) {
1403 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
1404 (dpp_curves[i].jwk_crv &&
1405 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
1406 return &dpp_curves[i];
1407 }
1408 return NULL;
1409}
1410
1411
1412static const struct dpp_curve_params *
1413dpp_get_curve_jwk_crv(const char *name)
1414{
1415 int i;
1416
1417 for (i = 0; dpp_curves[i].name; i++) {
1418 if (dpp_curves[i].jwk_crv &&
1419 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
1420 return &dpp_curves[i];
1421 }
1422 return NULL;
1423}
1424
1425
1426static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1427 const u8 *privkey, size_t privkey_len)
1428{
1429 EVP_PKEY *pkey;
1430 EC_KEY *eckey;
1431 const EC_GROUP *group;
1432 int nid;
1433
1434 pkey = EVP_PKEY_new();
1435 if (!pkey)
1436 return NULL;
1437 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1438 if (!eckey) {
1439 wpa_printf(MSG_INFO,
1440 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1441 ERR_error_string(ERR_get_error(), NULL));
1442 EVP_PKEY_free(pkey);
1443 return NULL;
1444 }
1445 group = EC_KEY_get0_group(eckey);
1446 if (!group) {
1447 EC_KEY_free(eckey);
1448 EVP_PKEY_free(pkey);
1449 return NULL;
1450 }
1451 nid = EC_GROUP_get_curve_name(group);
1452 *curve = dpp_get_curve_nid(nid);
1453 if (!*curve) {
1454 wpa_printf(MSG_INFO,
1455 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1456 nid);
1457 EC_KEY_free(eckey);
1458 EVP_PKEY_free(pkey);
1459 return NULL;
1460 }
1461
1462 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1463 EC_KEY_free(eckey);
1464 EVP_PKEY_free(pkey);
1465 return NULL;
1466 }
1467 return pkey;
1468}
1469
1470
Roshan Pius3a1667e2018-07-03 15:17:14 -07001471typedef struct {
1472 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1473 * as an OID identifying the curve */
1474 X509_ALGOR *alg;
1475 /* Compressed format public key per ANSI X9.63 */
1476 ASN1_BIT_STRING *pub_key;
1477} DPP_BOOTSTRAPPING_KEY;
1478
1479ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
1480 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
1481 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
1482} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
1483
1484IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1485
1486
1487static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001488{
1489 unsigned char *der = NULL;
1490 int der_len;
1491 EC_KEY *eckey;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001492 struct wpabuf *ret = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001493 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001494 const EC_GROUP *group;
1495 const EC_POINT *point;
1496 BN_CTX *ctx;
1497 DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1498 int nid;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001499
Roshan Pius3a1667e2018-07-03 15:17:14 -07001500 ctx = BN_CTX_new();
1501 eckey = EVP_PKEY_get1_EC_KEY(key);
1502 if (!ctx || !eckey)
1503 goto fail;
1504
1505 group = EC_KEY_get0_group(eckey);
1506 point = EC_KEY_get0_public_key(eckey);
1507 if (!group || !point)
1508 goto fail;
1509 dpp_debug_print_point("DPP: bootstrap public key", group, point);
1510 nid = EC_GROUP_get_curve_name(group);
1511
1512 bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1513 if (!bootstrap ||
1514 X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1515 V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1516 goto fail;
1517
1518 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1519 NULL, 0, ctx);
1520 if (len == 0)
1521 goto fail;
1522
1523 der = OPENSSL_malloc(len);
1524 if (!der)
1525 goto fail;
1526 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1527 der, len, ctx);
1528
1529 OPENSSL_free(bootstrap->pub_key->data);
1530 bootstrap->pub_key->data = der;
1531 der = NULL;
1532 bootstrap->pub_key->length = len;
1533 /* No unused bits */
1534 bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
1535 bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
1536
1537 der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001538 if (der_len <= 0) {
1539 wpa_printf(MSG_ERROR,
1540 "DDP: Failed to build DER encoded public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001541 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001542 }
1543
Roshan Pius3a1667e2018-07-03 15:17:14 -07001544 ret = wpabuf_alloc_copy(der, der_len);
1545fail:
1546 DPP_BOOTSTRAPPING_KEY_free(bootstrap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001547 OPENSSL_free(der);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001548 EC_KEY_free(eckey);
1549 BN_CTX_free(ctx);
1550 return ret;
1551}
1552
1553
Hai Shalomfdcde762020-04-02 11:19:20 -07001554static int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001555{
1556 struct wpabuf *der;
1557 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001558
1559 der = dpp_bootstrap_key_der(bi->pubkey);
1560 if (!der)
1561 return -1;
1562 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1563 der);
Hai Shalomfdcde762020-04-02 11:19:20 -07001564 res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001565 if (res < 0)
1566 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001567 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001568 return res;
1569}
1570
1571
Hai Shalomfdcde762020-04-02 11:19:20 -07001572static int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1573 const u8 *privkey, size_t privkey_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001574{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001575 char *base64 = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001576 char *pos, *end;
1577 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001578 struct wpabuf *der = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001579
1580 if (!curve) {
1581 bi->curve = &dpp_curves[0];
1582 } else {
1583 bi->curve = dpp_get_curve_name(curve);
1584 if (!bi->curve) {
1585 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1586 curve);
Hai Shalomfdcde762020-04-02 11:19:20 -07001587 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001588 }
1589 }
1590 if (privkey)
1591 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1592 else
1593 bi->pubkey = dpp_gen_keypair(bi->curve);
1594 if (!bi->pubkey)
1595 goto fail;
1596 bi->own = 1;
1597
Roshan Pius3a1667e2018-07-03 15:17:14 -07001598 der = dpp_bootstrap_key_der(bi->pubkey);
1599 if (!der)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001600 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001601 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1602 der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001603
Hai Shalomfdcde762020-04-02 11:19:20 -07001604 if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001605 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1606 goto fail;
1607 }
1608
Roshan Pius3a1667e2018-07-03 15:17:14 -07001609 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1610 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001611 der = NULL;
1612 if (!base64)
1613 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001614 pos = base64;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001615 end = pos + len;
1616 for (;;) {
1617 pos = os_strchr(pos, '\n');
1618 if (!pos)
1619 break;
1620 os_memmove(pos, pos + 1, end - pos);
1621 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001622 os_free(bi->pk);
1623 bi->pk = base64;
1624 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001625fail:
1626 os_free(base64);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001627 wpabuf_free(der);
Hai Shalomfdcde762020-04-02 11:19:20 -07001628 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001629}
1630
1631
1632static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1633 unsigned int hash_len)
1634{
1635 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1636 const char *info = "first intermediate key";
1637 int res;
1638
1639 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1640
1641 /* HKDF-Extract(<>, M.x) */
1642 os_memset(salt, 0, hash_len);
1643 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
1644 return -1;
1645 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1646 prk, hash_len);
1647
1648 /* HKDF-Expand(PRK, info, L) */
1649 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
1650 os_memset(prk, 0, hash_len);
1651 if (res < 0)
1652 return -1;
1653
1654 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1655 k1, hash_len);
1656 return 0;
1657}
1658
1659
1660static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1661 unsigned int hash_len)
1662{
1663 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1664 const char *info = "second intermediate key";
1665 int res;
1666
1667 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1668
1669 /* HKDF-Extract(<>, N.x) */
1670 os_memset(salt, 0, hash_len);
1671 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
1672 if (res < 0)
1673 return -1;
1674 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1675 prk, hash_len);
1676
1677 /* HKDF-Expand(PRK, info, L) */
1678 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
1679 os_memset(prk, 0, hash_len);
1680 if (res < 0)
1681 return -1;
1682
1683 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1684 k2, hash_len);
1685 return 0;
1686}
1687
1688
1689static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1690 unsigned int hash_len)
1691{
1692 size_t nonce_len;
1693 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1694 const char *info_ke = "DPP Key";
1695 u8 prk[DPP_MAX_HASH_LEN];
1696 int res;
1697 const u8 *addr[3];
1698 size_t len[3];
1699 size_t num_elem = 0;
1700
Roshan Pius3a1667e2018-07-03 15:17:14 -07001701 if (!auth->Mx_len || !auth->Nx_len) {
1702 wpa_printf(MSG_DEBUG,
1703 "DPP: Mx/Nx not available - cannot derive ke");
1704 return -1;
1705 }
1706
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001707 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1708
1709 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1710 nonce_len = auth->curve->nonce_len;
1711 os_memcpy(nonces, auth->i_nonce, nonce_len);
1712 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1713 addr[num_elem] = auth->Mx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001714 len[num_elem] = auth->Mx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001715 num_elem++;
1716 addr[num_elem] = auth->Nx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001717 len[num_elem] = auth->Nx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001718 num_elem++;
1719 if (auth->peer_bi && auth->own_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001720 if (!auth->Lx_len) {
1721 wpa_printf(MSG_DEBUG,
1722 "DPP: Lx not available - cannot derive ke");
1723 return -1;
1724 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001725 addr[num_elem] = auth->Lx;
1726 len[num_elem] = auth->secret_len;
1727 num_elem++;
1728 }
1729 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1730 num_elem, addr, len, prk);
1731 if (res < 0)
1732 return -1;
1733 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1734 prk, hash_len);
1735
1736 /* HKDF-Expand(PRK, info, L) */
1737 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
1738 os_memset(prk, 0, hash_len);
1739 if (res < 0)
1740 return -1;
1741
1742 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1743 ke, hash_len);
1744 return 0;
1745}
1746
1747
Roshan Pius3a1667e2018-07-03 15:17:14 -07001748static void dpp_build_attr_status(struct wpabuf *msg,
1749 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001750{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001751 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
1752 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1753 wpabuf_put_le16(msg, 1);
1754 wpabuf_put_u8(msg, status);
1755}
1756
1757
1758static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1759 const u8 *hash)
1760{
1761 if (hash) {
1762 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1763 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1764 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1765 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1766 }
1767}
1768
1769
1770static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1771 const u8 *hash)
1772{
1773 if (hash) {
1774 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1775 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1776 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1777 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1778 }
1779}
1780
1781
1782static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1783 const struct wpabuf *pi,
1784 size_t nonce_len,
1785 const u8 *r_pubkey_hash,
1786 const u8 *i_pubkey_hash,
1787 unsigned int neg_freq)
1788{
1789 struct wpabuf *msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001790 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1791 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1792 u8 *pos;
1793 const u8 *addr[2];
1794 size_t len[2], siv_len, attr_len;
1795 u8 *attr_start, *attr_end;
1796
Roshan Pius3a1667e2018-07-03 15:17:14 -07001797 /* Build DPP Authentication Request frame attributes */
1798 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
1799 4 + sizeof(wrapped_data);
1800 if (neg_freq > 0)
1801 attr_len += 4 + 2;
Hai Shalom021b0b52019-04-10 11:17:58 -07001802#ifdef CONFIG_DPP2
1803 attr_len += 5;
1804#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001805#ifdef CONFIG_TESTING_OPTIONS
1806 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1807 attr_len += 5;
1808#endif /* CONFIG_TESTING_OPTIONS */
1809 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1810 if (!msg)
1811 return NULL;
1812
1813 attr_start = wpabuf_put(msg, 0);
1814
1815 /* Responder Bootstrapping Key Hash */
1816 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1817
1818 /* Initiator Bootstrapping Key Hash */
1819 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1820
1821 /* Initiator Protocol Key */
1822 if (pi) {
1823 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1824 wpabuf_put_le16(msg, wpabuf_len(pi));
1825 wpabuf_put_buf(msg, pi);
1826 }
1827
1828 /* Channel */
1829 if (neg_freq > 0) {
1830 u8 op_class, channel;
1831
1832 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1833 &channel) ==
1834 NUM_HOSTAPD_MODES) {
1835 wpa_printf(MSG_INFO,
1836 "DPP: Unsupported negotiation frequency request: %d",
1837 neg_freq);
1838 wpabuf_free(msg);
1839 return NULL;
1840 }
1841 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1842 wpabuf_put_le16(msg, 2);
1843 wpabuf_put_u8(msg, op_class);
1844 wpabuf_put_u8(msg, channel);
1845 }
1846
Hai Shalom021b0b52019-04-10 11:17:58 -07001847#ifdef CONFIG_DPP2
1848 /* Protocol Version */
1849 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1850 wpabuf_put_le16(msg, 1);
1851 wpabuf_put_u8(msg, 2);
1852#endif /* CONFIG_DPP2 */
1853
Roshan Pius3a1667e2018-07-03 15:17:14 -07001854#ifdef CONFIG_TESTING_OPTIONS
1855 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1856 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1857 goto skip_wrapped_data;
1858 }
1859#endif /* CONFIG_TESTING_OPTIONS */
1860
1861 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1862 pos = clear;
1863
1864#ifdef CONFIG_TESTING_OPTIONS
1865 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1866 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1867 goto skip_i_nonce;
1868 }
1869 if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1870 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1871 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1872 pos += 2;
1873 WPA_PUT_LE16(pos, nonce_len - 1);
1874 pos += 2;
1875 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1876 pos += nonce_len - 1;
1877 goto skip_i_nonce;
1878 }
1879#endif /* CONFIG_TESTING_OPTIONS */
1880
1881 /* I-nonce */
1882 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1883 pos += 2;
1884 WPA_PUT_LE16(pos, nonce_len);
1885 pos += 2;
1886 os_memcpy(pos, auth->i_nonce, nonce_len);
1887 pos += nonce_len;
1888
1889#ifdef CONFIG_TESTING_OPTIONS
1890skip_i_nonce:
1891 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1892 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1893 goto skip_i_capab;
1894 }
1895#endif /* CONFIG_TESTING_OPTIONS */
1896
1897 /* I-capabilities */
1898 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1899 pos += 2;
1900 WPA_PUT_LE16(pos, 1);
1901 pos += 2;
1902 auth->i_capab = auth->allowed_roles;
1903 *pos++ = auth->i_capab;
1904#ifdef CONFIG_TESTING_OPTIONS
1905 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1906 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1907 pos[-1] = 0;
1908 }
1909skip_i_capab:
1910#endif /* CONFIG_TESTING_OPTIONS */
1911
1912 attr_end = wpabuf_put(msg, 0);
1913
1914 /* OUI, OUI type, Crypto Suite, DPP frame type */
1915 addr[0] = wpabuf_head_u8(msg) + 2;
1916 len[0] = 3 + 1 + 1 + 1;
1917 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1918
1919 /* Attributes before Wrapped Data */
1920 addr[1] = attr_start;
1921 len[1] = attr_end - attr_start;
1922 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1923
1924 siv_len = pos - clear;
1925 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1926 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1927 2, addr, len, wrapped_data) < 0) {
1928 wpabuf_free(msg);
1929 return NULL;
1930 }
1931 siv_len += AES_BLOCK_SIZE;
1932 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1933 wrapped_data, siv_len);
1934
1935 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1936 wpabuf_put_le16(msg, siv_len);
1937 wpabuf_put_data(msg, wrapped_data, siv_len);
1938
1939#ifdef CONFIG_TESTING_OPTIONS
1940 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1941 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1942 dpp_build_attr_status(msg, DPP_STATUS_OK);
1943 }
1944skip_wrapped_data:
1945#endif /* CONFIG_TESTING_OPTIONS */
1946
1947 wpa_hexdump_buf(MSG_DEBUG,
1948 "DPP: Authentication Request frame attributes", msg);
1949
1950 return msg;
1951}
1952
1953
1954static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1955 enum dpp_status_error status,
1956 const struct wpabuf *pr,
1957 size_t nonce_len,
1958 const u8 *r_pubkey_hash,
1959 const u8 *i_pubkey_hash,
1960 const u8 *r_nonce, const u8 *i_nonce,
1961 const u8 *wrapped_r_auth,
1962 size_t wrapped_r_auth_len,
1963 const u8 *siv_key)
1964{
1965 struct wpabuf *msg;
1966#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1967 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1968 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1969 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1970 const u8 *addr[2];
1971 size_t len[2], siv_len, attr_len;
1972 u8 *attr_start, *attr_end, *pos;
1973
1974 auth->waiting_auth_conf = 1;
1975 auth->auth_resp_tries = 0;
1976
1977 /* Build DPP Authentication Response frame attributes */
1978 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1979 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
Hai Shalom021b0b52019-04-10 11:17:58 -07001980#ifdef CONFIG_DPP2
1981 attr_len += 5;
1982#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001983#ifdef CONFIG_TESTING_OPTIONS
1984 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1985 attr_len += 5;
1986#endif /* CONFIG_TESTING_OPTIONS */
1987 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1988 if (!msg)
1989 return NULL;
1990
1991 attr_start = wpabuf_put(msg, 0);
1992
1993 /* DPP Status */
1994 if (status != 255)
1995 dpp_build_attr_status(msg, status);
1996
1997 /* Responder Bootstrapping Key Hash */
1998 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1999
2000 /* Initiator Bootstrapping Key Hash (mutual authentication) */
2001 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
2002
2003 /* Responder Protocol Key */
2004 if (pr) {
2005 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
2006 wpabuf_put_le16(msg, wpabuf_len(pr));
2007 wpabuf_put_buf(msg, pr);
2008 }
2009
Hai Shalom021b0b52019-04-10 11:17:58 -07002010#ifdef CONFIG_DPP2
2011 /* Protocol Version */
Hai Shalomfdcde762020-04-02 11:19:20 -07002012 if (auth->peer_version >= 2) {
2013 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
2014 wpabuf_put_le16(msg, 1);
2015 wpabuf_put_u8(msg, 2);
2016 }
Hai Shalom021b0b52019-04-10 11:17:58 -07002017#endif /* CONFIG_DPP2 */
2018
Roshan Pius3a1667e2018-07-03 15:17:14 -07002019 attr_end = wpabuf_put(msg, 0);
2020
2021#ifdef CONFIG_TESTING_OPTIONS
2022 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
2023 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2024 goto skip_wrapped_data;
2025 }
2026#endif /* CONFIG_TESTING_OPTIONS */
2027
2028 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
2029 pos = clear;
2030
2031 if (r_nonce) {
2032 /* R-nonce */
2033 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
2034 pos += 2;
2035 WPA_PUT_LE16(pos, nonce_len);
2036 pos += 2;
2037 os_memcpy(pos, r_nonce, nonce_len);
2038 pos += nonce_len;
2039 }
2040
2041 if (i_nonce) {
2042 /* I-nonce */
2043 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
2044 pos += 2;
2045 WPA_PUT_LE16(pos, nonce_len);
2046 pos += 2;
2047 os_memcpy(pos, i_nonce, nonce_len);
2048#ifdef CONFIG_TESTING_OPTIONS
2049 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
2050 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
2051 pos[nonce_len / 2] ^= 0x01;
2052 }
2053#endif /* CONFIG_TESTING_OPTIONS */
2054 pos += nonce_len;
2055 }
2056
2057#ifdef CONFIG_TESTING_OPTIONS
2058 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
2059 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
2060 goto skip_r_capab;
2061 }
2062#endif /* CONFIG_TESTING_OPTIONS */
2063
2064 /* R-capabilities */
2065 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
2066 pos += 2;
2067 WPA_PUT_LE16(pos, 1);
2068 pos += 2;
2069 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
2070 DPP_CAPAB_ENROLLEE;
2071 *pos++ = auth->r_capab;
2072#ifdef CONFIG_TESTING_OPTIONS
2073 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
2074 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
2075 pos[-1] = 0;
2076 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
2077 wpa_printf(MSG_INFO,
2078 "DPP: TESTING - incompatible R-capabilities");
2079 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
2080 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
2081 pos[-1] = 0;
2082 else
2083 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
2084 DPP_CAPAB_CONFIGURATOR;
2085 }
2086skip_r_capab:
2087#endif /* CONFIG_TESTING_OPTIONS */
2088
2089 if (wrapped_r_auth) {
2090 /* {R-auth}ke */
2091 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
2092 pos += 2;
2093 WPA_PUT_LE16(pos, wrapped_r_auth_len);
2094 pos += 2;
2095 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
2096 pos += wrapped_r_auth_len;
2097 }
2098
2099 /* OUI, OUI type, Crypto Suite, DPP frame type */
2100 addr[0] = wpabuf_head_u8(msg) + 2;
2101 len[0] = 3 + 1 + 1 + 1;
2102 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2103
2104 /* Attributes before Wrapped Data */
2105 addr[1] = attr_start;
2106 len[1] = attr_end - attr_start;
2107 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
2108
2109 siv_len = pos - clear;
2110 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
2111 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
2112 2, addr, len, wrapped_data) < 0) {
2113 wpabuf_free(msg);
2114 return NULL;
2115 }
2116 siv_len += AES_BLOCK_SIZE;
2117 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2118 wrapped_data, siv_len);
2119
2120 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2121 wpabuf_put_le16(msg, siv_len);
2122 wpabuf_put_data(msg, wrapped_data, siv_len);
2123
2124#ifdef CONFIG_TESTING_OPTIONS
2125 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
2126 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2127 dpp_build_attr_status(msg, DPP_STATUS_OK);
2128 }
2129skip_wrapped_data:
2130#endif /* CONFIG_TESTING_OPTIONS */
2131
2132 wpa_hexdump_buf(MSG_DEBUG,
2133 "DPP: Authentication Response frame attributes", msg);
2134 return msg;
2135}
2136
2137
2138static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
2139 u16 num_modes, unsigned int freq)
2140{
2141 u16 m;
2142 int c, flag;
2143
2144 if (!own_modes || !num_modes)
2145 return 1;
2146
2147 for (m = 0; m < num_modes; m++) {
2148 for (c = 0; c < own_modes[m].num_channels; c++) {
2149 if ((unsigned int) own_modes[m].channels[c].freq !=
2150 freq)
2151 continue;
2152 flag = own_modes[m].channels[c].flag;
2153 if (!(flag & (HOSTAPD_CHAN_DISABLED |
2154 HOSTAPD_CHAN_NO_IR |
2155 HOSTAPD_CHAN_RADAR)))
2156 return 1;
2157 }
2158 }
2159
2160 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
2161 return 0;
2162}
2163
2164
2165static int freq_included(const unsigned int freqs[], unsigned int num,
2166 unsigned int freq)
2167{
2168 while (num > 0) {
2169 if (freqs[--num] == freq)
2170 return 1;
2171 }
2172 return 0;
2173}
2174
2175
2176static void freq_to_start(unsigned int freqs[], unsigned int num,
2177 unsigned int freq)
2178{
2179 unsigned int i;
2180
2181 for (i = 0; i < num; i++) {
2182 if (freqs[i] == freq)
2183 break;
2184 }
2185 if (i == 0 || i >= num)
2186 return;
2187 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
2188 freqs[0] = freq;
2189}
2190
2191
2192static int dpp_channel_intersect(struct dpp_authentication *auth,
2193 struct hostapd_hw_modes *own_modes,
2194 u16 num_modes)
2195{
2196 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
2197 unsigned int i, freq;
2198
2199 for (i = 0; i < peer_bi->num_freq; i++) {
2200 freq = peer_bi->freq[i];
2201 if (freq_included(auth->freq, auth->num_freq, freq))
2202 continue;
2203 if (dpp_channel_ok_init(own_modes, num_modes, freq))
2204 auth->freq[auth->num_freq++] = freq;
2205 }
2206 if (!auth->num_freq) {
2207 wpa_printf(MSG_INFO,
2208 "DPP: No available channels for initiating DPP Authentication");
2209 return -1;
2210 }
2211 auth->curr_freq = auth->freq[0];
2212 return 0;
2213}
2214
2215
2216static int dpp_channel_local_list(struct dpp_authentication *auth,
2217 struct hostapd_hw_modes *own_modes,
2218 u16 num_modes)
2219{
2220 u16 m;
2221 int c, flag;
2222 unsigned int freq;
2223
2224 auth->num_freq = 0;
2225
2226 if (!own_modes || !num_modes) {
2227 auth->freq[0] = 2412;
2228 auth->freq[1] = 2437;
2229 auth->freq[2] = 2462;
2230 auth->num_freq = 3;
2231 return 0;
2232 }
2233
2234 for (m = 0; m < num_modes; m++) {
2235 for (c = 0; c < own_modes[m].num_channels; c++) {
2236 freq = own_modes[m].channels[c].freq;
2237 flag = own_modes[m].channels[c].flag;
2238 if (flag & (HOSTAPD_CHAN_DISABLED |
2239 HOSTAPD_CHAN_NO_IR |
2240 HOSTAPD_CHAN_RADAR))
2241 continue;
2242 if (freq_included(auth->freq, auth->num_freq, freq))
2243 continue;
2244 auth->freq[auth->num_freq++] = freq;
2245 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
2246 m = num_modes;
2247 break;
2248 }
2249 }
2250 }
2251
2252 return auth->num_freq == 0 ? -1 : 0;
2253}
2254
2255
2256static int dpp_prepare_channel_list(struct dpp_authentication *auth,
Hai Shalomfdcde762020-04-02 11:19:20 -07002257 unsigned int neg_freq,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002258 struct hostapd_hw_modes *own_modes,
2259 u16 num_modes)
2260{
2261 int res;
2262 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
2263 unsigned int i;
2264
Hai Shalomfdcde762020-04-02 11:19:20 -07002265 if (!own_modes) {
2266 if (!neg_freq)
2267 return -1;
2268 auth->num_freq = 1;
2269 auth->freq[0] = neg_freq;
2270 return 0;
2271 }
2272
Roshan Pius3a1667e2018-07-03 15:17:14 -07002273 if (auth->peer_bi->num_freq > 0)
2274 res = dpp_channel_intersect(auth, own_modes, num_modes);
2275 else
2276 res = dpp_channel_local_list(auth, own_modes, num_modes);
2277 if (res < 0)
2278 return res;
2279
2280 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2281 * likely channels first. */
2282 freq_to_start(auth->freq, auth->num_freq, 2462);
2283 freq_to_start(auth->freq, auth->num_freq, 2412);
2284 freq_to_start(auth->freq, auth->num_freq, 2437);
2285
2286 auth->freq_idx = 0;
2287 auth->curr_freq = auth->freq[0];
2288
2289 pos = freqs;
2290 end = pos + sizeof(freqs);
2291 for (i = 0; i < auth->num_freq; i++) {
2292 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
2293 if (os_snprintf_error(end - pos, res))
2294 break;
2295 pos += res;
2296 }
2297 *pos = '\0';
2298 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
2299 freqs);
2300
2301 return 0;
2302}
2303
2304
Hai Shalomfdcde762020-04-02 11:19:20 -07002305static int dpp_gen_uri(struct dpp_bootstrap_info *bi)
2306{
2307 char macstr[ETH_ALEN * 2 + 10];
2308 size_t len;
2309
2310 len = 4; /* "DPP:" */
2311 if (bi->chan)
2312 len += 3 + os_strlen(bi->chan); /* C:...; */
2313 if (is_zero_ether_addr(bi->mac_addr))
2314 macstr[0] = '\0';
2315 else
2316 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
2317 MAC2STR(bi->mac_addr));
2318 len += os_strlen(macstr); /* M:...; */
2319 if (bi->info)
2320 len += 3 + os_strlen(bi->info); /* I:...; */
2321 len += 4 + os_strlen(bi->pk); /* K:...;; */
2322
2323 os_free(bi->uri);
2324 bi->uri = os_malloc(len + 1);
2325 if (!bi->uri)
2326 return -1;
2327 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
2328 bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
2329 bi->chan ? ";" : "",
2330 macstr,
2331 bi->info ? "I:" : "", bi->info ? bi->info : "",
2332 bi->info ? ";" : "",
2333 bi->pk);
2334 return 0;
2335}
2336
2337
Roshan Pius3a1667e2018-07-03 15:17:14 -07002338static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
2339{
2340 struct dpp_bootstrap_info *bi;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002341
2342 if (auth->own_bi)
2343 return 0; /* already generated */
2344
2345 bi = os_zalloc(sizeof(*bi));
2346 if (!bi)
2347 return -1;
2348 bi->type = DPP_BOOTSTRAP_QR_CODE;
Hai Shalomfdcde762020-04-02 11:19:20 -07002349 if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
2350 dpp_gen_uri(bi) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002351 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002352 wpa_printf(MSG_DEBUG,
2353 "DPP: Auto-generated own bootstrapping key info: URI %s",
2354 bi->uri);
2355
2356 auth->tmp_own_bi = auth->own_bi = bi;
2357
Roshan Pius3a1667e2018-07-03 15:17:14 -07002358 return 0;
2359fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07002360 dpp_bootstrap_info_free(bi);
2361 return -1;
2362}
2363
2364
Hai Shalomfdcde762020-04-02 11:19:20 -07002365struct dpp_authentication *
2366dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
2367{
2368 struct dpp_authentication *auth;
2369
2370 auth = os_zalloc(sizeof(*auth));
2371 if (!auth)
2372 return NULL;
2373 auth->global = dpp;
2374 auth->msg_ctx = msg_ctx;
2375 auth->conf_resp_status = 255;
2376 return auth;
2377}
2378
2379
2380struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002381 struct dpp_bootstrap_info *peer_bi,
2382 struct dpp_bootstrap_info *own_bi,
2383 u8 dpp_allowed_roles,
2384 unsigned int neg_freq,
2385 struct hostapd_hw_modes *own_modes,
2386 u16 num_modes)
2387{
2388 struct dpp_authentication *auth;
2389 size_t nonce_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002390 size_t secret_len;
2391 struct wpabuf *pi = NULL;
2392 const u8 *r_pubkey_hash, *i_pubkey_hash;
2393#ifdef CONFIG_TESTING_OPTIONS
2394 u8 test_hash[SHA256_MAC_LEN];
2395#endif /* CONFIG_TESTING_OPTIONS */
2396
Hai Shalomfdcde762020-04-02 11:19:20 -07002397 auth = dpp_alloc_auth(dpp, msg_ctx);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002398 if (!auth)
2399 return NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07002400 if (peer_bi->configurator_params &&
2401 dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
2402 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002403 auth->initiator = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002404 auth->waiting_auth_resp = 1;
2405 auth->allowed_roles = dpp_allowed_roles;
2406 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002407 auth->peer_bi = peer_bi;
2408 auth->own_bi = own_bi;
2409 auth->curve = peer_bi->curve;
2410
Roshan Pius3a1667e2018-07-03 15:17:14 -07002411 if (dpp_autogen_bootstrap_key(auth) < 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07002412 dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002413 goto fail;
2414
2415#ifdef CONFIG_TESTING_OPTIONS
2416 if (dpp_nonce_override_len > 0) {
2417 wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
2418 nonce_len = dpp_nonce_override_len;
2419 os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
2420 } else {
2421 nonce_len = auth->curve->nonce_len;
2422 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2423 wpa_printf(MSG_ERROR,
2424 "DPP: Failed to generate I-nonce");
2425 goto fail;
2426 }
2427 }
2428#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002429 nonce_len = auth->curve->nonce_len;
2430 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2431 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
2432 goto fail;
2433 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002434#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002435 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2436
Roshan Pius3a1667e2018-07-03 15:17:14 -07002437#ifdef CONFIG_TESTING_OPTIONS
2438 if (dpp_protocol_key_override_len) {
2439 const struct dpp_curve_params *tmp_curve;
2440
2441 wpa_printf(MSG_INFO,
2442 "DPP: TESTING - override protocol key");
2443 auth->own_protocol_key = dpp_set_keypair(
2444 &tmp_curve, dpp_protocol_key_override,
2445 dpp_protocol_key_override_len);
2446 } else {
2447 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2448 }
2449#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002450 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002451#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002452 if (!auth->own_protocol_key)
2453 goto fail;
2454
2455 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2456 if (!pi)
2457 goto fail;
2458
2459 /* ECDH: M = pI * BR */
Hai Shalomc3565922019-10-28 11:58:20 -07002460 if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
2461 auth->Mx, &secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002462 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002463 auth->secret_len = secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002464
2465 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2466 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002467 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002468
2469 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2470 auth->curve->hash_len) < 0)
2471 goto fail;
2472
Roshan Pius3a1667e2018-07-03 15:17:14 -07002473 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2474 i_pubkey_hash = auth->own_bi->pubkey_hash;
2475
2476#ifdef CONFIG_TESTING_OPTIONS
2477 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2478 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2479 r_pubkey_hash = NULL;
2480 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2481 wpa_printf(MSG_INFO,
2482 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2483 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2484 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2485 r_pubkey_hash = test_hash;
2486 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2487 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2488 i_pubkey_hash = NULL;
2489 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2490 wpa_printf(MSG_INFO,
2491 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2492 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2493 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2494 i_pubkey_hash = test_hash;
2495 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2496 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2497 wpabuf_free(pi);
2498 pi = NULL;
2499 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2500 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2501 wpabuf_free(pi);
2502 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2503 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2504 goto fail;
2505 }
2506#endif /* CONFIG_TESTING_OPTIONS */
2507
Hai Shalomfdcde762020-04-02 11:19:20 -07002508 if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq)
2509 neg_freq = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002510 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
2511 i_pubkey_hash, neg_freq);
2512 if (!auth->req_msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002513 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002514
Roshan Pius3a1667e2018-07-03 15:17:14 -07002515out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002516 wpabuf_free(pi);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002517 return auth;
2518fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002519 dpp_auth_deinit(auth);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002520 auth = NULL;
2521 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002522}
2523
2524
Hai Shalom021b0b52019-04-10 11:17:58 -07002525static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
2526 const char *json)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002527{
2528 size_t nonce_len;
2529 size_t json_len, clear_len;
2530 struct wpabuf *clear = NULL, *msg = NULL;
2531 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002532 size_t attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002533
2534 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2535
2536 nonce_len = auth->curve->nonce_len;
2537 if (random_get_bytes(auth->e_nonce, nonce_len)) {
2538 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2539 goto fail;
2540 }
2541 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2542 json_len = os_strlen(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002543 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002544
2545 /* { E-nonce, configAttrib }ke */
2546 clear_len = 4 + nonce_len + 4 + json_len;
2547 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002548 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2549#ifdef CONFIG_TESTING_OPTIONS
2550 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
2551 attr_len += 5;
2552#endif /* CONFIG_TESTING_OPTIONS */
2553 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002554 if (!clear || !msg)
2555 goto fail;
2556
Roshan Pius3a1667e2018-07-03 15:17:14 -07002557#ifdef CONFIG_TESTING_OPTIONS
2558 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2559 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2560 goto skip_e_nonce;
2561 }
2562 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
2563 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
2564 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2565 wpabuf_put_le16(clear, nonce_len - 1);
2566 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
2567 goto skip_e_nonce;
2568 }
2569 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2570 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2571 goto skip_wrapped_data;
2572 }
2573#endif /* CONFIG_TESTING_OPTIONS */
2574
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002575 /* E-nonce */
2576 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2577 wpabuf_put_le16(clear, nonce_len);
2578 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2579
Roshan Pius3a1667e2018-07-03 15:17:14 -07002580#ifdef CONFIG_TESTING_OPTIONS
2581skip_e_nonce:
2582 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2583 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2584 goto skip_conf_attr_obj;
2585 }
2586#endif /* CONFIG_TESTING_OPTIONS */
2587
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002588 /* configAttrib */
2589 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2590 wpabuf_put_le16(clear, json_len);
2591 wpabuf_put_data(clear, json, json_len);
2592
Roshan Pius3a1667e2018-07-03 15:17:14 -07002593#ifdef CONFIG_TESTING_OPTIONS
2594skip_conf_attr_obj:
2595#endif /* CONFIG_TESTING_OPTIONS */
2596
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002597 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2598 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2599 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2600
2601 /* No AES-SIV AD */
2602 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2603 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2604 wpabuf_head(clear), wpabuf_len(clear),
2605 0, NULL, NULL, wrapped) < 0)
2606 goto fail;
2607 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2608 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2609
Roshan Pius3a1667e2018-07-03 15:17:14 -07002610#ifdef CONFIG_TESTING_OPTIONS
2611 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2612 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2613 dpp_build_attr_status(msg, DPP_STATUS_OK);
2614 }
2615skip_wrapped_data:
2616#endif /* CONFIG_TESTING_OPTIONS */
2617
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002618 wpa_hexdump_buf(MSG_DEBUG,
2619 "DPP: Configuration Request frame attributes", msg);
2620 wpabuf_free(clear);
2621 return msg;
2622
2623fail:
2624 wpabuf_free(clear);
2625 wpabuf_free(msg);
2626 return NULL;
2627}
2628
2629
Hai Shalom021b0b52019-04-10 11:17:58 -07002630static void dpp_write_adv_proto(struct wpabuf *buf)
2631{
2632 /* Advertisement Protocol IE */
2633 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
2634 wpabuf_put_u8(buf, 8); /* Length */
2635 wpabuf_put_u8(buf, 0x7f);
2636 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
2637 wpabuf_put_u8(buf, 5);
2638 wpabuf_put_be24(buf, OUI_WFA);
2639 wpabuf_put_u8(buf, DPP_OUI_TYPE);
2640 wpabuf_put_u8(buf, 0x01);
2641}
2642
2643
2644static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
2645{
2646 /* GAS Query */
2647 wpabuf_put_le16(buf, wpabuf_len(query));
2648 wpabuf_put_buf(buf, query);
2649}
2650
2651
2652struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2653 const char *json)
2654{
2655 struct wpabuf *buf, *conf_req;
2656
2657 conf_req = dpp_build_conf_req_attr(auth, json);
2658 if (!conf_req) {
2659 wpa_printf(MSG_DEBUG,
2660 "DPP: No configuration request data available");
2661 return NULL;
2662 }
2663
2664 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
2665 if (!buf) {
2666 wpabuf_free(conf_req);
2667 return NULL;
2668 }
2669
2670 dpp_write_adv_proto(buf);
2671 dpp_write_gas_query(buf, conf_req);
2672 wpabuf_free(conf_req);
2673 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
2674
2675 return buf;
2676}
2677
2678
Hai Shalomc3565922019-10-28 11:58:20 -07002679struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002680 const char *name,
2681 enum dpp_netrole netrole,
Hai Shalomc3565922019-10-28 11:58:20 -07002682 const char *mud_url, int *opclasses)
2683{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002684 size_t len, name_len;
Hai Shalomc3565922019-10-28 11:58:20 -07002685 const char *tech = "infra";
2686 const char *dpp_name;
Hai Shalomc3565922019-10-28 11:58:20 -07002687 struct wpabuf *buf, *json;
2688
2689#ifdef CONFIG_TESTING_OPTIONS
2690 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
2691 static const char *bogus_tech = "knfra";
2692
2693 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
2694 tech = bogus_tech;
2695 }
2696#endif /* CONFIG_TESTING_OPTIONS */
2697
2698 dpp_name = name ? name : "Test";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002699 name_len = os_strlen(dpp_name);
Hai Shalomc3565922019-10-28 11:58:20 -07002700
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002701 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
Hai Shalomc3565922019-10-28 11:58:20 -07002702 if (mud_url && mud_url[0])
2703 len += 10 + os_strlen(mud_url);
2704 json = wpabuf_alloc(len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002705 if (!json)
2706 return NULL;
2707
2708 json_start_object(json, NULL);
2709 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
2710 wpabuf_free(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002711 return NULL;
2712 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002713 json_value_sep(json);
2714 json_add_string(json, "wi-fi_tech", tech);
2715 json_value_sep(json);
2716 json_add_string(json, "netRole", dpp_netrole_str(netrole));
2717 if (mud_url && mud_url[0]) {
2718 json_value_sep(json);
2719 json_add_string(json, "mudurl", mud_url);
2720 }
Hai Shalomc3565922019-10-28 11:58:20 -07002721 if (opclasses) {
2722 int i;
2723
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002724 json_value_sep(json);
2725 json_start_array(json, "bandSupport");
Hai Shalomc3565922019-10-28 11:58:20 -07002726 for (i = 0; opclasses[i]; i++)
2727 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002728 json_end_array(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002729 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002730 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002731
2732 buf = dpp_build_conf_req(auth, wpabuf_head(json));
2733 wpabuf_free(json);
2734
2735 return buf;
2736}
2737
2738
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002739static void dpp_auth_success(struct dpp_authentication *auth)
2740{
2741 wpa_printf(MSG_DEBUG,
2742 "DPP: Authentication success - clear temporary keys");
2743 os_memset(auth->Mx, 0, sizeof(auth->Mx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002744 auth->Mx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002745 os_memset(auth->Nx, 0, sizeof(auth->Nx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002746 auth->Nx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002747 os_memset(auth->Lx, 0, sizeof(auth->Lx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002748 auth->Lx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002749 os_memset(auth->k1, 0, sizeof(auth->k1));
2750 os_memset(auth->k2, 0, sizeof(auth->k2));
2751
2752 auth->auth_success = 1;
2753}
2754
2755
2756static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2757{
2758 struct wpabuf *pix, *prx, *bix, *brx;
2759 const u8 *addr[7];
2760 size_t len[7];
2761 size_t i, num_elem = 0;
2762 size_t nonce_len;
2763 u8 zero = 0;
2764 int res = -1;
2765
2766 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2767 nonce_len = auth->curve->nonce_len;
2768
2769 if (auth->initiator) {
2770 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2771 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2772 if (auth->own_bi)
2773 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2774 else
2775 bix = NULL;
2776 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2777 } else {
2778 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2779 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2780 if (auth->peer_bi)
2781 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2782 else
2783 bix = NULL;
2784 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2785 }
2786 if (!pix || !prx || !brx)
2787 goto fail;
2788
2789 addr[num_elem] = auth->i_nonce;
2790 len[num_elem] = nonce_len;
2791 num_elem++;
2792
2793 addr[num_elem] = auth->r_nonce;
2794 len[num_elem] = nonce_len;
2795 num_elem++;
2796
2797 addr[num_elem] = wpabuf_head(pix);
2798 len[num_elem] = wpabuf_len(pix) / 2;
2799 num_elem++;
2800
2801 addr[num_elem] = wpabuf_head(prx);
2802 len[num_elem] = wpabuf_len(prx) / 2;
2803 num_elem++;
2804
2805 if (bix) {
2806 addr[num_elem] = wpabuf_head(bix);
2807 len[num_elem] = wpabuf_len(bix) / 2;
2808 num_elem++;
2809 }
2810
2811 addr[num_elem] = wpabuf_head(brx);
2812 len[num_elem] = wpabuf_len(brx) / 2;
2813 num_elem++;
2814
2815 addr[num_elem] = &zero;
2816 len[num_elem] = 1;
2817 num_elem++;
2818
2819 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2820 for (i = 0; i < num_elem; i++)
2821 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2822 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
2823 if (res == 0)
2824 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2825 auth->curve->hash_len);
2826fail:
2827 wpabuf_free(pix);
2828 wpabuf_free(prx);
2829 wpabuf_free(bix);
2830 wpabuf_free(brx);
2831 return res;
2832}
2833
2834
2835static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2836{
2837 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2838 const u8 *addr[7];
2839 size_t len[7];
2840 size_t i, num_elem = 0;
2841 size_t nonce_len;
2842 u8 one = 1;
2843 int res = -1;
2844
2845 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2846 nonce_len = auth->curve->nonce_len;
2847
2848 if (auth->initiator) {
2849 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2850 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2851 if (auth->own_bi)
2852 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2853 else
2854 bix = NULL;
2855 if (!auth->peer_bi)
2856 goto fail;
2857 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2858 } else {
2859 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2860 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2861 if (auth->peer_bi)
2862 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2863 else
2864 bix = NULL;
2865 if (!auth->own_bi)
2866 goto fail;
2867 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2868 }
2869 if (!pix || !prx || !brx)
2870 goto fail;
2871
2872 addr[num_elem] = auth->r_nonce;
2873 len[num_elem] = nonce_len;
2874 num_elem++;
2875
2876 addr[num_elem] = auth->i_nonce;
2877 len[num_elem] = nonce_len;
2878 num_elem++;
2879
2880 addr[num_elem] = wpabuf_head(prx);
2881 len[num_elem] = wpabuf_len(prx) / 2;
2882 num_elem++;
2883
2884 addr[num_elem] = wpabuf_head(pix);
2885 len[num_elem] = wpabuf_len(pix) / 2;
2886 num_elem++;
2887
2888 addr[num_elem] = wpabuf_head(brx);
2889 len[num_elem] = wpabuf_len(brx) / 2;
2890 num_elem++;
2891
2892 if (bix) {
2893 addr[num_elem] = wpabuf_head(bix);
2894 len[num_elem] = wpabuf_len(bix) / 2;
2895 num_elem++;
2896 }
2897
2898 addr[num_elem] = &one;
2899 len[num_elem] = 1;
2900 num_elem++;
2901
2902 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2903 for (i = 0; i < num_elem; i++)
2904 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2905 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
2906 if (res == 0)
2907 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2908 auth->curve->hash_len);
2909fail:
2910 wpabuf_free(pix);
2911 wpabuf_free(prx);
2912 wpabuf_free(bix);
2913 wpabuf_free(brx);
2914 return res;
2915}
2916
2917
2918static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2919{
2920 const EC_GROUP *group;
2921 EC_POINT *l = NULL;
2922 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2923 const EC_POINT *BI_point;
2924 BN_CTX *bnctx;
2925 BIGNUM *lx, *sum, *q;
2926 const BIGNUM *bR_bn, *pR_bn;
2927 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002928
2929 /* L = ((bR + pR) modulo q) * BI */
2930
2931 bnctx = BN_CTX_new();
2932 sum = BN_new();
2933 q = BN_new();
2934 lx = BN_new();
2935 if (!bnctx || !sum || !q || !lx)
2936 goto fail;
2937 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2938 if (!BI)
2939 goto fail;
2940 BI_point = EC_KEY_get0_public_key(BI);
2941 group = EC_KEY_get0_group(BI);
2942 if (!group)
2943 goto fail;
2944
2945 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2946 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2947 if (!bR || !pR)
2948 goto fail;
2949 bR_bn = EC_KEY_get0_private_key(bR);
2950 pR_bn = EC_KEY_get0_private_key(pR);
2951 if (!bR_bn || !pR_bn)
2952 goto fail;
2953 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2954 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2955 goto fail;
2956 l = EC_POINT_new(group);
2957 if (!l ||
2958 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2959 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2960 bnctx) != 1) {
2961 wpa_printf(MSG_ERROR,
2962 "OpenSSL: failed: %s",
2963 ERR_error_string(ERR_get_error(), NULL));
2964 goto fail;
2965 }
2966
Roshan Pius3a1667e2018-07-03 15:17:14 -07002967 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002968 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002969 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002970 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002971 ret = 0;
2972fail:
2973 EC_POINT_clear_free(l);
2974 EC_KEY_free(BI);
2975 EC_KEY_free(bR);
2976 EC_KEY_free(pR);
2977 BN_clear_free(lx);
2978 BN_clear_free(sum);
2979 BN_free(q);
2980 BN_CTX_free(bnctx);
2981 return ret;
2982}
2983
2984
2985static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2986{
2987 const EC_GROUP *group;
2988 EC_POINT *l = NULL, *sum = NULL;
2989 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2990 const EC_POINT *BR_point, *PR_point;
2991 BN_CTX *bnctx;
2992 BIGNUM *lx;
2993 const BIGNUM *bI_bn;
2994 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002995
2996 /* L = bI * (BR + PR) */
2997
2998 bnctx = BN_CTX_new();
2999 lx = BN_new();
3000 if (!bnctx || !lx)
3001 goto fail;
3002 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
3003 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
3004 if (!BR || !PR)
3005 goto fail;
3006 BR_point = EC_KEY_get0_public_key(BR);
3007 PR_point = EC_KEY_get0_public_key(PR);
3008
3009 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
3010 if (!bI)
3011 goto fail;
3012 group = EC_KEY_get0_group(bI);
3013 bI_bn = EC_KEY_get0_private_key(bI);
3014 if (!group || !bI_bn)
3015 goto fail;
3016 sum = EC_POINT_new(group);
3017 l = EC_POINT_new(group);
3018 if (!sum || !l ||
3019 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
3020 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
3021 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
3022 bnctx) != 1) {
3023 wpa_printf(MSG_ERROR,
3024 "OpenSSL: failed: %s",
3025 ERR_error_string(ERR_get_error(), NULL));
3026 goto fail;
3027 }
3028
Roshan Pius3a1667e2018-07-03 15:17:14 -07003029 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003030 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003031 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003032 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003033 ret = 0;
3034fail:
3035 EC_POINT_clear_free(l);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08003036 EC_POINT_clear_free(sum);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003037 EC_KEY_free(bI);
3038 EC_KEY_free(BR);
3039 EC_KEY_free(PR);
3040 BN_clear_free(lx);
3041 BN_CTX_free(bnctx);
3042 return ret;
3043}
3044
3045
Roshan Pius3a1667e2018-07-03 15:17:14 -07003046static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003047{
3048 size_t nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003049 size_t secret_len;
3050 struct wpabuf *msg, *pr = NULL;
3051 u8 r_auth[4 + DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07003052 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003053 size_t wrapped_r_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003054 int ret = -1;
3055 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
3056 enum dpp_status_error status = DPP_STATUS_OK;
3057#ifdef CONFIG_TESTING_OPTIONS
3058 u8 test_hash[SHA256_MAC_LEN];
3059#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003060
3061 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003062 if (!auth->own_bi)
3063 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003064
Roshan Pius3a1667e2018-07-03 15:17:14 -07003065#ifdef CONFIG_TESTING_OPTIONS
3066 if (dpp_nonce_override_len > 0) {
3067 wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
3068 nonce_len = dpp_nonce_override_len;
3069 os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
3070 } else {
3071 nonce_len = auth->curve->nonce_len;
3072 if (random_get_bytes(auth->r_nonce, nonce_len)) {
3073 wpa_printf(MSG_ERROR,
3074 "DPP: Failed to generate R-nonce");
3075 goto fail;
3076 }
3077 }
3078#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003079 nonce_len = auth->curve->nonce_len;
3080 if (random_get_bytes(auth->r_nonce, nonce_len)) {
3081 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
3082 goto fail;
3083 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003084#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003085 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
3086
Hai Shalom81f62d82019-07-22 12:10:00 -07003087 EVP_PKEY_free(auth->own_protocol_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003088#ifdef CONFIG_TESTING_OPTIONS
3089 if (dpp_protocol_key_override_len) {
3090 const struct dpp_curve_params *tmp_curve;
3091
3092 wpa_printf(MSG_INFO,
3093 "DPP: TESTING - override protocol key");
3094 auth->own_protocol_key = dpp_set_keypair(
3095 &tmp_curve, dpp_protocol_key_override,
3096 dpp_protocol_key_override_len);
3097 } else {
3098 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
3099 }
3100#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003101 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003102#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003103 if (!auth->own_protocol_key)
3104 goto fail;
3105
3106 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
3107 if (!pr)
3108 goto fail;
3109
3110 /* ECDH: N = pR * PI */
Hai Shalomc3565922019-10-28 11:58:20 -07003111 if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
3112 auth->Nx, &secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003113 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003114
3115 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3116 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003117 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003118
3119 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3120 auth->curve->hash_len) < 0)
3121 goto fail;
3122
3123 if (auth->own_bi && auth->peer_bi) {
3124 /* Mutual authentication */
3125 if (dpp_auth_derive_l_responder(auth) < 0)
3126 goto fail;
3127 }
3128
3129 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3130 goto fail;
3131
3132 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3133 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
3134 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003135 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
3136 goto fail;
3137#ifdef CONFIG_TESTING_OPTIONS
3138 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
3139 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
3140 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3141 }
3142#endif /* CONFIG_TESTING_OPTIONS */
3143 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003144 r_auth, 4 + auth->curve->hash_len,
3145 0, NULL, NULL, wrapped_r_auth) < 0)
3146 goto fail;
3147 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
3148 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
3149 wrapped_r_auth, wrapped_r_auth_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003150 w_r_auth = wrapped_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003151
Roshan Pius3a1667e2018-07-03 15:17:14 -07003152 r_pubkey_hash = auth->own_bi->pubkey_hash;
3153 if (auth->peer_bi)
3154 i_pubkey_hash = auth->peer_bi->pubkey_hash;
3155 else
3156 i_pubkey_hash = NULL;
3157
3158 i_nonce = auth->i_nonce;
3159 r_nonce = auth->r_nonce;
3160
3161#ifdef CONFIG_TESTING_OPTIONS
3162 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3163 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3164 r_pubkey_hash = NULL;
3165 } else if (dpp_test ==
3166 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3167 wpa_printf(MSG_INFO,
3168 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3169 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3170 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3171 r_pubkey_hash = test_hash;
3172 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3173 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3174 i_pubkey_hash = NULL;
3175 } else if (dpp_test ==
3176 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3177 wpa_printf(MSG_INFO,
3178 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3179 if (i_pubkey_hash)
3180 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3181 else
3182 os_memset(test_hash, 0, SHA256_MAC_LEN);
3183 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3184 i_pubkey_hash = test_hash;
3185 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
3186 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
3187 wpabuf_free(pr);
3188 pr = NULL;
3189 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
3190 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
3191 wpabuf_free(pr);
3192 pr = wpabuf_alloc(2 * auth->curve->prime_len);
3193 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
3194 goto fail;
3195 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
3196 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
3197 w_r_auth = NULL;
3198 wrapped_r_auth_len = 0;
3199 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
3200 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3201 status = 255;
3202 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
3203 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3204 status = 254;
3205 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
3206 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
3207 r_nonce = NULL;
3208 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
3209 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
3210 i_nonce = NULL;
3211 }
3212#endif /* CONFIG_TESTING_OPTIONS */
3213
3214 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
3215 r_pubkey_hash, i_pubkey_hash,
3216 r_nonce, i_nonce,
3217 w_r_auth, wrapped_r_auth_len,
3218 auth->k2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003219 if (!msg)
3220 goto fail;
3221 wpabuf_free(auth->resp_msg);
3222 auth->resp_msg = msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003223 ret = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003224fail:
3225 wpabuf_free(pr);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003226 return ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003227}
3228
3229
3230static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
3231 enum dpp_status_error status)
3232{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003233 struct wpabuf *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003234 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
3235#ifdef CONFIG_TESTING_OPTIONS
3236 u8 test_hash[SHA256_MAC_LEN];
3237#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003238
Roshan Pius3a1667e2018-07-03 15:17:14 -07003239 if (!auth->own_bi)
3240 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003241 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
3242
Roshan Pius3a1667e2018-07-03 15:17:14 -07003243 r_pubkey_hash = auth->own_bi->pubkey_hash;
3244 if (auth->peer_bi)
3245 i_pubkey_hash = auth->peer_bi->pubkey_hash;
3246 else
3247 i_pubkey_hash = NULL;
3248
3249 i_nonce = auth->i_nonce;
3250
3251#ifdef CONFIG_TESTING_OPTIONS
3252 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3253 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3254 r_pubkey_hash = NULL;
3255 } else if (dpp_test ==
3256 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3257 wpa_printf(MSG_INFO,
3258 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3259 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3260 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3261 r_pubkey_hash = test_hash;
3262 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3263 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3264 i_pubkey_hash = NULL;
3265 } else if (dpp_test ==
3266 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3267 wpa_printf(MSG_INFO,
3268 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3269 if (i_pubkey_hash)
3270 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3271 else
3272 os_memset(test_hash, 0, SHA256_MAC_LEN);
3273 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3274 i_pubkey_hash = test_hash;
3275 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
3276 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
Hai Shalom74f70d42019-02-11 14:42:39 -08003277 status = 255;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003278 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
3279 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
3280 i_nonce = NULL;
3281 }
3282#endif /* CONFIG_TESTING_OPTIONS */
3283
3284 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
3285 r_pubkey_hash, i_pubkey_hash,
3286 NULL, i_nonce, NULL, 0, auth->k1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003287 if (!msg)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003288 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003289 wpabuf_free(auth->resp_msg);
3290 auth->resp_msg = msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003291 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003292}
3293
3294
3295struct dpp_authentication *
Hai Shalomfdcde762020-04-02 11:19:20 -07003296dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
3297 int qr_mutual, struct dpp_bootstrap_info *peer_bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003298 struct dpp_bootstrap_info *own_bi,
3299 unsigned int freq, const u8 *hdr, const u8 *attr_start,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003300 size_t attr_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003301{
3302 EVP_PKEY *pi = NULL;
3303 EVP_PKEY_CTX *ctx = NULL;
3304 size_t secret_len;
3305 const u8 *addr[2];
3306 size_t len[2];
3307 u8 *unwrapped = NULL;
3308 size_t unwrapped_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003309 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
3310 *channel;
3311 u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
3312 i_bootstrap_len, channel_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003313 struct dpp_authentication *auth = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07003314#ifdef CONFIG_DPP2
3315 const u8 *version;
3316 u16 version_len;
3317#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003318
Roshan Pius3a1667e2018-07-03 15:17:14 -07003319#ifdef CONFIG_TESTING_OPTIONS
3320 if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
3321 wpa_printf(MSG_INFO,
3322 "DPP: TESTING - stop at Authentication Request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003323 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003324 }
3325#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003326
Roshan Pius3a1667e2018-07-03 15:17:14 -07003327 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3328 &wrapped_data_len);
3329 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3330 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3331 "Missing or invalid required Wrapped Data attribute");
3332 return NULL;
3333 }
3334 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
3335 wrapped_data, wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003336 attr_len = wrapped_data - 4 - attr_start;
3337
Hai Shalomfdcde762020-04-02 11:19:20 -07003338 auth = dpp_alloc_auth(dpp, msg_ctx);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003339 if (!auth)
3340 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003341 if (peer_bi && peer_bi->configurator_params &&
3342 dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
3343 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003344 auth->peer_bi = peer_bi;
3345 auth->own_bi = own_bi;
3346 auth->curve = own_bi->curve;
3347 auth->curr_freq = freq;
3348
Hai Shalom021b0b52019-04-10 11:17:58 -07003349 auth->peer_version = 1; /* default to the first version */
3350#ifdef CONFIG_DPP2
3351 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3352 &version_len);
3353 if (version) {
3354 if (version_len < 1 || version[0] == 0) {
3355 dpp_auth_fail(auth,
3356 "Invalid Protocol Version attribute");
3357 goto fail;
3358 }
3359 auth->peer_version = version[0];
3360 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3361 auth->peer_version);
3362 }
3363#endif /* CONFIG_DPP2 */
3364
Roshan Pius3a1667e2018-07-03 15:17:14 -07003365 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
3366 &channel_len);
3367 if (channel) {
3368 int neg_freq;
3369
3370 if (channel_len < 2) {
3371 dpp_auth_fail(auth, "Too short Channel attribute");
3372 goto fail;
3373 }
3374
3375 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
3376 wpa_printf(MSG_DEBUG,
3377 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3378 channel[0], channel[1], neg_freq);
3379 if (neg_freq < 0) {
3380 dpp_auth_fail(auth,
3381 "Unsupported Channel attribute value");
3382 goto fail;
3383 }
3384
3385 if (auth->curr_freq != (unsigned int) neg_freq) {
3386 wpa_printf(MSG_DEBUG,
3387 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3388 freq, neg_freq);
3389 auth->curr_freq = neg_freq;
3390 }
3391 }
3392
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003393 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
3394 &i_proto_len);
3395 if (!i_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003396 dpp_auth_fail(auth,
3397 "Missing required Initiator Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003398 goto fail;
3399 }
3400 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
3401 i_proto, i_proto_len);
3402
3403 /* M = bR * PI */
3404 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
3405 if (!pi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003406 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003407 goto fail;
3408 }
3409 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
3410
Hai Shalomc3565922019-10-28 11:58:20 -07003411 if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003412 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003413 auth->secret_len = secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003414
3415 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
3416 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003417 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003418
3419 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
3420 auth->curve->hash_len) < 0)
3421 goto fail;
3422
3423 addr[0] = hdr;
3424 len[0] = DPP_HDR_LEN;
3425 addr[1] = attr_start;
3426 len[1] = attr_len;
3427 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3428 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3429 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3430 wrapped_data, wrapped_data_len);
3431 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3432 unwrapped = os_malloc(unwrapped_len);
3433 if (!unwrapped)
3434 goto fail;
3435 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3436 wrapped_data, wrapped_data_len,
3437 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003438 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003439 goto fail;
3440 }
3441 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3442 unwrapped, unwrapped_len);
3443
3444 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003445 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003446 goto fail;
3447 }
3448
3449 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3450 &i_nonce_len);
3451 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003452 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003453 goto fail;
3454 }
3455 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3456 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
3457
3458 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
3459 DPP_ATTR_I_CAPABILITIES,
3460 &i_capab_len);
3461 if (!i_capab || i_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003462 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003463 goto fail;
3464 }
3465 auth->i_capab = i_capab[0];
3466 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
3467
3468 bin_clear_free(unwrapped, unwrapped_len);
3469 unwrapped = NULL;
3470
3471 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
3472 case DPP_CAPAB_ENROLLEE:
3473 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
3474 wpa_printf(MSG_DEBUG,
3475 "DPP: Local policy does not allow Configurator role");
3476 goto not_compatible;
3477 }
3478 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3479 auth->configurator = 1;
3480 break;
3481 case DPP_CAPAB_CONFIGURATOR:
3482 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
3483 wpa_printf(MSG_DEBUG,
3484 "DPP: Local policy does not allow Enrollee role");
3485 goto not_compatible;
3486 }
3487 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3488 auth->configurator = 0;
3489 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003490 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
3491 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
3492 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3493 auth->configurator = 0;
3494 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
3495 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3496 auth->configurator = 1;
3497 } else {
3498 wpa_printf(MSG_DEBUG,
3499 "DPP: Local policy does not allow Configurator/Enrollee role");
3500 goto not_compatible;
3501 }
3502 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003503 default:
3504 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003505 wpa_msg(auth->msg_ctx, MSG_INFO,
3506 DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
3507 auth->i_capab & DPP_CAPAB_ROLE_MASK);
3508 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003509 }
3510
3511 auth->peer_protocol_key = pi;
3512 pi = NULL;
3513 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
3514 char hex[SHA256_MAC_LEN * 2 + 1];
3515
3516 wpa_printf(MSG_DEBUG,
3517 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3518 if (dpp_auth_build_resp_status(auth,
3519 DPP_STATUS_RESPONSE_PENDING) < 0)
3520 goto fail;
3521 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3522 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3523 &i_bootstrap_len);
3524 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
3525 auth->response_pending = 1;
3526 os_memcpy(auth->waiting_pubkey_hash,
3527 i_bootstrap, i_bootstrap_len);
3528 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
3529 i_bootstrap_len);
3530 } else {
3531 hex[0] = '\0';
3532 }
3533
3534 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
3535 "%s", hex);
3536 return auth;
3537 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003538 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003539 goto fail;
3540
3541 return auth;
3542
3543not_compatible:
3544 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3545 "i-capab=0x%02x", auth->i_capab);
3546 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
3547 auth->configurator = 1;
3548 else
3549 auth->configurator = 0;
3550 auth->peer_protocol_key = pi;
3551 pi = NULL;
3552 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
3553 goto fail;
3554
3555 auth->remove_on_tx_status = 1;
3556 return auth;
3557fail:
3558 bin_clear_free(unwrapped, unwrapped_len);
3559 EVP_PKEY_free(pi);
3560 EVP_PKEY_CTX_free(ctx);
3561 dpp_auth_deinit(auth);
3562 return NULL;
3563}
3564
3565
3566int dpp_notify_new_qr_code(struct dpp_authentication *auth,
3567 struct dpp_bootstrap_info *peer_bi)
3568{
3569 if (!auth || !auth->response_pending ||
3570 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
3571 SHA256_MAC_LEN) != 0)
3572 return 0;
3573
3574 wpa_printf(MSG_DEBUG,
3575 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3576 MACSTR, MAC2STR(auth->peer_mac_addr));
3577 auth->peer_bi = peer_bi;
3578
Roshan Pius3a1667e2018-07-03 15:17:14 -07003579 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003580 return -1;
3581
3582 return 1;
3583}
3584
3585
Roshan Pius3a1667e2018-07-03 15:17:14 -07003586static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
3587 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003588{
3589 struct wpabuf *msg;
3590 u8 i_auth[4 + DPP_MAX_HASH_LEN];
3591 size_t i_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003592 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3593 size_t r_nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003594 const u8 *addr[2];
3595 size_t len[2], attr_len;
3596 u8 *wrapped_i_auth;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003597 u8 *wrapped_r_nonce;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003598 u8 *attr_start, *attr_end;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003599 const u8 *r_pubkey_hash, *i_pubkey_hash;
3600#ifdef CONFIG_TESTING_OPTIONS
3601 u8 test_hash[SHA256_MAC_LEN];
3602#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003603
3604 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3605
3606 i_auth_len = 4 + auth->curve->hash_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003607 r_nonce_len = 4 + auth->curve->nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003608 /* Build DPP Authentication Confirmation frame attributes */
3609 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
Roshan Pius3a1667e2018-07-03 15:17:14 -07003610 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
3611#ifdef CONFIG_TESTING_OPTIONS
3612 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
3613 attr_len += 5;
3614#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003615 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
3616 if (!msg)
3617 goto fail;
3618
3619 attr_start = wpabuf_put(msg, 0);
3620
Roshan Pius3a1667e2018-07-03 15:17:14 -07003621 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3622 if (auth->own_bi)
3623 i_pubkey_hash = auth->own_bi->pubkey_hash;
3624 else
3625 i_pubkey_hash = NULL;
3626
3627#ifdef CONFIG_TESTING_OPTIONS
3628 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3629 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3630 goto skip_status;
3631 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3632 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3633 status = 254;
3634 }
3635#endif /* CONFIG_TESTING_OPTIONS */
3636
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003637 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003638 dpp_build_attr_status(msg, status);
3639
3640#ifdef CONFIG_TESTING_OPTIONS
3641skip_status:
3642 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3643 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3644 r_pubkey_hash = NULL;
3645 } else if (dpp_test ==
3646 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3647 wpa_printf(MSG_INFO,
3648 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3649 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3650 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3651 r_pubkey_hash = test_hash;
3652 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3653 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3654 i_pubkey_hash = NULL;
3655 } else if (dpp_test ==
3656 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3657 wpa_printf(MSG_INFO,
3658 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3659 if (i_pubkey_hash)
3660 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3661 else
3662 os_memset(test_hash, 0, SHA256_MAC_LEN);
3663 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3664 i_pubkey_hash = test_hash;
3665 }
3666#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003667
3668 /* Responder Bootstrapping Key Hash */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003669 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003670
Roshan Pius3a1667e2018-07-03 15:17:14 -07003671 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3672 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
3673
3674#ifdef CONFIG_TESTING_OPTIONS
3675 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3676 goto skip_wrapped_data;
3677 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3678 i_auth_len = 0;
3679#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003680
3681 attr_end = wpabuf_put(msg, 0);
3682
3683 /* OUI, OUI type, Crypto Suite, DPP frame type */
3684 addr[0] = wpabuf_head_u8(msg) + 2;
3685 len[0] = 3 + 1 + 1 + 1;
3686 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3687
3688 /* Attributes before Wrapped Data */
3689 addr[1] = attr_start;
3690 len[1] = attr_end - attr_start;
3691 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3692
Roshan Pius3a1667e2018-07-03 15:17:14 -07003693 if (status == DPP_STATUS_OK) {
3694 /* I-auth wrapped with ke */
3695 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3696 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3697 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
3698
3699#ifdef CONFIG_TESTING_OPTIONS
3700 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3701 goto skip_i_auth;
3702#endif /* CONFIG_TESTING_OPTIONS */
3703
3704 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3705 * 1) */
3706 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3707 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3708 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3709 goto fail;
3710
3711#ifdef CONFIG_TESTING_OPTIONS
3712 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3713 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3714 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3715 }
3716skip_i_auth:
3717#endif /* CONFIG_TESTING_OPTIONS */
3718 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3719 i_auth, i_auth_len,
3720 2, addr, len, wrapped_i_auth) < 0)
3721 goto fail;
3722 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3723 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3724 } else {
3725 /* R-nonce wrapped with k2 */
3726 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3727 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3728 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3729
3730 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3731 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3732 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3733
3734 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3735 r_nonce, r_nonce_len,
3736 2, addr, len, wrapped_r_nonce) < 0)
3737 goto fail;
3738 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3739 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3740 }
3741
3742#ifdef CONFIG_TESTING_OPTIONS
3743 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3744 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
3745 dpp_build_attr_status(msg, DPP_STATUS_OK);
3746 }
3747skip_wrapped_data:
3748#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003749
3750 wpa_hexdump_buf(MSG_DEBUG,
3751 "DPP: Authentication Confirmation frame attributes",
3752 msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003753 if (status == DPP_STATUS_OK)
3754 dpp_auth_success(auth);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003755
3756 return msg;
3757
3758fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07003759 wpabuf_free(msg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003760 return NULL;
3761}
3762
3763
3764static void
3765dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
3766 const u8 *attr_start, size_t attr_len,
3767 const u8 *wrapped_data, u16 wrapped_data_len,
3768 enum dpp_status_error status)
3769{
3770 const u8 *addr[2];
3771 size_t len[2];
3772 u8 *unwrapped = NULL;
3773 size_t unwrapped_len = 0;
3774 const u8 *i_nonce, *r_capab;
3775 u16 i_nonce_len, r_capab_len;
3776
3777 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3778 wpa_printf(MSG_DEBUG,
3779 "DPP: Responder reported incompatible roles");
3780 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3781 wpa_printf(MSG_DEBUG,
3782 "DPP: Responder reported more time needed");
3783 } else {
3784 wpa_printf(MSG_DEBUG,
3785 "DPP: Responder reported failure (status %d)",
3786 status);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003787 dpp_auth_fail(auth, "Responder reported failure");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003788 return;
3789 }
3790
3791 addr[0] = hdr;
3792 len[0] = DPP_HDR_LEN;
3793 addr[1] = attr_start;
3794 len[1] = attr_len;
3795 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3796 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3797 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3798 wrapped_data, wrapped_data_len);
3799 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3800 unwrapped = os_malloc(unwrapped_len);
3801 if (!unwrapped)
3802 goto fail;
3803 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3804 wrapped_data, wrapped_data_len,
3805 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003806 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003807 goto fail;
3808 }
3809 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3810 unwrapped, unwrapped_len);
3811
3812 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003813 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003814 goto fail;
3815 }
3816
3817 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3818 &i_nonce_len);
3819 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003820 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003821 goto fail;
3822 }
3823 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3824 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003825 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003826 goto fail;
3827 }
3828
3829 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3830 DPP_ATTR_R_CAPABILITIES,
3831 &r_capab_len);
3832 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003833 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003834 goto fail;
3835 }
3836 auth->r_capab = r_capab[0];
3837 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3838 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3839 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3840 "r-capab=0x%02x", auth->r_capab);
3841 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003842 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3843
3844 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3845 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3846 wpa_msg(auth->msg_ctx, MSG_INFO,
3847 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3848 role);
3849 } else {
3850 wpa_printf(MSG_DEBUG,
3851 "DPP: Continue waiting for full DPP Authentication Response");
3852 wpa_msg(auth->msg_ctx, MSG_INFO,
3853 DPP_EVENT_RESPONSE_PENDING "%s",
3854 auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
3855 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003856 }
3857fail:
3858 bin_clear_free(unwrapped, unwrapped_len);
3859}
3860
3861
3862struct wpabuf *
3863dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3864 const u8 *attr_start, size_t attr_len)
3865{
3866 EVP_PKEY *pr;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003867 size_t secret_len;
3868 const u8 *addr[2];
3869 size_t len[2];
3870 u8 *unwrapped = NULL, *unwrapped2 = NULL;
3871 size_t unwrapped_len = 0, unwrapped2_len = 0;
3872 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3873 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3874 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3875 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3876 wrapped2_len, r_auth_len;
3877 u8 r_auth2[DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07003878 u8 role;
Hai Shalom021b0b52019-04-10 11:17:58 -07003879#ifdef CONFIG_DPP2
3880 const u8 *version;
3881 u16 version_len;
3882#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003883
3884#ifdef CONFIG_TESTING_OPTIONS
3885 if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
3886 wpa_printf(MSG_INFO,
3887 "DPP: TESTING - stop at Authentication Response");
3888 return NULL;
3889 }
3890#endif /* CONFIG_TESTING_OPTIONS */
3891
Hai Shalom74f70d42019-02-11 14:42:39 -08003892 if (!auth->initiator || !auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003893 dpp_auth_fail(auth, "Unexpected Authentication Response");
3894 return NULL;
3895 }
3896
3897 auth->waiting_auth_resp = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003898
3899 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3900 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003901 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3902 dpp_auth_fail(auth,
3903 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003904 return NULL;
3905 }
3906 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3907 wrapped_data, wrapped_data_len);
3908
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003909 attr_len = wrapped_data - 4 - attr_start;
3910
3911 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3912 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3913 &r_bootstrap_len);
3914 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003915 dpp_auth_fail(auth,
3916 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003917 return NULL;
3918 }
3919 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3920 r_bootstrap, r_bootstrap_len);
3921 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3922 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003923 dpp_auth_fail(auth,
3924 "Unexpected Responder Bootstrapping Key Hash value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003925 wpa_hexdump(MSG_DEBUG,
3926 "DPP: Expected Responder Bootstrapping Key Hash",
3927 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3928 return NULL;
3929 }
3930
3931 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3932 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3933 &i_bootstrap_len);
3934 if (i_bootstrap) {
3935 if (i_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003936 dpp_auth_fail(auth,
3937 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003938 return NULL;
3939 }
3940 wpa_hexdump(MSG_MSGDUMP,
3941 "DPP: Initiator Bootstrapping Key Hash",
3942 i_bootstrap, i_bootstrap_len);
3943 if (!auth->own_bi ||
3944 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3945 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003946 dpp_auth_fail(auth,
3947 "Initiator Bootstrapping Key Hash attribute did not match");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003948 return NULL;
3949 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003950 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3951 /* PKEX bootstrapping mandates use of mutual authentication */
3952 dpp_auth_fail(auth,
3953 "Missing Initiator Bootstrapping Key Hash attribute");
3954 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003955 }
3956
Hai Shalom021b0b52019-04-10 11:17:58 -07003957 auth->peer_version = 1; /* default to the first version */
3958#ifdef CONFIG_DPP2
3959 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3960 &version_len);
3961 if (version) {
3962 if (version_len < 1 || version[0] == 0) {
3963 dpp_auth_fail(auth,
3964 "Invalid Protocol Version attribute");
3965 return NULL;
3966 }
3967 auth->peer_version = version[0];
3968 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3969 auth->peer_version);
3970 }
3971#endif /* CONFIG_DPP2 */
3972
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003973 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3974 &status_len);
3975 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003976 dpp_auth_fail(auth,
3977 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003978 return NULL;
3979 }
3980 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3981 auth->auth_resp_status = status[0];
3982 if (status[0] != DPP_STATUS_OK) {
3983 dpp_auth_resp_rx_status(auth, hdr, attr_start,
3984 attr_len, wrapped_data,
3985 wrapped_data_len, status[0]);
3986 return NULL;
3987 }
3988
Roshan Pius3a1667e2018-07-03 15:17:14 -07003989 if (!i_bootstrap && auth->own_bi) {
3990 wpa_printf(MSG_DEBUG,
3991 "DPP: Responder decided not to use mutual authentication");
3992 auth->own_bi = NULL;
3993 }
3994
3995 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
3996 auth->own_bi != NULL);
3997
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003998 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3999 &r_proto_len);
4000 if (!r_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004001 dpp_auth_fail(auth,
4002 "Missing required Responder Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004003 return NULL;
4004 }
4005 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
4006 r_proto, r_proto_len);
4007
4008 /* N = pI * PR */
4009 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
4010 if (!pr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004011 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004012 return NULL;
4013 }
4014 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
4015
Hai Shalomc3565922019-10-28 11:58:20 -07004016 if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004017 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004018 goto fail;
4019 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004020 EVP_PKEY_free(auth->peer_protocol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004021 auth->peer_protocol_key = pr;
4022 pr = NULL;
4023
4024 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4025 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004026 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004027
4028 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
4029 auth->curve->hash_len) < 0)
4030 goto fail;
4031
4032 addr[0] = hdr;
4033 len[0] = DPP_HDR_LEN;
4034 addr[1] = attr_start;
4035 len[1] = attr_len;
4036 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4037 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4038 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4039 wrapped_data, wrapped_data_len);
4040 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4041 unwrapped = os_malloc(unwrapped_len);
4042 if (!unwrapped)
4043 goto fail;
4044 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
4045 wrapped_data, wrapped_data_len,
4046 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004047 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004048 goto fail;
4049 }
4050 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4051 unwrapped, unwrapped_len);
4052
4053 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004054 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004055 goto fail;
4056 }
4057
4058 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
4059 &r_nonce_len);
4060 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004061 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004062 goto fail;
4063 }
4064 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
4065 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
4066
4067 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
4068 &i_nonce_len);
4069 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004070 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004071 goto fail;
4072 }
4073 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
4074 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004075 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004076 goto fail;
4077 }
4078
Hai Shalom74f70d42019-02-11 14:42:39 -08004079 if (auth->own_bi) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004080 /* Mutual authentication */
4081 if (dpp_auth_derive_l_initiator(auth) < 0)
4082 goto fail;
4083 }
4084
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004085 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
4086 DPP_ATTR_R_CAPABILITIES,
4087 &r_capab_len);
4088 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004089 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004090 goto fail;
4091 }
4092 auth->r_capab = r_capab[0];
4093 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004094 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
4095 if ((auth->allowed_roles ==
4096 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
4097 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
4098 /* Peer selected its role, so move from "either role" to the
4099 * role that is compatible with peer's selection. */
4100 auth->configurator = role == DPP_CAPAB_ENROLLEE;
4101 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
4102 auth->configurator ? "Configurator" : "Enrollee");
4103 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
4104 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004105 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004106 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
4107 "Unexpected role in R-capabilities 0x%02x",
4108 role);
4109 if (role != DPP_CAPAB_ENROLLEE &&
4110 role != DPP_CAPAB_CONFIGURATOR)
4111 goto fail;
4112 bin_clear_free(unwrapped, unwrapped_len);
4113 auth->remove_on_tx_status = 1;
4114 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004115 }
4116
4117 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
4118 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
4119 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004120 dpp_auth_fail(auth,
4121 "Missing or invalid Secondary Wrapped Data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004122 goto fail;
4123 }
4124
4125 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4126 wrapped2, wrapped2_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004127
4128 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
4129 goto fail;
4130
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004131 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
4132 unwrapped2 = os_malloc(unwrapped2_len);
4133 if (!unwrapped2)
4134 goto fail;
4135 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4136 wrapped2, wrapped2_len,
4137 0, NULL, NULL, unwrapped2) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004138 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004139 goto fail;
4140 }
4141 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4142 unwrapped2, unwrapped2_len);
4143
4144 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004145 dpp_auth_fail(auth,
4146 "Invalid attribute in secondary unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004147 goto fail;
4148 }
4149
4150 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
4151 &r_auth_len);
4152 if (!r_auth || r_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004153 dpp_auth_fail(auth,
4154 "Missing or invalid Responder Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004155 goto fail;
4156 }
4157 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
4158 r_auth, r_auth_len);
4159 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4160 if (dpp_gen_r_auth(auth, r_auth2) < 0)
4161 goto fail;
4162 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
4163 r_auth2, r_auth_len);
4164 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004165 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
4166 bin_clear_free(unwrapped, unwrapped_len);
4167 bin_clear_free(unwrapped2, unwrapped2_len);
4168 auth->remove_on_tx_status = 1;
4169 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004170 }
4171
4172 bin_clear_free(unwrapped, unwrapped_len);
4173 bin_clear_free(unwrapped2, unwrapped2_len);
4174
Roshan Pius3a1667e2018-07-03 15:17:14 -07004175#ifdef CONFIG_TESTING_OPTIONS
4176 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
4177 wpa_printf(MSG_INFO,
4178 "DPP: TESTING - Authentication Response in place of Confirm");
4179 if (dpp_auth_build_resp_ok(auth) < 0)
4180 return NULL;
4181 return wpabuf_dup(auth->resp_msg);
4182 }
4183#endif /* CONFIG_TESTING_OPTIONS */
4184
4185 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004186
4187fail:
4188 bin_clear_free(unwrapped, unwrapped_len);
4189 bin_clear_free(unwrapped2, unwrapped2_len);
4190 EVP_PKEY_free(pr);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004191 return NULL;
4192}
4193
4194
Roshan Pius3a1667e2018-07-03 15:17:14 -07004195static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
4196 const u8 *hdr,
4197 const u8 *attr_start, size_t attr_len,
4198 const u8 *wrapped_data,
4199 u16 wrapped_data_len,
4200 enum dpp_status_error status)
4201{
4202 const u8 *addr[2];
4203 size_t len[2];
4204 u8 *unwrapped = NULL;
4205 size_t unwrapped_len = 0;
4206 const u8 *r_nonce;
4207 u16 r_nonce_len;
4208
4209 /* Authentication Confirm failure cases are expected to include
4210 * {R-nonce}k2 in the Wrapped Data attribute. */
4211
4212 addr[0] = hdr;
4213 len[0] = DPP_HDR_LEN;
4214 addr[1] = attr_start;
4215 len[1] = attr_len;
4216 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4217 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4218 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4219 wrapped_data, wrapped_data_len);
4220 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4221 unwrapped = os_malloc(unwrapped_len);
4222 if (!unwrapped) {
4223 dpp_auth_fail(auth, "Authentication failed");
4224 goto fail;
4225 }
4226 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
4227 wrapped_data, wrapped_data_len,
4228 2, addr, len, unwrapped) < 0) {
4229 dpp_auth_fail(auth, "AES-SIV decryption failed");
4230 goto fail;
4231 }
4232 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4233 unwrapped, unwrapped_len);
4234
4235 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4236 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4237 goto fail;
4238 }
4239
4240 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
4241 &r_nonce_len);
4242 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
4243 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
4244 goto fail;
4245 }
4246 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
4247 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
4248 r_nonce, r_nonce_len);
4249 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
4250 auth->r_nonce, r_nonce_len);
4251 dpp_auth_fail(auth, "R-nonce mismatch");
4252 goto fail;
4253 }
4254
4255 if (status == DPP_STATUS_NOT_COMPATIBLE)
4256 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
4257 else if (status == DPP_STATUS_AUTH_FAILURE)
4258 dpp_auth_fail(auth, "Peer reported authentication failure)");
4259
4260fail:
4261 bin_clear_free(unwrapped, unwrapped_len);
4262 return -1;
4263}
4264
4265
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004266int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
4267 const u8 *attr_start, size_t attr_len)
4268{
4269 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
4270 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
4271 i_auth_len;
4272 const u8 *addr[2];
4273 size_t len[2];
4274 u8 *unwrapped = NULL;
4275 size_t unwrapped_len = 0;
4276 u8 i_auth2[DPP_MAX_HASH_LEN];
4277
Roshan Pius3a1667e2018-07-03 15:17:14 -07004278#ifdef CONFIG_TESTING_OPTIONS
4279 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
4280 wpa_printf(MSG_INFO,
4281 "DPP: TESTING - stop at Authentication Confirm");
4282 return -1;
4283 }
4284#endif /* CONFIG_TESTING_OPTIONS */
4285
Hai Shalomfdcde762020-04-02 11:19:20 -07004286 if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) {
4287 wpa_printf(MSG_DEBUG,
4288 "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
4289 auth->initiator, !!auth->own_bi,
4290 auth->waiting_auth_conf);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004291 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
4292 return -1;
4293 }
4294
4295 auth->waiting_auth_conf = 0;
4296
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004297 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4298 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004299 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4300 dpp_auth_fail(auth,
4301 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004302 return -1;
4303 }
4304 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
4305 wrapped_data, wrapped_data_len);
4306
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004307 attr_len = wrapped_data - 4 - attr_start;
4308
4309 r_bootstrap = dpp_get_attr(attr_start, attr_len,
4310 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
4311 &r_bootstrap_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004312 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
4313 dpp_auth_fail(auth,
4314 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004315 return -1;
4316 }
4317 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
4318 r_bootstrap, r_bootstrap_len);
4319 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
4320 SHA256_MAC_LEN) != 0) {
4321 wpa_hexdump(MSG_DEBUG,
4322 "DPP: Expected Responder Bootstrapping Key Hash",
4323 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004324 dpp_auth_fail(auth,
4325 "Responder Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004326 return -1;
4327 }
4328
4329 i_bootstrap = dpp_get_attr(attr_start, attr_len,
4330 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
4331 &i_bootstrap_len);
4332 if (i_bootstrap) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004333 if (i_bootstrap_len != SHA256_MAC_LEN) {
4334 dpp_auth_fail(auth,
4335 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004336 return -1;
4337 }
4338 wpa_hexdump(MSG_MSGDUMP,
4339 "DPP: Initiator Bootstrapping Key Hash",
4340 i_bootstrap, i_bootstrap_len);
4341 if (!auth->peer_bi ||
4342 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
4343 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004344 dpp_auth_fail(auth,
4345 "Initiator Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004346 return -1;
4347 }
Hai Shalom74f70d42019-02-11 14:42:39 -08004348 } else if (auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004349 /* Mutual authentication and peer did not include its
4350 * Bootstrapping Key Hash attribute. */
4351 dpp_auth_fail(auth,
4352 "Missing Initiator Bootstrapping Key Hash attribute");
4353 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004354 }
4355
4356 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
4357 &status_len);
4358 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004359 dpp_auth_fail(auth,
4360 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004361 return -1;
4362 }
4363 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004364 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
4365 status[0] == DPP_STATUS_AUTH_FAILURE)
4366 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
4367 attr_len, wrapped_data,
4368 wrapped_data_len, status[0]);
4369
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004370 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004371 dpp_auth_fail(auth, "Authentication failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004372 return -1;
4373 }
4374
4375 addr[0] = hdr;
4376 len[0] = DPP_HDR_LEN;
4377 addr[1] = attr_start;
4378 len[1] = attr_len;
4379 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4380 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4381 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4382 wrapped_data, wrapped_data_len);
4383 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4384 unwrapped = os_malloc(unwrapped_len);
4385 if (!unwrapped)
4386 return -1;
4387 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4388 wrapped_data, wrapped_data_len,
4389 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004390 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004391 goto fail;
4392 }
4393 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4394 unwrapped, unwrapped_len);
4395
4396 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004397 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004398 goto fail;
4399 }
4400
4401 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
4402 &i_auth_len);
4403 if (!i_auth || i_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004404 dpp_auth_fail(auth,
4405 "Missing or invalid Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004406 goto fail;
4407 }
4408 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
4409 i_auth, i_auth_len);
4410 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4411 if (dpp_gen_i_auth(auth, i_auth2) < 0)
4412 goto fail;
4413 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
4414 i_auth2, i_auth_len);
4415 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004416 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004417 goto fail;
4418 }
4419
4420 bin_clear_free(unwrapped, unwrapped_len);
4421 dpp_auth_success(auth);
4422 return 0;
4423fail:
4424 bin_clear_free(unwrapped, unwrapped_len);
4425 return -1;
4426}
4427
4428
Hai Shalom021b0b52019-04-10 11:17:58 -07004429static int bin_str_eq(const char *val, size_t len, const char *cmp)
4430{
4431 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
4432}
4433
4434
4435struct dpp_configuration * dpp_configuration_alloc(const char *type)
4436{
4437 struct dpp_configuration *conf;
4438 const char *end;
4439 size_t len;
4440
4441 conf = os_zalloc(sizeof(*conf));
4442 if (!conf)
4443 goto fail;
4444
4445 end = os_strchr(type, ' ');
4446 if (end)
4447 len = end - type;
4448 else
4449 len = os_strlen(type);
4450
4451 if (bin_str_eq(type, len, "psk"))
4452 conf->akm = DPP_AKM_PSK;
4453 else if (bin_str_eq(type, len, "sae"))
4454 conf->akm = DPP_AKM_SAE;
4455 else if (bin_str_eq(type, len, "psk-sae") ||
4456 bin_str_eq(type, len, "psk+sae"))
4457 conf->akm = DPP_AKM_PSK_SAE;
4458 else if (bin_str_eq(type, len, "sae-dpp") ||
4459 bin_str_eq(type, len, "dpp+sae"))
4460 conf->akm = DPP_AKM_SAE_DPP;
4461 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
4462 bin_str_eq(type, len, "dpp+psk+sae"))
4463 conf->akm = DPP_AKM_PSK_SAE_DPP;
4464 else if (bin_str_eq(type, len, "dpp"))
4465 conf->akm = DPP_AKM_DPP;
4466 else
4467 goto fail;
4468
4469 return conf;
4470fail:
4471 dpp_configuration_free(conf);
4472 return NULL;
4473}
4474
4475
4476int dpp_akm_psk(enum dpp_akm akm)
4477{
4478 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4479 akm == DPP_AKM_PSK_SAE_DPP;
4480}
4481
4482
4483int dpp_akm_sae(enum dpp_akm akm)
4484{
4485 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
4486 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4487}
4488
4489
4490int dpp_akm_legacy(enum dpp_akm akm)
4491{
4492 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4493 akm == DPP_AKM_SAE;
4494}
4495
4496
4497int dpp_akm_dpp(enum dpp_akm akm)
4498{
4499 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
4500 akm == DPP_AKM_PSK_SAE_DPP;
4501}
4502
4503
4504int dpp_akm_ver2(enum dpp_akm akm)
4505{
4506 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4507}
4508
4509
4510int dpp_configuration_valid(const struct dpp_configuration *conf)
4511{
4512 if (conf->ssid_len == 0)
4513 return 0;
4514 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
4515 return 0;
4516 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
4517 return 0;
4518 return 1;
4519}
4520
4521
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004522void dpp_configuration_free(struct dpp_configuration *conf)
4523{
4524 if (!conf)
4525 return;
4526 str_clear_free(conf->passphrase);
Hai Shalomce48b4a2018-09-05 11:41:35 -07004527 os_free(conf->group_id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004528 bin_clear_free(conf, sizeof(*conf));
4529}
4530
4531
Hai Shalomc3565922019-10-28 11:58:20 -07004532static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
4533 const char *cmd, int idx)
Hai Shalom021b0b52019-04-10 11:17:58 -07004534{
4535 const char *pos, *end;
4536 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
4537 struct dpp_configuration *conf = NULL;
4538
4539 pos = os_strstr(cmd, " conf=sta-");
4540 if (pos) {
4541 conf_sta = dpp_configuration_alloc(pos + 10);
4542 if (!conf_sta)
4543 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07004544 conf_sta->netrole = DPP_NETROLE_STA;
Hai Shalom021b0b52019-04-10 11:17:58 -07004545 conf = conf_sta;
4546 }
4547
4548 pos = os_strstr(cmd, " conf=ap-");
4549 if (pos) {
4550 conf_ap = dpp_configuration_alloc(pos + 9);
4551 if (!conf_ap)
4552 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07004553 conf_ap->netrole = DPP_NETROLE_AP;
Hai Shalom021b0b52019-04-10 11:17:58 -07004554 conf = conf_ap;
4555 }
4556
Hai Shalomfdcde762020-04-02 11:19:20 -07004557 pos = os_strstr(cmd, " conf=configurator");
4558 if (pos)
4559 auth->provision_configurator = 1;
4560
Hai Shalom021b0b52019-04-10 11:17:58 -07004561 if (!conf)
4562 return 0;
4563
4564 pos = os_strstr(cmd, " ssid=");
4565 if (pos) {
4566 pos += 6;
4567 end = os_strchr(pos, ' ');
4568 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
4569 conf->ssid_len /= 2;
4570 if (conf->ssid_len > sizeof(conf->ssid) ||
4571 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
4572 goto fail;
4573 } else {
4574#ifdef CONFIG_TESTING_OPTIONS
4575 /* use a default SSID for legacy testing reasons */
4576 os_memcpy(conf->ssid, "test", 4);
4577 conf->ssid_len = 4;
4578#else /* CONFIG_TESTING_OPTIONS */
4579 goto fail;
4580#endif /* CONFIG_TESTING_OPTIONS */
4581 }
4582
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004583 pos = os_strstr(cmd, " ssid_charset=");
4584 if (pos) {
4585 if (conf_ap) {
4586 wpa_printf(MSG_INFO,
4587 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
4588 goto fail;
4589 }
4590 conf->ssid_charset = atoi(pos + 14);
4591 }
4592
Hai Shalom021b0b52019-04-10 11:17:58 -07004593 pos = os_strstr(cmd, " pass=");
4594 if (pos) {
4595 size_t pass_len;
4596
4597 pos += 6;
4598 end = os_strchr(pos, ' ');
4599 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
4600 pass_len /= 2;
4601 if (pass_len > 63 || pass_len < 8)
4602 goto fail;
4603 conf->passphrase = os_zalloc(pass_len + 1);
4604 if (!conf->passphrase ||
4605 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
4606 goto fail;
4607 }
4608
4609 pos = os_strstr(cmd, " psk=");
4610 if (pos) {
4611 pos += 5;
4612 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
4613 goto fail;
4614 conf->psk_set = 1;
4615 }
4616
4617 pos = os_strstr(cmd, " group_id=");
4618 if (pos) {
4619 size_t group_id_len;
4620
4621 pos += 10;
4622 end = os_strchr(pos, ' ');
4623 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
4624 conf->group_id = os_malloc(group_id_len + 1);
4625 if (!conf->group_id)
4626 goto fail;
4627 os_memcpy(conf->group_id, pos, group_id_len);
4628 conf->group_id[group_id_len] = '\0';
4629 }
4630
4631 pos = os_strstr(cmd, " expiry=");
4632 if (pos) {
4633 long int val;
4634
4635 pos += 8;
4636 val = strtol(pos, NULL, 0);
4637 if (val <= 0)
4638 goto fail;
4639 conf->netaccesskey_expiry = val;
4640 }
4641
4642 if (!dpp_configuration_valid(conf))
4643 goto fail;
4644
Hai Shalomc3565922019-10-28 11:58:20 -07004645 if (idx == 0) {
4646 auth->conf_sta = conf_sta;
4647 auth->conf_ap = conf_ap;
4648 } else if (idx == 1) {
4649 auth->conf2_sta = conf_sta;
4650 auth->conf2_ap = conf_ap;
4651 } else {
4652 goto fail;
4653 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004654 return 0;
4655
4656fail:
4657 dpp_configuration_free(conf_sta);
4658 dpp_configuration_free(conf_ap);
4659 return -1;
4660}
4661
4662
Hai Shalomc3565922019-10-28 11:58:20 -07004663static int dpp_configuration_parse(struct dpp_authentication *auth,
4664 const char *cmd)
4665{
4666 const char *pos;
4667 char *tmp;
4668 size_t len;
4669 int res;
4670
4671 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
4672 if (!pos)
4673 return dpp_configuration_parse_helper(auth, cmd, 0);
4674
4675 len = pos - cmd;
4676 tmp = os_malloc(len + 1);
4677 if (!tmp)
4678 goto fail;
4679 os_memcpy(tmp, cmd, len);
4680 tmp[len] = '\0';
4681 res = dpp_configuration_parse_helper(auth, cmd, 0);
4682 str_clear_free(tmp);
4683 if (res)
4684 goto fail;
4685 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
4686 if (res)
4687 goto fail;
4688 return 0;
4689fail:
4690 dpp_configuration_free(auth->conf_sta);
4691 dpp_configuration_free(auth->conf2_sta);
4692 dpp_configuration_free(auth->conf_ap);
4693 dpp_configuration_free(auth->conf2_ap);
4694 return -1;
4695}
4696
4697
Hai Shalom021b0b52019-04-10 11:17:58 -07004698static struct dpp_configurator *
4699dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
4700{
4701 struct dpp_configurator *conf;
4702
4703 if (!dpp)
4704 return NULL;
4705
4706 dl_list_for_each(conf, &dpp->configurator,
4707 struct dpp_configurator, list) {
4708 if (conf->id == id)
4709 return conf;
4710 }
4711 return NULL;
4712}
4713
4714
Hai Shalomfdcde762020-04-02 11:19:20 -07004715int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
Hai Shalom021b0b52019-04-10 11:17:58 -07004716{
4717 const char *pos;
Hai Shalomfdcde762020-04-02 11:19:20 -07004718 char *tmp = NULL;
4719 int ret = -1;
Hai Shalom021b0b52019-04-10 11:17:58 -07004720
Hai Shalomfdcde762020-04-02 11:19:20 -07004721 if (!cmd || auth->configurator_set)
Hai Shalom021b0b52019-04-10 11:17:58 -07004722 return 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004723 auth->configurator_set = 1;
4724
4725 if (cmd[0] != ' ') {
4726 size_t len;
4727
4728 len = os_strlen(cmd);
4729 tmp = os_malloc(len + 2);
4730 if (!tmp)
4731 goto fail;
4732 tmp[0] = ' ';
4733 os_memcpy(tmp + 1, cmd, len + 1);
4734 cmd = tmp;
4735 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004736
4737 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
4738
4739 pos = os_strstr(cmd, " configurator=");
4740 if (pos) {
4741 pos += 14;
Hai Shalomfdcde762020-04-02 11:19:20 -07004742 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
Hai Shalom021b0b52019-04-10 11:17:58 -07004743 if (!auth->conf) {
4744 wpa_printf(MSG_INFO,
4745 "DPP: Could not find the specified configurator");
Hai Shalomfdcde762020-04-02 11:19:20 -07004746 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07004747 }
4748 }
4749
Hai Shalomc3565922019-10-28 11:58:20 -07004750 pos = os_strstr(cmd, " conn_status=");
4751 if (pos) {
4752 pos += 13;
4753 auth->send_conn_status = atoi(pos);
4754 }
4755
4756 pos = os_strstr(cmd, " akm_use_selector=");
4757 if (pos) {
4758 pos += 18;
4759 auth->akm_use_selector = atoi(pos);
4760 }
4761
Hai Shalom021b0b52019-04-10 11:17:58 -07004762 if (dpp_configuration_parse(auth, cmd) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004763 wpa_msg(auth->msg_ctx, MSG_INFO,
Hai Shalom021b0b52019-04-10 11:17:58 -07004764 "DPP: Failed to set configurator parameters");
Hai Shalomfdcde762020-04-02 11:19:20 -07004765 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07004766 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004767 ret = 0;
4768fail:
4769 os_free(tmp);
4770 return ret;
4771}
4772
4773
4774static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
4775{
4776 while (key) {
4777 struct dpp_asymmetric_key *next = key->next;
4778
4779 EVP_PKEY_free(key->csign);
4780 str_clear_free(key->config_template);
4781 str_clear_free(key->connector_template);
4782 os_free(key);
4783 key = next;
4784 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004785}
4786
4787
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004788void dpp_auth_deinit(struct dpp_authentication *auth)
4789{
Hai Shalomc3565922019-10-28 11:58:20 -07004790 unsigned int i;
4791
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004792 if (!auth)
4793 return;
4794 dpp_configuration_free(auth->conf_ap);
Hai Shalomc3565922019-10-28 11:58:20 -07004795 dpp_configuration_free(auth->conf2_ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004796 dpp_configuration_free(auth->conf_sta);
Hai Shalomc3565922019-10-28 11:58:20 -07004797 dpp_configuration_free(auth->conf2_sta);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004798 EVP_PKEY_free(auth->own_protocol_key);
4799 EVP_PKEY_free(auth->peer_protocol_key);
4800 wpabuf_free(auth->req_msg);
4801 wpabuf_free(auth->resp_msg);
4802 wpabuf_free(auth->conf_req);
Hai Shalomc3565922019-10-28 11:58:20 -07004803 for (i = 0; i < auth->num_conf_obj; i++) {
4804 struct dpp_config_obj *conf = &auth->conf_obj[i];
4805
4806 os_free(conf->connector);
4807 wpabuf_free(conf->c_sign_key);
4808 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004809 dpp_free_asymmetric_key(auth->conf_key_pkg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004810 wpabuf_free(auth->net_access_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004811 dpp_bootstrap_info_free(auth->tmp_own_bi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004812#ifdef CONFIG_TESTING_OPTIONS
4813 os_free(auth->config_obj_override);
4814 os_free(auth->discovery_override);
4815 os_free(auth->groups_override);
4816#endif /* CONFIG_TESTING_OPTIONS */
4817 bin_clear_free(auth, sizeof(*auth));
4818}
4819
4820
4821static struct wpabuf *
4822dpp_build_conf_start(struct dpp_authentication *auth,
4823 struct dpp_configuration *conf, size_t tailroom)
4824{
4825 struct wpabuf *buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004826
4827#ifdef CONFIG_TESTING_OPTIONS
4828 if (auth->discovery_override)
4829 tailroom += os_strlen(auth->discovery_override);
4830#endif /* CONFIG_TESTING_OPTIONS */
4831
4832 buf = wpabuf_alloc(200 + tailroom);
4833 if (!buf)
4834 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004835 json_start_object(buf, NULL);
4836 json_add_string(buf, "wi-fi_tech", "infra");
4837 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004838#ifdef CONFIG_TESTING_OPTIONS
4839 if (auth->discovery_override) {
4840 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
4841 auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004842 wpabuf_put_str(buf, "\"discovery\":");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004843 wpabuf_put_str(buf, auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004844 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004845 return buf;
4846 }
4847#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004848 json_start_object(buf, "discovery");
4849 if (((!conf->ssid_charset || auth->peer_version < 2) &&
4850 json_add_string_escape(buf, "ssid", conf->ssid,
4851 conf->ssid_len) < 0) ||
4852 ((conf->ssid_charset && auth->peer_version >= 2) &&
4853 json_add_base64url(buf, "ssid64", conf->ssid,
4854 conf->ssid_len) < 0)) {
4855 wpabuf_free(buf);
4856 return NULL;
4857 }
4858 if (conf->ssid_charset > 0) {
4859 json_value_sep(buf);
4860 json_add_int(buf, "ssid_charset", conf->ssid_charset);
4861 }
4862 json_end_object(buf);
4863 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004864
4865 return buf;
4866}
4867
4868
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004869static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
4870 const char *kid, const struct dpp_curve_params *curve)
4871{
4872 struct wpabuf *pub;
4873 const u8 *pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004874 int ret = -1;
4875
4876 pub = dpp_get_pubkey_point(key, 0);
4877 if (!pub)
4878 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004879
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004880 json_start_object(buf, name);
4881 json_add_string(buf, "kty", "EC");
4882 json_value_sep(buf);
4883 json_add_string(buf, "crv", curve->jwk_crv);
4884 json_value_sep(buf);
4885 pos = wpabuf_head(pub);
4886 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
4887 goto fail;
4888 json_value_sep(buf);
4889 pos += curve->prime_len;
4890 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
4891 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004892 if (kid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004893 json_value_sep(buf);
4894 json_add_string(buf, "kid", kid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004895 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004896 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004897 ret = 0;
4898fail:
4899 wpabuf_free(pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004900 return ret;
4901}
4902
4903
Hai Shalom021b0b52019-04-10 11:17:58 -07004904static void dpp_build_legacy_cred_params(struct wpabuf *buf,
4905 struct dpp_configuration *conf)
4906{
4907 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004908 json_add_string_escape(buf, "pass", conf->passphrase,
4909 os_strlen(conf->passphrase));
Hai Shalom021b0b52019-04-10 11:17:58 -07004910 } else if (conf->psk_set) {
4911 char psk[2 * sizeof(conf->psk) + 1];
4912
4913 wpa_snprintf_hex(psk, sizeof(psk),
4914 conf->psk, sizeof(conf->psk));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004915 json_add_string(buf, "psk_hex", psk);
4916 forced_memzero(psk, sizeof(psk));
Hai Shalom021b0b52019-04-10 11:17:58 -07004917 }
4918}
4919
4920
Hai Shalomc3565922019-10-28 11:58:20 -07004921static const char * dpp_netrole_str(enum dpp_netrole netrole)
4922{
4923 switch (netrole) {
4924 case DPP_NETROLE_STA:
4925 return "sta";
4926 case DPP_NETROLE_AP:
4927 return "ap";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004928 case DPP_NETROLE_CONFIGURATOR:
4929 return "configurator";
Hai Shalomc3565922019-10-28 11:58:20 -07004930 default:
4931 return "??";
4932 }
4933}
4934
4935
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004936static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07004937dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004938 struct dpp_configuration *conf)
4939{
4940 struct wpabuf *buf = NULL;
4941 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
4942 size_t tailroom;
4943 const struct dpp_curve_params *curve;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004944 struct wpabuf *jws_prot_hdr;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004945 size_t signed1_len, signed2_len, signed3_len;
4946 struct wpabuf *dppcon = NULL;
4947 unsigned char *signature = NULL;
4948 const unsigned char *p;
4949 size_t signature_len;
4950 EVP_MD_CTX *md_ctx = NULL;
4951 ECDSA_SIG *sig = NULL;
4952 char *dot = ".";
4953 const EVP_MD *sign_md;
4954 const BIGNUM *r, *s;
4955 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07004956 int incl_legacy;
4957 enum dpp_akm akm;
Hai Shalomc3565922019-10-28 11:58:20 -07004958 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004959
4960 if (!auth->conf) {
4961 wpa_printf(MSG_INFO,
4962 "DPP: No configurator specified - cannot generate DPP config object");
4963 goto fail;
4964 }
4965 curve = auth->conf->curve;
4966 if (curve->hash_len == SHA256_MAC_LEN) {
4967 sign_md = EVP_sha256();
4968 } else if (curve->hash_len == SHA384_MAC_LEN) {
4969 sign_md = EVP_sha384();
4970 } else if (curve->hash_len == SHA512_MAC_LEN) {
4971 sign_md = EVP_sha512();
4972 } else {
4973 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
4974 goto fail;
4975 }
4976
Hai Shalom021b0b52019-04-10 11:17:58 -07004977 akm = conf->akm;
4978 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
4979 wpa_printf(MSG_DEBUG,
4980 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4981 akm = DPP_AKM_DPP;
4982 }
4983
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004984#ifdef CONFIG_TESTING_OPTIONS
4985 if (auth->groups_override)
4986 extra_len += os_strlen(auth->groups_override);
4987#endif /* CONFIG_TESTING_OPTIONS */
4988
Hai Shalomce48b4a2018-09-05 11:41:35 -07004989 if (conf->group_id)
4990 extra_len += os_strlen(conf->group_id);
4991
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004992 /* Connector (JSON dppCon object) */
4993 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
4994 if (!dppcon)
4995 goto fail;
4996#ifdef CONFIG_TESTING_OPTIONS
4997 if (auth->groups_override) {
4998 wpabuf_put_u8(dppcon, '{');
4999 if (auth->groups_override) {
5000 wpa_printf(MSG_DEBUG,
5001 "DPP: TESTING - groups override: '%s'",
5002 auth->groups_override);
5003 wpabuf_put_str(dppcon, "\"groups\":");
5004 wpabuf_put_str(dppcon, auth->groups_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005005 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005006 }
5007 goto skip_groups;
5008 }
5009#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005010 json_start_object(dppcon, NULL);
5011 json_start_array(dppcon, "groups");
5012 json_start_object(dppcon, NULL);
5013 json_add_string(dppcon, "groupId",
5014 conf->group_id ? conf->group_id : "*");
5015 json_value_sep(dppcon);
5016 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
5017 json_end_object(dppcon);
5018 json_end_array(dppcon);
5019 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005020#ifdef CONFIG_TESTING_OPTIONS
5021skip_groups:
5022#endif /* CONFIG_TESTING_OPTIONS */
5023 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
5024 auth->curve) < 0) {
5025 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
5026 goto fail;
5027 }
5028 if (conf->netaccesskey_expiry) {
5029 struct os_tm tm;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005030 char expiry[30];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005031
5032 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
5033 wpa_printf(MSG_DEBUG,
5034 "DPP: Failed to generate expiry string");
5035 goto fail;
5036 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005037 os_snprintf(expiry, sizeof(expiry),
5038 "%04u-%02u-%02uT%02u:%02u:%02uZ",
5039 tm.year, tm.month, tm.day,
5040 tm.hour, tm.min, tm.sec);
5041 json_value_sep(dppcon);
5042 json_add_string(dppcon, "expiry", expiry);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005043 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005044 json_end_object(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005045 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
5046 (const char *) wpabuf_head(dppcon));
5047
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005048 jws_prot_hdr = wpabuf_alloc(100);
5049 if (!jws_prot_hdr)
5050 goto fail;
5051 json_start_object(jws_prot_hdr, NULL);
5052 json_add_string(jws_prot_hdr, "typ", "dppCon");
5053 json_value_sep(jws_prot_hdr);
5054 json_add_string(jws_prot_hdr, "kid", auth->conf->kid);
5055 json_value_sep(jws_prot_hdr);
5056 json_add_string(jws_prot_hdr, "alg", curve->jws_alg);
5057 json_end_object(jws_prot_hdr);
5058 signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
5059 wpabuf_len(jws_prot_hdr),
5060 &signed1_len);
5061 wpabuf_free(jws_prot_hdr);
5062 signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
5063 &signed2_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005064 if (!signed1 || !signed2)
5065 goto fail;
5066
5067 md_ctx = EVP_MD_CTX_create();
5068 if (!md_ctx)
5069 goto fail;
5070
5071 ERR_clear_error();
5072 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
5073 auth->conf->csign) != 1) {
5074 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
5075 ERR_error_string(ERR_get_error(), NULL));
5076 goto fail;
5077 }
5078 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
5079 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
5080 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
5081 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
5082 ERR_error_string(ERR_get_error(), NULL));
5083 goto fail;
5084 }
5085 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
5086 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
5087 ERR_error_string(ERR_get_error(), NULL));
5088 goto fail;
5089 }
5090 signature = os_malloc(signature_len);
5091 if (!signature)
5092 goto fail;
5093 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
5094 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
5095 ERR_error_string(ERR_get_error(), NULL));
5096 goto fail;
5097 }
5098 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
5099 signature, signature_len);
5100 /* Convert to raw coordinates r,s */
5101 p = signature;
5102 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
5103 if (!sig)
5104 goto fail;
5105 ECDSA_SIG_get0(sig, &r, &s);
5106 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
5107 dpp_bn2bin_pad(s, signature + curve->prime_len,
5108 curve->prime_len) < 0)
5109 goto fail;
5110 signature_len = 2 * curve->prime_len;
5111 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
5112 signature, signature_len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005113 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005114 if (!signed3)
5115 goto fail;
5116
Hai Shalom021b0b52019-04-10 11:17:58 -07005117 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005118 tailroom = 1000;
5119 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
5120 tailroom += signed1_len + signed2_len + signed3_len;
Hai Shalom021b0b52019-04-10 11:17:58 -07005121 if (incl_legacy)
5122 tailroom += 1000;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005123 buf = dpp_build_conf_start(auth, conf, tailroom);
5124 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005125 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005126
Hai Shalomc3565922019-10-28 11:58:20 -07005127 if (auth->akm_use_selector && dpp_akm_ver2(akm))
5128 akm_str = dpp_akm_selector_str(akm);
5129 else
5130 akm_str = dpp_akm_str(akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005131 json_start_object(buf, "cred");
5132 json_add_string(buf, "akm", akm_str);
5133 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07005134 if (incl_legacy) {
5135 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005136 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07005137 }
5138 wpabuf_put_str(buf, "\"signedConnector\":\"");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005139 wpabuf_put_str(buf, signed1);
5140 wpabuf_put_u8(buf, '.');
5141 wpabuf_put_str(buf, signed2);
5142 wpabuf_put_u8(buf, '.');
5143 wpabuf_put_str(buf, signed3);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005144 wpabuf_put_str(buf, "\"");
5145 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005146 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
5147 curve) < 0) {
5148 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
5149 goto fail;
5150 }
5151
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005152 json_end_object(buf);
5153 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005154
5155 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
5156 wpabuf_head(buf), wpabuf_len(buf));
5157
5158out:
5159 EVP_MD_CTX_destroy(md_ctx);
5160 ECDSA_SIG_free(sig);
5161 os_free(signed1);
5162 os_free(signed2);
5163 os_free(signed3);
5164 os_free(signature);
5165 wpabuf_free(dppcon);
5166 return buf;
5167fail:
5168 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
5169 wpabuf_free(buf);
5170 buf = NULL;
5171 goto out;
5172}
5173
5174
5175static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07005176dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005177 struct dpp_configuration *conf)
5178{
5179 struct wpabuf *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07005180 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005181
5182 buf = dpp_build_conf_start(auth, conf, 1000);
5183 if (!buf)
5184 return NULL;
5185
Hai Shalomc3565922019-10-28 11:58:20 -07005186 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
5187 akm_str = dpp_akm_selector_str(conf->akm);
5188 else
5189 akm_str = dpp_akm_str(conf->akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005190 json_start_object(buf, "cred");
5191 json_add_string(buf, "akm", akm_str);
5192 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07005193 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005194 json_end_object(buf);
5195 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005196
5197 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
5198 wpabuf_head(buf), wpabuf_len(buf));
5199
5200 return buf;
5201}
5202
5203
5204static struct wpabuf *
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005205dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
5206 int idx)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005207{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005208 struct dpp_configuration *conf = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005209
5210#ifdef CONFIG_TESTING_OPTIONS
5211 if (auth->config_obj_override) {
Hai Shalomc3565922019-10-28 11:58:20 -07005212 if (idx != 0)
5213 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005214 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
5215 return wpabuf_alloc_copy(auth->config_obj_override,
5216 os_strlen(auth->config_obj_override));
5217 }
5218#endif /* CONFIG_TESTING_OPTIONS */
5219
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005220 if (idx == 0) {
5221 if (netrole == DPP_NETROLE_STA)
5222 conf = auth->conf_sta;
5223 else if (netrole == DPP_NETROLE_AP)
5224 conf = auth->conf_ap;
5225 } else if (idx == 1) {
5226 if (netrole == DPP_NETROLE_STA)
5227 conf = auth->conf2_sta;
5228 else if (netrole == DPP_NETROLE_AP)
5229 conf = auth->conf2_ap;
5230 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005231 if (!conf) {
Hai Shalomc3565922019-10-28 11:58:20 -07005232 if (idx == 0)
5233 wpa_printf(MSG_DEBUG,
5234 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005235 dpp_netrole_str(netrole));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005236 return NULL;
5237 }
5238
Hai Shalomfdcde762020-04-02 11:19:20 -07005239 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
Hai Shalomc3565922019-10-28 11:58:20 -07005240 return dpp_build_conf_obj_dpp(auth, conf);
5241 return dpp_build_conf_obj_legacy(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005242}
5243
5244
Hai Shalomfdcde762020-04-02 11:19:20 -07005245#ifdef CONFIG_DPP2
5246
5247static struct wpabuf * dpp_build_conf_params(void)
5248{
5249 struct wpabuf *buf;
5250 size_t len;
5251 /* TODO: proper template values */
5252 const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
5253 const char *connector_template = NULL;
5254
5255 len = 100 + os_strlen(conf_template);
5256 if (connector_template)
5257 len += os_strlen(connector_template);
5258 buf = wpabuf_alloc(len);
5259 if (!buf)
5260 return NULL;
5261
5262 /*
5263 * DPPConfigurationParameters ::= SEQUENCE {
5264 * configurationTemplate UTF8String,
5265 * connectorTemplate UTF8String OPTIONAL}
5266 */
5267
5268 asn1_put_utf8string(buf, conf_template);
5269 if (connector_template)
5270 asn1_put_utf8string(buf, connector_template);
5271 return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5272}
5273
5274
5275static struct wpabuf * dpp_build_attribute(void)
5276{
5277 struct wpabuf *conf_params, *attr;
5278
5279 /*
5280 * aa-DPPConfigurationParameters ATTRIBUTE ::=
5281 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
5282 *
5283 * Attribute ::= SEQUENCE {
5284 * type OBJECT IDENTIFIER,
5285 * values SET SIZE(1..MAX) OF Type
5286 */
5287 conf_params = dpp_build_conf_params();
5288 conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
5289 ASN1_TAG_SET);
5290 if (!conf_params)
5291 return NULL;
5292
5293 attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
5294 if (!attr) {
5295 wpabuf_clear_free(conf_params);
5296 return NULL;
5297 }
5298
5299 asn1_put_oid(attr, &asn1_dpp_config_params_oid);
5300 wpabuf_put_buf(attr, conf_params);
5301 wpabuf_clear_free(conf_params);
5302
5303 return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5304}
5305
5306
5307static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
5308{
5309 const struct asn1_oid *oid;
5310 struct wpabuf *params, *res;
5311
5312 switch (curve->ike_group) {
5313 case 19:
5314 oid = &asn1_prime256v1_oid;
5315 break;
5316 case 20:
5317 oid = &asn1_secp384r1_oid;
5318 break;
5319 case 21:
5320 oid = &asn1_secp521r1_oid;
5321 break;
5322 case 28:
5323 oid = &asn1_brainpoolP256r1_oid;
5324 break;
5325 case 29:
5326 oid = &asn1_brainpoolP384r1_oid;
5327 break;
5328 case 30:
5329 oid = &asn1_brainpoolP512r1_oid;
5330 break;
5331 default:
5332 return NULL;
5333 }
5334
5335 params = wpabuf_alloc(20);
5336 if (!params)
5337 return NULL;
5338 asn1_put_oid(params, oid); /* namedCurve */
5339
5340 res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
5341 wpabuf_free(params);
5342 return res;
5343}
5344
5345
5346static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
5347{
5348 struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
5349 EC_KEY *eckey;
5350 unsigned char *der = NULL;
5351 int der_len;
5352
5353 eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
5354 if (!eckey)
5355 return NULL;
5356
5357 EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
5358 der_len = i2d_ECPrivateKey(eckey, &der);
5359 if (der_len > 0)
5360 priv_key = wpabuf_alloc_copy(der, der_len);
5361 OPENSSL_free(der);
5362
5363 alg = dpp_build_key_alg(auth->conf->curve);
5364
5365 /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
5366 attr = dpp_build_attribute();
5367 attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
5368 if (!priv_key || !attr || !alg)
5369 goto fail;
5370
5371 /*
5372 * OneAsymmetricKey ::= SEQUENCE {
5373 * version Version,
5374 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
5375 * privateKey PrivateKey,
5376 * attributes [0] Attributes OPTIONAL,
5377 * ...,
5378 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
5379 * ...
5380 * }
5381 */
5382
5383 key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
5384 wpabuf_len(attr));
5385 if (!key)
5386 goto fail;
5387
5388 asn1_put_integer(key, 1); /* version = v2(1) */
5389
5390 /* PrivateKeyAlgorithmIdentifier */
5391 wpabuf_put_buf(key, alg);
5392
5393 /* PrivateKey ::= OCTET STRING */
5394 asn1_put_octet_string(key, priv_key);
5395
5396 /* [0] Attributes OPTIONAL */
5397 asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
5398 wpabuf_put_buf(key, attr);
5399
5400fail:
5401 wpabuf_clear_free(attr);
5402 wpabuf_clear_free(priv_key);
5403 wpabuf_free(alg);
5404
5405 /*
5406 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
5407 *
5408 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
5409 *
5410 * OneAsymmetricKey ::= SEQUENCE
5411 */
5412 return asn1_encaps(asn1_encaps(key,
5413 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
5414 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5415}
5416
5417
5418static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
5419 size_t hash_len)
5420{
5421 struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
5422 const struct asn1_oid *oid;
5423
5424 /*
5425 * PBKDF2-params ::= SEQUENCE {
5426 * salt CHOICE {
5427 * specified OCTET STRING,
5428 * otherSource AlgorithmIdentifier}
5429 * iterationCount INTEGER (1..MAX),
5430 * keyLength INTEGER (1..MAX),
5431 * prf AlgorithmIdentifier}
5432 *
5433 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
5434 * on Configurator signing key length, prf is
5435 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
5436 */
5437
5438 if (hash_len == 32)
5439 oid = &asn1_pbkdf2_hmac_sha256_oid;
5440 else if (hash_len == 48)
5441 oid = &asn1_pbkdf2_hmac_sha384_oid;
5442 else if (hash_len == 64)
5443 oid = &asn1_pbkdf2_hmac_sha512_oid;
5444 else
5445 goto fail;
5446 prf = asn1_build_alg_id(oid, NULL);
5447 if (!prf)
5448 goto fail;
5449 params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
5450 if (!params)
5451 goto fail;
5452 asn1_put_octet_string(params, salt); /* salt.specified */
5453 asn1_put_integer(params, 1000); /* iterationCount */
5454 asn1_put_integer(params, hash_len); /* keyLength */
5455 wpabuf_put_buf(params, prf);
5456 params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5457 if (!params)
5458 goto fail;
5459 buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
5460fail:
5461 wpabuf_free(params);
5462 wpabuf_free(prf);
5463 return buf;
5464}
5465
5466
5467static struct wpabuf *
5468dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
5469 const struct wpabuf *cont_enc_key)
5470{
5471 struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
5472 *key_enc_alg = NULL, *salt;
5473 u8 kek[DPP_MAX_HASH_LEN];
5474 const u8 *key;
5475 size_t key_len;
5476
5477 salt = wpabuf_alloc(64);
5478 if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
5479 goto fail;
5480 wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
5481
5482 /* TODO: For initial testing, use ke as the key. Replace this with a
5483 * new key once that has been defined. */
5484 key = auth->ke;
5485 key_len = auth->curve->hash_len;
5486 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
5487
5488 if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
5489 kek, hash_len)) {
5490 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
5491 goto fail;
5492 }
5493 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
5494 kek, hash_len);
5495
5496 enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
5497 if (!enc_key ||
5498 aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
5499 wpabuf_len(cont_enc_key), 0, NULL, NULL,
5500 wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
5501 goto fail;
5502 wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
5503
5504 /*
5505 * PasswordRecipientInfo ::= SEQUENCE {
5506 * version CMSVersion,
5507 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
5508 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
5509 * encryptedKey EncryptedKey}
5510 *
5511 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
5512 * parameters contains PBKDF2-params SEQUENCE.
5513 */
5514
5515 key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
5516 key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
5517 if (!key_der_alg || !key_enc_alg)
5518 goto fail;
5519 pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
5520 wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
5521 if (!pwri)
5522 goto fail;
5523
5524 /* version = 0 */
5525 asn1_put_integer(pwri, 0);
5526
5527 /* [0] KeyDerivationAlgorithmIdentifier */
5528 asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
5529 wpabuf_len(key_der_alg));
5530 wpabuf_put_buf(pwri, key_der_alg);
5531
5532 /* KeyEncryptionAlgorithmIdentifier */
5533 wpabuf_put_buf(pwri, key_enc_alg);
5534
5535 /* EncryptedKey ::= OCTET STRING */
5536 asn1_put_octet_string(pwri, enc_key);
5537
5538fail:
5539 wpabuf_clear_free(key_der_alg);
5540 wpabuf_free(key_enc_alg);
5541 wpabuf_free(enc_key);
5542 wpabuf_free(salt);
5543 forced_memzero(kek, sizeof(kek));
5544 return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5545}
5546
5547
5548static struct wpabuf *
5549dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
5550 const struct wpabuf *cont_enc_key)
5551{
5552 struct wpabuf *pwri;
5553
5554 /*
5555 * RecipientInfo ::= CHOICE {
5556 * ktri KeyTransRecipientInfo,
5557 * kari [1] KeyAgreeRecipientInfo,
5558 * kekri [2] KEKRecipientInfo,
5559 * pwri [3] PasswordRecipientInfo,
5560 * ori [4] OtherRecipientInfo}
5561 *
5562 * Shall always use the pwri CHOICE.
5563 */
5564
5565 pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
5566 return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
5567}
5568
5569
5570static struct wpabuf *
5571dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
5572 const struct wpabuf *cont_enc_key)
5573{
5574 struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
5575 *enc_alg;
5576 const struct asn1_oid *oid;
5577 size_t enc_cont_len;
5578
5579 /*
5580 * EncryptedContentInfo ::= SEQUENCE {
5581 * contentType ContentType,
5582 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
5583 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
5584 */
5585
5586 if (hash_len == 32)
5587 oid = &asn1_aes_siv_cmac_aead_256_oid;
5588 else if (hash_len == 48)
5589 oid = &asn1_aes_siv_cmac_aead_384_oid;
5590 else if (hash_len == 64)
5591 oid = &asn1_aes_siv_cmac_aead_512_oid;
5592 else
5593 return NULL;
5594
5595 key_pkg = dpp_build_key_pkg(auth);
5596 enc_alg = asn1_build_alg_id(oid, NULL);
5597 if (!key_pkg || !enc_alg)
5598 goto fail;
5599
5600 wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
5601 key_pkg);
5602
5603 enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
5604 enc_cont = wpabuf_alloc(enc_cont_len);
5605 if (!enc_cont ||
5606 aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
5607 wpabuf_head(key_pkg), wpabuf_len(key_pkg),
5608 0, NULL, NULL,
5609 wpabuf_put(enc_cont, enc_cont_len)) < 0)
5610 goto fail;
5611
5612 enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
5613 wpabuf_len(enc_cont));
5614 if (!enc_cont_info)
5615 goto fail;
5616
5617 /* ContentType ::= OBJECT IDENTIFIER */
5618 asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
5619
5620 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
5621 wpabuf_put_buf(enc_cont_info, enc_alg);
5622
5623 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
5624 * EncryptedContent ::= OCTET STRING */
5625 asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
5626 wpabuf_len(enc_cont));
5627 wpabuf_put_buf(enc_cont_info, enc_cont);
5628
5629fail:
5630 wpabuf_clear_free(key_pkg);
5631 wpabuf_free(enc_cont);
5632 wpabuf_free(enc_alg);
5633 return enc_cont_info;
5634}
5635
5636
5637static struct wpabuf * dpp_gen_random(size_t len)
5638{
5639 struct wpabuf *key;
5640
5641 key = wpabuf_alloc(len);
5642 if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
5643 wpabuf_free(key);
5644 key = NULL;
5645 }
5646 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
5647 return key;
5648}
5649
5650
5651static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
5652{
5653 struct wpabuf *env = NULL;
5654 struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
5655 struct wpabuf *cont_enc_key = NULL;
5656 size_t hash_len;
5657
5658 if (!auth->conf) {
5659 wpa_printf(MSG_DEBUG,
5660 "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
5661 return NULL;
5662 }
5663
5664 if (!auth->provision_configurator) {
5665 wpa_printf(MSG_DEBUG,
5666 "DPP: Configurator provisioning not allowed");
5667 return NULL;
5668 }
5669
5670 wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
5671
5672 hash_len = auth->conf->curve->hash_len;
5673 cont_enc_key = dpp_gen_random(hash_len);
5674 if (!cont_enc_key)
5675 goto fail;
5676 recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
5677 enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
5678 if (!recipient_info || !enc_cont_info)
5679 goto fail;
5680
5681 env = wpabuf_alloc(wpabuf_len(recipient_info) +
5682 wpabuf_len(enc_cont_info) +
5683 100);
5684 if (!env)
5685 goto fail;
5686
5687 /*
5688 * DPPEnvelopedData ::= EnvelopedData
5689 *
5690 * EnvelopedData ::= SEQUENCE {
5691 * version CMSVersion,
5692 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
5693 * recipientInfos RecipientInfos,
5694 * encryptedContentInfo EncryptedContentInfo,
5695 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
5696 *
5697 * For DPP, version is 3, both originatorInfo and
5698 * unprotectedAttrs are omitted, and recipientInfos contains a single
5699 * RecipientInfo.
5700 */
5701
5702 /* EnvelopedData.version = 3 */
5703 asn1_put_integer(env, 3);
5704
5705 /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
5706 asn1_put_set(env, recipient_info);
5707
5708 /* EncryptedContentInfo ::= SEQUENCE */
5709 asn1_put_sequence(env, enc_cont_info);
5710
5711 env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5712 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
5713out:
5714 wpabuf_clear_free(cont_enc_key);
5715 wpabuf_clear_free(recipient_info);
5716 wpabuf_free(enc_cont_info);
5717 return env;
5718fail:
5719 wpabuf_free(env);
5720 env = NULL;
5721 goto out;
5722}
5723
5724#endif /* CONFIG_DPP2 */
5725
5726
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005727static struct wpabuf *
5728dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005729 u16 e_nonce_len, enum dpp_netrole netrole)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005730{
Hai Shalomfdcde762020-04-02 11:19:20 -07005731 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005732 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005733 struct wpabuf *clear = NULL, *msg = NULL;
5734 u8 *wrapped;
5735 const u8 *addr[1];
5736 size_t len[1];
5737 enum dpp_status_error status;
5738
Hai Shalomfdcde762020-04-02 11:19:20 -07005739 if (netrole == DPP_NETROLE_CONFIGURATOR) {
5740#ifdef CONFIG_DPP2
5741 env_data = dpp_build_enveloped_data(auth);
5742#endif /* CONFIG_DPP2 */
5743 } else {
5744 conf = dpp_build_conf_obj(auth, netrole, 0);
5745 if (conf) {
5746 wpa_hexdump_ascii(MSG_DEBUG,
5747 "DPP: configurationObject JSON",
5748 wpabuf_head(conf), wpabuf_len(conf));
5749 conf2 = dpp_build_conf_obj(auth, netrole, 1);
5750 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005751 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005752 status = (conf || env_data) ? DPP_STATUS_OK :
5753 DPP_STATUS_CONFIGURE_FAILURE;
Hai Shalom021b0b52019-04-10 11:17:58 -07005754 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005755
Hai Shalomc3565922019-10-28 11:58:20 -07005756 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005757 clear_len = 4 + e_nonce_len;
5758 if (conf)
5759 clear_len += 4 + wpabuf_len(conf);
Hai Shalomc3565922019-10-28 11:58:20 -07005760 if (conf2)
5761 clear_len += 4 + wpabuf_len(conf2);
Hai Shalomfdcde762020-04-02 11:19:20 -07005762 if (env_data)
5763 clear_len += 4 + wpabuf_len(env_data);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005764 if (auth->peer_version >= 2 && auth->send_conn_status &&
5765 netrole == DPP_NETROLE_STA)
Hai Shalomc3565922019-10-28 11:58:20 -07005766 clear_len += 4;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005767 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005768 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
5769#ifdef CONFIG_TESTING_OPTIONS
5770 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
5771 attr_len += 5;
5772#endif /* CONFIG_TESTING_OPTIONS */
5773 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005774 if (!clear || !msg)
5775 goto fail;
5776
Roshan Pius3a1667e2018-07-03 15:17:14 -07005777#ifdef CONFIG_TESTING_OPTIONS
5778 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
5779 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
5780 goto skip_e_nonce;
5781 }
5782 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
5783 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
5784 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5785 wpabuf_put_le16(clear, e_nonce_len);
5786 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
5787 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
5788 goto skip_e_nonce;
5789 }
5790 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
5791 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
5792 goto skip_wrapped_data;
5793 }
5794#endif /* CONFIG_TESTING_OPTIONS */
5795
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005796 /* E-nonce */
5797 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5798 wpabuf_put_le16(clear, e_nonce_len);
5799 wpabuf_put_data(clear, e_nonce, e_nonce_len);
5800
Roshan Pius3a1667e2018-07-03 15:17:14 -07005801#ifdef CONFIG_TESTING_OPTIONS
5802skip_e_nonce:
5803 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
5804 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
5805 goto skip_config_obj;
5806 }
5807#endif /* CONFIG_TESTING_OPTIONS */
5808
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005809 if (conf) {
5810 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5811 wpabuf_put_le16(clear, wpabuf_len(conf));
5812 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005813 }
Hai Shalomc3565922019-10-28 11:58:20 -07005814 if (auth->peer_version >= 2 && conf2) {
5815 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5816 wpabuf_put_le16(clear, wpabuf_len(conf2));
5817 wpabuf_put_buf(clear, conf2);
5818 } else if (conf2) {
5819 wpa_printf(MSG_DEBUG,
5820 "DPP: Second Config Object available, but peer does not support more than one");
5821 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005822 if (env_data) {
5823 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
5824 wpabuf_put_le16(clear, wpabuf_len(env_data));
5825 wpabuf_put_buf(clear, env_data);
5826 }
Hai Shalomc3565922019-10-28 11:58:20 -07005827
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005828 if (auth->peer_version >= 2 && auth->send_conn_status &&
5829 netrole == DPP_NETROLE_STA) {
Hai Shalomc3565922019-10-28 11:58:20 -07005830 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
5831 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
5832 wpabuf_put_le16(clear, 0);
5833 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005834
Roshan Pius3a1667e2018-07-03 15:17:14 -07005835#ifdef CONFIG_TESTING_OPTIONS
5836skip_config_obj:
5837 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
5838 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
5839 goto skip_status;
5840 }
5841 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
5842 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
5843 status = 255;
5844 }
5845#endif /* CONFIG_TESTING_OPTIONS */
5846
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005847 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07005848 dpp_build_attr_status(msg, status);
5849
5850#ifdef CONFIG_TESTING_OPTIONS
5851skip_status:
5852#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005853
5854 addr[0] = wpabuf_head(msg);
5855 len[0] = wpabuf_len(msg);
5856 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5857
5858 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
5859 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5860 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5861
5862 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
5863 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
5864 wpabuf_head(clear), wpabuf_len(clear),
5865 1, addr, len, wrapped) < 0)
5866 goto fail;
5867 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5868 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005869
5870#ifdef CONFIG_TESTING_OPTIONS
5871 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
5872 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
5873 dpp_build_attr_status(msg, DPP_STATUS_OK);
5874 }
5875skip_wrapped_data:
5876#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005877
5878 wpa_hexdump_buf(MSG_DEBUG,
5879 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005880out:
Hai Shalomfdcde762020-04-02 11:19:20 -07005881 wpabuf_clear_free(conf);
5882 wpabuf_clear_free(conf2);
5883 wpabuf_clear_free(env_data);
5884 wpabuf_clear_free(clear);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005885
5886 return msg;
5887fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005888 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005889 msg = NULL;
5890 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005891}
5892
5893
5894struct wpabuf *
5895dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
5896 size_t attr_len)
5897{
5898 const u8 *wrapped_data, *e_nonce, *config_attr;
5899 u16 wrapped_data_len, e_nonce_len, config_attr_len;
5900 u8 *unwrapped = NULL;
5901 size_t unwrapped_len = 0;
5902 struct wpabuf *resp = NULL;
5903 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005904 enum dpp_netrole netrole;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005905
Roshan Pius3a1667e2018-07-03 15:17:14 -07005906#ifdef CONFIG_TESTING_OPTIONS
5907 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
5908 wpa_printf(MSG_INFO,
5909 "DPP: TESTING - stop at Config Request");
5910 return NULL;
5911 }
5912#endif /* CONFIG_TESTING_OPTIONS */
5913
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005914 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005915 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005916 return NULL;
5917 }
5918
5919 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
5920 &wrapped_data_len);
5921 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005922 dpp_auth_fail(auth,
5923 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005924 return NULL;
5925 }
5926
5927 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5928 wrapped_data, wrapped_data_len);
5929 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5930 unwrapped = os_malloc(unwrapped_len);
5931 if (!unwrapped)
5932 return NULL;
5933 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5934 wrapped_data, wrapped_data_len,
5935 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005936 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005937 goto fail;
5938 }
5939 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5940 unwrapped, unwrapped_len);
5941
5942 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005943 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005944 goto fail;
5945 }
5946
5947 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5948 DPP_ATTR_ENROLLEE_NONCE,
5949 &e_nonce_len);
5950 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005951 dpp_auth_fail(auth,
5952 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005953 goto fail;
5954 }
5955 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07005956 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005957
5958 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
5959 DPP_ATTR_CONFIG_ATTR_OBJ,
5960 &config_attr_len);
5961 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005962 dpp_auth_fail(auth,
5963 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005964 goto fail;
5965 }
5966 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
5967 config_attr, config_attr_len);
5968
5969 root = json_parse((const char *) config_attr, config_attr_len);
5970 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005971 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005972 goto fail;
5973 }
5974
5975 token = json_get_member(root, "name");
5976 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005977 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005978 goto fail;
5979 }
5980 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
5981
5982 token = json_get_member(root, "wi-fi_tech");
5983 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005984 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005985 goto fail;
5986 }
5987 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
5988 if (os_strcmp(token->string, "infra") != 0) {
5989 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
5990 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005991 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005992 goto fail;
5993 }
5994
5995 token = json_get_member(root, "netRole");
5996 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005997 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005998 goto fail;
5999 }
6000 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
6001 if (os_strcmp(token->string, "sta") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006002 netrole = DPP_NETROLE_STA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006003 } else if (os_strcmp(token->string, "ap") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006004 netrole = DPP_NETROLE_AP;
6005 } else if (os_strcmp(token->string, "configurator") == 0) {
6006 netrole = DPP_NETROLE_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006007 } else {
6008 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
6009 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006010 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006011 goto fail;
6012 }
6013
Hai Shalomc3565922019-10-28 11:58:20 -07006014 token = json_get_member(root, "mudurl");
6015 if (token && token->type == JSON_STRING)
6016 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
6017
6018 token = json_get_member(root, "bandSupport");
Hai Shalom06768112019-12-04 15:49:43 -08006019 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07006020 if (token && token->type == JSON_ARRAY) {
Hai Shalom06768112019-12-04 15:49:43 -08006021 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07006022 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
6023 token = token->child;
6024 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08006025 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07006026 wpa_printf(MSG_DEBUG,
6027 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08006028 } else {
6029 if (auth->band_list_size < DPP_MAX_CHANNELS) {
6030 auth->band_list[auth->band_list_size++] = token->number;
6031 }
Hai Shalomc3565922019-10-28 11:58:20 -07006032 wpa_printf(MSG_DEBUG,
6033 "DPP: Supported global operating class: %d",
6034 token->number);
Hai Shalom06768112019-12-04 15:49:43 -08006035 }
Hai Shalomc3565922019-10-28 11:58:20 -07006036 token = token->sibling;
6037 }
6038 }
6039
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006040 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006041
6042fail:
6043 json_free(root);
6044 os_free(unwrapped);
6045 return resp;
6046}
6047
6048
6049static struct wpabuf *
6050dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
6051 const u8 *prot_hdr, u16 prot_hdr_len,
6052 const EVP_MD **ret_md)
6053{
6054 struct json_token *root, *token;
6055 struct wpabuf *kid = NULL;
6056
6057 root = json_parse((const char *) prot_hdr, prot_hdr_len);
6058 if (!root) {
6059 wpa_printf(MSG_DEBUG,
6060 "DPP: JSON parsing failed for JWS Protected Header");
6061 goto fail;
6062 }
6063
6064 if (root->type != JSON_OBJECT) {
6065 wpa_printf(MSG_DEBUG,
6066 "DPP: JWS Protected Header root is not an object");
6067 goto fail;
6068 }
6069
6070 token = json_get_member(root, "typ");
6071 if (!token || token->type != JSON_STRING) {
6072 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
6073 goto fail;
6074 }
6075 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
6076 token->string);
6077 if (os_strcmp(token->string, "dppCon") != 0) {
6078 wpa_printf(MSG_DEBUG,
6079 "DPP: Unsupported JWS Protected Header typ=%s",
6080 token->string);
6081 goto fail;
6082 }
6083
6084 token = json_get_member(root, "alg");
6085 if (!token || token->type != JSON_STRING) {
6086 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
6087 goto fail;
6088 }
6089 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
6090 token->string);
6091 if (os_strcmp(token->string, curve->jws_alg) != 0) {
6092 wpa_printf(MSG_DEBUG,
6093 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
6094 token->string, curve->jws_alg);
6095 goto fail;
6096 }
6097 if (os_strcmp(token->string, "ES256") == 0 ||
6098 os_strcmp(token->string, "BS256") == 0)
6099 *ret_md = EVP_sha256();
6100 else if (os_strcmp(token->string, "ES384") == 0 ||
6101 os_strcmp(token->string, "BS384") == 0)
6102 *ret_md = EVP_sha384();
6103 else if (os_strcmp(token->string, "ES512") == 0 ||
6104 os_strcmp(token->string, "BS512") == 0)
6105 *ret_md = EVP_sha512();
6106 else
6107 *ret_md = NULL;
6108 if (!*ret_md) {
6109 wpa_printf(MSG_DEBUG,
6110 "DPP: Unsupported JWS Protected Header alg=%s",
6111 token->string);
6112 goto fail;
6113 }
6114
6115 kid = json_get_member_base64url(root, "kid");
6116 if (!kid) {
6117 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
6118 goto fail;
6119 }
6120 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
6121 kid);
6122
6123fail:
6124 json_free(root);
6125 return kid;
6126}
6127
6128
Hai Shalomc3565922019-10-28 11:58:20 -07006129static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006130 struct json_token *cred)
6131{
6132 struct json_token *pass, *psk_hex;
6133
6134 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
6135
6136 pass = json_get_member(cred, "pass");
6137 psk_hex = json_get_member(cred, "psk_hex");
6138
6139 if (pass && pass->type == JSON_STRING) {
6140 size_t len = os_strlen(pass->string);
6141
6142 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
6143 pass->string, len);
6144 if (len < 8 || len > 63)
6145 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07006146 os_strlcpy(conf->passphrase, pass->string,
6147 sizeof(conf->passphrase));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006148 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07006149 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006150 wpa_printf(MSG_DEBUG,
6151 "DPP: Unexpected psk_hex with akm=sae");
6152 return -1;
6153 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006154 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07006155 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006156 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
6157 return -1;
6158 }
6159 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07006160 conf->psk, PMK_LEN);
6161 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006162 } else {
6163 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
6164 return -1;
6165 }
6166
Hai Shalomc3565922019-10-28 11:58:20 -07006167 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006168 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
6169 return -1;
6170 }
6171
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006172 return 0;
6173}
6174
6175
6176static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
6177 const struct dpp_curve_params **key_curve)
6178{
6179 struct json_token *token;
6180 const struct dpp_curve_params *curve;
6181 struct wpabuf *x = NULL, *y = NULL;
6182 EC_GROUP *group;
6183 EVP_PKEY *pkey = NULL;
6184
6185 token = json_get_member(jwk, "kty");
6186 if (!token || token->type != JSON_STRING) {
6187 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
6188 goto fail;
6189 }
6190 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08006191 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006192 token->string);
6193 goto fail;
6194 }
6195
6196 token = json_get_member(jwk, "crv");
6197 if (!token || token->type != JSON_STRING) {
6198 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
6199 goto fail;
6200 }
6201 curve = dpp_get_curve_jwk_crv(token->string);
6202 if (!curve) {
6203 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
6204 token->string);
6205 goto fail;
6206 }
6207
6208 x = json_get_member_base64url(jwk, "x");
6209 if (!x) {
6210 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
6211 goto fail;
6212 }
6213 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
6214 if (wpabuf_len(x) != curve->prime_len) {
6215 wpa_printf(MSG_DEBUG,
6216 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
6217 (unsigned int) wpabuf_len(x),
6218 (unsigned int) curve->prime_len, curve->name);
6219 goto fail;
6220 }
6221
6222 y = json_get_member_base64url(jwk, "y");
6223 if (!y) {
6224 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
6225 goto fail;
6226 }
6227 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
6228 if (wpabuf_len(y) != curve->prime_len) {
6229 wpa_printf(MSG_DEBUG,
6230 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
6231 (unsigned int) wpabuf_len(y),
6232 (unsigned int) curve->prime_len, curve->name);
6233 goto fail;
6234 }
6235
6236 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6237 if (!group) {
6238 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
6239 goto fail;
6240 }
6241
6242 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
6243 wpabuf_len(x));
Hai Shalom81f62d82019-07-22 12:10:00 -07006244 EC_GROUP_free(group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006245 *key_curve = curve;
6246
6247fail:
6248 wpabuf_free(x);
6249 wpabuf_free(y);
6250
6251 return pkey;
6252}
6253
6254
6255int dpp_key_expired(const char *timestamp, os_time_t *expiry)
6256{
6257 struct os_time now;
6258 unsigned int year, month, day, hour, min, sec;
6259 os_time_t utime;
6260 const char *pos;
6261
6262 /* ISO 8601 date and time:
6263 * <date>T<time>
6264 * YYYY-MM-DDTHH:MM:SSZ
6265 * YYYY-MM-DDTHH:MM:SS+03:00
6266 */
6267 if (os_strlen(timestamp) < 19) {
6268 wpa_printf(MSG_DEBUG,
6269 "DPP: Too short timestamp - assume expired key");
6270 return 1;
6271 }
6272 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
6273 &year, &month, &day, &hour, &min, &sec) != 6) {
6274 wpa_printf(MSG_DEBUG,
6275 "DPP: Failed to parse expiration day - assume expired key");
6276 return 1;
6277 }
6278
6279 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
6280 wpa_printf(MSG_DEBUG,
6281 "DPP: Invalid date/time information - assume expired key");
6282 return 1;
6283 }
6284
6285 pos = timestamp + 19;
6286 if (*pos == 'Z' || *pos == '\0') {
6287 /* In UTC - no need to adjust */
6288 } else if (*pos == '-' || *pos == '+') {
6289 int items;
6290
6291 /* Adjust local time to UTC */
6292 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
6293 if (items < 1) {
6294 wpa_printf(MSG_DEBUG,
6295 "DPP: Invalid time zone designator (%s) - assume expired key",
6296 pos);
6297 return 1;
6298 }
6299 if (*pos == '-')
6300 utime += 3600 * hour;
6301 if (*pos == '+')
6302 utime -= 3600 * hour;
6303 if (items > 1) {
6304 if (*pos == '-')
6305 utime += 60 * min;
6306 if (*pos == '+')
6307 utime -= 60 * min;
6308 }
6309 } else {
6310 wpa_printf(MSG_DEBUG,
6311 "DPP: Invalid time zone designator (%s) - assume expired key",
6312 pos);
6313 return 1;
6314 }
6315 if (expiry)
6316 *expiry = utime;
6317
6318 if (os_get_time(&now) < 0) {
6319 wpa_printf(MSG_DEBUG,
6320 "DPP: Cannot get current time - assume expired key");
6321 return 1;
6322 }
6323
6324 if (now.sec > utime) {
6325 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
6326 utime, now.sec);
6327 return 1;
6328 }
6329
6330 return 0;
6331}
6332
6333
6334static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07006335 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006336 const unsigned char *payload,
6337 u16 payload_len)
6338{
6339 struct json_token *root, *groups, *netkey, *token;
6340 int ret = -1;
6341 EVP_PKEY *key = NULL;
6342 const struct dpp_curve_params *curve;
6343 unsigned int rules = 0;
6344
6345 root = json_parse((const char *) payload, payload_len);
6346 if (!root) {
6347 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
6348 goto fail;
6349 }
6350
6351 groups = json_get_member(root, "groups");
6352 if (!groups || groups->type != JSON_ARRAY) {
6353 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
6354 goto skip_groups;
6355 }
6356 for (token = groups->child; token; token = token->sibling) {
6357 struct json_token *id, *role;
6358
6359 id = json_get_member(token, "groupId");
6360 if (!id || id->type != JSON_STRING) {
6361 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
6362 goto fail;
6363 }
6364
6365 role = json_get_member(token, "netRole");
6366 if (!role || role->type != JSON_STRING) {
6367 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
6368 goto fail;
6369 }
6370 wpa_printf(MSG_DEBUG,
6371 "DPP: connector group: groupId='%s' netRole='%s'",
6372 id->string, role->string);
6373 rules++;
6374 }
6375skip_groups:
6376
6377 if (!rules) {
6378 wpa_printf(MSG_DEBUG,
6379 "DPP: Connector includes no groups");
6380 goto fail;
6381 }
6382
6383 token = json_get_member(root, "expiry");
6384 if (!token || token->type != JSON_STRING) {
6385 wpa_printf(MSG_DEBUG,
6386 "DPP: No expiry string found - connector does not expire");
6387 } else {
6388 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
6389 if (dpp_key_expired(token->string,
6390 &auth->net_access_key_expiry)) {
6391 wpa_printf(MSG_DEBUG,
6392 "DPP: Connector (netAccessKey) has expired");
6393 goto fail;
6394 }
6395 }
6396
6397 netkey = json_get_member(root, "netAccessKey");
6398 if (!netkey || netkey->type != JSON_OBJECT) {
6399 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
6400 goto fail;
6401 }
6402
6403 key = dpp_parse_jwk(netkey, &curve);
6404 if (!key)
6405 goto fail;
6406 dpp_debug_print_key("DPP: Received netAccessKey", key);
6407
6408 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
6409 wpa_printf(MSG_DEBUG,
6410 "DPP: netAccessKey in connector does not match own protocol key");
6411#ifdef CONFIG_TESTING_OPTIONS
6412 if (auth->ignore_netaccesskey_mismatch) {
6413 wpa_printf(MSG_DEBUG,
6414 "DPP: TESTING - skip netAccessKey mismatch");
6415 } else {
6416 goto fail;
6417 }
6418#else /* CONFIG_TESTING_OPTIONS */
6419 goto fail;
6420#endif /* CONFIG_TESTING_OPTIONS */
6421 }
6422
6423 ret = 0;
6424fail:
6425 EVP_PKEY_free(key);
6426 json_free(root);
6427 return ret;
6428}
6429
6430
6431static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
6432{
6433 struct wpabuf *uncomp;
6434 int res;
6435 u8 hash[SHA256_MAC_LEN];
6436 const u8 *addr[1];
6437 size_t len[1];
6438
6439 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
6440 return -1;
6441 uncomp = dpp_get_pubkey_point(pub, 1);
6442 if (!uncomp)
6443 return -1;
6444 addr[0] = wpabuf_head(uncomp);
6445 len[0] = wpabuf_len(uncomp);
6446 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
6447 addr[0], len[0]);
6448 res = sha256_vector(1, addr, len, hash);
6449 wpabuf_free(uncomp);
6450 if (res < 0)
6451 return -1;
6452 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
6453 wpa_printf(MSG_DEBUG,
6454 "DPP: Received hash value does not match calculated public key hash value");
6455 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
6456 hash, SHA256_MAC_LEN);
6457 return -1;
6458 }
6459 return 0;
6460}
6461
6462
Hai Shalomc3565922019-10-28 11:58:20 -07006463static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006464{
6465 unsigned char *der = NULL;
6466 int der_len;
6467
6468 der_len = i2d_PUBKEY(csign, &der);
6469 if (der_len <= 0)
6470 return;
Hai Shalomc3565922019-10-28 11:58:20 -07006471 wpabuf_free(conf->c_sign_key);
6472 conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006473 OPENSSL_free(der);
6474}
6475
6476
Hai Shalomc3565922019-10-28 11:58:20 -07006477static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
6478 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006479{
6480 unsigned char *der = NULL;
6481 int der_len;
6482 EC_KEY *eckey;
6483
6484 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
6485 if (!eckey)
6486 return;
6487
6488 der_len = i2d_ECPrivateKey(eckey, &der);
6489 if (der_len <= 0) {
6490 EC_KEY_free(eckey);
6491 return;
6492 }
6493 wpabuf_free(auth->net_access_key);
6494 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
6495 OPENSSL_free(der);
6496 EC_KEY_free(eckey);
6497}
6498
6499
6500struct dpp_signed_connector_info {
6501 unsigned char *payload;
6502 size_t payload_len;
6503};
6504
Roshan Pius3a1667e2018-07-03 15:17:14 -07006505static enum dpp_status_error
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006506dpp_process_signed_connector(struct dpp_signed_connector_info *info,
6507 EVP_PKEY *csign_pub, const char *connector)
6508{
Roshan Pius3a1667e2018-07-03 15:17:14 -07006509 enum dpp_status_error ret = 255;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006510 const char *pos, *end, *signed_start, *signed_end;
6511 struct wpabuf *kid = NULL;
6512 unsigned char *prot_hdr = NULL, *signature = NULL;
6513 size_t prot_hdr_len = 0, signature_len = 0;
6514 const EVP_MD *sign_md = NULL;
6515 unsigned char *der = NULL;
6516 int der_len;
6517 int res;
6518 EVP_MD_CTX *md_ctx = NULL;
6519 ECDSA_SIG *sig = NULL;
6520 BIGNUM *r = NULL, *s = NULL;
6521 const struct dpp_curve_params *curve;
6522 EC_KEY *eckey;
6523 const EC_GROUP *group;
6524 int nid;
6525
6526 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
6527 if (!eckey)
6528 goto fail;
6529 group = EC_KEY_get0_group(eckey);
6530 if (!group)
6531 goto fail;
6532 nid = EC_GROUP_get_curve_name(group);
6533 curve = dpp_get_curve_nid(nid);
6534 if (!curve)
6535 goto fail;
6536 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
6537 os_memset(info, 0, sizeof(*info));
6538
6539 signed_start = pos = connector;
6540 end = os_strchr(pos, '.');
6541 if (!end) {
6542 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006543 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006544 goto fail;
6545 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006546 prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006547 if (!prot_hdr) {
6548 wpa_printf(MSG_DEBUG,
6549 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006550 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006551 goto fail;
6552 }
6553 wpa_hexdump_ascii(MSG_DEBUG,
6554 "DPP: signedConnector - JWS Protected Header",
6555 prot_hdr, prot_hdr_len);
6556 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006557 if (!kid) {
6558 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006559 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006560 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006561 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
6562 wpa_printf(MSG_DEBUG,
6563 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
6564 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006565 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006566 goto fail;
6567 }
6568
6569 pos = end + 1;
6570 end = os_strchr(pos, '.');
6571 if (!end) {
6572 wpa_printf(MSG_DEBUG,
6573 "DPP: Missing dot(2) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006574 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006575 goto fail;
6576 }
6577 signed_end = end - 1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006578 info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006579 if (!info->payload) {
6580 wpa_printf(MSG_DEBUG,
6581 "DPP: Failed to base64url decode signedConnector JWS Payload");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006582 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006583 goto fail;
6584 }
6585 wpa_hexdump_ascii(MSG_DEBUG,
6586 "DPP: signedConnector - JWS Payload",
6587 info->payload, info->payload_len);
6588 pos = end + 1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006589 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006590 if (!signature) {
6591 wpa_printf(MSG_DEBUG,
6592 "DPP: Failed to base64url decode signedConnector signature");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006593 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006594 goto fail;
6595 }
6596 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
6597 signature, signature_len);
6598
Roshan Pius3a1667e2018-07-03 15:17:14 -07006599 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
6600 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006601 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006602 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006603
6604 if (signature_len & 0x01) {
6605 wpa_printf(MSG_DEBUG,
6606 "DPP: Unexpected signedConnector signature length (%d)",
6607 (int) signature_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006608 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006609 goto fail;
6610 }
6611
6612 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
6613 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
6614 r = BN_bin2bn(signature, signature_len / 2, NULL);
6615 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
6616 sig = ECDSA_SIG_new();
6617 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
6618 goto fail;
6619 r = NULL;
6620 s = NULL;
6621
6622 der_len = i2d_ECDSA_SIG(sig, &der);
6623 if (der_len <= 0) {
6624 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
6625 goto fail;
6626 }
6627 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
6628 md_ctx = EVP_MD_CTX_create();
6629 if (!md_ctx)
6630 goto fail;
6631
6632 ERR_clear_error();
6633 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
6634 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
6635 ERR_error_string(ERR_get_error(), NULL));
6636 goto fail;
6637 }
6638 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
6639 signed_end - signed_start + 1) != 1) {
6640 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
6641 ERR_error_string(ERR_get_error(), NULL));
6642 goto fail;
6643 }
6644 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
6645 if (res != 1) {
6646 wpa_printf(MSG_DEBUG,
6647 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
6648 res, ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07006649 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006650 goto fail;
6651 }
6652
Roshan Pius3a1667e2018-07-03 15:17:14 -07006653 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006654fail:
6655 EC_KEY_free(eckey);
6656 EVP_MD_CTX_destroy(md_ctx);
6657 os_free(prot_hdr);
6658 wpabuf_free(kid);
6659 os_free(signature);
6660 ECDSA_SIG_free(sig);
6661 BN_free(r);
6662 BN_free(s);
6663 OPENSSL_free(der);
6664 return ret;
6665}
6666
6667
6668static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07006669 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006670 struct json_token *cred)
6671{
6672 struct dpp_signed_connector_info info;
6673 struct json_token *token, *csign;
6674 int ret = -1;
6675 EVP_PKEY *csign_pub = NULL;
6676 const struct dpp_curve_params *key_curve = NULL;
6677 const char *signed_connector;
6678
6679 os_memset(&info, 0, sizeof(info));
6680
Hai Shalomc3565922019-10-28 11:58:20 -07006681 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07006682 wpa_printf(MSG_DEBUG,
6683 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07006684 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07006685 return -1;
6686 }
6687
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006688 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
6689
6690 csign = json_get_member(cred, "csign");
6691 if (!csign || csign->type != JSON_OBJECT) {
6692 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
6693 goto fail;
6694 }
6695
6696 csign_pub = dpp_parse_jwk(csign, &key_curve);
6697 if (!csign_pub) {
6698 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
6699 goto fail;
6700 }
6701 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
6702
6703 token = json_get_member(cred, "signedConnector");
6704 if (!token || token->type != JSON_STRING) {
6705 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
6706 goto fail;
6707 }
6708 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
6709 token->string, os_strlen(token->string));
6710 signed_connector = token->string;
6711
6712 if (os_strchr(signed_connector, '"') ||
6713 os_strchr(signed_connector, '\n')) {
6714 wpa_printf(MSG_DEBUG,
6715 "DPP: Unexpected character in signedConnector");
6716 goto fail;
6717 }
6718
6719 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006720 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006721 goto fail;
6722
Hai Shalomc3565922019-10-28 11:58:20 -07006723 if (dpp_parse_connector(auth, conf,
6724 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006725 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
6726 goto fail;
6727 }
6728
Hai Shalomc3565922019-10-28 11:58:20 -07006729 os_free(conf->connector);
6730 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006731
Hai Shalomc3565922019-10-28 11:58:20 -07006732 dpp_copy_csign(conf, csign_pub);
Jeff Changa5ae4a72020-04-24 03:47:18 +00006733 if (dpp_akm_dpp(conf->akm))
Hai Shalomfdcde762020-04-02 11:19:20 -07006734 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006735
6736 ret = 0;
6737fail:
6738 EVP_PKEY_free(csign_pub);
6739 os_free(info.payload);
6740 return ret;
6741}
6742
6743
Roshan Pius3a1667e2018-07-03 15:17:14 -07006744const char * dpp_akm_str(enum dpp_akm akm)
6745{
6746 switch (akm) {
6747 case DPP_AKM_DPP:
6748 return "dpp";
6749 case DPP_AKM_PSK:
6750 return "psk";
6751 case DPP_AKM_SAE:
6752 return "sae";
6753 case DPP_AKM_PSK_SAE:
6754 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07006755 case DPP_AKM_SAE_DPP:
6756 return "dpp+sae";
6757 case DPP_AKM_PSK_SAE_DPP:
6758 return "dpp+psk+sae";
Roshan Pius3a1667e2018-07-03 15:17:14 -07006759 default:
6760 return "??";
6761 }
6762}
6763
6764
Hai Shalomc3565922019-10-28 11:58:20 -07006765const char * dpp_akm_selector_str(enum dpp_akm akm)
6766{
6767 switch (akm) {
6768 case DPP_AKM_DPP:
6769 return "506F9A02";
6770 case DPP_AKM_PSK:
6771 return "000FAC02+000FAC06";
6772 case DPP_AKM_SAE:
6773 return "000FAC08";
6774 case DPP_AKM_PSK_SAE:
6775 return "000FAC02+000FAC06+000FAC08";
6776 case DPP_AKM_SAE_DPP:
6777 return "506F9A02+000FAC08";
6778 case DPP_AKM_PSK_SAE_DPP:
6779 return "506F9A02+000FAC08+000FAC02+000FAC06";
6780 default:
6781 return "??";
6782 }
6783}
6784
6785
Roshan Pius3a1667e2018-07-03 15:17:14 -07006786static enum dpp_akm dpp_akm_from_str(const char *akm)
6787{
Hai Shalomc3565922019-10-28 11:58:20 -07006788 const char *pos;
6789 int dpp = 0, psk = 0, sae = 0;
6790
Roshan Pius3a1667e2018-07-03 15:17:14 -07006791 if (os_strcmp(akm, "psk") == 0)
6792 return DPP_AKM_PSK;
6793 if (os_strcmp(akm, "sae") == 0)
6794 return DPP_AKM_SAE;
6795 if (os_strcmp(akm, "psk+sae") == 0)
6796 return DPP_AKM_PSK_SAE;
6797 if (os_strcmp(akm, "dpp") == 0)
6798 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07006799 if (os_strcmp(akm, "dpp+sae") == 0)
6800 return DPP_AKM_SAE_DPP;
6801 if (os_strcmp(akm, "dpp+psk+sae") == 0)
6802 return DPP_AKM_PSK_SAE_DPP;
Hai Shalomc3565922019-10-28 11:58:20 -07006803
6804 pos = akm;
6805 while (*pos) {
6806 if (os_strlen(pos) < 8)
6807 break;
6808 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
6809 dpp = 1;
6810 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
6811 psk = 1;
6812 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
6813 psk = 1;
6814 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
6815 sae = 1;
6816 pos += 8;
6817 if (*pos != '+')
6818 break;
6819 pos++;
6820 }
6821
6822 if (dpp && psk && sae)
6823 return DPP_AKM_PSK_SAE_DPP;
6824 if (dpp && sae)
6825 return DPP_AKM_SAE_DPP;
6826 if (dpp)
6827 return DPP_AKM_DPP;
6828 if (psk && sae)
6829 return DPP_AKM_PSK_SAE;
6830 if (sae)
6831 return DPP_AKM_SAE;
6832 if (psk)
6833 return DPP_AKM_PSK;
6834
Roshan Pius3a1667e2018-07-03 15:17:14 -07006835 return DPP_AKM_UNKNOWN;
6836}
6837
6838
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006839static int dpp_parse_conf_obj(struct dpp_authentication *auth,
6840 const u8 *conf_obj, u16 conf_obj_len)
6841{
6842 int ret = -1;
6843 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07006844 struct dpp_config_obj *conf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006845 struct wpabuf *ssid64 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07006846 int legacy;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006847
6848 root = json_parse((const char *) conf_obj, conf_obj_len);
6849 if (!root)
6850 return -1;
6851 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006852 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006853 goto fail;
6854 }
6855
6856 token = json_get_member(root, "wi-fi_tech");
6857 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006858 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006859 goto fail;
6860 }
6861 if (os_strcmp(token->string, "infra") != 0) {
6862 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
6863 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006864 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006865 goto fail;
6866 }
6867
6868 discovery = json_get_member(root, "discovery");
6869 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006870 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006871 goto fail;
6872 }
6873
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006874 ssid64 = json_get_member_base64url(discovery, "ssid64");
6875 if (ssid64) {
6876 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
6877 wpabuf_head(ssid64), wpabuf_len(ssid64));
6878 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
6879 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
6880 goto fail;
6881 }
6882 } else {
6883 token = json_get_member(discovery, "ssid");
6884 if (!token || token->type != JSON_STRING) {
6885 dpp_auth_fail(auth,
6886 "No discovery::ssid string value found");
6887 goto fail;
6888 }
6889 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
6890 token->string, os_strlen(token->string));
6891 if (os_strlen(token->string) > SSID_MAX_LEN) {
6892 dpp_auth_fail(auth,
6893 "Too long discovery::ssid string value");
6894 goto fail;
6895 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006896 }
Hai Shalomc3565922019-10-28 11:58:20 -07006897
6898 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
6899 wpa_printf(MSG_DEBUG,
6900 "DPP: No room for this many Config Objects - ignore this one");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006901 ret = 0;
6902 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07006903 }
6904 conf = &auth->conf_obj[auth->num_conf_obj++];
6905
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006906 if (ssid64) {
6907 conf->ssid_len = wpabuf_len(ssid64);
6908 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
6909 } else {
6910 conf->ssid_len = os_strlen(token->string);
6911 os_memcpy(conf->ssid, token->string, conf->ssid_len);
6912 }
6913
6914 token = json_get_member(discovery, "ssid_charset");
6915 if (token && token->type == JSON_NUMBER) {
6916 conf->ssid_charset = token->number;
6917 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
6918 conf->ssid_charset);
6919 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006920
6921 cred = json_get_member(root, "cred");
6922 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006923 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006924 goto fail;
6925 }
6926
6927 token = json_get_member(cred, "akm");
6928 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006929 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006930 goto fail;
6931 }
Hai Shalomc3565922019-10-28 11:58:20 -07006932 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006933
Hai Shalomfdcde762020-04-02 11:19:20 -07006934 legacy = dpp_akm_legacy(conf->akm);
6935 if (legacy && auth->peer_version >= 2) {
6936 struct json_token *csign, *s_conn;
6937
6938 csign = json_get_member(cred, "csign");
6939 s_conn = json_get_member(cred, "signedConnector");
6940 if (csign && csign->type == JSON_OBJECT &&
6941 s_conn && s_conn->type == JSON_STRING)
6942 legacy = 0;
6943 }
6944 if (legacy) {
Hai Shalomc3565922019-10-28 11:58:20 -07006945 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006946 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07006947 } else if (dpp_akm_dpp(conf->akm) ||
6948 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
Hai Shalomc3565922019-10-28 11:58:20 -07006949 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006950 goto fail;
6951 } else {
6952 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
6953 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006954 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006955 goto fail;
6956 }
6957
6958 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
6959 ret = 0;
6960fail:
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006961 wpabuf_free(ssid64);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006962 json_free(root);
6963 return ret;
6964}
6965
6966
Hai Shalomfdcde762020-04-02 11:19:20 -07006967#ifdef CONFIG_DPP2
6968
6969struct dpp_enveloped_data {
6970 const u8 *enc_cont;
6971 size_t enc_cont_len;
6972 const u8 *enc_key;
6973 size_t enc_key_len;
6974 const u8 *salt;
6975 size_t pbkdf2_key_len;
6976 size_t prf_hash_len;
6977};
6978
6979
6980static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
6981 struct dpp_enveloped_data *data)
6982{
6983 struct asn1_hdr hdr;
6984 const u8 *end = pos + len;
6985 const u8 *next, *e_end;
6986 struct asn1_oid oid;
6987 int val;
6988 const u8 *params;
6989 size_t params_len;
6990
6991 wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
6992
6993 /*
6994 * RecipientInfo ::= CHOICE {
6995 * ktri KeyTransRecipientInfo,
6996 * kari [1] KeyAgreeRecipientInfo,
6997 * kekri [2] KEKRecipientInfo,
6998 * pwri [3] PasswordRecipientInfo,
6999 * ori [4] OtherRecipientInfo}
7000 *
7001 * Shall always use the pwri CHOICE.
7002 */
7003
7004 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7005 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
7006 wpa_printf(MSG_DEBUG,
7007 "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
7008 hdr.class, hdr.tag);
7009 return -1;
7010 }
7011 wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
7012 hdr.payload, hdr.length);
7013 pos = hdr.payload;
7014 end = pos + hdr.length;
7015
7016 /*
7017 * PasswordRecipientInfo ::= SEQUENCE {
7018 * version CMSVersion,
7019 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
7020 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
7021 * encryptedKey EncryptedKey}
7022 *
7023 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
7024 * parameters contains PBKDF2-params SEQUENCE.
7025 */
7026
7027 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
7028 return -1;
7029 pos = hdr.payload;
7030
7031 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7032 return -1;
7033 if (val != 0) {
7034 wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
7035 return -1;
7036 }
7037
7038 wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
7039 pos, end - pos);
7040
7041 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7042 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7043 wpa_printf(MSG_DEBUG,
7044 "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
7045 hdr.class, hdr.tag);
7046 return -1;
7047 }
7048 pos = hdr.payload;
7049 e_end = pos + hdr.length;
7050
7051 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
7052 if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
7053 &next) < 0)
7054 return -1;
7055 if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
7056 char buf[80];
7057
7058 asn1_oid_to_str(&oid, buf, sizeof(buf));
7059 wpa_printf(MSG_DEBUG,
7060 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
7061 buf);
7062 return -1;
7063 }
7064
7065 /*
7066 * PBKDF2-params ::= SEQUENCE {
7067 * salt CHOICE {
7068 * specified OCTET STRING,
7069 * otherSource AlgorithmIdentifier}
7070 * iterationCount INTEGER (1..MAX),
7071 * keyLength INTEGER (1..MAX),
7072 * prf AlgorithmIdentifier}
7073 *
7074 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
7075 * on Configurator signing key length, prf is
7076 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
7077 */
7078 if (!params ||
7079 asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
7080 return -1;
7081 pos = hdr.payload;
7082
7083 if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
7084 hdr.class != ASN1_CLASS_UNIVERSAL ||
7085 hdr.tag != ASN1_TAG_OCTETSTRING) {
7086 wpa_printf(MSG_DEBUG,
7087 "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
7088 hdr.class, hdr.tag);
7089 return -1;
7090 }
7091 wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
7092 hdr.payload, hdr.length);
7093 if (hdr.length != 64) {
7094 wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
7095 hdr.length);
7096 return -1;
7097 }
7098 data->salt = hdr.payload;
7099 pos = hdr.payload + hdr.length;
7100
7101 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
7102 return -1;
7103 if (val != 1000) {
7104 wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
7105 return -1;
7106 }
7107
7108 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
7109 return -1;
7110 if (val != 32 && val != 48 && val != 64) {
7111 wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
7112 return -1;
7113 }
7114 data->pbkdf2_key_len = val;
7115
7116 if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
7117 asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
7118 wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
7119 return -1;
7120 }
7121 if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
7122 data->prf_hash_len = 32;
7123 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
7124 data->prf_hash_len = 48;
7125 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
7126 data->prf_hash_len = 64;
7127 } else {
7128 char buf[80];
7129
7130 asn1_oid_to_str(&oid, buf, sizeof(buf));
7131 wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
7132 buf);
7133 return -1;
7134 }
7135
7136 pos = next;
7137
7138 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
7139 *
7140 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
7141 *
7142 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
7143 * id-alg-AES-SIV-CMAC-aed-512. */
7144 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
7145 return -1;
7146 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
7147 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
7148 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
7149 char buf[80];
7150
7151 asn1_oid_to_str(&oid, buf, sizeof(buf));
7152 wpa_printf(MSG_DEBUG,
7153 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
7154 buf);
7155 return -1;
7156 }
7157
7158 /*
7159 * encryptedKey EncryptedKey
7160 *
7161 * EncryptedKey ::= OCTET STRING
7162 */
7163 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7164 hdr.class != ASN1_CLASS_UNIVERSAL ||
7165 hdr.tag != ASN1_TAG_OCTETSTRING) {
7166 wpa_printf(MSG_DEBUG,
7167 "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
7168 hdr.class, hdr.tag);
7169 return -1;
7170 }
7171 wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
7172 hdr.payload, hdr.length);
7173 data->enc_key = hdr.payload;
7174 data->enc_key_len = hdr.length;
7175
7176 return 0;
7177}
7178
7179
7180static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
7181 struct dpp_enveloped_data *data)
7182{
7183 struct asn1_hdr hdr;
7184 struct asn1_oid oid;
7185
7186 /*
7187 * EncryptedContentInfo ::= SEQUENCE {
7188 * contentType ContentType,
7189 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
7190 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
7191 */
7192 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7193 return -1;
7194 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
7195 hdr.payload, hdr.length);
7196 if (pos < end) {
7197 wpa_hexdump(MSG_DEBUG,
7198 "DPP: Unexpected extra data after EncryptedContentInfo",
7199 pos, end - pos);
7200 return -1;
7201 }
7202
7203 end = pos;
7204 pos = hdr.payload;
7205
7206 /* ContentType ::= OBJECT IDENTIFIER */
7207 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
7208 wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
7209 return -1;
7210 }
7211 if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
7212 char buf[80];
7213
7214 asn1_oid_to_str(&oid, buf, sizeof(buf));
7215 wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
7216 return -1;
7217 }
7218
7219 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
7220 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
7221 return -1;
7222 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
7223 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
7224 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
7225 char buf[80];
7226
7227 asn1_oid_to_str(&oid, buf, sizeof(buf));
7228 wpa_printf(MSG_DEBUG,
7229 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
7230 buf);
7231 return -1;
7232 }
7233 /* ignore optional parameters */
7234
7235 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
7236 * EncryptedContent ::= OCTET STRING */
7237 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7238 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7239 wpa_printf(MSG_DEBUG,
7240 "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
7241 hdr.class, hdr.tag);
7242 return -1;
7243 }
7244 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
7245 hdr.payload, hdr.length);
7246 data->enc_cont = hdr.payload;
7247 data->enc_cont_len = hdr.length;
7248 return 0;
7249}
7250
7251
7252static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
7253 struct dpp_enveloped_data *data)
7254{
7255 struct asn1_hdr hdr;
7256 const u8 *pos, *end;
7257 int val;
7258
7259 os_memset(data, 0, sizeof(*data));
7260
7261 /*
7262 * DPPEnvelopedData ::= EnvelopedData
7263 *
7264 * EnvelopedData ::= SEQUENCE {
7265 * version CMSVersion,
7266 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
7267 * recipientInfos RecipientInfos,
7268 * encryptedContentInfo EncryptedContentInfo,
7269 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
7270 *
7271 * CMSVersion ::= INTEGER
7272 *
7273 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
7274 *
7275 * For DPP, version is 3, both originatorInfo and
7276 * unprotectedAttrs are omitted, and recipientInfos contains a single
7277 * RecipientInfo.
7278 */
7279 if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
7280 return -1;
7281 pos = hdr.payload;
7282 if (end < env_data + env_data_len) {
7283 wpa_hexdump(MSG_DEBUG,
7284 "DPP: Unexpected extra data after DPPEnvelopedData",
7285 end, env_data + env_data_len - end);
7286 return -1;
7287 }
7288
7289 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7290 return -1;
7291 if (val != 3) {
7292 wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
7293 return -1;
7294 }
7295
7296 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7297 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7298 wpa_printf(MSG_DEBUG,
7299 "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
7300 hdr.class, hdr.tag);
7301 return -1;
7302 }
7303
7304 if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
7305 return -1;
7306 return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
7307 data);
7308}
7309
7310
7311static struct dpp_asymmetric_key *
7312dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
7313{
7314 struct asn1_hdr hdr;
7315 const u8 *pos = buf, *end = buf + len, *next;
7316 int val;
7317 const u8 *params;
7318 size_t params_len;
7319 struct asn1_oid oid;
7320 char txt[80];
7321 struct dpp_asymmetric_key *key;
7322 EC_KEY *eckey;
7323
7324 wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
7325
7326 key = os_zalloc(sizeof(*key));
7327 if (!key)
7328 return NULL;
7329
7330 /*
7331 * OneAsymmetricKey ::= SEQUENCE {
7332 * version Version,
7333 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
7334 * privateKey PrivateKey,
7335 * attributes [0] Attributes OPTIONAL,
7336 * ...,
7337 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
7338 * ...
7339 * }
7340 */
7341 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
7342 goto fail;
7343 pos = hdr.payload;
7344
7345 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
7346 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7347 goto fail;
7348 if (val != 1) {
7349 wpa_printf(MSG_DEBUG,
7350 "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
7351 val);
7352 goto fail;
7353 }
7354
7355 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
7356 if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
7357 &pos) < 0)
7358 goto fail;
7359 if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
7360 asn1_oid_to_str(&oid, txt, sizeof(txt));
7361 wpa_printf(MSG_DEBUG,
7362 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
7363 txt);
7364 goto fail;
7365 }
7366 wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
7367 params, params_len);
7368 /*
7369 * ECParameters ::= CHOICE {
7370 * namedCurve OBJECT IDENTIFIER
7371 * -- implicitCurve NULL
7372 * -- specifiedCurve SpecifiedECDomain}
7373 */
7374 if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
7375 wpa_printf(MSG_DEBUG,
7376 "DPP: Could not parse ECParameters.namedCurve");
7377 goto fail;
7378 }
7379 asn1_oid_to_str(&oid, txt, sizeof(txt));
7380 wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
7381 /* Assume the curve is identified within ECPrivateKey, so that this
7382 * separate indication is not really needed. */
7383
7384 /*
7385 * PrivateKey ::= OCTET STRING
7386 * (Contains DER encoding of ECPrivateKey)
7387 */
7388 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7389 hdr.class != ASN1_CLASS_UNIVERSAL ||
7390 hdr.tag != ASN1_TAG_OCTETSTRING) {
7391 wpa_printf(MSG_DEBUG,
7392 "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
7393 hdr.class, hdr.tag);
7394 goto fail;
7395 }
7396 wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
7397 hdr.payload, hdr.length);
7398 pos = hdr.payload + hdr.length;
7399 eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
7400 if (!eckey) {
7401 wpa_printf(MSG_INFO,
7402 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
7403 ERR_error_string(ERR_get_error(), NULL));
7404 goto fail;
7405 }
7406 key->csign = EVP_PKEY_new();
7407 if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
7408 EC_KEY_free(eckey);
7409 goto fail;
7410 }
7411 if (wpa_debug_show_keys)
7412 dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
7413
7414 /*
7415 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
7416 *
7417 * Exactly one instance of type Attribute in OneAsymmetricKey.
7418 */
7419 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7420 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7421 wpa_printf(MSG_DEBUG,
7422 "DPP: Expected [0] Attributes - found class %d tag 0x%x",
7423 hdr.class, hdr.tag);
7424 goto fail;
7425 }
7426 wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
7427 hdr.payload, hdr.length);
7428 if (hdr.payload + hdr.length < end) {
7429 wpa_hexdump_key(MSG_MSGDUMP,
7430 "DPP: Ignore additional data at the end of OneAsymmetricKey",
7431 hdr.payload + hdr.length,
7432 end - (hdr.payload + hdr.length));
7433 }
7434 pos = hdr.payload;
7435 end = hdr.payload + hdr.length;
7436
7437 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7438 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7439 wpa_printf(MSG_DEBUG,
7440 "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
7441 hdr.class, hdr.tag);
7442 goto fail;
7443 }
7444 if (hdr.payload + hdr.length < end) {
7445 wpa_hexdump_key(MSG_MSGDUMP,
7446 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
7447 hdr.payload + hdr.length,
7448 end - (hdr.payload + hdr.length));
7449 }
7450 pos = hdr.payload;
7451 end = hdr.payload + hdr.length;
7452
7453 /*
7454 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
7455 * aa-DPPConfigurationParameters,
7456 * ... -- For local profiles
7457 * }
7458 *
7459 * aa-DPPConfigurationParameters ATTRIBUTE ::=
7460 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
7461 *
7462 * Attribute ::= SEQUENCE {
7463 * type OBJECT IDENTIFIER,
7464 * values SET SIZE(1..MAX) OF Type
7465 *
7466 * Exactly one instance of ATTRIBUTE in attrValues.
7467 */
7468 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7469 goto fail;
7470 if (pos < end) {
7471 wpa_hexdump_key(MSG_MSGDUMP,
7472 "DPP: Ignore additional data at the end of ATTRIBUTE",
7473 pos, end - pos);
7474 }
7475 end = pos;
7476 pos = hdr.payload;
7477
7478 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
7479 goto fail;
7480 if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
7481 asn1_oid_to_str(&oid, txt, sizeof(txt));
7482 wpa_printf(MSG_DEBUG,
7483 "DPP: Unexpected Attribute identifier %s", txt);
7484 goto fail;
7485 }
7486
7487 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7488 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7489 wpa_printf(MSG_DEBUG,
7490 "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
7491 hdr.class, hdr.tag);
7492 goto fail;
7493 }
7494 pos = hdr.payload;
7495 end = hdr.payload + hdr.length;
7496
7497 /*
7498 * DPPConfigurationParameters ::= SEQUENCE {
7499 * configurationTemplate UTF8String,
7500 * connectorTemplate UTF8String OPTIONAL}
7501 */
7502
7503 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
7504 pos, end - pos);
7505 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7506 goto fail;
7507 if (pos < end) {
7508 wpa_hexdump_key(MSG_MSGDUMP,
7509 "DPP: Ignore additional data after DPPConfigurationParameters",
7510 pos, end - pos);
7511 }
7512 end = pos;
7513 pos = hdr.payload;
7514
7515 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7516 hdr.class != ASN1_CLASS_UNIVERSAL ||
7517 hdr.tag != ASN1_TAG_UTF8STRING) {
7518 wpa_printf(MSG_DEBUG,
7519 "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
7520 hdr.class, hdr.tag);
7521 goto fail;
7522 }
7523 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
7524 hdr.payload, hdr.length);
7525 key->config_template = os_zalloc(hdr.length + 1);
7526 if (!key->config_template)
7527 goto fail;
7528 os_memcpy(key->config_template, hdr.payload, hdr.length);
7529
7530 pos = hdr.payload + hdr.length;
7531
7532 if (pos < end) {
7533 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7534 hdr.class != ASN1_CLASS_UNIVERSAL ||
7535 hdr.tag != ASN1_TAG_UTF8STRING) {
7536 wpa_printf(MSG_DEBUG,
7537 "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
7538 hdr.class, hdr.tag);
7539 goto fail;
7540 }
7541 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
7542 hdr.payload, hdr.length);
7543 key->connector_template = os_zalloc(hdr.length + 1);
7544 if (!key->connector_template)
7545 goto fail;
7546 os_memcpy(key->connector_template, hdr.payload, hdr.length);
7547 }
7548
7549 return key;
7550fail:
7551 wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
7552 dpp_free_asymmetric_key(key);
7553 return NULL;
7554}
7555
7556
7557static struct dpp_asymmetric_key *
7558dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
7559{
7560 struct asn1_hdr hdr;
7561 const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
7562 struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
7563
7564 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
7565 key_pkg, key_pkg_len);
7566
7567 /*
7568 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
7569 *
7570 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
7571 */
7572 while (pos < end) {
7573 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
7574 !(key = dpp_parse_one_asymmetric_key(hdr.payload,
7575 hdr.length))) {
7576 dpp_free_asymmetric_key(first);
7577 return NULL;
7578 }
7579 if (!last) {
7580 first = last = key;
7581 } else {
7582 last->next = key;
7583 last = key;
7584 }
7585 }
7586
7587 return first;
7588}
7589
7590
7591static int dpp_conf_resp_env_data(struct dpp_authentication *auth,
7592 const u8 *env_data, size_t env_data_len)
7593{
7594 const u8 *key;
7595 size_t key_len;
7596 u8 kek[DPP_MAX_HASH_LEN];
7597 u8 cont_encr_key[DPP_MAX_HASH_LEN];
7598 size_t cont_encr_key_len;
7599 int res;
7600 u8 *key_pkg;
7601 size_t key_pkg_len;
7602 struct dpp_enveloped_data data;
7603 struct dpp_asymmetric_key *keys;
7604
7605 wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
7606
7607 if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
7608 return -1;
7609
7610 /* TODO: For initial testing, use ke as the key. Replace this with a
7611 * new key once that has been defined. */
7612 key = auth->ke;
7613 key_len = auth->curve->hash_len;
7614 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
7615
7616 if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
7617 kek, data.pbkdf2_key_len)) {
7618 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
7619 return -1;
7620 }
7621 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
7622 kek, data.pbkdf2_key_len);
7623
7624 if (data.enc_key_len < AES_BLOCK_SIZE ||
7625 data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
7626 wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
7627 return -1;
7628 }
7629 res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
7630 data.enc_key, data.enc_key_len,
7631 0, NULL, NULL, cont_encr_key);
7632 forced_memzero(kek, data.pbkdf2_key_len);
7633 if (res < 0) {
7634 wpa_printf(MSG_DEBUG,
7635 "DPP: AES-SIV decryption of encryptedKey failed");
7636 return -1;
7637 }
7638 cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
7639 wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
7640 cont_encr_key, cont_encr_key_len);
7641
7642 if (data.enc_cont_len < AES_BLOCK_SIZE)
7643 return -1;
7644 key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
7645 key_pkg = os_malloc(key_pkg_len);
7646 if (!key_pkg)
7647 return -1;
7648 res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
7649 data.enc_cont, data.enc_cont_len,
7650 0, NULL, NULL, key_pkg);
7651 forced_memzero(cont_encr_key, cont_encr_key_len);
7652 if (res < 0) {
7653 bin_clear_free(key_pkg, key_pkg_len);
7654 wpa_printf(MSG_DEBUG,
7655 "DPP: AES-SIV decryption of encryptedContent failed");
7656 return -1;
7657 }
7658
7659 keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
7660 bin_clear_free(key_pkg, key_pkg_len);
7661 dpp_free_asymmetric_key(auth->conf_key_pkg);
7662 auth->conf_key_pkg = keys;
7663
7664 return keys != NULL;;
7665}
7666
7667#endif /* CONFIG_DPP2 */
7668
7669
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007670int dpp_conf_resp_rx(struct dpp_authentication *auth,
7671 const struct wpabuf *resp)
7672{
7673 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
7674 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07007675 const u8 *env_data;
7676 u16 env_data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007677 const u8 *addr[1];
7678 size_t len[1];
7679 u8 *unwrapped = NULL;
7680 size_t unwrapped_len = 0;
7681 int ret = -1;
7682
Hai Shalom021b0b52019-04-10 11:17:58 -07007683 auth->conf_resp_status = 255;
7684
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007685 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007686 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007687 return -1;
7688 }
7689
7690 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
7691 DPP_ATTR_WRAPPED_DATA,
7692 &wrapped_data_len);
7693 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007694 dpp_auth_fail(auth,
7695 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007696 return -1;
7697 }
7698
7699 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7700 wrapped_data, wrapped_data_len);
7701 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7702 unwrapped = os_malloc(unwrapped_len);
7703 if (!unwrapped)
7704 return -1;
7705
7706 addr[0] = wpabuf_head(resp);
7707 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
7708 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
7709
7710 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7711 wrapped_data, wrapped_data_len,
7712 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007713 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007714 goto fail;
7715 }
7716 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7717 unwrapped, unwrapped_len);
7718
7719 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007720 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007721 goto fail;
7722 }
7723
7724 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
7725 DPP_ATTR_ENROLLEE_NONCE,
7726 &e_nonce_len);
7727 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007728 dpp_auth_fail(auth,
7729 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007730 goto fail;
7731 }
7732 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
7733 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007734 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007735 goto fail;
7736 }
7737
7738 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
7739 DPP_ATTR_STATUS, &status_len);
7740 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007741 dpp_auth_fail(auth,
7742 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007743 goto fail;
7744 }
Hai Shalom021b0b52019-04-10 11:17:58 -07007745 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007746 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
7747 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007748 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007749 goto fail;
7750 }
7751
Hai Shalomfdcde762020-04-02 11:19:20 -07007752 env_data = dpp_get_attr(unwrapped, unwrapped_len,
7753 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
7754#ifdef CONFIG_DPP2
7755 if (env_data &&
7756 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
7757 goto fail;
7758#endif /* CONFIG_DPP2 */
7759
Hai Shalomc3565922019-10-28 11:58:20 -07007760 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
7761 &conf_obj_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07007762 if (!conf_obj && !env_data) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007763 dpp_auth_fail(auth,
7764 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007765 goto fail;
7766 }
Hai Shalomc3565922019-10-28 11:58:20 -07007767 while (conf_obj) {
7768 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
7769 conf_obj, conf_obj_len);
7770 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
7771 goto fail;
7772 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
7773 DPP_ATTR_CONFIG_OBJ,
7774 &conf_obj_len);
7775 }
7776
7777#ifdef CONFIG_DPP2
7778 status = dpp_get_attr(unwrapped, unwrapped_len,
7779 DPP_ATTR_SEND_CONN_STATUS, &status_len);
7780 if (status) {
7781 wpa_printf(MSG_DEBUG,
7782 "DPP: Configurator requested connection status result");
7783 auth->conn_status_requested = 1;
7784 }
7785#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007786
7787 ret = 0;
7788
7789fail:
7790 os_free(unwrapped);
7791 return ret;
7792}
7793
7794
Hai Shalom021b0b52019-04-10 11:17:58 -07007795#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07007796
Hai Shalom021b0b52019-04-10 11:17:58 -07007797enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
7798 const u8 *hdr,
7799 const u8 *attr_start, size_t attr_len)
7800{
7801 const u8 *wrapped_data, *status, *e_nonce;
7802 u16 wrapped_data_len, status_len, e_nonce_len;
7803 const u8 *addr[2];
7804 size_t len[2];
7805 u8 *unwrapped = NULL;
7806 size_t unwrapped_len = 0;
7807 enum dpp_status_error ret = 256;
7808
7809 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
7810 &wrapped_data_len);
7811 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7812 dpp_auth_fail(auth,
7813 "Missing or invalid required Wrapped Data attribute");
7814 goto fail;
7815 }
7816 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
7817 wrapped_data, wrapped_data_len);
7818
7819 attr_len = wrapped_data - 4 - attr_start;
7820
7821 addr[0] = hdr;
7822 len[0] = DPP_HDR_LEN;
7823 addr[1] = attr_start;
7824 len[1] = attr_len;
7825 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7826 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7827 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7828 wrapped_data, wrapped_data_len);
7829 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7830 unwrapped = os_malloc(unwrapped_len);
7831 if (!unwrapped)
7832 goto fail;
7833 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7834 wrapped_data, wrapped_data_len,
7835 2, addr, len, unwrapped) < 0) {
7836 dpp_auth_fail(auth, "AES-SIV decryption failed");
7837 goto fail;
7838 }
7839 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7840 unwrapped, unwrapped_len);
7841
7842 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7843 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
7844 goto fail;
7845 }
7846
7847 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
7848 DPP_ATTR_ENROLLEE_NONCE,
7849 &e_nonce_len);
7850 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
7851 dpp_auth_fail(auth,
7852 "Missing or invalid Enrollee Nonce attribute");
7853 goto fail;
7854 }
7855 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
7856 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
7857 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
7858 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
7859 auth->e_nonce, e_nonce_len);
7860 goto fail;
7861 }
7862
7863 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
7864 &status_len);
7865 if (!status || status_len < 1) {
7866 dpp_auth_fail(auth,
7867 "Missing or invalid required DPP Status attribute");
7868 goto fail;
7869 }
7870 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
7871 ret = status[0];
7872
7873fail:
7874 bin_clear_free(unwrapped, unwrapped_len);
7875 return ret;
7876}
Hai Shalom021b0b52019-04-10 11:17:58 -07007877
7878
7879struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
7880 enum dpp_status_error status)
7881{
7882 struct wpabuf *msg, *clear;
7883 size_t nonce_len, clear_len, attr_len;
7884 const u8 *addr[2];
7885 size_t len[2];
7886 u8 *wrapped;
7887
7888 nonce_len = auth->curve->nonce_len;
7889 clear_len = 5 + 4 + nonce_len;
7890 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7891 clear = wpabuf_alloc(clear_len);
7892 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
7893 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07007894 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07007895
7896 /* DPP Status */
7897 dpp_build_attr_status(clear, status);
7898
7899 /* E-nonce */
7900 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
7901 wpabuf_put_le16(clear, nonce_len);
7902 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
7903
7904 /* OUI, OUI type, Crypto Suite, DPP frame type */
7905 addr[0] = wpabuf_head_u8(msg) + 2;
7906 len[0] = 3 + 1 + 1 + 1;
7907 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7908
7909 /* Attributes before Wrapped Data (none) */
7910 addr[1] = wpabuf_put(msg, 0);
7911 len[1] = 0;
7912 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7913
7914 /* Wrapped Data */
7915 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7916 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7917 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7918
7919 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7920 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
7921 wpabuf_head(clear), wpabuf_len(clear),
7922 2, addr, len, wrapped) < 0)
7923 goto fail;
7924
7925 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
7926 wpabuf_free(clear);
7927 return msg;
7928fail:
7929 wpabuf_free(clear);
7930 wpabuf_free(msg);
7931 return NULL;
7932}
7933
7934
Hai Shalomc3565922019-10-28 11:58:20 -07007935static int valid_channel_list(const char *val)
7936{
7937 while (*val) {
7938 if (!((*val >= '0' && *val <= '9') ||
7939 *val == '/' || *val == ','))
7940 return 0;
7941 val++;
7942 }
7943
7944 return 1;
7945}
7946
7947
7948enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
7949 const u8 *hdr,
7950 const u8 *attr_start,
7951 size_t attr_len,
7952 u8 *ssid, size_t *ssid_len,
7953 char **channel_list)
7954{
7955 const u8 *wrapped_data, *status, *e_nonce;
7956 u16 wrapped_data_len, status_len, e_nonce_len;
7957 const u8 *addr[2];
7958 size_t len[2];
7959 u8 *unwrapped = NULL;
7960 size_t unwrapped_len = 0;
7961 enum dpp_status_error ret = 256;
7962 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007963 struct wpabuf *ssid64;
Hai Shalomc3565922019-10-28 11:58:20 -07007964
7965 *ssid_len = 0;
7966 *channel_list = NULL;
7967
7968 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
7969 &wrapped_data_len);
7970 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7971 dpp_auth_fail(auth,
7972 "Missing or invalid required Wrapped Data attribute");
7973 goto fail;
7974 }
7975 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
7976 wrapped_data, wrapped_data_len);
7977
7978 attr_len = wrapped_data - 4 - attr_start;
7979
7980 addr[0] = hdr;
7981 len[0] = DPP_HDR_LEN;
7982 addr[1] = attr_start;
7983 len[1] = attr_len;
7984 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7985 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7986 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7987 wrapped_data, wrapped_data_len);
7988 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7989 unwrapped = os_malloc(unwrapped_len);
7990 if (!unwrapped)
7991 goto fail;
7992 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7993 wrapped_data, wrapped_data_len,
7994 2, addr, len, unwrapped) < 0) {
7995 dpp_auth_fail(auth, "AES-SIV decryption failed");
7996 goto fail;
7997 }
7998 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7999 unwrapped, unwrapped_len);
8000
8001 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8002 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
8003 goto fail;
8004 }
8005
8006 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
8007 DPP_ATTR_ENROLLEE_NONCE,
8008 &e_nonce_len);
8009 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8010 dpp_auth_fail(auth,
8011 "Missing or invalid Enrollee Nonce attribute");
8012 goto fail;
8013 }
8014 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
8015 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
8016 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
8017 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
8018 auth->e_nonce, e_nonce_len);
8019 goto fail;
8020 }
8021
8022 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
8023 &status_len);
8024 if (!status) {
8025 dpp_auth_fail(auth,
8026 "Missing required DPP Connection Status attribute");
8027 goto fail;
8028 }
8029 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
8030 status, status_len);
8031
8032 root = json_parse((const char *) status, status_len);
8033 if (!root) {
8034 dpp_auth_fail(auth, "Could not parse connStatus");
8035 goto fail;
8036 }
8037
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008038 ssid64 = json_get_member_base64url(root, "ssid64");
8039 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
8040 *ssid_len = wpabuf_len(ssid64);
8041 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
Hai Shalomc3565922019-10-28 11:58:20 -07008042 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008043 wpabuf_free(ssid64);
Hai Shalomc3565922019-10-28 11:58:20 -07008044
8045 token = json_get_member(root, "channelList");
8046 if (token && token->type == JSON_STRING &&
8047 valid_channel_list(token->string))
8048 *channel_list = os_strdup(token->string);
8049
8050 token = json_get_member(root, "result");
8051 if (!token || token->type != JSON_NUMBER) {
8052 dpp_auth_fail(auth, "No connStatus - result");
8053 goto fail;
8054 }
8055 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
8056 ret = token->number;
8057
8058fail:
8059 json_free(root);
8060 bin_clear_free(unwrapped, unwrapped_len);
8061 return ret;
8062}
8063
8064
8065struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
8066 enum dpp_status_error result,
8067 const u8 *ssid, size_t ssid_len,
8068 const char *channel_list)
8069{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008070 struct wpabuf *msg = NULL, *clear = NULL, *json;
Hai Shalomc3565922019-10-28 11:58:20 -07008071 size_t nonce_len, clear_len, attr_len;
8072 const u8 *addr[2];
8073 size_t len[2];
8074 u8 *wrapped;
8075
8076 json = wpabuf_alloc(1000);
8077 if (!json)
8078 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008079 json_start_object(json, NULL);
8080 json_add_int(json, "result", result);
Hai Shalomc3565922019-10-28 11:58:20 -07008081 if (ssid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008082 json_value_sep(json);
8083 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0)
8084 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07008085 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008086 if (channel_list) {
8087 json_value_sep(json);
8088 json_add_string(json, "channelList", channel_list);
8089 }
8090 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07008091 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
8092 wpabuf_head(json), wpabuf_len(json));
8093
8094 nonce_len = auth->curve->nonce_len;
8095 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
8096 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
8097 clear = wpabuf_alloc(clear_len);
8098 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
8099 if (!clear || !msg)
8100 goto fail;
8101
8102 /* E-nonce */
8103 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
8104 wpabuf_put_le16(clear, nonce_len);
8105 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
8106
8107 /* DPP Connection Status */
8108 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
8109 wpabuf_put_le16(clear, wpabuf_len(json));
8110 wpabuf_put_buf(clear, json);
8111
8112 /* OUI, OUI type, Crypto Suite, DPP frame type */
8113 addr[0] = wpabuf_head_u8(msg) + 2;
8114 len[0] = 3 + 1 + 1 + 1;
8115 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8116
8117 /* Attributes before Wrapped Data (none) */
8118 addr[1] = wpabuf_put(msg, 0);
8119 len[1] = 0;
8120 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8121
8122 /* Wrapped Data */
8123 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
8124 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8125 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8126
8127 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
8128 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
8129 wpabuf_head(clear), wpabuf_len(clear),
8130 2, addr, len, wrapped) < 0)
8131 goto fail;
8132
8133 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
8134 msg);
8135 wpabuf_free(json);
8136 wpabuf_free(clear);
8137 return msg;
8138fail:
8139 wpabuf_free(json);
8140 wpabuf_free(clear);
8141 wpabuf_free(msg);
8142 return NULL;
8143}
8144
8145#endif /* CONFIG_DPP2 */
8146
8147
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008148void dpp_configurator_free(struct dpp_configurator *conf)
8149{
8150 if (!conf)
8151 return;
8152 EVP_PKEY_free(conf->csign);
8153 os_free(conf->kid);
8154 os_free(conf);
8155}
8156
8157
Roshan Pius3a1667e2018-07-03 15:17:14 -07008158int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
8159 size_t buflen)
8160{
8161 EC_KEY *eckey;
8162 int key_len, ret = -1;
8163 unsigned char *key = NULL;
8164
8165 if (!conf->csign)
8166 return -1;
8167
8168 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
8169 if (!eckey)
8170 return -1;
8171
8172 key_len = i2d_ECPrivateKey(eckey, &key);
8173 if (key_len > 0)
8174 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
8175
8176 EC_KEY_free(eckey);
8177 OPENSSL_free(key);
8178 return ret;
8179}
8180
8181
Hai Shalomfdcde762020-04-02 11:19:20 -07008182static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
8183{
8184 struct wpabuf *csign_pub = NULL;
8185 u8 kid_hash[SHA256_MAC_LEN];
8186 const u8 *addr[1];
8187 size_t len[1];
8188 int res;
8189
8190 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
8191 if (!csign_pub) {
8192 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
8193 return -1;
8194 }
8195
8196 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
8197 addr[0] = wpabuf_head(csign_pub);
8198 len[0] = wpabuf_len(csign_pub);
8199 res = sha256_vector(1, addr, len, kid_hash);
8200 wpabuf_free(csign_pub);
8201 if (res < 0) {
8202 wpa_printf(MSG_DEBUG,
8203 "DPP: Failed to derive kid for C-sign-key");
8204 return -1;
8205 }
8206
8207 conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
8208 return conf->kid ? 0 : -1;
8209}
8210
8211
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008212struct dpp_configurator *
8213dpp_keygen_configurator(const char *curve, const u8 *privkey,
8214 size_t privkey_len)
8215{
8216 struct dpp_configurator *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008217
8218 conf = os_zalloc(sizeof(*conf));
8219 if (!conf)
8220 return NULL;
8221
8222 if (!curve) {
8223 conf->curve = &dpp_curves[0];
8224 } else {
8225 conf->curve = dpp_get_curve_name(curve);
8226 if (!conf->curve) {
8227 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
8228 curve);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008229 os_free(conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008230 return NULL;
8231 }
8232 }
8233 if (privkey)
8234 conf->csign = dpp_set_keypair(&conf->curve, privkey,
8235 privkey_len);
8236 else
8237 conf->csign = dpp_gen_keypair(conf->curve);
8238 if (!conf->csign)
8239 goto fail;
8240 conf->own = 1;
8241
Hai Shalomfdcde762020-04-02 11:19:20 -07008242 if (dpp_configurator_gen_kid(conf) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008243 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008244 return conf;
8245fail:
8246 dpp_configurator_free(conf);
Hai Shalomfdcde762020-04-02 11:19:20 -07008247 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008248}
8249
8250
8251int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008252 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008253{
8254 struct wpabuf *conf_obj;
8255 int ret = -1;
8256
8257 if (!auth->conf) {
8258 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
8259 return -1;
8260 }
8261
8262 if (!curve) {
8263 auth->curve = &dpp_curves[0];
8264 } else {
8265 auth->curve = dpp_get_curve_name(curve);
8266 if (!auth->curve) {
8267 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
8268 curve);
8269 return -1;
8270 }
8271 }
8272 wpa_printf(MSG_DEBUG,
8273 "DPP: Building own configuration/connector with curve %s",
8274 auth->curve->name);
8275
8276 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
8277 if (!auth->own_protocol_key)
8278 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07008279 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008280 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07008281 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008282
Hai Shalomc3565922019-10-28 11:58:20 -07008283 conf_obj = dpp_build_conf_obj(auth, ap, 0);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008284 if (!conf_obj) {
8285 wpabuf_free(auth->conf_obj[0].c_sign_key);
8286 auth->conf_obj[0].c_sign_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008287 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008288 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008289 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
8290 wpabuf_len(conf_obj));
8291fail:
8292 wpabuf_free(conf_obj);
8293 auth->peer_protocol_key = NULL;
8294 return ret;
8295}
8296
8297
8298static int dpp_compatible_netrole(const char *role1, const char *role2)
8299{
8300 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
8301 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
8302}
8303
8304
8305static int dpp_connector_compatible_group(struct json_token *root,
8306 const char *group_id,
8307 const char *net_role)
8308{
8309 struct json_token *groups, *token;
8310
8311 groups = json_get_member(root, "groups");
8312 if (!groups || groups->type != JSON_ARRAY)
8313 return 0;
8314
8315 for (token = groups->child; token; token = token->sibling) {
8316 struct json_token *id, *role;
8317
8318 id = json_get_member(token, "groupId");
8319 if (!id || id->type != JSON_STRING)
8320 continue;
8321
8322 role = json_get_member(token, "netRole");
8323 if (!role || role->type != JSON_STRING)
8324 continue;
8325
8326 if (os_strcmp(id->string, "*") != 0 &&
8327 os_strcmp(group_id, "*") != 0 &&
8328 os_strcmp(id->string, group_id) != 0)
8329 continue;
8330
8331 if (dpp_compatible_netrole(role->string, net_role))
8332 return 1;
8333 }
8334
8335 return 0;
8336}
8337
8338
8339static int dpp_connector_match_groups(struct json_token *own_root,
8340 struct json_token *peer_root)
8341{
8342 struct json_token *groups, *token;
8343
8344 groups = json_get_member(peer_root, "groups");
8345 if (!groups || groups->type != JSON_ARRAY) {
8346 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
8347 return 0;
8348 }
8349
8350 for (token = groups->child; token; token = token->sibling) {
8351 struct json_token *id, *role;
8352
8353 id = json_get_member(token, "groupId");
8354 if (!id || id->type != JSON_STRING) {
8355 wpa_printf(MSG_DEBUG,
8356 "DPP: Missing peer groupId string");
8357 continue;
8358 }
8359
8360 role = json_get_member(token, "netRole");
8361 if (!role || role->type != JSON_STRING) {
8362 wpa_printf(MSG_DEBUG,
8363 "DPP: Missing peer groups::netRole string");
8364 continue;
8365 }
8366 wpa_printf(MSG_DEBUG,
8367 "DPP: peer connector group: groupId='%s' netRole='%s'",
8368 id->string, role->string);
8369 if (dpp_connector_compatible_group(own_root, id->string,
8370 role->string)) {
8371 wpa_printf(MSG_DEBUG,
8372 "DPP: Compatible group/netRole in own connector");
8373 return 1;
8374 }
8375 }
8376
8377 return 0;
8378}
8379
8380
8381static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
8382 unsigned int hash_len)
8383{
8384 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
8385 const char *info = "DPP PMK";
8386 int res;
8387
8388 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8389
8390 /* HKDF-Extract(<>, N.x) */
8391 os_memset(salt, 0, hash_len);
8392 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
8393 return -1;
8394 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
8395 prk, hash_len);
8396
8397 /* HKDF-Expand(PRK, info, L) */
8398 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
8399 os_memset(prk, 0, hash_len);
8400 if (res < 0)
8401 return -1;
8402
8403 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
8404 pmk, hash_len);
8405 return 0;
8406}
8407
8408
8409static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
8410 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
8411{
8412 struct wpabuf *nkx, *pkx;
8413 int ret = -1, res;
8414 const u8 *addr[2];
8415 size_t len[2];
8416 u8 hash[SHA256_MAC_LEN];
8417
8418 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8419 nkx = dpp_get_pubkey_point(own_key, 0);
8420 pkx = dpp_get_pubkey_point(peer_key, 0);
8421 if (!nkx || !pkx)
8422 goto fail;
8423 addr[0] = wpabuf_head(nkx);
8424 len[0] = wpabuf_len(nkx) / 2;
8425 addr[1] = wpabuf_head(pkx);
8426 len[1] = wpabuf_len(pkx) / 2;
8427 if (len[0] != len[1])
8428 goto fail;
8429 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
8430 addr[0] = wpabuf_head(pkx);
8431 addr[1] = wpabuf_head(nkx);
8432 }
8433 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
8434 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
8435 res = sha256_vector(2, addr, len, hash);
8436 if (res < 0)
8437 goto fail;
8438 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
8439 os_memcpy(pmkid, hash, PMKID_LEN);
8440 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
8441 ret = 0;
8442fail:
8443 wpabuf_free(nkx);
8444 wpabuf_free(pkx);
8445 return ret;
8446}
8447
8448
Roshan Pius3a1667e2018-07-03 15:17:14 -07008449enum dpp_status_error
8450dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
8451 const u8 *net_access_key, size_t net_access_key_len,
8452 const u8 *csign_key, size_t csign_key_len,
8453 const u8 *peer_connector, size_t peer_connector_len,
8454 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008455{
8456 struct json_token *root = NULL, *netkey, *token;
8457 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008458 enum dpp_status_error ret = 255, res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008459 EVP_PKEY *own_key = NULL, *peer_key = NULL;
8460 struct wpabuf *own_key_pub = NULL;
8461 const struct dpp_curve_params *curve, *own_curve;
8462 struct dpp_signed_connector_info info;
8463 const unsigned char *p;
8464 EVP_PKEY *csign = NULL;
8465 char *signed_connector = NULL;
8466 const char *pos, *end;
8467 unsigned char *own_conn = NULL;
8468 size_t own_conn_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008469 size_t Nx_len;
8470 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
8471
8472 os_memset(intro, 0, sizeof(*intro));
8473 os_memset(&info, 0, sizeof(info));
8474 if (expiry)
8475 *expiry = 0;
8476
8477 p = csign_key;
8478 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
8479 if (!csign) {
8480 wpa_printf(MSG_ERROR,
8481 "DPP: Failed to parse local C-sign-key information");
8482 goto fail;
8483 }
8484
8485 own_key = dpp_set_keypair(&own_curve, net_access_key,
8486 net_access_key_len);
8487 if (!own_key) {
8488 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
8489 goto fail;
8490 }
8491
8492 pos = os_strchr(own_connector, '.');
8493 if (!pos) {
8494 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
8495 goto fail;
8496 }
8497 pos++;
8498 end = os_strchr(pos, '.');
8499 if (!end) {
8500 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
8501 goto fail;
8502 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008503 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008504 if (!own_conn) {
8505 wpa_printf(MSG_DEBUG,
8506 "DPP: Failed to base64url decode own signedConnector JWS Payload");
8507 goto fail;
8508 }
8509
8510 own_root = json_parse((const char *) own_conn, own_conn_len);
8511 if (!own_root) {
8512 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
8513 goto fail;
8514 }
8515
8516 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
8517 peer_connector, peer_connector_len);
8518 signed_connector = os_malloc(peer_connector_len + 1);
8519 if (!signed_connector)
8520 goto fail;
8521 os_memcpy(signed_connector, peer_connector, peer_connector_len);
8522 signed_connector[peer_connector_len] = '\0';
8523
Roshan Pius3a1667e2018-07-03 15:17:14 -07008524 res = dpp_process_signed_connector(&info, csign, signed_connector);
8525 if (res != DPP_STATUS_OK) {
8526 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008527 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008528 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008529
8530 root = json_parse((const char *) info.payload, info.payload_len);
8531 if (!root) {
8532 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008533 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008534 goto fail;
8535 }
8536
8537 if (!dpp_connector_match_groups(own_root, root)) {
8538 wpa_printf(MSG_DEBUG,
8539 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008540 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008541 goto fail;
8542 }
8543
8544 token = json_get_member(root, "expiry");
8545 if (!token || token->type != JSON_STRING) {
8546 wpa_printf(MSG_DEBUG,
8547 "DPP: No expiry string found - connector does not expire");
8548 } else {
8549 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
8550 if (dpp_key_expired(token->string, expiry)) {
8551 wpa_printf(MSG_DEBUG,
8552 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008553 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008554 goto fail;
8555 }
8556 }
8557
8558 netkey = json_get_member(root, "netAccessKey");
8559 if (!netkey || netkey->type != JSON_OBJECT) {
8560 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008561 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008562 goto fail;
8563 }
8564
8565 peer_key = dpp_parse_jwk(netkey, &curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008566 if (!peer_key) {
8567 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008568 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008569 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008570 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
8571
8572 if (own_curve != curve) {
8573 wpa_printf(MSG_DEBUG,
8574 "DPP: Mismatching netAccessKey curves (%s != %s)",
8575 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008576 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008577 goto fail;
8578 }
8579
8580 /* ECDH: N = nk * PK */
Hai Shalomc3565922019-10-28 11:58:20 -07008581 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008582 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008583
8584 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
8585 Nx, Nx_len);
8586
8587 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8588 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
8589 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
8590 goto fail;
8591 }
8592 intro->pmk_len = curve->hash_len;
8593
8594 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8595 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
8596 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
8597 goto fail;
8598 }
8599
Roshan Pius3a1667e2018-07-03 15:17:14 -07008600 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008601fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07008602 if (ret != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008603 os_memset(intro, 0, sizeof(*intro));
8604 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008605 os_free(own_conn);
8606 os_free(signed_connector);
8607 os_free(info.payload);
8608 EVP_PKEY_free(own_key);
8609 wpabuf_free(own_key_pub);
8610 EVP_PKEY_free(peer_key);
8611 EVP_PKEY_free(csign);
8612 json_free(root);
8613 json_free(own_root);
8614 return ret;
8615}
8616
8617
8618static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
8619 int init)
8620{
8621 EC_GROUP *group;
8622 size_t len = curve->prime_len;
8623 const u8 *x, *y;
Hai Shalom81f62d82019-07-22 12:10:00 -07008624 EVP_PKEY *res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008625
8626 switch (curve->ike_group) {
8627 case 19:
8628 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
8629 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
8630 break;
8631 case 20:
8632 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
8633 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
8634 break;
8635 case 21:
8636 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
8637 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
8638 break;
8639 case 28:
8640 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
8641 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
8642 break;
8643 case 29:
8644 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
8645 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
8646 break;
8647 case 30:
8648 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
8649 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
8650 break;
8651 default:
8652 return NULL;
8653 }
8654
8655 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
8656 if (!group)
8657 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07008658 res = dpp_set_pubkey_point_group(group, x, y, len);
8659 EC_GROUP_free(group);
8660 return res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008661}
8662
8663
8664static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
8665 const u8 *mac_init, const char *code,
8666 const char *identifier, BN_CTX *bnctx,
Hai Shalom81f62d82019-07-22 12:10:00 -07008667 EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008668{
8669 u8 hash[DPP_MAX_HASH_LEN];
8670 const u8 *addr[3];
8671 size_t len[3];
8672 unsigned int num_elem = 0;
8673 EC_POINT *Qi = NULL;
8674 EVP_PKEY *Pi = NULL;
8675 EC_KEY *Pi_ec = NULL;
8676 const EC_POINT *Pi_point;
8677 BIGNUM *hash_bn = NULL;
8678 const EC_GROUP *group = NULL;
8679 EC_GROUP *group2 = NULL;
8680
8681 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8682
8683 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
8684 addr[num_elem] = mac_init;
8685 len[num_elem] = ETH_ALEN;
8686 num_elem++;
8687 if (identifier) {
8688 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
8689 identifier);
8690 addr[num_elem] = (const u8 *) identifier;
8691 len[num_elem] = os_strlen(identifier);
8692 num_elem++;
8693 }
8694 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
8695 addr[num_elem] = (const u8 *) code;
8696 len[num_elem] = os_strlen(code);
8697 num_elem++;
8698 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
8699 goto fail;
8700 wpa_hexdump_key(MSG_DEBUG,
8701 "DPP: H(MAC-Initiator | [identifier |] code)",
8702 hash, curve->hash_len);
8703 Pi = dpp_pkex_get_role_elem(curve, 1);
8704 if (!Pi)
8705 goto fail;
8706 dpp_debug_print_key("DPP: Pi", Pi);
8707 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
8708 if (!Pi_ec)
8709 goto fail;
8710 Pi_point = EC_KEY_get0_public_key(Pi_ec);
8711
8712 group = EC_KEY_get0_group(Pi_ec);
8713 if (!group)
8714 goto fail;
8715 group2 = EC_GROUP_dup(group);
8716 if (!group2)
8717 goto fail;
8718 Qi = EC_POINT_new(group2);
8719 if (!Qi) {
8720 EC_GROUP_free(group2);
8721 goto fail;
8722 }
8723 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
8724 if (!hash_bn ||
8725 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
8726 goto fail;
8727 if (EC_POINT_is_at_infinity(group, Qi)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008728 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008729 goto fail;
8730 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07008731 dpp_debug_print_point("DPP: Qi", group, Qi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008732out:
8733 EC_KEY_free(Pi_ec);
8734 EVP_PKEY_free(Pi);
8735 BN_clear_free(hash_bn);
Hai Shalom81f62d82019-07-22 12:10:00 -07008736 if (ret_group && Qi)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008737 *ret_group = group2;
Hai Shalom81f62d82019-07-22 12:10:00 -07008738 else
8739 EC_GROUP_free(group2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008740 return Qi;
8741fail:
8742 EC_POINT_free(Qi);
8743 Qi = NULL;
8744 goto out;
8745}
8746
8747
8748static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
8749 const u8 *mac_resp, const char *code,
8750 const char *identifier, BN_CTX *bnctx,
Hai Shalom81f62d82019-07-22 12:10:00 -07008751 EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008752{
8753 u8 hash[DPP_MAX_HASH_LEN];
8754 const u8 *addr[3];
8755 size_t len[3];
8756 unsigned int num_elem = 0;
8757 EC_POINT *Qr = NULL;
8758 EVP_PKEY *Pr = NULL;
8759 EC_KEY *Pr_ec = NULL;
8760 const EC_POINT *Pr_point;
8761 BIGNUM *hash_bn = NULL;
8762 const EC_GROUP *group = NULL;
8763 EC_GROUP *group2 = NULL;
8764
8765 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8766
8767 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
8768 addr[num_elem] = mac_resp;
8769 len[num_elem] = ETH_ALEN;
8770 num_elem++;
8771 if (identifier) {
8772 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
8773 identifier);
8774 addr[num_elem] = (const u8 *) identifier;
8775 len[num_elem] = os_strlen(identifier);
8776 num_elem++;
8777 }
8778 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
8779 addr[num_elem] = (const u8 *) code;
8780 len[num_elem] = os_strlen(code);
8781 num_elem++;
8782 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
8783 goto fail;
8784 wpa_hexdump_key(MSG_DEBUG,
8785 "DPP: H(MAC-Responder | [identifier |] code)",
8786 hash, curve->hash_len);
8787 Pr = dpp_pkex_get_role_elem(curve, 0);
8788 if (!Pr)
8789 goto fail;
8790 dpp_debug_print_key("DPP: Pr", Pr);
8791 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
8792 if (!Pr_ec)
8793 goto fail;
8794 Pr_point = EC_KEY_get0_public_key(Pr_ec);
8795
8796 group = EC_KEY_get0_group(Pr_ec);
8797 if (!group)
8798 goto fail;
8799 group2 = EC_GROUP_dup(group);
8800 if (!group2)
8801 goto fail;
8802 Qr = EC_POINT_new(group2);
8803 if (!Qr) {
8804 EC_GROUP_free(group2);
8805 goto fail;
8806 }
8807 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
8808 if (!hash_bn ||
8809 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
8810 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008811 if (EC_POINT_is_at_infinity(group, Qr)) {
8812 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
8813 goto fail;
8814 }
8815 dpp_debug_print_point("DPP: Qr", group, Qr);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008816out:
8817 EC_KEY_free(Pr_ec);
8818 EVP_PKEY_free(Pr);
8819 BN_clear_free(hash_bn);
Hai Shalom81f62d82019-07-22 12:10:00 -07008820 if (ret_group && Qr)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008821 *ret_group = group2;
Hai Shalom81f62d82019-07-22 12:10:00 -07008822 else
8823 EC_GROUP_free(group2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008824 return Qr;
8825fail:
8826 EC_POINT_free(Qr);
8827 Qr = NULL;
8828 goto out;
8829}
8830
8831
Roshan Pius3a1667e2018-07-03 15:17:14 -07008832#ifdef CONFIG_TESTING_OPTIONS
8833static int dpp_test_gen_invalid_key(struct wpabuf *msg,
8834 const struct dpp_curve_params *curve)
8835{
8836 BN_CTX *ctx;
8837 BIGNUM *x, *y;
8838 int ret = -1;
8839 EC_GROUP *group;
8840 EC_POINT *point;
8841
8842 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
8843 if (!group)
8844 return -1;
8845
8846 ctx = BN_CTX_new();
8847 point = EC_POINT_new(group);
8848 x = BN_new();
8849 y = BN_new();
8850 if (!ctx || !point || !x || !y)
8851 goto fail;
8852
8853 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
8854 goto fail;
8855
8856 /* Generate a random y coordinate that results in a point that is not
8857 * on the curve. */
8858 for (;;) {
8859 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
8860 goto fail;
8861
8862 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
8863 ctx) != 1) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008864#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
Roshan Pius3a1667e2018-07-03 15:17:14 -07008865 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
8866 * return an error from EC_POINT_set_affine_coordinates_GFp()
8867 * when the point is not on the curve. */
8868 break;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008869#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07008870 goto fail;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008871#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07008872 }
8873
8874 if (!EC_POINT_is_on_curve(group, point, ctx))
8875 break;
8876 }
8877
8878 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
8879 curve->prime_len) < 0 ||
8880 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
8881 curve->prime_len) < 0)
8882 goto fail;
8883
8884 ret = 0;
8885fail:
8886 if (ret < 0)
8887 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
8888 BN_free(x);
8889 BN_free(y);
8890 EC_POINT_free(point);
8891 BN_CTX_free(ctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07008892 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008893
8894 return ret;
8895}
8896#endif /* CONFIG_TESTING_OPTIONS */
8897
8898
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008899static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
8900{
8901 EC_KEY *X_ec = NULL;
8902 const EC_POINT *X_point;
8903 BN_CTX *bnctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07008904 EC_GROUP *group = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008905 EC_POINT *Qi = NULL, *M = NULL;
8906 struct wpabuf *M_buf = NULL;
8907 BIGNUM *Mx = NULL, *My = NULL;
8908 struct wpabuf *msg = NULL;
8909 size_t attr_len;
8910 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008911
8912 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
8913
8914 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8915 bnctx = BN_CTX_new();
8916 if (!bnctx)
8917 goto fail;
8918 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
8919 pkex->identifier, bnctx, &group);
8920 if (!Qi)
8921 goto fail;
8922
8923 /* Generate a random ephemeral keypair x/X */
Roshan Pius3a1667e2018-07-03 15:17:14 -07008924#ifdef CONFIG_TESTING_OPTIONS
8925 if (dpp_pkex_ephemeral_key_override_len) {
8926 const struct dpp_curve_params *tmp_curve;
8927
8928 wpa_printf(MSG_INFO,
8929 "DPP: TESTING - override ephemeral key x/X");
8930 pkex->x = dpp_set_keypair(&tmp_curve,
8931 dpp_pkex_ephemeral_key_override,
8932 dpp_pkex_ephemeral_key_override_len);
8933 } else {
8934 pkex->x = dpp_gen_keypair(curve);
8935 }
8936#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008937 pkex->x = dpp_gen_keypair(curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008938#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008939 if (!pkex->x)
8940 goto fail;
8941
8942 /* M = X + Qi */
8943 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
8944 if (!X_ec)
8945 goto fail;
8946 X_point = EC_KEY_get0_public_key(X_ec);
8947 if (!X_point)
8948 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008949 dpp_debug_print_point("DPP: X", group, X_point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008950 M = EC_POINT_new(group);
8951 Mx = BN_new();
8952 My = BN_new();
8953 if (!M || !Mx || !My ||
8954 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
8955 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
8956 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008957 dpp_debug_print_point("DPP: M", group, M);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008958
8959 /* Initiator -> Responder: group, [identifier,] M */
8960 attr_len = 4 + 2;
8961 if (pkex->identifier)
8962 attr_len += 4 + os_strlen(pkex->identifier);
8963 attr_len += 4 + 2 * curve->prime_len;
8964 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
8965 if (!msg)
8966 goto fail;
8967
Roshan Pius3a1667e2018-07-03 15:17:14 -07008968#ifdef CONFIG_TESTING_OPTIONS
8969 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
8970 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
8971 goto skip_finite_cyclic_group;
8972 }
8973#endif /* CONFIG_TESTING_OPTIONS */
8974
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008975 /* Finite Cyclic Group attribute */
8976 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
8977 wpabuf_put_le16(msg, 2);
8978 wpabuf_put_le16(msg, curve->ike_group);
8979
Roshan Pius3a1667e2018-07-03 15:17:14 -07008980#ifdef CONFIG_TESTING_OPTIONS
8981skip_finite_cyclic_group:
8982#endif /* CONFIG_TESTING_OPTIONS */
8983
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008984 /* Code Identifier attribute */
8985 if (pkex->identifier) {
8986 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
8987 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
8988 wpabuf_put_str(msg, pkex->identifier);
8989 }
8990
Roshan Pius3a1667e2018-07-03 15:17:14 -07008991#ifdef CONFIG_TESTING_OPTIONS
8992 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
8993 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
8994 goto out;
8995 }
8996#endif /* CONFIG_TESTING_OPTIONS */
8997
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008998 /* M in Encrypted Key attribute */
8999 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
9000 wpabuf_put_le16(msg, 2 * curve->prime_len);
9001
Roshan Pius3a1667e2018-07-03 15:17:14 -07009002#ifdef CONFIG_TESTING_OPTIONS
9003 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
9004 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
9005 if (dpp_test_gen_invalid_key(msg, curve) < 0)
9006 goto fail;
9007 goto out;
9008 }
9009#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009010
Roshan Pius3a1667e2018-07-03 15:17:14 -07009011 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
9012 curve->prime_len) < 0 ||
9013 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
9014 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
9015 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009016 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009017
9018out:
9019 wpabuf_free(M_buf);
9020 EC_KEY_free(X_ec);
9021 EC_POINT_free(M);
9022 EC_POINT_free(Qi);
9023 BN_clear_free(Mx);
9024 BN_clear_free(My);
9025 BN_CTX_free(bnctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07009026 EC_GROUP_free(group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009027 return msg;
9028fail:
9029 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
9030 wpabuf_free(msg);
9031 msg = NULL;
9032 goto out;
9033}
9034
9035
Roshan Pius3a1667e2018-07-03 15:17:14 -07009036static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
9037{
9038 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
9039}
9040
9041
9042struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009043 const u8 *own_mac,
9044 const char *identifier,
9045 const char *code)
9046{
9047 struct dpp_pkex *pkex;
9048
Roshan Pius3a1667e2018-07-03 15:17:14 -07009049#ifdef CONFIG_TESTING_OPTIONS
9050 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
9051 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
9052 MAC2STR(dpp_pkex_own_mac_override));
9053 own_mac = dpp_pkex_own_mac_override;
9054 }
9055#endif /* CONFIG_TESTING_OPTIONS */
9056
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009057 pkex = os_zalloc(sizeof(*pkex));
9058 if (!pkex)
9059 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009060 pkex->msg_ctx = msg_ctx;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009061 pkex->initiator = 1;
9062 pkex->own_bi = bi;
9063 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
9064 if (identifier) {
9065 pkex->identifier = os_strdup(identifier);
9066 if (!pkex->identifier)
9067 goto fail;
9068 }
9069 pkex->code = os_strdup(code);
9070 if (!pkex->code)
9071 goto fail;
9072 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
9073 if (!pkex->exchange_req)
9074 goto fail;
9075 return pkex;
9076fail:
9077 dpp_pkex_free(pkex);
9078 return NULL;
9079}
9080
9081
Roshan Pius3a1667e2018-07-03 15:17:14 -07009082static struct wpabuf *
9083dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
9084 enum dpp_status_error status,
9085 const BIGNUM *Nx, const BIGNUM *Ny)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009086{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009087 struct wpabuf *msg = NULL;
9088 size_t attr_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009089 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009090
9091 /* Initiator -> Responder: DPP Status, [identifier,] N */
9092 attr_len = 4 + 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009093 if (pkex->identifier)
9094 attr_len += 4 + os_strlen(pkex->identifier);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009095 attr_len += 4 + 2 * curve->prime_len;
9096 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
9097 if (!msg)
9098 goto fail;
9099
Roshan Pius3a1667e2018-07-03 15:17:14 -07009100#ifdef CONFIG_TESTING_OPTIONS
9101 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
9102 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
9103 goto skip_status;
9104 }
9105
9106 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
9107 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
9108 status = 255;
9109 }
9110#endif /* CONFIG_TESTING_OPTIONS */
9111
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009112 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07009113 dpp_build_attr_status(msg, status);
9114
9115#ifdef CONFIG_TESTING_OPTIONS
9116skip_status:
9117#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009118
9119 /* Code Identifier attribute */
9120 if (pkex->identifier) {
9121 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
9122 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
9123 wpabuf_put_str(msg, pkex->identifier);
9124 }
9125
Roshan Pius3a1667e2018-07-03 15:17:14 -07009126 if (status != DPP_STATUS_OK)
9127 goto skip_encrypted_key;
9128
9129#ifdef CONFIG_TESTING_OPTIONS
9130 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
9131 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
9132 goto skip_encrypted_key;
9133 }
9134#endif /* CONFIG_TESTING_OPTIONS */
9135
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009136 /* N in Encrypted Key attribute */
9137 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
9138 wpabuf_put_le16(msg, 2 * curve->prime_len);
9139
Roshan Pius3a1667e2018-07-03 15:17:14 -07009140#ifdef CONFIG_TESTING_OPTIONS
9141 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
9142 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
9143 if (dpp_test_gen_invalid_key(msg, curve) < 0)
9144 goto fail;
9145 goto skip_encrypted_key;
9146 }
9147#endif /* CONFIG_TESTING_OPTIONS */
9148
9149 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
9150 curve->prime_len) < 0 ||
9151 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
9152 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
9153 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009154 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009155
Roshan Pius3a1667e2018-07-03 15:17:14 -07009156skip_encrypted_key:
9157 if (status == DPP_STATUS_BAD_GROUP) {
9158 /* Finite Cyclic Group attribute */
9159 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
9160 wpabuf_put_le16(msg, 2);
9161 wpabuf_put_le16(msg, curve->ike_group);
9162 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009163
Roshan Pius3a1667e2018-07-03 15:17:14 -07009164 return msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009165fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07009166 wpabuf_free(msg);
9167 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009168}
9169
9170
9171static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
9172 const u8 *Mx, size_t Mx_len,
9173 const u8 *Nx, size_t Nx_len,
9174 const char *code,
9175 const u8 *Kx, size_t Kx_len,
9176 u8 *z, unsigned int hash_len)
9177{
9178 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
9179 int res;
9180 u8 *info, *pos;
9181 size_t info_len;
9182
9183 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9184 */
9185
9186 /* HKDF-Extract(<>, IKM=K.x) */
9187 os_memset(salt, 0, hash_len);
9188 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
9189 return -1;
9190 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
9191 prk, hash_len);
9192 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
9193 info = os_malloc(info_len);
9194 if (!info)
9195 return -1;
9196 pos = info;
9197 os_memcpy(pos, mac_init, ETH_ALEN);
9198 pos += ETH_ALEN;
9199 os_memcpy(pos, mac_resp, ETH_ALEN);
9200 pos += ETH_ALEN;
9201 os_memcpy(pos, Mx, Mx_len);
9202 pos += Mx_len;
9203 os_memcpy(pos, Nx, Nx_len);
9204 pos += Nx_len;
9205 os_memcpy(pos, code, os_strlen(code));
9206
9207 /* HKDF-Expand(PRK, info, L) */
9208 if (hash_len == 32)
9209 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
9210 z, hash_len);
9211 else if (hash_len == 48)
9212 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
9213 z, hash_len);
9214 else if (hash_len == 64)
9215 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
9216 z, hash_len);
9217 else
9218 res = -1;
9219 os_free(info);
9220 os_memset(prk, 0, hash_len);
9221 if (res < 0)
9222 return -1;
9223
9224 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
9225 z, hash_len);
9226 return 0;
9227}
9228
9229
Hai Shalom74f70d42019-02-11 14:42:39 -08009230static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
9231 const char *identifier)
9232{
9233 if (!attr_id && identifier) {
9234 wpa_printf(MSG_DEBUG,
9235 "DPP: No PKEX code identifier received, but expected one");
9236 return 0;
9237 }
9238
9239 if (attr_id && !identifier) {
9240 wpa_printf(MSG_DEBUG,
9241 "DPP: PKEX code identifier received, but not expecting one");
9242 return 0;
9243 }
9244
9245 if (attr_id && identifier &&
9246 (os_strlen(identifier) != attr_id_len ||
9247 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
9248 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
9249 return 0;
9250 }
9251
9252 return 1;
9253}
9254
9255
Roshan Pius3a1667e2018-07-03 15:17:14 -07009256struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
9257 struct dpp_bootstrap_info *bi,
9258 const u8 *own_mac,
9259 const u8 *peer_mac,
9260 const char *identifier,
9261 const char *code,
9262 const u8 *buf, size_t len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009263{
Roshan Pius3a1667e2018-07-03 15:17:14 -07009264 const u8 *attr_group, *attr_id, *attr_key;
9265 u16 attr_group_len, attr_id_len, attr_key_len;
9266 const struct dpp_curve_params *curve = bi->curve;
9267 u16 ike_group;
9268 struct dpp_pkex *pkex = NULL;
9269 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009270 BN_CTX *bnctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07009271 EC_GROUP *group = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009272 BIGNUM *Mx = NULL, *My = NULL;
9273 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
9274 const EC_POINT *Y_point;
9275 BIGNUM *Nx = NULL, *Ny = NULL;
9276 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
9277 size_t Kx_len;
9278 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009279
9280 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
9281 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9282 "PKEX counter t limit reached - ignore message");
9283 return NULL;
9284 }
9285
9286#ifdef CONFIG_TESTING_OPTIONS
9287 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
9288 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
9289 MAC2STR(dpp_pkex_peer_mac_override));
9290 peer_mac = dpp_pkex_peer_mac_override;
9291 }
9292 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
9293 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
9294 MAC2STR(dpp_pkex_own_mac_override));
9295 own_mac = dpp_pkex_own_mac_override;
9296 }
9297#endif /* CONFIG_TESTING_OPTIONS */
9298
Hai Shalom74f70d42019-02-11 14:42:39 -08009299 attr_id_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009300 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
9301 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08009302 if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
Roshan Pius3a1667e2018-07-03 15:17:14 -07009303 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009304
9305 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
9306 &attr_group_len);
9307 if (!attr_group || attr_group_len != 2) {
9308 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9309 "Missing or invalid Finite Cyclic Group attribute");
9310 return NULL;
9311 }
9312 ike_group = WPA_GET_LE16(attr_group);
9313 if (ike_group != curve->ike_group) {
9314 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9315 "Mismatching PKEX curve: peer=%u own=%u",
9316 ike_group, curve->ike_group);
9317 pkex = os_zalloc(sizeof(*pkex));
9318 if (!pkex)
9319 goto fail;
9320 pkex->own_bi = bi;
9321 pkex->failed = 1;
9322 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
9323 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
9324 if (!pkex->exchange_resp)
9325 goto fail;
9326 return pkex;
9327 }
9328
9329 /* M in Encrypted Key attribute */
9330 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
9331 &attr_key_len);
9332 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
9333 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
9334 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9335 "Missing Encrypted Key attribute");
9336 return NULL;
9337 }
9338
9339 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
9340 bnctx = BN_CTX_new();
9341 if (!bnctx)
9342 goto fail;
9343 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
9344 &group);
9345 if (!Qi)
9346 goto fail;
9347
9348 /* X' = M - Qi */
9349 X = EC_POINT_new(group);
9350 M = EC_POINT_new(group);
9351 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
9352 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
9353 if (!X || !M || !Mx || !My ||
9354 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
9355 EC_POINT_is_at_infinity(group, M) ||
9356 !EC_POINT_is_on_curve(group, M, bnctx) ||
9357 EC_POINT_invert(group, Qi, bnctx) != 1 ||
9358 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
9359 EC_POINT_is_at_infinity(group, X) ||
9360 !EC_POINT_is_on_curve(group, X, bnctx)) {
9361 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9362 "Invalid Encrypted Key value");
9363 bi->pkex_t++;
9364 goto fail;
9365 }
9366 dpp_debug_print_point("DPP: M", group, M);
9367 dpp_debug_print_point("DPP: X'", group, X);
9368
9369 pkex = os_zalloc(sizeof(*pkex));
9370 if (!pkex)
9371 goto fail;
9372 pkex->t = bi->pkex_t;
9373 pkex->msg_ctx = msg_ctx;
9374 pkex->own_bi = bi;
9375 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
9376 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
9377 if (identifier) {
9378 pkex->identifier = os_strdup(identifier);
9379 if (!pkex->identifier)
9380 goto fail;
9381 }
9382 pkex->code = os_strdup(code);
9383 if (!pkex->code)
9384 goto fail;
9385
9386 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
9387
9388 X_ec = EC_KEY_new();
9389 if (!X_ec ||
9390 EC_KEY_set_group(X_ec, group) != 1 ||
9391 EC_KEY_set_public_key(X_ec, X) != 1)
9392 goto fail;
9393 pkex->x = EVP_PKEY_new();
9394 if (!pkex->x ||
9395 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
9396 goto fail;
9397
9398 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
9399 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
9400 if (!Qr)
9401 goto fail;
9402
9403 /* Generate a random ephemeral keypair y/Y */
9404#ifdef CONFIG_TESTING_OPTIONS
9405 if (dpp_pkex_ephemeral_key_override_len) {
9406 const struct dpp_curve_params *tmp_curve;
9407
9408 wpa_printf(MSG_INFO,
9409 "DPP: TESTING - override ephemeral key y/Y");
9410 pkex->y = dpp_set_keypair(&tmp_curve,
9411 dpp_pkex_ephemeral_key_override,
9412 dpp_pkex_ephemeral_key_override_len);
9413 } else {
9414 pkex->y = dpp_gen_keypair(curve);
9415 }
9416#else /* CONFIG_TESTING_OPTIONS */
9417 pkex->y = dpp_gen_keypair(curve);
9418#endif /* CONFIG_TESTING_OPTIONS */
9419 if (!pkex->y)
9420 goto fail;
9421
9422 /* N = Y + Qr */
9423 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
9424 if (!Y_ec)
9425 goto fail;
9426 Y_point = EC_KEY_get0_public_key(Y_ec);
9427 if (!Y_point)
9428 goto fail;
9429 dpp_debug_print_point("DPP: Y", group, Y_point);
9430 N = EC_POINT_new(group);
9431 Nx = BN_new();
9432 Ny = BN_new();
9433 if (!N || !Nx || !Ny ||
9434 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
9435 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
9436 goto fail;
9437 dpp_debug_print_point("DPP: N", group, N);
9438
9439 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
9440 Nx, Ny);
9441 if (!pkex->exchange_resp)
9442 goto fail;
9443
9444 /* K = y * X' */
Hai Shalomc3565922019-10-28 11:58:20 -07009445 if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07009446 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009447
9448 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
9449 Kx, Kx_len);
9450
9451 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9452 */
9453 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
9454 pkex->Mx, curve->prime_len,
9455 pkex->Nx, curve->prime_len, pkex->code,
9456 Kx, Kx_len, pkex->z, curve->hash_len);
9457 os_memset(Kx, 0, Kx_len);
9458 if (res < 0)
9459 goto fail;
9460
9461 pkex->exchange_done = 1;
9462
9463out:
Roshan Pius3a1667e2018-07-03 15:17:14 -07009464 BN_CTX_free(bnctx);
9465 EC_POINT_free(Qi);
9466 EC_POINT_free(Qr);
9467 BN_free(Mx);
9468 BN_free(My);
9469 BN_free(Nx);
9470 BN_free(Ny);
9471 EC_POINT_free(M);
9472 EC_POINT_free(N);
9473 EC_POINT_free(X);
9474 EC_KEY_free(X_ec);
9475 EC_KEY_free(Y_ec);
Hai Shalom81f62d82019-07-22 12:10:00 -07009476 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009477 return pkex;
9478fail:
9479 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
9480 dpp_pkex_free(pkex);
9481 pkex = NULL;
9482 goto out;
9483}
9484
9485
9486static struct wpabuf *
9487dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
9488 const struct wpabuf *A_pub, const u8 *u)
9489{
9490 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9491 struct wpabuf *msg = NULL;
9492 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009493 struct wpabuf *clear = NULL;
9494 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009495 u8 octet;
9496 const u8 *addr[2];
9497 size_t len[2];
9498
9499 /* {A, u, [bootstrapping info]}z */
9500 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
9501 clear = wpabuf_alloc(clear_len);
9502 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
9503#ifdef CONFIG_TESTING_OPTIONS
9504 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
9505 attr_len += 5;
9506#endif /* CONFIG_TESTING_OPTIONS */
9507 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
9508 if (!clear || !msg)
9509 goto fail;
9510
9511#ifdef CONFIG_TESTING_OPTIONS
9512 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
9513 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
9514 goto skip_bootstrap_key;
9515 }
9516 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
9517 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
9518 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9519 wpabuf_put_le16(clear, 2 * curve->prime_len);
9520 if (dpp_test_gen_invalid_key(clear, curve) < 0)
9521 goto fail;
9522 goto skip_bootstrap_key;
9523 }
9524#endif /* CONFIG_TESTING_OPTIONS */
9525
9526 /* A in Bootstrap Key attribute */
9527 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9528 wpabuf_put_le16(clear, wpabuf_len(A_pub));
9529 wpabuf_put_buf(clear, A_pub);
9530
9531#ifdef CONFIG_TESTING_OPTIONS
9532skip_bootstrap_key:
9533 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
9534 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
9535 goto skip_i_auth_tag;
9536 }
9537 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
9538 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
9539 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
9540 wpabuf_put_le16(clear, curve->hash_len);
9541 wpabuf_put_data(clear, u, curve->hash_len - 1);
9542 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
9543 goto skip_i_auth_tag;
9544 }
9545#endif /* CONFIG_TESTING_OPTIONS */
9546
9547 /* u in I-Auth tag attribute */
9548 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
9549 wpabuf_put_le16(clear, curve->hash_len);
9550 wpabuf_put_data(clear, u, curve->hash_len);
9551
9552#ifdef CONFIG_TESTING_OPTIONS
9553skip_i_auth_tag:
9554 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
9555 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
9556 goto skip_wrapped_data;
9557 }
9558#endif /* CONFIG_TESTING_OPTIONS */
9559
9560 addr[0] = wpabuf_head_u8(msg) + 2;
9561 len[0] = DPP_HDR_LEN;
9562 octet = 0;
9563 addr[1] = &octet;
9564 len[1] = sizeof(octet);
9565 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9566 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9567
9568 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
9569 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9570 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9571
9572 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
9573 if (aes_siv_encrypt(pkex->z, curve->hash_len,
9574 wpabuf_head(clear), wpabuf_len(clear),
9575 2, addr, len, wrapped) < 0)
9576 goto fail;
9577 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9578 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
9579
9580#ifdef CONFIG_TESTING_OPTIONS
9581 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
9582 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
9583 dpp_build_attr_status(msg, DPP_STATUS_OK);
9584 }
9585skip_wrapped_data:
9586#endif /* CONFIG_TESTING_OPTIONS */
9587
9588out:
9589 wpabuf_free(clear);
9590 return msg;
9591
9592fail:
9593 wpabuf_free(msg);
9594 msg = NULL;
9595 goto out;
9596}
9597
9598
9599struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
9600 const u8 *peer_mac,
9601 const u8 *buf, size_t buflen)
9602{
9603 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
9604 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
Hai Shalom81f62d82019-07-22 12:10:00 -07009605 EC_GROUP *group = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009606 BN_CTX *bnctx = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009607 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
9608 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9609 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
9610 BIGNUM *Nx = NULL, *Ny = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009611 EC_KEY *Y_ec = NULL;
9612 size_t Jx_len, Kx_len;
9613 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
9614 const u8 *addr[4];
9615 size_t len[4];
9616 u8 u[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009617 int res;
9618
Roshan Pius3a1667e2018-07-03 15:17:14 -07009619 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
9620 return NULL;
9621
9622#ifdef CONFIG_TESTING_OPTIONS
9623 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
9624 wpa_printf(MSG_INFO,
9625 "DPP: TESTING - stop at PKEX Exchange Response");
9626 pkex->failed = 1;
9627 return NULL;
9628 }
9629
9630 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
9631 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
9632 MAC2STR(dpp_pkex_peer_mac_override));
9633 peer_mac = dpp_pkex_peer_mac_override;
9634 }
9635#endif /* CONFIG_TESTING_OPTIONS */
9636
9637 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
9638
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009639 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
9640 &attr_status_len);
9641 if (!attr_status || attr_status_len != 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009642 dpp_pkex_fail(pkex, "No DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009643 return NULL;
9644 }
9645 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009646
9647 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
9648 attr_group = dpp_get_attr(buf, buflen,
9649 DPP_ATTR_FINITE_CYCLIC_GROUP,
9650 &attr_group_len);
9651 if (attr_group && attr_group_len == 2) {
9652 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9653 "Peer indicated mismatching PKEX group - proposed %u",
9654 WPA_GET_LE16(attr_group));
9655 return NULL;
9656 }
9657 }
9658
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009659 if (attr_status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009660 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009661 return NULL;
9662 }
9663
Hai Shalom74f70d42019-02-11 14:42:39 -08009664 attr_id_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009665 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
9666 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08009667 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
9668 pkex->identifier)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009669 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009670 return NULL;
9671 }
9672
9673 /* N in Encrypted Key attribute */
9674 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
9675 &attr_key_len);
9676 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009677 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009678 return NULL;
9679 }
9680
9681 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
9682 bnctx = BN_CTX_new();
9683 if (!bnctx)
9684 goto fail;
9685 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
9686 pkex->identifier, bnctx, &group);
9687 if (!Qr)
9688 goto fail;
9689
9690 /* Y' = N - Qr */
9691 Y = EC_POINT_new(group);
9692 N = EC_POINT_new(group);
9693 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
9694 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
9695 if (!Y || !N || !Nx || !Ny ||
9696 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
9697 EC_POINT_is_at_infinity(group, N) ||
9698 !EC_POINT_is_on_curve(group, N, bnctx) ||
9699 EC_POINT_invert(group, Qr, bnctx) != 1 ||
9700 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
9701 EC_POINT_is_at_infinity(group, Y) ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07009702 !EC_POINT_is_on_curve(group, Y, bnctx)) {
9703 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
9704 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009705 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009706 }
9707 dpp_debug_print_point("DPP: N", group, N);
9708 dpp_debug_print_point("DPP: Y'", group, Y);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009709
9710 pkex->exchange_done = 1;
9711
9712 /* ECDH: J = a * Y’ */
9713 Y_ec = EC_KEY_new();
9714 if (!Y_ec ||
9715 EC_KEY_set_group(Y_ec, group) != 1 ||
9716 EC_KEY_set_public_key(Y_ec, Y) != 1)
9717 goto fail;
9718 pkex->y = EVP_PKEY_new();
9719 if (!pkex->y ||
9720 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
9721 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07009722 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009723 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009724
9725 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
9726 Jx, Jx_len);
9727
9728 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
9729 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
9730 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
9731 X_pub = dpp_get_pubkey_point(pkex->x, 0);
9732 if (!A_pub || !Y_pub || !X_pub)
9733 goto fail;
9734 addr[0] = pkex->own_mac;
9735 len[0] = ETH_ALEN;
9736 addr[1] = wpabuf_head(A_pub);
9737 len[1] = wpabuf_len(A_pub) / 2;
9738 addr[2] = wpabuf_head(Y_pub);
9739 len[2] = wpabuf_len(Y_pub) / 2;
9740 addr[3] = wpabuf_head(X_pub);
9741 len[3] = wpabuf_len(X_pub) / 2;
9742 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
9743 goto fail;
9744 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
9745
9746 /* K = x * Y’ */
Hai Shalomc3565922019-10-28 11:58:20 -07009747 if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009748 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009749
9750 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
9751 Kx, Kx_len);
9752
9753 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9754 */
9755 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
9756 pkex->Mx, curve->prime_len,
9757 attr_key /* N.x */, attr_key_len / 2,
9758 pkex->code, Kx, Kx_len,
9759 pkex->z, curve->hash_len);
9760 os_memset(Kx, 0, Kx_len);
9761 if (res < 0)
9762 goto fail;
9763
Roshan Pius3a1667e2018-07-03 15:17:14 -07009764 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
9765 if (!msg)
9766 goto fail;
9767
9768out:
9769 wpabuf_free(A_pub);
9770 wpabuf_free(X_pub);
9771 wpabuf_free(Y_pub);
9772 EC_POINT_free(Qr);
9773 EC_POINT_free(Y);
9774 EC_POINT_free(N);
9775 BN_free(Nx);
9776 BN_free(Ny);
9777 EC_KEY_free(Y_ec);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009778 BN_CTX_free(bnctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07009779 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009780 return msg;
9781fail:
9782 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
9783 goto out;
9784}
9785
9786
9787static struct wpabuf *
9788dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
9789 const struct wpabuf *B_pub, const u8 *v)
9790{
9791 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9792 struct wpabuf *msg = NULL;
9793 const u8 *addr[2];
9794 size_t len[2];
9795 u8 octet;
9796 u8 *wrapped;
9797 struct wpabuf *clear = NULL;
9798 size_t clear_len, attr_len;
9799
9800 /* {B, v [bootstrapping info]}z */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009801 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
9802 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009803 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
9804#ifdef CONFIG_TESTING_OPTIONS
9805 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
9806 attr_len += 5;
9807#endif /* CONFIG_TESTING_OPTIONS */
9808 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009809 if (!clear || !msg)
9810 goto fail;
9811
Roshan Pius3a1667e2018-07-03 15:17:14 -07009812#ifdef CONFIG_TESTING_OPTIONS
9813 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
9814 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
9815 goto skip_bootstrap_key;
9816 }
9817 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
9818 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
9819 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9820 wpabuf_put_le16(clear, 2 * curve->prime_len);
9821 if (dpp_test_gen_invalid_key(clear, curve) < 0)
9822 goto fail;
9823 goto skip_bootstrap_key;
9824 }
9825#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009826
Roshan Pius3a1667e2018-07-03 15:17:14 -07009827 /* B in Bootstrap Key attribute */
9828 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9829 wpabuf_put_le16(clear, wpabuf_len(B_pub));
9830 wpabuf_put_buf(clear, B_pub);
9831
9832#ifdef CONFIG_TESTING_OPTIONS
9833skip_bootstrap_key:
9834 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
9835 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
9836 goto skip_r_auth_tag;
9837 }
9838 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
9839 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
9840 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
9841 wpabuf_put_le16(clear, curve->hash_len);
9842 wpabuf_put_data(clear, v, curve->hash_len - 1);
9843 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
9844 goto skip_r_auth_tag;
9845 }
9846#endif /* CONFIG_TESTING_OPTIONS */
9847
9848 /* v in R-Auth tag attribute */
9849 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009850 wpabuf_put_le16(clear, curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009851 wpabuf_put_data(clear, v, curve->hash_len);
9852
9853#ifdef CONFIG_TESTING_OPTIONS
9854skip_r_auth_tag:
9855 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
9856 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
9857 goto skip_wrapped_data;
9858 }
9859#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009860
9861 addr[0] = wpabuf_head_u8(msg) + 2;
9862 len[0] = DPP_HDR_LEN;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009863 octet = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009864 addr[1] = &octet;
9865 len[1] = sizeof(octet);
9866 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9867 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9868
9869 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
9870 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9871 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9872
9873 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
9874 if (aes_siv_encrypt(pkex->z, curve->hash_len,
9875 wpabuf_head(clear), wpabuf_len(clear),
9876 2, addr, len, wrapped) < 0)
9877 goto fail;
9878 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9879 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
9880
Roshan Pius3a1667e2018-07-03 15:17:14 -07009881#ifdef CONFIG_TESTING_OPTIONS
9882 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
9883 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
9884 dpp_build_attr_status(msg, DPP_STATUS_OK);
9885 }
9886skip_wrapped_data:
9887#endif /* CONFIG_TESTING_OPTIONS */
9888
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009889out:
9890 wpabuf_free(clear);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009891 return msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009892
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009893fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009894 wpabuf_free(msg);
9895 msg = NULL;
9896 goto out;
9897}
9898
9899
9900struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
9901 const u8 *hdr,
9902 const u8 *buf, size_t buflen)
9903{
9904 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009905 size_t Jx_len, Lx_len;
9906 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009907 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
9908 const u8 *wrapped_data, *b_key, *peer_u;
9909 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
9910 const u8 *addr[4];
9911 size_t len[4];
9912 u8 octet;
9913 u8 *unwrapped = NULL;
9914 size_t unwrapped_len = 0;
9915 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
9916 struct wpabuf *B_pub = NULL;
9917 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009918
Roshan Pius3a1667e2018-07-03 15:17:14 -07009919#ifdef CONFIG_TESTING_OPTIONS
9920 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
9921 wpa_printf(MSG_INFO,
9922 "DPP: TESTING - stop at PKEX CR Request");
9923 pkex->failed = 1;
9924 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009925 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07009926#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009927
Roshan Pius3a1667e2018-07-03 15:17:14 -07009928 if (!pkex->exchange_done || pkex->failed ||
9929 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009930 goto fail;
9931
9932 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
9933 &wrapped_data_len);
9934 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009935 dpp_pkex_fail(pkex,
9936 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009937 goto fail;
9938 }
9939
9940 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9941 wrapped_data, wrapped_data_len);
9942 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
9943 unwrapped = os_malloc(unwrapped_len);
9944 if (!unwrapped)
9945 goto fail;
9946
9947 addr[0] = hdr;
9948 len[0] = DPP_HDR_LEN;
9949 octet = 0;
9950 addr[1] = &octet;
9951 len[1] = sizeof(octet);
9952 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9953 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9954
9955 if (aes_siv_decrypt(pkex->z, curve->hash_len,
9956 wrapped_data, wrapped_data_len,
9957 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009958 dpp_pkex_fail(pkex,
9959 "AES-SIV decryption failed - possible PKEX code mismatch");
9960 pkex->failed = 1;
9961 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009962 goto fail;
9963 }
9964 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
9965 unwrapped, unwrapped_len);
9966
9967 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009968 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009969 goto fail;
9970 }
9971
9972 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
9973 &b_key_len);
9974 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009975 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009976 goto fail;
9977 }
9978 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
9979 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009980 if (!pkex->peer_bootstrap_key) {
9981 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009982 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009983 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009984 dpp_debug_print_key("DPP: Peer bootstrap public key",
9985 pkex->peer_bootstrap_key);
9986
9987 /* ECDH: J' = y * A' */
Hai Shalomc3565922019-10-28 11:58:20 -07009988 if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009989 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009990
9991 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
9992 Jx, Jx_len);
9993
9994 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
9995 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
9996 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
9997 X_pub = dpp_get_pubkey_point(pkex->x, 0);
9998 if (!A_pub || !Y_pub || !X_pub)
9999 goto fail;
10000 addr[0] = pkex->peer_mac;
10001 len[0] = ETH_ALEN;
10002 addr[1] = wpabuf_head(A_pub);
10003 len[1] = wpabuf_len(A_pub) / 2;
10004 addr[2] = wpabuf_head(Y_pub);
10005 len[2] = wpabuf_len(Y_pub) / 2;
10006 addr[3] = wpabuf_head(X_pub);
10007 len[3] = wpabuf_len(X_pub) / 2;
10008 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
10009 goto fail;
10010
10011 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
10012 &peer_u_len);
10013 if (!peer_u || peer_u_len != curve->hash_len ||
10014 os_memcmp(peer_u, u, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010015 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010016 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
10017 u, curve->hash_len);
10018 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010019 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010020 goto fail;
10021 }
10022 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
10023
10024 /* ECDH: L = b * X' */
Hai Shalomc3565922019-10-28 11:58:20 -070010025 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010026 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010027
10028 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
10029 Lx, Lx_len);
10030
10031 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
10032 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
10033 if (!B_pub)
10034 goto fail;
10035 addr[0] = pkex->own_mac;
10036 len[0] = ETH_ALEN;
10037 addr[1] = wpabuf_head(B_pub);
10038 len[1] = wpabuf_len(B_pub) / 2;
10039 addr[2] = wpabuf_head(X_pub);
10040 len[2] = wpabuf_len(X_pub) / 2;
10041 addr[3] = wpabuf_head(Y_pub);
10042 len[3] = wpabuf_len(Y_pub) / 2;
10043 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
10044 goto fail;
10045 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
10046
Roshan Pius3a1667e2018-07-03 15:17:14 -070010047 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
10048 if (!msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010049 goto fail;
10050
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010051out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010052 os_free(unwrapped);
10053 wpabuf_free(A_pub);
10054 wpabuf_free(B_pub);
10055 wpabuf_free(X_pub);
10056 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010057 return msg;
10058fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -070010059 wpa_printf(MSG_DEBUG,
10060 "DPP: PKEX Commit-Reveal Request processing failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010061 goto out;
10062}
10063
10064
10065int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
10066 const u8 *buf, size_t buflen)
10067{
10068 const struct dpp_curve_params *curve = pkex->own_bi->curve;
10069 const u8 *wrapped_data, *b_key, *peer_v;
10070 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
10071 const u8 *addr[4];
10072 size_t len[4];
10073 u8 octet;
10074 u8 *unwrapped = NULL;
10075 size_t unwrapped_len = 0;
10076 int ret = -1;
10077 u8 v[DPP_MAX_HASH_LEN];
10078 size_t Lx_len;
10079 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010080 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
10081
Roshan Pius3a1667e2018-07-03 15:17:14 -070010082#ifdef CONFIG_TESTING_OPTIONS
10083 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
10084 wpa_printf(MSG_INFO,
10085 "DPP: TESTING - stop at PKEX CR Response");
10086 pkex->failed = 1;
10087 goto fail;
10088 }
10089#endif /* CONFIG_TESTING_OPTIONS */
10090
10091 if (!pkex->exchange_done || pkex->failed ||
10092 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
10093 goto fail;
10094
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010095 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
10096 &wrapped_data_len);
10097 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010098 dpp_pkex_fail(pkex,
10099 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010100 goto fail;
10101 }
10102
10103 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
10104 wrapped_data, wrapped_data_len);
10105 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
10106 unwrapped = os_malloc(unwrapped_len);
10107 if (!unwrapped)
10108 goto fail;
10109
10110 addr[0] = hdr;
10111 len[0] = DPP_HDR_LEN;
10112 octet = 1;
10113 addr[1] = &octet;
10114 len[1] = sizeof(octet);
10115 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
10116 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
10117
10118 if (aes_siv_decrypt(pkex->z, curve->hash_len,
10119 wrapped_data, wrapped_data_len,
10120 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010121 dpp_pkex_fail(pkex,
10122 "AES-SIV decryption failed - possible PKEX code mismatch");
10123 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010124 goto fail;
10125 }
10126 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
10127 unwrapped, unwrapped_len);
10128
10129 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010130 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010131 goto fail;
10132 }
10133
10134 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
10135 &b_key_len);
10136 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010137 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010138 goto fail;
10139 }
10140 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
10141 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010142 if (!pkex->peer_bootstrap_key) {
10143 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010144 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -070010145 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010146 dpp_debug_print_key("DPP: Peer bootstrap public key",
10147 pkex->peer_bootstrap_key);
10148
10149 /* ECDH: L' = x * B' */
Hai Shalomc3565922019-10-28 11:58:20 -070010150 if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010151 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010152
10153 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
10154 Lx, Lx_len);
10155
10156 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
10157 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
10158 X_pub = dpp_get_pubkey_point(pkex->x, 0);
10159 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
10160 if (!B_pub || !X_pub || !Y_pub)
10161 goto fail;
10162 addr[0] = pkex->peer_mac;
10163 len[0] = ETH_ALEN;
10164 addr[1] = wpabuf_head(B_pub);
10165 len[1] = wpabuf_len(B_pub) / 2;
10166 addr[2] = wpabuf_head(X_pub);
10167 len[2] = wpabuf_len(X_pub) / 2;
10168 addr[3] = wpabuf_head(Y_pub);
10169 len[3] = wpabuf_len(Y_pub) / 2;
10170 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
10171 goto fail;
10172
10173 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
10174 &peer_v_len);
10175 if (!peer_v || peer_v_len != curve->hash_len ||
10176 os_memcmp(peer_v, v, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010177 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010178 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
10179 v, curve->hash_len);
10180 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010181 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010182 goto fail;
10183 }
10184 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
10185
10186 ret = 0;
10187out:
10188 wpabuf_free(B_pub);
10189 wpabuf_free(X_pub);
10190 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010191 os_free(unwrapped);
10192 return ret;
10193fail:
10194 goto out;
10195}
10196
10197
10198void dpp_pkex_free(struct dpp_pkex *pkex)
10199{
10200 if (!pkex)
10201 return;
10202
10203 os_free(pkex->identifier);
10204 os_free(pkex->code);
10205 EVP_PKEY_free(pkex->x);
10206 EVP_PKEY_free(pkex->y);
10207 EVP_PKEY_free(pkex->peer_bootstrap_key);
10208 wpabuf_free(pkex->exchange_req);
10209 wpabuf_free(pkex->exchange_resp);
10210 os_free(pkex);
10211}
Roshan Pius3a1667e2018-07-03 15:17:14 -070010212
10213
10214#ifdef CONFIG_TESTING_OPTIONS
10215char * dpp_corrupt_connector_signature(const char *connector)
10216{
10217 char *tmp, *pos, *signed3 = NULL;
10218 unsigned char *signature = NULL;
10219 size_t signature_len = 0, signed3_len;
10220
10221 tmp = os_zalloc(os_strlen(connector) + 5);
10222 if (!tmp)
10223 goto fail;
10224 os_memcpy(tmp, connector, os_strlen(connector));
10225
10226 pos = os_strchr(tmp, '.');
10227 if (!pos)
10228 goto fail;
10229
10230 pos = os_strchr(pos + 1, '.');
10231 if (!pos)
10232 goto fail;
10233 pos++;
10234
10235 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
10236 pos);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010237 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010238 if (!signature || signature_len == 0)
10239 goto fail;
10240 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
10241 signature, signature_len);
10242 signature[signature_len - 1] ^= 0x01;
10243 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
10244 signature, signature_len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010245 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010246 if (!signed3)
10247 goto fail;
10248 os_memcpy(pos, signed3, signed3_len);
10249 pos[signed3_len] = '\0';
10250 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
10251 pos);
10252
10253out:
10254 os_free(signature);
10255 os_free(signed3);
10256 return tmp;
10257fail:
10258 os_free(tmp);
10259 tmp = NULL;
10260 goto out;
10261}
10262#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom021b0b52019-04-10 11:17:58 -070010263
10264
10265#ifdef CONFIG_DPP2
10266
10267struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
10268 size_t net_access_key_len)
10269{
10270 struct wpabuf *pub = NULL;
10271 EVP_PKEY *own_key;
10272 struct dpp_pfs *pfs;
10273
10274 pfs = os_zalloc(sizeof(*pfs));
10275 if (!pfs)
10276 return NULL;
10277
10278 own_key = dpp_set_keypair(&pfs->curve, net_access_key,
10279 net_access_key_len);
10280 if (!own_key) {
10281 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
10282 goto fail;
10283 }
10284 EVP_PKEY_free(own_key);
10285
10286 pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
10287 if (!pfs->ecdh)
10288 goto fail;
10289
10290 pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
10291 pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
10292 if (!pub)
10293 goto fail;
10294
10295 pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
10296 if (!pfs->ie)
10297 goto fail;
10298 wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
10299 wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
10300 wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
10301 wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
10302 wpabuf_put_buf(pfs->ie, pub);
10303 wpabuf_free(pub);
10304 wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
10305 pfs->ie);
10306
10307 return pfs;
10308fail:
10309 wpabuf_free(pub);
10310 dpp_pfs_free(pfs);
10311 return NULL;
10312}
10313
10314
10315int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
10316{
10317 if (peer_ie_len < 2)
10318 return -1;
10319 if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
10320 wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
10321 return -1;
10322 }
10323
10324 pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
10325 peer_ie_len - 2);
10326 pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
10327 if (!pfs->secret) {
10328 wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
10329 return -1;
10330 }
10331 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
10332 return 0;
10333}
10334
10335
10336void dpp_pfs_free(struct dpp_pfs *pfs)
10337{
10338 if (!pfs)
10339 return;
10340 crypto_ecdh_deinit(pfs->ecdh);
10341 wpabuf_free(pfs->ie);
10342 wpabuf_clear_free(pfs->secret);
10343 os_free(pfs);
10344}
10345
10346#endif /* CONFIG_DPP2 */
10347
10348
10349static unsigned int dpp_next_id(struct dpp_global *dpp)
10350{
10351 struct dpp_bootstrap_info *bi;
10352 unsigned int max_id = 0;
10353
10354 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10355 if (bi->id > max_id)
10356 max_id = bi->id;
10357 }
10358 return max_id + 1;
10359}
10360
10361
10362static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
10363{
10364 struct dpp_bootstrap_info *bi, *tmp;
10365 int found = 0;
10366
10367 if (!dpp)
10368 return -1;
10369
10370 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
10371 struct dpp_bootstrap_info, list) {
10372 if (id && bi->id != id)
10373 continue;
10374 found = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -070010375#ifdef CONFIG_DPP2
10376 if (dpp->remove_bi)
10377 dpp->remove_bi(dpp->cb_ctx, bi);
10378#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070010379 dl_list_del(&bi->list);
10380 dpp_bootstrap_info_free(bi);
10381 }
10382
10383 if (id == 0)
10384 return 0; /* flush succeeds regardless of entries found */
10385 return found ? 0 : -1;
10386}
10387
10388
10389struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
10390 const char *uri)
10391{
10392 struct dpp_bootstrap_info *bi;
10393
10394 if (!dpp)
10395 return NULL;
10396
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010397 bi = dpp_parse_uri(uri);
Hai Shalom021b0b52019-04-10 11:17:58 -070010398 if (!bi)
10399 return NULL;
10400
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010401 bi->type = DPP_BOOTSTRAP_QR_CODE;
10402 bi->id = dpp_next_id(dpp);
10403 dl_list_add(&dpp->bootstrap, &bi->list);
10404 return bi;
10405}
10406
10407
10408struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
10409 const char *uri)
10410{
10411 struct dpp_bootstrap_info *bi;
10412
10413 if (!dpp)
10414 return NULL;
10415
10416 bi = dpp_parse_uri(uri);
10417 if (!bi)
10418 return NULL;
10419
10420 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -070010421 bi->id = dpp_next_id(dpp);
10422 dl_list_add(&dpp->bootstrap, &bi->list);
10423 return bi;
10424}
10425
10426
10427int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
10428{
Hai Shalomfdcde762020-04-02 11:19:20 -070010429 char *mac = NULL, *info = NULL, *curve = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -070010430 char *key = NULL;
10431 u8 *privkey = NULL;
10432 size_t privkey_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -070010433 int ret = -1;
10434 struct dpp_bootstrap_info *bi;
10435
10436 if (!dpp)
10437 return -1;
10438
10439 bi = os_zalloc(sizeof(*bi));
10440 if (!bi)
10441 goto fail;
10442
10443 if (os_strstr(cmd, "type=qrcode"))
10444 bi->type = DPP_BOOTSTRAP_QR_CODE;
10445 else if (os_strstr(cmd, "type=pkex"))
10446 bi->type = DPP_BOOTSTRAP_PKEX;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010447 else if (os_strstr(cmd, "type=nfc-uri"))
10448 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -070010449 else
10450 goto fail;
10451
Hai Shalomfdcde762020-04-02 11:19:20 -070010452 bi->chan = get_param(cmd, " chan=");
Hai Shalom021b0b52019-04-10 11:17:58 -070010453 mac = get_param(cmd, " mac=");
10454 info = get_param(cmd, " info=");
10455 curve = get_param(cmd, " curve=");
10456 key = get_param(cmd, " key=");
10457
10458 if (key) {
10459 privkey_len = os_strlen(key) / 2;
10460 privkey = os_malloc(privkey_len);
10461 if (!privkey ||
10462 hexstr2bin(key, privkey, privkey_len) < 0)
10463 goto fail;
10464 }
10465
Hai Shalomfdcde762020-04-02 11:19:20 -070010466 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
10467 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
10468 dpp_parse_uri_mac(bi, mac) < 0 ||
10469 dpp_parse_uri_info(bi, info) < 0 ||
10470 dpp_gen_uri(bi) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -070010471 goto fail;
10472
Hai Shalom021b0b52019-04-10 11:17:58 -070010473 bi->id = dpp_next_id(dpp);
10474 dl_list_add(&dpp->bootstrap, &bi->list);
10475 ret = bi->id;
10476 bi = NULL;
10477fail:
10478 os_free(curve);
Hai Shalom021b0b52019-04-10 11:17:58 -070010479 os_free(mac);
10480 os_free(info);
10481 str_clear_free(key);
10482 bin_clear_free(privkey, privkey_len);
10483 dpp_bootstrap_info_free(bi);
10484 return ret;
10485}
10486
10487
10488struct dpp_bootstrap_info *
10489dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
10490{
10491 struct dpp_bootstrap_info *bi;
10492
10493 if (!dpp)
10494 return NULL;
10495
10496 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10497 if (bi->id == id)
10498 return bi;
10499 }
10500 return NULL;
10501}
10502
10503
10504int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
10505{
10506 unsigned int id_val;
10507
10508 if (os_strcmp(id, "*") == 0) {
10509 id_val = 0;
10510 } else {
10511 id_val = atoi(id);
10512 if (id_val == 0)
10513 return -1;
10514 }
10515
10516 return dpp_bootstrap_del(dpp, id_val);
10517}
10518
10519
10520struct dpp_bootstrap_info *
10521dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
10522 unsigned int freq)
10523{
10524 struct dpp_bootstrap_info *bi;
10525
10526 bi = os_zalloc(sizeof(*bi));
10527 if (!bi)
10528 return NULL;
10529 bi->id = dpp_next_id(dpp);
10530 bi->type = DPP_BOOTSTRAP_PKEX;
10531 os_memcpy(bi->mac_addr, peer, ETH_ALEN);
10532 bi->num_freq = 1;
10533 bi->freq[0] = freq;
10534 bi->curve = pkex->own_bi->curve;
10535 bi->pubkey = pkex->peer_bootstrap_key;
10536 pkex->peer_bootstrap_key = NULL;
10537 if (dpp_bootstrap_key_hash(bi) < 0) {
10538 dpp_bootstrap_info_free(bi);
10539 return NULL;
10540 }
10541 dpp_pkex_free(pkex);
10542 dl_list_add(&dpp->bootstrap, &bi->list);
10543 return bi;
10544}
10545
10546
10547const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
10548{
10549 struct dpp_bootstrap_info *bi;
10550
10551 bi = dpp_bootstrap_get_id(dpp, id);
10552 if (!bi)
10553 return NULL;
10554 return bi->uri;
10555}
10556
10557
10558int dpp_bootstrap_info(struct dpp_global *dpp, int id,
10559 char *reply, int reply_size)
10560{
10561 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -070010562 char pkhash[2 * SHA256_MAC_LEN + 1];
Hai Shalom021b0b52019-04-10 11:17:58 -070010563
10564 bi = dpp_bootstrap_get_id(dpp, id);
10565 if (!bi)
10566 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -070010567 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
10568 SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -070010569 return os_snprintf(reply, reply_size, "type=%s\n"
10570 "mac_addr=" MACSTR "\n"
10571 "info=%s\n"
10572 "num_freq=%u\n"
Hai Shalomfdcde762020-04-02 11:19:20 -070010573 "use_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -070010574 "curve=%s\n"
10575 "pkhash=%s\n",
Hai Shalom021b0b52019-04-10 11:17:58 -070010576 dpp_bootstrap_type_txt(bi->type),
10577 MAC2STR(bi->mac_addr),
10578 bi->info ? bi->info : "",
10579 bi->num_freq,
Hai Shalomfdcde762020-04-02 11:19:20 -070010580 bi->num_freq == 1 ? bi->freq[0] : 0,
Hai Shalom81f62d82019-07-22 12:10:00 -070010581 bi->curve->name,
10582 pkhash);
Hai Shalom021b0b52019-04-10 11:17:58 -070010583}
10584
10585
Hai Shalomfdcde762020-04-02 11:19:20 -070010586int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
10587{
10588 struct dpp_bootstrap_info *bi;
10589
10590 bi = dpp_bootstrap_get_id(dpp, id);
10591 if (!bi)
10592 return -1;
10593
10594 str_clear_free(bi->configurator_params);
10595
10596 if (params) {
10597 bi->configurator_params = os_strdup(params);
10598 return bi->configurator_params ? 0 : -1;
10599 }
10600
10601 bi->configurator_params = NULL;
10602 return 0;
10603}
10604
10605
Hai Shalom021b0b52019-04-10 11:17:58 -070010606void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
10607 const u8 *r_bootstrap,
10608 struct dpp_bootstrap_info **own_bi,
10609 struct dpp_bootstrap_info **peer_bi)
10610{
10611 struct dpp_bootstrap_info *bi;
10612
10613 *own_bi = NULL;
10614 *peer_bi = NULL;
10615 if (!dpp)
10616 return;
10617
10618 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10619 if (!*own_bi && bi->own &&
10620 os_memcmp(bi->pubkey_hash, r_bootstrap,
10621 SHA256_MAC_LEN) == 0) {
10622 wpa_printf(MSG_DEBUG,
10623 "DPP: Found matching own bootstrapping information");
10624 *own_bi = bi;
10625 }
10626
10627 if (!*peer_bi && !bi->own &&
10628 os_memcmp(bi->pubkey_hash, i_bootstrap,
10629 SHA256_MAC_LEN) == 0) {
10630 wpa_printf(MSG_DEBUG,
10631 "DPP: Found matching peer bootstrapping information");
10632 *peer_bi = bi;
10633 }
10634
10635 if (*own_bi && *peer_bi)
10636 break;
10637 }
Hai Shalomfdcde762020-04-02 11:19:20 -070010638}
Hai Shalom021b0b52019-04-10 11:17:58 -070010639
Hai Shalomfdcde762020-04-02 11:19:20 -070010640
10641#ifdef CONFIG_DPP2
10642struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
10643 const u8 *hash)
10644{
10645 struct dpp_bootstrap_info *bi;
10646
10647 if (!dpp)
10648 return NULL;
10649
10650 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10651 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
10652 SHA256_MAC_LEN) == 0)
10653 return bi;
10654 }
10655
10656 return NULL;
10657}
10658#endif /* CONFIG_DPP2 */
10659
10660
10661static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
10662 struct dpp_bootstrap_info *peer_bi)
10663{
10664 unsigned int i, freq = 0;
10665 enum hostapd_hw_mode mode;
10666 u8 op_class, channel;
10667 char chan[20];
10668
10669 if (peer_bi->num_freq == 0)
10670 return 0; /* no channel preference/constraint */
10671
10672 for (i = 0; i < peer_bi->num_freq; i++) {
10673 if (own_bi->num_freq == 0 ||
10674 freq_included(own_bi->freq, own_bi->num_freq,
10675 peer_bi->freq[i])) {
10676 freq = peer_bi->freq[i];
10677 break;
10678 }
10679 }
10680 if (!freq) {
10681 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
10682 return -1;
10683 }
10684
10685 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
10686 if (mode == NUM_HOSTAPD_MODES) {
10687 wpa_printf(MSG_DEBUG,
10688 "DPP: Could not determine operating class or channel number for %u MHz",
10689 freq);
10690 }
10691
10692 wpa_printf(MSG_DEBUG,
10693 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
10694 freq, op_class, channel);
10695 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
10696 os_free(own_bi->chan);
10697 own_bi->chan = os_strdup(chan);
10698 own_bi->freq[0] = freq;
10699 own_bi->num_freq = 1;
10700 os_free(peer_bi->chan);
10701 peer_bi->chan = os_strdup(chan);
10702 peer_bi->freq[0] = freq;
10703 peer_bi->num_freq = 1;
10704
10705 return dpp_gen_uri(own_bi);
10706}
10707
10708
10709static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
10710 struct dpp_bootstrap_info *peer_bi)
10711{
10712 if (peer_bi->curve == own_bi->curve)
10713 return 0;
10714
10715 wpa_printf(MSG_DEBUG,
10716 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
10717
10718 EVP_PKEY_free(own_bi->pubkey);
10719 own_bi->pubkey = NULL;
10720
10721 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
10722 dpp_gen_uri(own_bi) < 0)
10723 goto fail;
10724
10725 return 0;
10726fail:
10727 dl_list_del(&own_bi->list);
10728 dpp_bootstrap_info_free(own_bi);
10729 return -1;
10730}
10731
10732
10733int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
10734 struct dpp_bootstrap_info *peer_bi)
10735{
10736 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
10737 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
10738 return -1;
10739 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -070010740}
10741
10742
10743static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
10744{
10745 struct dpp_configurator *conf;
10746 unsigned int max_id = 0;
10747
10748 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
10749 list) {
10750 if (conf->id > max_id)
10751 max_id = conf->id;
10752 }
10753 return max_id + 1;
10754}
10755
10756
10757int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
10758{
10759 char *curve = NULL;
10760 char *key = NULL;
10761 u8 *privkey = NULL;
10762 size_t privkey_len = 0;
10763 int ret = -1;
10764 struct dpp_configurator *conf = NULL;
10765
10766 curve = get_param(cmd, " curve=");
10767 key = get_param(cmd, " key=");
10768
10769 if (key) {
10770 privkey_len = os_strlen(key) / 2;
10771 privkey = os_malloc(privkey_len);
10772 if (!privkey ||
10773 hexstr2bin(key, privkey, privkey_len) < 0)
10774 goto fail;
10775 }
10776
10777 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
10778 if (!conf)
10779 goto fail;
10780
10781 conf->id = dpp_next_configurator_id(dpp);
10782 dl_list_add(&dpp->configurator, &conf->list);
10783 ret = conf->id;
10784 conf = NULL;
10785fail:
10786 os_free(curve);
10787 str_clear_free(key);
10788 bin_clear_free(privkey, privkey_len);
10789 dpp_configurator_free(conf);
10790 return ret;
10791}
10792
10793
10794static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
10795{
10796 struct dpp_configurator *conf, *tmp;
10797 int found = 0;
10798
10799 if (!dpp)
10800 return -1;
10801
10802 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
10803 struct dpp_configurator, list) {
10804 if (id && conf->id != id)
10805 continue;
10806 found = 1;
10807 dl_list_del(&conf->list);
10808 dpp_configurator_free(conf);
10809 }
10810
10811 if (id == 0)
10812 return 0; /* flush succeeds regardless of entries found */
10813 return found ? 0 : -1;
10814}
10815
10816
10817int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
10818{
10819 unsigned int id_val;
10820
10821 if (os_strcmp(id, "*") == 0) {
10822 id_val = 0;
10823 } else {
10824 id_val = atoi(id);
10825 if (id_val == 0)
10826 return -1;
10827 }
10828
10829 return dpp_configurator_del(dpp, id_val);
10830}
10831
10832
10833int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
10834 char *buf, size_t buflen)
10835{
10836 struct dpp_configurator *conf;
10837
10838 conf = dpp_configurator_get_id(dpp, id);
10839 if (!conf)
10840 return -1;
10841
10842 return dpp_configurator_get_key(conf, buf, buflen);
10843}
10844
10845
Hai Shalom81f62d82019-07-22 12:10:00 -070010846#ifdef CONFIG_DPP2
10847
Hai Shalomfdcde762020-04-02 11:19:20 -070010848int dpp_configurator_from_backup(struct dpp_global *dpp,
10849 struct dpp_asymmetric_key *key)
10850{
10851 struct dpp_configurator *conf;
10852 const EC_KEY *eckey;
10853 const EC_GROUP *group;
10854 int nid;
10855 const struct dpp_curve_params *curve;
10856
10857 if (!key->csign)
10858 return -1;
10859 eckey = EVP_PKEY_get0_EC_KEY(key->csign);
10860 if (!eckey)
10861 return -1;
10862 group = EC_KEY_get0_group(eckey);
10863 if (!group)
10864 return -1;
10865 nid = EC_GROUP_get_curve_name(group);
10866 curve = dpp_get_curve_nid(nid);
10867 if (!curve) {
10868 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
10869 return -1;
10870 }
10871
10872 conf = os_zalloc(sizeof(*conf));
10873 if (!conf)
10874 return -1;
10875 conf->curve = curve;
10876 conf->csign = key->csign;
10877 key->csign = NULL;
10878 conf->own = 1;
10879 if (dpp_configurator_gen_kid(conf) < 0) {
10880 dpp_configurator_free(conf);
10881 return -1;
10882 }
10883
10884 conf->id = dpp_next_configurator_id(dpp);
10885 dl_list_add(&dpp->configurator, &conf->list);
10886 return conf->id;
10887}
10888
10889
Hai Shalomc3565922019-10-28 11:58:20 -070010890static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
10891 void *timeout_ctx);
10892
10893
Hai Shalom81f62d82019-07-22 12:10:00 -070010894static void dpp_connection_free(struct dpp_connection *conn)
10895{
10896 if (conn->sock >= 0) {
10897 wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
10898 conn->sock);
10899 eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
10900 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
10901 close(conn->sock);
10902 }
Hai Shalomc3565922019-10-28 11:58:20 -070010903 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
10904 conn, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070010905 wpabuf_free(conn->msg);
10906 wpabuf_free(conn->msg_out);
10907 dpp_auth_deinit(conn->auth);
10908 os_free(conn);
10909}
10910
10911
10912static void dpp_connection_remove(struct dpp_connection *conn)
10913{
10914 dl_list_del(&conn->list);
10915 dpp_connection_free(conn);
10916}
10917
10918
10919static void dpp_tcp_init_flush(struct dpp_global *dpp)
10920{
10921 struct dpp_connection *conn, *tmp;
10922
10923 dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
10924 list)
10925 dpp_connection_remove(conn);
10926}
10927
10928
10929static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
10930{
10931 struct dpp_connection *conn, *tmp;
10932
10933 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
10934 list)
10935 dpp_connection_remove(conn);
10936 os_free(ctrl);
10937}
10938
10939
10940static void dpp_relay_flush_controllers(struct dpp_global *dpp)
10941{
10942 struct dpp_relay_controller *ctrl, *tmp;
10943
10944 if (!dpp)
10945 return;
10946
10947 dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
10948 struct dpp_relay_controller, list) {
10949 dl_list_del(&ctrl->list);
10950 dpp_relay_controller_free(ctrl);
10951 }
10952}
10953
10954#endif /* CONFIG_DPP2 */
10955
10956
10957struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -070010958{
10959 struct dpp_global *dpp;
10960
10961 dpp = os_zalloc(sizeof(*dpp));
10962 if (!dpp)
10963 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -070010964 dpp->msg_ctx = config->msg_ctx;
10965#ifdef CONFIG_DPP2
10966 dpp->cb_ctx = config->cb_ctx;
10967 dpp->process_conf_obj = config->process_conf_obj;
Hai Shalomfdcde762020-04-02 11:19:20 -070010968 dpp->remove_bi = config->remove_bi;
Hai Shalom81f62d82019-07-22 12:10:00 -070010969#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070010970
10971 dl_list_init(&dpp->bootstrap);
10972 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -070010973#ifdef CONFIG_DPP2
10974 dl_list_init(&dpp->controllers);
10975 dl_list_init(&dpp->tcp_init);
10976#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070010977
10978 return dpp;
10979}
10980
10981
10982void dpp_global_clear(struct dpp_global *dpp)
10983{
10984 if (!dpp)
10985 return;
10986
10987 dpp_bootstrap_del(dpp, 0);
10988 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -070010989#ifdef CONFIG_DPP2
10990 dpp_tcp_init_flush(dpp);
10991 dpp_relay_flush_controllers(dpp);
10992 dpp_controller_stop(dpp);
10993#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070010994}
10995
10996
10997void dpp_global_deinit(struct dpp_global *dpp)
10998{
10999 dpp_global_clear(dpp);
11000 os_free(dpp);
11001}
Hai Shalom81f62d82019-07-22 12:10:00 -070011002
11003
11004#ifdef CONFIG_DPP2
11005
11006static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
11007static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
11008static void dpp_controller_auth_success(struct dpp_connection *conn,
11009 int initiator);
11010
11011
11012int dpp_relay_add_controller(struct dpp_global *dpp,
11013 struct dpp_relay_config *config)
11014{
11015 struct dpp_relay_controller *ctrl;
11016
11017 if (!dpp)
11018 return -1;
11019
11020 ctrl = os_zalloc(sizeof(*ctrl));
11021 if (!ctrl)
11022 return -1;
11023 dl_list_init(&ctrl->conn);
11024 ctrl->global = dpp;
11025 os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
11026 os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
11027 ctrl->cb_ctx = config->cb_ctx;
11028 ctrl->tx = config->tx;
11029 ctrl->gas_resp_tx = config->gas_resp_tx;
11030 dl_list_add(&dpp->controllers, &ctrl->list);
11031 return 0;
11032}
11033
11034
11035static struct dpp_relay_controller *
11036dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
11037{
11038 struct dpp_relay_controller *ctrl;
11039
11040 if (!dpp)
11041 return NULL;
11042
11043 dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
11044 list) {
11045 if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
11046 return ctrl;
11047 }
11048
11049 return NULL;
11050}
11051
11052
11053static void dpp_controller_gas_done(struct dpp_connection *conn)
11054{
11055 struct dpp_authentication *auth = conn->auth;
11056
11057 if (auth->peer_version >= 2 &&
11058 auth->conf_resp_status == DPP_STATUS_OK) {
11059 wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
11060 auth->waiting_conf_result = 1;
11061 return;
11062 }
11063
11064 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
11065 dpp_connection_remove(conn);
11066}
11067
11068
11069static int dpp_tcp_send(struct dpp_connection *conn)
11070{
11071 int res;
11072
11073 if (!conn->msg_out) {
11074 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
11075 conn->write_eloop = 0;
11076 return -1;
11077 }
11078 res = send(conn->sock,
11079 wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
11080 wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
11081 if (res < 0) {
11082 wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
11083 strerror(errno));
11084 dpp_connection_remove(conn);
11085 return -1;
11086 }
11087
11088 conn->msg_out_pos += res;
11089 if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
11090 wpa_printf(MSG_DEBUG,
11091 "DPP: %u/%u bytes of message sent to Controller",
11092 (unsigned int) conn->msg_out_pos,
11093 (unsigned int) wpabuf_len(conn->msg_out));
11094 if (!conn->write_eloop &&
11095 eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11096 dpp_conn_tx_ready, conn, NULL) == 0)
11097 conn->write_eloop = 1;
11098 return 1;
11099 }
11100
11101 wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
11102 wpabuf_free(conn->msg_out);
11103 conn->msg_out = NULL;
11104 conn->msg_out_pos = 0;
11105 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
11106 conn->write_eloop = 0;
11107 if (!conn->read_eloop &&
11108 eloop_register_sock(conn->sock, EVENT_TYPE_READ,
11109 dpp_controller_rx, conn, NULL) == 0)
11110 conn->read_eloop = 1;
11111 if (conn->on_tcp_tx_complete_remove) {
11112 dpp_connection_remove(conn);
11113 } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
11114 conn->auth) {
11115 dpp_controller_gas_done(conn);
11116 } else if (conn->on_tcp_tx_complete_auth_ok) {
11117 conn->on_tcp_tx_complete_auth_ok = 0;
11118 dpp_controller_auth_success(conn, 1);
11119 }
11120
11121 return 0;
11122}
11123
11124
Hai Shalomfdcde762020-04-02 11:19:20 -070011125static int dpp_tcp_send_msg(struct dpp_connection *conn,
11126 const struct wpabuf *msg)
11127{
11128 wpabuf_free(conn->msg_out);
11129 conn->msg_out_pos = 0;
11130 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
11131 if (!conn->msg_out)
11132 return -1;
11133 wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
11134 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
11135 wpabuf_len(msg) - 1);
11136
11137 if (dpp_tcp_send(conn) == 1) {
11138 if (!conn->write_eloop) {
11139 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11140 dpp_conn_tx_ready,
11141 conn, NULL) < 0)
11142 return -1;
11143 conn->write_eloop = 1;
11144 }
11145 }
11146
11147 return 0;
11148}
11149
11150
Hai Shalom81f62d82019-07-22 12:10:00 -070011151static void dpp_controller_start_gas_client(struct dpp_connection *conn)
11152{
11153 struct dpp_authentication *auth = conn->auth;
11154 struct wpabuf *buf;
Hai Shalom81f62d82019-07-22 12:10:00 -070011155 int netrole_ap = 0; /* TODO: make this configurable */
11156
Hai Shalomc3565922019-10-28 11:58:20 -070011157 buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070011158 if (!buf) {
11159 wpa_printf(MSG_DEBUG,
11160 "DPP: No configuration request data available");
11161 return;
11162 }
11163
Hai Shalomfdcde762020-04-02 11:19:20 -070011164 dpp_tcp_send_msg(conn, buf);
Hai Shalom81f62d82019-07-22 12:10:00 -070011165 wpabuf_free(buf);
Hai Shalom81f62d82019-07-22 12:10:00 -070011166}
11167
11168
11169static void dpp_controller_auth_success(struct dpp_connection *conn,
11170 int initiator)
11171{
11172 struct dpp_authentication *auth = conn->auth;
11173
11174 if (!auth)
11175 return;
11176
11177 wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
11178 wpa_msg(conn->global->msg_ctx, MSG_INFO,
11179 DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
11180#ifdef CONFIG_TESTING_OPTIONS
11181 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
11182 wpa_printf(MSG_INFO,
11183 "DPP: TESTING - stop at Authentication Confirm");
11184 if (auth->configurator) {
11185 /* Prevent GAS response */
11186 auth->auth_success = 0;
11187 }
11188 return;
11189 }
11190#endif /* CONFIG_TESTING_OPTIONS */
11191
11192 if (!auth->configurator)
11193 dpp_controller_start_gas_client(conn);
11194}
11195
11196
11197static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
11198{
11199 struct dpp_connection *conn = eloop_ctx;
11200
11201 wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
11202 dpp_tcp_send(conn);
11203}
11204
11205
11206static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
11207 const struct hostapd_ip_addr *ipaddr,
11208 int port)
11209{
11210 struct sockaddr_in *dst;
11211#ifdef CONFIG_IPV6
11212 struct sockaddr_in6 *dst6;
11213#endif /* CONFIG_IPV6 */
11214
11215 switch (ipaddr->af) {
11216 case AF_INET:
11217 dst = (struct sockaddr_in *) addr;
11218 os_memset(dst, 0, sizeof(*dst));
11219 dst->sin_family = AF_INET;
11220 dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
11221 dst->sin_port = htons(port);
11222 *addrlen = sizeof(*dst);
11223 break;
11224#ifdef CONFIG_IPV6
11225 case AF_INET6:
11226 dst6 = (struct sockaddr_in6 *) addr;
11227 os_memset(dst6, 0, sizeof(*dst6));
11228 dst6->sin6_family = AF_INET6;
11229 os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
11230 sizeof(struct in6_addr));
11231 dst6->sin6_port = htons(port);
11232 *addrlen = sizeof(*dst6);
11233 break;
11234#endif /* CONFIG_IPV6 */
11235 default:
11236 return -1;
11237 }
11238
11239 return 0;
11240}
11241
11242
11243static struct dpp_connection *
11244dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
11245 unsigned int freq)
11246{
11247 struct dpp_connection *conn;
11248 struct sockaddr_storage addr;
11249 socklen_t addrlen;
11250 char txt[100];
11251
11252 if (dl_list_len(&ctrl->conn) >= 15) {
11253 wpa_printf(MSG_DEBUG,
11254 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
11255 return NULL;
11256 }
11257
11258 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
11259 &ctrl->ipaddr, DPP_TCP_PORT) < 0)
11260 return NULL;
11261
11262 conn = os_zalloc(sizeof(*conn));
11263 if (!conn)
11264 return NULL;
11265
11266 conn->global = ctrl->global;
11267 conn->relay = ctrl;
11268 os_memcpy(conn->mac_addr, src, ETH_ALEN);
11269 conn->freq = freq;
11270
11271 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
11272 if (conn->sock < 0)
11273 goto fail;
11274 wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
11275 conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
11276
11277 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
11278 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
11279 strerror(errno));
11280 goto fail;
11281 }
11282
11283 if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
11284 if (errno != EINPROGRESS) {
11285 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
11286 strerror(errno));
11287 goto fail;
11288 }
11289
11290 /*
11291 * Continue connecting in the background; eloop will call us
11292 * once the connection is ready (or failed).
11293 */
11294 }
11295
11296 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11297 dpp_conn_tx_ready, conn, NULL) < 0)
11298 goto fail;
11299 conn->write_eloop = 1;
11300
11301 /* TODO: eloop timeout to clear a connection if it does not complete
11302 * properly */
11303
11304 dl_list_add(&ctrl->conn, &conn->list);
11305 return conn;
11306fail:
11307 dpp_connection_free(conn);
11308 return NULL;
11309}
11310
11311
11312static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
11313{
11314 struct wpabuf *msg;
11315
11316 msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
11317 if (!msg)
11318 return NULL;
11319 wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
11320 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
11321 wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
11322 wpabuf_put_data(msg, buf, len);
11323 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
11324 return msg;
11325}
11326
11327
11328static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
11329 const u8 *buf, size_t len)
11330{
11331 u8 type = hdr[DPP_HDR_LEN - 1];
11332
11333 wpa_printf(MSG_DEBUG,
11334 "DPP: Continue already established Relay/Controller connection for this session");
11335 wpabuf_free(conn->msg_out);
11336 conn->msg_out_pos = 0;
11337 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
11338 if (!conn->msg_out) {
11339 dpp_connection_remove(conn);
11340 return -1;
11341 }
11342
11343 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
11344 * TX status */
11345 if (type == DPP_PA_CONFIGURATION_RESULT)
11346 conn->on_tcp_tx_complete_remove = 1;
11347 dpp_tcp_send(conn);
11348 return 0;
11349}
11350
11351
11352int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
11353 const u8 *buf, size_t len, unsigned int freq,
11354 const u8 *i_bootstrap, const u8 *r_bootstrap)
11355{
11356 struct dpp_relay_controller *ctrl;
11357 struct dpp_connection *conn;
11358 u8 type = hdr[DPP_HDR_LEN - 1];
11359
11360 /* Check if there is an already started session for this peer and if so,
11361 * continue that session (send this over TCP) and return 0.
11362 */
11363 if (type != DPP_PA_PEER_DISCOVERY_REQ &&
Hai Shalomfdcde762020-04-02 11:19:20 -070011364 type != DPP_PA_PEER_DISCOVERY_RESP &&
11365 type != DPP_PA_PRESENCE_ANNOUNCEMENT) {
Hai Shalom81f62d82019-07-22 12:10:00 -070011366 dl_list_for_each(ctrl, &dpp->controllers,
11367 struct dpp_relay_controller, list) {
11368 dl_list_for_each(conn, &ctrl->conn,
11369 struct dpp_connection, list) {
11370 if (os_memcmp(src, conn->mac_addr,
11371 ETH_ALEN) == 0)
11372 return dpp_relay_tx(conn, hdr, buf, len);
11373 }
11374 }
11375 }
11376
11377 if (!r_bootstrap)
11378 return -1;
11379
Hai Shalomfdcde762020-04-02 11:19:20 -070011380 if (type == DPP_PA_PRESENCE_ANNOUNCEMENT) {
11381 /* TODO: Could send this to all configured Controllers. For now,
11382 * only the first Controller is supported. */
11383 ctrl = dl_list_first(&dpp->controllers,
11384 struct dpp_relay_controller, list);
11385 } else {
11386 ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
11387 }
Hai Shalom81f62d82019-07-22 12:10:00 -070011388 if (!ctrl)
11389 return -1;
11390
11391 wpa_printf(MSG_DEBUG,
11392 "DPP: Authentication Request for a configured Controller");
11393 conn = dpp_relay_new_conn(ctrl, src, freq);
11394 if (!conn)
11395 return -1;
11396
11397 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
11398 if (!conn->msg_out) {
11399 dpp_connection_remove(conn);
11400 return -1;
11401 }
11402 /* Message will be sent in dpp_conn_tx_ready() */
11403
11404 return 0;
11405}
11406
11407
11408int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
11409 size_t data_len)
11410{
11411 struct dpp_relay_controller *ctrl;
11412 struct dpp_connection *conn, *found = NULL;
11413 struct wpabuf *msg;
11414
11415 /* Check if there is a successfully completed authentication for this
11416 * and if so, continue that session (send this over TCP) and return 0.
11417 */
11418 dl_list_for_each(ctrl, &dpp->controllers,
11419 struct dpp_relay_controller, list) {
11420 if (found)
11421 break;
11422 dl_list_for_each(conn, &ctrl->conn,
11423 struct dpp_connection, list) {
11424 if (os_memcmp(src, conn->mac_addr,
11425 ETH_ALEN) == 0) {
11426 found = conn;
11427 break;
11428 }
11429 }
11430 }
11431
11432 if (!found)
11433 return -1;
11434
11435 msg = wpabuf_alloc(4 + 1 + data_len);
11436 if (!msg)
11437 return -1;
11438 wpabuf_put_be32(msg, 1 + data_len);
11439 wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
11440 wpabuf_put_data(msg, data, data_len);
11441 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
11442
11443 wpabuf_free(conn->msg_out);
11444 conn->msg_out_pos = 0;
11445 conn->msg_out = msg;
11446 dpp_tcp_send(conn);
11447 return 0;
11448}
11449
11450
11451static void dpp_controller_free(struct dpp_controller *ctrl)
11452{
11453 struct dpp_connection *conn, *tmp;
11454
11455 if (!ctrl)
11456 return;
11457
11458 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
11459 list)
11460 dpp_connection_remove(conn);
11461
11462 if (ctrl->sock >= 0) {
11463 close(ctrl->sock);
11464 eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
11465 }
11466 os_free(ctrl->configurator_params);
11467 os_free(ctrl);
11468}
11469
11470
11471static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
11472 const u8 *hdr, const u8 *buf, size_t len)
11473{
11474 const u8 *r_bootstrap, *i_bootstrap;
11475 u16 r_bootstrap_len, i_bootstrap_len;
11476 struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
11477
11478 if (!conn->ctrl)
11479 return 0;
11480
11481 wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
11482
11483 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
11484 &r_bootstrap_len);
11485 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
11486 wpa_printf(MSG_INFO,
11487 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11488 return -1;
11489 }
11490 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
11491 r_bootstrap, r_bootstrap_len);
11492
11493 i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
11494 &i_bootstrap_len);
11495 if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
11496 wpa_printf(MSG_INFO,
11497 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
11498 return -1;
11499 }
11500 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
11501 i_bootstrap, i_bootstrap_len);
11502
11503 /* Try to find own and peer bootstrapping key matches based on the
11504 * received hash values */
11505 dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
11506 &own_bi, &peer_bi);
11507 if (!own_bi) {
11508 wpa_printf(MSG_INFO,
11509 "No matching own bootstrapping key found - ignore message");
11510 return -1;
11511 }
11512
11513 if (conn->auth) {
11514 wpa_printf(MSG_INFO,
11515 "Already in DPP authentication exchange - ignore new one");
11516 return 0;
11517 }
11518
Hai Shalomfdcde762020-04-02 11:19:20 -070011519 conn->auth = dpp_auth_req_rx(conn->ctrl->global,
11520 conn->ctrl->global->msg_ctx,
Hai Shalom81f62d82019-07-22 12:10:00 -070011521 conn->ctrl->allowed_roles,
11522 conn->ctrl->qr_mutual,
11523 peer_bi, own_bi, -1, hdr, buf, len);
11524 if (!conn->auth) {
11525 wpa_printf(MSG_DEBUG, "DPP: No response generated");
11526 return -1;
11527 }
11528
Hai Shalomfdcde762020-04-02 11:19:20 -070011529 if (dpp_set_configurator(conn->auth,
Hai Shalom81f62d82019-07-22 12:10:00 -070011530 conn->ctrl->configurator_params) < 0) {
11531 dpp_connection_remove(conn);
11532 return -1;
11533 }
11534
Hai Shalomfdcde762020-04-02 11:19:20 -070011535 return dpp_tcp_send_msg(conn, conn->auth->resp_msg);
Hai Shalom81f62d82019-07-22 12:10:00 -070011536}
11537
11538
11539static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
11540 const u8 *hdr, const u8 *buf, size_t len)
11541{
11542 struct dpp_authentication *auth = conn->auth;
11543 struct wpabuf *msg;
Hai Shalomfdcde762020-04-02 11:19:20 -070011544 int res;
Hai Shalom81f62d82019-07-22 12:10:00 -070011545
11546 if (!auth)
11547 return -1;
11548
11549 wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
11550
11551 msg = dpp_auth_resp_rx(auth, hdr, buf, len);
11552 if (!msg) {
11553 if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
11554 wpa_printf(MSG_DEBUG,
11555 "DPP: Start wait for full response");
11556 return -1;
11557 }
11558 wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
11559 dpp_connection_remove(conn);
11560 return -1;
11561 }
11562
Hai Shalom81f62d82019-07-22 12:10:00 -070011563 conn->on_tcp_tx_complete_auth_ok = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -070011564 res = dpp_tcp_send_msg(conn, msg);
11565 wpabuf_free(msg);
11566 return res;
Hai Shalom81f62d82019-07-22 12:10:00 -070011567}
11568
11569
11570static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
11571 const u8 *hdr, const u8 *buf, size_t len)
11572{
11573 struct dpp_authentication *auth = conn->auth;
11574
11575 wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
11576
11577 if (!auth) {
11578 wpa_printf(MSG_DEBUG,
11579 "DPP: No DPP Authentication in progress - drop");
11580 return -1;
11581 }
11582
11583 if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
11584 wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
11585 return -1;
11586 }
11587
11588 dpp_controller_auth_success(conn, 0);
11589 return 0;
11590}
11591
11592
Hai Shalomc3565922019-10-28 11:58:20 -070011593static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
11594 void *timeout_ctx)
11595{
11596 struct dpp_connection *conn = eloop_ctx;
11597
11598 if (!conn->auth->waiting_conf_result)
11599 return;
11600
11601 wpa_printf(MSG_DEBUG,
11602 "DPP: Timeout while waiting for Connection Status Result");
11603 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11604 DPP_EVENT_CONN_STATUS_RESULT "timeout");
11605 dpp_connection_remove(conn);
11606}
11607
11608
Hai Shalom81f62d82019-07-22 12:10:00 -070011609static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
11610 const u8 *hdr, const u8 *buf,
11611 size_t len)
11612{
11613 struct dpp_authentication *auth = conn->auth;
11614 enum dpp_status_error status;
11615
11616 if (!conn->ctrl)
11617 return 0;
11618
11619 wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
11620
11621 if (!auth || !auth->waiting_conf_result) {
11622 wpa_printf(MSG_DEBUG,
11623 "DPP: No DPP Configuration waiting for result - drop");
11624 return -1;
11625 }
11626
11627 status = dpp_conf_result_rx(auth, hdr, buf, len);
Hai Shalomc3565922019-10-28 11:58:20 -070011628 if (status == DPP_STATUS_OK && auth->send_conn_status) {
11629 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11630 DPP_EVENT_CONF_SENT "wait_conn_status=1");
11631 wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
11632 eloop_cancel_timeout(
11633 dpp_controller_conn_status_result_wait_timeout,
11634 conn, NULL);
11635 eloop_register_timeout(
11636 16, 0, dpp_controller_conn_status_result_wait_timeout,
11637 conn, NULL);
11638 return 0;
11639 }
Hai Shalom81f62d82019-07-22 12:10:00 -070011640 if (status == DPP_STATUS_OK)
11641 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11642 DPP_EVENT_CONF_SENT);
11643 else
11644 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11645 DPP_EVENT_CONF_FAILED);
11646 return -1; /* to remove the completed connection */
11647}
11648
11649
Hai Shalomc3565922019-10-28 11:58:20 -070011650static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
11651 const u8 *hdr, const u8 *buf,
11652 size_t len)
11653{
11654 struct dpp_authentication *auth = conn->auth;
11655 enum dpp_status_error status;
11656 u8 ssid[SSID_MAX_LEN];
11657 size_t ssid_len = 0;
11658 char *channel_list = NULL;
11659
11660 if (!conn->ctrl)
11661 return 0;
11662
11663 wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
11664
11665 if (!auth || !auth->waiting_conn_status_result) {
11666 wpa_printf(MSG_DEBUG,
11667 "DPP: No DPP Configuration waiting for connection status result - drop");
11668 return -1;
11669 }
11670
11671 status = dpp_conn_status_result_rx(auth, hdr, buf, len,
11672 ssid, &ssid_len, &channel_list);
11673 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11674 DPP_EVENT_CONN_STATUS_RESULT
11675 "result=%d ssid=%s channel_list=%s",
11676 status, wpa_ssid_txt(ssid, ssid_len),
11677 channel_list ? channel_list : "N/A");
11678 os_free(channel_list);
11679 return -1; /* to remove the completed connection */
11680}
11681
11682
Hai Shalomfdcde762020-04-02 11:19:20 -070011683static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
11684 const u8 *hdr, const u8 *buf,
11685 size_t len)
11686{
11687 const u8 *r_bootstrap;
11688 u16 r_bootstrap_len;
11689 struct dpp_bootstrap_info *peer_bi;
11690 struct dpp_authentication *auth;
11691 struct dpp_global *dpp = conn->ctrl->global;
11692
11693 if (conn->auth) {
11694 wpa_printf(MSG_DEBUG,
11695 "DPP: Ignore Presence Announcement during ongoing Authentication");
11696 return -1;
11697 }
11698
11699 wpa_printf(MSG_DEBUG, "DPP: Presence Announcement");
11700
11701 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
11702 &r_bootstrap_len);
11703 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
11704 wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
11705 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11706 return -1;
11707 }
11708 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
11709 r_bootstrap, r_bootstrap_len);
11710 peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap);
11711 if (!peer_bi) {
11712 wpa_printf(MSG_DEBUG,
11713 "DPP: No matching bootstrapping information found");
11714 return -1;
11715 }
11716
11717 auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL,
11718 DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
11719 if (!auth)
11720 return -1;
11721 if (dpp_set_configurator(conn->auth,
11722 conn->ctrl->configurator_params) < 0) {
11723 dpp_auth_deinit(auth);
11724 dpp_connection_remove(conn);
11725 return -1;
11726 }
11727
11728 conn->auth = auth;
11729 return dpp_tcp_send_msg(conn, conn->auth->req_msg);
11730}
11731
11732
Hai Shalom81f62d82019-07-22 12:10:00 -070011733static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
11734 size_t len)
11735{
11736 const u8 *pos, *end;
11737 u8 type;
11738
11739 wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
11740 pos = msg;
11741 end = msg + len;
11742
11743 if (end - pos < DPP_HDR_LEN ||
11744 WPA_GET_BE24(pos) != OUI_WFA ||
11745 pos[3] != DPP_OUI_TYPE) {
11746 wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
11747 return -1;
11748 }
11749
11750 if (pos[4] != 1) {
11751 wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
11752 pos[4]);
11753 return -1;
11754 }
11755 type = pos[5];
11756 wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
11757 pos += DPP_HDR_LEN;
11758
11759 wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
11760 pos, end - pos);
11761 if (dpp_check_attrs(pos, end - pos) < 0)
11762 return -1;
11763
11764 if (conn->relay) {
11765 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
11766 conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
11767 conn->freq, msg, len);
11768 return 0;
11769 }
11770
11771 switch (type) {
11772 case DPP_PA_AUTHENTICATION_REQ:
11773 return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
11774 case DPP_PA_AUTHENTICATION_RESP:
11775 return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
11776 case DPP_PA_AUTHENTICATION_CONF:
11777 return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
11778 case DPP_PA_CONFIGURATION_RESULT:
11779 return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
Hai Shalomc3565922019-10-28 11:58:20 -070011780 case DPP_PA_CONNECTION_STATUS_RESULT:
11781 return dpp_controller_rx_conn_status_result(conn, msg, pos,
11782 end - pos);
Hai Shalomfdcde762020-04-02 11:19:20 -070011783 case DPP_PA_PRESENCE_ANNOUNCEMENT:
11784 return dpp_controller_rx_presence_announcement(conn, msg, pos,
11785 end - pos);
Hai Shalom81f62d82019-07-22 12:10:00 -070011786 default:
11787 /* TODO: missing messages types */
11788 wpa_printf(MSG_DEBUG,
11789 "DPP: Unsupported frame subtype %d", type);
11790 return -1;
11791 }
11792}
11793
11794
11795static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
11796 size_t len)
11797{
11798 const u8 *pos, *end, *next;
11799 u8 dialog_token;
11800 const u8 *adv_proto;
11801 u16 slen;
11802 struct wpabuf *resp, *buf;
11803 struct dpp_authentication *auth = conn->auth;
11804
11805 if (len < 1 + 2)
11806 return -1;
11807
11808 wpa_printf(MSG_DEBUG,
11809 "DPP: Received DPP Configuration Request over TCP");
11810
11811 if (!conn->ctrl || !auth || !auth->auth_success) {
11812 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
11813 return -1;
11814 }
11815
11816 pos = msg;
11817 end = msg + len;
11818
11819 dialog_token = *pos++;
11820 adv_proto = pos++;
11821 slen = *pos++;
11822 if (*adv_proto != WLAN_EID_ADV_PROTO ||
11823 slen > end - pos || slen < 2)
11824 return -1;
11825
11826 next = pos + slen;
11827 pos++; /* skip QueryRespLenLimit and PAME-BI */
11828
11829 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
11830 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
11831 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
11832 return -1;
11833
11834 pos = next;
11835 /* Query Request */
11836 if (end - pos < 2)
11837 return -1;
11838 slen = WPA_GET_LE16(pos);
11839 pos += 2;
11840 if (slen > end - pos)
11841 return -1;
11842
11843 resp = dpp_conf_req_rx(auth, pos, slen);
11844 if (!resp)
11845 return -1;
11846
11847 buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
11848 if (!buf) {
11849 wpabuf_free(resp);
11850 return -1;
11851 }
11852
11853 wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
11854
11855 wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
11856 wpabuf_put_u8(buf, dialog_token);
11857 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
11858 wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
11859
11860 dpp_write_adv_proto(buf);
11861 dpp_write_gas_query(buf, resp);
11862 wpabuf_free(resp);
11863
11864 /* Send Config Response over TCP; GAS fragmentation is taken care of by
11865 * the Relay */
11866 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
11867 wpabuf_free(conn->msg_out);
11868 conn->msg_out_pos = 0;
11869 conn->msg_out = buf;
11870 conn->on_tcp_tx_complete_gas_done = 1;
11871 dpp_tcp_send(conn);
11872 return 0;
11873}
11874
11875
11876static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
11877{
11878 struct dpp_authentication *auth = conn->auth;
11879 int res;
Hai Shalomfdcde762020-04-02 11:19:20 -070011880 struct wpabuf *msg;
Hai Shalom81f62d82019-07-22 12:10:00 -070011881 enum dpp_status_error status;
11882
11883 wpa_printf(MSG_DEBUG,
11884 "DPP: Configuration Response for local stack from TCP");
11885
11886 res = dpp_conf_resp_rx(auth, resp);
11887 wpabuf_free(resp);
11888 if (res < 0) {
11889 wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
11890 return -1;
11891 }
11892
11893 if (conn->global->process_conf_obj)
11894 res = conn->global->process_conf_obj(conn->global->cb_ctx,
11895 auth);
11896 else
11897 res = 0;
11898
11899 if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
11900 return -1;
11901
11902 wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
11903 status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
11904 msg = dpp_build_conf_result(auth, status);
11905 if (!msg)
11906 return -1;
11907
Hai Shalom81f62d82019-07-22 12:10:00 -070011908 conn->on_tcp_tx_complete_remove = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -070011909 res = dpp_tcp_send_msg(conn, msg);
11910 wpabuf_free(msg);
Hai Shalom81f62d82019-07-22 12:10:00 -070011911
11912 /* This exchange will be terminated in the TX status handler */
11913
Hai Shalomfdcde762020-04-02 11:19:20 -070011914 return res;
Hai Shalom81f62d82019-07-22 12:10:00 -070011915}
11916
11917
11918static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
11919 size_t len)
11920{
11921 struct wpabuf *buf;
11922 u8 dialog_token;
11923 const u8 *pos, *end, *next, *adv_proto;
11924 u16 status, slen;
11925
11926 if (len < 5 + 2)
11927 return -1;
11928
11929 wpa_printf(MSG_DEBUG,
11930 "DPP: Received DPP Configuration Response over TCP");
11931
11932 pos = msg;
11933 end = msg + len;
11934
11935 dialog_token = *pos++;
11936 status = WPA_GET_LE16(pos);
11937 if (status != WLAN_STATUS_SUCCESS) {
11938 wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
11939 return -1;
11940 }
11941 pos += 2;
11942 pos += 2; /* ignore GAS Comeback Delay */
11943
11944 adv_proto = pos++;
11945 slen = *pos++;
11946 if (*adv_proto != WLAN_EID_ADV_PROTO ||
11947 slen > end - pos || slen < 2)
11948 return -1;
11949
11950 next = pos + slen;
11951 pos++; /* skip QueryRespLenLimit and PAME-BI */
11952
11953 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
11954 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
11955 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
11956 return -1;
11957
11958 pos = next;
11959 /* Query Response */
11960 if (end - pos < 2)
11961 return -1;
11962 slen = WPA_GET_LE16(pos);
11963 pos += 2;
11964 if (slen > end - pos)
11965 return -1;
11966
11967 buf = wpabuf_alloc(slen);
11968 if (!buf)
11969 return -1;
11970 wpabuf_put_data(buf, pos, slen);
11971
11972 if (!conn->relay && !conn->ctrl)
11973 return dpp_tcp_rx_gas_resp(conn, buf);
11974
11975 if (!conn->relay) {
11976 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
11977 wpabuf_free(buf);
11978 return -1;
11979 }
11980 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
11981 conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
11982 dialog_token, 0, buf);
11983
11984 return 0;
11985}
11986
11987
11988static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
11989{
11990 struct dpp_connection *conn = eloop_ctx;
11991 int res;
11992 const u8 *pos;
11993
11994 wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
11995 sd);
11996
11997 if (conn->msg_len_octets < 4) {
11998 u32 msglen;
11999
12000 res = recv(sd, &conn->msg_len[conn->msg_len_octets],
12001 4 - conn->msg_len_octets, 0);
12002 if (res < 0) {
12003 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
12004 strerror(errno));
12005 dpp_connection_remove(conn);
12006 return;
12007 }
12008 if (res == 0) {
12009 wpa_printf(MSG_DEBUG,
12010 "DPP: No more data available over TCP");
12011 dpp_connection_remove(conn);
12012 return;
12013 }
12014 wpa_printf(MSG_DEBUG,
12015 "DPP: Received %d/%d octet(s) of message length field",
12016 res, (int) (4 - conn->msg_len_octets));
12017 conn->msg_len_octets += res;
12018
12019 if (conn->msg_len_octets < 4) {
12020 wpa_printf(MSG_DEBUG,
12021 "DPP: Need %d more octets of message length field",
12022 (int) (4 - conn->msg_len_octets));
12023 return;
12024 }
12025
12026 msglen = WPA_GET_BE32(conn->msg_len);
12027 wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
12028 if (msglen > 65535) {
12029 wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
12030 dpp_connection_remove(conn);
12031 return;
12032 }
12033
12034 wpabuf_free(conn->msg);
12035 conn->msg = wpabuf_alloc(msglen);
12036 }
12037
12038 if (!conn->msg) {
12039 wpa_printf(MSG_DEBUG,
12040 "DPP: No buffer available for receiving the message");
12041 dpp_connection_remove(conn);
12042 return;
12043 }
12044
12045 wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
12046 (unsigned int) wpabuf_tailroom(conn->msg));
12047
12048 res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
12049 if (res < 0) {
12050 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
12051 dpp_connection_remove(conn);
12052 return;
12053 }
12054 if (res == 0) {
12055 wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
12056 dpp_connection_remove(conn);
12057 return;
12058 }
12059 wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
12060 wpabuf_put(conn->msg, res);
12061
12062 if (wpabuf_tailroom(conn->msg) > 0) {
12063 wpa_printf(MSG_DEBUG,
12064 "DPP: Need %u more octets of message payload",
12065 (unsigned int) wpabuf_tailroom(conn->msg));
12066 return;
12067 }
12068
12069 conn->msg_len_octets = 0;
12070 wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
12071 if (wpabuf_len(conn->msg) < 1) {
12072 dpp_connection_remove(conn);
12073 return;
12074 }
12075
12076 pos = wpabuf_head(conn->msg);
12077 switch (*pos) {
12078 case WLAN_PA_VENDOR_SPECIFIC:
12079 if (dpp_controller_rx_action(conn, pos + 1,
12080 wpabuf_len(conn->msg) - 1) < 0)
12081 dpp_connection_remove(conn);
12082 break;
12083 case WLAN_PA_GAS_INITIAL_REQ:
12084 if (dpp_controller_rx_gas_req(conn, pos + 1,
12085 wpabuf_len(conn->msg) - 1) < 0)
12086 dpp_connection_remove(conn);
12087 break;
12088 case WLAN_PA_GAS_INITIAL_RESP:
12089 if (dpp_rx_gas_resp(conn, pos + 1,
12090 wpabuf_len(conn->msg) - 1) < 0)
12091 dpp_connection_remove(conn);
12092 break;
12093 default:
12094 wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
12095 *pos);
12096 break;
12097 }
12098}
12099
12100
12101static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
12102{
12103 struct dpp_controller *ctrl = eloop_ctx;
12104 struct sockaddr_in addr;
12105 socklen_t addr_len = sizeof(addr);
12106 int fd;
12107 struct dpp_connection *conn;
12108
12109 wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
12110
12111 fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
12112 if (fd < 0) {
12113 wpa_printf(MSG_DEBUG,
12114 "DPP: Failed to accept new connection: %s",
12115 strerror(errno));
12116 return;
12117 }
12118 wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
12119 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
12120
12121 conn = os_zalloc(sizeof(*conn));
12122 if (!conn)
12123 goto fail;
12124
12125 conn->global = ctrl->global;
12126 conn->ctrl = ctrl;
12127 conn->sock = fd;
12128
12129 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
12130 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
12131 strerror(errno));
12132 goto fail;
12133 }
12134
12135 if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
12136 dpp_controller_rx, conn, NULL) < 0)
12137 goto fail;
12138 conn->read_eloop = 1;
12139
12140 /* TODO: eloop timeout to expire connections that do not complete in
12141 * reasonable time */
12142 dl_list_add(&ctrl->conn, &conn->list);
12143 return;
12144
12145fail:
12146 close(fd);
12147 os_free(conn);
12148}
12149
12150
12151int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
12152 const struct hostapd_ip_addr *addr, int port)
12153{
12154 struct dpp_connection *conn;
12155 struct sockaddr_storage saddr;
12156 socklen_t addrlen;
12157 const u8 *hdr, *pos, *end;
12158 char txt[100];
12159
12160 wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
12161 hostapd_ip_txt(addr, txt, sizeof(txt)), port);
12162 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
12163 addr, port) < 0) {
12164 dpp_auth_deinit(auth);
12165 return -1;
12166 }
12167
12168 conn = os_zalloc(sizeof(*conn));
12169 if (!conn) {
12170 dpp_auth_deinit(auth);
12171 return -1;
12172 }
12173
12174 conn->global = dpp;
12175 conn->auth = auth;
12176 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
12177 if (conn->sock < 0)
12178 goto fail;
12179
12180 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
12181 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
12182 strerror(errno));
12183 goto fail;
12184 }
12185
12186 if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
12187 if (errno != EINPROGRESS) {
12188 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
12189 strerror(errno));
12190 goto fail;
12191 }
12192
12193 /*
12194 * Continue connecting in the background; eloop will call us
12195 * once the connection is ready (or failed).
12196 */
12197 }
12198
12199 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
12200 dpp_conn_tx_ready, conn, NULL) < 0)
12201 goto fail;
12202 conn->write_eloop = 1;
12203
12204 hdr = wpabuf_head(auth->req_msg);
12205 end = hdr + wpabuf_len(auth->req_msg);
12206 hdr += 2; /* skip Category and Actiom */
12207 pos = hdr + DPP_HDR_LEN;
12208 conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
12209 if (!conn->msg_out)
12210 goto fail;
12211 /* Message will be sent in dpp_conn_tx_ready() */
12212
12213 /* TODO: eloop timeout to clear a connection if it does not complete
12214 * properly */
12215 dl_list_add(&dpp->tcp_init, &conn->list);
12216 return 0;
12217fail:
12218 dpp_connection_free(conn);
12219 return -1;
12220}
12221
12222
12223int dpp_controller_start(struct dpp_global *dpp,
12224 struct dpp_controller_config *config)
12225{
12226 struct dpp_controller *ctrl;
12227 int on = 1;
12228 struct sockaddr_in sin;
12229 int port;
12230
12231 if (!dpp || dpp->controller)
12232 return -1;
12233
12234 ctrl = os_zalloc(sizeof(*ctrl));
12235 if (!ctrl)
12236 return -1;
12237 ctrl->global = dpp;
12238 if (config->configurator_params)
12239 ctrl->configurator_params =
12240 os_strdup(config->configurator_params);
12241 dl_list_init(&ctrl->conn);
12242 /* TODO: configure these somehow */
12243 ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
12244 ctrl->qr_mutual = 0;
12245
12246 ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
12247 if (ctrl->sock < 0)
12248 goto fail;
12249
12250 if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
12251 &on, sizeof(on)) < 0) {
12252 wpa_printf(MSG_DEBUG,
12253 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
12254 strerror(errno));
12255 /* try to continue anyway */
12256 }
12257
12258 if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
12259 wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
12260 strerror(errno));
12261 goto fail;
12262 }
12263
12264 /* TODO: IPv6 */
12265 os_memset(&sin, 0, sizeof(sin));
12266 sin.sin_family = AF_INET;
12267 sin.sin_addr.s_addr = INADDR_ANY;
12268 port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
12269 sin.sin_port = htons(port);
12270 if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
12271 wpa_printf(MSG_INFO,
12272 "DPP: Failed to bind Controller TCP port: %s",
12273 strerror(errno));
12274 goto fail;
12275 }
12276 if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
12277 fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
12278 eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
12279 dpp_controller_tcp_cb, ctrl, NULL))
12280 goto fail;
12281
12282 dpp->controller = ctrl;
12283 wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
12284 return 0;
12285fail:
12286 dpp_controller_free(ctrl);
12287 return -1;
12288}
12289
12290
12291void dpp_controller_stop(struct dpp_global *dpp)
12292{
12293 if (dpp) {
12294 dpp_controller_free(dpp->controller);
12295 dpp->controller = NULL;
12296 }
12297}
12298
Hai Shalomfdcde762020-04-02 11:19:20 -070012299
12300struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
12301{
12302 struct wpabuf *msg;
12303
12304 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
12305
12306 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
12307 if (!msg)
12308 return NULL;
12309
12310 /* Responder Bootstrapping Key Hash */
12311 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
12312 wpa_hexdump_buf(MSG_DEBUG,
12313 "DPP: Presence Announcement frame attributes", msg);
12314 return msg;
12315}
12316
Hai Shalom81f62d82019-07-22 12:10:00 -070012317#endif /* CONFIG_DPP2 */