blob: b33ab15c0cc8f9194710a1b0e51f21410540282a [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
Hai Shalomb755a2a2020-04-23 21:49:02 -070077#ifdef CONFIG_DPP2
Hai Shalomfdcde762020-04-02 11:19:20 -070078static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
79{
80 if (pkey->type != EVP_PKEY_EC)
81 return NULL;
82 return pkey->pkey.ec;
83}
Hai Shalomb755a2a2020-04-23 21:49:02 -070084#endif /* CONFIG_DPP2 */
Hai Shalomfdcde762020-04-02 11:19:20 -070085
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070086#endif
87
88
Hai Shalom81f62d82019-07-22 12:10:00 -070089struct dpp_connection {
90 struct dl_list list;
91 struct dpp_controller *ctrl;
92 struct dpp_relay_controller *relay;
93 struct dpp_global *global;
94 struct dpp_authentication *auth;
95 int sock;
96 u8 mac_addr[ETH_ALEN];
97 unsigned int freq;
98 u8 msg_len[4];
99 size_t msg_len_octets;
100 struct wpabuf *msg;
101 struct wpabuf *msg_out;
102 size_t msg_out_pos;
103 unsigned int read_eloop:1;
104 unsigned int write_eloop:1;
105 unsigned int on_tcp_tx_complete_gas_done:1;
106 unsigned int on_tcp_tx_complete_remove:1;
107 unsigned int on_tcp_tx_complete_auth_ok:1;
108};
109
110/* Remote Controller */
111struct dpp_relay_controller {
112 struct dl_list list;
113 struct dpp_global *global;
114 u8 pkhash[SHA256_MAC_LEN];
115 struct hostapd_ip_addr ipaddr;
116 void *cb_ctx;
117 void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
118 size_t len);
119 void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
120 int prot, struct wpabuf *buf);
121 struct dl_list conn; /* struct dpp_connection */
122};
123
124/* Local Controller */
125struct dpp_controller {
126 struct dpp_global *global;
127 u8 allowed_roles;
128 int qr_mutual;
129 int sock;
130 struct dl_list conn; /* struct dpp_connection */
131 char *configurator_params;
132};
133
Hai Shalom021b0b52019-04-10 11:17:58 -0700134struct dpp_global {
Hai Shalom81f62d82019-07-22 12:10:00 -0700135 void *msg_ctx;
Hai Shalom021b0b52019-04-10 11:17:58 -0700136 struct dl_list bootstrap; /* struct dpp_bootstrap_info */
137 struct dl_list configurator; /* struct dpp_configurator */
Hai Shalom81f62d82019-07-22 12:10:00 -0700138#ifdef CONFIG_DPP2
139 struct dl_list controllers; /* struct dpp_relay_controller */
140 struct dpp_controller *controller;
141 struct dl_list tcp_init; /* struct dpp_connection */
142 void *cb_ctx;
143 int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
Hai Shalomfdcde762020-04-02 11:19:20 -0700144 void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
Hai Shalom81f62d82019-07-22 12:10:00 -0700145#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -0700146};
147
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700148static const struct dpp_curve_params dpp_curves[] = {
149 /* The mandatory to support and the default NIST P-256 curve needs to
150 * be the first entry on this list. */
151 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
152 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
153 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
154 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
155 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
156 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
157 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
158};
159
160
161/* Role-specific elements for PKEX */
162
163/* NIST P-256 */
164static const u8 pkex_init_x_p256[32] = {
165 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
166 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
167 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
168 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
169 };
170static const u8 pkex_init_y_p256[32] = {
171 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
172 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
173 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
174 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
175 };
176static const u8 pkex_resp_x_p256[32] = {
177 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
178 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
179 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
180 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
181};
182static const u8 pkex_resp_y_p256[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700183 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
184 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
185 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
186 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700187};
188
189/* NIST P-384 */
190static const u8 pkex_init_x_p384[48] = {
191 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
192 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
193 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
194 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
195 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
196 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
197};
198static const u8 pkex_init_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700199 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
200 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
201 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
202 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
203 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
204 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700205};
206static const u8 pkex_resp_x_p384[48] = {
207 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
208 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
209 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
210 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
211 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
212 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
213};
214static const u8 pkex_resp_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700215 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
216 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
217 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
218 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
219 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
220 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700221};
222
223/* NIST P-521 */
224static const u8 pkex_init_x_p521[66] = {
225 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
226 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
227 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
228 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
229 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
230 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
231 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
232 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
233 0x97, 0x76
234};
235static const u8 pkex_init_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700236 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
237 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
238 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
239 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
240 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
241 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
242 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
243 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
244 0x03, 0xa8
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700245};
246static const u8 pkex_resp_x_p521[66] = {
247 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
248 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
249 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
250 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
251 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
252 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
253 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
254 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
255 0x84, 0xb4
256};
257static const u8 pkex_resp_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700258 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
259 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
260 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
261 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
262 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
263 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
264 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
265 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
266 0xce, 0xe1
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700267};
268
269/* Brainpool P-256r1 */
270static const u8 pkex_init_x_bp_p256r1[32] = {
271 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
272 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
273 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
274 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
275};
276static const u8 pkex_init_y_bp_p256r1[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700277 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
278 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
279 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
280 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700281};
282static const u8 pkex_resp_x_bp_p256r1[32] = {
283 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
284 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
285 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
286 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
287};
288static const u8 pkex_resp_y_bp_p256r1[32] = {
289 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
290 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
291 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
292 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
293};
294
295/* Brainpool P-384r1 */
296static const u8 pkex_init_x_bp_p384r1[48] = {
297 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
298 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
299 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
300 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
301 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
302 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
303};
304static const u8 pkex_init_y_bp_p384r1[48] = {
305 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
306 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
307 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
308 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
309 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
310 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
311};
312static const u8 pkex_resp_x_bp_p384r1[48] = {
313 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
314 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
315 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
316 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
317 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
318 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
319};
320static const u8 pkex_resp_y_bp_p384r1[48] = {
321 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
322 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
323 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
324 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
325 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
326 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
327};
328
329/* Brainpool P-512r1 */
330static const u8 pkex_init_x_bp_p512r1[64] = {
331 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
332 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
333 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
334 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
335 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
336 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
337 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
338 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
339};
340static const u8 pkex_init_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700341 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
342 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
343 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
344 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
345 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
346 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
347 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
348 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700349};
350static const u8 pkex_resp_x_bp_p512r1[64] = {
351 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
352 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
353 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
354 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
355 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
356 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
357 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
358 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
359};
360static const u8 pkex_resp_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700361 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
362 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
363 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
364 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
365 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
366 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
367 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
368 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700369};
370
371
Roshan Pius3a1667e2018-07-03 15:17:14 -0700372static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
373 const EC_POINT *point)
374{
375 BIGNUM *x, *y;
376 BN_CTX *ctx;
377 char *x_str = NULL, *y_str = NULL;
378
379 if (!wpa_debug_show_keys)
380 return;
381
382 ctx = BN_CTX_new();
383 x = BN_new();
384 y = BN_new();
385 if (!ctx || !x || !y ||
386 EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
387 goto fail;
388
389 x_str = BN_bn2hex(x);
390 y_str = BN_bn2hex(y);
391 if (!x_str || !y_str)
392 goto fail;
393
394 wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
395
396fail:
397 OPENSSL_free(x_str);
398 OPENSSL_free(y_str);
399 BN_free(x);
400 BN_free(y);
401 BN_CTX_free(ctx);
402}
403
404
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700405static int dpp_hash_vector(const struct dpp_curve_params *curve,
406 size_t num_elem, const u8 *addr[], const size_t *len,
407 u8 *mac)
408{
409 if (curve->hash_len == 32)
410 return sha256_vector(num_elem, addr, len, mac);
411 if (curve->hash_len == 48)
412 return sha384_vector(num_elem, addr, len, mac);
413 if (curve->hash_len == 64)
414 return sha512_vector(num_elem, addr, len, mac);
415 return -1;
416}
417
418
419static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
420 const char *label, u8 *out, size_t outlen)
421{
422 if (hash_len == 32)
423 return hmac_sha256_kdf(secret, secret_len, NULL,
424 (const u8 *) label, os_strlen(label),
425 out, outlen);
426 if (hash_len == 48)
427 return hmac_sha384_kdf(secret, secret_len, NULL,
428 (const u8 *) label, os_strlen(label),
429 out, outlen);
430 if (hash_len == 64)
431 return hmac_sha512_kdf(secret, secret_len, NULL,
432 (const u8 *) label, os_strlen(label),
433 out, outlen);
434 return -1;
435}
436
437
438static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
439 size_t num_elem, const u8 *addr[],
440 const size_t *len, u8 *mac)
441{
442 if (hash_len == 32)
443 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
444 mac);
445 if (hash_len == 48)
446 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
447 mac);
448 if (hash_len == 64)
449 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
450 mac);
451 return -1;
452}
453
454
455static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
456 const u8 *data, size_t data_len, u8 *mac)
457{
458 if (hash_len == 32)
459 return hmac_sha256(key, key_len, data, data_len, mac);
460 if (hash_len == 48)
461 return hmac_sha384(key, key_len, data, data_len, mac);
462 if (hash_len == 64)
463 return hmac_sha512(key, key_len, data, data_len, mac);
464 return -1;
465}
466
467
Hai Shalomfdcde762020-04-02 11:19:20 -0700468#ifdef CONFIG_DPP2
469
470static int dpp_pbkdf2_f(size_t hash_len,
471 const u8 *password, size_t password_len,
472 const u8 *salt, size_t salt_len,
473 unsigned int iterations, unsigned int count, u8 *digest)
474{
475 unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
476 unsigned int i;
477 size_t j;
478 u8 count_buf[4];
479 const u8 *addr[2];
480 size_t len[2];
481
482 addr[0] = salt;
483 len[0] = salt_len;
484 addr[1] = count_buf;
485 len[1] = 4;
486
487 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
488 * U1 = PRF(P, S || i)
489 * U2 = PRF(P, U1)
490 * Uc = PRF(P, Uc-1)
491 */
492
493 WPA_PUT_BE32(count_buf, count);
494 if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
495 tmp))
496 return -1;
497 os_memcpy(digest, tmp, hash_len);
498
499 for (i = 1; i < iterations; i++) {
500 if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
501 tmp2))
502 return -1;
503 os_memcpy(tmp, tmp2, hash_len);
504 for (j = 0; j < hash_len; j++)
505 digest[j] ^= tmp2[j];
506 }
507
508 return 0;
509}
510
511
512static int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
513 const u8 *salt, size_t salt_len, unsigned int iterations,
514 u8 *buf, size_t buflen)
515{
516 unsigned int count = 0;
517 unsigned char *pos = buf;
518 size_t left = buflen, plen;
519 unsigned char digest[DPP_MAX_HASH_LEN];
520
521 while (left > 0) {
522 count++;
523 if (dpp_pbkdf2_f(hash_len, password, password_len,
524 salt, salt_len, iterations, count, digest))
525 return -1;
526 plen = left > hash_len ? hash_len : left;
527 os_memcpy(pos, digest, plen);
528 pos += plen;
529 left -= plen;
530 }
531
532 return 0;
533}
534
535#endif /* CONFIG_DPP2 */
536
537
Roshan Pius3a1667e2018-07-03 15:17:14 -0700538static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
539{
540 int num_bytes, offset;
541
542 num_bytes = BN_num_bytes(bn);
543 if ((size_t) num_bytes > len)
544 return -1;
545 offset = len - num_bytes;
546 os_memset(pos, 0, offset);
547 BN_bn2bin(bn, pos + offset);
548 return 0;
549}
550
551
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700552static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
553{
554 int len, res;
555 EC_KEY *eckey;
556 struct wpabuf *buf;
557 unsigned char *pos;
558
559 eckey = EVP_PKEY_get1_EC_KEY(pkey);
560 if (!eckey)
561 return NULL;
562 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
563 len = i2o_ECPublicKey(eckey, NULL);
564 if (len <= 0) {
565 wpa_printf(MSG_ERROR,
566 "DDP: Failed to determine public key encoding length");
567 EC_KEY_free(eckey);
568 return NULL;
569 }
570
571 buf = wpabuf_alloc(len);
572 if (!buf) {
573 EC_KEY_free(eckey);
574 return NULL;
575 }
576
577 pos = wpabuf_put(buf, len);
578 res = i2o_ECPublicKey(eckey, &pos);
579 EC_KEY_free(eckey);
580 if (res != len) {
581 wpa_printf(MSG_ERROR,
582 "DDP: Failed to encode public key (res=%d/%d)",
583 res, len);
584 wpabuf_free(buf);
585 return NULL;
586 }
587
588 if (!prefix) {
589 /* Remove 0x04 prefix to match DPP definition */
590 pos = wpabuf_mhead(buf);
591 os_memmove(pos, pos + 1, len - 1);
592 buf->used--;
593 }
594
595 return buf;
596}
597
598
599static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
600 const u8 *buf_x, const u8 *buf_y,
601 size_t len)
602{
603 EC_KEY *eckey = NULL;
604 BN_CTX *ctx;
605 EC_POINT *point = NULL;
606 BIGNUM *x = NULL, *y = NULL;
607 EVP_PKEY *pkey = NULL;
608
609 ctx = BN_CTX_new();
610 if (!ctx) {
611 wpa_printf(MSG_ERROR, "DPP: Out of memory");
612 return NULL;
613 }
614
615 point = EC_POINT_new(group);
616 x = BN_bin2bn(buf_x, len, NULL);
617 y = BN_bin2bn(buf_y, len, NULL);
618 if (!point || !x || !y) {
619 wpa_printf(MSG_ERROR, "DPP: Out of memory");
620 goto fail;
621 }
622
623 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
624 wpa_printf(MSG_ERROR,
625 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
626 ERR_error_string(ERR_get_error(), NULL));
627 goto fail;
628 }
629
630 if (!EC_POINT_is_on_curve(group, point, ctx) ||
631 EC_POINT_is_at_infinity(group, point)) {
632 wpa_printf(MSG_ERROR, "DPP: Invalid point");
633 goto fail;
634 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700635 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700636
637 eckey = EC_KEY_new();
638 if (!eckey ||
639 EC_KEY_set_group(eckey, group) != 1 ||
640 EC_KEY_set_public_key(eckey, point) != 1) {
641 wpa_printf(MSG_ERROR,
642 "DPP: Failed to set EC_KEY: %s",
643 ERR_error_string(ERR_get_error(), NULL));
644 goto fail;
645 }
646 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
647
648 pkey = EVP_PKEY_new();
649 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
650 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
651 goto fail;
652 }
653
654out:
655 BN_free(x);
656 BN_free(y);
657 EC_KEY_free(eckey);
658 EC_POINT_free(point);
659 BN_CTX_free(ctx);
660 return pkey;
661fail:
662 EVP_PKEY_free(pkey);
663 pkey = NULL;
664 goto out;
665}
666
667
668static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
669 const u8 *buf, size_t len)
670{
671 EC_KEY *eckey;
672 const EC_GROUP *group;
673 EVP_PKEY *pkey = NULL;
674
675 if (len & 1)
676 return NULL;
677
678 eckey = EVP_PKEY_get1_EC_KEY(group_key);
679 if (!eckey) {
680 wpa_printf(MSG_ERROR,
681 "DPP: Could not get EC_KEY from group_key");
682 return NULL;
683 }
684
685 group = EC_KEY_get0_group(eckey);
686 if (group)
687 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
688 len / 2);
689 else
690 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
691
692 EC_KEY_free(eckey);
693 return pkey;
694}
695
696
Hai Shalomc3565922019-10-28 11:58:20 -0700697static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
698 u8 *secret, size_t *secret_len)
699{
700 EVP_PKEY_CTX *ctx;
701 int ret = -1;
702
703 ERR_clear_error();
704 *secret_len = 0;
705
706 ctx = EVP_PKEY_CTX_new(own, NULL);
707 if (!ctx) {
708 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
709 ERR_error_string(ERR_get_error(), NULL));
710 return -1;
711 }
712
713 if (EVP_PKEY_derive_init(ctx) != 1) {
714 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
715 ERR_error_string(ERR_get_error(), NULL));
716 goto fail;
717 }
718
719 if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
720 wpa_printf(MSG_ERROR,
721 "DPP: EVP_PKEY_derive_set_peet failed: %s",
722 ERR_error_string(ERR_get_error(), NULL));
723 goto fail;
724 }
725
726 if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
727 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
728 ERR_error_string(ERR_get_error(), NULL));
729 goto fail;
730 }
731
732 if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
733 u8 buf[200];
734 int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
735
736 /* It looks like OpenSSL can return unexpectedly large buffer
737 * need for shared secret from EVP_PKEY_derive(NULL) in some
738 * cases. For example, group 19 has shown cases where secret_len
739 * is set to 72 even though the actual length ends up being
740 * updated to 32 when EVP_PKEY_derive() is called with a buffer
741 * for the value. Work around this by trying to fetch the value
742 * and continue if it is within supported range even when the
743 * initial buffer need is claimed to be larger. */
744 wpa_printf(level,
745 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
746 (int) *secret_len);
747 if (*secret_len > 200)
748 goto fail;
749 if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
750 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
751 ERR_error_string(ERR_get_error(), NULL));
752 goto fail;
753 }
754 if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
755 wpa_printf(MSG_ERROR,
756 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
757 (int) *secret_len);
758 goto fail;
759 }
760 wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
761 buf, *secret_len);
762 os_memcpy(secret, buf, *secret_len);
763 forced_memzero(buf, sizeof(buf));
764 goto done;
765 }
766
767 if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
768 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
769 ERR_error_string(ERR_get_error(), NULL));
770 goto fail;
771 }
772
773done:
774 ret = 0;
775
776fail:
777 EVP_PKEY_CTX_free(ctx);
778 return ret;
779}
780
781
Roshan Pius3a1667e2018-07-03 15:17:14 -0700782static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
783{
784 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
785}
786
787
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700788struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
789 size_t len)
790{
791 struct wpabuf *msg;
792
793 msg = wpabuf_alloc(8 + len);
794 if (!msg)
795 return NULL;
796 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
797 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
798 wpabuf_put_be24(msg, OUI_WFA);
799 wpabuf_put_u8(msg, DPP_OUI_TYPE);
800 wpabuf_put_u8(msg, 1); /* Crypto Suite */
801 wpabuf_put_u8(msg, type);
802 return msg;
803}
804
805
806const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
807{
808 u16 id, alen;
809 const u8 *pos = buf, *end = buf + len;
810
811 while (end - pos >= 4) {
812 id = WPA_GET_LE16(pos);
813 pos += 2;
814 alen = WPA_GET_LE16(pos);
815 pos += 2;
816 if (alen > end - pos)
817 return NULL;
818 if (id == req_id) {
819 *ret_len = alen;
820 return pos;
821 }
822 pos += alen;
823 }
824
825 return NULL;
826}
827
828
Hai Shalomc3565922019-10-28 11:58:20 -0700829static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
830 u16 req_id, u16 *ret_len)
831{
832 u16 id, alen;
833 const u8 *pos, *end = buf + len;
834
835 if (!prev)
836 pos = buf;
837 else
838 pos = prev + WPA_GET_LE16(prev - 2);
839 while (end - pos >= 4) {
840 id = WPA_GET_LE16(pos);
841 pos += 2;
842 alen = WPA_GET_LE16(pos);
843 pos += 2;
844 if (alen > end - pos)
845 return NULL;
846 if (id == req_id) {
847 *ret_len = alen;
848 return pos;
849 }
850 pos += alen;
851 }
852
853 return NULL;
854}
855
856
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700857int dpp_check_attrs(const u8 *buf, size_t len)
858{
859 const u8 *pos, *end;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700860 int wrapped_data = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700861
862 pos = buf;
863 end = buf + len;
864 while (end - pos >= 4) {
865 u16 id, alen;
866
867 id = WPA_GET_LE16(pos);
868 pos += 2;
869 alen = WPA_GET_LE16(pos);
870 pos += 2;
871 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
872 id, alen);
873 if (alen > end - pos) {
874 wpa_printf(MSG_DEBUG,
875 "DPP: Truncated message - not enough room for the attribute - dropped");
876 return -1;
877 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700878 if (wrapped_data) {
879 wpa_printf(MSG_DEBUG,
880 "DPP: An unexpected attribute included after the Wrapped Data attribute");
881 return -1;
882 }
883 if (id == DPP_ATTR_WRAPPED_DATA)
884 wrapped_data = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700885 pos += alen;
886 }
887
888 if (end != pos) {
889 wpa_printf(MSG_DEBUG,
890 "DPP: Unexpected octets (%d) after the last attribute",
891 (int) (end - pos));
892 return -1;
893 }
894
895 return 0;
896}
897
898
899void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
900{
901 if (!info)
902 return;
903 os_free(info->uri);
904 os_free(info->info);
Hai Shalomfdcde762020-04-02 11:19:20 -0700905 os_free(info->chan);
906 os_free(info->pk);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700907 EVP_PKEY_free(info->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -0700908 str_clear_free(info->configurator_params);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700909 os_free(info);
910}
911
912
913const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
914{
915 switch (type) {
916 case DPP_BOOTSTRAP_QR_CODE:
917 return "QRCODE";
918 case DPP_BOOTSTRAP_PKEX:
919 return "PKEX";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800920 case DPP_BOOTSTRAP_NFC_URI:
921 return "NFC-URI";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700922 }
923 return "??";
924}
925
926
927static int dpp_uri_valid_info(const char *info)
928{
929 while (*info) {
930 unsigned char val = *info++;
931
932 if (val < 0x20 || val > 0x7e || val == 0x3b)
933 return 0;
934 }
935
936 return 1;
937}
938
939
940static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
941{
942 bi->uri = os_strdup(uri);
943 return bi->uri ? 0 : -1;
944}
945
946
947int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
948 const char *chan_list)
949{
Hai Shalom81f62d82019-07-22 12:10:00 -0700950 const char *pos = chan_list, *pos2;
951 int opclass = -1, channel, freq;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700952
953 while (pos && *pos && *pos != ';') {
Hai Shalom81f62d82019-07-22 12:10:00 -0700954 pos2 = pos;
955 while (*pos2 >= '0' && *pos2 <= '9')
956 pos2++;
957 if (*pos2 == '/') {
958 opclass = atoi(pos);
959 pos = pos2 + 1;
960 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700961 if (opclass <= 0)
962 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700963 channel = atoi(pos);
964 if (channel <= 0)
965 goto fail;
966 while (*pos >= '0' && *pos <= '9')
967 pos++;
968 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
969 wpa_printf(MSG_DEBUG,
970 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
971 opclass, channel, freq);
972 if (freq < 0) {
973 wpa_printf(MSG_DEBUG,
974 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
975 opclass, channel);
976 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
977 wpa_printf(MSG_DEBUG,
978 "DPP: Too many channels in URI channel-list - ignore list");
979 bi->num_freq = 0;
980 break;
981 } else {
982 bi->freq[bi->num_freq++] = freq;
983 }
984
985 if (*pos == ';' || *pos == '\0')
986 break;
987 if (*pos != ',')
988 goto fail;
989 pos++;
990 }
991
992 return 0;
993fail:
994 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
995 return -1;
996}
997
998
999int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
1000{
1001 if (!mac)
1002 return 0;
1003
1004 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
1005 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
1006 return -1;
1007 }
1008
1009 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
1010
1011 return 0;
1012}
1013
1014
1015int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
1016{
1017 const char *end;
1018
1019 if (!info)
1020 return 0;
1021
1022 end = os_strchr(info, ';');
1023 if (!end)
1024 end = info + os_strlen(info);
1025 bi->info = os_malloc(end - info + 1);
1026 if (!bi->info)
1027 return -1;
1028 os_memcpy(bi->info, info, end - info);
1029 bi->info[end - info] = '\0';
1030 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
1031 if (!dpp_uri_valid_info(bi->info)) {
1032 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
1033 return -1;
1034 }
1035
1036 return 0;
1037}
1038
1039
1040static const struct dpp_curve_params *
1041dpp_get_curve_oid(const ASN1_OBJECT *poid)
1042{
1043 ASN1_OBJECT *oid;
1044 int i;
1045
1046 for (i = 0; dpp_curves[i].name; i++) {
1047 oid = OBJ_txt2obj(dpp_curves[i].name, 0);
1048 if (oid && OBJ_cmp(poid, oid) == 0)
1049 return &dpp_curves[i];
1050 }
1051 return NULL;
1052}
1053
1054
1055static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
1056{
1057 int i, tmp;
1058
1059 if (!nid)
1060 return NULL;
1061 for (i = 0; dpp_curves[i].name; i++) {
1062 tmp = OBJ_txt2nid(dpp_curves[i].name);
1063 if (tmp == nid)
1064 return &dpp_curves[i];
1065 }
1066 return NULL;
1067}
1068
1069
Hai Shalomfdcde762020-04-02 11:19:20 -07001070static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
1071 const u8 *data, size_t data_len)
1072{
1073 const u8 *addr[2];
1074 size_t len[2];
1075
1076 addr[0] = data;
1077 len[0] = data_len;
1078 if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
1079 return -1;
1080 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
1081 bi->pubkey_hash, SHA256_MAC_LEN);
1082
1083 addr[0] = (const u8 *) "chirp";
1084 len[0] = 5;
1085 addr[1] = data;
1086 len[1] = data_len;
1087 if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
1088 return -1;
1089 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
1090 bi->pubkey_hash_chirp, SHA256_MAC_LEN);
1091
1092 return 0;
1093}
1094
1095
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001096static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
1097{
1098 const char *end;
1099 u8 *data;
1100 size_t data_len;
1101 EVP_PKEY *pkey;
1102 const unsigned char *p;
1103 int res;
1104 X509_PUBKEY *pub = NULL;
1105 ASN1_OBJECT *ppkalg;
1106 const unsigned char *pk;
1107 int ppklen;
1108 X509_ALGOR *pa;
Hai Shalom74f70d42019-02-11 14:42:39 -08001109#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1110 (defined(LIBRESSL_VERSION_NUMBER) && \
1111 LIBRESSL_VERSION_NUMBER < 0x20800000L)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001112 ASN1_OBJECT *pa_oid;
1113#else
1114 const ASN1_OBJECT *pa_oid;
1115#endif
1116 const void *pval;
1117 int ptype;
1118 const ASN1_OBJECT *poid;
1119 char buf[100];
1120
1121 end = os_strchr(info, ';');
1122 if (!end)
1123 return -1;
1124
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001125 data = base64_decode(info, end - info, &data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001126 if (!data) {
1127 wpa_printf(MSG_DEBUG,
1128 "DPP: Invalid base64 encoding on URI public-key");
1129 return -1;
1130 }
1131 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
1132 data, data_len);
1133
Hai Shalomfdcde762020-04-02 11:19:20 -07001134 if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001135 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001136 os_free(data);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001137 return -1;
1138 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001139
1140 /* DER encoded ASN.1 SubjectPublicKeyInfo
1141 *
1142 * SubjectPublicKeyInfo ::= SEQUENCE {
1143 * algorithm AlgorithmIdentifier,
1144 * subjectPublicKey BIT STRING }
1145 *
1146 * AlgorithmIdentifier ::= SEQUENCE {
1147 * algorithm OBJECT IDENTIFIER,
1148 * parameters ANY DEFINED BY algorithm OPTIONAL }
1149 *
1150 * subjectPublicKey = compressed format public key per ANSI X9.63
1151 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1152 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1153 * prime256v1 (1.2.840.10045.3.1.7)
1154 */
1155
1156 p = data;
1157 pkey = d2i_PUBKEY(NULL, &p, data_len);
1158 os_free(data);
1159
1160 if (!pkey) {
1161 wpa_printf(MSG_DEBUG,
1162 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1163 return -1;
1164 }
1165
1166 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
1167 wpa_printf(MSG_DEBUG,
1168 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1169 EVP_PKEY_free(pkey);
1170 return -1;
1171 }
1172
1173 res = X509_PUBKEY_set(&pub, pkey);
1174 if (res != 1) {
1175 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
1176 goto fail;
1177 }
1178
1179 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
1180 if (res != 1) {
1181 wpa_printf(MSG_DEBUG,
1182 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1183 goto fail;
1184 }
1185 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
1186 if (res < 0 || (size_t) res >= sizeof(buf)) {
1187 wpa_printf(MSG_DEBUG,
1188 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1189 goto fail;
1190 }
1191 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
1192 if (os_strcmp(buf, "id-ecPublicKey") != 0) {
1193 wpa_printf(MSG_DEBUG,
1194 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1195 goto fail;
1196 }
1197
1198 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
1199 if (ptype != V_ASN1_OBJECT) {
1200 wpa_printf(MSG_DEBUG,
1201 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1202 goto fail;
1203 }
1204 poid = pval;
1205 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
1206 if (res < 0 || (size_t) res >= sizeof(buf)) {
1207 wpa_printf(MSG_DEBUG,
1208 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1209 goto fail;
1210 }
1211 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
1212 bi->curve = dpp_get_curve_oid(poid);
1213 if (!bi->curve) {
1214 wpa_printf(MSG_DEBUG,
1215 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1216 buf);
1217 goto fail;
1218 }
1219
1220 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
1221
1222 X509_PUBKEY_free(pub);
1223 bi->pubkey = pkey;
1224 return 0;
1225fail:
1226 X509_PUBKEY_free(pub);
1227 EVP_PKEY_free(pkey);
1228 return -1;
1229}
1230
1231
1232static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
1233{
1234 const char *pos = uri;
1235 const char *end;
1236 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
1237 struct dpp_bootstrap_info *bi;
1238
1239 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
1240
1241 if (os_strncmp(pos, "DPP:", 4) != 0) {
1242 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
1243 return NULL;
1244 }
1245 pos += 4;
1246
1247 for (;;) {
1248 end = os_strchr(pos, ';');
1249 if (!end)
1250 break;
1251
1252 if (end == pos) {
1253 /* Handle terminating ";;" and ignore unexpected ";"
1254 * for parsing robustness. */
1255 pos++;
1256 continue;
1257 }
1258
1259 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
1260 chan_list = pos + 2;
1261 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
1262 mac = pos + 2;
1263 else if (pos[0] == 'I' && pos[1] == ':' && !info)
1264 info = pos + 2;
1265 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
1266 pk = pos + 2;
1267 else
1268 wpa_hexdump_ascii(MSG_DEBUG,
1269 "DPP: Ignore unrecognized URI parameter",
1270 pos, end - pos);
1271 pos = end + 1;
1272 }
1273
1274 if (!pk) {
1275 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
1276 return NULL;
1277 }
1278
1279 bi = os_zalloc(sizeof(*bi));
1280 if (!bi)
1281 return NULL;
1282
1283 if (dpp_clone_uri(bi, uri) < 0 ||
1284 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
1285 dpp_parse_uri_mac(bi, mac) < 0 ||
1286 dpp_parse_uri_info(bi, info) < 0 ||
1287 dpp_parse_uri_pk(bi, pk) < 0) {
1288 dpp_bootstrap_info_free(bi);
1289 bi = NULL;
1290 }
1291
1292 return bi;
1293}
1294
1295
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001296static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
1297{
1298 EC_KEY *eckey;
1299 BIO *out;
1300 size_t rlen;
1301 char *txt;
1302 int res;
1303 unsigned char *der = NULL;
1304 int der_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001305 const EC_GROUP *group;
1306 const EC_POINT *point;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001307
1308 out = BIO_new(BIO_s_mem());
1309 if (!out)
1310 return;
1311
1312 EVP_PKEY_print_private(out, key, 0, NULL);
1313 rlen = BIO_ctrl_pending(out);
1314 txt = os_malloc(rlen + 1);
1315 if (txt) {
1316 res = BIO_read(out, txt, rlen);
1317 if (res > 0) {
1318 txt[res] = '\0';
1319 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
1320 }
1321 os_free(txt);
1322 }
1323 BIO_free(out);
1324
1325 eckey = EVP_PKEY_get1_EC_KEY(key);
1326 if (!eckey)
1327 return;
1328
Roshan Pius3a1667e2018-07-03 15:17:14 -07001329 group = EC_KEY_get0_group(eckey);
1330 point = EC_KEY_get0_public_key(eckey);
1331 if (group && point)
1332 dpp_debug_print_point(title, group, point);
1333
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001334 der_len = i2d_ECPrivateKey(eckey, &der);
1335 if (der_len > 0)
1336 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1337 OPENSSL_free(der);
1338 if (der_len <= 0) {
1339 der = NULL;
1340 der_len = i2d_EC_PUBKEY(eckey, &der);
1341 if (der_len > 0)
1342 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1343 OPENSSL_free(der);
1344 }
1345
1346 EC_KEY_free(eckey);
1347}
1348
1349
1350static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1351{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001352 EVP_PKEY_CTX *kctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07001353 EC_KEY *ec_params = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001354 EVP_PKEY *params = NULL, *key = NULL;
1355 int nid;
1356
1357 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1358
1359 nid = OBJ_txt2nid(curve->name);
1360 if (nid == NID_undef) {
1361 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1362 return NULL;
1363 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001364
1365 ec_params = EC_KEY_new_by_curve_name(nid);
1366 if (!ec_params) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001367 wpa_printf(MSG_ERROR,
1368 "DPP: Failed to generate EC_KEY parameters");
1369 goto fail;
1370 }
1371 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
1372 params = EVP_PKEY_new();
1373 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
1374 wpa_printf(MSG_ERROR,
1375 "DPP: Failed to generate EVP_PKEY parameters");
1376 goto fail;
1377 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001378
1379 kctx = EVP_PKEY_CTX_new(params, NULL);
1380 if (!kctx ||
1381 EVP_PKEY_keygen_init(kctx) != 1 ||
1382 EVP_PKEY_keygen(kctx, &key) != 1) {
1383 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
Hai Shalom81f62d82019-07-22 12:10:00 -07001384 key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001385 goto fail;
1386 }
1387
1388 if (wpa_debug_show_keys)
1389 dpp_debug_print_key("Own generated key", key);
1390
Hai Shalom81f62d82019-07-22 12:10:00 -07001391fail:
1392 EC_KEY_free(ec_params);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001393 EVP_PKEY_free(params);
1394 EVP_PKEY_CTX_free(kctx);
1395 return key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001396}
1397
1398
1399static const struct dpp_curve_params *
1400dpp_get_curve_name(const char *name)
1401{
1402 int i;
1403
1404 for (i = 0; dpp_curves[i].name; i++) {
1405 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
1406 (dpp_curves[i].jwk_crv &&
1407 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
1408 return &dpp_curves[i];
1409 }
1410 return NULL;
1411}
1412
1413
1414static const struct dpp_curve_params *
1415dpp_get_curve_jwk_crv(const char *name)
1416{
1417 int i;
1418
1419 for (i = 0; dpp_curves[i].name; i++) {
1420 if (dpp_curves[i].jwk_crv &&
1421 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
1422 return &dpp_curves[i];
1423 }
1424 return NULL;
1425}
1426
1427
1428static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1429 const u8 *privkey, size_t privkey_len)
1430{
1431 EVP_PKEY *pkey;
1432 EC_KEY *eckey;
1433 const EC_GROUP *group;
1434 int nid;
1435
1436 pkey = EVP_PKEY_new();
1437 if (!pkey)
1438 return NULL;
1439 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1440 if (!eckey) {
1441 wpa_printf(MSG_INFO,
1442 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1443 ERR_error_string(ERR_get_error(), NULL));
1444 EVP_PKEY_free(pkey);
1445 return NULL;
1446 }
1447 group = EC_KEY_get0_group(eckey);
1448 if (!group) {
1449 EC_KEY_free(eckey);
1450 EVP_PKEY_free(pkey);
1451 return NULL;
1452 }
1453 nid = EC_GROUP_get_curve_name(group);
1454 *curve = dpp_get_curve_nid(nid);
1455 if (!*curve) {
1456 wpa_printf(MSG_INFO,
1457 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1458 nid);
1459 EC_KEY_free(eckey);
1460 EVP_PKEY_free(pkey);
1461 return NULL;
1462 }
1463
1464 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1465 EC_KEY_free(eckey);
1466 EVP_PKEY_free(pkey);
1467 return NULL;
1468 }
1469 return pkey;
1470}
1471
1472
Roshan Pius3a1667e2018-07-03 15:17:14 -07001473typedef struct {
1474 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1475 * as an OID identifying the curve */
1476 X509_ALGOR *alg;
1477 /* Compressed format public key per ANSI X9.63 */
1478 ASN1_BIT_STRING *pub_key;
1479} DPP_BOOTSTRAPPING_KEY;
1480
1481ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
1482 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
1483 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
1484} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
1485
1486IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1487
1488
1489static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001490{
1491 unsigned char *der = NULL;
1492 int der_len;
1493 EC_KEY *eckey;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001494 struct wpabuf *ret = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001495 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001496 const EC_GROUP *group;
1497 const EC_POINT *point;
1498 BN_CTX *ctx;
1499 DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1500 int nid;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001501
Roshan Pius3a1667e2018-07-03 15:17:14 -07001502 ctx = BN_CTX_new();
1503 eckey = EVP_PKEY_get1_EC_KEY(key);
1504 if (!ctx || !eckey)
1505 goto fail;
1506
1507 group = EC_KEY_get0_group(eckey);
1508 point = EC_KEY_get0_public_key(eckey);
1509 if (!group || !point)
1510 goto fail;
1511 dpp_debug_print_point("DPP: bootstrap public key", group, point);
1512 nid = EC_GROUP_get_curve_name(group);
1513
1514 bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1515 if (!bootstrap ||
1516 X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1517 V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1518 goto fail;
1519
1520 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1521 NULL, 0, ctx);
1522 if (len == 0)
1523 goto fail;
1524
1525 der = OPENSSL_malloc(len);
1526 if (!der)
1527 goto fail;
1528 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1529 der, len, ctx);
1530
1531 OPENSSL_free(bootstrap->pub_key->data);
1532 bootstrap->pub_key->data = der;
1533 der = NULL;
1534 bootstrap->pub_key->length = len;
1535 /* No unused bits */
1536 bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
1537 bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
1538
1539 der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001540 if (der_len <= 0) {
1541 wpa_printf(MSG_ERROR,
1542 "DDP: Failed to build DER encoded public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001543 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001544 }
1545
Roshan Pius3a1667e2018-07-03 15:17:14 -07001546 ret = wpabuf_alloc_copy(der, der_len);
1547fail:
1548 DPP_BOOTSTRAPPING_KEY_free(bootstrap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001549 OPENSSL_free(der);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001550 EC_KEY_free(eckey);
1551 BN_CTX_free(ctx);
1552 return ret;
1553}
1554
1555
Hai Shalomfdcde762020-04-02 11:19:20 -07001556static int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001557{
1558 struct wpabuf *der;
1559 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001560
1561 der = dpp_bootstrap_key_der(bi->pubkey);
1562 if (!der)
1563 return -1;
1564 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1565 der);
Hai Shalomfdcde762020-04-02 11:19:20 -07001566 res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001567 if (res < 0)
1568 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001569 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001570 return res;
1571}
1572
1573
Hai Shalomfdcde762020-04-02 11:19:20 -07001574static int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1575 const u8 *privkey, size_t privkey_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001576{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001577 char *base64 = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001578 char *pos, *end;
1579 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001580 struct wpabuf *der = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001581
1582 if (!curve) {
1583 bi->curve = &dpp_curves[0];
1584 } else {
1585 bi->curve = dpp_get_curve_name(curve);
1586 if (!bi->curve) {
1587 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1588 curve);
Hai Shalomfdcde762020-04-02 11:19:20 -07001589 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001590 }
1591 }
1592 if (privkey)
1593 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1594 else
1595 bi->pubkey = dpp_gen_keypair(bi->curve);
1596 if (!bi->pubkey)
1597 goto fail;
1598 bi->own = 1;
1599
Roshan Pius3a1667e2018-07-03 15:17:14 -07001600 der = dpp_bootstrap_key_der(bi->pubkey);
1601 if (!der)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001602 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001603 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1604 der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001605
Hai Shalomfdcde762020-04-02 11:19:20 -07001606 if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001607 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1608 goto fail;
1609 }
1610
Roshan Pius3a1667e2018-07-03 15:17:14 -07001611 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1612 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001613 der = NULL;
1614 if (!base64)
1615 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001616 pos = base64;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001617 end = pos + len;
1618 for (;;) {
1619 pos = os_strchr(pos, '\n');
1620 if (!pos)
1621 break;
1622 os_memmove(pos, pos + 1, end - pos);
1623 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001624 os_free(bi->pk);
1625 bi->pk = base64;
1626 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001627fail:
1628 os_free(base64);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001629 wpabuf_free(der);
Hai Shalomfdcde762020-04-02 11:19:20 -07001630 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001631}
1632
1633
1634static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1635 unsigned int hash_len)
1636{
1637 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1638 const char *info = "first intermediate key";
1639 int res;
1640
1641 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1642
1643 /* HKDF-Extract(<>, M.x) */
1644 os_memset(salt, 0, hash_len);
1645 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
1646 return -1;
1647 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1648 prk, hash_len);
1649
1650 /* HKDF-Expand(PRK, info, L) */
1651 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
1652 os_memset(prk, 0, hash_len);
1653 if (res < 0)
1654 return -1;
1655
1656 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1657 k1, hash_len);
1658 return 0;
1659}
1660
1661
1662static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1663 unsigned int hash_len)
1664{
1665 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1666 const char *info = "second intermediate key";
1667 int res;
1668
1669 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1670
1671 /* HKDF-Extract(<>, N.x) */
1672 os_memset(salt, 0, hash_len);
1673 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
1674 if (res < 0)
1675 return -1;
1676 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1677 prk, hash_len);
1678
1679 /* HKDF-Expand(PRK, info, L) */
1680 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
1681 os_memset(prk, 0, hash_len);
1682 if (res < 0)
1683 return -1;
1684
1685 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1686 k2, hash_len);
1687 return 0;
1688}
1689
1690
1691static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1692 unsigned int hash_len)
1693{
1694 size_t nonce_len;
1695 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1696 const char *info_ke = "DPP Key";
1697 u8 prk[DPP_MAX_HASH_LEN];
1698 int res;
1699 const u8 *addr[3];
1700 size_t len[3];
1701 size_t num_elem = 0;
1702
Roshan Pius3a1667e2018-07-03 15:17:14 -07001703 if (!auth->Mx_len || !auth->Nx_len) {
1704 wpa_printf(MSG_DEBUG,
1705 "DPP: Mx/Nx not available - cannot derive ke");
1706 return -1;
1707 }
1708
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001709 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1710
1711 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1712 nonce_len = auth->curve->nonce_len;
1713 os_memcpy(nonces, auth->i_nonce, nonce_len);
1714 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1715 addr[num_elem] = auth->Mx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001716 len[num_elem] = auth->Mx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001717 num_elem++;
1718 addr[num_elem] = auth->Nx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001719 len[num_elem] = auth->Nx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001720 num_elem++;
1721 if (auth->peer_bi && auth->own_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001722 if (!auth->Lx_len) {
1723 wpa_printf(MSG_DEBUG,
1724 "DPP: Lx not available - cannot derive ke");
1725 return -1;
1726 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001727 addr[num_elem] = auth->Lx;
1728 len[num_elem] = auth->secret_len;
1729 num_elem++;
1730 }
1731 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1732 num_elem, addr, len, prk);
1733 if (res < 0)
1734 return -1;
1735 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1736 prk, hash_len);
1737
1738 /* HKDF-Expand(PRK, info, L) */
1739 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
1740 os_memset(prk, 0, hash_len);
1741 if (res < 0)
1742 return -1;
1743
1744 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1745 ke, hash_len);
1746 return 0;
1747}
1748
1749
Roshan Pius3a1667e2018-07-03 15:17:14 -07001750static void dpp_build_attr_status(struct wpabuf *msg,
1751 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001752{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001753 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
1754 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1755 wpabuf_put_le16(msg, 1);
1756 wpabuf_put_u8(msg, status);
1757}
1758
1759
1760static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1761 const u8 *hash)
1762{
1763 if (hash) {
1764 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1765 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1766 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1767 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1768 }
1769}
1770
1771
1772static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1773 const u8 *hash)
1774{
1775 if (hash) {
1776 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1777 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1778 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1779 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1780 }
1781}
1782
1783
1784static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1785 const struct wpabuf *pi,
1786 size_t nonce_len,
1787 const u8 *r_pubkey_hash,
1788 const u8 *i_pubkey_hash,
1789 unsigned int neg_freq)
1790{
1791 struct wpabuf *msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001792 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1793 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1794 u8 *pos;
1795 const u8 *addr[2];
1796 size_t len[2], siv_len, attr_len;
1797 u8 *attr_start, *attr_end;
1798
Roshan Pius3a1667e2018-07-03 15:17:14 -07001799 /* Build DPP Authentication Request frame attributes */
1800 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
1801 4 + sizeof(wrapped_data);
1802 if (neg_freq > 0)
1803 attr_len += 4 + 2;
Hai Shalom021b0b52019-04-10 11:17:58 -07001804#ifdef CONFIG_DPP2
1805 attr_len += 5;
1806#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001807#ifdef CONFIG_TESTING_OPTIONS
1808 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1809 attr_len += 5;
1810#endif /* CONFIG_TESTING_OPTIONS */
1811 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1812 if (!msg)
1813 return NULL;
1814
1815 attr_start = wpabuf_put(msg, 0);
1816
1817 /* Responder Bootstrapping Key Hash */
1818 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1819
1820 /* Initiator Bootstrapping Key Hash */
1821 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1822
1823 /* Initiator Protocol Key */
1824 if (pi) {
1825 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1826 wpabuf_put_le16(msg, wpabuf_len(pi));
1827 wpabuf_put_buf(msg, pi);
1828 }
1829
1830 /* Channel */
1831 if (neg_freq > 0) {
1832 u8 op_class, channel;
1833
1834 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1835 &channel) ==
1836 NUM_HOSTAPD_MODES) {
1837 wpa_printf(MSG_INFO,
1838 "DPP: Unsupported negotiation frequency request: %d",
1839 neg_freq);
1840 wpabuf_free(msg);
1841 return NULL;
1842 }
1843 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1844 wpabuf_put_le16(msg, 2);
1845 wpabuf_put_u8(msg, op_class);
1846 wpabuf_put_u8(msg, channel);
1847 }
1848
Hai Shalom021b0b52019-04-10 11:17:58 -07001849#ifdef CONFIG_DPP2
1850 /* Protocol Version */
1851 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1852 wpabuf_put_le16(msg, 1);
1853 wpabuf_put_u8(msg, 2);
1854#endif /* CONFIG_DPP2 */
1855
Roshan Pius3a1667e2018-07-03 15:17:14 -07001856#ifdef CONFIG_TESTING_OPTIONS
1857 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1858 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1859 goto skip_wrapped_data;
1860 }
1861#endif /* CONFIG_TESTING_OPTIONS */
1862
1863 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1864 pos = clear;
1865
1866#ifdef CONFIG_TESTING_OPTIONS
1867 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1868 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1869 goto skip_i_nonce;
1870 }
1871 if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1872 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1873 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1874 pos += 2;
1875 WPA_PUT_LE16(pos, nonce_len - 1);
1876 pos += 2;
1877 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1878 pos += nonce_len - 1;
1879 goto skip_i_nonce;
1880 }
1881#endif /* CONFIG_TESTING_OPTIONS */
1882
1883 /* I-nonce */
1884 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1885 pos += 2;
1886 WPA_PUT_LE16(pos, nonce_len);
1887 pos += 2;
1888 os_memcpy(pos, auth->i_nonce, nonce_len);
1889 pos += nonce_len;
1890
1891#ifdef CONFIG_TESTING_OPTIONS
1892skip_i_nonce:
1893 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1894 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1895 goto skip_i_capab;
1896 }
1897#endif /* CONFIG_TESTING_OPTIONS */
1898
1899 /* I-capabilities */
1900 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1901 pos += 2;
1902 WPA_PUT_LE16(pos, 1);
1903 pos += 2;
1904 auth->i_capab = auth->allowed_roles;
1905 *pos++ = auth->i_capab;
1906#ifdef CONFIG_TESTING_OPTIONS
1907 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1908 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1909 pos[-1] = 0;
1910 }
1911skip_i_capab:
1912#endif /* CONFIG_TESTING_OPTIONS */
1913
1914 attr_end = wpabuf_put(msg, 0);
1915
1916 /* OUI, OUI type, Crypto Suite, DPP frame type */
1917 addr[0] = wpabuf_head_u8(msg) + 2;
1918 len[0] = 3 + 1 + 1 + 1;
1919 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1920
1921 /* Attributes before Wrapped Data */
1922 addr[1] = attr_start;
1923 len[1] = attr_end - attr_start;
1924 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1925
1926 siv_len = pos - clear;
1927 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1928 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1929 2, addr, len, wrapped_data) < 0) {
1930 wpabuf_free(msg);
1931 return NULL;
1932 }
1933 siv_len += AES_BLOCK_SIZE;
1934 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1935 wrapped_data, siv_len);
1936
1937 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1938 wpabuf_put_le16(msg, siv_len);
1939 wpabuf_put_data(msg, wrapped_data, siv_len);
1940
1941#ifdef CONFIG_TESTING_OPTIONS
1942 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1943 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1944 dpp_build_attr_status(msg, DPP_STATUS_OK);
1945 }
1946skip_wrapped_data:
1947#endif /* CONFIG_TESTING_OPTIONS */
1948
1949 wpa_hexdump_buf(MSG_DEBUG,
1950 "DPP: Authentication Request frame attributes", msg);
1951
1952 return msg;
1953}
1954
1955
1956static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1957 enum dpp_status_error status,
1958 const struct wpabuf *pr,
1959 size_t nonce_len,
1960 const u8 *r_pubkey_hash,
1961 const u8 *i_pubkey_hash,
1962 const u8 *r_nonce, const u8 *i_nonce,
1963 const u8 *wrapped_r_auth,
1964 size_t wrapped_r_auth_len,
1965 const u8 *siv_key)
1966{
1967 struct wpabuf *msg;
1968#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1969 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1970 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1971 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1972 const u8 *addr[2];
1973 size_t len[2], siv_len, attr_len;
1974 u8 *attr_start, *attr_end, *pos;
1975
1976 auth->waiting_auth_conf = 1;
1977 auth->auth_resp_tries = 0;
1978
1979 /* Build DPP Authentication Response frame attributes */
1980 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1981 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
Hai Shalom021b0b52019-04-10 11:17:58 -07001982#ifdef CONFIG_DPP2
1983 attr_len += 5;
1984#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001985#ifdef CONFIG_TESTING_OPTIONS
1986 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1987 attr_len += 5;
1988#endif /* CONFIG_TESTING_OPTIONS */
1989 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1990 if (!msg)
1991 return NULL;
1992
1993 attr_start = wpabuf_put(msg, 0);
1994
1995 /* DPP Status */
1996 if (status != 255)
1997 dpp_build_attr_status(msg, status);
1998
1999 /* Responder Bootstrapping Key Hash */
2000 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
2001
2002 /* Initiator Bootstrapping Key Hash (mutual authentication) */
2003 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
2004
2005 /* Responder Protocol Key */
2006 if (pr) {
2007 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
2008 wpabuf_put_le16(msg, wpabuf_len(pr));
2009 wpabuf_put_buf(msg, pr);
2010 }
2011
Hai Shalom021b0b52019-04-10 11:17:58 -07002012#ifdef CONFIG_DPP2
2013 /* Protocol Version */
Hai Shalomfdcde762020-04-02 11:19:20 -07002014 if (auth->peer_version >= 2) {
2015 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
2016 wpabuf_put_le16(msg, 1);
2017 wpabuf_put_u8(msg, 2);
2018 }
Hai Shalom021b0b52019-04-10 11:17:58 -07002019#endif /* CONFIG_DPP2 */
2020
Roshan Pius3a1667e2018-07-03 15:17:14 -07002021 attr_end = wpabuf_put(msg, 0);
2022
2023#ifdef CONFIG_TESTING_OPTIONS
2024 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
2025 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2026 goto skip_wrapped_data;
2027 }
2028#endif /* CONFIG_TESTING_OPTIONS */
2029
2030 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
2031 pos = clear;
2032
2033 if (r_nonce) {
2034 /* R-nonce */
2035 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
2036 pos += 2;
2037 WPA_PUT_LE16(pos, nonce_len);
2038 pos += 2;
2039 os_memcpy(pos, r_nonce, nonce_len);
2040 pos += nonce_len;
2041 }
2042
2043 if (i_nonce) {
2044 /* I-nonce */
2045 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
2046 pos += 2;
2047 WPA_PUT_LE16(pos, nonce_len);
2048 pos += 2;
2049 os_memcpy(pos, i_nonce, nonce_len);
2050#ifdef CONFIG_TESTING_OPTIONS
2051 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
2052 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
2053 pos[nonce_len / 2] ^= 0x01;
2054 }
2055#endif /* CONFIG_TESTING_OPTIONS */
2056 pos += nonce_len;
2057 }
2058
2059#ifdef CONFIG_TESTING_OPTIONS
2060 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
2061 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
2062 goto skip_r_capab;
2063 }
2064#endif /* CONFIG_TESTING_OPTIONS */
2065
2066 /* R-capabilities */
2067 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
2068 pos += 2;
2069 WPA_PUT_LE16(pos, 1);
2070 pos += 2;
2071 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
2072 DPP_CAPAB_ENROLLEE;
2073 *pos++ = auth->r_capab;
2074#ifdef CONFIG_TESTING_OPTIONS
2075 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
2076 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
2077 pos[-1] = 0;
2078 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
2079 wpa_printf(MSG_INFO,
2080 "DPP: TESTING - incompatible R-capabilities");
2081 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
2082 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
2083 pos[-1] = 0;
2084 else
2085 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
2086 DPP_CAPAB_CONFIGURATOR;
2087 }
2088skip_r_capab:
2089#endif /* CONFIG_TESTING_OPTIONS */
2090
2091 if (wrapped_r_auth) {
2092 /* {R-auth}ke */
2093 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
2094 pos += 2;
2095 WPA_PUT_LE16(pos, wrapped_r_auth_len);
2096 pos += 2;
2097 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
2098 pos += wrapped_r_auth_len;
2099 }
2100
2101 /* OUI, OUI type, Crypto Suite, DPP frame type */
2102 addr[0] = wpabuf_head_u8(msg) + 2;
2103 len[0] = 3 + 1 + 1 + 1;
2104 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2105
2106 /* Attributes before Wrapped Data */
2107 addr[1] = attr_start;
2108 len[1] = attr_end - attr_start;
2109 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
2110
2111 siv_len = pos - clear;
2112 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
2113 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
2114 2, addr, len, wrapped_data) < 0) {
2115 wpabuf_free(msg);
2116 return NULL;
2117 }
2118 siv_len += AES_BLOCK_SIZE;
2119 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2120 wrapped_data, siv_len);
2121
2122 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2123 wpabuf_put_le16(msg, siv_len);
2124 wpabuf_put_data(msg, wrapped_data, siv_len);
2125
2126#ifdef CONFIG_TESTING_OPTIONS
2127 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
2128 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2129 dpp_build_attr_status(msg, DPP_STATUS_OK);
2130 }
2131skip_wrapped_data:
2132#endif /* CONFIG_TESTING_OPTIONS */
2133
2134 wpa_hexdump_buf(MSG_DEBUG,
2135 "DPP: Authentication Response frame attributes", msg);
2136 return msg;
2137}
2138
2139
2140static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
2141 u16 num_modes, unsigned int freq)
2142{
2143 u16 m;
2144 int c, flag;
2145
2146 if (!own_modes || !num_modes)
2147 return 1;
2148
2149 for (m = 0; m < num_modes; m++) {
2150 for (c = 0; c < own_modes[m].num_channels; c++) {
2151 if ((unsigned int) own_modes[m].channels[c].freq !=
2152 freq)
2153 continue;
2154 flag = own_modes[m].channels[c].flag;
2155 if (!(flag & (HOSTAPD_CHAN_DISABLED |
2156 HOSTAPD_CHAN_NO_IR |
2157 HOSTAPD_CHAN_RADAR)))
2158 return 1;
2159 }
2160 }
2161
2162 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
2163 return 0;
2164}
2165
2166
2167static int freq_included(const unsigned int freqs[], unsigned int num,
2168 unsigned int freq)
2169{
2170 while (num > 0) {
2171 if (freqs[--num] == freq)
2172 return 1;
2173 }
2174 return 0;
2175}
2176
2177
2178static void freq_to_start(unsigned int freqs[], unsigned int num,
2179 unsigned int freq)
2180{
2181 unsigned int i;
2182
2183 for (i = 0; i < num; i++) {
2184 if (freqs[i] == freq)
2185 break;
2186 }
2187 if (i == 0 || i >= num)
2188 return;
2189 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
2190 freqs[0] = freq;
2191}
2192
2193
2194static int dpp_channel_intersect(struct dpp_authentication *auth,
2195 struct hostapd_hw_modes *own_modes,
2196 u16 num_modes)
2197{
2198 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
2199 unsigned int i, freq;
2200
2201 for (i = 0; i < peer_bi->num_freq; i++) {
2202 freq = peer_bi->freq[i];
2203 if (freq_included(auth->freq, auth->num_freq, freq))
2204 continue;
2205 if (dpp_channel_ok_init(own_modes, num_modes, freq))
2206 auth->freq[auth->num_freq++] = freq;
2207 }
2208 if (!auth->num_freq) {
2209 wpa_printf(MSG_INFO,
2210 "DPP: No available channels for initiating DPP Authentication");
2211 return -1;
2212 }
2213 auth->curr_freq = auth->freq[0];
2214 return 0;
2215}
2216
2217
2218static int dpp_channel_local_list(struct dpp_authentication *auth,
2219 struct hostapd_hw_modes *own_modes,
2220 u16 num_modes)
2221{
2222 u16 m;
2223 int c, flag;
2224 unsigned int freq;
2225
2226 auth->num_freq = 0;
2227
2228 if (!own_modes || !num_modes) {
2229 auth->freq[0] = 2412;
2230 auth->freq[1] = 2437;
2231 auth->freq[2] = 2462;
2232 auth->num_freq = 3;
2233 return 0;
2234 }
2235
2236 for (m = 0; m < num_modes; m++) {
2237 for (c = 0; c < own_modes[m].num_channels; c++) {
2238 freq = own_modes[m].channels[c].freq;
2239 flag = own_modes[m].channels[c].flag;
2240 if (flag & (HOSTAPD_CHAN_DISABLED |
2241 HOSTAPD_CHAN_NO_IR |
2242 HOSTAPD_CHAN_RADAR))
2243 continue;
2244 if (freq_included(auth->freq, auth->num_freq, freq))
2245 continue;
2246 auth->freq[auth->num_freq++] = freq;
2247 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
2248 m = num_modes;
2249 break;
2250 }
2251 }
2252 }
2253
2254 return auth->num_freq == 0 ? -1 : 0;
2255}
2256
2257
2258static int dpp_prepare_channel_list(struct dpp_authentication *auth,
Hai Shalomfdcde762020-04-02 11:19:20 -07002259 unsigned int neg_freq,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002260 struct hostapd_hw_modes *own_modes,
2261 u16 num_modes)
2262{
2263 int res;
2264 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
2265 unsigned int i;
2266
Hai Shalomfdcde762020-04-02 11:19:20 -07002267 if (!own_modes) {
2268 if (!neg_freq)
2269 return -1;
2270 auth->num_freq = 1;
2271 auth->freq[0] = neg_freq;
2272 return 0;
2273 }
2274
Roshan Pius3a1667e2018-07-03 15:17:14 -07002275 if (auth->peer_bi->num_freq > 0)
2276 res = dpp_channel_intersect(auth, own_modes, num_modes);
2277 else
2278 res = dpp_channel_local_list(auth, own_modes, num_modes);
2279 if (res < 0)
2280 return res;
2281
2282 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2283 * likely channels first. */
2284 freq_to_start(auth->freq, auth->num_freq, 2462);
2285 freq_to_start(auth->freq, auth->num_freq, 2412);
2286 freq_to_start(auth->freq, auth->num_freq, 2437);
2287
2288 auth->freq_idx = 0;
2289 auth->curr_freq = auth->freq[0];
2290
2291 pos = freqs;
2292 end = pos + sizeof(freqs);
2293 for (i = 0; i < auth->num_freq; i++) {
2294 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
2295 if (os_snprintf_error(end - pos, res))
2296 break;
2297 pos += res;
2298 }
2299 *pos = '\0';
2300 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
2301 freqs);
2302
2303 return 0;
2304}
2305
2306
Hai Shalomfdcde762020-04-02 11:19:20 -07002307static int dpp_gen_uri(struct dpp_bootstrap_info *bi)
2308{
2309 char macstr[ETH_ALEN * 2 + 10];
2310 size_t len;
2311
2312 len = 4; /* "DPP:" */
2313 if (bi->chan)
2314 len += 3 + os_strlen(bi->chan); /* C:...; */
2315 if (is_zero_ether_addr(bi->mac_addr))
2316 macstr[0] = '\0';
2317 else
2318 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
2319 MAC2STR(bi->mac_addr));
2320 len += os_strlen(macstr); /* M:...; */
2321 if (bi->info)
2322 len += 3 + os_strlen(bi->info); /* I:...; */
2323 len += 4 + os_strlen(bi->pk); /* K:...;; */
2324
2325 os_free(bi->uri);
2326 bi->uri = os_malloc(len + 1);
2327 if (!bi->uri)
2328 return -1;
2329 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
2330 bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
2331 bi->chan ? ";" : "",
2332 macstr,
2333 bi->info ? "I:" : "", bi->info ? bi->info : "",
2334 bi->info ? ";" : "",
2335 bi->pk);
2336 return 0;
2337}
2338
2339
Roshan Pius3a1667e2018-07-03 15:17:14 -07002340static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
2341{
2342 struct dpp_bootstrap_info *bi;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002343
2344 if (auth->own_bi)
2345 return 0; /* already generated */
2346
2347 bi = os_zalloc(sizeof(*bi));
2348 if (!bi)
2349 return -1;
2350 bi->type = DPP_BOOTSTRAP_QR_CODE;
Hai Shalomfdcde762020-04-02 11:19:20 -07002351 if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
2352 dpp_gen_uri(bi) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002353 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002354 wpa_printf(MSG_DEBUG,
2355 "DPP: Auto-generated own bootstrapping key info: URI %s",
2356 bi->uri);
2357
2358 auth->tmp_own_bi = auth->own_bi = bi;
2359
Roshan Pius3a1667e2018-07-03 15:17:14 -07002360 return 0;
2361fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07002362 dpp_bootstrap_info_free(bi);
2363 return -1;
2364}
2365
2366
Hai Shalomfdcde762020-04-02 11:19:20 -07002367struct dpp_authentication *
2368dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
2369{
2370 struct dpp_authentication *auth;
2371
2372 auth = os_zalloc(sizeof(*auth));
2373 if (!auth)
2374 return NULL;
2375 auth->global = dpp;
2376 auth->msg_ctx = msg_ctx;
2377 auth->conf_resp_status = 255;
2378 return auth;
2379}
2380
2381
2382struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002383 struct dpp_bootstrap_info *peer_bi,
2384 struct dpp_bootstrap_info *own_bi,
2385 u8 dpp_allowed_roles,
2386 unsigned int neg_freq,
2387 struct hostapd_hw_modes *own_modes,
2388 u16 num_modes)
2389{
2390 struct dpp_authentication *auth;
2391 size_t nonce_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002392 size_t secret_len;
2393 struct wpabuf *pi = NULL;
2394 const u8 *r_pubkey_hash, *i_pubkey_hash;
2395#ifdef CONFIG_TESTING_OPTIONS
2396 u8 test_hash[SHA256_MAC_LEN];
2397#endif /* CONFIG_TESTING_OPTIONS */
2398
Hai Shalomfdcde762020-04-02 11:19:20 -07002399 auth = dpp_alloc_auth(dpp, msg_ctx);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002400 if (!auth)
2401 return NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07002402 if (peer_bi->configurator_params &&
2403 dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
2404 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002405 auth->initiator = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002406 auth->waiting_auth_resp = 1;
2407 auth->allowed_roles = dpp_allowed_roles;
2408 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002409 auth->peer_bi = peer_bi;
2410 auth->own_bi = own_bi;
2411 auth->curve = peer_bi->curve;
2412
Roshan Pius3a1667e2018-07-03 15:17:14 -07002413 if (dpp_autogen_bootstrap_key(auth) < 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07002414 dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002415 goto fail;
2416
2417#ifdef CONFIG_TESTING_OPTIONS
2418 if (dpp_nonce_override_len > 0) {
2419 wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
2420 nonce_len = dpp_nonce_override_len;
2421 os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
2422 } else {
2423 nonce_len = auth->curve->nonce_len;
2424 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2425 wpa_printf(MSG_ERROR,
2426 "DPP: Failed to generate I-nonce");
2427 goto fail;
2428 }
2429 }
2430#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002431 nonce_len = auth->curve->nonce_len;
2432 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2433 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
2434 goto fail;
2435 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002436#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002437 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2438
Roshan Pius3a1667e2018-07-03 15:17:14 -07002439#ifdef CONFIG_TESTING_OPTIONS
2440 if (dpp_protocol_key_override_len) {
2441 const struct dpp_curve_params *tmp_curve;
2442
2443 wpa_printf(MSG_INFO,
2444 "DPP: TESTING - override protocol key");
2445 auth->own_protocol_key = dpp_set_keypair(
2446 &tmp_curve, dpp_protocol_key_override,
2447 dpp_protocol_key_override_len);
2448 } else {
2449 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2450 }
2451#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002452 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002453#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002454 if (!auth->own_protocol_key)
2455 goto fail;
2456
2457 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2458 if (!pi)
2459 goto fail;
2460
2461 /* ECDH: M = pI * BR */
Hai Shalomc3565922019-10-28 11:58:20 -07002462 if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
2463 auth->Mx, &secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002464 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002465 auth->secret_len = secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002466
2467 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2468 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002469 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002470
2471 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2472 auth->curve->hash_len) < 0)
2473 goto fail;
2474
Roshan Pius3a1667e2018-07-03 15:17:14 -07002475 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2476 i_pubkey_hash = auth->own_bi->pubkey_hash;
2477
2478#ifdef CONFIG_TESTING_OPTIONS
2479 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2480 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2481 r_pubkey_hash = NULL;
2482 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2483 wpa_printf(MSG_INFO,
2484 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2485 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2486 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2487 r_pubkey_hash = test_hash;
2488 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2489 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2490 i_pubkey_hash = NULL;
2491 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2492 wpa_printf(MSG_INFO,
2493 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2494 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2495 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2496 i_pubkey_hash = test_hash;
2497 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2498 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2499 wpabuf_free(pi);
2500 pi = NULL;
2501 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2502 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2503 wpabuf_free(pi);
2504 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2505 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2506 goto fail;
2507 }
2508#endif /* CONFIG_TESTING_OPTIONS */
2509
Hai Shalomfdcde762020-04-02 11:19:20 -07002510 if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq)
2511 neg_freq = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002512 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
2513 i_pubkey_hash, neg_freq);
2514 if (!auth->req_msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002515 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002516
Roshan Pius3a1667e2018-07-03 15:17:14 -07002517out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002518 wpabuf_free(pi);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002519 return auth;
2520fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002521 dpp_auth_deinit(auth);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002522 auth = NULL;
2523 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002524}
2525
2526
Hai Shalom021b0b52019-04-10 11:17:58 -07002527static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
2528 const char *json)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002529{
2530 size_t nonce_len;
2531 size_t json_len, clear_len;
2532 struct wpabuf *clear = NULL, *msg = NULL;
2533 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002534 size_t attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002535
2536 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2537
2538 nonce_len = auth->curve->nonce_len;
2539 if (random_get_bytes(auth->e_nonce, nonce_len)) {
2540 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2541 goto fail;
2542 }
2543 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2544 json_len = os_strlen(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002545 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002546
2547 /* { E-nonce, configAttrib }ke */
2548 clear_len = 4 + nonce_len + 4 + json_len;
2549 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002550 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2551#ifdef CONFIG_TESTING_OPTIONS
2552 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
2553 attr_len += 5;
2554#endif /* CONFIG_TESTING_OPTIONS */
2555 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002556 if (!clear || !msg)
2557 goto fail;
2558
Roshan Pius3a1667e2018-07-03 15:17:14 -07002559#ifdef CONFIG_TESTING_OPTIONS
2560 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2561 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2562 goto skip_e_nonce;
2563 }
2564 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
2565 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
2566 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2567 wpabuf_put_le16(clear, nonce_len - 1);
2568 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
2569 goto skip_e_nonce;
2570 }
2571 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2572 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2573 goto skip_wrapped_data;
2574 }
2575#endif /* CONFIG_TESTING_OPTIONS */
2576
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002577 /* E-nonce */
2578 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2579 wpabuf_put_le16(clear, nonce_len);
2580 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2581
Roshan Pius3a1667e2018-07-03 15:17:14 -07002582#ifdef CONFIG_TESTING_OPTIONS
2583skip_e_nonce:
2584 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2585 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2586 goto skip_conf_attr_obj;
2587 }
2588#endif /* CONFIG_TESTING_OPTIONS */
2589
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002590 /* configAttrib */
2591 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2592 wpabuf_put_le16(clear, json_len);
2593 wpabuf_put_data(clear, json, json_len);
2594
Roshan Pius3a1667e2018-07-03 15:17:14 -07002595#ifdef CONFIG_TESTING_OPTIONS
2596skip_conf_attr_obj:
2597#endif /* CONFIG_TESTING_OPTIONS */
2598
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002599 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2600 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2601 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2602
2603 /* No AES-SIV AD */
2604 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2605 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2606 wpabuf_head(clear), wpabuf_len(clear),
2607 0, NULL, NULL, wrapped) < 0)
2608 goto fail;
2609 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2610 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2611
Roshan Pius3a1667e2018-07-03 15:17:14 -07002612#ifdef CONFIG_TESTING_OPTIONS
2613 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2614 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2615 dpp_build_attr_status(msg, DPP_STATUS_OK);
2616 }
2617skip_wrapped_data:
2618#endif /* CONFIG_TESTING_OPTIONS */
2619
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002620 wpa_hexdump_buf(MSG_DEBUG,
2621 "DPP: Configuration Request frame attributes", msg);
2622 wpabuf_free(clear);
2623 return msg;
2624
2625fail:
2626 wpabuf_free(clear);
2627 wpabuf_free(msg);
2628 return NULL;
2629}
2630
2631
Hai Shalom021b0b52019-04-10 11:17:58 -07002632static void dpp_write_adv_proto(struct wpabuf *buf)
2633{
2634 /* Advertisement Protocol IE */
2635 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
2636 wpabuf_put_u8(buf, 8); /* Length */
2637 wpabuf_put_u8(buf, 0x7f);
2638 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
2639 wpabuf_put_u8(buf, 5);
2640 wpabuf_put_be24(buf, OUI_WFA);
2641 wpabuf_put_u8(buf, DPP_OUI_TYPE);
2642 wpabuf_put_u8(buf, 0x01);
2643}
2644
2645
2646static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
2647{
2648 /* GAS Query */
2649 wpabuf_put_le16(buf, wpabuf_len(query));
2650 wpabuf_put_buf(buf, query);
2651}
2652
2653
2654struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2655 const char *json)
2656{
2657 struct wpabuf *buf, *conf_req;
2658
2659 conf_req = dpp_build_conf_req_attr(auth, json);
2660 if (!conf_req) {
2661 wpa_printf(MSG_DEBUG,
2662 "DPP: No configuration request data available");
2663 return NULL;
2664 }
2665
2666 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
2667 if (!buf) {
2668 wpabuf_free(conf_req);
2669 return NULL;
2670 }
2671
2672 dpp_write_adv_proto(buf);
2673 dpp_write_gas_query(buf, conf_req);
2674 wpabuf_free(conf_req);
2675 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
2676
2677 return buf;
2678}
2679
2680
Hai Shalomc3565922019-10-28 11:58:20 -07002681struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002682 const char *name,
2683 enum dpp_netrole netrole,
Hai Shalomc3565922019-10-28 11:58:20 -07002684 const char *mud_url, int *opclasses)
2685{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002686 size_t len, name_len;
Hai Shalomc3565922019-10-28 11:58:20 -07002687 const char *tech = "infra";
2688 const char *dpp_name;
Hai Shalomc3565922019-10-28 11:58:20 -07002689 struct wpabuf *buf, *json;
2690
2691#ifdef CONFIG_TESTING_OPTIONS
2692 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
2693 static const char *bogus_tech = "knfra";
2694
2695 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
2696 tech = bogus_tech;
2697 }
2698#endif /* CONFIG_TESTING_OPTIONS */
2699
2700 dpp_name = name ? name : "Test";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002701 name_len = os_strlen(dpp_name);
Hai Shalomc3565922019-10-28 11:58:20 -07002702
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002703 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
Hai Shalomc3565922019-10-28 11:58:20 -07002704 if (mud_url && mud_url[0])
2705 len += 10 + os_strlen(mud_url);
2706 json = wpabuf_alloc(len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002707 if (!json)
2708 return NULL;
2709
2710 json_start_object(json, NULL);
2711 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
2712 wpabuf_free(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002713 return NULL;
2714 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002715 json_value_sep(json);
2716 json_add_string(json, "wi-fi_tech", tech);
2717 json_value_sep(json);
2718 json_add_string(json, "netRole", dpp_netrole_str(netrole));
2719 if (mud_url && mud_url[0]) {
2720 json_value_sep(json);
2721 json_add_string(json, "mudurl", mud_url);
2722 }
Hai Shalomc3565922019-10-28 11:58:20 -07002723 if (opclasses) {
2724 int i;
2725
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002726 json_value_sep(json);
2727 json_start_array(json, "bandSupport");
Hai Shalomc3565922019-10-28 11:58:20 -07002728 for (i = 0; opclasses[i]; i++)
2729 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002730 json_end_array(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002731 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002732 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07002733
2734 buf = dpp_build_conf_req(auth, wpabuf_head(json));
2735 wpabuf_free(json);
2736
2737 return buf;
2738}
2739
2740
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002741static void dpp_auth_success(struct dpp_authentication *auth)
2742{
2743 wpa_printf(MSG_DEBUG,
2744 "DPP: Authentication success - clear temporary keys");
2745 os_memset(auth->Mx, 0, sizeof(auth->Mx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002746 auth->Mx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002747 os_memset(auth->Nx, 0, sizeof(auth->Nx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002748 auth->Nx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002749 os_memset(auth->Lx, 0, sizeof(auth->Lx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002750 auth->Lx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002751 os_memset(auth->k1, 0, sizeof(auth->k1));
2752 os_memset(auth->k2, 0, sizeof(auth->k2));
2753
2754 auth->auth_success = 1;
2755}
2756
2757
2758static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2759{
2760 struct wpabuf *pix, *prx, *bix, *brx;
2761 const u8 *addr[7];
2762 size_t len[7];
2763 size_t i, num_elem = 0;
2764 size_t nonce_len;
2765 u8 zero = 0;
2766 int res = -1;
2767
2768 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2769 nonce_len = auth->curve->nonce_len;
2770
2771 if (auth->initiator) {
2772 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2773 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2774 if (auth->own_bi)
2775 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2776 else
2777 bix = NULL;
2778 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2779 } else {
2780 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2781 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2782 if (auth->peer_bi)
2783 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2784 else
2785 bix = NULL;
2786 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2787 }
2788 if (!pix || !prx || !brx)
2789 goto fail;
2790
2791 addr[num_elem] = auth->i_nonce;
2792 len[num_elem] = nonce_len;
2793 num_elem++;
2794
2795 addr[num_elem] = auth->r_nonce;
2796 len[num_elem] = nonce_len;
2797 num_elem++;
2798
2799 addr[num_elem] = wpabuf_head(pix);
2800 len[num_elem] = wpabuf_len(pix) / 2;
2801 num_elem++;
2802
2803 addr[num_elem] = wpabuf_head(prx);
2804 len[num_elem] = wpabuf_len(prx) / 2;
2805 num_elem++;
2806
2807 if (bix) {
2808 addr[num_elem] = wpabuf_head(bix);
2809 len[num_elem] = wpabuf_len(bix) / 2;
2810 num_elem++;
2811 }
2812
2813 addr[num_elem] = wpabuf_head(brx);
2814 len[num_elem] = wpabuf_len(brx) / 2;
2815 num_elem++;
2816
2817 addr[num_elem] = &zero;
2818 len[num_elem] = 1;
2819 num_elem++;
2820
2821 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2822 for (i = 0; i < num_elem; i++)
2823 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2824 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
2825 if (res == 0)
2826 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2827 auth->curve->hash_len);
2828fail:
2829 wpabuf_free(pix);
2830 wpabuf_free(prx);
2831 wpabuf_free(bix);
2832 wpabuf_free(brx);
2833 return res;
2834}
2835
2836
2837static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2838{
2839 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2840 const u8 *addr[7];
2841 size_t len[7];
2842 size_t i, num_elem = 0;
2843 size_t nonce_len;
2844 u8 one = 1;
2845 int res = -1;
2846
2847 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2848 nonce_len = auth->curve->nonce_len;
2849
2850 if (auth->initiator) {
2851 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2852 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2853 if (auth->own_bi)
2854 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2855 else
2856 bix = NULL;
2857 if (!auth->peer_bi)
2858 goto fail;
2859 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2860 } else {
2861 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2862 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2863 if (auth->peer_bi)
2864 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2865 else
2866 bix = NULL;
2867 if (!auth->own_bi)
2868 goto fail;
2869 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2870 }
2871 if (!pix || !prx || !brx)
2872 goto fail;
2873
2874 addr[num_elem] = auth->r_nonce;
2875 len[num_elem] = nonce_len;
2876 num_elem++;
2877
2878 addr[num_elem] = auth->i_nonce;
2879 len[num_elem] = nonce_len;
2880 num_elem++;
2881
2882 addr[num_elem] = wpabuf_head(prx);
2883 len[num_elem] = wpabuf_len(prx) / 2;
2884 num_elem++;
2885
2886 addr[num_elem] = wpabuf_head(pix);
2887 len[num_elem] = wpabuf_len(pix) / 2;
2888 num_elem++;
2889
2890 addr[num_elem] = wpabuf_head(brx);
2891 len[num_elem] = wpabuf_len(brx) / 2;
2892 num_elem++;
2893
2894 if (bix) {
2895 addr[num_elem] = wpabuf_head(bix);
2896 len[num_elem] = wpabuf_len(bix) / 2;
2897 num_elem++;
2898 }
2899
2900 addr[num_elem] = &one;
2901 len[num_elem] = 1;
2902 num_elem++;
2903
2904 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2905 for (i = 0; i < num_elem; i++)
2906 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2907 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
2908 if (res == 0)
2909 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2910 auth->curve->hash_len);
2911fail:
2912 wpabuf_free(pix);
2913 wpabuf_free(prx);
2914 wpabuf_free(bix);
2915 wpabuf_free(brx);
2916 return res;
2917}
2918
2919
2920static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2921{
2922 const EC_GROUP *group;
2923 EC_POINT *l = NULL;
2924 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2925 const EC_POINT *BI_point;
2926 BN_CTX *bnctx;
2927 BIGNUM *lx, *sum, *q;
2928 const BIGNUM *bR_bn, *pR_bn;
2929 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002930
2931 /* L = ((bR + pR) modulo q) * BI */
2932
2933 bnctx = BN_CTX_new();
2934 sum = BN_new();
2935 q = BN_new();
2936 lx = BN_new();
2937 if (!bnctx || !sum || !q || !lx)
2938 goto fail;
2939 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2940 if (!BI)
2941 goto fail;
2942 BI_point = EC_KEY_get0_public_key(BI);
2943 group = EC_KEY_get0_group(BI);
2944 if (!group)
2945 goto fail;
2946
2947 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2948 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2949 if (!bR || !pR)
2950 goto fail;
2951 bR_bn = EC_KEY_get0_private_key(bR);
2952 pR_bn = EC_KEY_get0_private_key(pR);
2953 if (!bR_bn || !pR_bn)
2954 goto fail;
2955 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2956 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2957 goto fail;
2958 l = EC_POINT_new(group);
2959 if (!l ||
2960 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2961 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2962 bnctx) != 1) {
2963 wpa_printf(MSG_ERROR,
2964 "OpenSSL: failed: %s",
2965 ERR_error_string(ERR_get_error(), NULL));
2966 goto fail;
2967 }
2968
Roshan Pius3a1667e2018-07-03 15:17:14 -07002969 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002970 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002971 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002972 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002973 ret = 0;
2974fail:
2975 EC_POINT_clear_free(l);
2976 EC_KEY_free(BI);
2977 EC_KEY_free(bR);
2978 EC_KEY_free(pR);
2979 BN_clear_free(lx);
2980 BN_clear_free(sum);
2981 BN_free(q);
2982 BN_CTX_free(bnctx);
2983 return ret;
2984}
2985
2986
2987static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2988{
2989 const EC_GROUP *group;
2990 EC_POINT *l = NULL, *sum = NULL;
2991 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2992 const EC_POINT *BR_point, *PR_point;
2993 BN_CTX *bnctx;
2994 BIGNUM *lx;
2995 const BIGNUM *bI_bn;
2996 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002997
2998 /* L = bI * (BR + PR) */
2999
3000 bnctx = BN_CTX_new();
3001 lx = BN_new();
3002 if (!bnctx || !lx)
3003 goto fail;
3004 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
3005 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
3006 if (!BR || !PR)
3007 goto fail;
3008 BR_point = EC_KEY_get0_public_key(BR);
3009 PR_point = EC_KEY_get0_public_key(PR);
3010
3011 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
3012 if (!bI)
3013 goto fail;
3014 group = EC_KEY_get0_group(bI);
3015 bI_bn = EC_KEY_get0_private_key(bI);
3016 if (!group || !bI_bn)
3017 goto fail;
3018 sum = EC_POINT_new(group);
3019 l = EC_POINT_new(group);
3020 if (!sum || !l ||
3021 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
3022 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
3023 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
3024 bnctx) != 1) {
3025 wpa_printf(MSG_ERROR,
3026 "OpenSSL: failed: %s",
3027 ERR_error_string(ERR_get_error(), NULL));
3028 goto fail;
3029 }
3030
Roshan Pius3a1667e2018-07-03 15:17:14 -07003031 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003032 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003033 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003034 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003035 ret = 0;
3036fail:
3037 EC_POINT_clear_free(l);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08003038 EC_POINT_clear_free(sum);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003039 EC_KEY_free(bI);
3040 EC_KEY_free(BR);
3041 EC_KEY_free(PR);
3042 BN_clear_free(lx);
3043 BN_CTX_free(bnctx);
3044 return ret;
3045}
3046
3047
Roshan Pius3a1667e2018-07-03 15:17:14 -07003048static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003049{
3050 size_t nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003051 size_t secret_len;
3052 struct wpabuf *msg, *pr = NULL;
3053 u8 r_auth[4 + DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07003054 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003055 size_t wrapped_r_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003056 int ret = -1;
3057 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
3058 enum dpp_status_error status = DPP_STATUS_OK;
3059#ifdef CONFIG_TESTING_OPTIONS
3060 u8 test_hash[SHA256_MAC_LEN];
3061#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003062
3063 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003064 if (!auth->own_bi)
3065 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003066
Roshan Pius3a1667e2018-07-03 15:17:14 -07003067#ifdef CONFIG_TESTING_OPTIONS
3068 if (dpp_nonce_override_len > 0) {
3069 wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
3070 nonce_len = dpp_nonce_override_len;
3071 os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
3072 } else {
3073 nonce_len = auth->curve->nonce_len;
3074 if (random_get_bytes(auth->r_nonce, nonce_len)) {
3075 wpa_printf(MSG_ERROR,
3076 "DPP: Failed to generate R-nonce");
3077 goto fail;
3078 }
3079 }
3080#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003081 nonce_len = auth->curve->nonce_len;
3082 if (random_get_bytes(auth->r_nonce, nonce_len)) {
3083 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
3084 goto fail;
3085 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003086#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003087 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
3088
Hai Shalom81f62d82019-07-22 12:10:00 -07003089 EVP_PKEY_free(auth->own_protocol_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003090#ifdef CONFIG_TESTING_OPTIONS
3091 if (dpp_protocol_key_override_len) {
3092 const struct dpp_curve_params *tmp_curve;
3093
3094 wpa_printf(MSG_INFO,
3095 "DPP: TESTING - override protocol key");
3096 auth->own_protocol_key = dpp_set_keypair(
3097 &tmp_curve, dpp_protocol_key_override,
3098 dpp_protocol_key_override_len);
3099 } else {
3100 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
3101 }
3102#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003103 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003104#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003105 if (!auth->own_protocol_key)
3106 goto fail;
3107
3108 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
3109 if (!pr)
3110 goto fail;
3111
3112 /* ECDH: N = pR * PI */
Hai Shalomc3565922019-10-28 11:58:20 -07003113 if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
3114 auth->Nx, &secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003115 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003116
3117 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3118 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003119 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003120
3121 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3122 auth->curve->hash_len) < 0)
3123 goto fail;
3124
3125 if (auth->own_bi && auth->peer_bi) {
3126 /* Mutual authentication */
3127 if (dpp_auth_derive_l_responder(auth) < 0)
3128 goto fail;
3129 }
3130
3131 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3132 goto fail;
3133
3134 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3135 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
3136 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003137 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
3138 goto fail;
3139#ifdef CONFIG_TESTING_OPTIONS
3140 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
3141 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
3142 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3143 }
3144#endif /* CONFIG_TESTING_OPTIONS */
3145 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003146 r_auth, 4 + auth->curve->hash_len,
3147 0, NULL, NULL, wrapped_r_auth) < 0)
3148 goto fail;
3149 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
3150 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
3151 wrapped_r_auth, wrapped_r_auth_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003152 w_r_auth = wrapped_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003153
Roshan Pius3a1667e2018-07-03 15:17:14 -07003154 r_pubkey_hash = auth->own_bi->pubkey_hash;
3155 if (auth->peer_bi)
3156 i_pubkey_hash = auth->peer_bi->pubkey_hash;
3157 else
3158 i_pubkey_hash = NULL;
3159
3160 i_nonce = auth->i_nonce;
3161 r_nonce = auth->r_nonce;
3162
3163#ifdef CONFIG_TESTING_OPTIONS
3164 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3165 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3166 r_pubkey_hash = NULL;
3167 } else if (dpp_test ==
3168 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3169 wpa_printf(MSG_INFO,
3170 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3171 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3172 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3173 r_pubkey_hash = test_hash;
3174 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3175 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3176 i_pubkey_hash = NULL;
3177 } else if (dpp_test ==
3178 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3179 wpa_printf(MSG_INFO,
3180 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3181 if (i_pubkey_hash)
3182 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3183 else
3184 os_memset(test_hash, 0, SHA256_MAC_LEN);
3185 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3186 i_pubkey_hash = test_hash;
3187 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
3188 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
3189 wpabuf_free(pr);
3190 pr = NULL;
3191 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
3192 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
3193 wpabuf_free(pr);
3194 pr = wpabuf_alloc(2 * auth->curve->prime_len);
3195 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
3196 goto fail;
3197 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
3198 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
3199 w_r_auth = NULL;
3200 wrapped_r_auth_len = 0;
3201 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
3202 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3203 status = 255;
3204 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
3205 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3206 status = 254;
3207 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
3208 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
3209 r_nonce = NULL;
3210 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
3211 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
3212 i_nonce = NULL;
3213 }
3214#endif /* CONFIG_TESTING_OPTIONS */
3215
3216 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
3217 r_pubkey_hash, i_pubkey_hash,
3218 r_nonce, i_nonce,
3219 w_r_auth, wrapped_r_auth_len,
3220 auth->k2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003221 if (!msg)
3222 goto fail;
3223 wpabuf_free(auth->resp_msg);
3224 auth->resp_msg = msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003225 ret = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003226fail:
3227 wpabuf_free(pr);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003228 return ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003229}
3230
3231
3232static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
3233 enum dpp_status_error status)
3234{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003235 struct wpabuf *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003236 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
3237#ifdef CONFIG_TESTING_OPTIONS
3238 u8 test_hash[SHA256_MAC_LEN];
3239#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003240
Roshan Pius3a1667e2018-07-03 15:17:14 -07003241 if (!auth->own_bi)
3242 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003243 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
3244
Roshan Pius3a1667e2018-07-03 15:17:14 -07003245 r_pubkey_hash = auth->own_bi->pubkey_hash;
3246 if (auth->peer_bi)
3247 i_pubkey_hash = auth->peer_bi->pubkey_hash;
3248 else
3249 i_pubkey_hash = NULL;
3250
3251 i_nonce = auth->i_nonce;
3252
3253#ifdef CONFIG_TESTING_OPTIONS
3254 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3255 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3256 r_pubkey_hash = NULL;
3257 } else if (dpp_test ==
3258 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3259 wpa_printf(MSG_INFO,
3260 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3261 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3262 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3263 r_pubkey_hash = test_hash;
3264 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3265 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3266 i_pubkey_hash = NULL;
3267 } else if (dpp_test ==
3268 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3269 wpa_printf(MSG_INFO,
3270 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3271 if (i_pubkey_hash)
3272 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3273 else
3274 os_memset(test_hash, 0, SHA256_MAC_LEN);
3275 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3276 i_pubkey_hash = test_hash;
3277 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
3278 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
Hai Shalom74f70d42019-02-11 14:42:39 -08003279 status = 255;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003280 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
3281 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
3282 i_nonce = NULL;
3283 }
3284#endif /* CONFIG_TESTING_OPTIONS */
3285
3286 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
3287 r_pubkey_hash, i_pubkey_hash,
3288 NULL, i_nonce, NULL, 0, auth->k1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003289 if (!msg)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003290 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003291 wpabuf_free(auth->resp_msg);
3292 auth->resp_msg = msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003293 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003294}
3295
3296
3297struct dpp_authentication *
Hai Shalomfdcde762020-04-02 11:19:20 -07003298dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
3299 int qr_mutual, struct dpp_bootstrap_info *peer_bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003300 struct dpp_bootstrap_info *own_bi,
3301 unsigned int freq, const u8 *hdr, const u8 *attr_start,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003302 size_t attr_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003303{
3304 EVP_PKEY *pi = NULL;
3305 EVP_PKEY_CTX *ctx = NULL;
3306 size_t secret_len;
3307 const u8 *addr[2];
3308 size_t len[2];
3309 u8 *unwrapped = NULL;
3310 size_t unwrapped_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003311 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
3312 *channel;
3313 u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
3314 i_bootstrap_len, channel_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003315 struct dpp_authentication *auth = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07003316#ifdef CONFIG_DPP2
3317 const u8 *version;
3318 u16 version_len;
3319#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003320
Roshan Pius3a1667e2018-07-03 15:17:14 -07003321#ifdef CONFIG_TESTING_OPTIONS
3322 if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
3323 wpa_printf(MSG_INFO,
3324 "DPP: TESTING - stop at Authentication Request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003325 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003326 }
3327#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003328
Roshan Pius3a1667e2018-07-03 15:17:14 -07003329 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3330 &wrapped_data_len);
3331 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3332 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3333 "Missing or invalid required Wrapped Data attribute");
3334 return NULL;
3335 }
3336 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
3337 wrapped_data, wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003338 attr_len = wrapped_data - 4 - attr_start;
3339
Hai Shalomfdcde762020-04-02 11:19:20 -07003340 auth = dpp_alloc_auth(dpp, msg_ctx);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003341 if (!auth)
3342 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003343 if (peer_bi && peer_bi->configurator_params &&
3344 dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
3345 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003346 auth->peer_bi = peer_bi;
3347 auth->own_bi = own_bi;
3348 auth->curve = own_bi->curve;
3349 auth->curr_freq = freq;
3350
Hai Shalom021b0b52019-04-10 11:17:58 -07003351 auth->peer_version = 1; /* default to the first version */
3352#ifdef CONFIG_DPP2
3353 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3354 &version_len);
3355 if (version) {
3356 if (version_len < 1 || version[0] == 0) {
3357 dpp_auth_fail(auth,
3358 "Invalid Protocol Version attribute");
3359 goto fail;
3360 }
3361 auth->peer_version = version[0];
3362 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3363 auth->peer_version);
3364 }
3365#endif /* CONFIG_DPP2 */
3366
Roshan Pius3a1667e2018-07-03 15:17:14 -07003367 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
3368 &channel_len);
3369 if (channel) {
3370 int neg_freq;
3371
3372 if (channel_len < 2) {
3373 dpp_auth_fail(auth, "Too short Channel attribute");
3374 goto fail;
3375 }
3376
3377 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
3378 wpa_printf(MSG_DEBUG,
3379 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3380 channel[0], channel[1], neg_freq);
3381 if (neg_freq < 0) {
3382 dpp_auth_fail(auth,
3383 "Unsupported Channel attribute value");
3384 goto fail;
3385 }
3386
3387 if (auth->curr_freq != (unsigned int) neg_freq) {
3388 wpa_printf(MSG_DEBUG,
3389 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3390 freq, neg_freq);
3391 auth->curr_freq = neg_freq;
3392 }
3393 }
3394
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003395 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
3396 &i_proto_len);
3397 if (!i_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003398 dpp_auth_fail(auth,
3399 "Missing required Initiator Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003400 goto fail;
3401 }
3402 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
3403 i_proto, i_proto_len);
3404
3405 /* M = bR * PI */
3406 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
3407 if (!pi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003408 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003409 goto fail;
3410 }
3411 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
3412
Hai Shalomc3565922019-10-28 11:58:20 -07003413 if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003414 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003415 auth->secret_len = secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003416
3417 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
3418 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003419 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003420
3421 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
3422 auth->curve->hash_len) < 0)
3423 goto fail;
3424
3425 addr[0] = hdr;
3426 len[0] = DPP_HDR_LEN;
3427 addr[1] = attr_start;
3428 len[1] = attr_len;
3429 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3430 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3431 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3432 wrapped_data, wrapped_data_len);
3433 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3434 unwrapped = os_malloc(unwrapped_len);
3435 if (!unwrapped)
3436 goto fail;
3437 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3438 wrapped_data, wrapped_data_len,
3439 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003440 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003441 goto fail;
3442 }
3443 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3444 unwrapped, unwrapped_len);
3445
3446 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003447 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003448 goto fail;
3449 }
3450
3451 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3452 &i_nonce_len);
3453 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003454 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003455 goto fail;
3456 }
3457 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3458 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
3459
3460 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
3461 DPP_ATTR_I_CAPABILITIES,
3462 &i_capab_len);
3463 if (!i_capab || i_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003464 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003465 goto fail;
3466 }
3467 auth->i_capab = i_capab[0];
3468 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
3469
3470 bin_clear_free(unwrapped, unwrapped_len);
3471 unwrapped = NULL;
3472
3473 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
3474 case DPP_CAPAB_ENROLLEE:
3475 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
3476 wpa_printf(MSG_DEBUG,
3477 "DPP: Local policy does not allow Configurator role");
3478 goto not_compatible;
3479 }
3480 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3481 auth->configurator = 1;
3482 break;
3483 case DPP_CAPAB_CONFIGURATOR:
3484 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
3485 wpa_printf(MSG_DEBUG,
3486 "DPP: Local policy does not allow Enrollee role");
3487 goto not_compatible;
3488 }
3489 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3490 auth->configurator = 0;
3491 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003492 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
3493 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
3494 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3495 auth->configurator = 0;
3496 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
3497 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3498 auth->configurator = 1;
3499 } else {
3500 wpa_printf(MSG_DEBUG,
3501 "DPP: Local policy does not allow Configurator/Enrollee role");
3502 goto not_compatible;
3503 }
3504 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003505 default:
3506 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003507 wpa_msg(auth->msg_ctx, MSG_INFO,
3508 DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
3509 auth->i_capab & DPP_CAPAB_ROLE_MASK);
3510 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003511 }
3512
3513 auth->peer_protocol_key = pi;
3514 pi = NULL;
3515 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
3516 char hex[SHA256_MAC_LEN * 2 + 1];
3517
3518 wpa_printf(MSG_DEBUG,
3519 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3520 if (dpp_auth_build_resp_status(auth,
3521 DPP_STATUS_RESPONSE_PENDING) < 0)
3522 goto fail;
3523 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3524 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3525 &i_bootstrap_len);
3526 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
3527 auth->response_pending = 1;
3528 os_memcpy(auth->waiting_pubkey_hash,
3529 i_bootstrap, i_bootstrap_len);
3530 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
3531 i_bootstrap_len);
3532 } else {
3533 hex[0] = '\0';
3534 }
3535
3536 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
3537 "%s", hex);
3538 return auth;
3539 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003540 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003541 goto fail;
3542
3543 return auth;
3544
3545not_compatible:
3546 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3547 "i-capab=0x%02x", auth->i_capab);
3548 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
3549 auth->configurator = 1;
3550 else
3551 auth->configurator = 0;
3552 auth->peer_protocol_key = pi;
3553 pi = NULL;
3554 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
3555 goto fail;
3556
3557 auth->remove_on_tx_status = 1;
3558 return auth;
3559fail:
3560 bin_clear_free(unwrapped, unwrapped_len);
3561 EVP_PKEY_free(pi);
3562 EVP_PKEY_CTX_free(ctx);
3563 dpp_auth_deinit(auth);
3564 return NULL;
3565}
3566
3567
3568int dpp_notify_new_qr_code(struct dpp_authentication *auth,
3569 struct dpp_bootstrap_info *peer_bi)
3570{
3571 if (!auth || !auth->response_pending ||
3572 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
3573 SHA256_MAC_LEN) != 0)
3574 return 0;
3575
3576 wpa_printf(MSG_DEBUG,
3577 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3578 MACSTR, MAC2STR(auth->peer_mac_addr));
3579 auth->peer_bi = peer_bi;
3580
Roshan Pius3a1667e2018-07-03 15:17:14 -07003581 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003582 return -1;
3583
3584 return 1;
3585}
3586
3587
Roshan Pius3a1667e2018-07-03 15:17:14 -07003588static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
3589 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003590{
3591 struct wpabuf *msg;
3592 u8 i_auth[4 + DPP_MAX_HASH_LEN];
3593 size_t i_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003594 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3595 size_t r_nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003596 const u8 *addr[2];
3597 size_t len[2], attr_len;
3598 u8 *wrapped_i_auth;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003599 u8 *wrapped_r_nonce;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003600 u8 *attr_start, *attr_end;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003601 const u8 *r_pubkey_hash, *i_pubkey_hash;
3602#ifdef CONFIG_TESTING_OPTIONS
3603 u8 test_hash[SHA256_MAC_LEN];
3604#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003605
3606 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3607
3608 i_auth_len = 4 + auth->curve->hash_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003609 r_nonce_len = 4 + auth->curve->nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003610 /* Build DPP Authentication Confirmation frame attributes */
3611 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
Roshan Pius3a1667e2018-07-03 15:17:14 -07003612 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
3613#ifdef CONFIG_TESTING_OPTIONS
3614 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
3615 attr_len += 5;
3616#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003617 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
3618 if (!msg)
3619 goto fail;
3620
3621 attr_start = wpabuf_put(msg, 0);
3622
Roshan Pius3a1667e2018-07-03 15:17:14 -07003623 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3624 if (auth->own_bi)
3625 i_pubkey_hash = auth->own_bi->pubkey_hash;
3626 else
3627 i_pubkey_hash = NULL;
3628
3629#ifdef CONFIG_TESTING_OPTIONS
3630 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3631 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3632 goto skip_status;
3633 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3634 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3635 status = 254;
3636 }
3637#endif /* CONFIG_TESTING_OPTIONS */
3638
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003639 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003640 dpp_build_attr_status(msg, status);
3641
3642#ifdef CONFIG_TESTING_OPTIONS
3643skip_status:
3644 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3645 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3646 r_pubkey_hash = NULL;
3647 } else if (dpp_test ==
3648 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3649 wpa_printf(MSG_INFO,
3650 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3651 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3652 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3653 r_pubkey_hash = test_hash;
3654 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3655 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3656 i_pubkey_hash = NULL;
3657 } else if (dpp_test ==
3658 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3659 wpa_printf(MSG_INFO,
3660 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3661 if (i_pubkey_hash)
3662 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3663 else
3664 os_memset(test_hash, 0, SHA256_MAC_LEN);
3665 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3666 i_pubkey_hash = test_hash;
3667 }
3668#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003669
3670 /* Responder Bootstrapping Key Hash */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003671 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003672
Roshan Pius3a1667e2018-07-03 15:17:14 -07003673 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3674 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
3675
3676#ifdef CONFIG_TESTING_OPTIONS
3677 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3678 goto skip_wrapped_data;
3679 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3680 i_auth_len = 0;
3681#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003682
3683 attr_end = wpabuf_put(msg, 0);
3684
3685 /* OUI, OUI type, Crypto Suite, DPP frame type */
3686 addr[0] = wpabuf_head_u8(msg) + 2;
3687 len[0] = 3 + 1 + 1 + 1;
3688 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3689
3690 /* Attributes before Wrapped Data */
3691 addr[1] = attr_start;
3692 len[1] = attr_end - attr_start;
3693 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3694
Roshan Pius3a1667e2018-07-03 15:17:14 -07003695 if (status == DPP_STATUS_OK) {
3696 /* I-auth wrapped with ke */
3697 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3698 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3699 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
3700
3701#ifdef CONFIG_TESTING_OPTIONS
3702 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3703 goto skip_i_auth;
3704#endif /* CONFIG_TESTING_OPTIONS */
3705
3706 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3707 * 1) */
3708 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3709 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3710 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3711 goto fail;
3712
3713#ifdef CONFIG_TESTING_OPTIONS
3714 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3715 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3716 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3717 }
3718skip_i_auth:
3719#endif /* CONFIG_TESTING_OPTIONS */
3720 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3721 i_auth, i_auth_len,
3722 2, addr, len, wrapped_i_auth) < 0)
3723 goto fail;
3724 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3725 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3726 } else {
3727 /* R-nonce wrapped with k2 */
3728 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3729 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3730 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3731
3732 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3733 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3734 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3735
3736 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3737 r_nonce, r_nonce_len,
3738 2, addr, len, wrapped_r_nonce) < 0)
3739 goto fail;
3740 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3741 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3742 }
3743
3744#ifdef CONFIG_TESTING_OPTIONS
3745 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3746 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
3747 dpp_build_attr_status(msg, DPP_STATUS_OK);
3748 }
3749skip_wrapped_data:
3750#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003751
3752 wpa_hexdump_buf(MSG_DEBUG,
3753 "DPP: Authentication Confirmation frame attributes",
3754 msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003755 if (status == DPP_STATUS_OK)
3756 dpp_auth_success(auth);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003757
3758 return msg;
3759
3760fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07003761 wpabuf_free(msg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003762 return NULL;
3763}
3764
3765
3766static void
3767dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
3768 const u8 *attr_start, size_t attr_len,
3769 const u8 *wrapped_data, u16 wrapped_data_len,
3770 enum dpp_status_error status)
3771{
3772 const u8 *addr[2];
3773 size_t len[2];
3774 u8 *unwrapped = NULL;
3775 size_t unwrapped_len = 0;
3776 const u8 *i_nonce, *r_capab;
3777 u16 i_nonce_len, r_capab_len;
3778
3779 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3780 wpa_printf(MSG_DEBUG,
3781 "DPP: Responder reported incompatible roles");
3782 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3783 wpa_printf(MSG_DEBUG,
3784 "DPP: Responder reported more time needed");
3785 } else {
3786 wpa_printf(MSG_DEBUG,
3787 "DPP: Responder reported failure (status %d)",
3788 status);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003789 dpp_auth_fail(auth, "Responder reported failure");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003790 return;
3791 }
3792
3793 addr[0] = hdr;
3794 len[0] = DPP_HDR_LEN;
3795 addr[1] = attr_start;
3796 len[1] = attr_len;
3797 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3798 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3799 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3800 wrapped_data, wrapped_data_len);
3801 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3802 unwrapped = os_malloc(unwrapped_len);
3803 if (!unwrapped)
3804 goto fail;
3805 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3806 wrapped_data, wrapped_data_len,
3807 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003808 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003809 goto fail;
3810 }
3811 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3812 unwrapped, unwrapped_len);
3813
3814 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003815 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003816 goto fail;
3817 }
3818
3819 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3820 &i_nonce_len);
3821 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003822 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003823 goto fail;
3824 }
3825 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3826 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003827 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003828 goto fail;
3829 }
3830
3831 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3832 DPP_ATTR_R_CAPABILITIES,
3833 &r_capab_len);
3834 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003835 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003836 goto fail;
3837 }
3838 auth->r_capab = r_capab[0];
3839 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3840 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3841 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3842 "r-capab=0x%02x", auth->r_capab);
3843 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003844 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3845
3846 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3847 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3848 wpa_msg(auth->msg_ctx, MSG_INFO,
3849 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3850 role);
3851 } else {
3852 wpa_printf(MSG_DEBUG,
3853 "DPP: Continue waiting for full DPP Authentication Response");
3854 wpa_msg(auth->msg_ctx, MSG_INFO,
3855 DPP_EVENT_RESPONSE_PENDING "%s",
3856 auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
3857 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003858 }
3859fail:
3860 bin_clear_free(unwrapped, unwrapped_len);
3861}
3862
3863
3864struct wpabuf *
3865dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3866 const u8 *attr_start, size_t attr_len)
3867{
3868 EVP_PKEY *pr;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003869 size_t secret_len;
3870 const u8 *addr[2];
3871 size_t len[2];
3872 u8 *unwrapped = NULL, *unwrapped2 = NULL;
3873 size_t unwrapped_len = 0, unwrapped2_len = 0;
3874 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3875 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3876 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3877 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3878 wrapped2_len, r_auth_len;
3879 u8 r_auth2[DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07003880 u8 role;
Hai Shalom021b0b52019-04-10 11:17:58 -07003881#ifdef CONFIG_DPP2
3882 const u8 *version;
3883 u16 version_len;
3884#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003885
3886#ifdef CONFIG_TESTING_OPTIONS
3887 if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
3888 wpa_printf(MSG_INFO,
3889 "DPP: TESTING - stop at Authentication Response");
3890 return NULL;
3891 }
3892#endif /* CONFIG_TESTING_OPTIONS */
3893
Hai Shalom74f70d42019-02-11 14:42:39 -08003894 if (!auth->initiator || !auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003895 dpp_auth_fail(auth, "Unexpected Authentication Response");
3896 return NULL;
3897 }
3898
3899 auth->waiting_auth_resp = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003900
3901 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3902 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003903 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3904 dpp_auth_fail(auth,
3905 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003906 return NULL;
3907 }
3908 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3909 wrapped_data, wrapped_data_len);
3910
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003911 attr_len = wrapped_data - 4 - attr_start;
3912
3913 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3914 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3915 &r_bootstrap_len);
3916 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003917 dpp_auth_fail(auth,
3918 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003919 return NULL;
3920 }
3921 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3922 r_bootstrap, r_bootstrap_len);
3923 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3924 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003925 dpp_auth_fail(auth,
3926 "Unexpected Responder Bootstrapping Key Hash value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003927 wpa_hexdump(MSG_DEBUG,
3928 "DPP: Expected Responder Bootstrapping Key Hash",
3929 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3930 return NULL;
3931 }
3932
3933 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3934 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3935 &i_bootstrap_len);
3936 if (i_bootstrap) {
3937 if (i_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003938 dpp_auth_fail(auth,
3939 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003940 return NULL;
3941 }
3942 wpa_hexdump(MSG_MSGDUMP,
3943 "DPP: Initiator Bootstrapping Key Hash",
3944 i_bootstrap, i_bootstrap_len);
3945 if (!auth->own_bi ||
3946 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3947 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003948 dpp_auth_fail(auth,
3949 "Initiator Bootstrapping Key Hash attribute did not match");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003950 return NULL;
3951 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003952 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3953 /* PKEX bootstrapping mandates use of mutual authentication */
3954 dpp_auth_fail(auth,
3955 "Missing Initiator Bootstrapping Key Hash attribute");
3956 return NULL;
Hai Shalomb755a2a2020-04-23 21:49:02 -07003957 } else if (auth->own_bi &&
3958 auth->own_bi->type == DPP_BOOTSTRAP_NFC_URI &&
3959 auth->own_bi->nfc_negotiated) {
3960 /* NFC negotiated connection handover bootstrapping mandates
3961 * use of mutual authentication */
3962 dpp_auth_fail(auth,
3963 "Missing Initiator Bootstrapping Key Hash attribute");
3964 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003965 }
3966
Hai Shalom021b0b52019-04-10 11:17:58 -07003967 auth->peer_version = 1; /* default to the first version */
3968#ifdef CONFIG_DPP2
3969 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3970 &version_len);
3971 if (version) {
3972 if (version_len < 1 || version[0] == 0) {
3973 dpp_auth_fail(auth,
3974 "Invalid Protocol Version attribute");
3975 return NULL;
3976 }
3977 auth->peer_version = version[0];
3978 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3979 auth->peer_version);
3980 }
3981#endif /* CONFIG_DPP2 */
3982
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003983 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3984 &status_len);
3985 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003986 dpp_auth_fail(auth,
3987 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003988 return NULL;
3989 }
3990 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3991 auth->auth_resp_status = status[0];
3992 if (status[0] != DPP_STATUS_OK) {
3993 dpp_auth_resp_rx_status(auth, hdr, attr_start,
3994 attr_len, wrapped_data,
3995 wrapped_data_len, status[0]);
3996 return NULL;
3997 }
3998
Roshan Pius3a1667e2018-07-03 15:17:14 -07003999 if (!i_bootstrap && auth->own_bi) {
4000 wpa_printf(MSG_DEBUG,
4001 "DPP: Responder decided not to use mutual authentication");
4002 auth->own_bi = NULL;
4003 }
4004
4005 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
4006 auth->own_bi != NULL);
4007
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004008 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
4009 &r_proto_len);
4010 if (!r_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004011 dpp_auth_fail(auth,
4012 "Missing required Responder Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004013 return NULL;
4014 }
4015 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
4016 r_proto, r_proto_len);
4017
4018 /* N = pI * PR */
4019 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
4020 if (!pr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004021 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004022 return NULL;
4023 }
4024 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
4025
Hai Shalomc3565922019-10-28 11:58:20 -07004026 if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004027 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004028 goto fail;
4029 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004030 EVP_PKEY_free(auth->peer_protocol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004031 auth->peer_protocol_key = pr;
4032 pr = NULL;
4033
4034 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4035 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004036 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004037
4038 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
4039 auth->curve->hash_len) < 0)
4040 goto fail;
4041
4042 addr[0] = hdr;
4043 len[0] = DPP_HDR_LEN;
4044 addr[1] = attr_start;
4045 len[1] = attr_len;
4046 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4047 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4048 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4049 wrapped_data, wrapped_data_len);
4050 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4051 unwrapped = os_malloc(unwrapped_len);
4052 if (!unwrapped)
4053 goto fail;
4054 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
4055 wrapped_data, wrapped_data_len,
4056 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004057 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004058 goto fail;
4059 }
4060 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4061 unwrapped, unwrapped_len);
4062
4063 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004064 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004065 goto fail;
4066 }
4067
4068 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
4069 &r_nonce_len);
4070 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004071 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004072 goto fail;
4073 }
4074 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
4075 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
4076
4077 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
4078 &i_nonce_len);
4079 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004080 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004081 goto fail;
4082 }
4083 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
4084 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004085 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004086 goto fail;
4087 }
4088
Hai Shalom74f70d42019-02-11 14:42:39 -08004089 if (auth->own_bi) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004090 /* Mutual authentication */
4091 if (dpp_auth_derive_l_initiator(auth) < 0)
4092 goto fail;
4093 }
4094
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004095 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
4096 DPP_ATTR_R_CAPABILITIES,
4097 &r_capab_len);
4098 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004099 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004100 goto fail;
4101 }
4102 auth->r_capab = r_capab[0];
4103 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004104 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
4105 if ((auth->allowed_roles ==
4106 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
4107 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
4108 /* Peer selected its role, so move from "either role" to the
4109 * role that is compatible with peer's selection. */
4110 auth->configurator = role == DPP_CAPAB_ENROLLEE;
4111 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
4112 auth->configurator ? "Configurator" : "Enrollee");
4113 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
4114 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004115 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004116 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
4117 "Unexpected role in R-capabilities 0x%02x",
4118 role);
4119 if (role != DPP_CAPAB_ENROLLEE &&
4120 role != DPP_CAPAB_CONFIGURATOR)
4121 goto fail;
4122 bin_clear_free(unwrapped, unwrapped_len);
4123 auth->remove_on_tx_status = 1;
4124 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004125 }
4126
4127 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
4128 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
4129 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004130 dpp_auth_fail(auth,
4131 "Missing or invalid Secondary Wrapped Data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004132 goto fail;
4133 }
4134
4135 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4136 wrapped2, wrapped2_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004137
4138 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
4139 goto fail;
4140
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004141 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
4142 unwrapped2 = os_malloc(unwrapped2_len);
4143 if (!unwrapped2)
4144 goto fail;
4145 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4146 wrapped2, wrapped2_len,
4147 0, NULL, NULL, unwrapped2) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004148 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004149 goto fail;
4150 }
4151 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4152 unwrapped2, unwrapped2_len);
4153
4154 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004155 dpp_auth_fail(auth,
4156 "Invalid attribute in secondary unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004157 goto fail;
4158 }
4159
4160 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
4161 &r_auth_len);
4162 if (!r_auth || r_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004163 dpp_auth_fail(auth,
4164 "Missing or invalid Responder Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004165 goto fail;
4166 }
4167 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
4168 r_auth, r_auth_len);
4169 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4170 if (dpp_gen_r_auth(auth, r_auth2) < 0)
4171 goto fail;
4172 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
4173 r_auth2, r_auth_len);
4174 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004175 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
4176 bin_clear_free(unwrapped, unwrapped_len);
4177 bin_clear_free(unwrapped2, unwrapped2_len);
4178 auth->remove_on_tx_status = 1;
4179 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004180 }
4181
4182 bin_clear_free(unwrapped, unwrapped_len);
4183 bin_clear_free(unwrapped2, unwrapped2_len);
4184
Roshan Pius3a1667e2018-07-03 15:17:14 -07004185#ifdef CONFIG_TESTING_OPTIONS
4186 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
4187 wpa_printf(MSG_INFO,
4188 "DPP: TESTING - Authentication Response in place of Confirm");
4189 if (dpp_auth_build_resp_ok(auth) < 0)
4190 return NULL;
4191 return wpabuf_dup(auth->resp_msg);
4192 }
4193#endif /* CONFIG_TESTING_OPTIONS */
4194
4195 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004196
4197fail:
4198 bin_clear_free(unwrapped, unwrapped_len);
4199 bin_clear_free(unwrapped2, unwrapped2_len);
4200 EVP_PKEY_free(pr);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004201 return NULL;
4202}
4203
4204
Roshan Pius3a1667e2018-07-03 15:17:14 -07004205static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
4206 const u8 *hdr,
4207 const u8 *attr_start, size_t attr_len,
4208 const u8 *wrapped_data,
4209 u16 wrapped_data_len,
4210 enum dpp_status_error status)
4211{
4212 const u8 *addr[2];
4213 size_t len[2];
4214 u8 *unwrapped = NULL;
4215 size_t unwrapped_len = 0;
4216 const u8 *r_nonce;
4217 u16 r_nonce_len;
4218
4219 /* Authentication Confirm failure cases are expected to include
4220 * {R-nonce}k2 in the Wrapped Data attribute. */
4221
4222 addr[0] = hdr;
4223 len[0] = DPP_HDR_LEN;
4224 addr[1] = attr_start;
4225 len[1] = attr_len;
4226 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4227 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4228 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4229 wrapped_data, wrapped_data_len);
4230 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4231 unwrapped = os_malloc(unwrapped_len);
4232 if (!unwrapped) {
4233 dpp_auth_fail(auth, "Authentication failed");
4234 goto fail;
4235 }
4236 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
4237 wrapped_data, wrapped_data_len,
4238 2, addr, len, unwrapped) < 0) {
4239 dpp_auth_fail(auth, "AES-SIV decryption failed");
4240 goto fail;
4241 }
4242 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4243 unwrapped, unwrapped_len);
4244
4245 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4246 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4247 goto fail;
4248 }
4249
4250 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
4251 &r_nonce_len);
4252 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
4253 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
4254 goto fail;
4255 }
4256 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
4257 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
4258 r_nonce, r_nonce_len);
4259 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
4260 auth->r_nonce, r_nonce_len);
4261 dpp_auth_fail(auth, "R-nonce mismatch");
4262 goto fail;
4263 }
4264
4265 if (status == DPP_STATUS_NOT_COMPATIBLE)
4266 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
4267 else if (status == DPP_STATUS_AUTH_FAILURE)
4268 dpp_auth_fail(auth, "Peer reported authentication failure)");
4269
4270fail:
4271 bin_clear_free(unwrapped, unwrapped_len);
4272 return -1;
4273}
4274
4275
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004276int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
4277 const u8 *attr_start, size_t attr_len)
4278{
4279 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
4280 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
4281 i_auth_len;
4282 const u8 *addr[2];
4283 size_t len[2];
4284 u8 *unwrapped = NULL;
4285 size_t unwrapped_len = 0;
4286 u8 i_auth2[DPP_MAX_HASH_LEN];
4287
Roshan Pius3a1667e2018-07-03 15:17:14 -07004288#ifdef CONFIG_TESTING_OPTIONS
4289 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
4290 wpa_printf(MSG_INFO,
4291 "DPP: TESTING - stop at Authentication Confirm");
4292 return -1;
4293 }
4294#endif /* CONFIG_TESTING_OPTIONS */
4295
Hai Shalomfdcde762020-04-02 11:19:20 -07004296 if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) {
4297 wpa_printf(MSG_DEBUG,
4298 "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
4299 auth->initiator, !!auth->own_bi,
4300 auth->waiting_auth_conf);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004301 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
4302 return -1;
4303 }
4304
4305 auth->waiting_auth_conf = 0;
4306
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004307 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4308 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004309 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4310 dpp_auth_fail(auth,
4311 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004312 return -1;
4313 }
4314 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
4315 wrapped_data, wrapped_data_len);
4316
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004317 attr_len = wrapped_data - 4 - attr_start;
4318
4319 r_bootstrap = dpp_get_attr(attr_start, attr_len,
4320 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
4321 &r_bootstrap_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004322 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
4323 dpp_auth_fail(auth,
4324 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004325 return -1;
4326 }
4327 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
4328 r_bootstrap, r_bootstrap_len);
4329 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
4330 SHA256_MAC_LEN) != 0) {
4331 wpa_hexdump(MSG_DEBUG,
4332 "DPP: Expected Responder Bootstrapping Key Hash",
4333 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004334 dpp_auth_fail(auth,
4335 "Responder Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004336 return -1;
4337 }
4338
4339 i_bootstrap = dpp_get_attr(attr_start, attr_len,
4340 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
4341 &i_bootstrap_len);
4342 if (i_bootstrap) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004343 if (i_bootstrap_len != SHA256_MAC_LEN) {
4344 dpp_auth_fail(auth,
4345 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004346 return -1;
4347 }
4348 wpa_hexdump(MSG_MSGDUMP,
4349 "DPP: Initiator Bootstrapping Key Hash",
4350 i_bootstrap, i_bootstrap_len);
4351 if (!auth->peer_bi ||
4352 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
4353 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004354 dpp_auth_fail(auth,
4355 "Initiator Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004356 return -1;
4357 }
Hai Shalom74f70d42019-02-11 14:42:39 -08004358 } else if (auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004359 /* Mutual authentication and peer did not include its
4360 * Bootstrapping Key Hash attribute. */
4361 dpp_auth_fail(auth,
4362 "Missing Initiator Bootstrapping Key Hash attribute");
4363 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004364 }
4365
4366 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
4367 &status_len);
4368 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004369 dpp_auth_fail(auth,
4370 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004371 return -1;
4372 }
4373 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004374 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
4375 status[0] == DPP_STATUS_AUTH_FAILURE)
4376 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
4377 attr_len, wrapped_data,
4378 wrapped_data_len, status[0]);
4379
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004380 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004381 dpp_auth_fail(auth, "Authentication failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004382 return -1;
4383 }
4384
4385 addr[0] = hdr;
4386 len[0] = DPP_HDR_LEN;
4387 addr[1] = attr_start;
4388 len[1] = attr_len;
4389 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4390 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4391 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4392 wrapped_data, wrapped_data_len);
4393 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4394 unwrapped = os_malloc(unwrapped_len);
4395 if (!unwrapped)
4396 return -1;
4397 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4398 wrapped_data, wrapped_data_len,
4399 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004400 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004401 goto fail;
4402 }
4403 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4404 unwrapped, unwrapped_len);
4405
4406 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004407 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004408 goto fail;
4409 }
4410
4411 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
4412 &i_auth_len);
4413 if (!i_auth || i_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004414 dpp_auth_fail(auth,
4415 "Missing or invalid Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004416 goto fail;
4417 }
4418 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
4419 i_auth, i_auth_len);
4420 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4421 if (dpp_gen_i_auth(auth, i_auth2) < 0)
4422 goto fail;
4423 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
4424 i_auth2, i_auth_len);
4425 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004426 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004427 goto fail;
4428 }
4429
4430 bin_clear_free(unwrapped, unwrapped_len);
4431 dpp_auth_success(auth);
4432 return 0;
4433fail:
4434 bin_clear_free(unwrapped, unwrapped_len);
4435 return -1;
4436}
4437
4438
Hai Shalom021b0b52019-04-10 11:17:58 -07004439static int bin_str_eq(const char *val, size_t len, const char *cmp)
4440{
4441 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
4442}
4443
4444
4445struct dpp_configuration * dpp_configuration_alloc(const char *type)
4446{
4447 struct dpp_configuration *conf;
4448 const char *end;
4449 size_t len;
4450
4451 conf = os_zalloc(sizeof(*conf));
4452 if (!conf)
4453 goto fail;
4454
4455 end = os_strchr(type, ' ');
4456 if (end)
4457 len = end - type;
4458 else
4459 len = os_strlen(type);
4460
4461 if (bin_str_eq(type, len, "psk"))
4462 conf->akm = DPP_AKM_PSK;
4463 else if (bin_str_eq(type, len, "sae"))
4464 conf->akm = DPP_AKM_SAE;
4465 else if (bin_str_eq(type, len, "psk-sae") ||
4466 bin_str_eq(type, len, "psk+sae"))
4467 conf->akm = DPP_AKM_PSK_SAE;
4468 else if (bin_str_eq(type, len, "sae-dpp") ||
4469 bin_str_eq(type, len, "dpp+sae"))
4470 conf->akm = DPP_AKM_SAE_DPP;
4471 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
4472 bin_str_eq(type, len, "dpp+psk+sae"))
4473 conf->akm = DPP_AKM_PSK_SAE_DPP;
4474 else if (bin_str_eq(type, len, "dpp"))
4475 conf->akm = DPP_AKM_DPP;
4476 else
4477 goto fail;
4478
4479 return conf;
4480fail:
4481 dpp_configuration_free(conf);
4482 return NULL;
4483}
4484
4485
4486int dpp_akm_psk(enum dpp_akm akm)
4487{
4488 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4489 akm == DPP_AKM_PSK_SAE_DPP;
4490}
4491
4492
4493int dpp_akm_sae(enum dpp_akm akm)
4494{
4495 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
4496 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4497}
4498
4499
4500int dpp_akm_legacy(enum dpp_akm akm)
4501{
4502 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4503 akm == DPP_AKM_SAE;
4504}
4505
4506
4507int dpp_akm_dpp(enum dpp_akm akm)
4508{
4509 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
4510 akm == DPP_AKM_PSK_SAE_DPP;
4511}
4512
4513
4514int dpp_akm_ver2(enum dpp_akm akm)
4515{
4516 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4517}
4518
4519
4520int dpp_configuration_valid(const struct dpp_configuration *conf)
4521{
4522 if (conf->ssid_len == 0)
4523 return 0;
4524 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
4525 return 0;
4526 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
4527 return 0;
4528 return 1;
4529}
4530
4531
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004532void dpp_configuration_free(struct dpp_configuration *conf)
4533{
4534 if (!conf)
4535 return;
4536 str_clear_free(conf->passphrase);
Hai Shalomce48b4a2018-09-05 11:41:35 -07004537 os_free(conf->group_id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004538 bin_clear_free(conf, sizeof(*conf));
4539}
4540
4541
Hai Shalomc3565922019-10-28 11:58:20 -07004542static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
4543 const char *cmd, int idx)
Hai Shalom021b0b52019-04-10 11:17:58 -07004544{
4545 const char *pos, *end;
4546 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
4547 struct dpp_configuration *conf = NULL;
4548
4549 pos = os_strstr(cmd, " conf=sta-");
4550 if (pos) {
4551 conf_sta = dpp_configuration_alloc(pos + 10);
4552 if (!conf_sta)
4553 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07004554 conf_sta->netrole = DPP_NETROLE_STA;
Hai Shalom021b0b52019-04-10 11:17:58 -07004555 conf = conf_sta;
4556 }
4557
4558 pos = os_strstr(cmd, " conf=ap-");
4559 if (pos) {
4560 conf_ap = dpp_configuration_alloc(pos + 9);
4561 if (!conf_ap)
4562 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07004563 conf_ap->netrole = DPP_NETROLE_AP;
Hai Shalom021b0b52019-04-10 11:17:58 -07004564 conf = conf_ap;
4565 }
4566
Hai Shalomfdcde762020-04-02 11:19:20 -07004567 pos = os_strstr(cmd, " conf=configurator");
4568 if (pos)
4569 auth->provision_configurator = 1;
4570
Hai Shalom021b0b52019-04-10 11:17:58 -07004571 if (!conf)
4572 return 0;
4573
4574 pos = os_strstr(cmd, " ssid=");
4575 if (pos) {
4576 pos += 6;
4577 end = os_strchr(pos, ' ');
4578 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
4579 conf->ssid_len /= 2;
4580 if (conf->ssid_len > sizeof(conf->ssid) ||
4581 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
4582 goto fail;
4583 } else {
4584#ifdef CONFIG_TESTING_OPTIONS
4585 /* use a default SSID for legacy testing reasons */
4586 os_memcpy(conf->ssid, "test", 4);
4587 conf->ssid_len = 4;
4588#else /* CONFIG_TESTING_OPTIONS */
4589 goto fail;
4590#endif /* CONFIG_TESTING_OPTIONS */
4591 }
4592
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004593 pos = os_strstr(cmd, " ssid_charset=");
4594 if (pos) {
4595 if (conf_ap) {
4596 wpa_printf(MSG_INFO,
4597 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
4598 goto fail;
4599 }
4600 conf->ssid_charset = atoi(pos + 14);
4601 }
4602
Hai Shalom021b0b52019-04-10 11:17:58 -07004603 pos = os_strstr(cmd, " pass=");
4604 if (pos) {
4605 size_t pass_len;
4606
4607 pos += 6;
4608 end = os_strchr(pos, ' ');
4609 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
4610 pass_len /= 2;
4611 if (pass_len > 63 || pass_len < 8)
4612 goto fail;
4613 conf->passphrase = os_zalloc(pass_len + 1);
4614 if (!conf->passphrase ||
4615 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
4616 goto fail;
4617 }
4618
4619 pos = os_strstr(cmd, " psk=");
4620 if (pos) {
4621 pos += 5;
4622 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
4623 goto fail;
4624 conf->psk_set = 1;
4625 }
4626
4627 pos = os_strstr(cmd, " group_id=");
4628 if (pos) {
4629 size_t group_id_len;
4630
4631 pos += 10;
4632 end = os_strchr(pos, ' ');
4633 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
4634 conf->group_id = os_malloc(group_id_len + 1);
4635 if (!conf->group_id)
4636 goto fail;
4637 os_memcpy(conf->group_id, pos, group_id_len);
4638 conf->group_id[group_id_len] = '\0';
4639 }
4640
4641 pos = os_strstr(cmd, " expiry=");
4642 if (pos) {
4643 long int val;
4644
4645 pos += 8;
4646 val = strtol(pos, NULL, 0);
4647 if (val <= 0)
4648 goto fail;
4649 conf->netaccesskey_expiry = val;
4650 }
4651
4652 if (!dpp_configuration_valid(conf))
4653 goto fail;
4654
Hai Shalomc3565922019-10-28 11:58:20 -07004655 if (idx == 0) {
4656 auth->conf_sta = conf_sta;
4657 auth->conf_ap = conf_ap;
4658 } else if (idx == 1) {
4659 auth->conf2_sta = conf_sta;
4660 auth->conf2_ap = conf_ap;
4661 } else {
4662 goto fail;
4663 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004664 return 0;
4665
4666fail:
4667 dpp_configuration_free(conf_sta);
4668 dpp_configuration_free(conf_ap);
4669 return -1;
4670}
4671
4672
Hai Shalomc3565922019-10-28 11:58:20 -07004673static int dpp_configuration_parse(struct dpp_authentication *auth,
4674 const char *cmd)
4675{
4676 const char *pos;
4677 char *tmp;
4678 size_t len;
4679 int res;
4680
4681 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
4682 if (!pos)
4683 return dpp_configuration_parse_helper(auth, cmd, 0);
4684
4685 len = pos - cmd;
4686 tmp = os_malloc(len + 1);
4687 if (!tmp)
4688 goto fail;
4689 os_memcpy(tmp, cmd, len);
4690 tmp[len] = '\0';
4691 res = dpp_configuration_parse_helper(auth, cmd, 0);
4692 str_clear_free(tmp);
4693 if (res)
4694 goto fail;
4695 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
4696 if (res)
4697 goto fail;
4698 return 0;
4699fail:
4700 dpp_configuration_free(auth->conf_sta);
4701 dpp_configuration_free(auth->conf2_sta);
4702 dpp_configuration_free(auth->conf_ap);
4703 dpp_configuration_free(auth->conf2_ap);
4704 return -1;
4705}
4706
4707
Hai Shalom021b0b52019-04-10 11:17:58 -07004708static struct dpp_configurator *
4709dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
4710{
4711 struct dpp_configurator *conf;
4712
4713 if (!dpp)
4714 return NULL;
4715
4716 dl_list_for_each(conf, &dpp->configurator,
4717 struct dpp_configurator, list) {
4718 if (conf->id == id)
4719 return conf;
4720 }
4721 return NULL;
4722}
4723
4724
Hai Shalomfdcde762020-04-02 11:19:20 -07004725int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
Hai Shalom021b0b52019-04-10 11:17:58 -07004726{
4727 const char *pos;
Hai Shalomfdcde762020-04-02 11:19:20 -07004728 char *tmp = NULL;
4729 int ret = -1;
Hai Shalom021b0b52019-04-10 11:17:58 -07004730
Hai Shalomfdcde762020-04-02 11:19:20 -07004731 if (!cmd || auth->configurator_set)
Hai Shalom021b0b52019-04-10 11:17:58 -07004732 return 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004733 auth->configurator_set = 1;
4734
4735 if (cmd[0] != ' ') {
4736 size_t len;
4737
4738 len = os_strlen(cmd);
4739 tmp = os_malloc(len + 2);
4740 if (!tmp)
4741 goto fail;
4742 tmp[0] = ' ';
4743 os_memcpy(tmp + 1, cmd, len + 1);
4744 cmd = tmp;
4745 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004746
4747 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
4748
4749 pos = os_strstr(cmd, " configurator=");
4750 if (pos) {
4751 pos += 14;
Hai Shalomfdcde762020-04-02 11:19:20 -07004752 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
Hai Shalom021b0b52019-04-10 11:17:58 -07004753 if (!auth->conf) {
4754 wpa_printf(MSG_INFO,
4755 "DPP: Could not find the specified configurator");
Hai Shalomfdcde762020-04-02 11:19:20 -07004756 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07004757 }
4758 }
4759
Hai Shalomc3565922019-10-28 11:58:20 -07004760 pos = os_strstr(cmd, " conn_status=");
4761 if (pos) {
4762 pos += 13;
4763 auth->send_conn_status = atoi(pos);
4764 }
4765
4766 pos = os_strstr(cmd, " akm_use_selector=");
4767 if (pos) {
4768 pos += 18;
4769 auth->akm_use_selector = atoi(pos);
4770 }
4771
Hai Shalom021b0b52019-04-10 11:17:58 -07004772 if (dpp_configuration_parse(auth, cmd) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004773 wpa_msg(auth->msg_ctx, MSG_INFO,
Hai Shalom021b0b52019-04-10 11:17:58 -07004774 "DPP: Failed to set configurator parameters");
Hai Shalomfdcde762020-04-02 11:19:20 -07004775 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07004776 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004777 ret = 0;
4778fail:
4779 os_free(tmp);
4780 return ret;
4781}
4782
4783
4784static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
4785{
4786 while (key) {
4787 struct dpp_asymmetric_key *next = key->next;
4788
4789 EVP_PKEY_free(key->csign);
4790 str_clear_free(key->config_template);
4791 str_clear_free(key->connector_template);
4792 os_free(key);
4793 key = next;
4794 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004795}
4796
4797
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004798void dpp_auth_deinit(struct dpp_authentication *auth)
4799{
Hai Shalomc3565922019-10-28 11:58:20 -07004800 unsigned int i;
4801
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004802 if (!auth)
4803 return;
4804 dpp_configuration_free(auth->conf_ap);
Hai Shalomc3565922019-10-28 11:58:20 -07004805 dpp_configuration_free(auth->conf2_ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004806 dpp_configuration_free(auth->conf_sta);
Hai Shalomc3565922019-10-28 11:58:20 -07004807 dpp_configuration_free(auth->conf2_sta);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004808 EVP_PKEY_free(auth->own_protocol_key);
4809 EVP_PKEY_free(auth->peer_protocol_key);
4810 wpabuf_free(auth->req_msg);
4811 wpabuf_free(auth->resp_msg);
4812 wpabuf_free(auth->conf_req);
Hai Shalomc3565922019-10-28 11:58:20 -07004813 for (i = 0; i < auth->num_conf_obj; i++) {
4814 struct dpp_config_obj *conf = &auth->conf_obj[i];
4815
4816 os_free(conf->connector);
4817 wpabuf_free(conf->c_sign_key);
4818 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004819 dpp_free_asymmetric_key(auth->conf_key_pkg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004820 wpabuf_free(auth->net_access_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004821 dpp_bootstrap_info_free(auth->tmp_own_bi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004822#ifdef CONFIG_TESTING_OPTIONS
4823 os_free(auth->config_obj_override);
4824 os_free(auth->discovery_override);
4825 os_free(auth->groups_override);
4826#endif /* CONFIG_TESTING_OPTIONS */
4827 bin_clear_free(auth, sizeof(*auth));
4828}
4829
4830
4831static struct wpabuf *
4832dpp_build_conf_start(struct dpp_authentication *auth,
4833 struct dpp_configuration *conf, size_t tailroom)
4834{
4835 struct wpabuf *buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004836
4837#ifdef CONFIG_TESTING_OPTIONS
4838 if (auth->discovery_override)
4839 tailroom += os_strlen(auth->discovery_override);
4840#endif /* CONFIG_TESTING_OPTIONS */
4841
4842 buf = wpabuf_alloc(200 + tailroom);
4843 if (!buf)
4844 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004845 json_start_object(buf, NULL);
4846 json_add_string(buf, "wi-fi_tech", "infra");
4847 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004848#ifdef CONFIG_TESTING_OPTIONS
4849 if (auth->discovery_override) {
4850 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
4851 auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004852 wpabuf_put_str(buf, "\"discovery\":");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004853 wpabuf_put_str(buf, auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004854 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004855 return buf;
4856 }
4857#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004858 json_start_object(buf, "discovery");
4859 if (((!conf->ssid_charset || auth->peer_version < 2) &&
4860 json_add_string_escape(buf, "ssid", conf->ssid,
4861 conf->ssid_len) < 0) ||
4862 ((conf->ssid_charset && auth->peer_version >= 2) &&
4863 json_add_base64url(buf, "ssid64", conf->ssid,
4864 conf->ssid_len) < 0)) {
4865 wpabuf_free(buf);
4866 return NULL;
4867 }
4868 if (conf->ssid_charset > 0) {
4869 json_value_sep(buf);
4870 json_add_int(buf, "ssid_charset", conf->ssid_charset);
4871 }
4872 json_end_object(buf);
4873 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004874
4875 return buf;
4876}
4877
4878
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004879static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
4880 const char *kid, const struct dpp_curve_params *curve)
4881{
4882 struct wpabuf *pub;
4883 const u8 *pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004884 int ret = -1;
4885
4886 pub = dpp_get_pubkey_point(key, 0);
4887 if (!pub)
4888 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004889
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004890 json_start_object(buf, name);
4891 json_add_string(buf, "kty", "EC");
4892 json_value_sep(buf);
4893 json_add_string(buf, "crv", curve->jwk_crv);
4894 json_value_sep(buf);
4895 pos = wpabuf_head(pub);
4896 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
4897 goto fail;
4898 json_value_sep(buf);
4899 pos += curve->prime_len;
4900 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
4901 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004902 if (kid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004903 json_value_sep(buf);
4904 json_add_string(buf, "kid", kid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004905 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004906 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004907 ret = 0;
4908fail:
4909 wpabuf_free(pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004910 return ret;
4911}
4912
4913
Hai Shalom021b0b52019-04-10 11:17:58 -07004914static void dpp_build_legacy_cred_params(struct wpabuf *buf,
4915 struct dpp_configuration *conf)
4916{
4917 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004918 json_add_string_escape(buf, "pass", conf->passphrase,
4919 os_strlen(conf->passphrase));
Hai Shalom021b0b52019-04-10 11:17:58 -07004920 } else if (conf->psk_set) {
4921 char psk[2 * sizeof(conf->psk) + 1];
4922
4923 wpa_snprintf_hex(psk, sizeof(psk),
4924 conf->psk, sizeof(conf->psk));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004925 json_add_string(buf, "psk_hex", psk);
4926 forced_memzero(psk, sizeof(psk));
Hai Shalom021b0b52019-04-10 11:17:58 -07004927 }
4928}
4929
4930
Hai Shalomc3565922019-10-28 11:58:20 -07004931static const char * dpp_netrole_str(enum dpp_netrole netrole)
4932{
4933 switch (netrole) {
4934 case DPP_NETROLE_STA:
4935 return "sta";
4936 case DPP_NETROLE_AP:
4937 return "ap";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004938 case DPP_NETROLE_CONFIGURATOR:
4939 return "configurator";
Hai Shalomc3565922019-10-28 11:58:20 -07004940 default:
4941 return "??";
4942 }
4943}
4944
4945
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004946static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07004947dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004948 struct dpp_configuration *conf)
4949{
4950 struct wpabuf *buf = NULL;
4951 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
4952 size_t tailroom;
4953 const struct dpp_curve_params *curve;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004954 struct wpabuf *jws_prot_hdr;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004955 size_t signed1_len, signed2_len, signed3_len;
4956 struct wpabuf *dppcon = NULL;
4957 unsigned char *signature = NULL;
4958 const unsigned char *p;
4959 size_t signature_len;
4960 EVP_MD_CTX *md_ctx = NULL;
4961 ECDSA_SIG *sig = NULL;
4962 char *dot = ".";
4963 const EVP_MD *sign_md;
4964 const BIGNUM *r, *s;
4965 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07004966 int incl_legacy;
4967 enum dpp_akm akm;
Hai Shalomc3565922019-10-28 11:58:20 -07004968 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004969
4970 if (!auth->conf) {
4971 wpa_printf(MSG_INFO,
4972 "DPP: No configurator specified - cannot generate DPP config object");
4973 goto fail;
4974 }
4975 curve = auth->conf->curve;
4976 if (curve->hash_len == SHA256_MAC_LEN) {
4977 sign_md = EVP_sha256();
4978 } else if (curve->hash_len == SHA384_MAC_LEN) {
4979 sign_md = EVP_sha384();
4980 } else if (curve->hash_len == SHA512_MAC_LEN) {
4981 sign_md = EVP_sha512();
4982 } else {
4983 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
4984 goto fail;
4985 }
4986
Hai Shalom021b0b52019-04-10 11:17:58 -07004987 akm = conf->akm;
4988 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
4989 wpa_printf(MSG_DEBUG,
4990 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4991 akm = DPP_AKM_DPP;
4992 }
4993
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004994#ifdef CONFIG_TESTING_OPTIONS
4995 if (auth->groups_override)
4996 extra_len += os_strlen(auth->groups_override);
4997#endif /* CONFIG_TESTING_OPTIONS */
4998
Hai Shalomce48b4a2018-09-05 11:41:35 -07004999 if (conf->group_id)
5000 extra_len += os_strlen(conf->group_id);
5001
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005002 /* Connector (JSON dppCon object) */
5003 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
5004 if (!dppcon)
5005 goto fail;
5006#ifdef CONFIG_TESTING_OPTIONS
5007 if (auth->groups_override) {
5008 wpabuf_put_u8(dppcon, '{');
5009 if (auth->groups_override) {
5010 wpa_printf(MSG_DEBUG,
5011 "DPP: TESTING - groups override: '%s'",
5012 auth->groups_override);
5013 wpabuf_put_str(dppcon, "\"groups\":");
5014 wpabuf_put_str(dppcon, auth->groups_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005015 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005016 }
5017 goto skip_groups;
5018 }
5019#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005020 json_start_object(dppcon, NULL);
5021 json_start_array(dppcon, "groups");
5022 json_start_object(dppcon, NULL);
5023 json_add_string(dppcon, "groupId",
5024 conf->group_id ? conf->group_id : "*");
5025 json_value_sep(dppcon);
5026 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
5027 json_end_object(dppcon);
5028 json_end_array(dppcon);
5029 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005030#ifdef CONFIG_TESTING_OPTIONS
5031skip_groups:
5032#endif /* CONFIG_TESTING_OPTIONS */
5033 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
5034 auth->curve) < 0) {
5035 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
5036 goto fail;
5037 }
5038 if (conf->netaccesskey_expiry) {
5039 struct os_tm tm;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005040 char expiry[30];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005041
5042 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
5043 wpa_printf(MSG_DEBUG,
5044 "DPP: Failed to generate expiry string");
5045 goto fail;
5046 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005047 os_snprintf(expiry, sizeof(expiry),
5048 "%04u-%02u-%02uT%02u:%02u:%02uZ",
5049 tm.year, tm.month, tm.day,
5050 tm.hour, tm.min, tm.sec);
5051 json_value_sep(dppcon);
5052 json_add_string(dppcon, "expiry", expiry);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005053 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005054 json_end_object(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005055 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
5056 (const char *) wpabuf_head(dppcon));
5057
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005058 jws_prot_hdr = wpabuf_alloc(100);
5059 if (!jws_prot_hdr)
5060 goto fail;
5061 json_start_object(jws_prot_hdr, NULL);
5062 json_add_string(jws_prot_hdr, "typ", "dppCon");
5063 json_value_sep(jws_prot_hdr);
5064 json_add_string(jws_prot_hdr, "kid", auth->conf->kid);
5065 json_value_sep(jws_prot_hdr);
5066 json_add_string(jws_prot_hdr, "alg", curve->jws_alg);
5067 json_end_object(jws_prot_hdr);
5068 signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
5069 wpabuf_len(jws_prot_hdr),
5070 &signed1_len);
5071 wpabuf_free(jws_prot_hdr);
5072 signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
5073 &signed2_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005074 if (!signed1 || !signed2)
5075 goto fail;
5076
5077 md_ctx = EVP_MD_CTX_create();
5078 if (!md_ctx)
5079 goto fail;
5080
5081 ERR_clear_error();
5082 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
5083 auth->conf->csign) != 1) {
5084 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
5085 ERR_error_string(ERR_get_error(), NULL));
5086 goto fail;
5087 }
5088 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
5089 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
5090 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
5091 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
5092 ERR_error_string(ERR_get_error(), NULL));
5093 goto fail;
5094 }
5095 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
5096 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
5097 ERR_error_string(ERR_get_error(), NULL));
5098 goto fail;
5099 }
5100 signature = os_malloc(signature_len);
5101 if (!signature)
5102 goto fail;
5103 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
5104 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
5105 ERR_error_string(ERR_get_error(), NULL));
5106 goto fail;
5107 }
5108 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
5109 signature, signature_len);
5110 /* Convert to raw coordinates r,s */
5111 p = signature;
5112 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
5113 if (!sig)
5114 goto fail;
5115 ECDSA_SIG_get0(sig, &r, &s);
5116 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
5117 dpp_bn2bin_pad(s, signature + curve->prime_len,
5118 curve->prime_len) < 0)
5119 goto fail;
5120 signature_len = 2 * curve->prime_len;
5121 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
5122 signature, signature_len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005123 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005124 if (!signed3)
5125 goto fail;
5126
Hai Shalom021b0b52019-04-10 11:17:58 -07005127 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005128 tailroom = 1000;
5129 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
5130 tailroom += signed1_len + signed2_len + signed3_len;
Hai Shalom021b0b52019-04-10 11:17:58 -07005131 if (incl_legacy)
5132 tailroom += 1000;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005133 buf = dpp_build_conf_start(auth, conf, tailroom);
5134 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005135 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005136
Hai Shalomc3565922019-10-28 11:58:20 -07005137 if (auth->akm_use_selector && dpp_akm_ver2(akm))
5138 akm_str = dpp_akm_selector_str(akm);
5139 else
5140 akm_str = dpp_akm_str(akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005141 json_start_object(buf, "cred");
5142 json_add_string(buf, "akm", akm_str);
5143 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07005144 if (incl_legacy) {
5145 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005146 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07005147 }
5148 wpabuf_put_str(buf, "\"signedConnector\":\"");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005149 wpabuf_put_str(buf, signed1);
5150 wpabuf_put_u8(buf, '.');
5151 wpabuf_put_str(buf, signed2);
5152 wpabuf_put_u8(buf, '.');
5153 wpabuf_put_str(buf, signed3);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005154 wpabuf_put_str(buf, "\"");
5155 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005156 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
5157 curve) < 0) {
5158 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
5159 goto fail;
5160 }
5161
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005162 json_end_object(buf);
5163 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005164
5165 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
5166 wpabuf_head(buf), wpabuf_len(buf));
5167
5168out:
5169 EVP_MD_CTX_destroy(md_ctx);
5170 ECDSA_SIG_free(sig);
5171 os_free(signed1);
5172 os_free(signed2);
5173 os_free(signed3);
5174 os_free(signature);
5175 wpabuf_free(dppcon);
5176 return buf;
5177fail:
5178 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
5179 wpabuf_free(buf);
5180 buf = NULL;
5181 goto out;
5182}
5183
5184
5185static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07005186dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005187 struct dpp_configuration *conf)
5188{
5189 struct wpabuf *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07005190 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005191
5192 buf = dpp_build_conf_start(auth, conf, 1000);
5193 if (!buf)
5194 return NULL;
5195
Hai Shalomc3565922019-10-28 11:58:20 -07005196 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
5197 akm_str = dpp_akm_selector_str(conf->akm);
5198 else
5199 akm_str = dpp_akm_str(conf->akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005200 json_start_object(buf, "cred");
5201 json_add_string(buf, "akm", akm_str);
5202 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07005203 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005204 json_end_object(buf);
5205 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005206
5207 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
5208 wpabuf_head(buf), wpabuf_len(buf));
5209
5210 return buf;
5211}
5212
5213
5214static struct wpabuf *
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005215dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
5216 int idx)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005217{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005218 struct dpp_configuration *conf = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005219
5220#ifdef CONFIG_TESTING_OPTIONS
5221 if (auth->config_obj_override) {
Hai Shalomc3565922019-10-28 11:58:20 -07005222 if (idx != 0)
5223 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005224 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
5225 return wpabuf_alloc_copy(auth->config_obj_override,
5226 os_strlen(auth->config_obj_override));
5227 }
5228#endif /* CONFIG_TESTING_OPTIONS */
5229
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005230 if (idx == 0) {
5231 if (netrole == DPP_NETROLE_STA)
5232 conf = auth->conf_sta;
5233 else if (netrole == DPP_NETROLE_AP)
5234 conf = auth->conf_ap;
5235 } else if (idx == 1) {
5236 if (netrole == DPP_NETROLE_STA)
5237 conf = auth->conf2_sta;
5238 else if (netrole == DPP_NETROLE_AP)
5239 conf = auth->conf2_ap;
5240 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005241 if (!conf) {
Hai Shalomc3565922019-10-28 11:58:20 -07005242 if (idx == 0)
5243 wpa_printf(MSG_DEBUG,
5244 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005245 dpp_netrole_str(netrole));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005246 return NULL;
5247 }
5248
Hai Shalomfdcde762020-04-02 11:19:20 -07005249 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
Hai Shalomc3565922019-10-28 11:58:20 -07005250 return dpp_build_conf_obj_dpp(auth, conf);
5251 return dpp_build_conf_obj_legacy(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005252}
5253
5254
Hai Shalomfdcde762020-04-02 11:19:20 -07005255#ifdef CONFIG_DPP2
5256
5257static struct wpabuf * dpp_build_conf_params(void)
5258{
5259 struct wpabuf *buf;
5260 size_t len;
5261 /* TODO: proper template values */
5262 const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
5263 const char *connector_template = NULL;
5264
5265 len = 100 + os_strlen(conf_template);
5266 if (connector_template)
5267 len += os_strlen(connector_template);
5268 buf = wpabuf_alloc(len);
5269 if (!buf)
5270 return NULL;
5271
5272 /*
5273 * DPPConfigurationParameters ::= SEQUENCE {
5274 * configurationTemplate UTF8String,
5275 * connectorTemplate UTF8String OPTIONAL}
5276 */
5277
5278 asn1_put_utf8string(buf, conf_template);
5279 if (connector_template)
5280 asn1_put_utf8string(buf, connector_template);
5281 return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5282}
5283
5284
5285static struct wpabuf * dpp_build_attribute(void)
5286{
5287 struct wpabuf *conf_params, *attr;
5288
5289 /*
5290 * aa-DPPConfigurationParameters ATTRIBUTE ::=
5291 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
5292 *
5293 * Attribute ::= SEQUENCE {
5294 * type OBJECT IDENTIFIER,
5295 * values SET SIZE(1..MAX) OF Type
5296 */
5297 conf_params = dpp_build_conf_params();
5298 conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
5299 ASN1_TAG_SET);
5300 if (!conf_params)
5301 return NULL;
5302
5303 attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
5304 if (!attr) {
5305 wpabuf_clear_free(conf_params);
5306 return NULL;
5307 }
5308
5309 asn1_put_oid(attr, &asn1_dpp_config_params_oid);
5310 wpabuf_put_buf(attr, conf_params);
5311 wpabuf_clear_free(conf_params);
5312
5313 return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5314}
5315
5316
5317static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
5318{
5319 const struct asn1_oid *oid;
5320 struct wpabuf *params, *res;
5321
5322 switch (curve->ike_group) {
5323 case 19:
5324 oid = &asn1_prime256v1_oid;
5325 break;
5326 case 20:
5327 oid = &asn1_secp384r1_oid;
5328 break;
5329 case 21:
5330 oid = &asn1_secp521r1_oid;
5331 break;
5332 case 28:
5333 oid = &asn1_brainpoolP256r1_oid;
5334 break;
5335 case 29:
5336 oid = &asn1_brainpoolP384r1_oid;
5337 break;
5338 case 30:
5339 oid = &asn1_brainpoolP512r1_oid;
5340 break;
5341 default:
5342 return NULL;
5343 }
5344
5345 params = wpabuf_alloc(20);
5346 if (!params)
5347 return NULL;
5348 asn1_put_oid(params, oid); /* namedCurve */
5349
5350 res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
5351 wpabuf_free(params);
5352 return res;
5353}
5354
5355
5356static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
5357{
5358 struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
5359 EC_KEY *eckey;
5360 unsigned char *der = NULL;
5361 int der_len;
5362
5363 eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
5364 if (!eckey)
5365 return NULL;
5366
5367 EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
5368 der_len = i2d_ECPrivateKey(eckey, &der);
5369 if (der_len > 0)
5370 priv_key = wpabuf_alloc_copy(der, der_len);
5371 OPENSSL_free(der);
5372
5373 alg = dpp_build_key_alg(auth->conf->curve);
5374
5375 /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
5376 attr = dpp_build_attribute();
5377 attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
5378 if (!priv_key || !attr || !alg)
5379 goto fail;
5380
5381 /*
5382 * OneAsymmetricKey ::= SEQUENCE {
5383 * version Version,
5384 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
5385 * privateKey PrivateKey,
5386 * attributes [0] Attributes OPTIONAL,
5387 * ...,
5388 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
5389 * ...
5390 * }
5391 */
5392
5393 key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
5394 wpabuf_len(attr));
5395 if (!key)
5396 goto fail;
5397
5398 asn1_put_integer(key, 1); /* version = v2(1) */
5399
5400 /* PrivateKeyAlgorithmIdentifier */
5401 wpabuf_put_buf(key, alg);
5402
5403 /* PrivateKey ::= OCTET STRING */
5404 asn1_put_octet_string(key, priv_key);
5405
5406 /* [0] Attributes OPTIONAL */
5407 asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
5408 wpabuf_put_buf(key, attr);
5409
5410fail:
5411 wpabuf_clear_free(attr);
5412 wpabuf_clear_free(priv_key);
5413 wpabuf_free(alg);
5414
5415 /*
5416 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
5417 *
5418 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
5419 *
5420 * OneAsymmetricKey ::= SEQUENCE
5421 */
5422 return asn1_encaps(asn1_encaps(key,
5423 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
5424 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5425}
5426
5427
5428static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
5429 size_t hash_len)
5430{
5431 struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
5432 const struct asn1_oid *oid;
5433
5434 /*
5435 * PBKDF2-params ::= SEQUENCE {
5436 * salt CHOICE {
5437 * specified OCTET STRING,
5438 * otherSource AlgorithmIdentifier}
5439 * iterationCount INTEGER (1..MAX),
5440 * keyLength INTEGER (1..MAX),
5441 * prf AlgorithmIdentifier}
5442 *
5443 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
5444 * on Configurator signing key length, prf is
5445 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
5446 */
5447
5448 if (hash_len == 32)
5449 oid = &asn1_pbkdf2_hmac_sha256_oid;
5450 else if (hash_len == 48)
5451 oid = &asn1_pbkdf2_hmac_sha384_oid;
5452 else if (hash_len == 64)
5453 oid = &asn1_pbkdf2_hmac_sha512_oid;
5454 else
5455 goto fail;
5456 prf = asn1_build_alg_id(oid, NULL);
5457 if (!prf)
5458 goto fail;
5459 params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
5460 if (!params)
5461 goto fail;
5462 asn1_put_octet_string(params, salt); /* salt.specified */
5463 asn1_put_integer(params, 1000); /* iterationCount */
5464 asn1_put_integer(params, hash_len); /* keyLength */
5465 wpabuf_put_buf(params, prf);
5466 params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5467 if (!params)
5468 goto fail;
5469 buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
5470fail:
5471 wpabuf_free(params);
5472 wpabuf_free(prf);
5473 return buf;
5474}
5475
5476
5477static struct wpabuf *
5478dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
5479 const struct wpabuf *cont_enc_key)
5480{
5481 struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
5482 *key_enc_alg = NULL, *salt;
5483 u8 kek[DPP_MAX_HASH_LEN];
5484 const u8 *key;
5485 size_t key_len;
5486
5487 salt = wpabuf_alloc(64);
5488 if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
5489 goto fail;
5490 wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
5491
5492 /* TODO: For initial testing, use ke as the key. Replace this with a
5493 * new key once that has been defined. */
5494 key = auth->ke;
5495 key_len = auth->curve->hash_len;
5496 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
5497
5498 if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
5499 kek, hash_len)) {
5500 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
5501 goto fail;
5502 }
5503 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
5504 kek, hash_len);
5505
5506 enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
5507 if (!enc_key ||
5508 aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
5509 wpabuf_len(cont_enc_key), 0, NULL, NULL,
5510 wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
5511 goto fail;
5512 wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
5513
5514 /*
5515 * PasswordRecipientInfo ::= SEQUENCE {
5516 * version CMSVersion,
5517 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
5518 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
5519 * encryptedKey EncryptedKey}
5520 *
5521 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
5522 * parameters contains PBKDF2-params SEQUENCE.
5523 */
5524
5525 key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
5526 key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
5527 if (!key_der_alg || !key_enc_alg)
5528 goto fail;
5529 pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
5530 wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
5531 if (!pwri)
5532 goto fail;
5533
5534 /* version = 0 */
5535 asn1_put_integer(pwri, 0);
5536
5537 /* [0] KeyDerivationAlgorithmIdentifier */
5538 asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
5539 wpabuf_len(key_der_alg));
5540 wpabuf_put_buf(pwri, key_der_alg);
5541
5542 /* KeyEncryptionAlgorithmIdentifier */
5543 wpabuf_put_buf(pwri, key_enc_alg);
5544
5545 /* EncryptedKey ::= OCTET STRING */
5546 asn1_put_octet_string(pwri, enc_key);
5547
5548fail:
5549 wpabuf_clear_free(key_der_alg);
5550 wpabuf_free(key_enc_alg);
5551 wpabuf_free(enc_key);
5552 wpabuf_free(salt);
5553 forced_memzero(kek, sizeof(kek));
5554 return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5555}
5556
5557
5558static struct wpabuf *
5559dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
5560 const struct wpabuf *cont_enc_key)
5561{
5562 struct wpabuf *pwri;
5563
5564 /*
5565 * RecipientInfo ::= CHOICE {
5566 * ktri KeyTransRecipientInfo,
5567 * kari [1] KeyAgreeRecipientInfo,
5568 * kekri [2] KEKRecipientInfo,
5569 * pwri [3] PasswordRecipientInfo,
5570 * ori [4] OtherRecipientInfo}
5571 *
5572 * Shall always use the pwri CHOICE.
5573 */
5574
5575 pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
5576 return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
5577}
5578
5579
5580static struct wpabuf *
5581dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
5582 const struct wpabuf *cont_enc_key)
5583{
5584 struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
5585 *enc_alg;
5586 const struct asn1_oid *oid;
5587 size_t enc_cont_len;
5588
5589 /*
5590 * EncryptedContentInfo ::= SEQUENCE {
5591 * contentType ContentType,
5592 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
5593 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
5594 */
5595
5596 if (hash_len == 32)
5597 oid = &asn1_aes_siv_cmac_aead_256_oid;
5598 else if (hash_len == 48)
5599 oid = &asn1_aes_siv_cmac_aead_384_oid;
5600 else if (hash_len == 64)
5601 oid = &asn1_aes_siv_cmac_aead_512_oid;
5602 else
5603 return NULL;
5604
5605 key_pkg = dpp_build_key_pkg(auth);
5606 enc_alg = asn1_build_alg_id(oid, NULL);
5607 if (!key_pkg || !enc_alg)
5608 goto fail;
5609
5610 wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
5611 key_pkg);
5612
5613 enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
5614 enc_cont = wpabuf_alloc(enc_cont_len);
5615 if (!enc_cont ||
5616 aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
5617 wpabuf_head(key_pkg), wpabuf_len(key_pkg),
5618 0, NULL, NULL,
5619 wpabuf_put(enc_cont, enc_cont_len)) < 0)
5620 goto fail;
5621
5622 enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
5623 wpabuf_len(enc_cont));
5624 if (!enc_cont_info)
5625 goto fail;
5626
5627 /* ContentType ::= OBJECT IDENTIFIER */
5628 asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
5629
5630 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
5631 wpabuf_put_buf(enc_cont_info, enc_alg);
5632
5633 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
5634 * EncryptedContent ::= OCTET STRING */
5635 asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
5636 wpabuf_len(enc_cont));
5637 wpabuf_put_buf(enc_cont_info, enc_cont);
5638
5639fail:
5640 wpabuf_clear_free(key_pkg);
5641 wpabuf_free(enc_cont);
5642 wpabuf_free(enc_alg);
5643 return enc_cont_info;
5644}
5645
5646
5647static struct wpabuf * dpp_gen_random(size_t len)
5648{
5649 struct wpabuf *key;
5650
5651 key = wpabuf_alloc(len);
5652 if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
5653 wpabuf_free(key);
5654 key = NULL;
5655 }
5656 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
5657 return key;
5658}
5659
5660
5661static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
5662{
5663 struct wpabuf *env = NULL;
5664 struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
5665 struct wpabuf *cont_enc_key = NULL;
5666 size_t hash_len;
5667
5668 if (!auth->conf) {
5669 wpa_printf(MSG_DEBUG,
5670 "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
5671 return NULL;
5672 }
5673
5674 if (!auth->provision_configurator) {
5675 wpa_printf(MSG_DEBUG,
5676 "DPP: Configurator provisioning not allowed");
5677 return NULL;
5678 }
5679
5680 wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
5681
5682 hash_len = auth->conf->curve->hash_len;
5683 cont_enc_key = dpp_gen_random(hash_len);
5684 if (!cont_enc_key)
5685 goto fail;
5686 recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
5687 enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
5688 if (!recipient_info || !enc_cont_info)
5689 goto fail;
5690
5691 env = wpabuf_alloc(wpabuf_len(recipient_info) +
5692 wpabuf_len(enc_cont_info) +
5693 100);
5694 if (!env)
5695 goto fail;
5696
5697 /*
5698 * DPPEnvelopedData ::= EnvelopedData
5699 *
5700 * EnvelopedData ::= SEQUENCE {
5701 * version CMSVersion,
5702 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
5703 * recipientInfos RecipientInfos,
5704 * encryptedContentInfo EncryptedContentInfo,
5705 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
5706 *
5707 * For DPP, version is 3, both originatorInfo and
5708 * unprotectedAttrs are omitted, and recipientInfos contains a single
5709 * RecipientInfo.
5710 */
5711
5712 /* EnvelopedData.version = 3 */
5713 asn1_put_integer(env, 3);
5714
5715 /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
5716 asn1_put_set(env, recipient_info);
5717
5718 /* EncryptedContentInfo ::= SEQUENCE */
5719 asn1_put_sequence(env, enc_cont_info);
5720
5721 env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5722 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
5723out:
5724 wpabuf_clear_free(cont_enc_key);
5725 wpabuf_clear_free(recipient_info);
5726 wpabuf_free(enc_cont_info);
5727 return env;
5728fail:
5729 wpabuf_free(env);
5730 env = NULL;
5731 goto out;
5732}
5733
5734#endif /* CONFIG_DPP2 */
5735
5736
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005737static struct wpabuf *
5738dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005739 u16 e_nonce_len, enum dpp_netrole netrole)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005740{
Hai Shalomfdcde762020-04-02 11:19:20 -07005741 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005742 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005743 struct wpabuf *clear = NULL, *msg = NULL;
5744 u8 *wrapped;
5745 const u8 *addr[1];
5746 size_t len[1];
5747 enum dpp_status_error status;
5748
Hai Shalomfdcde762020-04-02 11:19:20 -07005749 if (netrole == DPP_NETROLE_CONFIGURATOR) {
5750#ifdef CONFIG_DPP2
5751 env_data = dpp_build_enveloped_data(auth);
5752#endif /* CONFIG_DPP2 */
5753 } else {
5754 conf = dpp_build_conf_obj(auth, netrole, 0);
5755 if (conf) {
5756 wpa_hexdump_ascii(MSG_DEBUG,
5757 "DPP: configurationObject JSON",
5758 wpabuf_head(conf), wpabuf_len(conf));
5759 conf2 = dpp_build_conf_obj(auth, netrole, 1);
5760 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005761 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005762 status = (conf || env_data) ? DPP_STATUS_OK :
5763 DPP_STATUS_CONFIGURE_FAILURE;
Hai Shalom021b0b52019-04-10 11:17:58 -07005764 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005765
Hai Shalomc3565922019-10-28 11:58:20 -07005766 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005767 clear_len = 4 + e_nonce_len;
5768 if (conf)
5769 clear_len += 4 + wpabuf_len(conf);
Hai Shalomc3565922019-10-28 11:58:20 -07005770 if (conf2)
5771 clear_len += 4 + wpabuf_len(conf2);
Hai Shalomfdcde762020-04-02 11:19:20 -07005772 if (env_data)
5773 clear_len += 4 + wpabuf_len(env_data);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005774 if (auth->peer_version >= 2 && auth->send_conn_status &&
5775 netrole == DPP_NETROLE_STA)
Hai Shalomc3565922019-10-28 11:58:20 -07005776 clear_len += 4;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005777 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005778 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
5779#ifdef CONFIG_TESTING_OPTIONS
5780 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
5781 attr_len += 5;
5782#endif /* CONFIG_TESTING_OPTIONS */
5783 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005784 if (!clear || !msg)
5785 goto fail;
5786
Roshan Pius3a1667e2018-07-03 15:17:14 -07005787#ifdef CONFIG_TESTING_OPTIONS
5788 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
5789 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
5790 goto skip_e_nonce;
5791 }
5792 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
5793 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
5794 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5795 wpabuf_put_le16(clear, e_nonce_len);
5796 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
5797 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
5798 goto skip_e_nonce;
5799 }
5800 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
5801 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
5802 goto skip_wrapped_data;
5803 }
5804#endif /* CONFIG_TESTING_OPTIONS */
5805
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005806 /* E-nonce */
5807 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5808 wpabuf_put_le16(clear, e_nonce_len);
5809 wpabuf_put_data(clear, e_nonce, e_nonce_len);
5810
Roshan Pius3a1667e2018-07-03 15:17:14 -07005811#ifdef CONFIG_TESTING_OPTIONS
5812skip_e_nonce:
5813 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
5814 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
5815 goto skip_config_obj;
5816 }
5817#endif /* CONFIG_TESTING_OPTIONS */
5818
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005819 if (conf) {
5820 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5821 wpabuf_put_le16(clear, wpabuf_len(conf));
5822 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005823 }
Hai Shalomc3565922019-10-28 11:58:20 -07005824 if (auth->peer_version >= 2 && conf2) {
5825 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5826 wpabuf_put_le16(clear, wpabuf_len(conf2));
5827 wpabuf_put_buf(clear, conf2);
5828 } else if (conf2) {
5829 wpa_printf(MSG_DEBUG,
5830 "DPP: Second Config Object available, but peer does not support more than one");
5831 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005832 if (env_data) {
5833 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
5834 wpabuf_put_le16(clear, wpabuf_len(env_data));
5835 wpabuf_put_buf(clear, env_data);
5836 }
Hai Shalomc3565922019-10-28 11:58:20 -07005837
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005838 if (auth->peer_version >= 2 && auth->send_conn_status &&
5839 netrole == DPP_NETROLE_STA) {
Hai Shalomc3565922019-10-28 11:58:20 -07005840 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
5841 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
5842 wpabuf_put_le16(clear, 0);
5843 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005844
Roshan Pius3a1667e2018-07-03 15:17:14 -07005845#ifdef CONFIG_TESTING_OPTIONS
5846skip_config_obj:
5847 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
5848 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
5849 goto skip_status;
5850 }
5851 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
5852 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
5853 status = 255;
5854 }
5855#endif /* CONFIG_TESTING_OPTIONS */
5856
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005857 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07005858 dpp_build_attr_status(msg, status);
5859
5860#ifdef CONFIG_TESTING_OPTIONS
5861skip_status:
5862#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005863
5864 addr[0] = wpabuf_head(msg);
5865 len[0] = wpabuf_len(msg);
5866 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5867
5868 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
5869 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5870 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5871
5872 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
5873 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
5874 wpabuf_head(clear), wpabuf_len(clear),
5875 1, addr, len, wrapped) < 0)
5876 goto fail;
5877 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5878 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005879
5880#ifdef CONFIG_TESTING_OPTIONS
5881 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
5882 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
5883 dpp_build_attr_status(msg, DPP_STATUS_OK);
5884 }
5885skip_wrapped_data:
5886#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005887
5888 wpa_hexdump_buf(MSG_DEBUG,
5889 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005890out:
Hai Shalomfdcde762020-04-02 11:19:20 -07005891 wpabuf_clear_free(conf);
5892 wpabuf_clear_free(conf2);
5893 wpabuf_clear_free(env_data);
5894 wpabuf_clear_free(clear);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005895
5896 return msg;
5897fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005898 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005899 msg = NULL;
5900 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005901}
5902
5903
5904struct wpabuf *
5905dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
5906 size_t attr_len)
5907{
5908 const u8 *wrapped_data, *e_nonce, *config_attr;
5909 u16 wrapped_data_len, e_nonce_len, config_attr_len;
5910 u8 *unwrapped = NULL;
5911 size_t unwrapped_len = 0;
5912 struct wpabuf *resp = NULL;
5913 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005914 enum dpp_netrole netrole;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005915
Roshan Pius3a1667e2018-07-03 15:17:14 -07005916#ifdef CONFIG_TESTING_OPTIONS
5917 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
5918 wpa_printf(MSG_INFO,
5919 "DPP: TESTING - stop at Config Request");
5920 return NULL;
5921 }
5922#endif /* CONFIG_TESTING_OPTIONS */
5923
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005924 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005925 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005926 return NULL;
5927 }
5928
5929 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
5930 &wrapped_data_len);
5931 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005932 dpp_auth_fail(auth,
5933 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005934 return NULL;
5935 }
5936
5937 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5938 wrapped_data, wrapped_data_len);
5939 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5940 unwrapped = os_malloc(unwrapped_len);
5941 if (!unwrapped)
5942 return NULL;
5943 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5944 wrapped_data, wrapped_data_len,
5945 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005946 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005947 goto fail;
5948 }
5949 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5950 unwrapped, unwrapped_len);
5951
5952 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005953 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005954 goto fail;
5955 }
5956
5957 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5958 DPP_ATTR_ENROLLEE_NONCE,
5959 &e_nonce_len);
5960 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005961 dpp_auth_fail(auth,
5962 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005963 goto fail;
5964 }
5965 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07005966 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005967
5968 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
5969 DPP_ATTR_CONFIG_ATTR_OBJ,
5970 &config_attr_len);
5971 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005972 dpp_auth_fail(auth,
5973 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005974 goto fail;
5975 }
5976 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
5977 config_attr, config_attr_len);
5978
5979 root = json_parse((const char *) config_attr, config_attr_len);
5980 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005981 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005982 goto fail;
5983 }
5984
5985 token = json_get_member(root, "name");
5986 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005987 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005988 goto fail;
5989 }
5990 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
5991
5992 token = json_get_member(root, "wi-fi_tech");
5993 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005994 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005995 goto fail;
5996 }
5997 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
5998 if (os_strcmp(token->string, "infra") != 0) {
5999 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
6000 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006001 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006002 goto fail;
6003 }
6004
6005 token = json_get_member(root, "netRole");
6006 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006007 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006008 goto fail;
6009 }
6010 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
6011 if (os_strcmp(token->string, "sta") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006012 netrole = DPP_NETROLE_STA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006013 } else if (os_strcmp(token->string, "ap") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006014 netrole = DPP_NETROLE_AP;
6015 } else if (os_strcmp(token->string, "configurator") == 0) {
6016 netrole = DPP_NETROLE_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006017 } else {
6018 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
6019 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006020 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006021 goto fail;
6022 }
6023
Hai Shalomc3565922019-10-28 11:58:20 -07006024 token = json_get_member(root, "mudurl");
6025 if (token && token->type == JSON_STRING)
6026 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
6027
6028 token = json_get_member(root, "bandSupport");
Hai Shalom06768112019-12-04 15:49:43 -08006029 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07006030 if (token && token->type == JSON_ARRAY) {
Hai Shalom06768112019-12-04 15:49:43 -08006031 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07006032 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
6033 token = token->child;
6034 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08006035 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07006036 wpa_printf(MSG_DEBUG,
6037 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08006038 } else {
6039 if (auth->band_list_size < DPP_MAX_CHANNELS) {
6040 auth->band_list[auth->band_list_size++] = token->number;
6041 }
Hai Shalomc3565922019-10-28 11:58:20 -07006042 wpa_printf(MSG_DEBUG,
6043 "DPP: Supported global operating class: %d",
6044 token->number);
Hai Shalom06768112019-12-04 15:49:43 -08006045 }
Hai Shalomc3565922019-10-28 11:58:20 -07006046 token = token->sibling;
6047 }
6048 }
6049
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006050 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006051
6052fail:
6053 json_free(root);
6054 os_free(unwrapped);
6055 return resp;
6056}
6057
6058
6059static struct wpabuf *
6060dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
6061 const u8 *prot_hdr, u16 prot_hdr_len,
6062 const EVP_MD **ret_md)
6063{
6064 struct json_token *root, *token;
6065 struct wpabuf *kid = NULL;
6066
6067 root = json_parse((const char *) prot_hdr, prot_hdr_len);
6068 if (!root) {
6069 wpa_printf(MSG_DEBUG,
6070 "DPP: JSON parsing failed for JWS Protected Header");
6071 goto fail;
6072 }
6073
6074 if (root->type != JSON_OBJECT) {
6075 wpa_printf(MSG_DEBUG,
6076 "DPP: JWS Protected Header root is not an object");
6077 goto fail;
6078 }
6079
6080 token = json_get_member(root, "typ");
6081 if (!token || token->type != JSON_STRING) {
6082 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
6083 goto fail;
6084 }
6085 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
6086 token->string);
6087 if (os_strcmp(token->string, "dppCon") != 0) {
6088 wpa_printf(MSG_DEBUG,
6089 "DPP: Unsupported JWS Protected Header typ=%s",
6090 token->string);
6091 goto fail;
6092 }
6093
6094 token = json_get_member(root, "alg");
6095 if (!token || token->type != JSON_STRING) {
6096 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
6097 goto fail;
6098 }
6099 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
6100 token->string);
6101 if (os_strcmp(token->string, curve->jws_alg) != 0) {
6102 wpa_printf(MSG_DEBUG,
6103 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
6104 token->string, curve->jws_alg);
6105 goto fail;
6106 }
6107 if (os_strcmp(token->string, "ES256") == 0 ||
6108 os_strcmp(token->string, "BS256") == 0)
6109 *ret_md = EVP_sha256();
6110 else if (os_strcmp(token->string, "ES384") == 0 ||
6111 os_strcmp(token->string, "BS384") == 0)
6112 *ret_md = EVP_sha384();
6113 else if (os_strcmp(token->string, "ES512") == 0 ||
6114 os_strcmp(token->string, "BS512") == 0)
6115 *ret_md = EVP_sha512();
6116 else
6117 *ret_md = NULL;
6118 if (!*ret_md) {
6119 wpa_printf(MSG_DEBUG,
6120 "DPP: Unsupported JWS Protected Header alg=%s",
6121 token->string);
6122 goto fail;
6123 }
6124
6125 kid = json_get_member_base64url(root, "kid");
6126 if (!kid) {
6127 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
6128 goto fail;
6129 }
6130 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
6131 kid);
6132
6133fail:
6134 json_free(root);
6135 return kid;
6136}
6137
6138
Hai Shalomc3565922019-10-28 11:58:20 -07006139static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006140 struct json_token *cred)
6141{
6142 struct json_token *pass, *psk_hex;
6143
6144 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
6145
6146 pass = json_get_member(cred, "pass");
6147 psk_hex = json_get_member(cred, "psk_hex");
6148
6149 if (pass && pass->type == JSON_STRING) {
6150 size_t len = os_strlen(pass->string);
6151
6152 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
6153 pass->string, len);
6154 if (len < 8 || len > 63)
6155 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07006156 os_strlcpy(conf->passphrase, pass->string,
6157 sizeof(conf->passphrase));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006158 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07006159 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006160 wpa_printf(MSG_DEBUG,
6161 "DPP: Unexpected psk_hex with akm=sae");
6162 return -1;
6163 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006164 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07006165 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006166 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
6167 return -1;
6168 }
6169 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07006170 conf->psk, PMK_LEN);
6171 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006172 } else {
6173 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
6174 return -1;
6175 }
6176
Hai Shalomc3565922019-10-28 11:58:20 -07006177 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006178 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
6179 return -1;
6180 }
6181
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006182 return 0;
6183}
6184
6185
6186static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
6187 const struct dpp_curve_params **key_curve)
6188{
6189 struct json_token *token;
6190 const struct dpp_curve_params *curve;
6191 struct wpabuf *x = NULL, *y = NULL;
6192 EC_GROUP *group;
6193 EVP_PKEY *pkey = NULL;
6194
6195 token = json_get_member(jwk, "kty");
6196 if (!token || token->type != JSON_STRING) {
6197 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
6198 goto fail;
6199 }
6200 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08006201 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006202 token->string);
6203 goto fail;
6204 }
6205
6206 token = json_get_member(jwk, "crv");
6207 if (!token || token->type != JSON_STRING) {
6208 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
6209 goto fail;
6210 }
6211 curve = dpp_get_curve_jwk_crv(token->string);
6212 if (!curve) {
6213 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
6214 token->string);
6215 goto fail;
6216 }
6217
6218 x = json_get_member_base64url(jwk, "x");
6219 if (!x) {
6220 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
6221 goto fail;
6222 }
6223 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
6224 if (wpabuf_len(x) != curve->prime_len) {
6225 wpa_printf(MSG_DEBUG,
6226 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
6227 (unsigned int) wpabuf_len(x),
6228 (unsigned int) curve->prime_len, curve->name);
6229 goto fail;
6230 }
6231
6232 y = json_get_member_base64url(jwk, "y");
6233 if (!y) {
6234 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
6235 goto fail;
6236 }
6237 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
6238 if (wpabuf_len(y) != curve->prime_len) {
6239 wpa_printf(MSG_DEBUG,
6240 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
6241 (unsigned int) wpabuf_len(y),
6242 (unsigned int) curve->prime_len, curve->name);
6243 goto fail;
6244 }
6245
6246 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6247 if (!group) {
6248 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
6249 goto fail;
6250 }
6251
6252 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
6253 wpabuf_len(x));
Hai Shalom81f62d82019-07-22 12:10:00 -07006254 EC_GROUP_free(group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006255 *key_curve = curve;
6256
6257fail:
6258 wpabuf_free(x);
6259 wpabuf_free(y);
6260
6261 return pkey;
6262}
6263
6264
6265int dpp_key_expired(const char *timestamp, os_time_t *expiry)
6266{
6267 struct os_time now;
6268 unsigned int year, month, day, hour, min, sec;
6269 os_time_t utime;
6270 const char *pos;
6271
6272 /* ISO 8601 date and time:
6273 * <date>T<time>
6274 * YYYY-MM-DDTHH:MM:SSZ
6275 * YYYY-MM-DDTHH:MM:SS+03:00
6276 */
6277 if (os_strlen(timestamp) < 19) {
6278 wpa_printf(MSG_DEBUG,
6279 "DPP: Too short timestamp - assume expired key");
6280 return 1;
6281 }
6282 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
6283 &year, &month, &day, &hour, &min, &sec) != 6) {
6284 wpa_printf(MSG_DEBUG,
6285 "DPP: Failed to parse expiration day - assume expired key");
6286 return 1;
6287 }
6288
6289 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
6290 wpa_printf(MSG_DEBUG,
6291 "DPP: Invalid date/time information - assume expired key");
6292 return 1;
6293 }
6294
6295 pos = timestamp + 19;
6296 if (*pos == 'Z' || *pos == '\0') {
6297 /* In UTC - no need to adjust */
6298 } else if (*pos == '-' || *pos == '+') {
6299 int items;
6300
6301 /* Adjust local time to UTC */
6302 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
6303 if (items < 1) {
6304 wpa_printf(MSG_DEBUG,
6305 "DPP: Invalid time zone designator (%s) - assume expired key",
6306 pos);
6307 return 1;
6308 }
6309 if (*pos == '-')
6310 utime += 3600 * hour;
6311 if (*pos == '+')
6312 utime -= 3600 * hour;
6313 if (items > 1) {
6314 if (*pos == '-')
6315 utime += 60 * min;
6316 if (*pos == '+')
6317 utime -= 60 * min;
6318 }
6319 } else {
6320 wpa_printf(MSG_DEBUG,
6321 "DPP: Invalid time zone designator (%s) - assume expired key",
6322 pos);
6323 return 1;
6324 }
6325 if (expiry)
6326 *expiry = utime;
6327
6328 if (os_get_time(&now) < 0) {
6329 wpa_printf(MSG_DEBUG,
6330 "DPP: Cannot get current time - assume expired key");
6331 return 1;
6332 }
6333
6334 if (now.sec > utime) {
6335 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
6336 utime, now.sec);
6337 return 1;
6338 }
6339
6340 return 0;
6341}
6342
6343
6344static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07006345 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006346 const unsigned char *payload,
6347 u16 payload_len)
6348{
6349 struct json_token *root, *groups, *netkey, *token;
6350 int ret = -1;
6351 EVP_PKEY *key = NULL;
6352 const struct dpp_curve_params *curve;
6353 unsigned int rules = 0;
6354
6355 root = json_parse((const char *) payload, payload_len);
6356 if (!root) {
6357 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
6358 goto fail;
6359 }
6360
6361 groups = json_get_member(root, "groups");
6362 if (!groups || groups->type != JSON_ARRAY) {
6363 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
6364 goto skip_groups;
6365 }
6366 for (token = groups->child; token; token = token->sibling) {
6367 struct json_token *id, *role;
6368
6369 id = json_get_member(token, "groupId");
6370 if (!id || id->type != JSON_STRING) {
6371 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
6372 goto fail;
6373 }
6374
6375 role = json_get_member(token, "netRole");
6376 if (!role || role->type != JSON_STRING) {
6377 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
6378 goto fail;
6379 }
6380 wpa_printf(MSG_DEBUG,
6381 "DPP: connector group: groupId='%s' netRole='%s'",
6382 id->string, role->string);
6383 rules++;
6384 }
6385skip_groups:
6386
6387 if (!rules) {
6388 wpa_printf(MSG_DEBUG,
6389 "DPP: Connector includes no groups");
6390 goto fail;
6391 }
6392
6393 token = json_get_member(root, "expiry");
6394 if (!token || token->type != JSON_STRING) {
6395 wpa_printf(MSG_DEBUG,
6396 "DPP: No expiry string found - connector does not expire");
6397 } else {
6398 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
6399 if (dpp_key_expired(token->string,
6400 &auth->net_access_key_expiry)) {
6401 wpa_printf(MSG_DEBUG,
6402 "DPP: Connector (netAccessKey) has expired");
6403 goto fail;
6404 }
6405 }
6406
6407 netkey = json_get_member(root, "netAccessKey");
6408 if (!netkey || netkey->type != JSON_OBJECT) {
6409 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
6410 goto fail;
6411 }
6412
6413 key = dpp_parse_jwk(netkey, &curve);
6414 if (!key)
6415 goto fail;
6416 dpp_debug_print_key("DPP: Received netAccessKey", key);
6417
6418 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
6419 wpa_printf(MSG_DEBUG,
6420 "DPP: netAccessKey in connector does not match own protocol key");
6421#ifdef CONFIG_TESTING_OPTIONS
6422 if (auth->ignore_netaccesskey_mismatch) {
6423 wpa_printf(MSG_DEBUG,
6424 "DPP: TESTING - skip netAccessKey mismatch");
6425 } else {
6426 goto fail;
6427 }
6428#else /* CONFIG_TESTING_OPTIONS */
6429 goto fail;
6430#endif /* CONFIG_TESTING_OPTIONS */
6431 }
6432
6433 ret = 0;
6434fail:
6435 EVP_PKEY_free(key);
6436 json_free(root);
6437 return ret;
6438}
6439
6440
6441static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
6442{
6443 struct wpabuf *uncomp;
6444 int res;
6445 u8 hash[SHA256_MAC_LEN];
6446 const u8 *addr[1];
6447 size_t len[1];
6448
6449 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
6450 return -1;
6451 uncomp = dpp_get_pubkey_point(pub, 1);
6452 if (!uncomp)
6453 return -1;
6454 addr[0] = wpabuf_head(uncomp);
6455 len[0] = wpabuf_len(uncomp);
6456 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
6457 addr[0], len[0]);
6458 res = sha256_vector(1, addr, len, hash);
6459 wpabuf_free(uncomp);
6460 if (res < 0)
6461 return -1;
6462 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
6463 wpa_printf(MSG_DEBUG,
6464 "DPP: Received hash value does not match calculated public key hash value");
6465 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
6466 hash, SHA256_MAC_LEN);
6467 return -1;
6468 }
6469 return 0;
6470}
6471
6472
Hai Shalomc3565922019-10-28 11:58:20 -07006473static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006474{
6475 unsigned char *der = NULL;
6476 int der_len;
6477
6478 der_len = i2d_PUBKEY(csign, &der);
6479 if (der_len <= 0)
6480 return;
Hai Shalomc3565922019-10-28 11:58:20 -07006481 wpabuf_free(conf->c_sign_key);
6482 conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006483 OPENSSL_free(der);
6484}
6485
6486
Hai Shalomc3565922019-10-28 11:58:20 -07006487static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
6488 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006489{
6490 unsigned char *der = NULL;
6491 int der_len;
6492 EC_KEY *eckey;
6493
6494 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
6495 if (!eckey)
6496 return;
6497
6498 der_len = i2d_ECPrivateKey(eckey, &der);
6499 if (der_len <= 0) {
6500 EC_KEY_free(eckey);
6501 return;
6502 }
6503 wpabuf_free(auth->net_access_key);
6504 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
6505 OPENSSL_free(der);
6506 EC_KEY_free(eckey);
6507}
6508
6509
6510struct dpp_signed_connector_info {
6511 unsigned char *payload;
6512 size_t payload_len;
6513};
6514
Roshan Pius3a1667e2018-07-03 15:17:14 -07006515static enum dpp_status_error
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006516dpp_process_signed_connector(struct dpp_signed_connector_info *info,
6517 EVP_PKEY *csign_pub, const char *connector)
6518{
Roshan Pius3a1667e2018-07-03 15:17:14 -07006519 enum dpp_status_error ret = 255;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006520 const char *pos, *end, *signed_start, *signed_end;
6521 struct wpabuf *kid = NULL;
6522 unsigned char *prot_hdr = NULL, *signature = NULL;
6523 size_t prot_hdr_len = 0, signature_len = 0;
6524 const EVP_MD *sign_md = NULL;
6525 unsigned char *der = NULL;
6526 int der_len;
6527 int res;
6528 EVP_MD_CTX *md_ctx = NULL;
6529 ECDSA_SIG *sig = NULL;
6530 BIGNUM *r = NULL, *s = NULL;
6531 const struct dpp_curve_params *curve;
6532 EC_KEY *eckey;
6533 const EC_GROUP *group;
6534 int nid;
6535
6536 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
6537 if (!eckey)
6538 goto fail;
6539 group = EC_KEY_get0_group(eckey);
6540 if (!group)
6541 goto fail;
6542 nid = EC_GROUP_get_curve_name(group);
6543 curve = dpp_get_curve_nid(nid);
6544 if (!curve)
6545 goto fail;
6546 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
6547 os_memset(info, 0, sizeof(*info));
6548
6549 signed_start = pos = connector;
6550 end = os_strchr(pos, '.');
6551 if (!end) {
6552 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006553 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006554 goto fail;
6555 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006556 prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006557 if (!prot_hdr) {
6558 wpa_printf(MSG_DEBUG,
6559 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006560 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006561 goto fail;
6562 }
6563 wpa_hexdump_ascii(MSG_DEBUG,
6564 "DPP: signedConnector - JWS Protected Header",
6565 prot_hdr, prot_hdr_len);
6566 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006567 if (!kid) {
6568 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006569 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006570 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006571 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
6572 wpa_printf(MSG_DEBUG,
6573 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
6574 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006575 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006576 goto fail;
6577 }
6578
6579 pos = end + 1;
6580 end = os_strchr(pos, '.');
6581 if (!end) {
6582 wpa_printf(MSG_DEBUG,
6583 "DPP: Missing dot(2) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006584 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006585 goto fail;
6586 }
6587 signed_end = end - 1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006588 info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006589 if (!info->payload) {
6590 wpa_printf(MSG_DEBUG,
6591 "DPP: Failed to base64url decode signedConnector JWS Payload");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006592 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006593 goto fail;
6594 }
6595 wpa_hexdump_ascii(MSG_DEBUG,
6596 "DPP: signedConnector - JWS Payload",
6597 info->payload, info->payload_len);
6598 pos = end + 1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006599 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006600 if (!signature) {
6601 wpa_printf(MSG_DEBUG,
6602 "DPP: Failed to base64url decode signedConnector signature");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006603 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006604 goto fail;
6605 }
6606 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
6607 signature, signature_len);
6608
Roshan Pius3a1667e2018-07-03 15:17:14 -07006609 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
6610 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006611 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006612 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006613
6614 if (signature_len & 0x01) {
6615 wpa_printf(MSG_DEBUG,
6616 "DPP: Unexpected signedConnector signature length (%d)",
6617 (int) signature_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006618 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006619 goto fail;
6620 }
6621
6622 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
6623 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
6624 r = BN_bin2bn(signature, signature_len / 2, NULL);
6625 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
6626 sig = ECDSA_SIG_new();
6627 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
6628 goto fail;
6629 r = NULL;
6630 s = NULL;
6631
6632 der_len = i2d_ECDSA_SIG(sig, &der);
6633 if (der_len <= 0) {
6634 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
6635 goto fail;
6636 }
6637 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
6638 md_ctx = EVP_MD_CTX_create();
6639 if (!md_ctx)
6640 goto fail;
6641
6642 ERR_clear_error();
6643 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
6644 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
6645 ERR_error_string(ERR_get_error(), NULL));
6646 goto fail;
6647 }
6648 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
6649 signed_end - signed_start + 1) != 1) {
6650 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
6651 ERR_error_string(ERR_get_error(), NULL));
6652 goto fail;
6653 }
6654 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
6655 if (res != 1) {
6656 wpa_printf(MSG_DEBUG,
6657 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
6658 res, ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07006659 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006660 goto fail;
6661 }
6662
Roshan Pius3a1667e2018-07-03 15:17:14 -07006663 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006664fail:
6665 EC_KEY_free(eckey);
6666 EVP_MD_CTX_destroy(md_ctx);
6667 os_free(prot_hdr);
6668 wpabuf_free(kid);
6669 os_free(signature);
6670 ECDSA_SIG_free(sig);
6671 BN_free(r);
6672 BN_free(s);
6673 OPENSSL_free(der);
6674 return ret;
6675}
6676
6677
6678static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07006679 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006680 struct json_token *cred)
6681{
6682 struct dpp_signed_connector_info info;
6683 struct json_token *token, *csign;
6684 int ret = -1;
6685 EVP_PKEY *csign_pub = NULL;
6686 const struct dpp_curve_params *key_curve = NULL;
6687 const char *signed_connector;
6688
6689 os_memset(&info, 0, sizeof(info));
6690
Hai Shalomc3565922019-10-28 11:58:20 -07006691 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07006692 wpa_printf(MSG_DEBUG,
6693 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07006694 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07006695 return -1;
6696 }
6697
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006698 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
6699
6700 csign = json_get_member(cred, "csign");
6701 if (!csign || csign->type != JSON_OBJECT) {
6702 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
6703 goto fail;
6704 }
6705
6706 csign_pub = dpp_parse_jwk(csign, &key_curve);
6707 if (!csign_pub) {
6708 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
6709 goto fail;
6710 }
6711 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
6712
6713 token = json_get_member(cred, "signedConnector");
6714 if (!token || token->type != JSON_STRING) {
6715 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
6716 goto fail;
6717 }
6718 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
6719 token->string, os_strlen(token->string));
6720 signed_connector = token->string;
6721
6722 if (os_strchr(signed_connector, '"') ||
6723 os_strchr(signed_connector, '\n')) {
6724 wpa_printf(MSG_DEBUG,
6725 "DPP: Unexpected character in signedConnector");
6726 goto fail;
6727 }
6728
6729 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006730 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006731 goto fail;
6732
Hai Shalomc3565922019-10-28 11:58:20 -07006733 if (dpp_parse_connector(auth, conf,
6734 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006735 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
6736 goto fail;
6737 }
6738
Hai Shalomc3565922019-10-28 11:58:20 -07006739 os_free(conf->connector);
6740 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006741
Hai Shalomc3565922019-10-28 11:58:20 -07006742 dpp_copy_csign(conf, csign_pub);
Hai Shalomb755a2a2020-04-23 21:49:02 -07006743 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
Hai Shalomfdcde762020-04-02 11:19:20 -07006744 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006745
6746 ret = 0;
6747fail:
6748 EVP_PKEY_free(csign_pub);
6749 os_free(info.payload);
6750 return ret;
6751}
6752
6753
Roshan Pius3a1667e2018-07-03 15:17:14 -07006754const char * dpp_akm_str(enum dpp_akm akm)
6755{
6756 switch (akm) {
6757 case DPP_AKM_DPP:
6758 return "dpp";
6759 case DPP_AKM_PSK:
6760 return "psk";
6761 case DPP_AKM_SAE:
6762 return "sae";
6763 case DPP_AKM_PSK_SAE:
6764 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07006765 case DPP_AKM_SAE_DPP:
6766 return "dpp+sae";
6767 case DPP_AKM_PSK_SAE_DPP:
6768 return "dpp+psk+sae";
Roshan Pius3a1667e2018-07-03 15:17:14 -07006769 default:
6770 return "??";
6771 }
6772}
6773
6774
Hai Shalomc3565922019-10-28 11:58:20 -07006775const char * dpp_akm_selector_str(enum dpp_akm akm)
6776{
6777 switch (akm) {
6778 case DPP_AKM_DPP:
6779 return "506F9A02";
6780 case DPP_AKM_PSK:
6781 return "000FAC02+000FAC06";
6782 case DPP_AKM_SAE:
6783 return "000FAC08";
6784 case DPP_AKM_PSK_SAE:
6785 return "000FAC02+000FAC06+000FAC08";
6786 case DPP_AKM_SAE_DPP:
6787 return "506F9A02+000FAC08";
6788 case DPP_AKM_PSK_SAE_DPP:
6789 return "506F9A02+000FAC08+000FAC02+000FAC06";
6790 default:
6791 return "??";
6792 }
6793}
6794
6795
Roshan Pius3a1667e2018-07-03 15:17:14 -07006796static enum dpp_akm dpp_akm_from_str(const char *akm)
6797{
Hai Shalomc3565922019-10-28 11:58:20 -07006798 const char *pos;
6799 int dpp = 0, psk = 0, sae = 0;
6800
Roshan Pius3a1667e2018-07-03 15:17:14 -07006801 if (os_strcmp(akm, "psk") == 0)
6802 return DPP_AKM_PSK;
6803 if (os_strcmp(akm, "sae") == 0)
6804 return DPP_AKM_SAE;
6805 if (os_strcmp(akm, "psk+sae") == 0)
6806 return DPP_AKM_PSK_SAE;
6807 if (os_strcmp(akm, "dpp") == 0)
6808 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07006809 if (os_strcmp(akm, "dpp+sae") == 0)
6810 return DPP_AKM_SAE_DPP;
6811 if (os_strcmp(akm, "dpp+psk+sae") == 0)
6812 return DPP_AKM_PSK_SAE_DPP;
Hai Shalomc3565922019-10-28 11:58:20 -07006813
6814 pos = akm;
6815 while (*pos) {
6816 if (os_strlen(pos) < 8)
6817 break;
6818 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
6819 dpp = 1;
6820 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
6821 psk = 1;
6822 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
6823 psk = 1;
6824 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
6825 sae = 1;
6826 pos += 8;
6827 if (*pos != '+')
6828 break;
6829 pos++;
6830 }
6831
6832 if (dpp && psk && sae)
6833 return DPP_AKM_PSK_SAE_DPP;
6834 if (dpp && sae)
6835 return DPP_AKM_SAE_DPP;
6836 if (dpp)
6837 return DPP_AKM_DPP;
6838 if (psk && sae)
6839 return DPP_AKM_PSK_SAE;
6840 if (sae)
6841 return DPP_AKM_SAE;
6842 if (psk)
6843 return DPP_AKM_PSK;
6844
Roshan Pius3a1667e2018-07-03 15:17:14 -07006845 return DPP_AKM_UNKNOWN;
6846}
6847
6848
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006849static int dpp_parse_conf_obj(struct dpp_authentication *auth,
6850 const u8 *conf_obj, u16 conf_obj_len)
6851{
6852 int ret = -1;
6853 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07006854 struct dpp_config_obj *conf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006855 struct wpabuf *ssid64 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07006856 int legacy;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006857
6858 root = json_parse((const char *) conf_obj, conf_obj_len);
6859 if (!root)
6860 return -1;
6861 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006862 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006863 goto fail;
6864 }
6865
6866 token = json_get_member(root, "wi-fi_tech");
6867 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006868 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006869 goto fail;
6870 }
6871 if (os_strcmp(token->string, "infra") != 0) {
6872 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
6873 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006874 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006875 goto fail;
6876 }
6877
6878 discovery = json_get_member(root, "discovery");
6879 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006880 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006881 goto fail;
6882 }
6883
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006884 ssid64 = json_get_member_base64url(discovery, "ssid64");
6885 if (ssid64) {
6886 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
6887 wpabuf_head(ssid64), wpabuf_len(ssid64));
6888 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
6889 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
6890 goto fail;
6891 }
6892 } else {
6893 token = json_get_member(discovery, "ssid");
6894 if (!token || token->type != JSON_STRING) {
6895 dpp_auth_fail(auth,
6896 "No discovery::ssid string value found");
6897 goto fail;
6898 }
6899 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
6900 token->string, os_strlen(token->string));
6901 if (os_strlen(token->string) > SSID_MAX_LEN) {
6902 dpp_auth_fail(auth,
6903 "Too long discovery::ssid string value");
6904 goto fail;
6905 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006906 }
Hai Shalomc3565922019-10-28 11:58:20 -07006907
6908 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
6909 wpa_printf(MSG_DEBUG,
6910 "DPP: No room for this many Config Objects - ignore this one");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006911 ret = 0;
6912 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07006913 }
6914 conf = &auth->conf_obj[auth->num_conf_obj++];
6915
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006916 if (ssid64) {
6917 conf->ssid_len = wpabuf_len(ssid64);
6918 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
6919 } else {
6920 conf->ssid_len = os_strlen(token->string);
6921 os_memcpy(conf->ssid, token->string, conf->ssid_len);
6922 }
6923
6924 token = json_get_member(discovery, "ssid_charset");
6925 if (token && token->type == JSON_NUMBER) {
6926 conf->ssid_charset = token->number;
6927 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
6928 conf->ssid_charset);
6929 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006930
6931 cred = json_get_member(root, "cred");
6932 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006933 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006934 goto fail;
6935 }
6936
6937 token = json_get_member(cred, "akm");
6938 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006939 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006940 goto fail;
6941 }
Hai Shalomc3565922019-10-28 11:58:20 -07006942 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006943
Hai Shalomfdcde762020-04-02 11:19:20 -07006944 legacy = dpp_akm_legacy(conf->akm);
6945 if (legacy && auth->peer_version >= 2) {
6946 struct json_token *csign, *s_conn;
6947
6948 csign = json_get_member(cred, "csign");
6949 s_conn = json_get_member(cred, "signedConnector");
6950 if (csign && csign->type == JSON_OBJECT &&
6951 s_conn && s_conn->type == JSON_STRING)
6952 legacy = 0;
6953 }
6954 if (legacy) {
Hai Shalomc3565922019-10-28 11:58:20 -07006955 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006956 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07006957 } else if (dpp_akm_dpp(conf->akm) ||
6958 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
Hai Shalomc3565922019-10-28 11:58:20 -07006959 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006960 goto fail;
6961 } else {
6962 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
6963 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006964 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006965 goto fail;
6966 }
6967
6968 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
6969 ret = 0;
6970fail:
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006971 wpabuf_free(ssid64);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006972 json_free(root);
6973 return ret;
6974}
6975
6976
Hai Shalomfdcde762020-04-02 11:19:20 -07006977#ifdef CONFIG_DPP2
6978
6979struct dpp_enveloped_data {
6980 const u8 *enc_cont;
6981 size_t enc_cont_len;
6982 const u8 *enc_key;
6983 size_t enc_key_len;
6984 const u8 *salt;
6985 size_t pbkdf2_key_len;
6986 size_t prf_hash_len;
6987};
6988
6989
6990static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
6991 struct dpp_enveloped_data *data)
6992{
6993 struct asn1_hdr hdr;
6994 const u8 *end = pos + len;
6995 const u8 *next, *e_end;
6996 struct asn1_oid oid;
6997 int val;
6998 const u8 *params;
6999 size_t params_len;
7000
7001 wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
7002
7003 /*
7004 * RecipientInfo ::= CHOICE {
7005 * ktri KeyTransRecipientInfo,
7006 * kari [1] KeyAgreeRecipientInfo,
7007 * kekri [2] KEKRecipientInfo,
7008 * pwri [3] PasswordRecipientInfo,
7009 * ori [4] OtherRecipientInfo}
7010 *
7011 * Shall always use the pwri CHOICE.
7012 */
7013
7014 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7015 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
7016 wpa_printf(MSG_DEBUG,
7017 "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
7018 hdr.class, hdr.tag);
7019 return -1;
7020 }
7021 wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
7022 hdr.payload, hdr.length);
7023 pos = hdr.payload;
7024 end = pos + hdr.length;
7025
7026 /*
7027 * PasswordRecipientInfo ::= SEQUENCE {
7028 * version CMSVersion,
7029 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
7030 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
7031 * encryptedKey EncryptedKey}
7032 *
7033 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
7034 * parameters contains PBKDF2-params SEQUENCE.
7035 */
7036
7037 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
7038 return -1;
7039 pos = hdr.payload;
7040
7041 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7042 return -1;
7043 if (val != 0) {
7044 wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
7045 return -1;
7046 }
7047
7048 wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
7049 pos, end - pos);
7050
7051 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7052 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7053 wpa_printf(MSG_DEBUG,
7054 "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
7055 hdr.class, hdr.tag);
7056 return -1;
7057 }
7058 pos = hdr.payload;
7059 e_end = pos + hdr.length;
7060
7061 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
7062 if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
7063 &next) < 0)
7064 return -1;
7065 if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
7066 char buf[80];
7067
7068 asn1_oid_to_str(&oid, buf, sizeof(buf));
7069 wpa_printf(MSG_DEBUG,
7070 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
7071 buf);
7072 return -1;
7073 }
7074
7075 /*
7076 * PBKDF2-params ::= SEQUENCE {
7077 * salt CHOICE {
7078 * specified OCTET STRING,
7079 * otherSource AlgorithmIdentifier}
7080 * iterationCount INTEGER (1..MAX),
7081 * keyLength INTEGER (1..MAX),
7082 * prf AlgorithmIdentifier}
7083 *
7084 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
7085 * on Configurator signing key length, prf is
7086 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
7087 */
7088 if (!params ||
7089 asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
7090 return -1;
7091 pos = hdr.payload;
7092
7093 if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
7094 hdr.class != ASN1_CLASS_UNIVERSAL ||
7095 hdr.tag != ASN1_TAG_OCTETSTRING) {
7096 wpa_printf(MSG_DEBUG,
7097 "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
7098 hdr.class, hdr.tag);
7099 return -1;
7100 }
7101 wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
7102 hdr.payload, hdr.length);
7103 if (hdr.length != 64) {
7104 wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
7105 hdr.length);
7106 return -1;
7107 }
7108 data->salt = hdr.payload;
7109 pos = hdr.payload + hdr.length;
7110
7111 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
7112 return -1;
7113 if (val != 1000) {
7114 wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
7115 return -1;
7116 }
7117
7118 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
7119 return -1;
7120 if (val != 32 && val != 48 && val != 64) {
7121 wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
7122 return -1;
7123 }
7124 data->pbkdf2_key_len = val;
7125
7126 if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
7127 asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
7128 wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
7129 return -1;
7130 }
7131 if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
7132 data->prf_hash_len = 32;
7133 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
7134 data->prf_hash_len = 48;
7135 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
7136 data->prf_hash_len = 64;
7137 } else {
7138 char buf[80];
7139
7140 asn1_oid_to_str(&oid, buf, sizeof(buf));
7141 wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
7142 buf);
7143 return -1;
7144 }
7145
7146 pos = next;
7147
7148 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
7149 *
7150 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
7151 *
7152 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
7153 * id-alg-AES-SIV-CMAC-aed-512. */
7154 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
7155 return -1;
7156 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
7157 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
7158 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
7159 char buf[80];
7160
7161 asn1_oid_to_str(&oid, buf, sizeof(buf));
7162 wpa_printf(MSG_DEBUG,
7163 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
7164 buf);
7165 return -1;
7166 }
7167
7168 /*
7169 * encryptedKey EncryptedKey
7170 *
7171 * EncryptedKey ::= OCTET STRING
7172 */
7173 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7174 hdr.class != ASN1_CLASS_UNIVERSAL ||
7175 hdr.tag != ASN1_TAG_OCTETSTRING) {
7176 wpa_printf(MSG_DEBUG,
7177 "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
7178 hdr.class, hdr.tag);
7179 return -1;
7180 }
7181 wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
7182 hdr.payload, hdr.length);
7183 data->enc_key = hdr.payload;
7184 data->enc_key_len = hdr.length;
7185
7186 return 0;
7187}
7188
7189
7190static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
7191 struct dpp_enveloped_data *data)
7192{
7193 struct asn1_hdr hdr;
7194 struct asn1_oid oid;
7195
7196 /*
7197 * EncryptedContentInfo ::= SEQUENCE {
7198 * contentType ContentType,
7199 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
7200 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
7201 */
7202 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7203 return -1;
7204 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
7205 hdr.payload, hdr.length);
7206 if (pos < end) {
7207 wpa_hexdump(MSG_DEBUG,
7208 "DPP: Unexpected extra data after EncryptedContentInfo",
7209 pos, end - pos);
7210 return -1;
7211 }
7212
7213 end = pos;
7214 pos = hdr.payload;
7215
7216 /* ContentType ::= OBJECT IDENTIFIER */
7217 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
7218 wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
7219 return -1;
7220 }
7221 if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
7222 char buf[80];
7223
7224 asn1_oid_to_str(&oid, buf, sizeof(buf));
7225 wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
7226 return -1;
7227 }
7228
7229 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
7230 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
7231 return -1;
7232 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
7233 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
7234 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
7235 char buf[80];
7236
7237 asn1_oid_to_str(&oid, buf, sizeof(buf));
7238 wpa_printf(MSG_DEBUG,
7239 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
7240 buf);
7241 return -1;
7242 }
7243 /* ignore optional parameters */
7244
7245 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
7246 * EncryptedContent ::= OCTET STRING */
7247 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7248 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7249 wpa_printf(MSG_DEBUG,
7250 "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
7251 hdr.class, hdr.tag);
7252 return -1;
7253 }
7254 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
7255 hdr.payload, hdr.length);
7256 data->enc_cont = hdr.payload;
7257 data->enc_cont_len = hdr.length;
7258 return 0;
7259}
7260
7261
7262static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
7263 struct dpp_enveloped_data *data)
7264{
7265 struct asn1_hdr hdr;
7266 const u8 *pos, *end;
7267 int val;
7268
7269 os_memset(data, 0, sizeof(*data));
7270
7271 /*
7272 * DPPEnvelopedData ::= EnvelopedData
7273 *
7274 * EnvelopedData ::= SEQUENCE {
7275 * version CMSVersion,
7276 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
7277 * recipientInfos RecipientInfos,
7278 * encryptedContentInfo EncryptedContentInfo,
7279 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
7280 *
7281 * CMSVersion ::= INTEGER
7282 *
7283 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
7284 *
7285 * For DPP, version is 3, both originatorInfo and
7286 * unprotectedAttrs are omitted, and recipientInfos contains a single
7287 * RecipientInfo.
7288 */
7289 if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
7290 return -1;
7291 pos = hdr.payload;
7292 if (end < env_data + env_data_len) {
7293 wpa_hexdump(MSG_DEBUG,
7294 "DPP: Unexpected extra data after DPPEnvelopedData",
7295 end, env_data + env_data_len - end);
7296 return -1;
7297 }
7298
7299 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7300 return -1;
7301 if (val != 3) {
7302 wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
7303 return -1;
7304 }
7305
7306 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7307 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7308 wpa_printf(MSG_DEBUG,
7309 "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
7310 hdr.class, hdr.tag);
7311 return -1;
7312 }
7313
7314 if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
7315 return -1;
7316 return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
7317 data);
7318}
7319
7320
7321static struct dpp_asymmetric_key *
7322dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
7323{
7324 struct asn1_hdr hdr;
7325 const u8 *pos = buf, *end = buf + len, *next;
7326 int val;
7327 const u8 *params;
7328 size_t params_len;
7329 struct asn1_oid oid;
7330 char txt[80];
7331 struct dpp_asymmetric_key *key;
7332 EC_KEY *eckey;
7333
7334 wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
7335
7336 key = os_zalloc(sizeof(*key));
7337 if (!key)
7338 return NULL;
7339
7340 /*
7341 * OneAsymmetricKey ::= SEQUENCE {
7342 * version Version,
7343 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
7344 * privateKey PrivateKey,
7345 * attributes [0] Attributes OPTIONAL,
7346 * ...,
7347 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
7348 * ...
7349 * }
7350 */
7351 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
7352 goto fail;
7353 pos = hdr.payload;
7354
7355 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
7356 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7357 goto fail;
7358 if (val != 1) {
7359 wpa_printf(MSG_DEBUG,
7360 "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
7361 val);
7362 goto fail;
7363 }
7364
7365 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
7366 if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
7367 &pos) < 0)
7368 goto fail;
7369 if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
7370 asn1_oid_to_str(&oid, txt, sizeof(txt));
7371 wpa_printf(MSG_DEBUG,
7372 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
7373 txt);
7374 goto fail;
7375 }
7376 wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
7377 params, params_len);
7378 /*
7379 * ECParameters ::= CHOICE {
7380 * namedCurve OBJECT IDENTIFIER
7381 * -- implicitCurve NULL
7382 * -- specifiedCurve SpecifiedECDomain}
7383 */
7384 if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
7385 wpa_printf(MSG_DEBUG,
7386 "DPP: Could not parse ECParameters.namedCurve");
7387 goto fail;
7388 }
7389 asn1_oid_to_str(&oid, txt, sizeof(txt));
7390 wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
7391 /* Assume the curve is identified within ECPrivateKey, so that this
7392 * separate indication is not really needed. */
7393
7394 /*
7395 * PrivateKey ::= OCTET STRING
7396 * (Contains DER encoding of ECPrivateKey)
7397 */
7398 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7399 hdr.class != ASN1_CLASS_UNIVERSAL ||
7400 hdr.tag != ASN1_TAG_OCTETSTRING) {
7401 wpa_printf(MSG_DEBUG,
7402 "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
7403 hdr.class, hdr.tag);
7404 goto fail;
7405 }
7406 wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
7407 hdr.payload, hdr.length);
7408 pos = hdr.payload + hdr.length;
7409 eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
7410 if (!eckey) {
7411 wpa_printf(MSG_INFO,
7412 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
7413 ERR_error_string(ERR_get_error(), NULL));
7414 goto fail;
7415 }
7416 key->csign = EVP_PKEY_new();
7417 if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
7418 EC_KEY_free(eckey);
7419 goto fail;
7420 }
7421 if (wpa_debug_show_keys)
7422 dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
7423
7424 /*
7425 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
7426 *
7427 * Exactly one instance of type Attribute in OneAsymmetricKey.
7428 */
7429 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7430 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7431 wpa_printf(MSG_DEBUG,
7432 "DPP: Expected [0] Attributes - found class %d tag 0x%x",
7433 hdr.class, hdr.tag);
7434 goto fail;
7435 }
7436 wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
7437 hdr.payload, hdr.length);
7438 if (hdr.payload + hdr.length < end) {
7439 wpa_hexdump_key(MSG_MSGDUMP,
7440 "DPP: Ignore additional data at the end of OneAsymmetricKey",
7441 hdr.payload + hdr.length,
7442 end - (hdr.payload + hdr.length));
7443 }
7444 pos = hdr.payload;
7445 end = hdr.payload + hdr.length;
7446
7447 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7448 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7449 wpa_printf(MSG_DEBUG,
7450 "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
7451 hdr.class, hdr.tag);
7452 goto fail;
7453 }
7454 if (hdr.payload + hdr.length < end) {
7455 wpa_hexdump_key(MSG_MSGDUMP,
7456 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
7457 hdr.payload + hdr.length,
7458 end - (hdr.payload + hdr.length));
7459 }
7460 pos = hdr.payload;
7461 end = hdr.payload + hdr.length;
7462
7463 /*
7464 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
7465 * aa-DPPConfigurationParameters,
7466 * ... -- For local profiles
7467 * }
7468 *
7469 * aa-DPPConfigurationParameters ATTRIBUTE ::=
7470 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
7471 *
7472 * Attribute ::= SEQUENCE {
7473 * type OBJECT IDENTIFIER,
7474 * values SET SIZE(1..MAX) OF Type
7475 *
7476 * Exactly one instance of ATTRIBUTE in attrValues.
7477 */
7478 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7479 goto fail;
7480 if (pos < end) {
7481 wpa_hexdump_key(MSG_MSGDUMP,
7482 "DPP: Ignore additional data at the end of ATTRIBUTE",
7483 pos, end - pos);
7484 }
7485 end = pos;
7486 pos = hdr.payload;
7487
7488 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
7489 goto fail;
7490 if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
7491 asn1_oid_to_str(&oid, txt, sizeof(txt));
7492 wpa_printf(MSG_DEBUG,
7493 "DPP: Unexpected Attribute identifier %s", txt);
7494 goto fail;
7495 }
7496
7497 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7498 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7499 wpa_printf(MSG_DEBUG,
7500 "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
7501 hdr.class, hdr.tag);
7502 goto fail;
7503 }
7504 pos = hdr.payload;
7505 end = hdr.payload + hdr.length;
7506
7507 /*
7508 * DPPConfigurationParameters ::= SEQUENCE {
7509 * configurationTemplate UTF8String,
7510 * connectorTemplate UTF8String OPTIONAL}
7511 */
7512
7513 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
7514 pos, end - pos);
7515 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7516 goto fail;
7517 if (pos < end) {
7518 wpa_hexdump_key(MSG_MSGDUMP,
7519 "DPP: Ignore additional data after DPPConfigurationParameters",
7520 pos, end - pos);
7521 }
7522 end = pos;
7523 pos = hdr.payload;
7524
7525 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7526 hdr.class != ASN1_CLASS_UNIVERSAL ||
7527 hdr.tag != ASN1_TAG_UTF8STRING) {
7528 wpa_printf(MSG_DEBUG,
7529 "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
7530 hdr.class, hdr.tag);
7531 goto fail;
7532 }
7533 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
7534 hdr.payload, hdr.length);
7535 key->config_template = os_zalloc(hdr.length + 1);
7536 if (!key->config_template)
7537 goto fail;
7538 os_memcpy(key->config_template, hdr.payload, hdr.length);
7539
7540 pos = hdr.payload + hdr.length;
7541
7542 if (pos < end) {
7543 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7544 hdr.class != ASN1_CLASS_UNIVERSAL ||
7545 hdr.tag != ASN1_TAG_UTF8STRING) {
7546 wpa_printf(MSG_DEBUG,
7547 "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
7548 hdr.class, hdr.tag);
7549 goto fail;
7550 }
7551 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
7552 hdr.payload, hdr.length);
7553 key->connector_template = os_zalloc(hdr.length + 1);
7554 if (!key->connector_template)
7555 goto fail;
7556 os_memcpy(key->connector_template, hdr.payload, hdr.length);
7557 }
7558
7559 return key;
7560fail:
7561 wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
7562 dpp_free_asymmetric_key(key);
7563 return NULL;
7564}
7565
7566
7567static struct dpp_asymmetric_key *
7568dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
7569{
7570 struct asn1_hdr hdr;
7571 const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
7572 struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
7573
7574 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
7575 key_pkg, key_pkg_len);
7576
7577 /*
7578 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
7579 *
7580 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
7581 */
7582 while (pos < end) {
7583 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
7584 !(key = dpp_parse_one_asymmetric_key(hdr.payload,
7585 hdr.length))) {
7586 dpp_free_asymmetric_key(first);
7587 return NULL;
7588 }
7589 if (!last) {
7590 first = last = key;
7591 } else {
7592 last->next = key;
7593 last = key;
7594 }
7595 }
7596
7597 return first;
7598}
7599
7600
7601static int dpp_conf_resp_env_data(struct dpp_authentication *auth,
7602 const u8 *env_data, size_t env_data_len)
7603{
7604 const u8 *key;
7605 size_t key_len;
7606 u8 kek[DPP_MAX_HASH_LEN];
7607 u8 cont_encr_key[DPP_MAX_HASH_LEN];
7608 size_t cont_encr_key_len;
7609 int res;
7610 u8 *key_pkg;
7611 size_t key_pkg_len;
7612 struct dpp_enveloped_data data;
7613 struct dpp_asymmetric_key *keys;
7614
7615 wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
7616
7617 if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
7618 return -1;
7619
7620 /* TODO: For initial testing, use ke as the key. Replace this with a
7621 * new key once that has been defined. */
7622 key = auth->ke;
7623 key_len = auth->curve->hash_len;
7624 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
7625
7626 if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
7627 kek, data.pbkdf2_key_len)) {
7628 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
7629 return -1;
7630 }
7631 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
7632 kek, data.pbkdf2_key_len);
7633
7634 if (data.enc_key_len < AES_BLOCK_SIZE ||
7635 data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
7636 wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
7637 return -1;
7638 }
7639 res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
7640 data.enc_key, data.enc_key_len,
7641 0, NULL, NULL, cont_encr_key);
7642 forced_memzero(kek, data.pbkdf2_key_len);
7643 if (res < 0) {
7644 wpa_printf(MSG_DEBUG,
7645 "DPP: AES-SIV decryption of encryptedKey failed");
7646 return -1;
7647 }
7648 cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
7649 wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
7650 cont_encr_key, cont_encr_key_len);
7651
7652 if (data.enc_cont_len < AES_BLOCK_SIZE)
7653 return -1;
7654 key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
7655 key_pkg = os_malloc(key_pkg_len);
7656 if (!key_pkg)
7657 return -1;
7658 res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
7659 data.enc_cont, data.enc_cont_len,
7660 0, NULL, NULL, key_pkg);
7661 forced_memzero(cont_encr_key, cont_encr_key_len);
7662 if (res < 0) {
7663 bin_clear_free(key_pkg, key_pkg_len);
7664 wpa_printf(MSG_DEBUG,
7665 "DPP: AES-SIV decryption of encryptedContent failed");
7666 return -1;
7667 }
7668
7669 keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
7670 bin_clear_free(key_pkg, key_pkg_len);
7671 dpp_free_asymmetric_key(auth->conf_key_pkg);
7672 auth->conf_key_pkg = keys;
7673
7674 return keys != NULL;;
7675}
7676
7677#endif /* CONFIG_DPP2 */
7678
7679
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007680int dpp_conf_resp_rx(struct dpp_authentication *auth,
7681 const struct wpabuf *resp)
7682{
7683 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
7684 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07007685 const u8 *env_data;
7686 u16 env_data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007687 const u8 *addr[1];
7688 size_t len[1];
7689 u8 *unwrapped = NULL;
7690 size_t unwrapped_len = 0;
7691 int ret = -1;
7692
Hai Shalom021b0b52019-04-10 11:17:58 -07007693 auth->conf_resp_status = 255;
7694
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007695 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007696 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007697 return -1;
7698 }
7699
7700 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
7701 DPP_ATTR_WRAPPED_DATA,
7702 &wrapped_data_len);
7703 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007704 dpp_auth_fail(auth,
7705 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007706 return -1;
7707 }
7708
7709 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7710 wrapped_data, wrapped_data_len);
7711 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7712 unwrapped = os_malloc(unwrapped_len);
7713 if (!unwrapped)
7714 return -1;
7715
7716 addr[0] = wpabuf_head(resp);
7717 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
7718 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
7719
7720 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7721 wrapped_data, wrapped_data_len,
7722 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007723 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007724 goto fail;
7725 }
7726 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7727 unwrapped, unwrapped_len);
7728
7729 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007730 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007731 goto fail;
7732 }
7733
7734 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
7735 DPP_ATTR_ENROLLEE_NONCE,
7736 &e_nonce_len);
7737 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007738 dpp_auth_fail(auth,
7739 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007740 goto fail;
7741 }
7742 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
7743 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007744 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007745 goto fail;
7746 }
7747
7748 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
7749 DPP_ATTR_STATUS, &status_len);
7750 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007751 dpp_auth_fail(auth,
7752 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007753 goto fail;
7754 }
Hai Shalom021b0b52019-04-10 11:17:58 -07007755 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007756 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
7757 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007758 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007759 goto fail;
7760 }
7761
Hai Shalomfdcde762020-04-02 11:19:20 -07007762 env_data = dpp_get_attr(unwrapped, unwrapped_len,
7763 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
7764#ifdef CONFIG_DPP2
7765 if (env_data &&
7766 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
7767 goto fail;
7768#endif /* CONFIG_DPP2 */
7769
Hai Shalomc3565922019-10-28 11:58:20 -07007770 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
7771 &conf_obj_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07007772 if (!conf_obj && !env_data) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007773 dpp_auth_fail(auth,
7774 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007775 goto fail;
7776 }
Hai Shalomc3565922019-10-28 11:58:20 -07007777 while (conf_obj) {
7778 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
7779 conf_obj, conf_obj_len);
7780 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
7781 goto fail;
7782 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
7783 DPP_ATTR_CONFIG_OBJ,
7784 &conf_obj_len);
7785 }
7786
7787#ifdef CONFIG_DPP2
7788 status = dpp_get_attr(unwrapped, unwrapped_len,
7789 DPP_ATTR_SEND_CONN_STATUS, &status_len);
7790 if (status) {
7791 wpa_printf(MSG_DEBUG,
7792 "DPP: Configurator requested connection status result");
7793 auth->conn_status_requested = 1;
7794 }
7795#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007796
7797 ret = 0;
7798
7799fail:
7800 os_free(unwrapped);
7801 return ret;
7802}
7803
7804
Hai Shalom021b0b52019-04-10 11:17:58 -07007805#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07007806
Hai Shalom021b0b52019-04-10 11:17:58 -07007807enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
7808 const u8 *hdr,
7809 const u8 *attr_start, size_t attr_len)
7810{
7811 const u8 *wrapped_data, *status, *e_nonce;
7812 u16 wrapped_data_len, status_len, e_nonce_len;
7813 const u8 *addr[2];
7814 size_t len[2];
7815 u8 *unwrapped = NULL;
7816 size_t unwrapped_len = 0;
7817 enum dpp_status_error ret = 256;
7818
7819 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
7820 &wrapped_data_len);
7821 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7822 dpp_auth_fail(auth,
7823 "Missing or invalid required Wrapped Data attribute");
7824 goto fail;
7825 }
7826 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
7827 wrapped_data, wrapped_data_len);
7828
7829 attr_len = wrapped_data - 4 - attr_start;
7830
7831 addr[0] = hdr;
7832 len[0] = DPP_HDR_LEN;
7833 addr[1] = attr_start;
7834 len[1] = attr_len;
7835 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7836 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7837 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7838 wrapped_data, wrapped_data_len);
7839 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7840 unwrapped = os_malloc(unwrapped_len);
7841 if (!unwrapped)
7842 goto fail;
7843 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7844 wrapped_data, wrapped_data_len,
7845 2, addr, len, unwrapped) < 0) {
7846 dpp_auth_fail(auth, "AES-SIV decryption failed");
7847 goto fail;
7848 }
7849 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7850 unwrapped, unwrapped_len);
7851
7852 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7853 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
7854 goto fail;
7855 }
7856
7857 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
7858 DPP_ATTR_ENROLLEE_NONCE,
7859 &e_nonce_len);
7860 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
7861 dpp_auth_fail(auth,
7862 "Missing or invalid Enrollee Nonce attribute");
7863 goto fail;
7864 }
7865 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
7866 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
7867 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
7868 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
7869 auth->e_nonce, e_nonce_len);
7870 goto fail;
7871 }
7872
7873 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
7874 &status_len);
7875 if (!status || status_len < 1) {
7876 dpp_auth_fail(auth,
7877 "Missing or invalid required DPP Status attribute");
7878 goto fail;
7879 }
7880 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
7881 ret = status[0];
7882
7883fail:
7884 bin_clear_free(unwrapped, unwrapped_len);
7885 return ret;
7886}
Hai Shalom021b0b52019-04-10 11:17:58 -07007887
7888
7889struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
7890 enum dpp_status_error status)
7891{
7892 struct wpabuf *msg, *clear;
7893 size_t nonce_len, clear_len, attr_len;
7894 const u8 *addr[2];
7895 size_t len[2];
7896 u8 *wrapped;
7897
7898 nonce_len = auth->curve->nonce_len;
7899 clear_len = 5 + 4 + nonce_len;
7900 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7901 clear = wpabuf_alloc(clear_len);
7902 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
7903 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07007904 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07007905
7906 /* DPP Status */
7907 dpp_build_attr_status(clear, status);
7908
7909 /* E-nonce */
7910 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
7911 wpabuf_put_le16(clear, nonce_len);
7912 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
7913
7914 /* OUI, OUI type, Crypto Suite, DPP frame type */
7915 addr[0] = wpabuf_head_u8(msg) + 2;
7916 len[0] = 3 + 1 + 1 + 1;
7917 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7918
7919 /* Attributes before Wrapped Data (none) */
7920 addr[1] = wpabuf_put(msg, 0);
7921 len[1] = 0;
7922 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7923
7924 /* Wrapped Data */
7925 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7926 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7927 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7928
7929 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7930 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
7931 wpabuf_head(clear), wpabuf_len(clear),
7932 2, addr, len, wrapped) < 0)
7933 goto fail;
7934
7935 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
7936 wpabuf_free(clear);
7937 return msg;
7938fail:
7939 wpabuf_free(clear);
7940 wpabuf_free(msg);
7941 return NULL;
7942}
7943
7944
Hai Shalomc3565922019-10-28 11:58:20 -07007945static int valid_channel_list(const char *val)
7946{
7947 while (*val) {
7948 if (!((*val >= '0' && *val <= '9') ||
7949 *val == '/' || *val == ','))
7950 return 0;
7951 val++;
7952 }
7953
7954 return 1;
7955}
7956
7957
7958enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
7959 const u8 *hdr,
7960 const u8 *attr_start,
7961 size_t attr_len,
7962 u8 *ssid, size_t *ssid_len,
7963 char **channel_list)
7964{
7965 const u8 *wrapped_data, *status, *e_nonce;
7966 u16 wrapped_data_len, status_len, e_nonce_len;
7967 const u8 *addr[2];
7968 size_t len[2];
7969 u8 *unwrapped = NULL;
7970 size_t unwrapped_len = 0;
7971 enum dpp_status_error ret = 256;
7972 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007973 struct wpabuf *ssid64;
Hai Shalomc3565922019-10-28 11:58:20 -07007974
7975 *ssid_len = 0;
7976 *channel_list = NULL;
7977
7978 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
7979 &wrapped_data_len);
7980 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7981 dpp_auth_fail(auth,
7982 "Missing or invalid required Wrapped Data attribute");
7983 goto fail;
7984 }
7985 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
7986 wrapped_data, wrapped_data_len);
7987
7988 attr_len = wrapped_data - 4 - attr_start;
7989
7990 addr[0] = hdr;
7991 len[0] = DPP_HDR_LEN;
7992 addr[1] = attr_start;
7993 len[1] = attr_len;
7994 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7995 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7996 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7997 wrapped_data, wrapped_data_len);
7998 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7999 unwrapped = os_malloc(unwrapped_len);
8000 if (!unwrapped)
8001 goto fail;
8002 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
8003 wrapped_data, wrapped_data_len,
8004 2, addr, len, unwrapped) < 0) {
8005 dpp_auth_fail(auth, "AES-SIV decryption failed");
8006 goto fail;
8007 }
8008 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
8009 unwrapped, unwrapped_len);
8010
8011 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8012 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
8013 goto fail;
8014 }
8015
8016 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
8017 DPP_ATTR_ENROLLEE_NONCE,
8018 &e_nonce_len);
8019 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8020 dpp_auth_fail(auth,
8021 "Missing or invalid Enrollee Nonce attribute");
8022 goto fail;
8023 }
8024 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
8025 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
8026 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
8027 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
8028 auth->e_nonce, e_nonce_len);
8029 goto fail;
8030 }
8031
8032 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
8033 &status_len);
8034 if (!status) {
8035 dpp_auth_fail(auth,
8036 "Missing required DPP Connection Status attribute");
8037 goto fail;
8038 }
8039 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
8040 status, status_len);
8041
8042 root = json_parse((const char *) status, status_len);
8043 if (!root) {
8044 dpp_auth_fail(auth, "Could not parse connStatus");
8045 goto fail;
8046 }
8047
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008048 ssid64 = json_get_member_base64url(root, "ssid64");
8049 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
8050 *ssid_len = wpabuf_len(ssid64);
8051 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
Hai Shalomc3565922019-10-28 11:58:20 -07008052 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008053 wpabuf_free(ssid64);
Hai Shalomc3565922019-10-28 11:58:20 -07008054
8055 token = json_get_member(root, "channelList");
8056 if (token && token->type == JSON_STRING &&
8057 valid_channel_list(token->string))
8058 *channel_list = os_strdup(token->string);
8059
8060 token = json_get_member(root, "result");
8061 if (!token || token->type != JSON_NUMBER) {
8062 dpp_auth_fail(auth, "No connStatus - result");
8063 goto fail;
8064 }
8065 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
8066 ret = token->number;
8067
8068fail:
8069 json_free(root);
8070 bin_clear_free(unwrapped, unwrapped_len);
8071 return ret;
8072}
8073
8074
8075struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
8076 enum dpp_status_error result,
8077 const u8 *ssid, size_t ssid_len,
8078 const char *channel_list)
8079{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008080 struct wpabuf *msg = NULL, *clear = NULL, *json;
Hai Shalomc3565922019-10-28 11:58:20 -07008081 size_t nonce_len, clear_len, attr_len;
8082 const u8 *addr[2];
8083 size_t len[2];
8084 u8 *wrapped;
8085
8086 json = wpabuf_alloc(1000);
8087 if (!json)
8088 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008089 json_start_object(json, NULL);
8090 json_add_int(json, "result", result);
Hai Shalomc3565922019-10-28 11:58:20 -07008091 if (ssid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008092 json_value_sep(json);
8093 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0)
8094 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07008095 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008096 if (channel_list) {
8097 json_value_sep(json);
8098 json_add_string(json, "channelList", channel_list);
8099 }
8100 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07008101 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
8102 wpabuf_head(json), wpabuf_len(json));
8103
8104 nonce_len = auth->curve->nonce_len;
8105 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
8106 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
8107 clear = wpabuf_alloc(clear_len);
8108 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
8109 if (!clear || !msg)
8110 goto fail;
8111
8112 /* E-nonce */
8113 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
8114 wpabuf_put_le16(clear, nonce_len);
8115 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
8116
8117 /* DPP Connection Status */
8118 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
8119 wpabuf_put_le16(clear, wpabuf_len(json));
8120 wpabuf_put_buf(clear, json);
8121
8122 /* OUI, OUI type, Crypto Suite, DPP frame type */
8123 addr[0] = wpabuf_head_u8(msg) + 2;
8124 len[0] = 3 + 1 + 1 + 1;
8125 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8126
8127 /* Attributes before Wrapped Data (none) */
8128 addr[1] = wpabuf_put(msg, 0);
8129 len[1] = 0;
8130 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8131
8132 /* Wrapped Data */
8133 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
8134 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8135 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8136
8137 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
8138 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
8139 wpabuf_head(clear), wpabuf_len(clear),
8140 2, addr, len, wrapped) < 0)
8141 goto fail;
8142
8143 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
8144 msg);
8145 wpabuf_free(json);
8146 wpabuf_free(clear);
8147 return msg;
8148fail:
8149 wpabuf_free(json);
8150 wpabuf_free(clear);
8151 wpabuf_free(msg);
8152 return NULL;
8153}
8154
8155#endif /* CONFIG_DPP2 */
8156
8157
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008158void dpp_configurator_free(struct dpp_configurator *conf)
8159{
8160 if (!conf)
8161 return;
8162 EVP_PKEY_free(conf->csign);
8163 os_free(conf->kid);
8164 os_free(conf);
8165}
8166
8167
Roshan Pius3a1667e2018-07-03 15:17:14 -07008168int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
8169 size_t buflen)
8170{
8171 EC_KEY *eckey;
8172 int key_len, ret = -1;
8173 unsigned char *key = NULL;
8174
8175 if (!conf->csign)
8176 return -1;
8177
8178 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
8179 if (!eckey)
8180 return -1;
8181
8182 key_len = i2d_ECPrivateKey(eckey, &key);
8183 if (key_len > 0)
8184 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
8185
8186 EC_KEY_free(eckey);
8187 OPENSSL_free(key);
8188 return ret;
8189}
8190
8191
Hai Shalomfdcde762020-04-02 11:19:20 -07008192static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
8193{
8194 struct wpabuf *csign_pub = NULL;
8195 u8 kid_hash[SHA256_MAC_LEN];
8196 const u8 *addr[1];
8197 size_t len[1];
8198 int res;
8199
8200 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
8201 if (!csign_pub) {
8202 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
8203 return -1;
8204 }
8205
8206 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
8207 addr[0] = wpabuf_head(csign_pub);
8208 len[0] = wpabuf_len(csign_pub);
8209 res = sha256_vector(1, addr, len, kid_hash);
8210 wpabuf_free(csign_pub);
8211 if (res < 0) {
8212 wpa_printf(MSG_DEBUG,
8213 "DPP: Failed to derive kid for C-sign-key");
8214 return -1;
8215 }
8216
8217 conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
8218 return conf->kid ? 0 : -1;
8219}
8220
8221
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008222struct dpp_configurator *
8223dpp_keygen_configurator(const char *curve, const u8 *privkey,
8224 size_t privkey_len)
8225{
8226 struct dpp_configurator *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008227
8228 conf = os_zalloc(sizeof(*conf));
8229 if (!conf)
8230 return NULL;
8231
8232 if (!curve) {
8233 conf->curve = &dpp_curves[0];
8234 } else {
8235 conf->curve = dpp_get_curve_name(curve);
8236 if (!conf->curve) {
8237 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
8238 curve);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008239 os_free(conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008240 return NULL;
8241 }
8242 }
8243 if (privkey)
8244 conf->csign = dpp_set_keypair(&conf->curve, privkey,
8245 privkey_len);
8246 else
8247 conf->csign = dpp_gen_keypair(conf->curve);
8248 if (!conf->csign)
8249 goto fail;
8250 conf->own = 1;
8251
Hai Shalomfdcde762020-04-02 11:19:20 -07008252 if (dpp_configurator_gen_kid(conf) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008253 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008254 return conf;
8255fail:
8256 dpp_configurator_free(conf);
Hai Shalomfdcde762020-04-02 11:19:20 -07008257 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008258}
8259
8260
8261int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008262 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008263{
8264 struct wpabuf *conf_obj;
8265 int ret = -1;
8266
8267 if (!auth->conf) {
8268 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
8269 return -1;
8270 }
8271
8272 if (!curve) {
8273 auth->curve = &dpp_curves[0];
8274 } else {
8275 auth->curve = dpp_get_curve_name(curve);
8276 if (!auth->curve) {
8277 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
8278 curve);
8279 return -1;
8280 }
8281 }
8282 wpa_printf(MSG_DEBUG,
8283 "DPP: Building own configuration/connector with curve %s",
8284 auth->curve->name);
8285
8286 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
8287 if (!auth->own_protocol_key)
8288 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07008289 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008290 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07008291 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008292
Hai Shalomc3565922019-10-28 11:58:20 -07008293 conf_obj = dpp_build_conf_obj(auth, ap, 0);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008294 if (!conf_obj) {
8295 wpabuf_free(auth->conf_obj[0].c_sign_key);
8296 auth->conf_obj[0].c_sign_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008297 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008298 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008299 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
8300 wpabuf_len(conf_obj));
8301fail:
8302 wpabuf_free(conf_obj);
8303 auth->peer_protocol_key = NULL;
8304 return ret;
8305}
8306
8307
8308static int dpp_compatible_netrole(const char *role1, const char *role2)
8309{
8310 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
8311 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
8312}
8313
8314
8315static int dpp_connector_compatible_group(struct json_token *root,
8316 const char *group_id,
8317 const char *net_role)
8318{
8319 struct json_token *groups, *token;
8320
8321 groups = json_get_member(root, "groups");
8322 if (!groups || groups->type != JSON_ARRAY)
8323 return 0;
8324
8325 for (token = groups->child; token; token = token->sibling) {
8326 struct json_token *id, *role;
8327
8328 id = json_get_member(token, "groupId");
8329 if (!id || id->type != JSON_STRING)
8330 continue;
8331
8332 role = json_get_member(token, "netRole");
8333 if (!role || role->type != JSON_STRING)
8334 continue;
8335
8336 if (os_strcmp(id->string, "*") != 0 &&
8337 os_strcmp(group_id, "*") != 0 &&
8338 os_strcmp(id->string, group_id) != 0)
8339 continue;
8340
8341 if (dpp_compatible_netrole(role->string, net_role))
8342 return 1;
8343 }
8344
8345 return 0;
8346}
8347
8348
8349static int dpp_connector_match_groups(struct json_token *own_root,
8350 struct json_token *peer_root)
8351{
8352 struct json_token *groups, *token;
8353
8354 groups = json_get_member(peer_root, "groups");
8355 if (!groups || groups->type != JSON_ARRAY) {
8356 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
8357 return 0;
8358 }
8359
8360 for (token = groups->child; token; token = token->sibling) {
8361 struct json_token *id, *role;
8362
8363 id = json_get_member(token, "groupId");
8364 if (!id || id->type != JSON_STRING) {
8365 wpa_printf(MSG_DEBUG,
8366 "DPP: Missing peer groupId string");
8367 continue;
8368 }
8369
8370 role = json_get_member(token, "netRole");
8371 if (!role || role->type != JSON_STRING) {
8372 wpa_printf(MSG_DEBUG,
8373 "DPP: Missing peer groups::netRole string");
8374 continue;
8375 }
8376 wpa_printf(MSG_DEBUG,
8377 "DPP: peer connector group: groupId='%s' netRole='%s'",
8378 id->string, role->string);
8379 if (dpp_connector_compatible_group(own_root, id->string,
8380 role->string)) {
8381 wpa_printf(MSG_DEBUG,
8382 "DPP: Compatible group/netRole in own connector");
8383 return 1;
8384 }
8385 }
8386
8387 return 0;
8388}
8389
8390
8391static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
8392 unsigned int hash_len)
8393{
8394 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
8395 const char *info = "DPP PMK";
8396 int res;
8397
8398 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8399
8400 /* HKDF-Extract(<>, N.x) */
8401 os_memset(salt, 0, hash_len);
8402 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
8403 return -1;
8404 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
8405 prk, hash_len);
8406
8407 /* HKDF-Expand(PRK, info, L) */
8408 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
8409 os_memset(prk, 0, hash_len);
8410 if (res < 0)
8411 return -1;
8412
8413 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
8414 pmk, hash_len);
8415 return 0;
8416}
8417
8418
8419static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
8420 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
8421{
8422 struct wpabuf *nkx, *pkx;
8423 int ret = -1, res;
8424 const u8 *addr[2];
8425 size_t len[2];
8426 u8 hash[SHA256_MAC_LEN];
8427
8428 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8429 nkx = dpp_get_pubkey_point(own_key, 0);
8430 pkx = dpp_get_pubkey_point(peer_key, 0);
8431 if (!nkx || !pkx)
8432 goto fail;
8433 addr[0] = wpabuf_head(nkx);
8434 len[0] = wpabuf_len(nkx) / 2;
8435 addr[1] = wpabuf_head(pkx);
8436 len[1] = wpabuf_len(pkx) / 2;
8437 if (len[0] != len[1])
8438 goto fail;
8439 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
8440 addr[0] = wpabuf_head(pkx);
8441 addr[1] = wpabuf_head(nkx);
8442 }
8443 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
8444 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
8445 res = sha256_vector(2, addr, len, hash);
8446 if (res < 0)
8447 goto fail;
8448 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
8449 os_memcpy(pmkid, hash, PMKID_LEN);
8450 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
8451 ret = 0;
8452fail:
8453 wpabuf_free(nkx);
8454 wpabuf_free(pkx);
8455 return ret;
8456}
8457
8458
Roshan Pius3a1667e2018-07-03 15:17:14 -07008459enum dpp_status_error
8460dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
8461 const u8 *net_access_key, size_t net_access_key_len,
8462 const u8 *csign_key, size_t csign_key_len,
8463 const u8 *peer_connector, size_t peer_connector_len,
8464 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008465{
8466 struct json_token *root = NULL, *netkey, *token;
8467 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008468 enum dpp_status_error ret = 255, res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008469 EVP_PKEY *own_key = NULL, *peer_key = NULL;
8470 struct wpabuf *own_key_pub = NULL;
8471 const struct dpp_curve_params *curve, *own_curve;
8472 struct dpp_signed_connector_info info;
8473 const unsigned char *p;
8474 EVP_PKEY *csign = NULL;
8475 char *signed_connector = NULL;
8476 const char *pos, *end;
8477 unsigned char *own_conn = NULL;
8478 size_t own_conn_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008479 size_t Nx_len;
8480 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
8481
8482 os_memset(intro, 0, sizeof(*intro));
8483 os_memset(&info, 0, sizeof(info));
8484 if (expiry)
8485 *expiry = 0;
8486
8487 p = csign_key;
8488 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
8489 if (!csign) {
8490 wpa_printf(MSG_ERROR,
8491 "DPP: Failed to parse local C-sign-key information");
8492 goto fail;
8493 }
8494
8495 own_key = dpp_set_keypair(&own_curve, net_access_key,
8496 net_access_key_len);
8497 if (!own_key) {
8498 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
8499 goto fail;
8500 }
8501
8502 pos = os_strchr(own_connector, '.');
8503 if (!pos) {
8504 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
8505 goto fail;
8506 }
8507 pos++;
8508 end = os_strchr(pos, '.');
8509 if (!end) {
8510 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
8511 goto fail;
8512 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008513 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008514 if (!own_conn) {
8515 wpa_printf(MSG_DEBUG,
8516 "DPP: Failed to base64url decode own signedConnector JWS Payload");
8517 goto fail;
8518 }
8519
8520 own_root = json_parse((const char *) own_conn, own_conn_len);
8521 if (!own_root) {
8522 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
8523 goto fail;
8524 }
8525
8526 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
8527 peer_connector, peer_connector_len);
8528 signed_connector = os_malloc(peer_connector_len + 1);
8529 if (!signed_connector)
8530 goto fail;
8531 os_memcpy(signed_connector, peer_connector, peer_connector_len);
8532 signed_connector[peer_connector_len] = '\0';
8533
Roshan Pius3a1667e2018-07-03 15:17:14 -07008534 res = dpp_process_signed_connector(&info, csign, signed_connector);
8535 if (res != DPP_STATUS_OK) {
8536 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008537 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008538 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008539
8540 root = json_parse((const char *) info.payload, info.payload_len);
8541 if (!root) {
8542 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008543 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008544 goto fail;
8545 }
8546
8547 if (!dpp_connector_match_groups(own_root, root)) {
8548 wpa_printf(MSG_DEBUG,
8549 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008550 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008551 goto fail;
8552 }
8553
8554 token = json_get_member(root, "expiry");
8555 if (!token || token->type != JSON_STRING) {
8556 wpa_printf(MSG_DEBUG,
8557 "DPP: No expiry string found - connector does not expire");
8558 } else {
8559 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
8560 if (dpp_key_expired(token->string, expiry)) {
8561 wpa_printf(MSG_DEBUG,
8562 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008563 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008564 goto fail;
8565 }
8566 }
8567
8568 netkey = json_get_member(root, "netAccessKey");
8569 if (!netkey || netkey->type != JSON_OBJECT) {
8570 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07008571 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008572 goto fail;
8573 }
8574
8575 peer_key = dpp_parse_jwk(netkey, &curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008576 if (!peer_key) {
8577 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008578 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008579 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008580 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
8581
8582 if (own_curve != curve) {
8583 wpa_printf(MSG_DEBUG,
8584 "DPP: Mismatching netAccessKey curves (%s != %s)",
8585 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008586 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008587 goto fail;
8588 }
8589
8590 /* ECDH: N = nk * PK */
Hai Shalomc3565922019-10-28 11:58:20 -07008591 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008592 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008593
8594 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
8595 Nx, Nx_len);
8596
8597 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8598 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
8599 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
8600 goto fail;
8601 }
8602 intro->pmk_len = curve->hash_len;
8603
8604 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8605 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
8606 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
8607 goto fail;
8608 }
8609
Roshan Pius3a1667e2018-07-03 15:17:14 -07008610 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008611fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07008612 if (ret != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008613 os_memset(intro, 0, sizeof(*intro));
8614 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008615 os_free(own_conn);
8616 os_free(signed_connector);
8617 os_free(info.payload);
8618 EVP_PKEY_free(own_key);
8619 wpabuf_free(own_key_pub);
8620 EVP_PKEY_free(peer_key);
8621 EVP_PKEY_free(csign);
8622 json_free(root);
8623 json_free(own_root);
8624 return ret;
8625}
8626
8627
8628static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
8629 int init)
8630{
8631 EC_GROUP *group;
8632 size_t len = curve->prime_len;
8633 const u8 *x, *y;
Hai Shalom81f62d82019-07-22 12:10:00 -07008634 EVP_PKEY *res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008635
8636 switch (curve->ike_group) {
8637 case 19:
8638 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
8639 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
8640 break;
8641 case 20:
8642 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
8643 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
8644 break;
8645 case 21:
8646 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
8647 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
8648 break;
8649 case 28:
8650 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
8651 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
8652 break;
8653 case 29:
8654 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
8655 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
8656 break;
8657 case 30:
8658 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
8659 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
8660 break;
8661 default:
8662 return NULL;
8663 }
8664
8665 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
8666 if (!group)
8667 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07008668 res = dpp_set_pubkey_point_group(group, x, y, len);
8669 EC_GROUP_free(group);
8670 return res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008671}
8672
8673
8674static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
8675 const u8 *mac_init, const char *code,
8676 const char *identifier, BN_CTX *bnctx,
Hai Shalom81f62d82019-07-22 12:10:00 -07008677 EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008678{
8679 u8 hash[DPP_MAX_HASH_LEN];
8680 const u8 *addr[3];
8681 size_t len[3];
8682 unsigned int num_elem = 0;
8683 EC_POINT *Qi = NULL;
8684 EVP_PKEY *Pi = NULL;
8685 EC_KEY *Pi_ec = NULL;
8686 const EC_POINT *Pi_point;
8687 BIGNUM *hash_bn = NULL;
8688 const EC_GROUP *group = NULL;
8689 EC_GROUP *group2 = NULL;
8690
8691 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8692
8693 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
8694 addr[num_elem] = mac_init;
8695 len[num_elem] = ETH_ALEN;
8696 num_elem++;
8697 if (identifier) {
8698 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
8699 identifier);
8700 addr[num_elem] = (const u8 *) identifier;
8701 len[num_elem] = os_strlen(identifier);
8702 num_elem++;
8703 }
8704 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
8705 addr[num_elem] = (const u8 *) code;
8706 len[num_elem] = os_strlen(code);
8707 num_elem++;
8708 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
8709 goto fail;
8710 wpa_hexdump_key(MSG_DEBUG,
8711 "DPP: H(MAC-Initiator | [identifier |] code)",
8712 hash, curve->hash_len);
8713 Pi = dpp_pkex_get_role_elem(curve, 1);
8714 if (!Pi)
8715 goto fail;
8716 dpp_debug_print_key("DPP: Pi", Pi);
8717 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
8718 if (!Pi_ec)
8719 goto fail;
8720 Pi_point = EC_KEY_get0_public_key(Pi_ec);
8721
8722 group = EC_KEY_get0_group(Pi_ec);
8723 if (!group)
8724 goto fail;
8725 group2 = EC_GROUP_dup(group);
8726 if (!group2)
8727 goto fail;
8728 Qi = EC_POINT_new(group2);
8729 if (!Qi) {
8730 EC_GROUP_free(group2);
8731 goto fail;
8732 }
8733 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
8734 if (!hash_bn ||
8735 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
8736 goto fail;
8737 if (EC_POINT_is_at_infinity(group, Qi)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008738 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008739 goto fail;
8740 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07008741 dpp_debug_print_point("DPP: Qi", group, Qi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008742out:
8743 EC_KEY_free(Pi_ec);
8744 EVP_PKEY_free(Pi);
8745 BN_clear_free(hash_bn);
Hai Shalom81f62d82019-07-22 12:10:00 -07008746 if (ret_group && Qi)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008747 *ret_group = group2;
Hai Shalom81f62d82019-07-22 12:10:00 -07008748 else
8749 EC_GROUP_free(group2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008750 return Qi;
8751fail:
8752 EC_POINT_free(Qi);
8753 Qi = NULL;
8754 goto out;
8755}
8756
8757
8758static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
8759 const u8 *mac_resp, const char *code,
8760 const char *identifier, BN_CTX *bnctx,
Hai Shalom81f62d82019-07-22 12:10:00 -07008761 EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008762{
8763 u8 hash[DPP_MAX_HASH_LEN];
8764 const u8 *addr[3];
8765 size_t len[3];
8766 unsigned int num_elem = 0;
8767 EC_POINT *Qr = NULL;
8768 EVP_PKEY *Pr = NULL;
8769 EC_KEY *Pr_ec = NULL;
8770 const EC_POINT *Pr_point;
8771 BIGNUM *hash_bn = NULL;
8772 const EC_GROUP *group = NULL;
8773 EC_GROUP *group2 = NULL;
8774
8775 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8776
8777 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
8778 addr[num_elem] = mac_resp;
8779 len[num_elem] = ETH_ALEN;
8780 num_elem++;
8781 if (identifier) {
8782 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
8783 identifier);
8784 addr[num_elem] = (const u8 *) identifier;
8785 len[num_elem] = os_strlen(identifier);
8786 num_elem++;
8787 }
8788 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
8789 addr[num_elem] = (const u8 *) code;
8790 len[num_elem] = os_strlen(code);
8791 num_elem++;
8792 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
8793 goto fail;
8794 wpa_hexdump_key(MSG_DEBUG,
8795 "DPP: H(MAC-Responder | [identifier |] code)",
8796 hash, curve->hash_len);
8797 Pr = dpp_pkex_get_role_elem(curve, 0);
8798 if (!Pr)
8799 goto fail;
8800 dpp_debug_print_key("DPP: Pr", Pr);
8801 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
8802 if (!Pr_ec)
8803 goto fail;
8804 Pr_point = EC_KEY_get0_public_key(Pr_ec);
8805
8806 group = EC_KEY_get0_group(Pr_ec);
8807 if (!group)
8808 goto fail;
8809 group2 = EC_GROUP_dup(group);
8810 if (!group2)
8811 goto fail;
8812 Qr = EC_POINT_new(group2);
8813 if (!Qr) {
8814 EC_GROUP_free(group2);
8815 goto fail;
8816 }
8817 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
8818 if (!hash_bn ||
8819 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
8820 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008821 if (EC_POINT_is_at_infinity(group, Qr)) {
8822 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
8823 goto fail;
8824 }
8825 dpp_debug_print_point("DPP: Qr", group, Qr);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008826out:
8827 EC_KEY_free(Pr_ec);
8828 EVP_PKEY_free(Pr);
8829 BN_clear_free(hash_bn);
Hai Shalom81f62d82019-07-22 12:10:00 -07008830 if (ret_group && Qr)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008831 *ret_group = group2;
Hai Shalom81f62d82019-07-22 12:10:00 -07008832 else
8833 EC_GROUP_free(group2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008834 return Qr;
8835fail:
8836 EC_POINT_free(Qr);
8837 Qr = NULL;
8838 goto out;
8839}
8840
8841
Roshan Pius3a1667e2018-07-03 15:17:14 -07008842#ifdef CONFIG_TESTING_OPTIONS
8843static int dpp_test_gen_invalid_key(struct wpabuf *msg,
8844 const struct dpp_curve_params *curve)
8845{
8846 BN_CTX *ctx;
8847 BIGNUM *x, *y;
8848 int ret = -1;
8849 EC_GROUP *group;
8850 EC_POINT *point;
8851
8852 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
8853 if (!group)
8854 return -1;
8855
8856 ctx = BN_CTX_new();
8857 point = EC_POINT_new(group);
8858 x = BN_new();
8859 y = BN_new();
8860 if (!ctx || !point || !x || !y)
8861 goto fail;
8862
8863 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
8864 goto fail;
8865
8866 /* Generate a random y coordinate that results in a point that is not
8867 * on the curve. */
8868 for (;;) {
8869 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
8870 goto fail;
8871
8872 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
8873 ctx) != 1) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008874#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
Roshan Pius3a1667e2018-07-03 15:17:14 -07008875 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
8876 * return an error from EC_POINT_set_affine_coordinates_GFp()
8877 * when the point is not on the curve. */
8878 break;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008879#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07008880 goto fail;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008881#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07008882 }
8883
8884 if (!EC_POINT_is_on_curve(group, point, ctx))
8885 break;
8886 }
8887
8888 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
8889 curve->prime_len) < 0 ||
8890 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
8891 curve->prime_len) < 0)
8892 goto fail;
8893
8894 ret = 0;
8895fail:
8896 if (ret < 0)
8897 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
8898 BN_free(x);
8899 BN_free(y);
8900 EC_POINT_free(point);
8901 BN_CTX_free(ctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07008902 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008903
8904 return ret;
8905}
8906#endif /* CONFIG_TESTING_OPTIONS */
8907
8908
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008909static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
8910{
8911 EC_KEY *X_ec = NULL;
8912 const EC_POINT *X_point;
8913 BN_CTX *bnctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07008914 EC_GROUP *group = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008915 EC_POINT *Qi = NULL, *M = NULL;
8916 struct wpabuf *M_buf = NULL;
8917 BIGNUM *Mx = NULL, *My = NULL;
8918 struct wpabuf *msg = NULL;
8919 size_t attr_len;
8920 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008921
8922 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
8923
8924 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8925 bnctx = BN_CTX_new();
8926 if (!bnctx)
8927 goto fail;
8928 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
8929 pkex->identifier, bnctx, &group);
8930 if (!Qi)
8931 goto fail;
8932
8933 /* Generate a random ephemeral keypair x/X */
Roshan Pius3a1667e2018-07-03 15:17:14 -07008934#ifdef CONFIG_TESTING_OPTIONS
8935 if (dpp_pkex_ephemeral_key_override_len) {
8936 const struct dpp_curve_params *tmp_curve;
8937
8938 wpa_printf(MSG_INFO,
8939 "DPP: TESTING - override ephemeral key x/X");
8940 pkex->x = dpp_set_keypair(&tmp_curve,
8941 dpp_pkex_ephemeral_key_override,
8942 dpp_pkex_ephemeral_key_override_len);
8943 } else {
8944 pkex->x = dpp_gen_keypair(curve);
8945 }
8946#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008947 pkex->x = dpp_gen_keypair(curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008948#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008949 if (!pkex->x)
8950 goto fail;
8951
8952 /* M = X + Qi */
8953 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
8954 if (!X_ec)
8955 goto fail;
8956 X_point = EC_KEY_get0_public_key(X_ec);
8957 if (!X_point)
8958 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008959 dpp_debug_print_point("DPP: X", group, X_point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008960 M = EC_POINT_new(group);
8961 Mx = BN_new();
8962 My = BN_new();
8963 if (!M || !Mx || !My ||
8964 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
8965 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
8966 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008967 dpp_debug_print_point("DPP: M", group, M);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008968
8969 /* Initiator -> Responder: group, [identifier,] M */
8970 attr_len = 4 + 2;
8971 if (pkex->identifier)
8972 attr_len += 4 + os_strlen(pkex->identifier);
8973 attr_len += 4 + 2 * curve->prime_len;
8974 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
8975 if (!msg)
8976 goto fail;
8977
Roshan Pius3a1667e2018-07-03 15:17:14 -07008978#ifdef CONFIG_TESTING_OPTIONS
8979 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
8980 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
8981 goto skip_finite_cyclic_group;
8982 }
8983#endif /* CONFIG_TESTING_OPTIONS */
8984
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008985 /* Finite Cyclic Group attribute */
8986 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
8987 wpabuf_put_le16(msg, 2);
8988 wpabuf_put_le16(msg, curve->ike_group);
8989
Roshan Pius3a1667e2018-07-03 15:17:14 -07008990#ifdef CONFIG_TESTING_OPTIONS
8991skip_finite_cyclic_group:
8992#endif /* CONFIG_TESTING_OPTIONS */
8993
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008994 /* Code Identifier attribute */
8995 if (pkex->identifier) {
8996 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
8997 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
8998 wpabuf_put_str(msg, pkex->identifier);
8999 }
9000
Roshan Pius3a1667e2018-07-03 15:17:14 -07009001#ifdef CONFIG_TESTING_OPTIONS
9002 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
9003 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
9004 goto out;
9005 }
9006#endif /* CONFIG_TESTING_OPTIONS */
9007
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009008 /* M in Encrypted Key attribute */
9009 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
9010 wpabuf_put_le16(msg, 2 * curve->prime_len);
9011
Roshan Pius3a1667e2018-07-03 15:17:14 -07009012#ifdef CONFIG_TESTING_OPTIONS
9013 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
9014 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
9015 if (dpp_test_gen_invalid_key(msg, curve) < 0)
9016 goto fail;
9017 goto out;
9018 }
9019#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009020
Roshan Pius3a1667e2018-07-03 15:17:14 -07009021 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
9022 curve->prime_len) < 0 ||
9023 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
9024 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
9025 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009026 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009027
9028out:
9029 wpabuf_free(M_buf);
9030 EC_KEY_free(X_ec);
9031 EC_POINT_free(M);
9032 EC_POINT_free(Qi);
9033 BN_clear_free(Mx);
9034 BN_clear_free(My);
9035 BN_CTX_free(bnctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07009036 EC_GROUP_free(group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009037 return msg;
9038fail:
9039 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
9040 wpabuf_free(msg);
9041 msg = NULL;
9042 goto out;
9043}
9044
9045
Roshan Pius3a1667e2018-07-03 15:17:14 -07009046static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
9047{
9048 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
9049}
9050
9051
9052struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009053 const u8 *own_mac,
9054 const char *identifier,
9055 const char *code)
9056{
9057 struct dpp_pkex *pkex;
9058
Roshan Pius3a1667e2018-07-03 15:17:14 -07009059#ifdef CONFIG_TESTING_OPTIONS
9060 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
9061 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
9062 MAC2STR(dpp_pkex_own_mac_override));
9063 own_mac = dpp_pkex_own_mac_override;
9064 }
9065#endif /* CONFIG_TESTING_OPTIONS */
9066
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009067 pkex = os_zalloc(sizeof(*pkex));
9068 if (!pkex)
9069 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009070 pkex->msg_ctx = msg_ctx;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009071 pkex->initiator = 1;
9072 pkex->own_bi = bi;
9073 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
9074 if (identifier) {
9075 pkex->identifier = os_strdup(identifier);
9076 if (!pkex->identifier)
9077 goto fail;
9078 }
9079 pkex->code = os_strdup(code);
9080 if (!pkex->code)
9081 goto fail;
9082 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
9083 if (!pkex->exchange_req)
9084 goto fail;
9085 return pkex;
9086fail:
9087 dpp_pkex_free(pkex);
9088 return NULL;
9089}
9090
9091
Roshan Pius3a1667e2018-07-03 15:17:14 -07009092static struct wpabuf *
9093dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
9094 enum dpp_status_error status,
9095 const BIGNUM *Nx, const BIGNUM *Ny)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009096{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009097 struct wpabuf *msg = NULL;
9098 size_t attr_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009099 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009100
9101 /* Initiator -> Responder: DPP Status, [identifier,] N */
9102 attr_len = 4 + 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009103 if (pkex->identifier)
9104 attr_len += 4 + os_strlen(pkex->identifier);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009105 attr_len += 4 + 2 * curve->prime_len;
9106 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
9107 if (!msg)
9108 goto fail;
9109
Roshan Pius3a1667e2018-07-03 15:17:14 -07009110#ifdef CONFIG_TESTING_OPTIONS
9111 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
9112 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
9113 goto skip_status;
9114 }
9115
9116 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
9117 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
9118 status = 255;
9119 }
9120#endif /* CONFIG_TESTING_OPTIONS */
9121
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009122 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07009123 dpp_build_attr_status(msg, status);
9124
9125#ifdef CONFIG_TESTING_OPTIONS
9126skip_status:
9127#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009128
9129 /* Code Identifier attribute */
9130 if (pkex->identifier) {
9131 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
9132 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
9133 wpabuf_put_str(msg, pkex->identifier);
9134 }
9135
Roshan Pius3a1667e2018-07-03 15:17:14 -07009136 if (status != DPP_STATUS_OK)
9137 goto skip_encrypted_key;
9138
9139#ifdef CONFIG_TESTING_OPTIONS
9140 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
9141 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
9142 goto skip_encrypted_key;
9143 }
9144#endif /* CONFIG_TESTING_OPTIONS */
9145
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009146 /* N in Encrypted Key attribute */
9147 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
9148 wpabuf_put_le16(msg, 2 * curve->prime_len);
9149
Roshan Pius3a1667e2018-07-03 15:17:14 -07009150#ifdef CONFIG_TESTING_OPTIONS
9151 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
9152 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
9153 if (dpp_test_gen_invalid_key(msg, curve) < 0)
9154 goto fail;
9155 goto skip_encrypted_key;
9156 }
9157#endif /* CONFIG_TESTING_OPTIONS */
9158
9159 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
9160 curve->prime_len) < 0 ||
9161 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
9162 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
9163 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009164 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009165
Roshan Pius3a1667e2018-07-03 15:17:14 -07009166skip_encrypted_key:
9167 if (status == DPP_STATUS_BAD_GROUP) {
9168 /* Finite Cyclic Group attribute */
9169 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
9170 wpabuf_put_le16(msg, 2);
9171 wpabuf_put_le16(msg, curve->ike_group);
9172 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009173
Roshan Pius3a1667e2018-07-03 15:17:14 -07009174 return msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009175fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07009176 wpabuf_free(msg);
9177 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009178}
9179
9180
9181static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
9182 const u8 *Mx, size_t Mx_len,
9183 const u8 *Nx, size_t Nx_len,
9184 const char *code,
9185 const u8 *Kx, size_t Kx_len,
9186 u8 *z, unsigned int hash_len)
9187{
9188 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
9189 int res;
9190 u8 *info, *pos;
9191 size_t info_len;
9192
9193 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9194 */
9195
9196 /* HKDF-Extract(<>, IKM=K.x) */
9197 os_memset(salt, 0, hash_len);
9198 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
9199 return -1;
9200 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
9201 prk, hash_len);
9202 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
9203 info = os_malloc(info_len);
9204 if (!info)
9205 return -1;
9206 pos = info;
9207 os_memcpy(pos, mac_init, ETH_ALEN);
9208 pos += ETH_ALEN;
9209 os_memcpy(pos, mac_resp, ETH_ALEN);
9210 pos += ETH_ALEN;
9211 os_memcpy(pos, Mx, Mx_len);
9212 pos += Mx_len;
9213 os_memcpy(pos, Nx, Nx_len);
9214 pos += Nx_len;
9215 os_memcpy(pos, code, os_strlen(code));
9216
9217 /* HKDF-Expand(PRK, info, L) */
9218 if (hash_len == 32)
9219 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
9220 z, hash_len);
9221 else if (hash_len == 48)
9222 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
9223 z, hash_len);
9224 else if (hash_len == 64)
9225 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
9226 z, hash_len);
9227 else
9228 res = -1;
9229 os_free(info);
9230 os_memset(prk, 0, hash_len);
9231 if (res < 0)
9232 return -1;
9233
9234 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
9235 z, hash_len);
9236 return 0;
9237}
9238
9239
Hai Shalom74f70d42019-02-11 14:42:39 -08009240static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
9241 const char *identifier)
9242{
9243 if (!attr_id && identifier) {
9244 wpa_printf(MSG_DEBUG,
9245 "DPP: No PKEX code identifier received, but expected one");
9246 return 0;
9247 }
9248
9249 if (attr_id && !identifier) {
9250 wpa_printf(MSG_DEBUG,
9251 "DPP: PKEX code identifier received, but not expecting one");
9252 return 0;
9253 }
9254
9255 if (attr_id && identifier &&
9256 (os_strlen(identifier) != attr_id_len ||
9257 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
9258 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
9259 return 0;
9260 }
9261
9262 return 1;
9263}
9264
9265
Roshan Pius3a1667e2018-07-03 15:17:14 -07009266struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
9267 struct dpp_bootstrap_info *bi,
9268 const u8 *own_mac,
9269 const u8 *peer_mac,
9270 const char *identifier,
9271 const char *code,
9272 const u8 *buf, size_t len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009273{
Roshan Pius3a1667e2018-07-03 15:17:14 -07009274 const u8 *attr_group, *attr_id, *attr_key;
9275 u16 attr_group_len, attr_id_len, attr_key_len;
9276 const struct dpp_curve_params *curve = bi->curve;
9277 u16 ike_group;
9278 struct dpp_pkex *pkex = NULL;
9279 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009280 BN_CTX *bnctx = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07009281 EC_GROUP *group = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009282 BIGNUM *Mx = NULL, *My = NULL;
9283 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
9284 const EC_POINT *Y_point;
9285 BIGNUM *Nx = NULL, *Ny = NULL;
9286 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
9287 size_t Kx_len;
9288 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009289
9290 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
9291 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9292 "PKEX counter t limit reached - ignore message");
9293 return NULL;
9294 }
9295
9296#ifdef CONFIG_TESTING_OPTIONS
9297 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
9298 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
9299 MAC2STR(dpp_pkex_peer_mac_override));
9300 peer_mac = dpp_pkex_peer_mac_override;
9301 }
9302 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
9303 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
9304 MAC2STR(dpp_pkex_own_mac_override));
9305 own_mac = dpp_pkex_own_mac_override;
9306 }
9307#endif /* CONFIG_TESTING_OPTIONS */
9308
Hai Shalom74f70d42019-02-11 14:42:39 -08009309 attr_id_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009310 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
9311 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08009312 if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
Roshan Pius3a1667e2018-07-03 15:17:14 -07009313 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009314
9315 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
9316 &attr_group_len);
9317 if (!attr_group || attr_group_len != 2) {
9318 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9319 "Missing or invalid Finite Cyclic Group attribute");
9320 return NULL;
9321 }
9322 ike_group = WPA_GET_LE16(attr_group);
9323 if (ike_group != curve->ike_group) {
9324 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9325 "Mismatching PKEX curve: peer=%u own=%u",
9326 ike_group, curve->ike_group);
9327 pkex = os_zalloc(sizeof(*pkex));
9328 if (!pkex)
9329 goto fail;
9330 pkex->own_bi = bi;
9331 pkex->failed = 1;
9332 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
9333 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
9334 if (!pkex->exchange_resp)
9335 goto fail;
9336 return pkex;
9337 }
9338
9339 /* M in Encrypted Key attribute */
9340 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
9341 &attr_key_len);
9342 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
9343 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
9344 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9345 "Missing Encrypted Key attribute");
9346 return NULL;
9347 }
9348
9349 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
9350 bnctx = BN_CTX_new();
9351 if (!bnctx)
9352 goto fail;
9353 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
9354 &group);
9355 if (!Qi)
9356 goto fail;
9357
9358 /* X' = M - Qi */
9359 X = EC_POINT_new(group);
9360 M = EC_POINT_new(group);
9361 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
9362 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
9363 if (!X || !M || !Mx || !My ||
9364 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
9365 EC_POINT_is_at_infinity(group, M) ||
9366 !EC_POINT_is_on_curve(group, M, bnctx) ||
9367 EC_POINT_invert(group, Qi, bnctx) != 1 ||
9368 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
9369 EC_POINT_is_at_infinity(group, X) ||
9370 !EC_POINT_is_on_curve(group, X, bnctx)) {
9371 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9372 "Invalid Encrypted Key value");
9373 bi->pkex_t++;
9374 goto fail;
9375 }
9376 dpp_debug_print_point("DPP: M", group, M);
9377 dpp_debug_print_point("DPP: X'", group, X);
9378
9379 pkex = os_zalloc(sizeof(*pkex));
9380 if (!pkex)
9381 goto fail;
9382 pkex->t = bi->pkex_t;
9383 pkex->msg_ctx = msg_ctx;
9384 pkex->own_bi = bi;
9385 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
9386 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
9387 if (identifier) {
9388 pkex->identifier = os_strdup(identifier);
9389 if (!pkex->identifier)
9390 goto fail;
9391 }
9392 pkex->code = os_strdup(code);
9393 if (!pkex->code)
9394 goto fail;
9395
9396 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
9397
9398 X_ec = EC_KEY_new();
9399 if (!X_ec ||
9400 EC_KEY_set_group(X_ec, group) != 1 ||
9401 EC_KEY_set_public_key(X_ec, X) != 1)
9402 goto fail;
9403 pkex->x = EVP_PKEY_new();
9404 if (!pkex->x ||
9405 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
9406 goto fail;
9407
9408 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
9409 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
9410 if (!Qr)
9411 goto fail;
9412
9413 /* Generate a random ephemeral keypair y/Y */
9414#ifdef CONFIG_TESTING_OPTIONS
9415 if (dpp_pkex_ephemeral_key_override_len) {
9416 const struct dpp_curve_params *tmp_curve;
9417
9418 wpa_printf(MSG_INFO,
9419 "DPP: TESTING - override ephemeral key y/Y");
9420 pkex->y = dpp_set_keypair(&tmp_curve,
9421 dpp_pkex_ephemeral_key_override,
9422 dpp_pkex_ephemeral_key_override_len);
9423 } else {
9424 pkex->y = dpp_gen_keypair(curve);
9425 }
9426#else /* CONFIG_TESTING_OPTIONS */
9427 pkex->y = dpp_gen_keypair(curve);
9428#endif /* CONFIG_TESTING_OPTIONS */
9429 if (!pkex->y)
9430 goto fail;
9431
9432 /* N = Y + Qr */
9433 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
9434 if (!Y_ec)
9435 goto fail;
9436 Y_point = EC_KEY_get0_public_key(Y_ec);
9437 if (!Y_point)
9438 goto fail;
9439 dpp_debug_print_point("DPP: Y", group, Y_point);
9440 N = EC_POINT_new(group);
9441 Nx = BN_new();
9442 Ny = BN_new();
9443 if (!N || !Nx || !Ny ||
9444 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
9445 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
9446 goto fail;
9447 dpp_debug_print_point("DPP: N", group, N);
9448
9449 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
9450 Nx, Ny);
9451 if (!pkex->exchange_resp)
9452 goto fail;
9453
9454 /* K = y * X' */
Hai Shalomc3565922019-10-28 11:58:20 -07009455 if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07009456 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009457
9458 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
9459 Kx, Kx_len);
9460
9461 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9462 */
9463 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
9464 pkex->Mx, curve->prime_len,
9465 pkex->Nx, curve->prime_len, pkex->code,
9466 Kx, Kx_len, pkex->z, curve->hash_len);
9467 os_memset(Kx, 0, Kx_len);
9468 if (res < 0)
9469 goto fail;
9470
9471 pkex->exchange_done = 1;
9472
9473out:
Roshan Pius3a1667e2018-07-03 15:17:14 -07009474 BN_CTX_free(bnctx);
9475 EC_POINT_free(Qi);
9476 EC_POINT_free(Qr);
9477 BN_free(Mx);
9478 BN_free(My);
9479 BN_free(Nx);
9480 BN_free(Ny);
9481 EC_POINT_free(M);
9482 EC_POINT_free(N);
9483 EC_POINT_free(X);
9484 EC_KEY_free(X_ec);
9485 EC_KEY_free(Y_ec);
Hai Shalom81f62d82019-07-22 12:10:00 -07009486 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009487 return pkex;
9488fail:
9489 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
9490 dpp_pkex_free(pkex);
9491 pkex = NULL;
9492 goto out;
9493}
9494
9495
9496static struct wpabuf *
9497dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
9498 const struct wpabuf *A_pub, const u8 *u)
9499{
9500 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9501 struct wpabuf *msg = NULL;
9502 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009503 struct wpabuf *clear = NULL;
9504 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009505 u8 octet;
9506 const u8 *addr[2];
9507 size_t len[2];
9508
9509 /* {A, u, [bootstrapping info]}z */
9510 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
9511 clear = wpabuf_alloc(clear_len);
9512 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
9513#ifdef CONFIG_TESTING_OPTIONS
9514 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
9515 attr_len += 5;
9516#endif /* CONFIG_TESTING_OPTIONS */
9517 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
9518 if (!clear || !msg)
9519 goto fail;
9520
9521#ifdef CONFIG_TESTING_OPTIONS
9522 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
9523 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
9524 goto skip_bootstrap_key;
9525 }
9526 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
9527 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
9528 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9529 wpabuf_put_le16(clear, 2 * curve->prime_len);
9530 if (dpp_test_gen_invalid_key(clear, curve) < 0)
9531 goto fail;
9532 goto skip_bootstrap_key;
9533 }
9534#endif /* CONFIG_TESTING_OPTIONS */
9535
9536 /* A in Bootstrap Key attribute */
9537 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9538 wpabuf_put_le16(clear, wpabuf_len(A_pub));
9539 wpabuf_put_buf(clear, A_pub);
9540
9541#ifdef CONFIG_TESTING_OPTIONS
9542skip_bootstrap_key:
9543 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
9544 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
9545 goto skip_i_auth_tag;
9546 }
9547 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
9548 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
9549 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
9550 wpabuf_put_le16(clear, curve->hash_len);
9551 wpabuf_put_data(clear, u, curve->hash_len - 1);
9552 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
9553 goto skip_i_auth_tag;
9554 }
9555#endif /* CONFIG_TESTING_OPTIONS */
9556
9557 /* u in I-Auth tag attribute */
9558 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
9559 wpabuf_put_le16(clear, curve->hash_len);
9560 wpabuf_put_data(clear, u, curve->hash_len);
9561
9562#ifdef CONFIG_TESTING_OPTIONS
9563skip_i_auth_tag:
9564 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
9565 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
9566 goto skip_wrapped_data;
9567 }
9568#endif /* CONFIG_TESTING_OPTIONS */
9569
9570 addr[0] = wpabuf_head_u8(msg) + 2;
9571 len[0] = DPP_HDR_LEN;
9572 octet = 0;
9573 addr[1] = &octet;
9574 len[1] = sizeof(octet);
9575 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9576 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9577
9578 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
9579 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9580 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9581
9582 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
9583 if (aes_siv_encrypt(pkex->z, curve->hash_len,
9584 wpabuf_head(clear), wpabuf_len(clear),
9585 2, addr, len, wrapped) < 0)
9586 goto fail;
9587 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9588 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
9589
9590#ifdef CONFIG_TESTING_OPTIONS
9591 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
9592 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
9593 dpp_build_attr_status(msg, DPP_STATUS_OK);
9594 }
9595skip_wrapped_data:
9596#endif /* CONFIG_TESTING_OPTIONS */
9597
9598out:
9599 wpabuf_free(clear);
9600 return msg;
9601
9602fail:
9603 wpabuf_free(msg);
9604 msg = NULL;
9605 goto out;
9606}
9607
9608
9609struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
9610 const u8 *peer_mac,
9611 const u8 *buf, size_t buflen)
9612{
9613 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
9614 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
Hai Shalom81f62d82019-07-22 12:10:00 -07009615 EC_GROUP *group = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009616 BN_CTX *bnctx = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009617 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
9618 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9619 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
9620 BIGNUM *Nx = NULL, *Ny = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009621 EC_KEY *Y_ec = NULL;
9622 size_t Jx_len, Kx_len;
9623 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
9624 const u8 *addr[4];
9625 size_t len[4];
9626 u8 u[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009627 int res;
9628
Roshan Pius3a1667e2018-07-03 15:17:14 -07009629 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
9630 return NULL;
9631
9632#ifdef CONFIG_TESTING_OPTIONS
9633 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
9634 wpa_printf(MSG_INFO,
9635 "DPP: TESTING - stop at PKEX Exchange Response");
9636 pkex->failed = 1;
9637 return NULL;
9638 }
9639
9640 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
9641 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
9642 MAC2STR(dpp_pkex_peer_mac_override));
9643 peer_mac = dpp_pkex_peer_mac_override;
9644 }
9645#endif /* CONFIG_TESTING_OPTIONS */
9646
9647 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
9648
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009649 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
9650 &attr_status_len);
9651 if (!attr_status || attr_status_len != 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009652 dpp_pkex_fail(pkex, "No DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009653 return NULL;
9654 }
9655 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009656
9657 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
9658 attr_group = dpp_get_attr(buf, buflen,
9659 DPP_ATTR_FINITE_CYCLIC_GROUP,
9660 &attr_group_len);
9661 if (attr_group && attr_group_len == 2) {
9662 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9663 "Peer indicated mismatching PKEX group - proposed %u",
9664 WPA_GET_LE16(attr_group));
9665 return NULL;
9666 }
9667 }
9668
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009669 if (attr_status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009670 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009671 return NULL;
9672 }
9673
Hai Shalom74f70d42019-02-11 14:42:39 -08009674 attr_id_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009675 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
9676 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08009677 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
9678 pkex->identifier)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009679 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009680 return NULL;
9681 }
9682
9683 /* N in Encrypted Key attribute */
9684 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
9685 &attr_key_len);
9686 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009687 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009688 return NULL;
9689 }
9690
9691 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
9692 bnctx = BN_CTX_new();
9693 if (!bnctx)
9694 goto fail;
9695 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
9696 pkex->identifier, bnctx, &group);
9697 if (!Qr)
9698 goto fail;
9699
9700 /* Y' = N - Qr */
9701 Y = EC_POINT_new(group);
9702 N = EC_POINT_new(group);
9703 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
9704 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
9705 if (!Y || !N || !Nx || !Ny ||
9706 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
9707 EC_POINT_is_at_infinity(group, N) ||
9708 !EC_POINT_is_on_curve(group, N, bnctx) ||
9709 EC_POINT_invert(group, Qr, bnctx) != 1 ||
9710 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
9711 EC_POINT_is_at_infinity(group, Y) ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07009712 !EC_POINT_is_on_curve(group, Y, bnctx)) {
9713 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
9714 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009715 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009716 }
9717 dpp_debug_print_point("DPP: N", group, N);
9718 dpp_debug_print_point("DPP: Y'", group, Y);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009719
9720 pkex->exchange_done = 1;
9721
9722 /* ECDH: J = a * Y’ */
9723 Y_ec = EC_KEY_new();
9724 if (!Y_ec ||
9725 EC_KEY_set_group(Y_ec, group) != 1 ||
9726 EC_KEY_set_public_key(Y_ec, Y) != 1)
9727 goto fail;
9728 pkex->y = EVP_PKEY_new();
9729 if (!pkex->y ||
9730 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
9731 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07009732 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009733 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009734
9735 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
9736 Jx, Jx_len);
9737
9738 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
9739 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
9740 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
9741 X_pub = dpp_get_pubkey_point(pkex->x, 0);
9742 if (!A_pub || !Y_pub || !X_pub)
9743 goto fail;
9744 addr[0] = pkex->own_mac;
9745 len[0] = ETH_ALEN;
9746 addr[1] = wpabuf_head(A_pub);
9747 len[1] = wpabuf_len(A_pub) / 2;
9748 addr[2] = wpabuf_head(Y_pub);
9749 len[2] = wpabuf_len(Y_pub) / 2;
9750 addr[3] = wpabuf_head(X_pub);
9751 len[3] = wpabuf_len(X_pub) / 2;
9752 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
9753 goto fail;
9754 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
9755
9756 /* K = x * Y’ */
Hai Shalomc3565922019-10-28 11:58:20 -07009757 if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009758 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009759
9760 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
9761 Kx, Kx_len);
9762
9763 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9764 */
9765 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
9766 pkex->Mx, curve->prime_len,
9767 attr_key /* N.x */, attr_key_len / 2,
9768 pkex->code, Kx, Kx_len,
9769 pkex->z, curve->hash_len);
9770 os_memset(Kx, 0, Kx_len);
9771 if (res < 0)
9772 goto fail;
9773
Roshan Pius3a1667e2018-07-03 15:17:14 -07009774 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
9775 if (!msg)
9776 goto fail;
9777
9778out:
9779 wpabuf_free(A_pub);
9780 wpabuf_free(X_pub);
9781 wpabuf_free(Y_pub);
9782 EC_POINT_free(Qr);
9783 EC_POINT_free(Y);
9784 EC_POINT_free(N);
9785 BN_free(Nx);
9786 BN_free(Ny);
9787 EC_KEY_free(Y_ec);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009788 BN_CTX_free(bnctx);
Hai Shalom81f62d82019-07-22 12:10:00 -07009789 EC_GROUP_free(group);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009790 return msg;
9791fail:
9792 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
9793 goto out;
9794}
9795
9796
9797static struct wpabuf *
9798dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
9799 const struct wpabuf *B_pub, const u8 *v)
9800{
9801 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9802 struct wpabuf *msg = NULL;
9803 const u8 *addr[2];
9804 size_t len[2];
9805 u8 octet;
9806 u8 *wrapped;
9807 struct wpabuf *clear = NULL;
9808 size_t clear_len, attr_len;
9809
9810 /* {B, v [bootstrapping info]}z */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009811 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
9812 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009813 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
9814#ifdef CONFIG_TESTING_OPTIONS
9815 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
9816 attr_len += 5;
9817#endif /* CONFIG_TESTING_OPTIONS */
9818 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009819 if (!clear || !msg)
9820 goto fail;
9821
Roshan Pius3a1667e2018-07-03 15:17:14 -07009822#ifdef CONFIG_TESTING_OPTIONS
9823 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
9824 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
9825 goto skip_bootstrap_key;
9826 }
9827 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
9828 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
9829 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9830 wpabuf_put_le16(clear, 2 * curve->prime_len);
9831 if (dpp_test_gen_invalid_key(clear, curve) < 0)
9832 goto fail;
9833 goto skip_bootstrap_key;
9834 }
9835#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009836
Roshan Pius3a1667e2018-07-03 15:17:14 -07009837 /* B in Bootstrap Key attribute */
9838 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9839 wpabuf_put_le16(clear, wpabuf_len(B_pub));
9840 wpabuf_put_buf(clear, B_pub);
9841
9842#ifdef CONFIG_TESTING_OPTIONS
9843skip_bootstrap_key:
9844 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
9845 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
9846 goto skip_r_auth_tag;
9847 }
9848 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
9849 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
9850 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
9851 wpabuf_put_le16(clear, curve->hash_len);
9852 wpabuf_put_data(clear, v, curve->hash_len - 1);
9853 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
9854 goto skip_r_auth_tag;
9855 }
9856#endif /* CONFIG_TESTING_OPTIONS */
9857
9858 /* v in R-Auth tag attribute */
9859 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009860 wpabuf_put_le16(clear, curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009861 wpabuf_put_data(clear, v, curve->hash_len);
9862
9863#ifdef CONFIG_TESTING_OPTIONS
9864skip_r_auth_tag:
9865 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
9866 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
9867 goto skip_wrapped_data;
9868 }
9869#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009870
9871 addr[0] = wpabuf_head_u8(msg) + 2;
9872 len[0] = DPP_HDR_LEN;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009873 octet = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009874 addr[1] = &octet;
9875 len[1] = sizeof(octet);
9876 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9877 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9878
9879 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
9880 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9881 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9882
9883 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
9884 if (aes_siv_encrypt(pkex->z, curve->hash_len,
9885 wpabuf_head(clear), wpabuf_len(clear),
9886 2, addr, len, wrapped) < 0)
9887 goto fail;
9888 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9889 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
9890
Roshan Pius3a1667e2018-07-03 15:17:14 -07009891#ifdef CONFIG_TESTING_OPTIONS
9892 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
9893 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
9894 dpp_build_attr_status(msg, DPP_STATUS_OK);
9895 }
9896skip_wrapped_data:
9897#endif /* CONFIG_TESTING_OPTIONS */
9898
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009899out:
9900 wpabuf_free(clear);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009901 return msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009902
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009903fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009904 wpabuf_free(msg);
9905 msg = NULL;
9906 goto out;
9907}
9908
9909
9910struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
9911 const u8 *hdr,
9912 const u8 *buf, size_t buflen)
9913{
9914 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009915 size_t Jx_len, Lx_len;
9916 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009917 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
9918 const u8 *wrapped_data, *b_key, *peer_u;
9919 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
9920 const u8 *addr[4];
9921 size_t len[4];
9922 u8 octet;
9923 u8 *unwrapped = NULL;
9924 size_t unwrapped_len = 0;
9925 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
9926 struct wpabuf *B_pub = NULL;
9927 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009928
Roshan Pius3a1667e2018-07-03 15:17:14 -07009929#ifdef CONFIG_TESTING_OPTIONS
9930 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
9931 wpa_printf(MSG_INFO,
9932 "DPP: TESTING - stop at PKEX CR Request");
9933 pkex->failed = 1;
9934 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009935 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07009936#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009937
Roshan Pius3a1667e2018-07-03 15:17:14 -07009938 if (!pkex->exchange_done || pkex->failed ||
9939 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009940 goto fail;
9941
9942 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
9943 &wrapped_data_len);
9944 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009945 dpp_pkex_fail(pkex,
9946 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009947 goto fail;
9948 }
9949
9950 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9951 wrapped_data, wrapped_data_len);
9952 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
9953 unwrapped = os_malloc(unwrapped_len);
9954 if (!unwrapped)
9955 goto fail;
9956
9957 addr[0] = hdr;
9958 len[0] = DPP_HDR_LEN;
9959 octet = 0;
9960 addr[1] = &octet;
9961 len[1] = sizeof(octet);
9962 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9963 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9964
9965 if (aes_siv_decrypt(pkex->z, curve->hash_len,
9966 wrapped_data, wrapped_data_len,
9967 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009968 dpp_pkex_fail(pkex,
9969 "AES-SIV decryption failed - possible PKEX code mismatch");
9970 pkex->failed = 1;
9971 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009972 goto fail;
9973 }
9974 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
9975 unwrapped, unwrapped_len);
9976
9977 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009978 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009979 goto fail;
9980 }
9981
9982 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
9983 &b_key_len);
9984 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07009985 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009986 goto fail;
9987 }
9988 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
9989 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009990 if (!pkex->peer_bootstrap_key) {
9991 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009992 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009993 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009994 dpp_debug_print_key("DPP: Peer bootstrap public key",
9995 pkex->peer_bootstrap_key);
9996
9997 /* ECDH: J' = y * A' */
Hai Shalomc3565922019-10-28 11:58:20 -07009998 if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009999 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010000
10001 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
10002 Jx, Jx_len);
10003
10004 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
10005 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
10006 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
10007 X_pub = dpp_get_pubkey_point(pkex->x, 0);
10008 if (!A_pub || !Y_pub || !X_pub)
10009 goto fail;
10010 addr[0] = pkex->peer_mac;
10011 len[0] = ETH_ALEN;
10012 addr[1] = wpabuf_head(A_pub);
10013 len[1] = wpabuf_len(A_pub) / 2;
10014 addr[2] = wpabuf_head(Y_pub);
10015 len[2] = wpabuf_len(Y_pub) / 2;
10016 addr[3] = wpabuf_head(X_pub);
10017 len[3] = wpabuf_len(X_pub) / 2;
10018 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
10019 goto fail;
10020
10021 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
10022 &peer_u_len);
10023 if (!peer_u || peer_u_len != curve->hash_len ||
10024 os_memcmp(peer_u, u, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010025 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010026 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
10027 u, curve->hash_len);
10028 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010029 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010030 goto fail;
10031 }
10032 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
10033
10034 /* ECDH: L = b * X' */
Hai Shalomc3565922019-10-28 11:58:20 -070010035 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010036 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010037
10038 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
10039 Lx, Lx_len);
10040
10041 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
10042 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
10043 if (!B_pub)
10044 goto fail;
10045 addr[0] = pkex->own_mac;
10046 len[0] = ETH_ALEN;
10047 addr[1] = wpabuf_head(B_pub);
10048 len[1] = wpabuf_len(B_pub) / 2;
10049 addr[2] = wpabuf_head(X_pub);
10050 len[2] = wpabuf_len(X_pub) / 2;
10051 addr[3] = wpabuf_head(Y_pub);
10052 len[3] = wpabuf_len(Y_pub) / 2;
10053 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
10054 goto fail;
10055 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
10056
Roshan Pius3a1667e2018-07-03 15:17:14 -070010057 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
10058 if (!msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010059 goto fail;
10060
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010061out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010062 os_free(unwrapped);
10063 wpabuf_free(A_pub);
10064 wpabuf_free(B_pub);
10065 wpabuf_free(X_pub);
10066 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010067 return msg;
10068fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -070010069 wpa_printf(MSG_DEBUG,
10070 "DPP: PKEX Commit-Reveal Request processing failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010071 goto out;
10072}
10073
10074
10075int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
10076 const u8 *buf, size_t buflen)
10077{
10078 const struct dpp_curve_params *curve = pkex->own_bi->curve;
10079 const u8 *wrapped_data, *b_key, *peer_v;
10080 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
10081 const u8 *addr[4];
10082 size_t len[4];
10083 u8 octet;
10084 u8 *unwrapped = NULL;
10085 size_t unwrapped_len = 0;
10086 int ret = -1;
10087 u8 v[DPP_MAX_HASH_LEN];
10088 size_t Lx_len;
10089 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010090 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
10091
Roshan Pius3a1667e2018-07-03 15:17:14 -070010092#ifdef CONFIG_TESTING_OPTIONS
10093 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
10094 wpa_printf(MSG_INFO,
10095 "DPP: TESTING - stop at PKEX CR Response");
10096 pkex->failed = 1;
10097 goto fail;
10098 }
10099#endif /* CONFIG_TESTING_OPTIONS */
10100
10101 if (!pkex->exchange_done || pkex->failed ||
10102 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
10103 goto fail;
10104
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010105 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
10106 &wrapped_data_len);
10107 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010108 dpp_pkex_fail(pkex,
10109 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010110 goto fail;
10111 }
10112
10113 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
10114 wrapped_data, wrapped_data_len);
10115 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
10116 unwrapped = os_malloc(unwrapped_len);
10117 if (!unwrapped)
10118 goto fail;
10119
10120 addr[0] = hdr;
10121 len[0] = DPP_HDR_LEN;
10122 octet = 1;
10123 addr[1] = &octet;
10124 len[1] = sizeof(octet);
10125 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
10126 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
10127
10128 if (aes_siv_decrypt(pkex->z, curve->hash_len,
10129 wrapped_data, wrapped_data_len,
10130 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010131 dpp_pkex_fail(pkex,
10132 "AES-SIV decryption failed - possible PKEX code mismatch");
10133 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010134 goto fail;
10135 }
10136 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
10137 unwrapped, unwrapped_len);
10138
10139 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010140 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010141 goto fail;
10142 }
10143
10144 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
10145 &b_key_len);
10146 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010147 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010148 goto fail;
10149 }
10150 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
10151 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010152 if (!pkex->peer_bootstrap_key) {
10153 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010154 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -070010155 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010156 dpp_debug_print_key("DPP: Peer bootstrap public key",
10157 pkex->peer_bootstrap_key);
10158
10159 /* ECDH: L' = x * B' */
Hai Shalomc3565922019-10-28 11:58:20 -070010160 if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010161 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010162
10163 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
10164 Lx, Lx_len);
10165
10166 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
10167 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
10168 X_pub = dpp_get_pubkey_point(pkex->x, 0);
10169 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
10170 if (!B_pub || !X_pub || !Y_pub)
10171 goto fail;
10172 addr[0] = pkex->peer_mac;
10173 len[0] = ETH_ALEN;
10174 addr[1] = wpabuf_head(B_pub);
10175 len[1] = wpabuf_len(B_pub) / 2;
10176 addr[2] = wpabuf_head(X_pub);
10177 len[2] = wpabuf_len(X_pub) / 2;
10178 addr[3] = wpabuf_head(Y_pub);
10179 len[3] = wpabuf_len(Y_pub) / 2;
10180 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
10181 goto fail;
10182
10183 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
10184 &peer_v_len);
10185 if (!peer_v || peer_v_len != curve->hash_len ||
10186 os_memcmp(peer_v, v, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -070010187 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010188 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
10189 v, curve->hash_len);
10190 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010191 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010192 goto fail;
10193 }
10194 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
10195
10196 ret = 0;
10197out:
10198 wpabuf_free(B_pub);
10199 wpabuf_free(X_pub);
10200 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010201 os_free(unwrapped);
10202 return ret;
10203fail:
10204 goto out;
10205}
10206
10207
10208void dpp_pkex_free(struct dpp_pkex *pkex)
10209{
10210 if (!pkex)
10211 return;
10212
10213 os_free(pkex->identifier);
10214 os_free(pkex->code);
10215 EVP_PKEY_free(pkex->x);
10216 EVP_PKEY_free(pkex->y);
10217 EVP_PKEY_free(pkex->peer_bootstrap_key);
10218 wpabuf_free(pkex->exchange_req);
10219 wpabuf_free(pkex->exchange_resp);
10220 os_free(pkex);
10221}
Roshan Pius3a1667e2018-07-03 15:17:14 -070010222
10223
10224#ifdef CONFIG_TESTING_OPTIONS
10225char * dpp_corrupt_connector_signature(const char *connector)
10226{
10227 char *tmp, *pos, *signed3 = NULL;
10228 unsigned char *signature = NULL;
10229 size_t signature_len = 0, signed3_len;
10230
10231 tmp = os_zalloc(os_strlen(connector) + 5);
10232 if (!tmp)
10233 goto fail;
10234 os_memcpy(tmp, connector, os_strlen(connector));
10235
10236 pos = os_strchr(tmp, '.');
10237 if (!pos)
10238 goto fail;
10239
10240 pos = os_strchr(pos + 1, '.');
10241 if (!pos)
10242 goto fail;
10243 pos++;
10244
10245 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
10246 pos);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010247 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010248 if (!signature || signature_len == 0)
10249 goto fail;
10250 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
10251 signature, signature_len);
10252 signature[signature_len - 1] ^= 0x01;
10253 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
10254 signature, signature_len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010255 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010256 if (!signed3)
10257 goto fail;
10258 os_memcpy(pos, signed3, signed3_len);
10259 pos[signed3_len] = '\0';
10260 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
10261 pos);
10262
10263out:
10264 os_free(signature);
10265 os_free(signed3);
10266 return tmp;
10267fail:
10268 os_free(tmp);
10269 tmp = NULL;
10270 goto out;
10271}
10272#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom021b0b52019-04-10 11:17:58 -070010273
10274
10275#ifdef CONFIG_DPP2
10276
10277struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
10278 size_t net_access_key_len)
10279{
10280 struct wpabuf *pub = NULL;
10281 EVP_PKEY *own_key;
10282 struct dpp_pfs *pfs;
10283
10284 pfs = os_zalloc(sizeof(*pfs));
10285 if (!pfs)
10286 return NULL;
10287
10288 own_key = dpp_set_keypair(&pfs->curve, net_access_key,
10289 net_access_key_len);
10290 if (!own_key) {
10291 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
10292 goto fail;
10293 }
10294 EVP_PKEY_free(own_key);
10295
10296 pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
10297 if (!pfs->ecdh)
10298 goto fail;
10299
10300 pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
10301 pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
10302 if (!pub)
10303 goto fail;
10304
10305 pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
10306 if (!pfs->ie)
10307 goto fail;
10308 wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
10309 wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
10310 wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
10311 wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
10312 wpabuf_put_buf(pfs->ie, pub);
10313 wpabuf_free(pub);
10314 wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
10315 pfs->ie);
10316
10317 return pfs;
10318fail:
10319 wpabuf_free(pub);
10320 dpp_pfs_free(pfs);
10321 return NULL;
10322}
10323
10324
10325int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
10326{
10327 if (peer_ie_len < 2)
10328 return -1;
10329 if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
10330 wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
10331 return -1;
10332 }
10333
10334 pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
10335 peer_ie_len - 2);
10336 pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
10337 if (!pfs->secret) {
10338 wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
10339 return -1;
10340 }
10341 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
10342 return 0;
10343}
10344
10345
10346void dpp_pfs_free(struct dpp_pfs *pfs)
10347{
10348 if (!pfs)
10349 return;
10350 crypto_ecdh_deinit(pfs->ecdh);
10351 wpabuf_free(pfs->ie);
10352 wpabuf_clear_free(pfs->secret);
10353 os_free(pfs);
10354}
10355
10356#endif /* CONFIG_DPP2 */
10357
10358
10359static unsigned int dpp_next_id(struct dpp_global *dpp)
10360{
10361 struct dpp_bootstrap_info *bi;
10362 unsigned int max_id = 0;
10363
10364 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10365 if (bi->id > max_id)
10366 max_id = bi->id;
10367 }
10368 return max_id + 1;
10369}
10370
10371
10372static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
10373{
10374 struct dpp_bootstrap_info *bi, *tmp;
10375 int found = 0;
10376
10377 if (!dpp)
10378 return -1;
10379
10380 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
10381 struct dpp_bootstrap_info, list) {
10382 if (id && bi->id != id)
10383 continue;
10384 found = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -070010385#ifdef CONFIG_DPP2
10386 if (dpp->remove_bi)
10387 dpp->remove_bi(dpp->cb_ctx, bi);
10388#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070010389 dl_list_del(&bi->list);
10390 dpp_bootstrap_info_free(bi);
10391 }
10392
10393 if (id == 0)
10394 return 0; /* flush succeeds regardless of entries found */
10395 return found ? 0 : -1;
10396}
10397
10398
10399struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
10400 const char *uri)
10401{
10402 struct dpp_bootstrap_info *bi;
10403
10404 if (!dpp)
10405 return NULL;
10406
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010407 bi = dpp_parse_uri(uri);
Hai Shalom021b0b52019-04-10 11:17:58 -070010408 if (!bi)
10409 return NULL;
10410
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010411 bi->type = DPP_BOOTSTRAP_QR_CODE;
10412 bi->id = dpp_next_id(dpp);
10413 dl_list_add(&dpp->bootstrap, &bi->list);
10414 return bi;
10415}
10416
10417
10418struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
10419 const char *uri)
10420{
10421 struct dpp_bootstrap_info *bi;
10422
10423 if (!dpp)
10424 return NULL;
10425
10426 bi = dpp_parse_uri(uri);
10427 if (!bi)
10428 return NULL;
10429
10430 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -070010431 bi->id = dpp_next_id(dpp);
10432 dl_list_add(&dpp->bootstrap, &bi->list);
10433 return bi;
10434}
10435
10436
10437int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
10438{
Hai Shalomfdcde762020-04-02 11:19:20 -070010439 char *mac = NULL, *info = NULL, *curve = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -070010440 char *key = NULL;
10441 u8 *privkey = NULL;
10442 size_t privkey_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -070010443 int ret = -1;
10444 struct dpp_bootstrap_info *bi;
10445
10446 if (!dpp)
10447 return -1;
10448
10449 bi = os_zalloc(sizeof(*bi));
10450 if (!bi)
10451 goto fail;
10452
10453 if (os_strstr(cmd, "type=qrcode"))
10454 bi->type = DPP_BOOTSTRAP_QR_CODE;
10455 else if (os_strstr(cmd, "type=pkex"))
10456 bi->type = DPP_BOOTSTRAP_PKEX;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010457 else if (os_strstr(cmd, "type=nfc-uri"))
10458 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -070010459 else
10460 goto fail;
10461
Hai Shalomfdcde762020-04-02 11:19:20 -070010462 bi->chan = get_param(cmd, " chan=");
Hai Shalom021b0b52019-04-10 11:17:58 -070010463 mac = get_param(cmd, " mac=");
10464 info = get_param(cmd, " info=");
10465 curve = get_param(cmd, " curve=");
10466 key = get_param(cmd, " key=");
10467
10468 if (key) {
10469 privkey_len = os_strlen(key) / 2;
10470 privkey = os_malloc(privkey_len);
10471 if (!privkey ||
10472 hexstr2bin(key, privkey, privkey_len) < 0)
10473 goto fail;
10474 }
10475
Hai Shalomfdcde762020-04-02 11:19:20 -070010476 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
10477 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
10478 dpp_parse_uri_mac(bi, mac) < 0 ||
10479 dpp_parse_uri_info(bi, info) < 0 ||
10480 dpp_gen_uri(bi) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -070010481 goto fail;
10482
Hai Shalom021b0b52019-04-10 11:17:58 -070010483 bi->id = dpp_next_id(dpp);
10484 dl_list_add(&dpp->bootstrap, &bi->list);
10485 ret = bi->id;
10486 bi = NULL;
10487fail:
10488 os_free(curve);
Hai Shalom021b0b52019-04-10 11:17:58 -070010489 os_free(mac);
10490 os_free(info);
10491 str_clear_free(key);
10492 bin_clear_free(privkey, privkey_len);
10493 dpp_bootstrap_info_free(bi);
10494 return ret;
10495}
10496
10497
10498struct dpp_bootstrap_info *
10499dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
10500{
10501 struct dpp_bootstrap_info *bi;
10502
10503 if (!dpp)
10504 return NULL;
10505
10506 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10507 if (bi->id == id)
10508 return bi;
10509 }
10510 return NULL;
10511}
10512
10513
10514int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
10515{
10516 unsigned int id_val;
10517
10518 if (os_strcmp(id, "*") == 0) {
10519 id_val = 0;
10520 } else {
10521 id_val = atoi(id);
10522 if (id_val == 0)
10523 return -1;
10524 }
10525
10526 return dpp_bootstrap_del(dpp, id_val);
10527}
10528
10529
10530struct dpp_bootstrap_info *
10531dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
10532 unsigned int freq)
10533{
10534 struct dpp_bootstrap_info *bi;
10535
10536 bi = os_zalloc(sizeof(*bi));
10537 if (!bi)
10538 return NULL;
10539 bi->id = dpp_next_id(dpp);
10540 bi->type = DPP_BOOTSTRAP_PKEX;
10541 os_memcpy(bi->mac_addr, peer, ETH_ALEN);
10542 bi->num_freq = 1;
10543 bi->freq[0] = freq;
10544 bi->curve = pkex->own_bi->curve;
10545 bi->pubkey = pkex->peer_bootstrap_key;
10546 pkex->peer_bootstrap_key = NULL;
10547 if (dpp_bootstrap_key_hash(bi) < 0) {
10548 dpp_bootstrap_info_free(bi);
10549 return NULL;
10550 }
10551 dpp_pkex_free(pkex);
10552 dl_list_add(&dpp->bootstrap, &bi->list);
10553 return bi;
10554}
10555
10556
10557const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
10558{
10559 struct dpp_bootstrap_info *bi;
10560
10561 bi = dpp_bootstrap_get_id(dpp, id);
10562 if (!bi)
10563 return NULL;
10564 return bi->uri;
10565}
10566
10567
10568int dpp_bootstrap_info(struct dpp_global *dpp, int id,
10569 char *reply, int reply_size)
10570{
10571 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -070010572 char pkhash[2 * SHA256_MAC_LEN + 1];
Hai Shalom021b0b52019-04-10 11:17:58 -070010573
10574 bi = dpp_bootstrap_get_id(dpp, id);
10575 if (!bi)
10576 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -070010577 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
10578 SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -070010579 return os_snprintf(reply, reply_size, "type=%s\n"
10580 "mac_addr=" MACSTR "\n"
10581 "info=%s\n"
10582 "num_freq=%u\n"
Hai Shalomfdcde762020-04-02 11:19:20 -070010583 "use_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -070010584 "curve=%s\n"
10585 "pkhash=%s\n",
Hai Shalom021b0b52019-04-10 11:17:58 -070010586 dpp_bootstrap_type_txt(bi->type),
10587 MAC2STR(bi->mac_addr),
10588 bi->info ? bi->info : "",
10589 bi->num_freq,
Hai Shalomfdcde762020-04-02 11:19:20 -070010590 bi->num_freq == 1 ? bi->freq[0] : 0,
Hai Shalom81f62d82019-07-22 12:10:00 -070010591 bi->curve->name,
10592 pkhash);
Hai Shalom021b0b52019-04-10 11:17:58 -070010593}
10594
10595
Hai Shalomfdcde762020-04-02 11:19:20 -070010596int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
10597{
10598 struct dpp_bootstrap_info *bi;
10599
10600 bi = dpp_bootstrap_get_id(dpp, id);
10601 if (!bi)
10602 return -1;
10603
10604 str_clear_free(bi->configurator_params);
10605
10606 if (params) {
10607 bi->configurator_params = os_strdup(params);
10608 return bi->configurator_params ? 0 : -1;
10609 }
10610
10611 bi->configurator_params = NULL;
10612 return 0;
10613}
10614
10615
Hai Shalom021b0b52019-04-10 11:17:58 -070010616void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
10617 const u8 *r_bootstrap,
10618 struct dpp_bootstrap_info **own_bi,
10619 struct dpp_bootstrap_info **peer_bi)
10620{
10621 struct dpp_bootstrap_info *bi;
10622
10623 *own_bi = NULL;
10624 *peer_bi = NULL;
10625 if (!dpp)
10626 return;
10627
10628 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10629 if (!*own_bi && bi->own &&
10630 os_memcmp(bi->pubkey_hash, r_bootstrap,
10631 SHA256_MAC_LEN) == 0) {
10632 wpa_printf(MSG_DEBUG,
10633 "DPP: Found matching own bootstrapping information");
10634 *own_bi = bi;
10635 }
10636
10637 if (!*peer_bi && !bi->own &&
10638 os_memcmp(bi->pubkey_hash, i_bootstrap,
10639 SHA256_MAC_LEN) == 0) {
10640 wpa_printf(MSG_DEBUG,
10641 "DPP: Found matching peer bootstrapping information");
10642 *peer_bi = bi;
10643 }
10644
10645 if (*own_bi && *peer_bi)
10646 break;
10647 }
Hai Shalomfdcde762020-04-02 11:19:20 -070010648}
Hai Shalom021b0b52019-04-10 11:17:58 -070010649
Hai Shalomfdcde762020-04-02 11:19:20 -070010650
10651#ifdef CONFIG_DPP2
10652struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
10653 const u8 *hash)
10654{
10655 struct dpp_bootstrap_info *bi;
10656
10657 if (!dpp)
10658 return NULL;
10659
10660 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10661 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
10662 SHA256_MAC_LEN) == 0)
10663 return bi;
10664 }
10665
10666 return NULL;
10667}
10668#endif /* CONFIG_DPP2 */
10669
10670
10671static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
10672 struct dpp_bootstrap_info *peer_bi)
10673{
10674 unsigned int i, freq = 0;
10675 enum hostapd_hw_mode mode;
10676 u8 op_class, channel;
10677 char chan[20];
10678
10679 if (peer_bi->num_freq == 0)
10680 return 0; /* no channel preference/constraint */
10681
10682 for (i = 0; i < peer_bi->num_freq; i++) {
10683 if (own_bi->num_freq == 0 ||
10684 freq_included(own_bi->freq, own_bi->num_freq,
10685 peer_bi->freq[i])) {
10686 freq = peer_bi->freq[i];
10687 break;
10688 }
10689 }
10690 if (!freq) {
10691 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
10692 return -1;
10693 }
10694
10695 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
10696 if (mode == NUM_HOSTAPD_MODES) {
10697 wpa_printf(MSG_DEBUG,
10698 "DPP: Could not determine operating class or channel number for %u MHz",
10699 freq);
10700 }
10701
10702 wpa_printf(MSG_DEBUG,
10703 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
10704 freq, op_class, channel);
10705 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
10706 os_free(own_bi->chan);
10707 own_bi->chan = os_strdup(chan);
10708 own_bi->freq[0] = freq;
10709 own_bi->num_freq = 1;
10710 os_free(peer_bi->chan);
10711 peer_bi->chan = os_strdup(chan);
10712 peer_bi->freq[0] = freq;
10713 peer_bi->num_freq = 1;
10714
10715 return dpp_gen_uri(own_bi);
10716}
10717
10718
10719static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
10720 struct dpp_bootstrap_info *peer_bi)
10721{
10722 if (peer_bi->curve == own_bi->curve)
10723 return 0;
10724
10725 wpa_printf(MSG_DEBUG,
10726 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
10727
10728 EVP_PKEY_free(own_bi->pubkey);
10729 own_bi->pubkey = NULL;
10730
10731 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
10732 dpp_gen_uri(own_bi) < 0)
10733 goto fail;
10734
10735 return 0;
10736fail:
10737 dl_list_del(&own_bi->list);
10738 dpp_bootstrap_info_free(own_bi);
10739 return -1;
10740}
10741
10742
10743int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
10744 struct dpp_bootstrap_info *peer_bi)
10745{
10746 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
10747 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
10748 return -1;
10749 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -070010750}
10751
10752
10753static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
10754{
10755 struct dpp_configurator *conf;
10756 unsigned int max_id = 0;
10757
10758 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
10759 list) {
10760 if (conf->id > max_id)
10761 max_id = conf->id;
10762 }
10763 return max_id + 1;
10764}
10765
10766
10767int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
10768{
10769 char *curve = NULL;
10770 char *key = NULL;
10771 u8 *privkey = NULL;
10772 size_t privkey_len = 0;
10773 int ret = -1;
10774 struct dpp_configurator *conf = NULL;
10775
10776 curve = get_param(cmd, " curve=");
10777 key = get_param(cmd, " key=");
10778
10779 if (key) {
10780 privkey_len = os_strlen(key) / 2;
10781 privkey = os_malloc(privkey_len);
10782 if (!privkey ||
10783 hexstr2bin(key, privkey, privkey_len) < 0)
10784 goto fail;
10785 }
10786
10787 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
10788 if (!conf)
10789 goto fail;
10790
10791 conf->id = dpp_next_configurator_id(dpp);
10792 dl_list_add(&dpp->configurator, &conf->list);
10793 ret = conf->id;
10794 conf = NULL;
10795fail:
10796 os_free(curve);
10797 str_clear_free(key);
10798 bin_clear_free(privkey, privkey_len);
10799 dpp_configurator_free(conf);
10800 return ret;
10801}
10802
10803
10804static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
10805{
10806 struct dpp_configurator *conf, *tmp;
10807 int found = 0;
10808
10809 if (!dpp)
10810 return -1;
10811
10812 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
10813 struct dpp_configurator, list) {
10814 if (id && conf->id != id)
10815 continue;
10816 found = 1;
10817 dl_list_del(&conf->list);
10818 dpp_configurator_free(conf);
10819 }
10820
10821 if (id == 0)
10822 return 0; /* flush succeeds regardless of entries found */
10823 return found ? 0 : -1;
10824}
10825
10826
10827int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
10828{
10829 unsigned int id_val;
10830
10831 if (os_strcmp(id, "*") == 0) {
10832 id_val = 0;
10833 } else {
10834 id_val = atoi(id);
10835 if (id_val == 0)
10836 return -1;
10837 }
10838
10839 return dpp_configurator_del(dpp, id_val);
10840}
10841
10842
10843int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
10844 char *buf, size_t buflen)
10845{
10846 struct dpp_configurator *conf;
10847
10848 conf = dpp_configurator_get_id(dpp, id);
10849 if (!conf)
10850 return -1;
10851
10852 return dpp_configurator_get_key(conf, buf, buflen);
10853}
10854
10855
Hai Shalom81f62d82019-07-22 12:10:00 -070010856#ifdef CONFIG_DPP2
10857
Hai Shalomfdcde762020-04-02 11:19:20 -070010858int dpp_configurator_from_backup(struct dpp_global *dpp,
10859 struct dpp_asymmetric_key *key)
10860{
10861 struct dpp_configurator *conf;
10862 const EC_KEY *eckey;
10863 const EC_GROUP *group;
10864 int nid;
10865 const struct dpp_curve_params *curve;
10866
10867 if (!key->csign)
10868 return -1;
10869 eckey = EVP_PKEY_get0_EC_KEY(key->csign);
10870 if (!eckey)
10871 return -1;
10872 group = EC_KEY_get0_group(eckey);
10873 if (!group)
10874 return -1;
10875 nid = EC_GROUP_get_curve_name(group);
10876 curve = dpp_get_curve_nid(nid);
10877 if (!curve) {
10878 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
10879 return -1;
10880 }
10881
10882 conf = os_zalloc(sizeof(*conf));
10883 if (!conf)
10884 return -1;
10885 conf->curve = curve;
10886 conf->csign = key->csign;
10887 key->csign = NULL;
10888 conf->own = 1;
10889 if (dpp_configurator_gen_kid(conf) < 0) {
10890 dpp_configurator_free(conf);
10891 return -1;
10892 }
10893
10894 conf->id = dpp_next_configurator_id(dpp);
10895 dl_list_add(&dpp->configurator, &conf->list);
10896 return conf->id;
10897}
10898
10899
Hai Shalomc3565922019-10-28 11:58:20 -070010900static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
10901 void *timeout_ctx);
10902
10903
Hai Shalom81f62d82019-07-22 12:10:00 -070010904static void dpp_connection_free(struct dpp_connection *conn)
10905{
10906 if (conn->sock >= 0) {
10907 wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
10908 conn->sock);
10909 eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
10910 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
10911 close(conn->sock);
10912 }
Hai Shalomc3565922019-10-28 11:58:20 -070010913 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
10914 conn, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070010915 wpabuf_free(conn->msg);
10916 wpabuf_free(conn->msg_out);
10917 dpp_auth_deinit(conn->auth);
10918 os_free(conn);
10919}
10920
10921
10922static void dpp_connection_remove(struct dpp_connection *conn)
10923{
10924 dl_list_del(&conn->list);
10925 dpp_connection_free(conn);
10926}
10927
10928
10929static void dpp_tcp_init_flush(struct dpp_global *dpp)
10930{
10931 struct dpp_connection *conn, *tmp;
10932
10933 dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
10934 list)
10935 dpp_connection_remove(conn);
10936}
10937
10938
10939static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
10940{
10941 struct dpp_connection *conn, *tmp;
10942
10943 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
10944 list)
10945 dpp_connection_remove(conn);
10946 os_free(ctrl);
10947}
10948
10949
10950static void dpp_relay_flush_controllers(struct dpp_global *dpp)
10951{
10952 struct dpp_relay_controller *ctrl, *tmp;
10953
10954 if (!dpp)
10955 return;
10956
10957 dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
10958 struct dpp_relay_controller, list) {
10959 dl_list_del(&ctrl->list);
10960 dpp_relay_controller_free(ctrl);
10961 }
10962}
10963
10964#endif /* CONFIG_DPP2 */
10965
10966
10967struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -070010968{
10969 struct dpp_global *dpp;
10970
10971 dpp = os_zalloc(sizeof(*dpp));
10972 if (!dpp)
10973 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -070010974 dpp->msg_ctx = config->msg_ctx;
10975#ifdef CONFIG_DPP2
10976 dpp->cb_ctx = config->cb_ctx;
10977 dpp->process_conf_obj = config->process_conf_obj;
Hai Shalomfdcde762020-04-02 11:19:20 -070010978 dpp->remove_bi = config->remove_bi;
Hai Shalom81f62d82019-07-22 12:10:00 -070010979#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070010980
10981 dl_list_init(&dpp->bootstrap);
10982 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -070010983#ifdef CONFIG_DPP2
10984 dl_list_init(&dpp->controllers);
10985 dl_list_init(&dpp->tcp_init);
10986#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070010987
10988 return dpp;
10989}
10990
10991
10992void dpp_global_clear(struct dpp_global *dpp)
10993{
10994 if (!dpp)
10995 return;
10996
10997 dpp_bootstrap_del(dpp, 0);
10998 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -070010999#ifdef CONFIG_DPP2
11000 dpp_tcp_init_flush(dpp);
11001 dpp_relay_flush_controllers(dpp);
11002 dpp_controller_stop(dpp);
11003#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -070011004}
11005
11006
11007void dpp_global_deinit(struct dpp_global *dpp)
11008{
11009 dpp_global_clear(dpp);
11010 os_free(dpp);
11011}
Hai Shalom81f62d82019-07-22 12:10:00 -070011012
11013
11014#ifdef CONFIG_DPP2
11015
11016static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
11017static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
11018static void dpp_controller_auth_success(struct dpp_connection *conn,
11019 int initiator);
11020
11021
11022int dpp_relay_add_controller(struct dpp_global *dpp,
11023 struct dpp_relay_config *config)
11024{
11025 struct dpp_relay_controller *ctrl;
11026
11027 if (!dpp)
11028 return -1;
11029
11030 ctrl = os_zalloc(sizeof(*ctrl));
11031 if (!ctrl)
11032 return -1;
11033 dl_list_init(&ctrl->conn);
11034 ctrl->global = dpp;
11035 os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
11036 os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
11037 ctrl->cb_ctx = config->cb_ctx;
11038 ctrl->tx = config->tx;
11039 ctrl->gas_resp_tx = config->gas_resp_tx;
11040 dl_list_add(&dpp->controllers, &ctrl->list);
11041 return 0;
11042}
11043
11044
11045static struct dpp_relay_controller *
11046dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
11047{
11048 struct dpp_relay_controller *ctrl;
11049
11050 if (!dpp)
11051 return NULL;
11052
11053 dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
11054 list) {
11055 if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
11056 return ctrl;
11057 }
11058
11059 return NULL;
11060}
11061
11062
11063static void dpp_controller_gas_done(struct dpp_connection *conn)
11064{
11065 struct dpp_authentication *auth = conn->auth;
11066
11067 if (auth->peer_version >= 2 &&
11068 auth->conf_resp_status == DPP_STATUS_OK) {
11069 wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
11070 auth->waiting_conf_result = 1;
11071 return;
11072 }
11073
11074 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
11075 dpp_connection_remove(conn);
11076}
11077
11078
11079static int dpp_tcp_send(struct dpp_connection *conn)
11080{
11081 int res;
11082
11083 if (!conn->msg_out) {
11084 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
11085 conn->write_eloop = 0;
11086 return -1;
11087 }
11088 res = send(conn->sock,
11089 wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
11090 wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
11091 if (res < 0) {
11092 wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
11093 strerror(errno));
11094 dpp_connection_remove(conn);
11095 return -1;
11096 }
11097
11098 conn->msg_out_pos += res;
11099 if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
11100 wpa_printf(MSG_DEBUG,
11101 "DPP: %u/%u bytes of message sent to Controller",
11102 (unsigned int) conn->msg_out_pos,
11103 (unsigned int) wpabuf_len(conn->msg_out));
11104 if (!conn->write_eloop &&
11105 eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11106 dpp_conn_tx_ready, conn, NULL) == 0)
11107 conn->write_eloop = 1;
11108 return 1;
11109 }
11110
11111 wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
11112 wpabuf_free(conn->msg_out);
11113 conn->msg_out = NULL;
11114 conn->msg_out_pos = 0;
11115 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
11116 conn->write_eloop = 0;
11117 if (!conn->read_eloop &&
11118 eloop_register_sock(conn->sock, EVENT_TYPE_READ,
11119 dpp_controller_rx, conn, NULL) == 0)
11120 conn->read_eloop = 1;
11121 if (conn->on_tcp_tx_complete_remove) {
11122 dpp_connection_remove(conn);
11123 } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
11124 conn->auth) {
11125 dpp_controller_gas_done(conn);
11126 } else if (conn->on_tcp_tx_complete_auth_ok) {
11127 conn->on_tcp_tx_complete_auth_ok = 0;
11128 dpp_controller_auth_success(conn, 1);
11129 }
11130
11131 return 0;
11132}
11133
11134
Hai Shalomfdcde762020-04-02 11:19:20 -070011135static int dpp_tcp_send_msg(struct dpp_connection *conn,
11136 const struct wpabuf *msg)
11137{
11138 wpabuf_free(conn->msg_out);
11139 conn->msg_out_pos = 0;
11140 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
11141 if (!conn->msg_out)
11142 return -1;
11143 wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
11144 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
11145 wpabuf_len(msg) - 1);
11146
11147 if (dpp_tcp_send(conn) == 1) {
11148 if (!conn->write_eloop) {
11149 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11150 dpp_conn_tx_ready,
11151 conn, NULL) < 0)
11152 return -1;
11153 conn->write_eloop = 1;
11154 }
11155 }
11156
11157 return 0;
11158}
11159
11160
Hai Shalom81f62d82019-07-22 12:10:00 -070011161static void dpp_controller_start_gas_client(struct dpp_connection *conn)
11162{
11163 struct dpp_authentication *auth = conn->auth;
11164 struct wpabuf *buf;
Hai Shalom81f62d82019-07-22 12:10:00 -070011165 int netrole_ap = 0; /* TODO: make this configurable */
11166
Hai Shalomc3565922019-10-28 11:58:20 -070011167 buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070011168 if (!buf) {
11169 wpa_printf(MSG_DEBUG,
11170 "DPP: No configuration request data available");
11171 return;
11172 }
11173
Hai Shalomfdcde762020-04-02 11:19:20 -070011174 dpp_tcp_send_msg(conn, buf);
Hai Shalom81f62d82019-07-22 12:10:00 -070011175 wpabuf_free(buf);
Hai Shalom81f62d82019-07-22 12:10:00 -070011176}
11177
11178
11179static void dpp_controller_auth_success(struct dpp_connection *conn,
11180 int initiator)
11181{
11182 struct dpp_authentication *auth = conn->auth;
11183
11184 if (!auth)
11185 return;
11186
11187 wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
11188 wpa_msg(conn->global->msg_ctx, MSG_INFO,
11189 DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
11190#ifdef CONFIG_TESTING_OPTIONS
11191 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
11192 wpa_printf(MSG_INFO,
11193 "DPP: TESTING - stop at Authentication Confirm");
11194 if (auth->configurator) {
11195 /* Prevent GAS response */
11196 auth->auth_success = 0;
11197 }
11198 return;
11199 }
11200#endif /* CONFIG_TESTING_OPTIONS */
11201
11202 if (!auth->configurator)
11203 dpp_controller_start_gas_client(conn);
11204}
11205
11206
11207static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
11208{
11209 struct dpp_connection *conn = eloop_ctx;
11210
11211 wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
11212 dpp_tcp_send(conn);
11213}
11214
11215
11216static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
11217 const struct hostapd_ip_addr *ipaddr,
11218 int port)
11219{
11220 struct sockaddr_in *dst;
11221#ifdef CONFIG_IPV6
11222 struct sockaddr_in6 *dst6;
11223#endif /* CONFIG_IPV6 */
11224
11225 switch (ipaddr->af) {
11226 case AF_INET:
11227 dst = (struct sockaddr_in *) addr;
11228 os_memset(dst, 0, sizeof(*dst));
11229 dst->sin_family = AF_INET;
11230 dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
11231 dst->sin_port = htons(port);
11232 *addrlen = sizeof(*dst);
11233 break;
11234#ifdef CONFIG_IPV6
11235 case AF_INET6:
11236 dst6 = (struct sockaddr_in6 *) addr;
11237 os_memset(dst6, 0, sizeof(*dst6));
11238 dst6->sin6_family = AF_INET6;
11239 os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
11240 sizeof(struct in6_addr));
11241 dst6->sin6_port = htons(port);
11242 *addrlen = sizeof(*dst6);
11243 break;
11244#endif /* CONFIG_IPV6 */
11245 default:
11246 return -1;
11247 }
11248
11249 return 0;
11250}
11251
11252
11253static struct dpp_connection *
11254dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
11255 unsigned int freq)
11256{
11257 struct dpp_connection *conn;
11258 struct sockaddr_storage addr;
11259 socklen_t addrlen;
11260 char txt[100];
11261
11262 if (dl_list_len(&ctrl->conn) >= 15) {
11263 wpa_printf(MSG_DEBUG,
11264 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
11265 return NULL;
11266 }
11267
11268 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
11269 &ctrl->ipaddr, DPP_TCP_PORT) < 0)
11270 return NULL;
11271
11272 conn = os_zalloc(sizeof(*conn));
11273 if (!conn)
11274 return NULL;
11275
11276 conn->global = ctrl->global;
11277 conn->relay = ctrl;
11278 os_memcpy(conn->mac_addr, src, ETH_ALEN);
11279 conn->freq = freq;
11280
11281 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
11282 if (conn->sock < 0)
11283 goto fail;
11284 wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
11285 conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
11286
11287 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
11288 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
11289 strerror(errno));
11290 goto fail;
11291 }
11292
11293 if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
11294 if (errno != EINPROGRESS) {
11295 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
11296 strerror(errno));
11297 goto fail;
11298 }
11299
11300 /*
11301 * Continue connecting in the background; eloop will call us
11302 * once the connection is ready (or failed).
11303 */
11304 }
11305
11306 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11307 dpp_conn_tx_ready, conn, NULL) < 0)
11308 goto fail;
11309 conn->write_eloop = 1;
11310
11311 /* TODO: eloop timeout to clear a connection if it does not complete
11312 * properly */
11313
11314 dl_list_add(&ctrl->conn, &conn->list);
11315 return conn;
11316fail:
11317 dpp_connection_free(conn);
11318 return NULL;
11319}
11320
11321
11322static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
11323{
11324 struct wpabuf *msg;
11325
11326 msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
11327 if (!msg)
11328 return NULL;
11329 wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
11330 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
11331 wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
11332 wpabuf_put_data(msg, buf, len);
11333 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
11334 return msg;
11335}
11336
11337
11338static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
11339 const u8 *buf, size_t len)
11340{
11341 u8 type = hdr[DPP_HDR_LEN - 1];
11342
11343 wpa_printf(MSG_DEBUG,
11344 "DPP: Continue already established Relay/Controller connection for this session");
11345 wpabuf_free(conn->msg_out);
11346 conn->msg_out_pos = 0;
11347 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
11348 if (!conn->msg_out) {
11349 dpp_connection_remove(conn);
11350 return -1;
11351 }
11352
11353 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
11354 * TX status */
11355 if (type == DPP_PA_CONFIGURATION_RESULT)
11356 conn->on_tcp_tx_complete_remove = 1;
11357 dpp_tcp_send(conn);
11358 return 0;
11359}
11360
11361
11362int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
11363 const u8 *buf, size_t len, unsigned int freq,
11364 const u8 *i_bootstrap, const u8 *r_bootstrap)
11365{
11366 struct dpp_relay_controller *ctrl;
11367 struct dpp_connection *conn;
11368 u8 type = hdr[DPP_HDR_LEN - 1];
11369
11370 /* Check if there is an already started session for this peer and if so,
11371 * continue that session (send this over TCP) and return 0.
11372 */
11373 if (type != DPP_PA_PEER_DISCOVERY_REQ &&
Hai Shalomfdcde762020-04-02 11:19:20 -070011374 type != DPP_PA_PEER_DISCOVERY_RESP &&
11375 type != DPP_PA_PRESENCE_ANNOUNCEMENT) {
Hai Shalom81f62d82019-07-22 12:10:00 -070011376 dl_list_for_each(ctrl, &dpp->controllers,
11377 struct dpp_relay_controller, list) {
11378 dl_list_for_each(conn, &ctrl->conn,
11379 struct dpp_connection, list) {
11380 if (os_memcmp(src, conn->mac_addr,
11381 ETH_ALEN) == 0)
11382 return dpp_relay_tx(conn, hdr, buf, len);
11383 }
11384 }
11385 }
11386
11387 if (!r_bootstrap)
11388 return -1;
11389
Hai Shalomfdcde762020-04-02 11:19:20 -070011390 if (type == DPP_PA_PRESENCE_ANNOUNCEMENT) {
11391 /* TODO: Could send this to all configured Controllers. For now,
11392 * only the first Controller is supported. */
11393 ctrl = dl_list_first(&dpp->controllers,
11394 struct dpp_relay_controller, list);
11395 } else {
11396 ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
11397 }
Hai Shalom81f62d82019-07-22 12:10:00 -070011398 if (!ctrl)
11399 return -1;
11400
11401 wpa_printf(MSG_DEBUG,
11402 "DPP: Authentication Request for a configured Controller");
11403 conn = dpp_relay_new_conn(ctrl, src, freq);
11404 if (!conn)
11405 return -1;
11406
11407 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
11408 if (!conn->msg_out) {
11409 dpp_connection_remove(conn);
11410 return -1;
11411 }
11412 /* Message will be sent in dpp_conn_tx_ready() */
11413
11414 return 0;
11415}
11416
11417
11418int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
11419 size_t data_len)
11420{
11421 struct dpp_relay_controller *ctrl;
11422 struct dpp_connection *conn, *found = NULL;
11423 struct wpabuf *msg;
11424
11425 /* Check if there is a successfully completed authentication for this
11426 * and if so, continue that session (send this over TCP) and return 0.
11427 */
11428 dl_list_for_each(ctrl, &dpp->controllers,
11429 struct dpp_relay_controller, list) {
11430 if (found)
11431 break;
11432 dl_list_for_each(conn, &ctrl->conn,
11433 struct dpp_connection, list) {
11434 if (os_memcmp(src, conn->mac_addr,
11435 ETH_ALEN) == 0) {
11436 found = conn;
11437 break;
11438 }
11439 }
11440 }
11441
11442 if (!found)
11443 return -1;
11444
11445 msg = wpabuf_alloc(4 + 1 + data_len);
11446 if (!msg)
11447 return -1;
11448 wpabuf_put_be32(msg, 1 + data_len);
11449 wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
11450 wpabuf_put_data(msg, data, data_len);
11451 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
11452
11453 wpabuf_free(conn->msg_out);
11454 conn->msg_out_pos = 0;
11455 conn->msg_out = msg;
11456 dpp_tcp_send(conn);
11457 return 0;
11458}
11459
11460
11461static void dpp_controller_free(struct dpp_controller *ctrl)
11462{
11463 struct dpp_connection *conn, *tmp;
11464
11465 if (!ctrl)
11466 return;
11467
11468 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
11469 list)
11470 dpp_connection_remove(conn);
11471
11472 if (ctrl->sock >= 0) {
11473 close(ctrl->sock);
11474 eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
11475 }
11476 os_free(ctrl->configurator_params);
11477 os_free(ctrl);
11478}
11479
11480
11481static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
11482 const u8 *hdr, const u8 *buf, size_t len)
11483{
11484 const u8 *r_bootstrap, *i_bootstrap;
11485 u16 r_bootstrap_len, i_bootstrap_len;
11486 struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
11487
11488 if (!conn->ctrl)
11489 return 0;
11490
11491 wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
11492
11493 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
11494 &r_bootstrap_len);
11495 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
11496 wpa_printf(MSG_INFO,
11497 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11498 return -1;
11499 }
11500 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
11501 r_bootstrap, r_bootstrap_len);
11502
11503 i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
11504 &i_bootstrap_len);
11505 if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
11506 wpa_printf(MSG_INFO,
11507 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
11508 return -1;
11509 }
11510 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
11511 i_bootstrap, i_bootstrap_len);
11512
11513 /* Try to find own and peer bootstrapping key matches based on the
11514 * received hash values */
11515 dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
11516 &own_bi, &peer_bi);
11517 if (!own_bi) {
11518 wpa_printf(MSG_INFO,
11519 "No matching own bootstrapping key found - ignore message");
11520 return -1;
11521 }
11522
11523 if (conn->auth) {
11524 wpa_printf(MSG_INFO,
11525 "Already in DPP authentication exchange - ignore new one");
11526 return 0;
11527 }
11528
Hai Shalomfdcde762020-04-02 11:19:20 -070011529 conn->auth = dpp_auth_req_rx(conn->ctrl->global,
11530 conn->ctrl->global->msg_ctx,
Hai Shalom81f62d82019-07-22 12:10:00 -070011531 conn->ctrl->allowed_roles,
11532 conn->ctrl->qr_mutual,
11533 peer_bi, own_bi, -1, hdr, buf, len);
11534 if (!conn->auth) {
11535 wpa_printf(MSG_DEBUG, "DPP: No response generated");
11536 return -1;
11537 }
11538
Hai Shalomfdcde762020-04-02 11:19:20 -070011539 if (dpp_set_configurator(conn->auth,
Hai Shalom81f62d82019-07-22 12:10:00 -070011540 conn->ctrl->configurator_params) < 0) {
11541 dpp_connection_remove(conn);
11542 return -1;
11543 }
11544
Hai Shalomfdcde762020-04-02 11:19:20 -070011545 return dpp_tcp_send_msg(conn, conn->auth->resp_msg);
Hai Shalom81f62d82019-07-22 12:10:00 -070011546}
11547
11548
11549static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
11550 const u8 *hdr, const u8 *buf, size_t len)
11551{
11552 struct dpp_authentication *auth = conn->auth;
11553 struct wpabuf *msg;
Hai Shalomfdcde762020-04-02 11:19:20 -070011554 int res;
Hai Shalom81f62d82019-07-22 12:10:00 -070011555
11556 if (!auth)
11557 return -1;
11558
11559 wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
11560
11561 msg = dpp_auth_resp_rx(auth, hdr, buf, len);
11562 if (!msg) {
11563 if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
11564 wpa_printf(MSG_DEBUG,
11565 "DPP: Start wait for full response");
11566 return -1;
11567 }
11568 wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
11569 dpp_connection_remove(conn);
11570 return -1;
11571 }
11572
Hai Shalom81f62d82019-07-22 12:10:00 -070011573 conn->on_tcp_tx_complete_auth_ok = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -070011574 res = dpp_tcp_send_msg(conn, msg);
11575 wpabuf_free(msg);
11576 return res;
Hai Shalom81f62d82019-07-22 12:10:00 -070011577}
11578
11579
11580static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
11581 const u8 *hdr, const u8 *buf, size_t len)
11582{
11583 struct dpp_authentication *auth = conn->auth;
11584
11585 wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
11586
11587 if (!auth) {
11588 wpa_printf(MSG_DEBUG,
11589 "DPP: No DPP Authentication in progress - drop");
11590 return -1;
11591 }
11592
11593 if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
11594 wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
11595 return -1;
11596 }
11597
11598 dpp_controller_auth_success(conn, 0);
11599 return 0;
11600}
11601
11602
Hai Shalomc3565922019-10-28 11:58:20 -070011603static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
11604 void *timeout_ctx)
11605{
11606 struct dpp_connection *conn = eloop_ctx;
11607
11608 if (!conn->auth->waiting_conf_result)
11609 return;
11610
11611 wpa_printf(MSG_DEBUG,
11612 "DPP: Timeout while waiting for Connection Status Result");
11613 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11614 DPP_EVENT_CONN_STATUS_RESULT "timeout");
11615 dpp_connection_remove(conn);
11616}
11617
11618
Hai Shalom81f62d82019-07-22 12:10:00 -070011619static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
11620 const u8 *hdr, const u8 *buf,
11621 size_t len)
11622{
11623 struct dpp_authentication *auth = conn->auth;
11624 enum dpp_status_error status;
11625
11626 if (!conn->ctrl)
11627 return 0;
11628
11629 wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
11630
11631 if (!auth || !auth->waiting_conf_result) {
11632 wpa_printf(MSG_DEBUG,
11633 "DPP: No DPP Configuration waiting for result - drop");
11634 return -1;
11635 }
11636
11637 status = dpp_conf_result_rx(auth, hdr, buf, len);
Hai Shalomc3565922019-10-28 11:58:20 -070011638 if (status == DPP_STATUS_OK && auth->send_conn_status) {
11639 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11640 DPP_EVENT_CONF_SENT "wait_conn_status=1");
11641 wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
11642 eloop_cancel_timeout(
11643 dpp_controller_conn_status_result_wait_timeout,
11644 conn, NULL);
11645 eloop_register_timeout(
11646 16, 0, dpp_controller_conn_status_result_wait_timeout,
11647 conn, NULL);
11648 return 0;
11649 }
Hai Shalom81f62d82019-07-22 12:10:00 -070011650 if (status == DPP_STATUS_OK)
11651 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11652 DPP_EVENT_CONF_SENT);
11653 else
11654 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11655 DPP_EVENT_CONF_FAILED);
11656 return -1; /* to remove the completed connection */
11657}
11658
11659
Hai Shalomc3565922019-10-28 11:58:20 -070011660static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
11661 const u8 *hdr, const u8 *buf,
11662 size_t len)
11663{
11664 struct dpp_authentication *auth = conn->auth;
11665 enum dpp_status_error status;
11666 u8 ssid[SSID_MAX_LEN];
11667 size_t ssid_len = 0;
11668 char *channel_list = NULL;
11669
11670 if (!conn->ctrl)
11671 return 0;
11672
11673 wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
11674
11675 if (!auth || !auth->waiting_conn_status_result) {
11676 wpa_printf(MSG_DEBUG,
11677 "DPP: No DPP Configuration waiting for connection status result - drop");
11678 return -1;
11679 }
11680
11681 status = dpp_conn_status_result_rx(auth, hdr, buf, len,
11682 ssid, &ssid_len, &channel_list);
11683 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11684 DPP_EVENT_CONN_STATUS_RESULT
11685 "result=%d ssid=%s channel_list=%s",
11686 status, wpa_ssid_txt(ssid, ssid_len),
11687 channel_list ? channel_list : "N/A");
11688 os_free(channel_list);
11689 return -1; /* to remove the completed connection */
11690}
11691
11692
Hai Shalomfdcde762020-04-02 11:19:20 -070011693static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
11694 const u8 *hdr, const u8 *buf,
11695 size_t len)
11696{
11697 const u8 *r_bootstrap;
11698 u16 r_bootstrap_len;
11699 struct dpp_bootstrap_info *peer_bi;
11700 struct dpp_authentication *auth;
11701 struct dpp_global *dpp = conn->ctrl->global;
11702
11703 if (conn->auth) {
11704 wpa_printf(MSG_DEBUG,
11705 "DPP: Ignore Presence Announcement during ongoing Authentication");
11706 return -1;
11707 }
11708
11709 wpa_printf(MSG_DEBUG, "DPP: Presence Announcement");
11710
11711 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
11712 &r_bootstrap_len);
11713 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
11714 wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
11715 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11716 return -1;
11717 }
11718 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
11719 r_bootstrap, r_bootstrap_len);
11720 peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap);
11721 if (!peer_bi) {
11722 wpa_printf(MSG_DEBUG,
11723 "DPP: No matching bootstrapping information found");
11724 return -1;
11725 }
11726
11727 auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL,
11728 DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
11729 if (!auth)
11730 return -1;
11731 if (dpp_set_configurator(conn->auth,
11732 conn->ctrl->configurator_params) < 0) {
11733 dpp_auth_deinit(auth);
11734 dpp_connection_remove(conn);
11735 return -1;
11736 }
11737
11738 conn->auth = auth;
11739 return dpp_tcp_send_msg(conn, conn->auth->req_msg);
11740}
11741
11742
Hai Shalom81f62d82019-07-22 12:10:00 -070011743static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
11744 size_t len)
11745{
11746 const u8 *pos, *end;
11747 u8 type;
11748
11749 wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
11750 pos = msg;
11751 end = msg + len;
11752
11753 if (end - pos < DPP_HDR_LEN ||
11754 WPA_GET_BE24(pos) != OUI_WFA ||
11755 pos[3] != DPP_OUI_TYPE) {
11756 wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
11757 return -1;
11758 }
11759
11760 if (pos[4] != 1) {
11761 wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
11762 pos[4]);
11763 return -1;
11764 }
11765 type = pos[5];
11766 wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
11767 pos += DPP_HDR_LEN;
11768
11769 wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
11770 pos, end - pos);
11771 if (dpp_check_attrs(pos, end - pos) < 0)
11772 return -1;
11773
11774 if (conn->relay) {
11775 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
11776 conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
11777 conn->freq, msg, len);
11778 return 0;
11779 }
11780
11781 switch (type) {
11782 case DPP_PA_AUTHENTICATION_REQ:
11783 return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
11784 case DPP_PA_AUTHENTICATION_RESP:
11785 return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
11786 case DPP_PA_AUTHENTICATION_CONF:
11787 return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
11788 case DPP_PA_CONFIGURATION_RESULT:
11789 return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
Hai Shalomc3565922019-10-28 11:58:20 -070011790 case DPP_PA_CONNECTION_STATUS_RESULT:
11791 return dpp_controller_rx_conn_status_result(conn, msg, pos,
11792 end - pos);
Hai Shalomfdcde762020-04-02 11:19:20 -070011793 case DPP_PA_PRESENCE_ANNOUNCEMENT:
11794 return dpp_controller_rx_presence_announcement(conn, msg, pos,
11795 end - pos);
Hai Shalom81f62d82019-07-22 12:10:00 -070011796 default:
11797 /* TODO: missing messages types */
11798 wpa_printf(MSG_DEBUG,
11799 "DPP: Unsupported frame subtype %d", type);
11800 return -1;
11801 }
11802}
11803
11804
11805static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
11806 size_t len)
11807{
11808 const u8 *pos, *end, *next;
11809 u8 dialog_token;
11810 const u8 *adv_proto;
11811 u16 slen;
11812 struct wpabuf *resp, *buf;
11813 struct dpp_authentication *auth = conn->auth;
11814
11815 if (len < 1 + 2)
11816 return -1;
11817
11818 wpa_printf(MSG_DEBUG,
11819 "DPP: Received DPP Configuration Request over TCP");
11820
11821 if (!conn->ctrl || !auth || !auth->auth_success) {
11822 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
11823 return -1;
11824 }
11825
11826 pos = msg;
11827 end = msg + len;
11828
11829 dialog_token = *pos++;
11830 adv_proto = pos++;
11831 slen = *pos++;
11832 if (*adv_proto != WLAN_EID_ADV_PROTO ||
11833 slen > end - pos || slen < 2)
11834 return -1;
11835
11836 next = pos + slen;
11837 pos++; /* skip QueryRespLenLimit and PAME-BI */
11838
11839 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
11840 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
11841 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
11842 return -1;
11843
11844 pos = next;
11845 /* Query Request */
11846 if (end - pos < 2)
11847 return -1;
11848 slen = WPA_GET_LE16(pos);
11849 pos += 2;
11850 if (slen > end - pos)
11851 return -1;
11852
11853 resp = dpp_conf_req_rx(auth, pos, slen);
11854 if (!resp)
11855 return -1;
11856
11857 buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
11858 if (!buf) {
11859 wpabuf_free(resp);
11860 return -1;
11861 }
11862
11863 wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
11864
11865 wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
11866 wpabuf_put_u8(buf, dialog_token);
11867 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
11868 wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
11869
11870 dpp_write_adv_proto(buf);
11871 dpp_write_gas_query(buf, resp);
11872 wpabuf_free(resp);
11873
11874 /* Send Config Response over TCP; GAS fragmentation is taken care of by
11875 * the Relay */
11876 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
11877 wpabuf_free(conn->msg_out);
11878 conn->msg_out_pos = 0;
11879 conn->msg_out = buf;
11880 conn->on_tcp_tx_complete_gas_done = 1;
11881 dpp_tcp_send(conn);
11882 return 0;
11883}
11884
11885
11886static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
11887{
11888 struct dpp_authentication *auth = conn->auth;
11889 int res;
Hai Shalomfdcde762020-04-02 11:19:20 -070011890 struct wpabuf *msg;
Hai Shalom81f62d82019-07-22 12:10:00 -070011891 enum dpp_status_error status;
11892
11893 wpa_printf(MSG_DEBUG,
11894 "DPP: Configuration Response for local stack from TCP");
11895
11896 res = dpp_conf_resp_rx(auth, resp);
11897 wpabuf_free(resp);
11898 if (res < 0) {
11899 wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
11900 return -1;
11901 }
11902
11903 if (conn->global->process_conf_obj)
11904 res = conn->global->process_conf_obj(conn->global->cb_ctx,
11905 auth);
11906 else
11907 res = 0;
11908
11909 if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
11910 return -1;
11911
11912 wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
11913 status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
11914 msg = dpp_build_conf_result(auth, status);
11915 if (!msg)
11916 return -1;
11917
Hai Shalom81f62d82019-07-22 12:10:00 -070011918 conn->on_tcp_tx_complete_remove = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -070011919 res = dpp_tcp_send_msg(conn, msg);
11920 wpabuf_free(msg);
Hai Shalom81f62d82019-07-22 12:10:00 -070011921
11922 /* This exchange will be terminated in the TX status handler */
11923
Hai Shalomfdcde762020-04-02 11:19:20 -070011924 return res;
Hai Shalom81f62d82019-07-22 12:10:00 -070011925}
11926
11927
11928static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
11929 size_t len)
11930{
11931 struct wpabuf *buf;
11932 u8 dialog_token;
11933 const u8 *pos, *end, *next, *adv_proto;
11934 u16 status, slen;
11935
11936 if (len < 5 + 2)
11937 return -1;
11938
11939 wpa_printf(MSG_DEBUG,
11940 "DPP: Received DPP Configuration Response over TCP");
11941
11942 pos = msg;
11943 end = msg + len;
11944
11945 dialog_token = *pos++;
11946 status = WPA_GET_LE16(pos);
11947 if (status != WLAN_STATUS_SUCCESS) {
11948 wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
11949 return -1;
11950 }
11951 pos += 2;
11952 pos += 2; /* ignore GAS Comeback Delay */
11953
11954 adv_proto = pos++;
11955 slen = *pos++;
11956 if (*adv_proto != WLAN_EID_ADV_PROTO ||
11957 slen > end - pos || slen < 2)
11958 return -1;
11959
11960 next = pos + slen;
11961 pos++; /* skip QueryRespLenLimit and PAME-BI */
11962
11963 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
11964 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
11965 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
11966 return -1;
11967
11968 pos = next;
11969 /* Query Response */
11970 if (end - pos < 2)
11971 return -1;
11972 slen = WPA_GET_LE16(pos);
11973 pos += 2;
11974 if (slen > end - pos)
11975 return -1;
11976
11977 buf = wpabuf_alloc(slen);
11978 if (!buf)
11979 return -1;
11980 wpabuf_put_data(buf, pos, slen);
11981
11982 if (!conn->relay && !conn->ctrl)
11983 return dpp_tcp_rx_gas_resp(conn, buf);
11984
11985 if (!conn->relay) {
11986 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
11987 wpabuf_free(buf);
11988 return -1;
11989 }
11990 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
11991 conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
11992 dialog_token, 0, buf);
11993
11994 return 0;
11995}
11996
11997
11998static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
11999{
12000 struct dpp_connection *conn = eloop_ctx;
12001 int res;
12002 const u8 *pos;
12003
12004 wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
12005 sd);
12006
12007 if (conn->msg_len_octets < 4) {
12008 u32 msglen;
12009
12010 res = recv(sd, &conn->msg_len[conn->msg_len_octets],
12011 4 - conn->msg_len_octets, 0);
12012 if (res < 0) {
12013 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
12014 strerror(errno));
12015 dpp_connection_remove(conn);
12016 return;
12017 }
12018 if (res == 0) {
12019 wpa_printf(MSG_DEBUG,
12020 "DPP: No more data available over TCP");
12021 dpp_connection_remove(conn);
12022 return;
12023 }
12024 wpa_printf(MSG_DEBUG,
12025 "DPP: Received %d/%d octet(s) of message length field",
12026 res, (int) (4 - conn->msg_len_octets));
12027 conn->msg_len_octets += res;
12028
12029 if (conn->msg_len_octets < 4) {
12030 wpa_printf(MSG_DEBUG,
12031 "DPP: Need %d more octets of message length field",
12032 (int) (4 - conn->msg_len_octets));
12033 return;
12034 }
12035
12036 msglen = WPA_GET_BE32(conn->msg_len);
12037 wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
12038 if (msglen > 65535) {
12039 wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
12040 dpp_connection_remove(conn);
12041 return;
12042 }
12043
12044 wpabuf_free(conn->msg);
12045 conn->msg = wpabuf_alloc(msglen);
12046 }
12047
12048 if (!conn->msg) {
12049 wpa_printf(MSG_DEBUG,
12050 "DPP: No buffer available for receiving the message");
12051 dpp_connection_remove(conn);
12052 return;
12053 }
12054
12055 wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
12056 (unsigned int) wpabuf_tailroom(conn->msg));
12057
12058 res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
12059 if (res < 0) {
12060 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
12061 dpp_connection_remove(conn);
12062 return;
12063 }
12064 if (res == 0) {
12065 wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
12066 dpp_connection_remove(conn);
12067 return;
12068 }
12069 wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
12070 wpabuf_put(conn->msg, res);
12071
12072 if (wpabuf_tailroom(conn->msg) > 0) {
12073 wpa_printf(MSG_DEBUG,
12074 "DPP: Need %u more octets of message payload",
12075 (unsigned int) wpabuf_tailroom(conn->msg));
12076 return;
12077 }
12078
12079 conn->msg_len_octets = 0;
12080 wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
12081 if (wpabuf_len(conn->msg) < 1) {
12082 dpp_connection_remove(conn);
12083 return;
12084 }
12085
12086 pos = wpabuf_head(conn->msg);
12087 switch (*pos) {
12088 case WLAN_PA_VENDOR_SPECIFIC:
12089 if (dpp_controller_rx_action(conn, pos + 1,
12090 wpabuf_len(conn->msg) - 1) < 0)
12091 dpp_connection_remove(conn);
12092 break;
12093 case WLAN_PA_GAS_INITIAL_REQ:
12094 if (dpp_controller_rx_gas_req(conn, pos + 1,
12095 wpabuf_len(conn->msg) - 1) < 0)
12096 dpp_connection_remove(conn);
12097 break;
12098 case WLAN_PA_GAS_INITIAL_RESP:
12099 if (dpp_rx_gas_resp(conn, pos + 1,
12100 wpabuf_len(conn->msg) - 1) < 0)
12101 dpp_connection_remove(conn);
12102 break;
12103 default:
12104 wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
12105 *pos);
12106 break;
12107 }
12108}
12109
12110
12111static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
12112{
12113 struct dpp_controller *ctrl = eloop_ctx;
12114 struct sockaddr_in addr;
12115 socklen_t addr_len = sizeof(addr);
12116 int fd;
12117 struct dpp_connection *conn;
12118
12119 wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
12120
12121 fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
12122 if (fd < 0) {
12123 wpa_printf(MSG_DEBUG,
12124 "DPP: Failed to accept new connection: %s",
12125 strerror(errno));
12126 return;
12127 }
12128 wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
12129 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
12130
12131 conn = os_zalloc(sizeof(*conn));
12132 if (!conn)
12133 goto fail;
12134
12135 conn->global = ctrl->global;
12136 conn->ctrl = ctrl;
12137 conn->sock = fd;
12138
12139 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
12140 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
12141 strerror(errno));
12142 goto fail;
12143 }
12144
12145 if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
12146 dpp_controller_rx, conn, NULL) < 0)
12147 goto fail;
12148 conn->read_eloop = 1;
12149
12150 /* TODO: eloop timeout to expire connections that do not complete in
12151 * reasonable time */
12152 dl_list_add(&ctrl->conn, &conn->list);
12153 return;
12154
12155fail:
12156 close(fd);
12157 os_free(conn);
12158}
12159
12160
12161int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
12162 const struct hostapd_ip_addr *addr, int port)
12163{
12164 struct dpp_connection *conn;
12165 struct sockaddr_storage saddr;
12166 socklen_t addrlen;
12167 const u8 *hdr, *pos, *end;
12168 char txt[100];
12169
12170 wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
12171 hostapd_ip_txt(addr, txt, sizeof(txt)), port);
12172 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
12173 addr, port) < 0) {
12174 dpp_auth_deinit(auth);
12175 return -1;
12176 }
12177
12178 conn = os_zalloc(sizeof(*conn));
12179 if (!conn) {
12180 dpp_auth_deinit(auth);
12181 return -1;
12182 }
12183
12184 conn->global = dpp;
12185 conn->auth = auth;
12186 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
12187 if (conn->sock < 0)
12188 goto fail;
12189
12190 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
12191 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
12192 strerror(errno));
12193 goto fail;
12194 }
12195
12196 if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
12197 if (errno != EINPROGRESS) {
12198 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
12199 strerror(errno));
12200 goto fail;
12201 }
12202
12203 /*
12204 * Continue connecting in the background; eloop will call us
12205 * once the connection is ready (or failed).
12206 */
12207 }
12208
12209 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
12210 dpp_conn_tx_ready, conn, NULL) < 0)
12211 goto fail;
12212 conn->write_eloop = 1;
12213
12214 hdr = wpabuf_head(auth->req_msg);
12215 end = hdr + wpabuf_len(auth->req_msg);
12216 hdr += 2; /* skip Category and Actiom */
12217 pos = hdr + DPP_HDR_LEN;
12218 conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
12219 if (!conn->msg_out)
12220 goto fail;
12221 /* Message will be sent in dpp_conn_tx_ready() */
12222
12223 /* TODO: eloop timeout to clear a connection if it does not complete
12224 * properly */
12225 dl_list_add(&dpp->tcp_init, &conn->list);
12226 return 0;
12227fail:
12228 dpp_connection_free(conn);
12229 return -1;
12230}
12231
12232
12233int dpp_controller_start(struct dpp_global *dpp,
12234 struct dpp_controller_config *config)
12235{
12236 struct dpp_controller *ctrl;
12237 int on = 1;
12238 struct sockaddr_in sin;
12239 int port;
12240
12241 if (!dpp || dpp->controller)
12242 return -1;
12243
12244 ctrl = os_zalloc(sizeof(*ctrl));
12245 if (!ctrl)
12246 return -1;
12247 ctrl->global = dpp;
12248 if (config->configurator_params)
12249 ctrl->configurator_params =
12250 os_strdup(config->configurator_params);
12251 dl_list_init(&ctrl->conn);
12252 /* TODO: configure these somehow */
12253 ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
12254 ctrl->qr_mutual = 0;
12255
12256 ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
12257 if (ctrl->sock < 0)
12258 goto fail;
12259
12260 if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
12261 &on, sizeof(on)) < 0) {
12262 wpa_printf(MSG_DEBUG,
12263 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
12264 strerror(errno));
12265 /* try to continue anyway */
12266 }
12267
12268 if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
12269 wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
12270 strerror(errno));
12271 goto fail;
12272 }
12273
12274 /* TODO: IPv6 */
12275 os_memset(&sin, 0, sizeof(sin));
12276 sin.sin_family = AF_INET;
12277 sin.sin_addr.s_addr = INADDR_ANY;
12278 port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
12279 sin.sin_port = htons(port);
12280 if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
12281 wpa_printf(MSG_INFO,
12282 "DPP: Failed to bind Controller TCP port: %s",
12283 strerror(errno));
12284 goto fail;
12285 }
12286 if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
12287 fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
12288 eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
12289 dpp_controller_tcp_cb, ctrl, NULL))
12290 goto fail;
12291
12292 dpp->controller = ctrl;
12293 wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
12294 return 0;
12295fail:
12296 dpp_controller_free(ctrl);
12297 return -1;
12298}
12299
12300
12301void dpp_controller_stop(struct dpp_global *dpp)
12302{
12303 if (dpp) {
12304 dpp_controller_free(dpp->controller);
12305 dpp->controller = NULL;
12306 }
12307}
12308
Hai Shalomfdcde762020-04-02 11:19:20 -070012309
12310struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
12311{
12312 struct wpabuf *msg;
12313
12314 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
12315
12316 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
12317 if (!msg)
12318 return NULL;
12319
12320 /* Responder Bootstrapping Key Hash */
12321 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
12322 wpa_hexdump_buf(MSG_DEBUG,
12323 "DPP: Presence Announcement frame attributes", msg);
12324 return msg;
12325}
12326
Hai Shalom81f62d82019-07-22 12:10:00 -070012327#endif /* CONFIG_DPP2 */