blob: 49de476973846797f81332f38ceba7457e20cb2a [file] [log] [blame]
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001/*
2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
Hai Shalom021b0b52019-04-10 11:17:58 -07004 * Copyright (c) 2018-2019, The Linux Foundation
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "utils/includes.h"
11#include <openssl/opensslv.h>
12#include <openssl/err.h>
Roshan Pius3a1667e2018-07-03 15:17:14 -070013#include <openssl/asn1.h>
14#include <openssl/asn1t.h>
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070015
16#include "utils/common.h"
17#include "utils/base64.h"
18#include "utils/json.h"
19#include "common/ieee802_11_common.h"
20#include "common/ieee802_11_defs.h"
21#include "common/wpa_ctrl.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070022#include "common/gas.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070023#include "crypto/crypto.h"
24#include "crypto/random.h"
25#include "crypto/aes.h"
26#include "crypto/aes_siv.h"
27#include "crypto/sha384.h"
28#include "crypto/sha512.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070029#include "drivers/driver.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070030#include "dpp.h"
31
32
Roshan Pius3a1667e2018-07-03 15:17:14 -070033#ifdef CONFIG_TESTING_OPTIONS
34enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
35u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
36u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
37u8 dpp_pkex_ephemeral_key_override[600];
38size_t dpp_pkex_ephemeral_key_override_len = 0;
39u8 dpp_protocol_key_override[600];
40size_t dpp_protocol_key_override_len = 0;
41u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
42size_t dpp_nonce_override_len = 0;
43
44static int dpp_test_gen_invalid_key(struct wpabuf *msg,
45 const struct dpp_curve_params *curve);
46#endif /* CONFIG_TESTING_OPTIONS */
47
48#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
49 (defined(LIBRESSL_VERSION_NUMBER) && \
50 LIBRESSL_VERSION_NUMBER < 0x20700000L)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070051/* Compatibility wrappers for older versions. */
52
53static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
54{
55 sig->r = r;
56 sig->s = s;
57 return 1;
58}
59
60
61static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
62 const BIGNUM **ps)
63{
64 if (pr)
65 *pr = sig->r;
66 if (ps)
67 *ps = sig->s;
68}
69
70#endif
71
72
Hai Shalom021b0b52019-04-10 11:17:58 -070073struct dpp_global {
74 struct dl_list bootstrap; /* struct dpp_bootstrap_info */
75 struct dl_list configurator; /* struct dpp_configurator */
76};
77
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070078static const struct dpp_curve_params dpp_curves[] = {
79 /* The mandatory to support and the default NIST P-256 curve needs to
80 * be the first entry on this list. */
81 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
82 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
83 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
84 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
85 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
86 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
87 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
88};
89
90
91/* Role-specific elements for PKEX */
92
93/* NIST P-256 */
94static const u8 pkex_init_x_p256[32] = {
95 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
96 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
97 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
98 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
99 };
100static const u8 pkex_init_y_p256[32] = {
101 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
102 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
103 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
104 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
105 };
106static const u8 pkex_resp_x_p256[32] = {
107 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
108 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
109 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
110 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
111};
112static const u8 pkex_resp_y_p256[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700113 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
114 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
115 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
116 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700117};
118
119/* NIST P-384 */
120static const u8 pkex_init_x_p384[48] = {
121 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
122 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
123 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
124 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
125 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
126 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
127};
128static const u8 pkex_init_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700129 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
130 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
131 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
132 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
133 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
134 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700135};
136static const u8 pkex_resp_x_p384[48] = {
137 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
138 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
139 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
140 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
141 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
142 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
143};
144static const u8 pkex_resp_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700145 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
146 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
147 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
148 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
149 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
150 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700151};
152
153/* NIST P-521 */
154static const u8 pkex_init_x_p521[66] = {
155 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
156 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
157 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
158 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
159 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
160 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
161 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
162 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
163 0x97, 0x76
164};
165static const u8 pkex_init_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700166 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
167 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
168 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
169 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
170 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
171 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
172 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
173 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
174 0x03, 0xa8
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700175};
176static const u8 pkex_resp_x_p521[66] = {
177 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
178 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
179 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
180 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
181 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
182 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
183 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
184 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
185 0x84, 0xb4
186};
187static const u8 pkex_resp_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700188 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
189 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
190 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
191 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
192 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
193 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
194 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
195 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
196 0xce, 0xe1
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700197};
198
199/* Brainpool P-256r1 */
200static const u8 pkex_init_x_bp_p256r1[32] = {
201 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
202 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
203 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
204 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
205};
206static const u8 pkex_init_y_bp_p256r1[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700207 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
208 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
209 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
210 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700211};
212static const u8 pkex_resp_x_bp_p256r1[32] = {
213 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
214 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
215 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
216 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
217};
218static const u8 pkex_resp_y_bp_p256r1[32] = {
219 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
220 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
221 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
222 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
223};
224
225/* Brainpool P-384r1 */
226static const u8 pkex_init_x_bp_p384r1[48] = {
227 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
228 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
229 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
230 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
231 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
232 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
233};
234static const u8 pkex_init_y_bp_p384r1[48] = {
235 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
236 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
237 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
238 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
239 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
240 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
241};
242static const u8 pkex_resp_x_bp_p384r1[48] = {
243 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
244 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
245 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
246 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
247 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
248 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
249};
250static const u8 pkex_resp_y_bp_p384r1[48] = {
251 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
252 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
253 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
254 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
255 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
256 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
257};
258
259/* Brainpool P-512r1 */
260static const u8 pkex_init_x_bp_p512r1[64] = {
261 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
262 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
263 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
264 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
265 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
266 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
267 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
268 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
269};
270static const u8 pkex_init_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700271 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
272 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
273 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
274 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
275 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
276 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
277 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
278 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700279};
280static const u8 pkex_resp_x_bp_p512r1[64] = {
281 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
282 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
283 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
284 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
285 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
286 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
287 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
288 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
289};
290static const u8 pkex_resp_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700291 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
292 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
293 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
294 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
295 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
296 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
297 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
298 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700299};
300
301
Roshan Pius3a1667e2018-07-03 15:17:14 -0700302static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
303 const EC_POINT *point)
304{
305 BIGNUM *x, *y;
306 BN_CTX *ctx;
307 char *x_str = NULL, *y_str = NULL;
308
309 if (!wpa_debug_show_keys)
310 return;
311
312 ctx = BN_CTX_new();
313 x = BN_new();
314 y = BN_new();
315 if (!ctx || !x || !y ||
316 EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
317 goto fail;
318
319 x_str = BN_bn2hex(x);
320 y_str = BN_bn2hex(y);
321 if (!x_str || !y_str)
322 goto fail;
323
324 wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
325
326fail:
327 OPENSSL_free(x_str);
328 OPENSSL_free(y_str);
329 BN_free(x);
330 BN_free(y);
331 BN_CTX_free(ctx);
332}
333
334
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700335static int dpp_hash_vector(const struct dpp_curve_params *curve,
336 size_t num_elem, const u8 *addr[], const size_t *len,
337 u8 *mac)
338{
339 if (curve->hash_len == 32)
340 return sha256_vector(num_elem, addr, len, mac);
341 if (curve->hash_len == 48)
342 return sha384_vector(num_elem, addr, len, mac);
343 if (curve->hash_len == 64)
344 return sha512_vector(num_elem, addr, len, mac);
345 return -1;
346}
347
348
349static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
350 const char *label, u8 *out, size_t outlen)
351{
352 if (hash_len == 32)
353 return hmac_sha256_kdf(secret, secret_len, NULL,
354 (const u8 *) label, os_strlen(label),
355 out, outlen);
356 if (hash_len == 48)
357 return hmac_sha384_kdf(secret, secret_len, NULL,
358 (const u8 *) label, os_strlen(label),
359 out, outlen);
360 if (hash_len == 64)
361 return hmac_sha512_kdf(secret, secret_len, NULL,
362 (const u8 *) label, os_strlen(label),
363 out, outlen);
364 return -1;
365}
366
367
368static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
369 size_t num_elem, const u8 *addr[],
370 const size_t *len, u8 *mac)
371{
372 if (hash_len == 32)
373 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
374 mac);
375 if (hash_len == 48)
376 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
377 mac);
378 if (hash_len == 64)
379 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
380 mac);
381 return -1;
382}
383
384
385static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
386 const u8 *data, size_t data_len, u8 *mac)
387{
388 if (hash_len == 32)
389 return hmac_sha256(key, key_len, data, data_len, mac);
390 if (hash_len == 48)
391 return hmac_sha384(key, key_len, data, data_len, mac);
392 if (hash_len == 64)
393 return hmac_sha512(key, key_len, data, data_len, mac);
394 return -1;
395}
396
397
Roshan Pius3a1667e2018-07-03 15:17:14 -0700398static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
399{
400 int num_bytes, offset;
401
402 num_bytes = BN_num_bytes(bn);
403 if ((size_t) num_bytes > len)
404 return -1;
405 offset = len - num_bytes;
406 os_memset(pos, 0, offset);
407 BN_bn2bin(bn, pos + offset);
408 return 0;
409}
410
411
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700412static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
413{
414 int len, res;
415 EC_KEY *eckey;
416 struct wpabuf *buf;
417 unsigned char *pos;
418
419 eckey = EVP_PKEY_get1_EC_KEY(pkey);
420 if (!eckey)
421 return NULL;
422 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
423 len = i2o_ECPublicKey(eckey, NULL);
424 if (len <= 0) {
425 wpa_printf(MSG_ERROR,
426 "DDP: Failed to determine public key encoding length");
427 EC_KEY_free(eckey);
428 return NULL;
429 }
430
431 buf = wpabuf_alloc(len);
432 if (!buf) {
433 EC_KEY_free(eckey);
434 return NULL;
435 }
436
437 pos = wpabuf_put(buf, len);
438 res = i2o_ECPublicKey(eckey, &pos);
439 EC_KEY_free(eckey);
440 if (res != len) {
441 wpa_printf(MSG_ERROR,
442 "DDP: Failed to encode public key (res=%d/%d)",
443 res, len);
444 wpabuf_free(buf);
445 return NULL;
446 }
447
448 if (!prefix) {
449 /* Remove 0x04 prefix to match DPP definition */
450 pos = wpabuf_mhead(buf);
451 os_memmove(pos, pos + 1, len - 1);
452 buf->used--;
453 }
454
455 return buf;
456}
457
458
459static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
460 const u8 *buf_x, const u8 *buf_y,
461 size_t len)
462{
463 EC_KEY *eckey = NULL;
464 BN_CTX *ctx;
465 EC_POINT *point = NULL;
466 BIGNUM *x = NULL, *y = NULL;
467 EVP_PKEY *pkey = NULL;
468
469 ctx = BN_CTX_new();
470 if (!ctx) {
471 wpa_printf(MSG_ERROR, "DPP: Out of memory");
472 return NULL;
473 }
474
475 point = EC_POINT_new(group);
476 x = BN_bin2bn(buf_x, len, NULL);
477 y = BN_bin2bn(buf_y, len, NULL);
478 if (!point || !x || !y) {
479 wpa_printf(MSG_ERROR, "DPP: Out of memory");
480 goto fail;
481 }
482
483 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
484 wpa_printf(MSG_ERROR,
485 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
486 ERR_error_string(ERR_get_error(), NULL));
487 goto fail;
488 }
489
490 if (!EC_POINT_is_on_curve(group, point, ctx) ||
491 EC_POINT_is_at_infinity(group, point)) {
492 wpa_printf(MSG_ERROR, "DPP: Invalid point");
493 goto fail;
494 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700495 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700496
497 eckey = EC_KEY_new();
498 if (!eckey ||
499 EC_KEY_set_group(eckey, group) != 1 ||
500 EC_KEY_set_public_key(eckey, point) != 1) {
501 wpa_printf(MSG_ERROR,
502 "DPP: Failed to set EC_KEY: %s",
503 ERR_error_string(ERR_get_error(), NULL));
504 goto fail;
505 }
506 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
507
508 pkey = EVP_PKEY_new();
509 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
510 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
511 goto fail;
512 }
513
514out:
515 BN_free(x);
516 BN_free(y);
517 EC_KEY_free(eckey);
518 EC_POINT_free(point);
519 BN_CTX_free(ctx);
520 return pkey;
521fail:
522 EVP_PKEY_free(pkey);
523 pkey = NULL;
524 goto out;
525}
526
527
528static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
529 const u8 *buf, size_t len)
530{
531 EC_KEY *eckey;
532 const EC_GROUP *group;
533 EVP_PKEY *pkey = NULL;
534
535 if (len & 1)
536 return NULL;
537
538 eckey = EVP_PKEY_get1_EC_KEY(group_key);
539 if (!eckey) {
540 wpa_printf(MSG_ERROR,
541 "DPP: Could not get EC_KEY from group_key");
542 return NULL;
543 }
544
545 group = EC_KEY_get0_group(eckey);
546 if (group)
547 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
548 len / 2);
549 else
550 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
551
552 EC_KEY_free(eckey);
553 return pkey;
554}
555
556
Roshan Pius3a1667e2018-07-03 15:17:14 -0700557static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
558{
559 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
560}
561
562
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700563struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
564 size_t len)
565{
566 struct wpabuf *msg;
567
568 msg = wpabuf_alloc(8 + len);
569 if (!msg)
570 return NULL;
571 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
572 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
573 wpabuf_put_be24(msg, OUI_WFA);
574 wpabuf_put_u8(msg, DPP_OUI_TYPE);
575 wpabuf_put_u8(msg, 1); /* Crypto Suite */
576 wpabuf_put_u8(msg, type);
577 return msg;
578}
579
580
581const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
582{
583 u16 id, alen;
584 const u8 *pos = buf, *end = buf + len;
585
586 while (end - pos >= 4) {
587 id = WPA_GET_LE16(pos);
588 pos += 2;
589 alen = WPA_GET_LE16(pos);
590 pos += 2;
591 if (alen > end - pos)
592 return NULL;
593 if (id == req_id) {
594 *ret_len = alen;
595 return pos;
596 }
597 pos += alen;
598 }
599
600 return NULL;
601}
602
603
604int dpp_check_attrs(const u8 *buf, size_t len)
605{
606 const u8 *pos, *end;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700607 int wrapped_data = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700608
609 pos = buf;
610 end = buf + len;
611 while (end - pos >= 4) {
612 u16 id, alen;
613
614 id = WPA_GET_LE16(pos);
615 pos += 2;
616 alen = WPA_GET_LE16(pos);
617 pos += 2;
618 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
619 id, alen);
620 if (alen > end - pos) {
621 wpa_printf(MSG_DEBUG,
622 "DPP: Truncated message - not enough room for the attribute - dropped");
623 return -1;
624 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700625 if (wrapped_data) {
626 wpa_printf(MSG_DEBUG,
627 "DPP: An unexpected attribute included after the Wrapped Data attribute");
628 return -1;
629 }
630 if (id == DPP_ATTR_WRAPPED_DATA)
631 wrapped_data = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700632 pos += alen;
633 }
634
635 if (end != pos) {
636 wpa_printf(MSG_DEBUG,
637 "DPP: Unexpected octets (%d) after the last attribute",
638 (int) (end - pos));
639 return -1;
640 }
641
642 return 0;
643}
644
645
646void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
647{
648 if (!info)
649 return;
650 os_free(info->uri);
651 os_free(info->info);
652 EVP_PKEY_free(info->pubkey);
653 os_free(info);
654}
655
656
657const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
658{
659 switch (type) {
660 case DPP_BOOTSTRAP_QR_CODE:
661 return "QRCODE";
662 case DPP_BOOTSTRAP_PKEX:
663 return "PKEX";
664 }
665 return "??";
666}
667
668
669static int dpp_uri_valid_info(const char *info)
670{
671 while (*info) {
672 unsigned char val = *info++;
673
674 if (val < 0x20 || val > 0x7e || val == 0x3b)
675 return 0;
676 }
677
678 return 1;
679}
680
681
682static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
683{
684 bi->uri = os_strdup(uri);
685 return bi->uri ? 0 : -1;
686}
687
688
689int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
690 const char *chan_list)
691{
Hai Shalomf1c97642019-07-19 23:42:07 +0000692 const char *pos = chan_list;
693 int opclass, channel, freq;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700694
695 while (pos && *pos && *pos != ';') {
Hai Shalomf1c97642019-07-19 23:42:07 +0000696 opclass = atoi(pos);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700697 if (opclass <= 0)
698 goto fail;
Hai Shalomf1c97642019-07-19 23:42:07 +0000699 pos = os_strchr(pos, '/');
700 if (!pos)
701 goto fail;
702 pos++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700703 channel = atoi(pos);
704 if (channel <= 0)
705 goto fail;
706 while (*pos >= '0' && *pos <= '9')
707 pos++;
708 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
709 wpa_printf(MSG_DEBUG,
710 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
711 opclass, channel, freq);
712 if (freq < 0) {
713 wpa_printf(MSG_DEBUG,
714 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
715 opclass, channel);
716 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
717 wpa_printf(MSG_DEBUG,
718 "DPP: Too many channels in URI channel-list - ignore list");
719 bi->num_freq = 0;
720 break;
721 } else {
722 bi->freq[bi->num_freq++] = freq;
723 }
724
725 if (*pos == ';' || *pos == '\0')
726 break;
727 if (*pos != ',')
728 goto fail;
729 pos++;
730 }
731
732 return 0;
733fail:
734 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
735 return -1;
736}
737
738
739int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
740{
741 if (!mac)
742 return 0;
743
744 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
745 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
746 return -1;
747 }
748
749 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
750
751 return 0;
752}
753
754
755int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
756{
757 const char *end;
758
759 if (!info)
760 return 0;
761
762 end = os_strchr(info, ';');
763 if (!end)
764 end = info + os_strlen(info);
765 bi->info = os_malloc(end - info + 1);
766 if (!bi->info)
767 return -1;
768 os_memcpy(bi->info, info, end - info);
769 bi->info[end - info] = '\0';
770 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
771 if (!dpp_uri_valid_info(bi->info)) {
772 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
773 return -1;
774 }
775
776 return 0;
777}
778
779
780static const struct dpp_curve_params *
781dpp_get_curve_oid(const ASN1_OBJECT *poid)
782{
783 ASN1_OBJECT *oid;
784 int i;
785
786 for (i = 0; dpp_curves[i].name; i++) {
787 oid = OBJ_txt2obj(dpp_curves[i].name, 0);
788 if (oid && OBJ_cmp(poid, oid) == 0)
789 return &dpp_curves[i];
790 }
791 return NULL;
792}
793
794
795static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
796{
797 int i, tmp;
798
799 if (!nid)
800 return NULL;
801 for (i = 0; dpp_curves[i].name; i++) {
802 tmp = OBJ_txt2nid(dpp_curves[i].name);
803 if (tmp == nid)
804 return &dpp_curves[i];
805 }
806 return NULL;
807}
808
809
810static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
811{
812 const char *end;
813 u8 *data;
814 size_t data_len;
815 EVP_PKEY *pkey;
816 const unsigned char *p;
817 int res;
818 X509_PUBKEY *pub = NULL;
819 ASN1_OBJECT *ppkalg;
820 const unsigned char *pk;
821 int ppklen;
822 X509_ALGOR *pa;
Hai Shalom74f70d42019-02-11 14:42:39 -0800823#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
824 (defined(LIBRESSL_VERSION_NUMBER) && \
825 LIBRESSL_VERSION_NUMBER < 0x20800000L)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700826 ASN1_OBJECT *pa_oid;
827#else
828 const ASN1_OBJECT *pa_oid;
829#endif
830 const void *pval;
831 int ptype;
832 const ASN1_OBJECT *poid;
833 char buf[100];
834
835 end = os_strchr(info, ';');
836 if (!end)
837 return -1;
838
839 data = base64_decode((const unsigned char *) info, end - info,
840 &data_len);
841 if (!data) {
842 wpa_printf(MSG_DEBUG,
843 "DPP: Invalid base64 encoding on URI public-key");
844 return -1;
845 }
846 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
847 data, data_len);
848
849 if (sha256_vector(1, (const u8 **) &data, &data_len,
850 bi->pubkey_hash) < 0) {
851 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800852 os_free(data);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700853 return -1;
854 }
855 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
856 bi->pubkey_hash, SHA256_MAC_LEN);
857
858 /* DER encoded ASN.1 SubjectPublicKeyInfo
859 *
860 * SubjectPublicKeyInfo ::= SEQUENCE {
861 * algorithm AlgorithmIdentifier,
862 * subjectPublicKey BIT STRING }
863 *
864 * AlgorithmIdentifier ::= SEQUENCE {
865 * algorithm OBJECT IDENTIFIER,
866 * parameters ANY DEFINED BY algorithm OPTIONAL }
867 *
868 * subjectPublicKey = compressed format public key per ANSI X9.63
869 * algorithm = ecPublicKey (1.2.840.10045.2.1)
870 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
871 * prime256v1 (1.2.840.10045.3.1.7)
872 */
873
874 p = data;
875 pkey = d2i_PUBKEY(NULL, &p, data_len);
876 os_free(data);
877
878 if (!pkey) {
879 wpa_printf(MSG_DEBUG,
880 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
881 return -1;
882 }
883
884 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
885 wpa_printf(MSG_DEBUG,
886 "DPP: SubjectPublicKeyInfo does not describe an EC key");
887 EVP_PKEY_free(pkey);
888 return -1;
889 }
890
891 res = X509_PUBKEY_set(&pub, pkey);
892 if (res != 1) {
893 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
894 goto fail;
895 }
896
897 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
898 if (res != 1) {
899 wpa_printf(MSG_DEBUG,
900 "DPP: Could not extract SubjectPublicKeyInfo parameters");
901 goto fail;
902 }
903 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
904 if (res < 0 || (size_t) res >= sizeof(buf)) {
905 wpa_printf(MSG_DEBUG,
906 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
907 goto fail;
908 }
909 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
910 if (os_strcmp(buf, "id-ecPublicKey") != 0) {
911 wpa_printf(MSG_DEBUG,
912 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
913 goto fail;
914 }
915
916 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
917 if (ptype != V_ASN1_OBJECT) {
918 wpa_printf(MSG_DEBUG,
919 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
920 goto fail;
921 }
922 poid = pval;
923 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
924 if (res < 0 || (size_t) res >= sizeof(buf)) {
925 wpa_printf(MSG_DEBUG,
926 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
927 goto fail;
928 }
929 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
930 bi->curve = dpp_get_curve_oid(poid);
931 if (!bi->curve) {
932 wpa_printf(MSG_DEBUG,
933 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
934 buf);
935 goto fail;
936 }
937
938 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
939
940 X509_PUBKEY_free(pub);
941 bi->pubkey = pkey;
942 return 0;
943fail:
944 X509_PUBKEY_free(pub);
945 EVP_PKEY_free(pkey);
946 return -1;
947}
948
949
950static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
951{
952 const char *pos = uri;
953 const char *end;
954 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
955 struct dpp_bootstrap_info *bi;
956
957 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
958
959 if (os_strncmp(pos, "DPP:", 4) != 0) {
960 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
961 return NULL;
962 }
963 pos += 4;
964
965 for (;;) {
966 end = os_strchr(pos, ';');
967 if (!end)
968 break;
969
970 if (end == pos) {
971 /* Handle terminating ";;" and ignore unexpected ";"
972 * for parsing robustness. */
973 pos++;
974 continue;
975 }
976
977 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
978 chan_list = pos + 2;
979 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
980 mac = pos + 2;
981 else if (pos[0] == 'I' && pos[1] == ':' && !info)
982 info = pos + 2;
983 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
984 pk = pos + 2;
985 else
986 wpa_hexdump_ascii(MSG_DEBUG,
987 "DPP: Ignore unrecognized URI parameter",
988 pos, end - pos);
989 pos = end + 1;
990 }
991
992 if (!pk) {
993 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
994 return NULL;
995 }
996
997 bi = os_zalloc(sizeof(*bi));
998 if (!bi)
999 return NULL;
1000
1001 if (dpp_clone_uri(bi, uri) < 0 ||
1002 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
1003 dpp_parse_uri_mac(bi, mac) < 0 ||
1004 dpp_parse_uri_info(bi, info) < 0 ||
1005 dpp_parse_uri_pk(bi, pk) < 0) {
1006 dpp_bootstrap_info_free(bi);
1007 bi = NULL;
1008 }
1009
1010 return bi;
1011}
1012
1013
1014struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
1015{
1016 struct dpp_bootstrap_info *bi;
1017
1018 bi = dpp_parse_uri(uri);
1019 if (bi)
1020 bi->type = DPP_BOOTSTRAP_QR_CODE;
1021 return bi;
1022}
1023
1024
1025static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
1026{
1027 EC_KEY *eckey;
1028 BIO *out;
1029 size_t rlen;
1030 char *txt;
1031 int res;
1032 unsigned char *der = NULL;
1033 int der_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001034 const EC_GROUP *group;
1035 const EC_POINT *point;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001036
1037 out = BIO_new(BIO_s_mem());
1038 if (!out)
1039 return;
1040
1041 EVP_PKEY_print_private(out, key, 0, NULL);
1042 rlen = BIO_ctrl_pending(out);
1043 txt = os_malloc(rlen + 1);
1044 if (txt) {
1045 res = BIO_read(out, txt, rlen);
1046 if (res > 0) {
1047 txt[res] = '\0';
1048 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
1049 }
1050 os_free(txt);
1051 }
1052 BIO_free(out);
1053
1054 eckey = EVP_PKEY_get1_EC_KEY(key);
1055 if (!eckey)
1056 return;
1057
Roshan Pius3a1667e2018-07-03 15:17:14 -07001058 group = EC_KEY_get0_group(eckey);
1059 point = EC_KEY_get0_public_key(eckey);
1060 if (group && point)
1061 dpp_debug_print_point(title, group, point);
1062
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001063 der_len = i2d_ECPrivateKey(eckey, &der);
1064 if (der_len > 0)
1065 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1066 OPENSSL_free(der);
1067 if (der_len <= 0) {
1068 der = NULL;
1069 der_len = i2d_EC_PUBKEY(eckey, &der);
1070 if (der_len > 0)
1071 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1072 OPENSSL_free(der);
1073 }
1074
1075 EC_KEY_free(eckey);
1076}
1077
1078
1079static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1080{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001081 EVP_PKEY_CTX *kctx = NULL;
Hai Shalomf1c97642019-07-19 23:42:07 +00001082 EC_KEY *ec_params;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001083 EVP_PKEY *params = NULL, *key = NULL;
1084 int nid;
1085
1086 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1087
1088 nid = OBJ_txt2nid(curve->name);
1089 if (nid == NID_undef) {
1090 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1091 return NULL;
1092 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001093
1094 ec_params = EC_KEY_new_by_curve_name(nid);
1095 if (!ec_params) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001096 wpa_printf(MSG_ERROR,
1097 "DPP: Failed to generate EC_KEY parameters");
1098 goto fail;
1099 }
1100 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
1101 params = EVP_PKEY_new();
1102 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
1103 wpa_printf(MSG_ERROR,
1104 "DPP: Failed to generate EVP_PKEY parameters");
1105 goto fail;
1106 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001107
1108 kctx = EVP_PKEY_CTX_new(params, NULL);
1109 if (!kctx ||
1110 EVP_PKEY_keygen_init(kctx) != 1 ||
1111 EVP_PKEY_keygen(kctx, &key) != 1) {
1112 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
1113 goto fail;
1114 }
1115
1116 if (wpa_debug_show_keys)
1117 dpp_debug_print_key("Own generated key", key);
1118
1119 EVP_PKEY_free(params);
1120 EVP_PKEY_CTX_free(kctx);
1121 return key;
Hai Shalomf1c97642019-07-19 23:42:07 +00001122fail:
1123 EVP_PKEY_CTX_free(kctx);
1124 EVP_PKEY_free(params);
1125 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001126}
1127
1128
1129static const struct dpp_curve_params *
1130dpp_get_curve_name(const char *name)
1131{
1132 int i;
1133
1134 for (i = 0; dpp_curves[i].name; i++) {
1135 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
1136 (dpp_curves[i].jwk_crv &&
1137 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
1138 return &dpp_curves[i];
1139 }
1140 return NULL;
1141}
1142
1143
1144static const struct dpp_curve_params *
1145dpp_get_curve_jwk_crv(const char *name)
1146{
1147 int i;
1148
1149 for (i = 0; dpp_curves[i].name; i++) {
1150 if (dpp_curves[i].jwk_crv &&
1151 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
1152 return &dpp_curves[i];
1153 }
1154 return NULL;
1155}
1156
1157
1158static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1159 const u8 *privkey, size_t privkey_len)
1160{
1161 EVP_PKEY *pkey;
1162 EC_KEY *eckey;
1163 const EC_GROUP *group;
1164 int nid;
1165
1166 pkey = EVP_PKEY_new();
1167 if (!pkey)
1168 return NULL;
1169 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1170 if (!eckey) {
1171 wpa_printf(MSG_INFO,
1172 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1173 ERR_error_string(ERR_get_error(), NULL));
1174 EVP_PKEY_free(pkey);
1175 return NULL;
1176 }
1177 group = EC_KEY_get0_group(eckey);
1178 if (!group) {
1179 EC_KEY_free(eckey);
1180 EVP_PKEY_free(pkey);
1181 return NULL;
1182 }
1183 nid = EC_GROUP_get_curve_name(group);
1184 *curve = dpp_get_curve_nid(nid);
1185 if (!*curve) {
1186 wpa_printf(MSG_INFO,
1187 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1188 nid);
1189 EC_KEY_free(eckey);
1190 EVP_PKEY_free(pkey);
1191 return NULL;
1192 }
1193
1194 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1195 EC_KEY_free(eckey);
1196 EVP_PKEY_free(pkey);
1197 return NULL;
1198 }
1199 return pkey;
1200}
1201
1202
Roshan Pius3a1667e2018-07-03 15:17:14 -07001203typedef struct {
1204 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1205 * as an OID identifying the curve */
1206 X509_ALGOR *alg;
1207 /* Compressed format public key per ANSI X9.63 */
1208 ASN1_BIT_STRING *pub_key;
1209} DPP_BOOTSTRAPPING_KEY;
1210
1211ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
1212 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
1213 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
1214} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
1215
1216IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1217
1218
1219static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001220{
1221 unsigned char *der = NULL;
1222 int der_len;
1223 EC_KEY *eckey;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001224 struct wpabuf *ret = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001225 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001226 const EC_GROUP *group;
1227 const EC_POINT *point;
1228 BN_CTX *ctx;
1229 DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1230 int nid;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001231
Roshan Pius3a1667e2018-07-03 15:17:14 -07001232 ctx = BN_CTX_new();
1233 eckey = EVP_PKEY_get1_EC_KEY(key);
1234 if (!ctx || !eckey)
1235 goto fail;
1236
1237 group = EC_KEY_get0_group(eckey);
1238 point = EC_KEY_get0_public_key(eckey);
1239 if (!group || !point)
1240 goto fail;
1241 dpp_debug_print_point("DPP: bootstrap public key", group, point);
1242 nid = EC_GROUP_get_curve_name(group);
1243
1244 bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1245 if (!bootstrap ||
1246 X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1247 V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1248 goto fail;
1249
1250 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1251 NULL, 0, ctx);
1252 if (len == 0)
1253 goto fail;
1254
1255 der = OPENSSL_malloc(len);
1256 if (!der)
1257 goto fail;
1258 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1259 der, len, ctx);
1260
1261 OPENSSL_free(bootstrap->pub_key->data);
1262 bootstrap->pub_key->data = der;
1263 der = NULL;
1264 bootstrap->pub_key->length = len;
1265 /* No unused bits */
1266 bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
1267 bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
1268
1269 der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001270 if (der_len <= 0) {
1271 wpa_printf(MSG_ERROR,
1272 "DDP: Failed to build DER encoded public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001273 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001274 }
1275
Roshan Pius3a1667e2018-07-03 15:17:14 -07001276 ret = wpabuf_alloc_copy(der, der_len);
1277fail:
1278 DPP_BOOTSTRAPPING_KEY_free(bootstrap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001279 OPENSSL_free(der);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001280 EC_KEY_free(eckey);
1281 BN_CTX_free(ctx);
1282 return ret;
1283}
1284
1285
1286int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
1287{
1288 struct wpabuf *der;
1289 int res;
1290 const u8 *addr[1];
1291 size_t len[1];
1292
1293 der = dpp_bootstrap_key_der(bi->pubkey);
1294 if (!der)
1295 return -1;
1296 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1297 der);
1298
1299 addr[0] = wpabuf_head(der);
1300 len[0] = wpabuf_len(der);
1301 res = sha256_vector(1, addr, len, bi->pubkey_hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001302 if (res < 0)
1303 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001304 else
1305 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1306 SHA256_MAC_LEN);
1307 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001308 return res;
1309}
1310
1311
1312char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1313 const u8 *privkey, size_t privkey_len)
1314{
1315 unsigned char *base64 = NULL;
1316 char *pos, *end;
1317 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001318 struct wpabuf *der = NULL;
1319 const u8 *addr[1];
1320 int res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001321
1322 if (!curve) {
1323 bi->curve = &dpp_curves[0];
1324 } else {
1325 bi->curve = dpp_get_curve_name(curve);
1326 if (!bi->curve) {
1327 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1328 curve);
1329 return NULL;
1330 }
1331 }
1332 if (privkey)
1333 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1334 else
1335 bi->pubkey = dpp_gen_keypair(bi->curve);
1336 if (!bi->pubkey)
1337 goto fail;
1338 bi->own = 1;
1339
Roshan Pius3a1667e2018-07-03 15:17:14 -07001340 der = dpp_bootstrap_key_der(bi->pubkey);
1341 if (!der)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001342 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001343 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1344 der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001345
Roshan Pius3a1667e2018-07-03 15:17:14 -07001346 addr[0] = wpabuf_head(der);
1347 len = wpabuf_len(der);
1348 res = sha256_vector(1, addr, &len, bi->pubkey_hash);
1349 if (res < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001350 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1351 goto fail;
1352 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001353 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1354 SHA256_MAC_LEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001355
Roshan Pius3a1667e2018-07-03 15:17:14 -07001356 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1357 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001358 der = NULL;
1359 if (!base64)
1360 goto fail;
1361 pos = (char *) base64;
1362 end = pos + len;
1363 for (;;) {
1364 pos = os_strchr(pos, '\n');
1365 if (!pos)
1366 break;
1367 os_memmove(pos, pos + 1, end - pos);
1368 }
1369 return (char *) base64;
1370fail:
1371 os_free(base64);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001372 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001373 return NULL;
1374}
1375
1376
1377static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1378 unsigned int hash_len)
1379{
1380 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1381 const char *info = "first intermediate key";
1382 int res;
1383
1384 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1385
1386 /* HKDF-Extract(<>, M.x) */
1387 os_memset(salt, 0, hash_len);
1388 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
1389 return -1;
1390 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1391 prk, hash_len);
1392
1393 /* HKDF-Expand(PRK, info, L) */
1394 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
1395 os_memset(prk, 0, hash_len);
1396 if (res < 0)
1397 return -1;
1398
1399 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1400 k1, hash_len);
1401 return 0;
1402}
1403
1404
1405static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1406 unsigned int hash_len)
1407{
1408 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1409 const char *info = "second intermediate key";
1410 int res;
1411
1412 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1413
1414 /* HKDF-Extract(<>, N.x) */
1415 os_memset(salt, 0, hash_len);
1416 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
1417 if (res < 0)
1418 return -1;
1419 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1420 prk, hash_len);
1421
1422 /* HKDF-Expand(PRK, info, L) */
1423 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
1424 os_memset(prk, 0, hash_len);
1425 if (res < 0)
1426 return -1;
1427
1428 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1429 k2, hash_len);
1430 return 0;
1431}
1432
1433
1434static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1435 unsigned int hash_len)
1436{
1437 size_t nonce_len;
1438 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1439 const char *info_ke = "DPP Key";
1440 u8 prk[DPP_MAX_HASH_LEN];
1441 int res;
1442 const u8 *addr[3];
1443 size_t len[3];
1444 size_t num_elem = 0;
1445
Roshan Pius3a1667e2018-07-03 15:17:14 -07001446 if (!auth->Mx_len || !auth->Nx_len) {
1447 wpa_printf(MSG_DEBUG,
1448 "DPP: Mx/Nx not available - cannot derive ke");
1449 return -1;
1450 }
1451
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001452 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1453
1454 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1455 nonce_len = auth->curve->nonce_len;
1456 os_memcpy(nonces, auth->i_nonce, nonce_len);
1457 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1458 addr[num_elem] = auth->Mx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001459 len[num_elem] = auth->Mx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001460 num_elem++;
1461 addr[num_elem] = auth->Nx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001462 len[num_elem] = auth->Nx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001463 num_elem++;
1464 if (auth->peer_bi && auth->own_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001465 if (!auth->Lx_len) {
1466 wpa_printf(MSG_DEBUG,
1467 "DPP: Lx not available - cannot derive ke");
1468 return -1;
1469 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001470 addr[num_elem] = auth->Lx;
1471 len[num_elem] = auth->secret_len;
1472 num_elem++;
1473 }
1474 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1475 num_elem, addr, len, prk);
1476 if (res < 0)
1477 return -1;
1478 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1479 prk, hash_len);
1480
1481 /* HKDF-Expand(PRK, info, L) */
1482 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
1483 os_memset(prk, 0, hash_len);
1484 if (res < 0)
1485 return -1;
1486
1487 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1488 ke, hash_len);
1489 return 0;
1490}
1491
1492
Roshan Pius3a1667e2018-07-03 15:17:14 -07001493static void dpp_build_attr_status(struct wpabuf *msg,
1494 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001495{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001496 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
1497 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1498 wpabuf_put_le16(msg, 1);
1499 wpabuf_put_u8(msg, status);
1500}
1501
1502
1503static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1504 const u8 *hash)
1505{
1506 if (hash) {
1507 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1508 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1509 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1510 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1511 }
1512}
1513
1514
1515static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1516 const u8 *hash)
1517{
1518 if (hash) {
1519 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1520 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1521 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1522 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1523 }
1524}
1525
1526
1527static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1528 const struct wpabuf *pi,
1529 size_t nonce_len,
1530 const u8 *r_pubkey_hash,
1531 const u8 *i_pubkey_hash,
1532 unsigned int neg_freq)
1533{
1534 struct wpabuf *msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001535 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1536 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1537 u8 *pos;
1538 const u8 *addr[2];
1539 size_t len[2], siv_len, attr_len;
1540 u8 *attr_start, *attr_end;
1541
Roshan Pius3a1667e2018-07-03 15:17:14 -07001542 /* Build DPP Authentication Request frame attributes */
1543 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
1544 4 + sizeof(wrapped_data);
1545 if (neg_freq > 0)
1546 attr_len += 4 + 2;
Hai Shalom021b0b52019-04-10 11:17:58 -07001547#ifdef CONFIG_DPP2
1548 attr_len += 5;
1549#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001550#ifdef CONFIG_TESTING_OPTIONS
1551 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1552 attr_len += 5;
1553#endif /* CONFIG_TESTING_OPTIONS */
1554 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1555 if (!msg)
1556 return NULL;
1557
1558 attr_start = wpabuf_put(msg, 0);
1559
1560 /* Responder Bootstrapping Key Hash */
1561 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1562
1563 /* Initiator Bootstrapping Key Hash */
1564 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1565
1566 /* Initiator Protocol Key */
1567 if (pi) {
1568 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1569 wpabuf_put_le16(msg, wpabuf_len(pi));
1570 wpabuf_put_buf(msg, pi);
1571 }
1572
1573 /* Channel */
1574 if (neg_freq > 0) {
1575 u8 op_class, channel;
1576
1577 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1578 &channel) ==
1579 NUM_HOSTAPD_MODES) {
1580 wpa_printf(MSG_INFO,
1581 "DPP: Unsupported negotiation frequency request: %d",
1582 neg_freq);
1583 wpabuf_free(msg);
1584 return NULL;
1585 }
1586 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1587 wpabuf_put_le16(msg, 2);
1588 wpabuf_put_u8(msg, op_class);
1589 wpabuf_put_u8(msg, channel);
1590 }
1591
Hai Shalom021b0b52019-04-10 11:17:58 -07001592#ifdef CONFIG_DPP2
1593 /* Protocol Version */
1594 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1595 wpabuf_put_le16(msg, 1);
1596 wpabuf_put_u8(msg, 2);
1597#endif /* CONFIG_DPP2 */
1598
Roshan Pius3a1667e2018-07-03 15:17:14 -07001599#ifdef CONFIG_TESTING_OPTIONS
1600 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1601 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1602 goto skip_wrapped_data;
1603 }
1604#endif /* CONFIG_TESTING_OPTIONS */
1605
1606 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1607 pos = clear;
1608
1609#ifdef CONFIG_TESTING_OPTIONS
1610 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1611 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1612 goto skip_i_nonce;
1613 }
1614 if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1615 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1616 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1617 pos += 2;
1618 WPA_PUT_LE16(pos, nonce_len - 1);
1619 pos += 2;
1620 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1621 pos += nonce_len - 1;
1622 goto skip_i_nonce;
1623 }
1624#endif /* CONFIG_TESTING_OPTIONS */
1625
1626 /* I-nonce */
1627 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1628 pos += 2;
1629 WPA_PUT_LE16(pos, nonce_len);
1630 pos += 2;
1631 os_memcpy(pos, auth->i_nonce, nonce_len);
1632 pos += nonce_len;
1633
1634#ifdef CONFIG_TESTING_OPTIONS
1635skip_i_nonce:
1636 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1637 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1638 goto skip_i_capab;
1639 }
1640#endif /* CONFIG_TESTING_OPTIONS */
1641
1642 /* I-capabilities */
1643 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1644 pos += 2;
1645 WPA_PUT_LE16(pos, 1);
1646 pos += 2;
1647 auth->i_capab = auth->allowed_roles;
1648 *pos++ = auth->i_capab;
1649#ifdef CONFIG_TESTING_OPTIONS
1650 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1651 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1652 pos[-1] = 0;
1653 }
1654skip_i_capab:
1655#endif /* CONFIG_TESTING_OPTIONS */
1656
1657 attr_end = wpabuf_put(msg, 0);
1658
1659 /* OUI, OUI type, Crypto Suite, DPP frame type */
1660 addr[0] = wpabuf_head_u8(msg) + 2;
1661 len[0] = 3 + 1 + 1 + 1;
1662 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1663
1664 /* Attributes before Wrapped Data */
1665 addr[1] = attr_start;
1666 len[1] = attr_end - attr_start;
1667 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1668
1669 siv_len = pos - clear;
1670 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1671 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1672 2, addr, len, wrapped_data) < 0) {
1673 wpabuf_free(msg);
1674 return NULL;
1675 }
1676 siv_len += AES_BLOCK_SIZE;
1677 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1678 wrapped_data, siv_len);
1679
1680 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1681 wpabuf_put_le16(msg, siv_len);
1682 wpabuf_put_data(msg, wrapped_data, siv_len);
1683
1684#ifdef CONFIG_TESTING_OPTIONS
1685 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1686 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1687 dpp_build_attr_status(msg, DPP_STATUS_OK);
1688 }
1689skip_wrapped_data:
1690#endif /* CONFIG_TESTING_OPTIONS */
1691
1692 wpa_hexdump_buf(MSG_DEBUG,
1693 "DPP: Authentication Request frame attributes", msg);
1694
1695 return msg;
1696}
1697
1698
1699static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1700 enum dpp_status_error status,
1701 const struct wpabuf *pr,
1702 size_t nonce_len,
1703 const u8 *r_pubkey_hash,
1704 const u8 *i_pubkey_hash,
1705 const u8 *r_nonce, const u8 *i_nonce,
1706 const u8 *wrapped_r_auth,
1707 size_t wrapped_r_auth_len,
1708 const u8 *siv_key)
1709{
1710 struct wpabuf *msg;
1711#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1712 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1713 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1714 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1715 const u8 *addr[2];
1716 size_t len[2], siv_len, attr_len;
1717 u8 *attr_start, *attr_end, *pos;
1718
1719 auth->waiting_auth_conf = 1;
1720 auth->auth_resp_tries = 0;
1721
1722 /* Build DPP Authentication Response frame attributes */
1723 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1724 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
Hai Shalom021b0b52019-04-10 11:17:58 -07001725#ifdef CONFIG_DPP2
1726 attr_len += 5;
1727#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001728#ifdef CONFIG_TESTING_OPTIONS
1729 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1730 attr_len += 5;
1731#endif /* CONFIG_TESTING_OPTIONS */
1732 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1733 if (!msg)
1734 return NULL;
1735
1736 attr_start = wpabuf_put(msg, 0);
1737
1738 /* DPP Status */
1739 if (status != 255)
1740 dpp_build_attr_status(msg, status);
1741
1742 /* Responder Bootstrapping Key Hash */
1743 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1744
1745 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1746 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1747
1748 /* Responder Protocol Key */
1749 if (pr) {
1750 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1751 wpabuf_put_le16(msg, wpabuf_len(pr));
1752 wpabuf_put_buf(msg, pr);
1753 }
1754
Hai Shalom021b0b52019-04-10 11:17:58 -07001755#ifdef CONFIG_DPP2
1756 /* Protocol Version */
1757 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1758 wpabuf_put_le16(msg, 1);
1759 wpabuf_put_u8(msg, 2);
1760#endif /* CONFIG_DPP2 */
1761
Roshan Pius3a1667e2018-07-03 15:17:14 -07001762 attr_end = wpabuf_put(msg, 0);
1763
1764#ifdef CONFIG_TESTING_OPTIONS
1765 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
1766 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1767 goto skip_wrapped_data;
1768 }
1769#endif /* CONFIG_TESTING_OPTIONS */
1770
1771 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1772 pos = clear;
1773
1774 if (r_nonce) {
1775 /* R-nonce */
1776 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1777 pos += 2;
1778 WPA_PUT_LE16(pos, nonce_len);
1779 pos += 2;
1780 os_memcpy(pos, r_nonce, nonce_len);
1781 pos += nonce_len;
1782 }
1783
1784 if (i_nonce) {
1785 /* I-nonce */
1786 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1787 pos += 2;
1788 WPA_PUT_LE16(pos, nonce_len);
1789 pos += 2;
1790 os_memcpy(pos, i_nonce, nonce_len);
1791#ifdef CONFIG_TESTING_OPTIONS
1792 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
1793 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
1794 pos[nonce_len / 2] ^= 0x01;
1795 }
1796#endif /* CONFIG_TESTING_OPTIONS */
1797 pos += nonce_len;
1798 }
1799
1800#ifdef CONFIG_TESTING_OPTIONS
1801 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
1802 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
1803 goto skip_r_capab;
1804 }
1805#endif /* CONFIG_TESTING_OPTIONS */
1806
1807 /* R-capabilities */
1808 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1809 pos += 2;
1810 WPA_PUT_LE16(pos, 1);
1811 pos += 2;
1812 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1813 DPP_CAPAB_ENROLLEE;
1814 *pos++ = auth->r_capab;
1815#ifdef CONFIG_TESTING_OPTIONS
1816 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
1817 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
1818 pos[-1] = 0;
1819 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
1820 wpa_printf(MSG_INFO,
1821 "DPP: TESTING - incompatible R-capabilities");
1822 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
1823 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
1824 pos[-1] = 0;
1825 else
1826 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
1827 DPP_CAPAB_CONFIGURATOR;
1828 }
1829skip_r_capab:
1830#endif /* CONFIG_TESTING_OPTIONS */
1831
1832 if (wrapped_r_auth) {
1833 /* {R-auth}ke */
1834 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1835 pos += 2;
1836 WPA_PUT_LE16(pos, wrapped_r_auth_len);
1837 pos += 2;
1838 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1839 pos += wrapped_r_auth_len;
1840 }
1841
1842 /* OUI, OUI type, Crypto Suite, DPP frame type */
1843 addr[0] = wpabuf_head_u8(msg) + 2;
1844 len[0] = 3 + 1 + 1 + 1;
1845 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1846
1847 /* Attributes before Wrapped Data */
1848 addr[1] = attr_start;
1849 len[1] = attr_end - attr_start;
1850 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1851
1852 siv_len = pos - clear;
1853 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1854 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
1855 2, addr, len, wrapped_data) < 0) {
1856 wpabuf_free(msg);
1857 return NULL;
1858 }
1859 siv_len += AES_BLOCK_SIZE;
1860 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1861 wrapped_data, siv_len);
1862
1863 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1864 wpabuf_put_le16(msg, siv_len);
1865 wpabuf_put_data(msg, wrapped_data, siv_len);
1866
1867#ifdef CONFIG_TESTING_OPTIONS
1868 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
1869 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1870 dpp_build_attr_status(msg, DPP_STATUS_OK);
1871 }
1872skip_wrapped_data:
1873#endif /* CONFIG_TESTING_OPTIONS */
1874
1875 wpa_hexdump_buf(MSG_DEBUG,
1876 "DPP: Authentication Response frame attributes", msg);
1877 return msg;
1878}
1879
1880
1881static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
1882 u16 num_modes, unsigned int freq)
1883{
1884 u16 m;
1885 int c, flag;
1886
1887 if (!own_modes || !num_modes)
1888 return 1;
1889
1890 for (m = 0; m < num_modes; m++) {
1891 for (c = 0; c < own_modes[m].num_channels; c++) {
1892 if ((unsigned int) own_modes[m].channels[c].freq !=
1893 freq)
1894 continue;
1895 flag = own_modes[m].channels[c].flag;
1896 if (!(flag & (HOSTAPD_CHAN_DISABLED |
1897 HOSTAPD_CHAN_NO_IR |
1898 HOSTAPD_CHAN_RADAR)))
1899 return 1;
1900 }
1901 }
1902
1903 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
1904 return 0;
1905}
1906
1907
1908static int freq_included(const unsigned int freqs[], unsigned int num,
1909 unsigned int freq)
1910{
1911 while (num > 0) {
1912 if (freqs[--num] == freq)
1913 return 1;
1914 }
1915 return 0;
1916}
1917
1918
1919static void freq_to_start(unsigned int freqs[], unsigned int num,
1920 unsigned int freq)
1921{
1922 unsigned int i;
1923
1924 for (i = 0; i < num; i++) {
1925 if (freqs[i] == freq)
1926 break;
1927 }
1928 if (i == 0 || i >= num)
1929 return;
1930 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
1931 freqs[0] = freq;
1932}
1933
1934
1935static int dpp_channel_intersect(struct dpp_authentication *auth,
1936 struct hostapd_hw_modes *own_modes,
1937 u16 num_modes)
1938{
1939 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
1940 unsigned int i, freq;
1941
1942 for (i = 0; i < peer_bi->num_freq; i++) {
1943 freq = peer_bi->freq[i];
1944 if (freq_included(auth->freq, auth->num_freq, freq))
1945 continue;
1946 if (dpp_channel_ok_init(own_modes, num_modes, freq))
1947 auth->freq[auth->num_freq++] = freq;
1948 }
1949 if (!auth->num_freq) {
1950 wpa_printf(MSG_INFO,
1951 "DPP: No available channels for initiating DPP Authentication");
1952 return -1;
1953 }
1954 auth->curr_freq = auth->freq[0];
1955 return 0;
1956}
1957
1958
1959static int dpp_channel_local_list(struct dpp_authentication *auth,
1960 struct hostapd_hw_modes *own_modes,
1961 u16 num_modes)
1962{
1963 u16 m;
1964 int c, flag;
1965 unsigned int freq;
1966
1967 auth->num_freq = 0;
1968
1969 if (!own_modes || !num_modes) {
1970 auth->freq[0] = 2412;
1971 auth->freq[1] = 2437;
1972 auth->freq[2] = 2462;
1973 auth->num_freq = 3;
1974 return 0;
1975 }
1976
1977 for (m = 0; m < num_modes; m++) {
1978 for (c = 0; c < own_modes[m].num_channels; c++) {
1979 freq = own_modes[m].channels[c].freq;
1980 flag = own_modes[m].channels[c].flag;
1981 if (flag & (HOSTAPD_CHAN_DISABLED |
1982 HOSTAPD_CHAN_NO_IR |
1983 HOSTAPD_CHAN_RADAR))
1984 continue;
1985 if (freq_included(auth->freq, auth->num_freq, freq))
1986 continue;
1987 auth->freq[auth->num_freq++] = freq;
1988 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
1989 m = num_modes;
1990 break;
1991 }
1992 }
1993 }
1994
1995 return auth->num_freq == 0 ? -1 : 0;
1996}
1997
1998
1999static int dpp_prepare_channel_list(struct dpp_authentication *auth,
2000 struct hostapd_hw_modes *own_modes,
2001 u16 num_modes)
2002{
2003 int res;
2004 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
2005 unsigned int i;
2006
2007 if (auth->peer_bi->num_freq > 0)
2008 res = dpp_channel_intersect(auth, own_modes, num_modes);
2009 else
2010 res = dpp_channel_local_list(auth, own_modes, num_modes);
2011 if (res < 0)
2012 return res;
2013
2014 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2015 * likely channels first. */
2016 freq_to_start(auth->freq, auth->num_freq, 2462);
2017 freq_to_start(auth->freq, auth->num_freq, 2412);
2018 freq_to_start(auth->freq, auth->num_freq, 2437);
2019
2020 auth->freq_idx = 0;
2021 auth->curr_freq = auth->freq[0];
2022
2023 pos = freqs;
2024 end = pos + sizeof(freqs);
2025 for (i = 0; i < auth->num_freq; i++) {
2026 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
2027 if (os_snprintf_error(end - pos, res))
2028 break;
2029 pos += res;
2030 }
2031 *pos = '\0';
2032 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
2033 freqs);
2034
2035 return 0;
2036}
2037
2038
2039static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
2040{
2041 struct dpp_bootstrap_info *bi;
2042 char *pk = NULL;
2043 size_t len;
2044
2045 if (auth->own_bi)
2046 return 0; /* already generated */
2047
2048 bi = os_zalloc(sizeof(*bi));
2049 if (!bi)
2050 return -1;
2051 bi->type = DPP_BOOTSTRAP_QR_CODE;
2052 pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
2053 if (!pk)
2054 goto fail;
2055
2056 len = 4; /* "DPP:" */
2057 len += 4 + os_strlen(pk);
2058 bi->uri = os_malloc(len + 1);
2059 if (!bi->uri)
2060 goto fail;
2061 os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
2062 wpa_printf(MSG_DEBUG,
2063 "DPP: Auto-generated own bootstrapping key info: URI %s",
2064 bi->uri);
2065
2066 auth->tmp_own_bi = auth->own_bi = bi;
2067
2068 os_free(pk);
2069
2070 return 0;
2071fail:
2072 os_free(pk);
2073 dpp_bootstrap_info_free(bi);
2074 return -1;
2075}
2076
2077
2078struct dpp_authentication * dpp_auth_init(void *msg_ctx,
2079 struct dpp_bootstrap_info *peer_bi,
2080 struct dpp_bootstrap_info *own_bi,
2081 u8 dpp_allowed_roles,
2082 unsigned int neg_freq,
2083 struct hostapd_hw_modes *own_modes,
2084 u16 num_modes)
2085{
2086 struct dpp_authentication *auth;
2087 size_t nonce_len;
2088 EVP_PKEY_CTX *ctx = NULL;
2089 size_t secret_len;
2090 struct wpabuf *pi = NULL;
2091 const u8 *r_pubkey_hash, *i_pubkey_hash;
2092#ifdef CONFIG_TESTING_OPTIONS
2093 u8 test_hash[SHA256_MAC_LEN];
2094#endif /* CONFIG_TESTING_OPTIONS */
2095
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002096 auth = os_zalloc(sizeof(*auth));
2097 if (!auth)
2098 return NULL;
2099 auth->msg_ctx = msg_ctx;
2100 auth->initiator = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002101 auth->waiting_auth_resp = 1;
2102 auth->allowed_roles = dpp_allowed_roles;
2103 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002104 auth->peer_bi = peer_bi;
2105 auth->own_bi = own_bi;
2106 auth->curve = peer_bi->curve;
2107
Roshan Pius3a1667e2018-07-03 15:17:14 -07002108 if (dpp_autogen_bootstrap_key(auth) < 0 ||
2109 dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
2110 goto fail;
2111
2112#ifdef CONFIG_TESTING_OPTIONS
2113 if (dpp_nonce_override_len > 0) {
2114 wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
2115 nonce_len = dpp_nonce_override_len;
2116 os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
2117 } else {
2118 nonce_len = auth->curve->nonce_len;
2119 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2120 wpa_printf(MSG_ERROR,
2121 "DPP: Failed to generate I-nonce");
2122 goto fail;
2123 }
2124 }
2125#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002126 nonce_len = auth->curve->nonce_len;
2127 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2128 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
2129 goto fail;
2130 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002131#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002132 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2133
Roshan Pius3a1667e2018-07-03 15:17:14 -07002134#ifdef CONFIG_TESTING_OPTIONS
2135 if (dpp_protocol_key_override_len) {
2136 const struct dpp_curve_params *tmp_curve;
2137
2138 wpa_printf(MSG_INFO,
2139 "DPP: TESTING - override protocol key");
2140 auth->own_protocol_key = dpp_set_keypair(
2141 &tmp_curve, dpp_protocol_key_override,
2142 dpp_protocol_key_override_len);
2143 } else {
2144 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2145 }
2146#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002147 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002148#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002149 if (!auth->own_protocol_key)
2150 goto fail;
2151
2152 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2153 if (!pi)
2154 goto fail;
2155
2156 /* ECDH: M = pI * BR */
2157 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2158 if (!ctx ||
2159 EVP_PKEY_derive_init(ctx) != 1 ||
2160 EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
2161 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2162 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2163 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
2164 wpa_printf(MSG_ERROR,
2165 "DPP: Failed to derive ECDH shared secret: %s",
2166 ERR_error_string(ERR_get_error(), NULL));
2167 goto fail;
2168 }
2169 auth->secret_len = secret_len;
2170 EVP_PKEY_CTX_free(ctx);
2171 ctx = NULL;
2172
2173 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2174 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002175 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002176
2177 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2178 auth->curve->hash_len) < 0)
2179 goto fail;
2180
Roshan Pius3a1667e2018-07-03 15:17:14 -07002181 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2182 i_pubkey_hash = auth->own_bi->pubkey_hash;
2183
2184#ifdef CONFIG_TESTING_OPTIONS
2185 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2186 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2187 r_pubkey_hash = NULL;
2188 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2189 wpa_printf(MSG_INFO,
2190 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2191 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2192 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2193 r_pubkey_hash = test_hash;
2194 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2195 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2196 i_pubkey_hash = NULL;
2197 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2198 wpa_printf(MSG_INFO,
2199 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2200 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2201 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2202 i_pubkey_hash = test_hash;
2203 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2204 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2205 wpabuf_free(pi);
2206 pi = NULL;
2207 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2208 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2209 wpabuf_free(pi);
2210 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2211 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2212 goto fail;
2213 }
2214#endif /* CONFIG_TESTING_OPTIONS */
2215
2216 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
2217 i_pubkey_hash, neg_freq);
2218 if (!auth->req_msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002219 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002220
Roshan Pius3a1667e2018-07-03 15:17:14 -07002221out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002222 wpabuf_free(pi);
2223 EVP_PKEY_CTX_free(ctx);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002224 return auth;
2225fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002226 dpp_auth_deinit(auth);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002227 auth = NULL;
2228 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002229}
2230
2231
Hai Shalom021b0b52019-04-10 11:17:58 -07002232static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
2233 const char *json)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002234{
2235 size_t nonce_len;
2236 size_t json_len, clear_len;
2237 struct wpabuf *clear = NULL, *msg = NULL;
2238 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002239 size_t attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002240
2241 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2242
2243 nonce_len = auth->curve->nonce_len;
2244 if (random_get_bytes(auth->e_nonce, nonce_len)) {
2245 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2246 goto fail;
2247 }
2248 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2249 json_len = os_strlen(json);
2250 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
2251
2252 /* { E-nonce, configAttrib }ke */
2253 clear_len = 4 + nonce_len + 4 + json_len;
2254 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002255 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2256#ifdef CONFIG_TESTING_OPTIONS
2257 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
2258 attr_len += 5;
2259#endif /* CONFIG_TESTING_OPTIONS */
2260 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002261 if (!clear || !msg)
2262 goto fail;
2263
Roshan Pius3a1667e2018-07-03 15:17:14 -07002264#ifdef CONFIG_TESTING_OPTIONS
2265 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2266 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2267 goto skip_e_nonce;
2268 }
2269 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
2270 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
2271 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2272 wpabuf_put_le16(clear, nonce_len - 1);
2273 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
2274 goto skip_e_nonce;
2275 }
2276 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2277 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2278 goto skip_wrapped_data;
2279 }
2280#endif /* CONFIG_TESTING_OPTIONS */
2281
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002282 /* E-nonce */
2283 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2284 wpabuf_put_le16(clear, nonce_len);
2285 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2286
Roshan Pius3a1667e2018-07-03 15:17:14 -07002287#ifdef CONFIG_TESTING_OPTIONS
2288skip_e_nonce:
2289 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2290 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2291 goto skip_conf_attr_obj;
2292 }
2293#endif /* CONFIG_TESTING_OPTIONS */
2294
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002295 /* configAttrib */
2296 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2297 wpabuf_put_le16(clear, json_len);
2298 wpabuf_put_data(clear, json, json_len);
2299
Roshan Pius3a1667e2018-07-03 15:17:14 -07002300#ifdef CONFIG_TESTING_OPTIONS
2301skip_conf_attr_obj:
2302#endif /* CONFIG_TESTING_OPTIONS */
2303
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002304 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2305 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2306 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2307
2308 /* No AES-SIV AD */
2309 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2310 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2311 wpabuf_head(clear), wpabuf_len(clear),
2312 0, NULL, NULL, wrapped) < 0)
2313 goto fail;
2314 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2315 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2316
Roshan Pius3a1667e2018-07-03 15:17:14 -07002317#ifdef CONFIG_TESTING_OPTIONS
2318 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2319 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2320 dpp_build_attr_status(msg, DPP_STATUS_OK);
2321 }
2322skip_wrapped_data:
2323#endif /* CONFIG_TESTING_OPTIONS */
2324
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002325 wpa_hexdump_buf(MSG_DEBUG,
2326 "DPP: Configuration Request frame attributes", msg);
2327 wpabuf_free(clear);
2328 return msg;
2329
2330fail:
2331 wpabuf_free(clear);
2332 wpabuf_free(msg);
2333 return NULL;
2334}
2335
2336
Hai Shalom021b0b52019-04-10 11:17:58 -07002337static void dpp_write_adv_proto(struct wpabuf *buf)
2338{
2339 /* Advertisement Protocol IE */
2340 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
2341 wpabuf_put_u8(buf, 8); /* Length */
2342 wpabuf_put_u8(buf, 0x7f);
2343 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
2344 wpabuf_put_u8(buf, 5);
2345 wpabuf_put_be24(buf, OUI_WFA);
2346 wpabuf_put_u8(buf, DPP_OUI_TYPE);
2347 wpabuf_put_u8(buf, 0x01);
2348}
2349
2350
2351static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
2352{
2353 /* GAS Query */
2354 wpabuf_put_le16(buf, wpabuf_len(query));
2355 wpabuf_put_buf(buf, query);
2356}
2357
2358
2359struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2360 const char *json)
2361{
2362 struct wpabuf *buf, *conf_req;
2363
2364 conf_req = dpp_build_conf_req_attr(auth, json);
2365 if (!conf_req) {
2366 wpa_printf(MSG_DEBUG,
2367 "DPP: No configuration request data available");
2368 return NULL;
2369 }
2370
2371 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
2372 if (!buf) {
2373 wpabuf_free(conf_req);
2374 return NULL;
2375 }
2376
2377 dpp_write_adv_proto(buf);
2378 dpp_write_gas_query(buf, conf_req);
2379 wpabuf_free(conf_req);
2380 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
2381
2382 return buf;
2383}
2384
2385
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002386static void dpp_auth_success(struct dpp_authentication *auth)
2387{
2388 wpa_printf(MSG_DEBUG,
2389 "DPP: Authentication success - clear temporary keys");
2390 os_memset(auth->Mx, 0, sizeof(auth->Mx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002391 auth->Mx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002392 os_memset(auth->Nx, 0, sizeof(auth->Nx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002393 auth->Nx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002394 os_memset(auth->Lx, 0, sizeof(auth->Lx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002395 auth->Lx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002396 os_memset(auth->k1, 0, sizeof(auth->k1));
2397 os_memset(auth->k2, 0, sizeof(auth->k2));
2398
2399 auth->auth_success = 1;
2400}
2401
2402
2403static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2404{
2405 struct wpabuf *pix, *prx, *bix, *brx;
2406 const u8 *addr[7];
2407 size_t len[7];
2408 size_t i, num_elem = 0;
2409 size_t nonce_len;
2410 u8 zero = 0;
2411 int res = -1;
2412
2413 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2414 nonce_len = auth->curve->nonce_len;
2415
2416 if (auth->initiator) {
2417 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2418 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2419 if (auth->own_bi)
2420 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2421 else
2422 bix = NULL;
2423 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2424 } else {
2425 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2426 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2427 if (auth->peer_bi)
2428 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2429 else
2430 bix = NULL;
2431 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2432 }
2433 if (!pix || !prx || !brx)
2434 goto fail;
2435
2436 addr[num_elem] = auth->i_nonce;
2437 len[num_elem] = nonce_len;
2438 num_elem++;
2439
2440 addr[num_elem] = auth->r_nonce;
2441 len[num_elem] = nonce_len;
2442 num_elem++;
2443
2444 addr[num_elem] = wpabuf_head(pix);
2445 len[num_elem] = wpabuf_len(pix) / 2;
2446 num_elem++;
2447
2448 addr[num_elem] = wpabuf_head(prx);
2449 len[num_elem] = wpabuf_len(prx) / 2;
2450 num_elem++;
2451
2452 if (bix) {
2453 addr[num_elem] = wpabuf_head(bix);
2454 len[num_elem] = wpabuf_len(bix) / 2;
2455 num_elem++;
2456 }
2457
2458 addr[num_elem] = wpabuf_head(brx);
2459 len[num_elem] = wpabuf_len(brx) / 2;
2460 num_elem++;
2461
2462 addr[num_elem] = &zero;
2463 len[num_elem] = 1;
2464 num_elem++;
2465
2466 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2467 for (i = 0; i < num_elem; i++)
2468 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2469 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
2470 if (res == 0)
2471 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2472 auth->curve->hash_len);
2473fail:
2474 wpabuf_free(pix);
2475 wpabuf_free(prx);
2476 wpabuf_free(bix);
2477 wpabuf_free(brx);
2478 return res;
2479}
2480
2481
2482static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2483{
2484 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2485 const u8 *addr[7];
2486 size_t len[7];
2487 size_t i, num_elem = 0;
2488 size_t nonce_len;
2489 u8 one = 1;
2490 int res = -1;
2491
2492 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2493 nonce_len = auth->curve->nonce_len;
2494
2495 if (auth->initiator) {
2496 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2497 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2498 if (auth->own_bi)
2499 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2500 else
2501 bix = NULL;
2502 if (!auth->peer_bi)
2503 goto fail;
2504 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2505 } else {
2506 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2507 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2508 if (auth->peer_bi)
2509 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2510 else
2511 bix = NULL;
2512 if (!auth->own_bi)
2513 goto fail;
2514 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2515 }
2516 if (!pix || !prx || !brx)
2517 goto fail;
2518
2519 addr[num_elem] = auth->r_nonce;
2520 len[num_elem] = nonce_len;
2521 num_elem++;
2522
2523 addr[num_elem] = auth->i_nonce;
2524 len[num_elem] = nonce_len;
2525 num_elem++;
2526
2527 addr[num_elem] = wpabuf_head(prx);
2528 len[num_elem] = wpabuf_len(prx) / 2;
2529 num_elem++;
2530
2531 addr[num_elem] = wpabuf_head(pix);
2532 len[num_elem] = wpabuf_len(pix) / 2;
2533 num_elem++;
2534
2535 addr[num_elem] = wpabuf_head(brx);
2536 len[num_elem] = wpabuf_len(brx) / 2;
2537 num_elem++;
2538
2539 if (bix) {
2540 addr[num_elem] = wpabuf_head(bix);
2541 len[num_elem] = wpabuf_len(bix) / 2;
2542 num_elem++;
2543 }
2544
2545 addr[num_elem] = &one;
2546 len[num_elem] = 1;
2547 num_elem++;
2548
2549 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2550 for (i = 0; i < num_elem; i++)
2551 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2552 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
2553 if (res == 0)
2554 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2555 auth->curve->hash_len);
2556fail:
2557 wpabuf_free(pix);
2558 wpabuf_free(prx);
2559 wpabuf_free(bix);
2560 wpabuf_free(brx);
2561 return res;
2562}
2563
2564
2565static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2566{
2567 const EC_GROUP *group;
2568 EC_POINT *l = NULL;
2569 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2570 const EC_POINT *BI_point;
2571 BN_CTX *bnctx;
2572 BIGNUM *lx, *sum, *q;
2573 const BIGNUM *bR_bn, *pR_bn;
2574 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002575
2576 /* L = ((bR + pR) modulo q) * BI */
2577
2578 bnctx = BN_CTX_new();
2579 sum = BN_new();
2580 q = BN_new();
2581 lx = BN_new();
2582 if (!bnctx || !sum || !q || !lx)
2583 goto fail;
2584 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2585 if (!BI)
2586 goto fail;
2587 BI_point = EC_KEY_get0_public_key(BI);
2588 group = EC_KEY_get0_group(BI);
2589 if (!group)
2590 goto fail;
2591
2592 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2593 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2594 if (!bR || !pR)
2595 goto fail;
2596 bR_bn = EC_KEY_get0_private_key(bR);
2597 pR_bn = EC_KEY_get0_private_key(pR);
2598 if (!bR_bn || !pR_bn)
2599 goto fail;
2600 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2601 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2602 goto fail;
2603 l = EC_POINT_new(group);
2604 if (!l ||
2605 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2606 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2607 bnctx) != 1) {
2608 wpa_printf(MSG_ERROR,
2609 "OpenSSL: failed: %s",
2610 ERR_error_string(ERR_get_error(), NULL));
2611 goto fail;
2612 }
2613
Roshan Pius3a1667e2018-07-03 15:17:14 -07002614 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002615 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002616 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002617 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002618 ret = 0;
2619fail:
2620 EC_POINT_clear_free(l);
2621 EC_KEY_free(BI);
2622 EC_KEY_free(bR);
2623 EC_KEY_free(pR);
2624 BN_clear_free(lx);
2625 BN_clear_free(sum);
2626 BN_free(q);
2627 BN_CTX_free(bnctx);
2628 return ret;
2629}
2630
2631
2632static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2633{
2634 const EC_GROUP *group;
2635 EC_POINT *l = NULL, *sum = NULL;
2636 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2637 const EC_POINT *BR_point, *PR_point;
2638 BN_CTX *bnctx;
2639 BIGNUM *lx;
2640 const BIGNUM *bI_bn;
2641 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002642
2643 /* L = bI * (BR + PR) */
2644
2645 bnctx = BN_CTX_new();
2646 lx = BN_new();
2647 if (!bnctx || !lx)
2648 goto fail;
2649 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2650 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
2651 if (!BR || !PR)
2652 goto fail;
2653 BR_point = EC_KEY_get0_public_key(BR);
2654 PR_point = EC_KEY_get0_public_key(PR);
2655
2656 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2657 if (!bI)
2658 goto fail;
2659 group = EC_KEY_get0_group(bI);
2660 bI_bn = EC_KEY_get0_private_key(bI);
2661 if (!group || !bI_bn)
2662 goto fail;
2663 sum = EC_POINT_new(group);
2664 l = EC_POINT_new(group);
2665 if (!sum || !l ||
2666 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
2667 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
2668 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2669 bnctx) != 1) {
2670 wpa_printf(MSG_ERROR,
2671 "OpenSSL: failed: %s",
2672 ERR_error_string(ERR_get_error(), NULL));
2673 goto fail;
2674 }
2675
Roshan Pius3a1667e2018-07-03 15:17:14 -07002676 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002677 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002678 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002679 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002680 ret = 0;
2681fail:
2682 EC_POINT_clear_free(l);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002683 EC_POINT_clear_free(sum);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002684 EC_KEY_free(bI);
2685 EC_KEY_free(BR);
2686 EC_KEY_free(PR);
2687 BN_clear_free(lx);
2688 BN_CTX_free(bnctx);
2689 return ret;
2690}
2691
2692
Roshan Pius3a1667e2018-07-03 15:17:14 -07002693static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002694{
2695 size_t nonce_len;
2696 EVP_PKEY_CTX *ctx = NULL;
2697 size_t secret_len;
2698 struct wpabuf *msg, *pr = NULL;
2699 u8 r_auth[4 + DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07002700 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002701 size_t wrapped_r_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002702 int ret = -1;
2703 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
2704 enum dpp_status_error status = DPP_STATUS_OK;
2705#ifdef CONFIG_TESTING_OPTIONS
2706 u8 test_hash[SHA256_MAC_LEN];
2707#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002708
2709 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
Roshan Pius3a1667e2018-07-03 15:17:14 -07002710 if (!auth->own_bi)
2711 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002712
Roshan Pius3a1667e2018-07-03 15:17:14 -07002713#ifdef CONFIG_TESTING_OPTIONS
2714 if (dpp_nonce_override_len > 0) {
2715 wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
2716 nonce_len = dpp_nonce_override_len;
2717 os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
2718 } else {
2719 nonce_len = auth->curve->nonce_len;
2720 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2721 wpa_printf(MSG_ERROR,
2722 "DPP: Failed to generate R-nonce");
2723 goto fail;
2724 }
2725 }
2726#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002727 nonce_len = auth->curve->nonce_len;
2728 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2729 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
2730 goto fail;
2731 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002732#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002733 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
2734
Roshan Pius3a1667e2018-07-03 15:17:14 -07002735#ifdef CONFIG_TESTING_OPTIONS
2736 if (dpp_protocol_key_override_len) {
2737 const struct dpp_curve_params *tmp_curve;
2738
2739 wpa_printf(MSG_INFO,
2740 "DPP: TESTING - override protocol key");
2741 auth->own_protocol_key = dpp_set_keypair(
2742 &tmp_curve, dpp_protocol_key_override,
2743 dpp_protocol_key_override_len);
2744 } else {
2745 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2746 }
2747#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002748 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002749#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002750 if (!auth->own_protocol_key)
2751 goto fail;
2752
2753 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2754 if (!pr)
2755 goto fail;
2756
2757 /* ECDH: N = pR * PI */
2758 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2759 if (!ctx ||
2760 EVP_PKEY_derive_init(ctx) != 1 ||
2761 EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
2762 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2763 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2764 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
2765 wpa_printf(MSG_ERROR,
2766 "DPP: Failed to derive ECDH shared secret: %s",
2767 ERR_error_string(ERR_get_error(), NULL));
2768 goto fail;
2769 }
2770 EVP_PKEY_CTX_free(ctx);
2771 ctx = NULL;
2772
2773 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
2774 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002775 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002776
2777 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2778 auth->curve->hash_len) < 0)
2779 goto fail;
2780
2781 if (auth->own_bi && auth->peer_bi) {
2782 /* Mutual authentication */
2783 if (dpp_auth_derive_l_responder(auth) < 0)
2784 goto fail;
2785 }
2786
2787 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2788 goto fail;
2789
2790 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2791 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
2792 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002793 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
2794 goto fail;
2795#ifdef CONFIG_TESTING_OPTIONS
2796 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
2797 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
2798 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
2799 }
2800#endif /* CONFIG_TESTING_OPTIONS */
2801 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002802 r_auth, 4 + auth->curve->hash_len,
2803 0, NULL, NULL, wrapped_r_auth) < 0)
2804 goto fail;
2805 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
2806 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
2807 wrapped_r_auth, wrapped_r_auth_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002808 w_r_auth = wrapped_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002809
Roshan Pius3a1667e2018-07-03 15:17:14 -07002810 r_pubkey_hash = auth->own_bi->pubkey_hash;
2811 if (auth->peer_bi)
2812 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2813 else
2814 i_pubkey_hash = NULL;
2815
2816 i_nonce = auth->i_nonce;
2817 r_nonce = auth->r_nonce;
2818
2819#ifdef CONFIG_TESTING_OPTIONS
2820 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2821 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2822 r_pubkey_hash = NULL;
2823 } else if (dpp_test ==
2824 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2825 wpa_printf(MSG_INFO,
2826 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2827 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2828 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2829 r_pubkey_hash = test_hash;
2830 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2831 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2832 i_pubkey_hash = NULL;
2833 } else if (dpp_test ==
2834 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2835 wpa_printf(MSG_INFO,
2836 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2837 if (i_pubkey_hash)
2838 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2839 else
2840 os_memset(test_hash, 0, SHA256_MAC_LEN);
2841 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2842 i_pubkey_hash = test_hash;
2843 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
2844 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
2845 wpabuf_free(pr);
2846 pr = NULL;
2847 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
2848 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
2849 wpabuf_free(pr);
2850 pr = wpabuf_alloc(2 * auth->curve->prime_len);
2851 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
2852 goto fail;
2853 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
2854 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
2855 w_r_auth = NULL;
2856 wrapped_r_auth_len = 0;
2857 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2858 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2859 status = 255;
2860 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
2861 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2862 status = 254;
2863 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
2864 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
2865 r_nonce = NULL;
2866 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2867 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2868 i_nonce = NULL;
2869 }
2870#endif /* CONFIG_TESTING_OPTIONS */
2871
2872 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
2873 r_pubkey_hash, i_pubkey_hash,
2874 r_nonce, i_nonce,
2875 w_r_auth, wrapped_r_auth_len,
2876 auth->k2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002877 if (!msg)
2878 goto fail;
2879 wpabuf_free(auth->resp_msg);
2880 auth->resp_msg = msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002881 ret = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002882fail:
2883 wpabuf_free(pr);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002884 return ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002885}
2886
2887
2888static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
2889 enum dpp_status_error status)
2890{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002891 struct wpabuf *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002892 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
2893#ifdef CONFIG_TESTING_OPTIONS
2894 u8 test_hash[SHA256_MAC_LEN];
2895#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002896
Roshan Pius3a1667e2018-07-03 15:17:14 -07002897 if (!auth->own_bi)
2898 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002899 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2900
Roshan Pius3a1667e2018-07-03 15:17:14 -07002901 r_pubkey_hash = auth->own_bi->pubkey_hash;
2902 if (auth->peer_bi)
2903 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2904 else
2905 i_pubkey_hash = NULL;
2906
2907 i_nonce = auth->i_nonce;
2908
2909#ifdef CONFIG_TESTING_OPTIONS
2910 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2911 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2912 r_pubkey_hash = NULL;
2913 } else if (dpp_test ==
2914 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2915 wpa_printf(MSG_INFO,
2916 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2917 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2918 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2919 r_pubkey_hash = test_hash;
2920 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2921 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2922 i_pubkey_hash = NULL;
2923 } else if (dpp_test ==
2924 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2925 wpa_printf(MSG_INFO,
2926 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2927 if (i_pubkey_hash)
2928 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2929 else
2930 os_memset(test_hash, 0, SHA256_MAC_LEN);
2931 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2932 i_pubkey_hash = test_hash;
2933 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2934 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
Hai Shalom74f70d42019-02-11 14:42:39 -08002935 status = 255;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002936 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2937 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2938 i_nonce = NULL;
2939 }
2940#endif /* CONFIG_TESTING_OPTIONS */
2941
2942 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
2943 r_pubkey_hash, i_pubkey_hash,
2944 NULL, i_nonce, NULL, 0, auth->k1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002945 if (!msg)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002946 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002947 wpabuf_free(auth->resp_msg);
2948 auth->resp_msg = msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002949 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002950}
2951
2952
2953struct dpp_authentication *
2954dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
2955 struct dpp_bootstrap_info *peer_bi,
2956 struct dpp_bootstrap_info *own_bi,
2957 unsigned int freq, const u8 *hdr, const u8 *attr_start,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002958 size_t attr_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002959{
2960 EVP_PKEY *pi = NULL;
2961 EVP_PKEY_CTX *ctx = NULL;
2962 size_t secret_len;
2963 const u8 *addr[2];
2964 size_t len[2];
2965 u8 *unwrapped = NULL;
2966 size_t unwrapped_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002967 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
2968 *channel;
2969 u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
2970 i_bootstrap_len, channel_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002971 struct dpp_authentication *auth = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07002972#ifdef CONFIG_DPP2
2973 const u8 *version;
2974 u16 version_len;
2975#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002976
Roshan Pius3a1667e2018-07-03 15:17:14 -07002977#ifdef CONFIG_TESTING_OPTIONS
2978 if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
2979 wpa_printf(MSG_INFO,
2980 "DPP: TESTING - stop at Authentication Request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002981 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002982 }
2983#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002984
Roshan Pius3a1667e2018-07-03 15:17:14 -07002985 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2986 &wrapped_data_len);
2987 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
2988 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
2989 "Missing or invalid required Wrapped Data attribute");
2990 return NULL;
2991 }
2992 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
2993 wrapped_data, wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002994 attr_len = wrapped_data - 4 - attr_start;
2995
2996 auth = os_zalloc(sizeof(*auth));
2997 if (!auth)
2998 goto fail;
2999 auth->msg_ctx = msg_ctx;
3000 auth->peer_bi = peer_bi;
3001 auth->own_bi = own_bi;
3002 auth->curve = own_bi->curve;
3003 auth->curr_freq = freq;
3004
Hai Shalom021b0b52019-04-10 11:17:58 -07003005 auth->peer_version = 1; /* default to the first version */
3006#ifdef CONFIG_DPP2
3007 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3008 &version_len);
3009 if (version) {
3010 if (version_len < 1 || version[0] == 0) {
3011 dpp_auth_fail(auth,
3012 "Invalid Protocol Version attribute");
3013 goto fail;
3014 }
3015 auth->peer_version = version[0];
3016 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3017 auth->peer_version);
3018 }
3019#endif /* CONFIG_DPP2 */
3020
Roshan Pius3a1667e2018-07-03 15:17:14 -07003021 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
3022 &channel_len);
3023 if (channel) {
3024 int neg_freq;
3025
3026 if (channel_len < 2) {
3027 dpp_auth_fail(auth, "Too short Channel attribute");
3028 goto fail;
3029 }
3030
3031 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
3032 wpa_printf(MSG_DEBUG,
3033 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3034 channel[0], channel[1], neg_freq);
3035 if (neg_freq < 0) {
3036 dpp_auth_fail(auth,
3037 "Unsupported Channel attribute value");
3038 goto fail;
3039 }
3040
3041 if (auth->curr_freq != (unsigned int) neg_freq) {
3042 wpa_printf(MSG_DEBUG,
3043 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3044 freq, neg_freq);
3045 auth->curr_freq = neg_freq;
3046 }
3047 }
3048
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003049 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
3050 &i_proto_len);
3051 if (!i_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003052 dpp_auth_fail(auth,
3053 "Missing required Initiator Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003054 goto fail;
3055 }
3056 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
3057 i_proto, i_proto_len);
3058
3059 /* M = bR * PI */
3060 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
3061 if (!pi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003062 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003063 goto fail;
3064 }
3065 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
3066
3067 ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
3068 if (!ctx ||
3069 EVP_PKEY_derive_init(ctx) != 1 ||
3070 EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
3071 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
3072 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
3073 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
3074 wpa_printf(MSG_ERROR,
3075 "DPP: Failed to derive ECDH shared secret: %s",
3076 ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003077 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003078 goto fail;
3079 }
3080 auth->secret_len = secret_len;
3081 EVP_PKEY_CTX_free(ctx);
3082 ctx = NULL;
3083
3084 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
3085 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003086 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003087
3088 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
3089 auth->curve->hash_len) < 0)
3090 goto fail;
3091
3092 addr[0] = hdr;
3093 len[0] = DPP_HDR_LEN;
3094 addr[1] = attr_start;
3095 len[1] = attr_len;
3096 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3097 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3098 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3099 wrapped_data, wrapped_data_len);
3100 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3101 unwrapped = os_malloc(unwrapped_len);
3102 if (!unwrapped)
3103 goto fail;
3104 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3105 wrapped_data, wrapped_data_len,
3106 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003107 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003108 goto fail;
3109 }
3110 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3111 unwrapped, unwrapped_len);
3112
3113 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003114 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003115 goto fail;
3116 }
3117
3118 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3119 &i_nonce_len);
3120 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003121 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003122 goto fail;
3123 }
3124 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3125 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
3126
3127 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
3128 DPP_ATTR_I_CAPABILITIES,
3129 &i_capab_len);
3130 if (!i_capab || i_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003131 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003132 goto fail;
3133 }
3134 auth->i_capab = i_capab[0];
3135 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
3136
3137 bin_clear_free(unwrapped, unwrapped_len);
3138 unwrapped = NULL;
3139
3140 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
3141 case DPP_CAPAB_ENROLLEE:
3142 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
3143 wpa_printf(MSG_DEBUG,
3144 "DPP: Local policy does not allow Configurator role");
3145 goto not_compatible;
3146 }
3147 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3148 auth->configurator = 1;
3149 break;
3150 case DPP_CAPAB_CONFIGURATOR:
3151 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
3152 wpa_printf(MSG_DEBUG,
3153 "DPP: Local policy does not allow Enrollee role");
3154 goto not_compatible;
3155 }
3156 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3157 auth->configurator = 0;
3158 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003159 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
3160 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
3161 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3162 auth->configurator = 0;
3163 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
3164 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3165 auth->configurator = 1;
3166 } else {
3167 wpa_printf(MSG_DEBUG,
3168 "DPP: Local policy does not allow Configurator/Enrollee role");
3169 goto not_compatible;
3170 }
3171 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003172 default:
3173 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003174 wpa_msg(auth->msg_ctx, MSG_INFO,
3175 DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
3176 auth->i_capab & DPP_CAPAB_ROLE_MASK);
3177 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003178 }
3179
3180 auth->peer_protocol_key = pi;
3181 pi = NULL;
3182 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
3183 char hex[SHA256_MAC_LEN * 2 + 1];
3184
3185 wpa_printf(MSG_DEBUG,
3186 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3187 if (dpp_auth_build_resp_status(auth,
3188 DPP_STATUS_RESPONSE_PENDING) < 0)
3189 goto fail;
3190 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3191 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3192 &i_bootstrap_len);
3193 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
3194 auth->response_pending = 1;
3195 os_memcpy(auth->waiting_pubkey_hash,
3196 i_bootstrap, i_bootstrap_len);
3197 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
3198 i_bootstrap_len);
3199 } else {
3200 hex[0] = '\0';
3201 }
3202
3203 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
3204 "%s", hex);
3205 return auth;
3206 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003207 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003208 goto fail;
3209
3210 return auth;
3211
3212not_compatible:
3213 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3214 "i-capab=0x%02x", auth->i_capab);
3215 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
3216 auth->configurator = 1;
3217 else
3218 auth->configurator = 0;
3219 auth->peer_protocol_key = pi;
3220 pi = NULL;
3221 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
3222 goto fail;
3223
3224 auth->remove_on_tx_status = 1;
3225 return auth;
3226fail:
3227 bin_clear_free(unwrapped, unwrapped_len);
3228 EVP_PKEY_free(pi);
3229 EVP_PKEY_CTX_free(ctx);
3230 dpp_auth_deinit(auth);
3231 return NULL;
3232}
3233
3234
3235int dpp_notify_new_qr_code(struct dpp_authentication *auth,
3236 struct dpp_bootstrap_info *peer_bi)
3237{
3238 if (!auth || !auth->response_pending ||
3239 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
3240 SHA256_MAC_LEN) != 0)
3241 return 0;
3242
3243 wpa_printf(MSG_DEBUG,
3244 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3245 MACSTR, MAC2STR(auth->peer_mac_addr));
3246 auth->peer_bi = peer_bi;
3247
Roshan Pius3a1667e2018-07-03 15:17:14 -07003248 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003249 return -1;
3250
3251 return 1;
3252}
3253
3254
Roshan Pius3a1667e2018-07-03 15:17:14 -07003255static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
3256 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003257{
3258 struct wpabuf *msg;
3259 u8 i_auth[4 + DPP_MAX_HASH_LEN];
3260 size_t i_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003261 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3262 size_t r_nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003263 const u8 *addr[2];
3264 size_t len[2], attr_len;
3265 u8 *wrapped_i_auth;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003266 u8 *wrapped_r_nonce;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003267 u8 *attr_start, *attr_end;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003268 const u8 *r_pubkey_hash, *i_pubkey_hash;
3269#ifdef CONFIG_TESTING_OPTIONS
3270 u8 test_hash[SHA256_MAC_LEN];
3271#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003272
3273 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3274
3275 i_auth_len = 4 + auth->curve->hash_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003276 r_nonce_len = 4 + auth->curve->nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003277 /* Build DPP Authentication Confirmation frame attributes */
3278 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
Roshan Pius3a1667e2018-07-03 15:17:14 -07003279 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
3280#ifdef CONFIG_TESTING_OPTIONS
3281 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
3282 attr_len += 5;
3283#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003284 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
3285 if (!msg)
3286 goto fail;
3287
3288 attr_start = wpabuf_put(msg, 0);
3289
Roshan Pius3a1667e2018-07-03 15:17:14 -07003290 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3291 if (auth->own_bi)
3292 i_pubkey_hash = auth->own_bi->pubkey_hash;
3293 else
3294 i_pubkey_hash = NULL;
3295
3296#ifdef CONFIG_TESTING_OPTIONS
3297 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3298 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3299 goto skip_status;
3300 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3301 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3302 status = 254;
3303 }
3304#endif /* CONFIG_TESTING_OPTIONS */
3305
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003306 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003307 dpp_build_attr_status(msg, status);
3308
3309#ifdef CONFIG_TESTING_OPTIONS
3310skip_status:
3311 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3312 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3313 r_pubkey_hash = NULL;
3314 } else if (dpp_test ==
3315 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3316 wpa_printf(MSG_INFO,
3317 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3318 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3319 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3320 r_pubkey_hash = test_hash;
3321 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3322 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3323 i_pubkey_hash = NULL;
3324 } else if (dpp_test ==
3325 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3326 wpa_printf(MSG_INFO,
3327 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3328 if (i_pubkey_hash)
3329 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3330 else
3331 os_memset(test_hash, 0, SHA256_MAC_LEN);
3332 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3333 i_pubkey_hash = test_hash;
3334 }
3335#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003336
3337 /* Responder Bootstrapping Key Hash */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003338 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003339
Roshan Pius3a1667e2018-07-03 15:17:14 -07003340 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3341 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
3342
3343#ifdef CONFIG_TESTING_OPTIONS
3344 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3345 goto skip_wrapped_data;
3346 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3347 i_auth_len = 0;
3348#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003349
3350 attr_end = wpabuf_put(msg, 0);
3351
3352 /* OUI, OUI type, Crypto Suite, DPP frame type */
3353 addr[0] = wpabuf_head_u8(msg) + 2;
3354 len[0] = 3 + 1 + 1 + 1;
3355 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3356
3357 /* Attributes before Wrapped Data */
3358 addr[1] = attr_start;
3359 len[1] = attr_end - attr_start;
3360 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3361
Roshan Pius3a1667e2018-07-03 15:17:14 -07003362 if (status == DPP_STATUS_OK) {
3363 /* I-auth wrapped with ke */
3364 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3365 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3366 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
3367
3368#ifdef CONFIG_TESTING_OPTIONS
3369 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3370 goto skip_i_auth;
3371#endif /* CONFIG_TESTING_OPTIONS */
3372
3373 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3374 * 1) */
3375 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3376 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3377 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3378 goto fail;
3379
3380#ifdef CONFIG_TESTING_OPTIONS
3381 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3382 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3383 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3384 }
3385skip_i_auth:
3386#endif /* CONFIG_TESTING_OPTIONS */
3387 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3388 i_auth, i_auth_len,
3389 2, addr, len, wrapped_i_auth) < 0)
3390 goto fail;
3391 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3392 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3393 } else {
3394 /* R-nonce wrapped with k2 */
3395 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3396 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3397 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3398
3399 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3400 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3401 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3402
3403 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3404 r_nonce, r_nonce_len,
3405 2, addr, len, wrapped_r_nonce) < 0)
3406 goto fail;
3407 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3408 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3409 }
3410
3411#ifdef CONFIG_TESTING_OPTIONS
3412 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3413 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
3414 dpp_build_attr_status(msg, DPP_STATUS_OK);
3415 }
3416skip_wrapped_data:
3417#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003418
3419 wpa_hexdump_buf(MSG_DEBUG,
3420 "DPP: Authentication Confirmation frame attributes",
3421 msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003422 if (status == DPP_STATUS_OK)
3423 dpp_auth_success(auth);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003424
3425 return msg;
3426
3427fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07003428 wpabuf_free(msg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003429 return NULL;
3430}
3431
3432
3433static void
3434dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
3435 const u8 *attr_start, size_t attr_len,
3436 const u8 *wrapped_data, u16 wrapped_data_len,
3437 enum dpp_status_error status)
3438{
3439 const u8 *addr[2];
3440 size_t len[2];
3441 u8 *unwrapped = NULL;
3442 size_t unwrapped_len = 0;
3443 const u8 *i_nonce, *r_capab;
3444 u16 i_nonce_len, r_capab_len;
3445
3446 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3447 wpa_printf(MSG_DEBUG,
3448 "DPP: Responder reported incompatible roles");
3449 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3450 wpa_printf(MSG_DEBUG,
3451 "DPP: Responder reported more time needed");
3452 } else {
3453 wpa_printf(MSG_DEBUG,
3454 "DPP: Responder reported failure (status %d)",
3455 status);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003456 dpp_auth_fail(auth, "Responder reported failure");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003457 return;
3458 }
3459
3460 addr[0] = hdr;
3461 len[0] = DPP_HDR_LEN;
3462 addr[1] = attr_start;
3463 len[1] = attr_len;
3464 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3465 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3466 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3467 wrapped_data, wrapped_data_len);
3468 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3469 unwrapped = os_malloc(unwrapped_len);
3470 if (!unwrapped)
3471 goto fail;
3472 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3473 wrapped_data, wrapped_data_len,
3474 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003475 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003476 goto fail;
3477 }
3478 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3479 unwrapped, unwrapped_len);
3480
3481 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003482 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003483 goto fail;
3484 }
3485
3486 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3487 &i_nonce_len);
3488 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003489 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003490 goto fail;
3491 }
3492 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3493 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003494 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003495 goto fail;
3496 }
3497
3498 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3499 DPP_ATTR_R_CAPABILITIES,
3500 &r_capab_len);
3501 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003502 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003503 goto fail;
3504 }
3505 auth->r_capab = r_capab[0];
3506 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3507 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3508 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3509 "r-capab=0x%02x", auth->r_capab);
3510 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003511 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3512
3513 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3514 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3515 wpa_msg(auth->msg_ctx, MSG_INFO,
3516 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3517 role);
3518 } else {
3519 wpa_printf(MSG_DEBUG,
3520 "DPP: Continue waiting for full DPP Authentication Response");
3521 wpa_msg(auth->msg_ctx, MSG_INFO,
3522 DPP_EVENT_RESPONSE_PENDING "%s",
3523 auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
3524 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003525 }
3526fail:
3527 bin_clear_free(unwrapped, unwrapped_len);
3528}
3529
3530
3531struct wpabuf *
3532dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3533 const u8 *attr_start, size_t attr_len)
3534{
3535 EVP_PKEY *pr;
3536 EVP_PKEY_CTX *ctx = NULL;
3537 size_t secret_len;
3538 const u8 *addr[2];
3539 size_t len[2];
3540 u8 *unwrapped = NULL, *unwrapped2 = NULL;
3541 size_t unwrapped_len = 0, unwrapped2_len = 0;
3542 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3543 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3544 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3545 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3546 wrapped2_len, r_auth_len;
3547 u8 r_auth2[DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07003548 u8 role;
Hai Shalom021b0b52019-04-10 11:17:58 -07003549#ifdef CONFIG_DPP2
3550 const u8 *version;
3551 u16 version_len;
3552#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003553
3554#ifdef CONFIG_TESTING_OPTIONS
3555 if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
3556 wpa_printf(MSG_INFO,
3557 "DPP: TESTING - stop at Authentication Response");
3558 return NULL;
3559 }
3560#endif /* CONFIG_TESTING_OPTIONS */
3561
Hai Shalom74f70d42019-02-11 14:42:39 -08003562 if (!auth->initiator || !auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003563 dpp_auth_fail(auth, "Unexpected Authentication Response");
3564 return NULL;
3565 }
3566
3567 auth->waiting_auth_resp = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003568
3569 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3570 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003571 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3572 dpp_auth_fail(auth,
3573 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003574 return NULL;
3575 }
3576 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3577 wrapped_data, wrapped_data_len);
3578
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003579 attr_len = wrapped_data - 4 - attr_start;
3580
3581 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3582 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3583 &r_bootstrap_len);
3584 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003585 dpp_auth_fail(auth,
3586 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003587 return NULL;
3588 }
3589 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3590 r_bootstrap, r_bootstrap_len);
3591 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3592 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003593 dpp_auth_fail(auth,
3594 "Unexpected Responder Bootstrapping Key Hash value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003595 wpa_hexdump(MSG_DEBUG,
3596 "DPP: Expected Responder Bootstrapping Key Hash",
3597 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3598 return NULL;
3599 }
3600
3601 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3602 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3603 &i_bootstrap_len);
3604 if (i_bootstrap) {
3605 if (i_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003606 dpp_auth_fail(auth,
3607 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003608 return NULL;
3609 }
3610 wpa_hexdump(MSG_MSGDUMP,
3611 "DPP: Initiator Bootstrapping Key Hash",
3612 i_bootstrap, i_bootstrap_len);
3613 if (!auth->own_bi ||
3614 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3615 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003616 dpp_auth_fail(auth,
3617 "Initiator Bootstrapping Key Hash attribute did not match");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003618 return NULL;
3619 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003620 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3621 /* PKEX bootstrapping mandates use of mutual authentication */
3622 dpp_auth_fail(auth,
3623 "Missing Initiator Bootstrapping Key Hash attribute");
3624 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003625 }
3626
Hai Shalom021b0b52019-04-10 11:17:58 -07003627 auth->peer_version = 1; /* default to the first version */
3628#ifdef CONFIG_DPP2
3629 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3630 &version_len);
3631 if (version) {
3632 if (version_len < 1 || version[0] == 0) {
3633 dpp_auth_fail(auth,
3634 "Invalid Protocol Version attribute");
3635 return NULL;
3636 }
3637 auth->peer_version = version[0];
3638 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3639 auth->peer_version);
3640 }
3641#endif /* CONFIG_DPP2 */
3642
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003643 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3644 &status_len);
3645 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003646 dpp_auth_fail(auth,
3647 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003648 return NULL;
3649 }
3650 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3651 auth->auth_resp_status = status[0];
3652 if (status[0] != DPP_STATUS_OK) {
3653 dpp_auth_resp_rx_status(auth, hdr, attr_start,
3654 attr_len, wrapped_data,
3655 wrapped_data_len, status[0]);
3656 return NULL;
3657 }
3658
Roshan Pius3a1667e2018-07-03 15:17:14 -07003659 if (!i_bootstrap && auth->own_bi) {
3660 wpa_printf(MSG_DEBUG,
3661 "DPP: Responder decided not to use mutual authentication");
3662 auth->own_bi = NULL;
3663 }
3664
3665 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
3666 auth->own_bi != NULL);
3667
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003668 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3669 &r_proto_len);
3670 if (!r_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003671 dpp_auth_fail(auth,
3672 "Missing required Responder Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003673 return NULL;
3674 }
3675 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3676 r_proto, r_proto_len);
3677
3678 /* N = pI * PR */
3679 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3680 if (!pr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003681 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003682 return NULL;
3683 }
3684 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3685
3686 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
3687 if (!ctx ||
3688 EVP_PKEY_derive_init(ctx) != 1 ||
3689 EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
3690 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
3691 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
3692 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
3693 wpa_printf(MSG_ERROR,
3694 "DPP: Failed to derive ECDH shared secret: %s",
3695 ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003696 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003697 goto fail;
3698 }
3699 EVP_PKEY_CTX_free(ctx);
3700 ctx = NULL;
3701 auth->peer_protocol_key = pr;
3702 pr = NULL;
3703
3704 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3705 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003706 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003707
3708 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3709 auth->curve->hash_len) < 0)
3710 goto fail;
3711
3712 addr[0] = hdr;
3713 len[0] = DPP_HDR_LEN;
3714 addr[1] = attr_start;
3715 len[1] = attr_len;
3716 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3717 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3718 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3719 wrapped_data, wrapped_data_len);
3720 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3721 unwrapped = os_malloc(unwrapped_len);
3722 if (!unwrapped)
3723 goto fail;
3724 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3725 wrapped_data, wrapped_data_len,
3726 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003727 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003728 goto fail;
3729 }
3730 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3731 unwrapped, unwrapped_len);
3732
3733 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003734 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003735 goto fail;
3736 }
3737
3738 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3739 &r_nonce_len);
3740 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003741 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003742 goto fail;
3743 }
3744 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
3745 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
3746
3747 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3748 &i_nonce_len);
3749 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003750 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003751 goto fail;
3752 }
3753 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3754 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003755 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003756 goto fail;
3757 }
3758
Hai Shalom74f70d42019-02-11 14:42:39 -08003759 if (auth->own_bi) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003760 /* Mutual authentication */
3761 if (dpp_auth_derive_l_initiator(auth) < 0)
3762 goto fail;
3763 }
3764
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003765 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3766 DPP_ATTR_R_CAPABILITIES,
3767 &r_capab_len);
3768 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003769 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003770 goto fail;
3771 }
3772 auth->r_capab = r_capab[0];
3773 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003774 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3775 if ((auth->allowed_roles ==
3776 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
3777 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
3778 /* Peer selected its role, so move from "either role" to the
3779 * role that is compatible with peer's selection. */
3780 auth->configurator = role == DPP_CAPAB_ENROLLEE;
3781 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
3782 auth->configurator ? "Configurator" : "Enrollee");
3783 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3784 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003785 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003786 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3787 "Unexpected role in R-capabilities 0x%02x",
3788 role);
3789 if (role != DPP_CAPAB_ENROLLEE &&
3790 role != DPP_CAPAB_CONFIGURATOR)
3791 goto fail;
3792 bin_clear_free(unwrapped, unwrapped_len);
3793 auth->remove_on_tx_status = 1;
3794 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003795 }
3796
3797 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
3798 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
3799 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003800 dpp_auth_fail(auth,
3801 "Missing or invalid Secondary Wrapped Data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003802 goto fail;
3803 }
3804
3805 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3806 wrapped2, wrapped2_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003807
3808 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3809 goto fail;
3810
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003811 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
3812 unwrapped2 = os_malloc(unwrapped2_len);
3813 if (!unwrapped2)
3814 goto fail;
3815 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3816 wrapped2, wrapped2_len,
3817 0, NULL, NULL, unwrapped2) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003818 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003819 goto fail;
3820 }
3821 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3822 unwrapped2, unwrapped2_len);
3823
3824 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003825 dpp_auth_fail(auth,
3826 "Invalid attribute in secondary unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003827 goto fail;
3828 }
3829
3830 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
3831 &r_auth_len);
3832 if (!r_auth || r_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003833 dpp_auth_fail(auth,
3834 "Missing or invalid Responder Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003835 goto fail;
3836 }
3837 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
3838 r_auth, r_auth_len);
3839 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3840 if (dpp_gen_r_auth(auth, r_auth2) < 0)
3841 goto fail;
3842 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
3843 r_auth2, r_auth_len);
3844 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003845 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
3846 bin_clear_free(unwrapped, unwrapped_len);
3847 bin_clear_free(unwrapped2, unwrapped2_len);
3848 auth->remove_on_tx_status = 1;
3849 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003850 }
3851
3852 bin_clear_free(unwrapped, unwrapped_len);
3853 bin_clear_free(unwrapped2, unwrapped2_len);
3854
Roshan Pius3a1667e2018-07-03 15:17:14 -07003855#ifdef CONFIG_TESTING_OPTIONS
3856 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
3857 wpa_printf(MSG_INFO,
3858 "DPP: TESTING - Authentication Response in place of Confirm");
3859 if (dpp_auth_build_resp_ok(auth) < 0)
3860 return NULL;
3861 return wpabuf_dup(auth->resp_msg);
3862 }
3863#endif /* CONFIG_TESTING_OPTIONS */
3864
3865 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003866
3867fail:
3868 bin_clear_free(unwrapped, unwrapped_len);
3869 bin_clear_free(unwrapped2, unwrapped2_len);
3870 EVP_PKEY_free(pr);
3871 EVP_PKEY_CTX_free(ctx);
3872 return NULL;
3873}
3874
3875
Roshan Pius3a1667e2018-07-03 15:17:14 -07003876static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
3877 const u8 *hdr,
3878 const u8 *attr_start, size_t attr_len,
3879 const u8 *wrapped_data,
3880 u16 wrapped_data_len,
3881 enum dpp_status_error status)
3882{
3883 const u8 *addr[2];
3884 size_t len[2];
3885 u8 *unwrapped = NULL;
3886 size_t unwrapped_len = 0;
3887 const u8 *r_nonce;
3888 u16 r_nonce_len;
3889
3890 /* Authentication Confirm failure cases are expected to include
3891 * {R-nonce}k2 in the Wrapped Data attribute. */
3892
3893 addr[0] = hdr;
3894 len[0] = DPP_HDR_LEN;
3895 addr[1] = attr_start;
3896 len[1] = attr_len;
3897 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3898 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3899 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3900 wrapped_data, wrapped_data_len);
3901 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3902 unwrapped = os_malloc(unwrapped_len);
3903 if (!unwrapped) {
3904 dpp_auth_fail(auth, "Authentication failed");
3905 goto fail;
3906 }
3907 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3908 wrapped_data, wrapped_data_len,
3909 2, addr, len, unwrapped) < 0) {
3910 dpp_auth_fail(auth, "AES-SIV decryption failed");
3911 goto fail;
3912 }
3913 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3914 unwrapped, unwrapped_len);
3915
3916 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3917 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3918 goto fail;
3919 }
3920
3921 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3922 &r_nonce_len);
3923 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3924 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3925 goto fail;
3926 }
3927 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
3928 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
3929 r_nonce, r_nonce_len);
3930 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
3931 auth->r_nonce, r_nonce_len);
3932 dpp_auth_fail(auth, "R-nonce mismatch");
3933 goto fail;
3934 }
3935
3936 if (status == DPP_STATUS_NOT_COMPATIBLE)
3937 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
3938 else if (status == DPP_STATUS_AUTH_FAILURE)
3939 dpp_auth_fail(auth, "Peer reported authentication failure)");
3940
3941fail:
3942 bin_clear_free(unwrapped, unwrapped_len);
3943 return -1;
3944}
3945
3946
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003947int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
3948 const u8 *attr_start, size_t attr_len)
3949{
3950 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
3951 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3952 i_auth_len;
3953 const u8 *addr[2];
3954 size_t len[2];
3955 u8 *unwrapped = NULL;
3956 size_t unwrapped_len = 0;
3957 u8 i_auth2[DPP_MAX_HASH_LEN];
3958
Roshan Pius3a1667e2018-07-03 15:17:14 -07003959#ifdef CONFIG_TESTING_OPTIONS
3960 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
3961 wpa_printf(MSG_INFO,
3962 "DPP: TESTING - stop at Authentication Confirm");
3963 return -1;
3964 }
3965#endif /* CONFIG_TESTING_OPTIONS */
3966
Hai Shalom74f70d42019-02-11 14:42:39 -08003967 if (auth->initiator || !auth->own_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003968 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
3969 return -1;
3970 }
3971
3972 auth->waiting_auth_conf = 0;
3973
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003974 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3975 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003976 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3977 dpp_auth_fail(auth,
3978 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003979 return -1;
3980 }
3981 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3982 wrapped_data, wrapped_data_len);
3983
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003984 attr_len = wrapped_data - 4 - attr_start;
3985
3986 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3987 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3988 &r_bootstrap_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003989 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3990 dpp_auth_fail(auth,
3991 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003992 return -1;
3993 }
3994 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3995 r_bootstrap, r_bootstrap_len);
3996 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
3997 SHA256_MAC_LEN) != 0) {
3998 wpa_hexdump(MSG_DEBUG,
3999 "DPP: Expected Responder Bootstrapping Key Hash",
4000 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004001 dpp_auth_fail(auth,
4002 "Responder Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004003 return -1;
4004 }
4005
4006 i_bootstrap = dpp_get_attr(attr_start, attr_len,
4007 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
4008 &i_bootstrap_len);
4009 if (i_bootstrap) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004010 if (i_bootstrap_len != SHA256_MAC_LEN) {
4011 dpp_auth_fail(auth,
4012 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004013 return -1;
4014 }
4015 wpa_hexdump(MSG_MSGDUMP,
4016 "DPP: Initiator Bootstrapping Key Hash",
4017 i_bootstrap, i_bootstrap_len);
4018 if (!auth->peer_bi ||
4019 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
4020 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004021 dpp_auth_fail(auth,
4022 "Initiator Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004023 return -1;
4024 }
Hai Shalom74f70d42019-02-11 14:42:39 -08004025 } else if (auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004026 /* Mutual authentication and peer did not include its
4027 * Bootstrapping Key Hash attribute. */
4028 dpp_auth_fail(auth,
4029 "Missing Initiator Bootstrapping Key Hash attribute");
4030 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004031 }
4032
4033 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
4034 &status_len);
4035 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004036 dpp_auth_fail(auth,
4037 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004038 return -1;
4039 }
4040 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004041 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
4042 status[0] == DPP_STATUS_AUTH_FAILURE)
4043 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
4044 attr_len, wrapped_data,
4045 wrapped_data_len, status[0]);
4046
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004047 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004048 dpp_auth_fail(auth, "Authentication failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004049 return -1;
4050 }
4051
4052 addr[0] = hdr;
4053 len[0] = DPP_HDR_LEN;
4054 addr[1] = attr_start;
4055 len[1] = attr_len;
4056 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4057 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4058 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4059 wrapped_data, wrapped_data_len);
4060 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4061 unwrapped = os_malloc(unwrapped_len);
4062 if (!unwrapped)
4063 return -1;
4064 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4065 wrapped_data, wrapped_data_len,
4066 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004067 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004068 goto fail;
4069 }
4070 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4071 unwrapped, unwrapped_len);
4072
4073 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004074 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004075 goto fail;
4076 }
4077
4078 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
4079 &i_auth_len);
4080 if (!i_auth || i_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004081 dpp_auth_fail(auth,
4082 "Missing or invalid Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004083 goto fail;
4084 }
4085 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
4086 i_auth, i_auth_len);
4087 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4088 if (dpp_gen_i_auth(auth, i_auth2) < 0)
4089 goto fail;
4090 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
4091 i_auth2, i_auth_len);
4092 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004093 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004094 goto fail;
4095 }
4096
4097 bin_clear_free(unwrapped, unwrapped_len);
4098 dpp_auth_success(auth);
4099 return 0;
4100fail:
4101 bin_clear_free(unwrapped, unwrapped_len);
4102 return -1;
4103}
4104
4105
Hai Shalom021b0b52019-04-10 11:17:58 -07004106static int bin_str_eq(const char *val, size_t len, const char *cmp)
4107{
4108 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
4109}
4110
4111
4112struct dpp_configuration * dpp_configuration_alloc(const char *type)
4113{
4114 struct dpp_configuration *conf;
4115 const char *end;
4116 size_t len;
4117
4118 conf = os_zalloc(sizeof(*conf));
4119 if (!conf)
4120 goto fail;
4121
4122 end = os_strchr(type, ' ');
4123 if (end)
4124 len = end - type;
4125 else
4126 len = os_strlen(type);
4127
4128 if (bin_str_eq(type, len, "psk"))
4129 conf->akm = DPP_AKM_PSK;
4130 else if (bin_str_eq(type, len, "sae"))
4131 conf->akm = DPP_AKM_SAE;
4132 else if (bin_str_eq(type, len, "psk-sae") ||
4133 bin_str_eq(type, len, "psk+sae"))
4134 conf->akm = DPP_AKM_PSK_SAE;
4135 else if (bin_str_eq(type, len, "sae-dpp") ||
4136 bin_str_eq(type, len, "dpp+sae"))
4137 conf->akm = DPP_AKM_SAE_DPP;
4138 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
4139 bin_str_eq(type, len, "dpp+psk+sae"))
4140 conf->akm = DPP_AKM_PSK_SAE_DPP;
4141 else if (bin_str_eq(type, len, "dpp"))
4142 conf->akm = DPP_AKM_DPP;
4143 else
4144 goto fail;
4145
4146 return conf;
4147fail:
4148 dpp_configuration_free(conf);
4149 return NULL;
4150}
4151
4152
4153int dpp_akm_psk(enum dpp_akm akm)
4154{
4155 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4156 akm == DPP_AKM_PSK_SAE_DPP;
4157}
4158
4159
4160int dpp_akm_sae(enum dpp_akm akm)
4161{
4162 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
4163 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4164}
4165
4166
4167int dpp_akm_legacy(enum dpp_akm akm)
4168{
4169 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4170 akm == DPP_AKM_SAE;
4171}
4172
4173
4174int dpp_akm_dpp(enum dpp_akm akm)
4175{
4176 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
4177 akm == DPP_AKM_PSK_SAE_DPP;
4178}
4179
4180
4181int dpp_akm_ver2(enum dpp_akm akm)
4182{
4183 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4184}
4185
4186
4187int dpp_configuration_valid(const struct dpp_configuration *conf)
4188{
4189 if (conf->ssid_len == 0)
4190 return 0;
4191 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
4192 return 0;
4193 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
4194 return 0;
4195 return 1;
4196}
4197
4198
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004199void dpp_configuration_free(struct dpp_configuration *conf)
4200{
4201 if (!conf)
4202 return;
4203 str_clear_free(conf->passphrase);
Hai Shalomce48b4a2018-09-05 11:41:35 -07004204 os_free(conf->group_id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004205 bin_clear_free(conf, sizeof(*conf));
4206}
4207
4208
Hai Shalom021b0b52019-04-10 11:17:58 -07004209static int dpp_configuration_parse(struct dpp_authentication *auth,
4210 const char *cmd)
4211{
4212 const char *pos, *end;
4213 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
4214 struct dpp_configuration *conf = NULL;
4215
4216 pos = os_strstr(cmd, " conf=sta-");
4217 if (pos) {
4218 conf_sta = dpp_configuration_alloc(pos + 10);
4219 if (!conf_sta)
4220 goto fail;
4221 conf = conf_sta;
4222 }
4223
4224 pos = os_strstr(cmd, " conf=ap-");
4225 if (pos) {
4226 conf_ap = dpp_configuration_alloc(pos + 9);
4227 if (!conf_ap)
4228 goto fail;
4229 conf = conf_ap;
4230 }
4231
4232 if (!conf)
4233 return 0;
4234
4235 pos = os_strstr(cmd, " ssid=");
4236 if (pos) {
4237 pos += 6;
4238 end = os_strchr(pos, ' ');
4239 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
4240 conf->ssid_len /= 2;
4241 if (conf->ssid_len > sizeof(conf->ssid) ||
4242 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
4243 goto fail;
4244 } else {
4245#ifdef CONFIG_TESTING_OPTIONS
4246 /* use a default SSID for legacy testing reasons */
4247 os_memcpy(conf->ssid, "test", 4);
4248 conf->ssid_len = 4;
4249#else /* CONFIG_TESTING_OPTIONS */
4250 goto fail;
4251#endif /* CONFIG_TESTING_OPTIONS */
4252 }
4253
4254 pos = os_strstr(cmd, " pass=");
4255 if (pos) {
4256 size_t pass_len;
4257
4258 pos += 6;
4259 end = os_strchr(pos, ' ');
4260 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
4261 pass_len /= 2;
4262 if (pass_len > 63 || pass_len < 8)
4263 goto fail;
4264 conf->passphrase = os_zalloc(pass_len + 1);
4265 if (!conf->passphrase ||
4266 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
4267 goto fail;
4268 }
4269
4270 pos = os_strstr(cmd, " psk=");
4271 if (pos) {
4272 pos += 5;
4273 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
4274 goto fail;
4275 conf->psk_set = 1;
4276 }
4277
4278 pos = os_strstr(cmd, " group_id=");
4279 if (pos) {
4280 size_t group_id_len;
4281
4282 pos += 10;
4283 end = os_strchr(pos, ' ');
4284 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
4285 conf->group_id = os_malloc(group_id_len + 1);
4286 if (!conf->group_id)
4287 goto fail;
4288 os_memcpy(conf->group_id, pos, group_id_len);
4289 conf->group_id[group_id_len] = '\0';
4290 }
4291
4292 pos = os_strstr(cmd, " expiry=");
4293 if (pos) {
4294 long int val;
4295
4296 pos += 8;
4297 val = strtol(pos, NULL, 0);
4298 if (val <= 0)
4299 goto fail;
4300 conf->netaccesskey_expiry = val;
4301 }
4302
4303 if (!dpp_configuration_valid(conf))
4304 goto fail;
4305
4306 auth->conf_sta = conf_sta;
4307 auth->conf_ap = conf_ap;
4308 return 0;
4309
4310fail:
4311 dpp_configuration_free(conf_sta);
4312 dpp_configuration_free(conf_ap);
4313 return -1;
4314}
4315
4316
4317static struct dpp_configurator *
4318dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
4319{
4320 struct dpp_configurator *conf;
4321
4322 if (!dpp)
4323 return NULL;
4324
4325 dl_list_for_each(conf, &dpp->configurator,
4326 struct dpp_configurator, list) {
4327 if (conf->id == id)
4328 return conf;
4329 }
4330 return NULL;
4331}
4332
4333
4334int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
4335 struct dpp_authentication *auth,
4336 const char *cmd)
4337{
4338 const char *pos;
4339
4340 if (!cmd)
4341 return 0;
4342
4343 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
4344
4345 pos = os_strstr(cmd, " configurator=");
4346 if (pos) {
4347 pos += 14;
4348 auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
4349 if (!auth->conf) {
4350 wpa_printf(MSG_INFO,
4351 "DPP: Could not find the specified configurator");
4352 return -1;
4353 }
4354 }
4355
4356 if (dpp_configuration_parse(auth, cmd) < 0) {
4357 wpa_msg(msg_ctx, MSG_INFO,
4358 "DPP: Failed to set configurator parameters");
4359 return -1;
4360 }
4361 return 0;
4362}
4363
4364
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004365void dpp_auth_deinit(struct dpp_authentication *auth)
4366{
4367 if (!auth)
4368 return;
4369 dpp_configuration_free(auth->conf_ap);
4370 dpp_configuration_free(auth->conf_sta);
4371 EVP_PKEY_free(auth->own_protocol_key);
4372 EVP_PKEY_free(auth->peer_protocol_key);
4373 wpabuf_free(auth->req_msg);
4374 wpabuf_free(auth->resp_msg);
4375 wpabuf_free(auth->conf_req);
4376 os_free(auth->connector);
4377 wpabuf_free(auth->net_access_key);
4378 wpabuf_free(auth->c_sign_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004379 dpp_bootstrap_info_free(auth->tmp_own_bi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004380#ifdef CONFIG_TESTING_OPTIONS
4381 os_free(auth->config_obj_override);
4382 os_free(auth->discovery_override);
4383 os_free(auth->groups_override);
4384#endif /* CONFIG_TESTING_OPTIONS */
4385 bin_clear_free(auth, sizeof(*auth));
4386}
4387
4388
4389static struct wpabuf *
4390dpp_build_conf_start(struct dpp_authentication *auth,
4391 struct dpp_configuration *conf, size_t tailroom)
4392{
4393 struct wpabuf *buf;
4394 char ssid[6 * sizeof(conf->ssid) + 1];
4395
4396#ifdef CONFIG_TESTING_OPTIONS
4397 if (auth->discovery_override)
4398 tailroom += os_strlen(auth->discovery_override);
4399#endif /* CONFIG_TESTING_OPTIONS */
4400
4401 buf = wpabuf_alloc(200 + tailroom);
4402 if (!buf)
4403 return NULL;
4404 wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4405#ifdef CONFIG_TESTING_OPTIONS
4406 if (auth->discovery_override) {
4407 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
4408 auth->discovery_override);
4409 wpabuf_put_str(buf, auth->discovery_override);
4410 wpabuf_put_u8(buf, ',');
4411 return buf;
4412 }
4413#endif /* CONFIG_TESTING_OPTIONS */
4414 wpabuf_put_str(buf, "{\"ssid\":\"");
4415 json_escape_string(ssid, sizeof(ssid),
4416 (const char *) conf->ssid, conf->ssid_len);
4417 wpabuf_put_str(buf, ssid);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004418 wpabuf_put_str(buf, "\"},");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004419
4420 return buf;
4421}
4422
4423
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004424static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
4425 const char *kid, const struct dpp_curve_params *curve)
4426{
4427 struct wpabuf *pub;
4428 const u8 *pos;
4429 char *x = NULL, *y = NULL;
4430 int ret = -1;
4431
4432 pub = dpp_get_pubkey_point(key, 0);
4433 if (!pub)
4434 goto fail;
4435 pos = wpabuf_head(pub);
4436 x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
4437 pos += curve->prime_len;
4438 y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
4439 if (!x || !y)
4440 goto fail;
4441
4442 wpabuf_put_str(buf, "\"");
4443 wpabuf_put_str(buf, name);
4444 wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
4445 wpabuf_put_str(buf, curve->jwk_crv);
4446 wpabuf_put_str(buf, "\",\"x\":\"");
4447 wpabuf_put_str(buf, x);
4448 wpabuf_put_str(buf, "\",\"y\":\"");
4449 wpabuf_put_str(buf, y);
4450 if (kid) {
4451 wpabuf_put_str(buf, "\",\"kid\":\"");
4452 wpabuf_put_str(buf, kid);
4453 }
4454 wpabuf_put_str(buf, "\"}");
4455 ret = 0;
4456fail:
4457 wpabuf_free(pub);
4458 os_free(x);
4459 os_free(y);
4460 return ret;
4461}
4462
4463
Hai Shalom021b0b52019-04-10 11:17:58 -07004464static void dpp_build_legacy_cred_params(struct wpabuf *buf,
4465 struct dpp_configuration *conf)
4466{
4467 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
4468 char pass[63 * 6 + 1];
4469
4470 json_escape_string(pass, sizeof(pass), conf->passphrase,
4471 os_strlen(conf->passphrase));
4472 wpabuf_put_str(buf, "\"pass\":\"");
4473 wpabuf_put_str(buf, pass);
4474 wpabuf_put_str(buf, "\"");
4475 os_memset(pass, 0, sizeof(pass));
4476 } else if (conf->psk_set) {
4477 char psk[2 * sizeof(conf->psk) + 1];
4478
4479 wpa_snprintf_hex(psk, sizeof(psk),
4480 conf->psk, sizeof(conf->psk));
4481 wpabuf_put_str(buf, "\"psk_hex\":\"");
4482 wpabuf_put_str(buf, psk);
4483 wpabuf_put_str(buf, "\"");
4484 os_memset(psk, 0, sizeof(psk));
4485 }
4486}
4487
4488
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004489static struct wpabuf *
4490dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
4491 struct dpp_configuration *conf)
4492{
4493 struct wpabuf *buf = NULL;
4494 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
4495 size_t tailroom;
4496 const struct dpp_curve_params *curve;
4497 char jws_prot_hdr[100];
4498 size_t signed1_len, signed2_len, signed3_len;
4499 struct wpabuf *dppcon = NULL;
4500 unsigned char *signature = NULL;
4501 const unsigned char *p;
4502 size_t signature_len;
4503 EVP_MD_CTX *md_ctx = NULL;
4504 ECDSA_SIG *sig = NULL;
4505 char *dot = ".";
4506 const EVP_MD *sign_md;
4507 const BIGNUM *r, *s;
4508 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07004509 int incl_legacy;
4510 enum dpp_akm akm;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004511
4512 if (!auth->conf) {
4513 wpa_printf(MSG_INFO,
4514 "DPP: No configurator specified - cannot generate DPP config object");
4515 goto fail;
4516 }
4517 curve = auth->conf->curve;
4518 if (curve->hash_len == SHA256_MAC_LEN) {
4519 sign_md = EVP_sha256();
4520 } else if (curve->hash_len == SHA384_MAC_LEN) {
4521 sign_md = EVP_sha384();
4522 } else if (curve->hash_len == SHA512_MAC_LEN) {
4523 sign_md = EVP_sha512();
4524 } else {
4525 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
4526 goto fail;
4527 }
4528
Hai Shalom021b0b52019-04-10 11:17:58 -07004529 akm = conf->akm;
4530 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
4531 wpa_printf(MSG_DEBUG,
4532 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4533 akm = DPP_AKM_DPP;
4534 }
4535
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004536#ifdef CONFIG_TESTING_OPTIONS
4537 if (auth->groups_override)
4538 extra_len += os_strlen(auth->groups_override);
4539#endif /* CONFIG_TESTING_OPTIONS */
4540
Hai Shalomce48b4a2018-09-05 11:41:35 -07004541 if (conf->group_id)
4542 extra_len += os_strlen(conf->group_id);
4543
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004544 /* Connector (JSON dppCon object) */
4545 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
4546 if (!dppcon)
4547 goto fail;
4548#ifdef CONFIG_TESTING_OPTIONS
4549 if (auth->groups_override) {
4550 wpabuf_put_u8(dppcon, '{');
4551 if (auth->groups_override) {
4552 wpa_printf(MSG_DEBUG,
4553 "DPP: TESTING - groups override: '%s'",
4554 auth->groups_override);
4555 wpabuf_put_str(dppcon, "\"groups\":");
4556 wpabuf_put_str(dppcon, auth->groups_override);
4557 wpabuf_put_u8(dppcon, ',');
4558 }
4559 goto skip_groups;
4560 }
4561#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomce48b4a2018-09-05 11:41:35 -07004562 wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
4563 conf->group_id ? conf->group_id : "*");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004564 wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
4565#ifdef CONFIG_TESTING_OPTIONS
4566skip_groups:
4567#endif /* CONFIG_TESTING_OPTIONS */
4568 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
4569 auth->curve) < 0) {
4570 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
4571 goto fail;
4572 }
4573 if (conf->netaccesskey_expiry) {
4574 struct os_tm tm;
4575
4576 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
4577 wpa_printf(MSG_DEBUG,
4578 "DPP: Failed to generate expiry string");
4579 goto fail;
4580 }
4581 wpabuf_printf(dppcon,
4582 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4583 tm.year, tm.month, tm.day,
4584 tm.hour, tm.min, tm.sec);
4585 }
4586 wpabuf_put_u8(dppcon, '}');
4587 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
4588 (const char *) wpabuf_head(dppcon));
4589
4590 os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
4591 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4592 auth->conf->kid, curve->jws_alg);
4593 signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
4594 os_strlen(jws_prot_hdr),
4595 &signed1_len, 0);
4596 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
4597 wpabuf_len(dppcon),
4598 &signed2_len, 0);
4599 if (!signed1 || !signed2)
4600 goto fail;
4601
4602 md_ctx = EVP_MD_CTX_create();
4603 if (!md_ctx)
4604 goto fail;
4605
4606 ERR_clear_error();
4607 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
4608 auth->conf->csign) != 1) {
4609 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
4610 ERR_error_string(ERR_get_error(), NULL));
4611 goto fail;
4612 }
4613 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
4614 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
4615 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
4616 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
4617 ERR_error_string(ERR_get_error(), NULL));
4618 goto fail;
4619 }
4620 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
4621 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4622 ERR_error_string(ERR_get_error(), NULL));
4623 goto fail;
4624 }
4625 signature = os_malloc(signature_len);
4626 if (!signature)
4627 goto fail;
4628 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
4629 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4630 ERR_error_string(ERR_get_error(), NULL));
4631 goto fail;
4632 }
4633 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
4634 signature, signature_len);
4635 /* Convert to raw coordinates r,s */
4636 p = signature;
4637 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
4638 if (!sig)
4639 goto fail;
4640 ECDSA_SIG_get0(sig, &r, &s);
4641 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4642 dpp_bn2bin_pad(s, signature + curve->prime_len,
4643 curve->prime_len) < 0)
4644 goto fail;
4645 signature_len = 2 * curve->prime_len;
4646 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4647 signature, signature_len);
4648 signed3 = (char *) base64_url_encode(signature, signature_len,
4649 &signed3_len, 0);
4650 if (!signed3)
4651 goto fail;
4652
Hai Shalom021b0b52019-04-10 11:17:58 -07004653 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004654 tailroom = 1000;
4655 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4656 tailroom += signed1_len + signed2_len + signed3_len;
Hai Shalom021b0b52019-04-10 11:17:58 -07004657 if (incl_legacy)
4658 tailroom += 1000;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004659 buf = dpp_build_conf_start(auth, conf, tailroom);
4660 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004661 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004662
Hai Shalom021b0b52019-04-10 11:17:58 -07004663 wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
4664 if (incl_legacy) {
4665 dpp_build_legacy_cred_params(buf, conf);
4666 wpabuf_put_str(buf, ",");
4667 }
4668 wpabuf_put_str(buf, "\"signedConnector\":\"");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004669 wpabuf_put_str(buf, signed1);
4670 wpabuf_put_u8(buf, '.');
4671 wpabuf_put_str(buf, signed2);
4672 wpabuf_put_u8(buf, '.');
4673 wpabuf_put_str(buf, signed3);
4674 wpabuf_put_str(buf, "\",");
4675 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4676 curve) < 0) {
4677 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4678 goto fail;
4679 }
4680
4681 wpabuf_put_str(buf, "}}");
4682
4683 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4684 wpabuf_head(buf), wpabuf_len(buf));
4685
4686out:
4687 EVP_MD_CTX_destroy(md_ctx);
4688 ECDSA_SIG_free(sig);
4689 os_free(signed1);
4690 os_free(signed2);
4691 os_free(signed3);
4692 os_free(signature);
4693 wpabuf_free(dppcon);
4694 return buf;
4695fail:
4696 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4697 wpabuf_free(buf);
4698 buf = NULL;
4699 goto out;
4700}
4701
4702
4703static struct wpabuf *
4704dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
4705 struct dpp_configuration *conf)
4706{
4707 struct wpabuf *buf;
4708
4709 buf = dpp_build_conf_start(auth, conf, 1000);
4710 if (!buf)
4711 return NULL;
4712
Roshan Pius3a1667e2018-07-03 15:17:14 -07004713 wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
Hai Shalom021b0b52019-04-10 11:17:58 -07004714 dpp_build_legacy_cred_params(buf, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004715 wpabuf_put_str(buf, "}}");
4716
4717 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4718 wpabuf_head(buf), wpabuf_len(buf));
4719
4720 return buf;
4721}
4722
4723
4724static struct wpabuf *
4725dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
4726{
4727 struct dpp_configuration *conf;
4728
4729#ifdef CONFIG_TESTING_OPTIONS
4730 if (auth->config_obj_override) {
4731 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
4732 return wpabuf_alloc_copy(auth->config_obj_override,
4733 os_strlen(auth->config_obj_override));
4734 }
4735#endif /* CONFIG_TESTING_OPTIONS */
4736
4737 conf = ap ? auth->conf_ap : auth->conf_sta;
4738 if (!conf) {
4739 wpa_printf(MSG_DEBUG,
4740 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4741 ap ? "ap" : "sta");
4742 return NULL;
4743 }
4744
Hai Shalom021b0b52019-04-10 11:17:58 -07004745 if (dpp_akm_dpp(conf->akm))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004746 return dpp_build_conf_obj_dpp(auth, ap, conf);
4747 return dpp_build_conf_obj_legacy(auth, ap, conf);
4748}
4749
4750
4751static struct wpabuf *
4752dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4753 u16 e_nonce_len, int ap)
4754{
4755 struct wpabuf *conf;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004756 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004757 struct wpabuf *clear = NULL, *msg = NULL;
4758 u8 *wrapped;
4759 const u8 *addr[1];
4760 size_t len[1];
4761 enum dpp_status_error status;
4762
4763 conf = dpp_build_conf_obj(auth, ap);
4764 if (conf) {
4765 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4766 wpabuf_head(conf), wpabuf_len(conf));
4767 }
4768 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
Hai Shalom021b0b52019-04-10 11:17:58 -07004769 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004770
4771 /* { E-nonce, configurationObject}ke */
4772 clear_len = 4 + e_nonce_len;
4773 if (conf)
4774 clear_len += 4 + wpabuf_len(conf);
4775 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004776 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
4777#ifdef CONFIG_TESTING_OPTIONS
4778 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
4779 attr_len += 5;
4780#endif /* CONFIG_TESTING_OPTIONS */
4781 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004782 if (!clear || !msg)
4783 goto fail;
4784
Roshan Pius3a1667e2018-07-03 15:17:14 -07004785#ifdef CONFIG_TESTING_OPTIONS
4786 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
4787 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
4788 goto skip_e_nonce;
4789 }
4790 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
4791 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
4792 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4793 wpabuf_put_le16(clear, e_nonce_len);
4794 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
4795 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
4796 goto skip_e_nonce;
4797 }
4798 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
4799 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
4800 goto skip_wrapped_data;
4801 }
4802#endif /* CONFIG_TESTING_OPTIONS */
4803
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004804 /* E-nonce */
4805 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4806 wpabuf_put_le16(clear, e_nonce_len);
4807 wpabuf_put_data(clear, e_nonce, e_nonce_len);
4808
Roshan Pius3a1667e2018-07-03 15:17:14 -07004809#ifdef CONFIG_TESTING_OPTIONS
4810skip_e_nonce:
4811 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
4812 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
4813 goto skip_config_obj;
4814 }
4815#endif /* CONFIG_TESTING_OPTIONS */
4816
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004817 if (conf) {
4818 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4819 wpabuf_put_le16(clear, wpabuf_len(conf));
4820 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004821 }
4822
Roshan Pius3a1667e2018-07-03 15:17:14 -07004823#ifdef CONFIG_TESTING_OPTIONS
4824skip_config_obj:
4825 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4826 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4827 goto skip_status;
4828 }
4829 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4830 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4831 status = 255;
4832 }
4833#endif /* CONFIG_TESTING_OPTIONS */
4834
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004835 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07004836 dpp_build_attr_status(msg, status);
4837
4838#ifdef CONFIG_TESTING_OPTIONS
4839skip_status:
4840#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004841
4842 addr[0] = wpabuf_head(msg);
4843 len[0] = wpabuf_len(msg);
4844 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4845
4846 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
4847 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4848 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4849
4850 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
4851 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
4852 wpabuf_head(clear), wpabuf_len(clear),
4853 1, addr, len, wrapped) < 0)
4854 goto fail;
4855 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4856 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004857
4858#ifdef CONFIG_TESTING_OPTIONS
4859 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
4860 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
4861 dpp_build_attr_status(msg, DPP_STATUS_OK);
4862 }
4863skip_wrapped_data:
4864#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004865
4866 wpa_hexdump_buf(MSG_DEBUG,
4867 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004868out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004869 wpabuf_free(conf);
4870 wpabuf_free(clear);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004871
4872 return msg;
4873fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004874 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004875 msg = NULL;
4876 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004877}
4878
4879
4880struct wpabuf *
4881dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4882 size_t attr_len)
4883{
4884 const u8 *wrapped_data, *e_nonce, *config_attr;
4885 u16 wrapped_data_len, e_nonce_len, config_attr_len;
4886 u8 *unwrapped = NULL;
4887 size_t unwrapped_len = 0;
4888 struct wpabuf *resp = NULL;
4889 struct json_token *root = NULL, *token;
4890 int ap;
4891
Roshan Pius3a1667e2018-07-03 15:17:14 -07004892#ifdef CONFIG_TESTING_OPTIONS
4893 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
4894 wpa_printf(MSG_INFO,
4895 "DPP: TESTING - stop at Config Request");
4896 return NULL;
4897 }
4898#endif /* CONFIG_TESTING_OPTIONS */
4899
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004900 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004901 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004902 return NULL;
4903 }
4904
4905 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4906 &wrapped_data_len);
4907 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004908 dpp_auth_fail(auth,
4909 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004910 return NULL;
4911 }
4912
4913 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4914 wrapped_data, wrapped_data_len);
4915 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4916 unwrapped = os_malloc(unwrapped_len);
4917 if (!unwrapped)
4918 return NULL;
4919 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4920 wrapped_data, wrapped_data_len,
4921 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004922 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004923 goto fail;
4924 }
4925 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4926 unwrapped, unwrapped_len);
4927
4928 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004929 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004930 goto fail;
4931 }
4932
4933 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4934 DPP_ATTR_ENROLLEE_NONCE,
4935 &e_nonce_len);
4936 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004937 dpp_auth_fail(auth,
4938 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004939 goto fail;
4940 }
4941 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004942 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004943
4944 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
4945 DPP_ATTR_CONFIG_ATTR_OBJ,
4946 &config_attr_len);
4947 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004948 dpp_auth_fail(auth,
4949 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004950 goto fail;
4951 }
4952 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
4953 config_attr, config_attr_len);
4954
4955 root = json_parse((const char *) config_attr, config_attr_len);
4956 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004957 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004958 goto fail;
4959 }
4960
4961 token = json_get_member(root, "name");
4962 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004963 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004964 goto fail;
4965 }
4966 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
4967
4968 token = json_get_member(root, "wi-fi_tech");
4969 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004970 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004971 goto fail;
4972 }
4973 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
4974 if (os_strcmp(token->string, "infra") != 0) {
4975 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
4976 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004977 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004978 goto fail;
4979 }
4980
4981 token = json_get_member(root, "netRole");
4982 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004983 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004984 goto fail;
4985 }
4986 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
4987 if (os_strcmp(token->string, "sta") == 0) {
4988 ap = 0;
4989 } else if (os_strcmp(token->string, "ap") == 0) {
4990 ap = 1;
4991 } else {
4992 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
4993 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004994 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004995 goto fail;
4996 }
4997
4998 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
4999
5000fail:
5001 json_free(root);
5002 os_free(unwrapped);
5003 return resp;
5004}
5005
5006
5007static struct wpabuf *
5008dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
5009 const u8 *prot_hdr, u16 prot_hdr_len,
5010 const EVP_MD **ret_md)
5011{
5012 struct json_token *root, *token;
5013 struct wpabuf *kid = NULL;
5014
5015 root = json_parse((const char *) prot_hdr, prot_hdr_len);
5016 if (!root) {
5017 wpa_printf(MSG_DEBUG,
5018 "DPP: JSON parsing failed for JWS Protected Header");
5019 goto fail;
5020 }
5021
5022 if (root->type != JSON_OBJECT) {
5023 wpa_printf(MSG_DEBUG,
5024 "DPP: JWS Protected Header root is not an object");
5025 goto fail;
5026 }
5027
5028 token = json_get_member(root, "typ");
5029 if (!token || token->type != JSON_STRING) {
5030 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
5031 goto fail;
5032 }
5033 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
5034 token->string);
5035 if (os_strcmp(token->string, "dppCon") != 0) {
5036 wpa_printf(MSG_DEBUG,
5037 "DPP: Unsupported JWS Protected Header typ=%s",
5038 token->string);
5039 goto fail;
5040 }
5041
5042 token = json_get_member(root, "alg");
5043 if (!token || token->type != JSON_STRING) {
5044 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
5045 goto fail;
5046 }
5047 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
5048 token->string);
5049 if (os_strcmp(token->string, curve->jws_alg) != 0) {
5050 wpa_printf(MSG_DEBUG,
5051 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5052 token->string, curve->jws_alg);
5053 goto fail;
5054 }
5055 if (os_strcmp(token->string, "ES256") == 0 ||
5056 os_strcmp(token->string, "BS256") == 0)
5057 *ret_md = EVP_sha256();
5058 else if (os_strcmp(token->string, "ES384") == 0 ||
5059 os_strcmp(token->string, "BS384") == 0)
5060 *ret_md = EVP_sha384();
5061 else if (os_strcmp(token->string, "ES512") == 0 ||
5062 os_strcmp(token->string, "BS512") == 0)
5063 *ret_md = EVP_sha512();
5064 else
5065 *ret_md = NULL;
5066 if (!*ret_md) {
5067 wpa_printf(MSG_DEBUG,
5068 "DPP: Unsupported JWS Protected Header alg=%s",
5069 token->string);
5070 goto fail;
5071 }
5072
5073 kid = json_get_member_base64url(root, "kid");
5074 if (!kid) {
5075 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
5076 goto fail;
5077 }
5078 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
5079 kid);
5080
5081fail:
5082 json_free(root);
5083 return kid;
5084}
5085
5086
5087static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
5088 struct json_token *cred)
5089{
5090 struct json_token *pass, *psk_hex;
5091
5092 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
5093
5094 pass = json_get_member(cred, "pass");
5095 psk_hex = json_get_member(cred, "psk_hex");
5096
5097 if (pass && pass->type == JSON_STRING) {
5098 size_t len = os_strlen(pass->string);
5099
5100 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
5101 pass->string, len);
5102 if (len < 8 || len > 63)
5103 return -1;
5104 os_strlcpy(auth->passphrase, pass->string,
5105 sizeof(auth->passphrase));
5106 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalom021b0b52019-04-10 11:17:58 -07005107 if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005108 wpa_printf(MSG_DEBUG,
5109 "DPP: Unexpected psk_hex with akm=sae");
5110 return -1;
5111 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005112 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
5113 hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
5114 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
5115 return -1;
5116 }
5117 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
5118 auth->psk, PMK_LEN);
5119 auth->psk_set = 1;
5120 } else {
5121 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
5122 return -1;
5123 }
5124
Hai Shalom021b0b52019-04-10 11:17:58 -07005125 if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005126 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
5127 return -1;
5128 }
5129
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005130 return 0;
5131}
5132
5133
5134static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
5135 const struct dpp_curve_params **key_curve)
5136{
5137 struct json_token *token;
5138 const struct dpp_curve_params *curve;
5139 struct wpabuf *x = NULL, *y = NULL;
5140 EC_GROUP *group;
5141 EVP_PKEY *pkey = NULL;
5142
5143 token = json_get_member(jwk, "kty");
5144 if (!token || token->type != JSON_STRING) {
5145 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
5146 goto fail;
5147 }
5148 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08005149 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005150 token->string);
5151 goto fail;
5152 }
5153
5154 token = json_get_member(jwk, "crv");
5155 if (!token || token->type != JSON_STRING) {
5156 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
5157 goto fail;
5158 }
5159 curve = dpp_get_curve_jwk_crv(token->string);
5160 if (!curve) {
5161 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
5162 token->string);
5163 goto fail;
5164 }
5165
5166 x = json_get_member_base64url(jwk, "x");
5167 if (!x) {
5168 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
5169 goto fail;
5170 }
5171 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
5172 if (wpabuf_len(x) != curve->prime_len) {
5173 wpa_printf(MSG_DEBUG,
5174 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5175 (unsigned int) wpabuf_len(x),
5176 (unsigned int) curve->prime_len, curve->name);
5177 goto fail;
5178 }
5179
5180 y = json_get_member_base64url(jwk, "y");
5181 if (!y) {
5182 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
5183 goto fail;
5184 }
5185 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
5186 if (wpabuf_len(y) != curve->prime_len) {
5187 wpa_printf(MSG_DEBUG,
5188 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5189 (unsigned int) wpabuf_len(y),
5190 (unsigned int) curve->prime_len, curve->name);
5191 goto fail;
5192 }
5193
5194 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5195 if (!group) {
5196 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
5197 goto fail;
5198 }
5199
5200 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
5201 wpabuf_len(x));
5202 *key_curve = curve;
5203
5204fail:
5205 wpabuf_free(x);
5206 wpabuf_free(y);
5207
5208 return pkey;
5209}
5210
5211
5212int dpp_key_expired(const char *timestamp, os_time_t *expiry)
5213{
5214 struct os_time now;
5215 unsigned int year, month, day, hour, min, sec;
5216 os_time_t utime;
5217 const char *pos;
5218
5219 /* ISO 8601 date and time:
5220 * <date>T<time>
5221 * YYYY-MM-DDTHH:MM:SSZ
5222 * YYYY-MM-DDTHH:MM:SS+03:00
5223 */
5224 if (os_strlen(timestamp) < 19) {
5225 wpa_printf(MSG_DEBUG,
5226 "DPP: Too short timestamp - assume expired key");
5227 return 1;
5228 }
5229 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
5230 &year, &month, &day, &hour, &min, &sec) != 6) {
5231 wpa_printf(MSG_DEBUG,
5232 "DPP: Failed to parse expiration day - assume expired key");
5233 return 1;
5234 }
5235
5236 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
5237 wpa_printf(MSG_DEBUG,
5238 "DPP: Invalid date/time information - assume expired key");
5239 return 1;
5240 }
5241
5242 pos = timestamp + 19;
5243 if (*pos == 'Z' || *pos == '\0') {
5244 /* In UTC - no need to adjust */
5245 } else if (*pos == '-' || *pos == '+') {
5246 int items;
5247
5248 /* Adjust local time to UTC */
5249 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
5250 if (items < 1) {
5251 wpa_printf(MSG_DEBUG,
5252 "DPP: Invalid time zone designator (%s) - assume expired key",
5253 pos);
5254 return 1;
5255 }
5256 if (*pos == '-')
5257 utime += 3600 * hour;
5258 if (*pos == '+')
5259 utime -= 3600 * hour;
5260 if (items > 1) {
5261 if (*pos == '-')
5262 utime += 60 * min;
5263 if (*pos == '+')
5264 utime -= 60 * min;
5265 }
5266 } else {
5267 wpa_printf(MSG_DEBUG,
5268 "DPP: Invalid time zone designator (%s) - assume expired key",
5269 pos);
5270 return 1;
5271 }
5272 if (expiry)
5273 *expiry = utime;
5274
5275 if (os_get_time(&now) < 0) {
5276 wpa_printf(MSG_DEBUG,
5277 "DPP: Cannot get current time - assume expired key");
5278 return 1;
5279 }
5280
5281 if (now.sec > utime) {
5282 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
5283 utime, now.sec);
5284 return 1;
5285 }
5286
5287 return 0;
5288}
5289
5290
5291static int dpp_parse_connector(struct dpp_authentication *auth,
5292 const unsigned char *payload,
5293 u16 payload_len)
5294{
5295 struct json_token *root, *groups, *netkey, *token;
5296 int ret = -1;
5297 EVP_PKEY *key = NULL;
5298 const struct dpp_curve_params *curve;
5299 unsigned int rules = 0;
5300
5301 root = json_parse((const char *) payload, payload_len);
5302 if (!root) {
5303 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5304 goto fail;
5305 }
5306
5307 groups = json_get_member(root, "groups");
5308 if (!groups || groups->type != JSON_ARRAY) {
5309 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
5310 goto skip_groups;
5311 }
5312 for (token = groups->child; token; token = token->sibling) {
5313 struct json_token *id, *role;
5314
5315 id = json_get_member(token, "groupId");
5316 if (!id || id->type != JSON_STRING) {
5317 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
5318 goto fail;
5319 }
5320
5321 role = json_get_member(token, "netRole");
5322 if (!role || role->type != JSON_STRING) {
5323 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
5324 goto fail;
5325 }
5326 wpa_printf(MSG_DEBUG,
5327 "DPP: connector group: groupId='%s' netRole='%s'",
5328 id->string, role->string);
5329 rules++;
5330 }
5331skip_groups:
5332
5333 if (!rules) {
5334 wpa_printf(MSG_DEBUG,
5335 "DPP: Connector includes no groups");
5336 goto fail;
5337 }
5338
5339 token = json_get_member(root, "expiry");
5340 if (!token || token->type != JSON_STRING) {
5341 wpa_printf(MSG_DEBUG,
5342 "DPP: No expiry string found - connector does not expire");
5343 } else {
5344 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5345 if (dpp_key_expired(token->string,
5346 &auth->net_access_key_expiry)) {
5347 wpa_printf(MSG_DEBUG,
5348 "DPP: Connector (netAccessKey) has expired");
5349 goto fail;
5350 }
5351 }
5352
5353 netkey = json_get_member(root, "netAccessKey");
5354 if (!netkey || netkey->type != JSON_OBJECT) {
5355 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
5356 goto fail;
5357 }
5358
5359 key = dpp_parse_jwk(netkey, &curve);
5360 if (!key)
5361 goto fail;
5362 dpp_debug_print_key("DPP: Received netAccessKey", key);
5363
5364 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
5365 wpa_printf(MSG_DEBUG,
5366 "DPP: netAccessKey in connector does not match own protocol key");
5367#ifdef CONFIG_TESTING_OPTIONS
5368 if (auth->ignore_netaccesskey_mismatch) {
5369 wpa_printf(MSG_DEBUG,
5370 "DPP: TESTING - skip netAccessKey mismatch");
5371 } else {
5372 goto fail;
5373 }
5374#else /* CONFIG_TESTING_OPTIONS */
5375 goto fail;
5376#endif /* CONFIG_TESTING_OPTIONS */
5377 }
5378
5379 ret = 0;
5380fail:
5381 EVP_PKEY_free(key);
5382 json_free(root);
5383 return ret;
5384}
5385
5386
5387static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
5388{
5389 struct wpabuf *uncomp;
5390 int res;
5391 u8 hash[SHA256_MAC_LEN];
5392 const u8 *addr[1];
5393 size_t len[1];
5394
5395 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
5396 return -1;
5397 uncomp = dpp_get_pubkey_point(pub, 1);
5398 if (!uncomp)
5399 return -1;
5400 addr[0] = wpabuf_head(uncomp);
5401 len[0] = wpabuf_len(uncomp);
5402 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
5403 addr[0], len[0]);
5404 res = sha256_vector(1, addr, len, hash);
5405 wpabuf_free(uncomp);
5406 if (res < 0)
5407 return -1;
5408 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
5409 wpa_printf(MSG_DEBUG,
5410 "DPP: Received hash value does not match calculated public key hash value");
5411 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
5412 hash, SHA256_MAC_LEN);
5413 return -1;
5414 }
5415 return 0;
5416}
5417
5418
5419static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
5420{
5421 unsigned char *der = NULL;
5422 int der_len;
5423
5424 der_len = i2d_PUBKEY(csign, &der);
5425 if (der_len <= 0)
5426 return;
5427 wpabuf_free(auth->c_sign_key);
5428 auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
5429 OPENSSL_free(der);
5430}
5431
5432
5433static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
5434{
5435 unsigned char *der = NULL;
5436 int der_len;
5437 EC_KEY *eckey;
5438
5439 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
5440 if (!eckey)
5441 return;
5442
5443 der_len = i2d_ECPrivateKey(eckey, &der);
5444 if (der_len <= 0) {
5445 EC_KEY_free(eckey);
5446 return;
5447 }
5448 wpabuf_free(auth->net_access_key);
5449 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
5450 OPENSSL_free(der);
5451 EC_KEY_free(eckey);
5452}
5453
5454
5455struct dpp_signed_connector_info {
5456 unsigned char *payload;
5457 size_t payload_len;
5458};
5459
Roshan Pius3a1667e2018-07-03 15:17:14 -07005460static enum dpp_status_error
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005461dpp_process_signed_connector(struct dpp_signed_connector_info *info,
5462 EVP_PKEY *csign_pub, const char *connector)
5463{
Roshan Pius3a1667e2018-07-03 15:17:14 -07005464 enum dpp_status_error ret = 255;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005465 const char *pos, *end, *signed_start, *signed_end;
5466 struct wpabuf *kid = NULL;
5467 unsigned char *prot_hdr = NULL, *signature = NULL;
5468 size_t prot_hdr_len = 0, signature_len = 0;
5469 const EVP_MD *sign_md = NULL;
5470 unsigned char *der = NULL;
5471 int der_len;
5472 int res;
5473 EVP_MD_CTX *md_ctx = NULL;
5474 ECDSA_SIG *sig = NULL;
5475 BIGNUM *r = NULL, *s = NULL;
5476 const struct dpp_curve_params *curve;
5477 EC_KEY *eckey;
5478 const EC_GROUP *group;
5479 int nid;
5480
5481 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
5482 if (!eckey)
5483 goto fail;
5484 group = EC_KEY_get0_group(eckey);
5485 if (!group)
5486 goto fail;
5487 nid = EC_GROUP_get_curve_name(group);
5488 curve = dpp_get_curve_nid(nid);
5489 if (!curve)
5490 goto fail;
5491 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
5492 os_memset(info, 0, sizeof(*info));
5493
5494 signed_start = pos = connector;
5495 end = os_strchr(pos, '.');
5496 if (!end) {
5497 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005498 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005499 goto fail;
5500 }
5501 prot_hdr = base64_url_decode((const unsigned char *) pos,
5502 end - pos, &prot_hdr_len);
5503 if (!prot_hdr) {
5504 wpa_printf(MSG_DEBUG,
5505 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005506 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005507 goto fail;
5508 }
5509 wpa_hexdump_ascii(MSG_DEBUG,
5510 "DPP: signedConnector - JWS Protected Header",
5511 prot_hdr, prot_hdr_len);
5512 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005513 if (!kid) {
5514 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005515 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005516 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005517 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
5518 wpa_printf(MSG_DEBUG,
5519 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5520 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005521 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005522 goto fail;
5523 }
5524
5525 pos = end + 1;
5526 end = os_strchr(pos, '.');
5527 if (!end) {
5528 wpa_printf(MSG_DEBUG,
5529 "DPP: Missing dot(2) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005530 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005531 goto fail;
5532 }
5533 signed_end = end - 1;
5534 info->payload = base64_url_decode((const unsigned char *) pos,
5535 end - pos, &info->payload_len);
5536 if (!info->payload) {
5537 wpa_printf(MSG_DEBUG,
5538 "DPP: Failed to base64url decode signedConnector JWS Payload");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005539 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005540 goto fail;
5541 }
5542 wpa_hexdump_ascii(MSG_DEBUG,
5543 "DPP: signedConnector - JWS Payload",
5544 info->payload, info->payload_len);
5545 pos = end + 1;
5546 signature = base64_url_decode((const unsigned char *) pos,
5547 os_strlen(pos), &signature_len);
5548 if (!signature) {
5549 wpa_printf(MSG_DEBUG,
5550 "DPP: Failed to base64url decode signedConnector signature");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005551 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005552 goto fail;
5553 }
5554 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5555 signature, signature_len);
5556
Roshan Pius3a1667e2018-07-03 15:17:14 -07005557 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5558 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005559 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005560 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005561
5562 if (signature_len & 0x01) {
5563 wpa_printf(MSG_DEBUG,
5564 "DPP: Unexpected signedConnector signature length (%d)",
5565 (int) signature_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005566 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005567 goto fail;
5568 }
5569
5570 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5571 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5572 r = BN_bin2bn(signature, signature_len / 2, NULL);
5573 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
5574 sig = ECDSA_SIG_new();
5575 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
5576 goto fail;
5577 r = NULL;
5578 s = NULL;
5579
5580 der_len = i2d_ECDSA_SIG(sig, &der);
5581 if (der_len <= 0) {
5582 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
5583 goto fail;
5584 }
5585 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
5586 md_ctx = EVP_MD_CTX_create();
5587 if (!md_ctx)
5588 goto fail;
5589
5590 ERR_clear_error();
5591 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
5592 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
5593 ERR_error_string(ERR_get_error(), NULL));
5594 goto fail;
5595 }
5596 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
5597 signed_end - signed_start + 1) != 1) {
5598 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
5599 ERR_error_string(ERR_get_error(), NULL));
5600 goto fail;
5601 }
5602 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
5603 if (res != 1) {
5604 wpa_printf(MSG_DEBUG,
5605 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5606 res, ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07005607 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005608 goto fail;
5609 }
5610
Roshan Pius3a1667e2018-07-03 15:17:14 -07005611 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005612fail:
5613 EC_KEY_free(eckey);
5614 EVP_MD_CTX_destroy(md_ctx);
5615 os_free(prot_hdr);
5616 wpabuf_free(kid);
5617 os_free(signature);
5618 ECDSA_SIG_free(sig);
5619 BN_free(r);
5620 BN_free(s);
5621 OPENSSL_free(der);
5622 return ret;
5623}
5624
5625
5626static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5627 struct json_token *cred)
5628{
5629 struct dpp_signed_connector_info info;
5630 struct json_token *token, *csign;
5631 int ret = -1;
5632 EVP_PKEY *csign_pub = NULL;
5633 const struct dpp_curve_params *key_curve = NULL;
5634 const char *signed_connector;
5635
5636 os_memset(&info, 0, sizeof(info));
5637
Hai Shalom021b0b52019-04-10 11:17:58 -07005638 if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
5639 wpa_printf(MSG_DEBUG,
5640 "DPP: Legacy credential included in Connector credential");
5641 if (dpp_parse_cred_legacy(auth, cred) < 0)
5642 return -1;
5643 }
5644
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005645 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5646
5647 csign = json_get_member(cred, "csign");
5648 if (!csign || csign->type != JSON_OBJECT) {
5649 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5650 goto fail;
5651 }
5652
5653 csign_pub = dpp_parse_jwk(csign, &key_curve);
5654 if (!csign_pub) {
5655 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5656 goto fail;
5657 }
5658 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5659
5660 token = json_get_member(cred, "signedConnector");
5661 if (!token || token->type != JSON_STRING) {
5662 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5663 goto fail;
5664 }
5665 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5666 token->string, os_strlen(token->string));
5667 signed_connector = token->string;
5668
5669 if (os_strchr(signed_connector, '"') ||
5670 os_strchr(signed_connector, '\n')) {
5671 wpa_printf(MSG_DEBUG,
5672 "DPP: Unexpected character in signedConnector");
5673 goto fail;
5674 }
5675
5676 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005677 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005678 goto fail;
5679
5680 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
5681 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5682 goto fail;
5683 }
5684
5685 os_free(auth->connector);
5686 auth->connector = os_strdup(signed_connector);
5687
5688 dpp_copy_csign(auth, csign_pub);
5689 dpp_copy_netaccesskey(auth);
5690
5691 ret = 0;
5692fail:
5693 EVP_PKEY_free(csign_pub);
5694 os_free(info.payload);
5695 return ret;
5696}
5697
5698
Roshan Pius3a1667e2018-07-03 15:17:14 -07005699const char * dpp_akm_str(enum dpp_akm akm)
5700{
5701 switch (akm) {
5702 case DPP_AKM_DPP:
5703 return "dpp";
5704 case DPP_AKM_PSK:
5705 return "psk";
5706 case DPP_AKM_SAE:
5707 return "sae";
5708 case DPP_AKM_PSK_SAE:
5709 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07005710 case DPP_AKM_SAE_DPP:
5711 return "dpp+sae";
5712 case DPP_AKM_PSK_SAE_DPP:
5713 return "dpp+psk+sae";
Roshan Pius3a1667e2018-07-03 15:17:14 -07005714 default:
5715 return "??";
5716 }
5717}
5718
5719
5720static enum dpp_akm dpp_akm_from_str(const char *akm)
5721{
5722 if (os_strcmp(akm, "psk") == 0)
5723 return DPP_AKM_PSK;
5724 if (os_strcmp(akm, "sae") == 0)
5725 return DPP_AKM_SAE;
5726 if (os_strcmp(akm, "psk+sae") == 0)
5727 return DPP_AKM_PSK_SAE;
5728 if (os_strcmp(akm, "dpp") == 0)
5729 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07005730 if (os_strcmp(akm, "dpp+sae") == 0)
5731 return DPP_AKM_SAE_DPP;
5732 if (os_strcmp(akm, "dpp+psk+sae") == 0)
5733 return DPP_AKM_PSK_SAE_DPP;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005734 return DPP_AKM_UNKNOWN;
5735}
5736
5737
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005738static int dpp_parse_conf_obj(struct dpp_authentication *auth,
5739 const u8 *conf_obj, u16 conf_obj_len)
5740{
5741 int ret = -1;
5742 struct json_token *root, *token, *discovery, *cred;
5743
5744 root = json_parse((const char *) conf_obj, conf_obj_len);
5745 if (!root)
5746 return -1;
5747 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005748 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005749 goto fail;
5750 }
5751
5752 token = json_get_member(root, "wi-fi_tech");
5753 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005754 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005755 goto fail;
5756 }
5757 if (os_strcmp(token->string, "infra") != 0) {
5758 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5759 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005760 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005761 goto fail;
5762 }
5763
5764 discovery = json_get_member(root, "discovery");
5765 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005766 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005767 goto fail;
5768 }
5769
5770 token = json_get_member(discovery, "ssid");
5771 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005772 dpp_auth_fail(auth, "No discovery::ssid string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005773 goto fail;
5774 }
5775 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
5776 token->string, os_strlen(token->string));
5777 if (os_strlen(token->string) > SSID_MAX_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005778 dpp_auth_fail(auth, "Too long discovery::ssid string value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005779 goto fail;
5780 }
5781 auth->ssid_len = os_strlen(token->string);
5782 os_memcpy(auth->ssid, token->string, auth->ssid_len);
5783
5784 cred = json_get_member(root, "cred");
5785 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005786 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005787 goto fail;
5788 }
5789
5790 token = json_get_member(cred, "akm");
5791 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005792 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005793 goto fail;
5794 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07005795 auth->akm = dpp_akm_from_str(token->string);
5796
Hai Shalom021b0b52019-04-10 11:17:58 -07005797 if (dpp_akm_legacy(auth->akm)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005798 if (dpp_parse_cred_legacy(auth, cred) < 0)
5799 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07005800 } else if (dpp_akm_dpp(auth->akm)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005801 if (dpp_parse_cred_dpp(auth, cred) < 0)
5802 goto fail;
5803 } else {
5804 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5805 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005806 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005807 goto fail;
5808 }
5809
5810 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5811 ret = 0;
5812fail:
5813 json_free(root);
5814 return ret;
5815}
5816
5817
5818int dpp_conf_resp_rx(struct dpp_authentication *auth,
5819 const struct wpabuf *resp)
5820{
5821 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5822 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5823 const u8 *addr[1];
5824 size_t len[1];
5825 u8 *unwrapped = NULL;
5826 size_t unwrapped_len = 0;
5827 int ret = -1;
5828
Hai Shalom021b0b52019-04-10 11:17:58 -07005829 auth->conf_resp_status = 255;
5830
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005831 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005832 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005833 return -1;
5834 }
5835
5836 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5837 DPP_ATTR_WRAPPED_DATA,
5838 &wrapped_data_len);
5839 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005840 dpp_auth_fail(auth,
5841 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005842 return -1;
5843 }
5844
5845 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5846 wrapped_data, wrapped_data_len);
5847 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5848 unwrapped = os_malloc(unwrapped_len);
5849 if (!unwrapped)
5850 return -1;
5851
5852 addr[0] = wpabuf_head(resp);
5853 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
5854 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5855
5856 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5857 wrapped_data, wrapped_data_len,
5858 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005859 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005860 goto fail;
5861 }
5862 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5863 unwrapped, unwrapped_len);
5864
5865 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005866 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005867 goto fail;
5868 }
5869
5870 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5871 DPP_ATTR_ENROLLEE_NONCE,
5872 &e_nonce_len);
5873 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005874 dpp_auth_fail(auth,
5875 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005876 goto fail;
5877 }
5878 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5879 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005880 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005881 goto fail;
5882 }
5883
5884 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5885 DPP_ATTR_STATUS, &status_len);
5886 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005887 dpp_auth_fail(auth,
5888 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005889 goto fail;
5890 }
Hai Shalom021b0b52019-04-10 11:17:58 -07005891 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005892 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5893 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005894 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005895 goto fail;
5896 }
5897
5898 conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
5899 DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
5900 if (!conf_obj) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005901 dpp_auth_fail(auth,
5902 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005903 goto fail;
5904 }
5905 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
5906 conf_obj, conf_obj_len);
5907 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
5908 goto fail;
5909
5910 ret = 0;
5911
5912fail:
5913 os_free(unwrapped);
5914 return ret;
5915}
5916
5917
Hai Shalom021b0b52019-04-10 11:17:58 -07005918#ifdef CONFIG_DPP2
5919enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
5920 const u8 *hdr,
5921 const u8 *attr_start, size_t attr_len)
5922{
5923 const u8 *wrapped_data, *status, *e_nonce;
5924 u16 wrapped_data_len, status_len, e_nonce_len;
5925 const u8 *addr[2];
5926 size_t len[2];
5927 u8 *unwrapped = NULL;
5928 size_t unwrapped_len = 0;
5929 enum dpp_status_error ret = 256;
5930
5931 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
5932 &wrapped_data_len);
5933 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
5934 dpp_auth_fail(auth,
5935 "Missing or invalid required Wrapped Data attribute");
5936 goto fail;
5937 }
5938 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
5939 wrapped_data, wrapped_data_len);
5940
5941 attr_len = wrapped_data - 4 - attr_start;
5942
5943 addr[0] = hdr;
5944 len[0] = DPP_HDR_LEN;
5945 addr[1] = attr_start;
5946 len[1] = attr_len;
5947 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
5948 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
5949 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5950 wrapped_data, wrapped_data_len);
5951 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5952 unwrapped = os_malloc(unwrapped_len);
5953 if (!unwrapped)
5954 goto fail;
5955 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5956 wrapped_data, wrapped_data_len,
5957 2, addr, len, unwrapped) < 0) {
5958 dpp_auth_fail(auth, "AES-SIV decryption failed");
5959 goto fail;
5960 }
5961 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5962 unwrapped, unwrapped_len);
5963
5964 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
5965 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
5966 goto fail;
5967 }
5968
5969 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5970 DPP_ATTR_ENROLLEE_NONCE,
5971 &e_nonce_len);
5972 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
5973 dpp_auth_fail(auth,
5974 "Missing or invalid Enrollee Nonce attribute");
5975 goto fail;
5976 }
5977 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5978 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
5979 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
5980 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
5981 auth->e_nonce, e_nonce_len);
5982 goto fail;
5983 }
5984
5985 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
5986 &status_len);
5987 if (!status || status_len < 1) {
5988 dpp_auth_fail(auth,
5989 "Missing or invalid required DPP Status attribute");
5990 goto fail;
5991 }
5992 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5993 ret = status[0];
5994
5995fail:
5996 bin_clear_free(unwrapped, unwrapped_len);
5997 return ret;
5998}
5999#endif /* CONFIG_DPP2 */
6000
6001
6002struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
6003 enum dpp_status_error status)
6004{
6005 struct wpabuf *msg, *clear;
6006 size_t nonce_len, clear_len, attr_len;
6007 const u8 *addr[2];
6008 size_t len[2];
6009 u8 *wrapped;
6010
6011 nonce_len = auth->curve->nonce_len;
6012 clear_len = 5 + 4 + nonce_len;
6013 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6014 clear = wpabuf_alloc(clear_len);
6015 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
6016 if (!clear || !msg)
6017 return NULL;
6018
6019 /* DPP Status */
6020 dpp_build_attr_status(clear, status);
6021
6022 /* E-nonce */
6023 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
6024 wpabuf_put_le16(clear, nonce_len);
6025 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
6026
6027 /* OUI, OUI type, Crypto Suite, DPP frame type */
6028 addr[0] = wpabuf_head_u8(msg) + 2;
6029 len[0] = 3 + 1 + 1 + 1;
6030 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6031
6032 /* Attributes before Wrapped Data (none) */
6033 addr[1] = wpabuf_put(msg, 0);
6034 len[1] = 0;
6035 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6036
6037 /* Wrapped Data */
6038 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6039 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6040 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6041
6042 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6043 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
6044 wpabuf_head(clear), wpabuf_len(clear),
6045 2, addr, len, wrapped) < 0)
6046 goto fail;
6047
6048 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
6049 wpabuf_free(clear);
6050 return msg;
6051fail:
6052 wpabuf_free(clear);
6053 wpabuf_free(msg);
6054 return NULL;
6055}
6056
6057
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006058void dpp_configurator_free(struct dpp_configurator *conf)
6059{
6060 if (!conf)
6061 return;
6062 EVP_PKEY_free(conf->csign);
6063 os_free(conf->kid);
6064 os_free(conf);
6065}
6066
6067
Roshan Pius3a1667e2018-07-03 15:17:14 -07006068int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
6069 size_t buflen)
6070{
6071 EC_KEY *eckey;
6072 int key_len, ret = -1;
6073 unsigned char *key = NULL;
6074
6075 if (!conf->csign)
6076 return -1;
6077
6078 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
6079 if (!eckey)
6080 return -1;
6081
6082 key_len = i2d_ECPrivateKey(eckey, &key);
6083 if (key_len > 0)
6084 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
6085
6086 EC_KEY_free(eckey);
6087 OPENSSL_free(key);
6088 return ret;
6089}
6090
6091
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006092struct dpp_configurator *
6093dpp_keygen_configurator(const char *curve, const u8 *privkey,
6094 size_t privkey_len)
6095{
6096 struct dpp_configurator *conf;
6097 struct wpabuf *csign_pub = NULL;
6098 u8 kid_hash[SHA256_MAC_LEN];
6099 const u8 *addr[1];
6100 size_t len[1];
6101
6102 conf = os_zalloc(sizeof(*conf));
6103 if (!conf)
6104 return NULL;
6105
6106 if (!curve) {
6107 conf->curve = &dpp_curves[0];
6108 } else {
6109 conf->curve = dpp_get_curve_name(curve);
6110 if (!conf->curve) {
6111 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6112 curve);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006113 os_free(conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006114 return NULL;
6115 }
6116 }
6117 if (privkey)
6118 conf->csign = dpp_set_keypair(&conf->curve, privkey,
6119 privkey_len);
6120 else
6121 conf->csign = dpp_gen_keypair(conf->curve);
6122 if (!conf->csign)
6123 goto fail;
6124 conf->own = 1;
6125
6126 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
6127 if (!csign_pub) {
6128 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
6129 goto fail;
6130 }
6131
6132 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6133 addr[0] = wpabuf_head(csign_pub);
6134 len[0] = wpabuf_len(csign_pub);
6135 if (sha256_vector(1, addr, len, kid_hash) < 0) {
6136 wpa_printf(MSG_DEBUG,
6137 "DPP: Failed to derive kid for C-sign-key");
6138 goto fail;
6139 }
6140
6141 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
6142 NULL, 0);
6143 if (!conf->kid)
6144 goto fail;
6145out:
6146 wpabuf_free(csign_pub);
6147 return conf;
6148fail:
6149 dpp_configurator_free(conf);
6150 conf = NULL;
6151 goto out;
6152}
6153
6154
6155int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006156 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006157{
6158 struct wpabuf *conf_obj;
6159 int ret = -1;
6160
6161 if (!auth->conf) {
6162 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
6163 return -1;
6164 }
6165
6166 if (!curve) {
6167 auth->curve = &dpp_curves[0];
6168 } else {
6169 auth->curve = dpp_get_curve_name(curve);
6170 if (!auth->curve) {
6171 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6172 curve);
6173 return -1;
6174 }
6175 }
6176 wpa_printf(MSG_DEBUG,
6177 "DPP: Building own configuration/connector with curve %s",
6178 auth->curve->name);
6179
6180 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
6181 if (!auth->own_protocol_key)
6182 return -1;
6183 dpp_copy_netaccesskey(auth);
6184 auth->peer_protocol_key = auth->own_protocol_key;
6185 dpp_copy_csign(auth, auth->conf->csign);
6186
Roshan Pius3a1667e2018-07-03 15:17:14 -07006187 conf_obj = dpp_build_conf_obj(auth, ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006188 if (!conf_obj)
6189 goto fail;
6190 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
6191 wpabuf_len(conf_obj));
6192fail:
6193 wpabuf_free(conf_obj);
6194 auth->peer_protocol_key = NULL;
6195 return ret;
6196}
6197
6198
6199static int dpp_compatible_netrole(const char *role1, const char *role2)
6200{
6201 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
6202 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
6203}
6204
6205
6206static int dpp_connector_compatible_group(struct json_token *root,
6207 const char *group_id,
6208 const char *net_role)
6209{
6210 struct json_token *groups, *token;
6211
6212 groups = json_get_member(root, "groups");
6213 if (!groups || groups->type != JSON_ARRAY)
6214 return 0;
6215
6216 for (token = groups->child; token; token = token->sibling) {
6217 struct json_token *id, *role;
6218
6219 id = json_get_member(token, "groupId");
6220 if (!id || id->type != JSON_STRING)
6221 continue;
6222
6223 role = json_get_member(token, "netRole");
6224 if (!role || role->type != JSON_STRING)
6225 continue;
6226
6227 if (os_strcmp(id->string, "*") != 0 &&
6228 os_strcmp(group_id, "*") != 0 &&
6229 os_strcmp(id->string, group_id) != 0)
6230 continue;
6231
6232 if (dpp_compatible_netrole(role->string, net_role))
6233 return 1;
6234 }
6235
6236 return 0;
6237}
6238
6239
6240static int dpp_connector_match_groups(struct json_token *own_root,
6241 struct json_token *peer_root)
6242{
6243 struct json_token *groups, *token;
6244
6245 groups = json_get_member(peer_root, "groups");
6246 if (!groups || groups->type != JSON_ARRAY) {
6247 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
6248 return 0;
6249 }
6250
6251 for (token = groups->child; token; token = token->sibling) {
6252 struct json_token *id, *role;
6253
6254 id = json_get_member(token, "groupId");
6255 if (!id || id->type != JSON_STRING) {
6256 wpa_printf(MSG_DEBUG,
6257 "DPP: Missing peer groupId string");
6258 continue;
6259 }
6260
6261 role = json_get_member(token, "netRole");
6262 if (!role || role->type != JSON_STRING) {
6263 wpa_printf(MSG_DEBUG,
6264 "DPP: Missing peer groups::netRole string");
6265 continue;
6266 }
6267 wpa_printf(MSG_DEBUG,
6268 "DPP: peer connector group: groupId='%s' netRole='%s'",
6269 id->string, role->string);
6270 if (dpp_connector_compatible_group(own_root, id->string,
6271 role->string)) {
6272 wpa_printf(MSG_DEBUG,
6273 "DPP: Compatible group/netRole in own connector");
6274 return 1;
6275 }
6276 }
6277
6278 return 0;
6279}
6280
6281
6282static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
6283 unsigned int hash_len)
6284{
6285 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6286 const char *info = "DPP PMK";
6287 int res;
6288
6289 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6290
6291 /* HKDF-Extract(<>, N.x) */
6292 os_memset(salt, 0, hash_len);
6293 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
6294 return -1;
6295 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6296 prk, hash_len);
6297
6298 /* HKDF-Expand(PRK, info, L) */
6299 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
6300 os_memset(prk, 0, hash_len);
6301 if (res < 0)
6302 return -1;
6303
6304 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6305 pmk, hash_len);
6306 return 0;
6307}
6308
6309
6310static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
6311 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
6312{
6313 struct wpabuf *nkx, *pkx;
6314 int ret = -1, res;
6315 const u8 *addr[2];
6316 size_t len[2];
6317 u8 hash[SHA256_MAC_LEN];
6318
6319 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6320 nkx = dpp_get_pubkey_point(own_key, 0);
6321 pkx = dpp_get_pubkey_point(peer_key, 0);
6322 if (!nkx || !pkx)
6323 goto fail;
6324 addr[0] = wpabuf_head(nkx);
6325 len[0] = wpabuf_len(nkx) / 2;
6326 addr[1] = wpabuf_head(pkx);
6327 len[1] = wpabuf_len(pkx) / 2;
6328 if (len[0] != len[1])
6329 goto fail;
6330 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
6331 addr[0] = wpabuf_head(pkx);
6332 addr[1] = wpabuf_head(nkx);
6333 }
6334 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
6335 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
6336 res = sha256_vector(2, addr, len, hash);
6337 if (res < 0)
6338 goto fail;
6339 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
6340 os_memcpy(pmkid, hash, PMKID_LEN);
6341 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
6342 ret = 0;
6343fail:
6344 wpabuf_free(nkx);
6345 wpabuf_free(pkx);
6346 return ret;
6347}
6348
6349
Roshan Pius3a1667e2018-07-03 15:17:14 -07006350enum dpp_status_error
6351dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
6352 const u8 *net_access_key, size_t net_access_key_len,
6353 const u8 *csign_key, size_t csign_key_len,
6354 const u8 *peer_connector, size_t peer_connector_len,
6355 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006356{
6357 struct json_token *root = NULL, *netkey, *token;
6358 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006359 enum dpp_status_error ret = 255, res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006360 EVP_PKEY *own_key = NULL, *peer_key = NULL;
6361 struct wpabuf *own_key_pub = NULL;
6362 const struct dpp_curve_params *curve, *own_curve;
6363 struct dpp_signed_connector_info info;
6364 const unsigned char *p;
6365 EVP_PKEY *csign = NULL;
6366 char *signed_connector = NULL;
6367 const char *pos, *end;
6368 unsigned char *own_conn = NULL;
6369 size_t own_conn_len;
6370 EVP_PKEY_CTX *ctx = NULL;
6371 size_t Nx_len;
6372 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
6373
6374 os_memset(intro, 0, sizeof(*intro));
6375 os_memset(&info, 0, sizeof(info));
6376 if (expiry)
6377 *expiry = 0;
6378
6379 p = csign_key;
6380 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
6381 if (!csign) {
6382 wpa_printf(MSG_ERROR,
6383 "DPP: Failed to parse local C-sign-key information");
6384 goto fail;
6385 }
6386
6387 own_key = dpp_set_keypair(&own_curve, net_access_key,
6388 net_access_key_len);
6389 if (!own_key) {
6390 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
6391 goto fail;
6392 }
6393
6394 pos = os_strchr(own_connector, '.');
6395 if (!pos) {
6396 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
6397 goto fail;
6398 }
6399 pos++;
6400 end = os_strchr(pos, '.');
6401 if (!end) {
6402 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
6403 goto fail;
6404 }
6405 own_conn = base64_url_decode((const unsigned char *) pos,
6406 end - pos, &own_conn_len);
6407 if (!own_conn) {
6408 wpa_printf(MSG_DEBUG,
6409 "DPP: Failed to base64url decode own signedConnector JWS Payload");
6410 goto fail;
6411 }
6412
6413 own_root = json_parse((const char *) own_conn, own_conn_len);
6414 if (!own_root) {
6415 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
6416 goto fail;
6417 }
6418
6419 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
6420 peer_connector, peer_connector_len);
6421 signed_connector = os_malloc(peer_connector_len + 1);
6422 if (!signed_connector)
6423 goto fail;
6424 os_memcpy(signed_connector, peer_connector, peer_connector_len);
6425 signed_connector[peer_connector_len] = '\0';
6426
Roshan Pius3a1667e2018-07-03 15:17:14 -07006427 res = dpp_process_signed_connector(&info, csign, signed_connector);
6428 if (res != DPP_STATUS_OK) {
6429 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006430 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006431 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006432
6433 root = json_parse((const char *) info.payload, info.payload_len);
6434 if (!root) {
6435 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006436 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006437 goto fail;
6438 }
6439
6440 if (!dpp_connector_match_groups(own_root, root)) {
6441 wpa_printf(MSG_DEBUG,
6442 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006443 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006444 goto fail;
6445 }
6446
6447 token = json_get_member(root, "expiry");
6448 if (!token || token->type != JSON_STRING) {
6449 wpa_printf(MSG_DEBUG,
6450 "DPP: No expiry string found - connector does not expire");
6451 } else {
6452 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
6453 if (dpp_key_expired(token->string, expiry)) {
6454 wpa_printf(MSG_DEBUG,
6455 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006456 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006457 goto fail;
6458 }
6459 }
6460
6461 netkey = json_get_member(root, "netAccessKey");
6462 if (!netkey || netkey->type != JSON_OBJECT) {
6463 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006464 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006465 goto fail;
6466 }
6467
6468 peer_key = dpp_parse_jwk(netkey, &curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006469 if (!peer_key) {
6470 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006471 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006472 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006473 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
6474
6475 if (own_curve != curve) {
6476 wpa_printf(MSG_DEBUG,
6477 "DPP: Mismatching netAccessKey curves (%s != %s)",
6478 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006479 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006480 goto fail;
6481 }
6482
6483 /* ECDH: N = nk * PK */
6484 ctx = EVP_PKEY_CTX_new(own_key, NULL);
6485 if (!ctx ||
6486 EVP_PKEY_derive_init(ctx) != 1 ||
6487 EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
6488 EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
6489 Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
6490 EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
6491 wpa_printf(MSG_ERROR,
6492 "DPP: Failed to derive ECDH shared secret: %s",
6493 ERR_error_string(ERR_get_error(), NULL));
6494 goto fail;
6495 }
6496
6497 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
6498 Nx, Nx_len);
6499
6500 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6501 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
6502 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
6503 goto fail;
6504 }
6505 intro->pmk_len = curve->hash_len;
6506
6507 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6508 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
6509 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
6510 goto fail;
6511 }
6512
Roshan Pius3a1667e2018-07-03 15:17:14 -07006513 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006514fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07006515 if (ret != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006516 os_memset(intro, 0, sizeof(*intro));
6517 os_memset(Nx, 0, sizeof(Nx));
6518 EVP_PKEY_CTX_free(ctx);
6519 os_free(own_conn);
6520 os_free(signed_connector);
6521 os_free(info.payload);
6522 EVP_PKEY_free(own_key);
6523 wpabuf_free(own_key_pub);
6524 EVP_PKEY_free(peer_key);
6525 EVP_PKEY_free(csign);
6526 json_free(root);
6527 json_free(own_root);
6528 return ret;
6529}
6530
6531
6532static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
6533 int init)
6534{
6535 EC_GROUP *group;
6536 size_t len = curve->prime_len;
6537 const u8 *x, *y;
6538
6539 switch (curve->ike_group) {
6540 case 19:
6541 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
6542 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
6543 break;
6544 case 20:
6545 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
6546 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
6547 break;
6548 case 21:
6549 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
6550 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
6551 break;
6552 case 28:
6553 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
6554 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
6555 break;
6556 case 29:
6557 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
6558 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
6559 break;
6560 case 30:
6561 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
6562 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
6563 break;
6564 default:
6565 return NULL;
6566 }
6567
6568 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6569 if (!group)
6570 return NULL;
Hai Shalomf1c97642019-07-19 23:42:07 +00006571 return dpp_set_pubkey_point_group(group, x, y, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006572}
6573
6574
6575static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
6576 const u8 *mac_init, const char *code,
6577 const char *identifier, BN_CTX *bnctx,
Hai Shalomf1c97642019-07-19 23:42:07 +00006578 const EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006579{
6580 u8 hash[DPP_MAX_HASH_LEN];
6581 const u8 *addr[3];
6582 size_t len[3];
6583 unsigned int num_elem = 0;
6584 EC_POINT *Qi = NULL;
6585 EVP_PKEY *Pi = NULL;
6586 EC_KEY *Pi_ec = NULL;
6587 const EC_POINT *Pi_point;
6588 BIGNUM *hash_bn = NULL;
6589 const EC_GROUP *group = NULL;
6590 EC_GROUP *group2 = NULL;
6591
6592 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6593
6594 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
6595 addr[num_elem] = mac_init;
6596 len[num_elem] = ETH_ALEN;
6597 num_elem++;
6598 if (identifier) {
6599 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6600 identifier);
6601 addr[num_elem] = (const u8 *) identifier;
6602 len[num_elem] = os_strlen(identifier);
6603 num_elem++;
6604 }
6605 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
6606 addr[num_elem] = (const u8 *) code;
6607 len[num_elem] = os_strlen(code);
6608 num_elem++;
6609 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6610 goto fail;
6611 wpa_hexdump_key(MSG_DEBUG,
6612 "DPP: H(MAC-Initiator | [identifier |] code)",
6613 hash, curve->hash_len);
6614 Pi = dpp_pkex_get_role_elem(curve, 1);
6615 if (!Pi)
6616 goto fail;
6617 dpp_debug_print_key("DPP: Pi", Pi);
6618 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
6619 if (!Pi_ec)
6620 goto fail;
6621 Pi_point = EC_KEY_get0_public_key(Pi_ec);
6622
6623 group = EC_KEY_get0_group(Pi_ec);
6624 if (!group)
6625 goto fail;
6626 group2 = EC_GROUP_dup(group);
6627 if (!group2)
6628 goto fail;
6629 Qi = EC_POINT_new(group2);
6630 if (!Qi) {
6631 EC_GROUP_free(group2);
6632 goto fail;
6633 }
6634 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6635 if (!hash_bn ||
6636 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
6637 goto fail;
6638 if (EC_POINT_is_at_infinity(group, Qi)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006639 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006640 goto fail;
6641 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07006642 dpp_debug_print_point("DPP: Qi", group, Qi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006643out:
6644 EC_KEY_free(Pi_ec);
6645 EVP_PKEY_free(Pi);
6646 BN_clear_free(hash_bn);
Hai Shalomf1c97642019-07-19 23:42:07 +00006647 if (ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006648 *ret_group = group2;
6649 return Qi;
6650fail:
6651 EC_POINT_free(Qi);
6652 Qi = NULL;
6653 goto out;
6654}
6655
6656
6657static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
6658 const u8 *mac_resp, const char *code,
6659 const char *identifier, BN_CTX *bnctx,
Hai Shalomf1c97642019-07-19 23:42:07 +00006660 const EC_GROUP **ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006661{
6662 u8 hash[DPP_MAX_HASH_LEN];
6663 const u8 *addr[3];
6664 size_t len[3];
6665 unsigned int num_elem = 0;
6666 EC_POINT *Qr = NULL;
6667 EVP_PKEY *Pr = NULL;
6668 EC_KEY *Pr_ec = NULL;
6669 const EC_POINT *Pr_point;
6670 BIGNUM *hash_bn = NULL;
6671 const EC_GROUP *group = NULL;
6672 EC_GROUP *group2 = NULL;
6673
6674 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6675
6676 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
6677 addr[num_elem] = mac_resp;
6678 len[num_elem] = ETH_ALEN;
6679 num_elem++;
6680 if (identifier) {
6681 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6682 identifier);
6683 addr[num_elem] = (const u8 *) identifier;
6684 len[num_elem] = os_strlen(identifier);
6685 num_elem++;
6686 }
6687 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
6688 addr[num_elem] = (const u8 *) code;
6689 len[num_elem] = os_strlen(code);
6690 num_elem++;
6691 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6692 goto fail;
6693 wpa_hexdump_key(MSG_DEBUG,
6694 "DPP: H(MAC-Responder | [identifier |] code)",
6695 hash, curve->hash_len);
6696 Pr = dpp_pkex_get_role_elem(curve, 0);
6697 if (!Pr)
6698 goto fail;
6699 dpp_debug_print_key("DPP: Pr", Pr);
6700 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
6701 if (!Pr_ec)
6702 goto fail;
6703 Pr_point = EC_KEY_get0_public_key(Pr_ec);
6704
6705 group = EC_KEY_get0_group(Pr_ec);
6706 if (!group)
6707 goto fail;
6708 group2 = EC_GROUP_dup(group);
6709 if (!group2)
6710 goto fail;
6711 Qr = EC_POINT_new(group2);
6712 if (!Qr) {
6713 EC_GROUP_free(group2);
6714 goto fail;
6715 }
6716 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6717 if (!hash_bn ||
6718 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
6719 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006720 if (EC_POINT_is_at_infinity(group, Qr)) {
6721 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
6722 goto fail;
6723 }
6724 dpp_debug_print_point("DPP: Qr", group, Qr);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006725out:
6726 EC_KEY_free(Pr_ec);
6727 EVP_PKEY_free(Pr);
6728 BN_clear_free(hash_bn);
Hai Shalomf1c97642019-07-19 23:42:07 +00006729 if (ret_group)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006730 *ret_group = group2;
6731 return Qr;
6732fail:
6733 EC_POINT_free(Qr);
6734 Qr = NULL;
6735 goto out;
6736}
6737
6738
Roshan Pius3a1667e2018-07-03 15:17:14 -07006739#ifdef CONFIG_TESTING_OPTIONS
6740static int dpp_test_gen_invalid_key(struct wpabuf *msg,
6741 const struct dpp_curve_params *curve)
6742{
6743 BN_CTX *ctx;
6744 BIGNUM *x, *y;
6745 int ret = -1;
6746 EC_GROUP *group;
6747 EC_POINT *point;
6748
6749 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6750 if (!group)
6751 return -1;
6752
6753 ctx = BN_CTX_new();
6754 point = EC_POINT_new(group);
6755 x = BN_new();
6756 y = BN_new();
6757 if (!ctx || !point || !x || !y)
6758 goto fail;
6759
6760 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
6761 goto fail;
6762
6763 /* Generate a random y coordinate that results in a point that is not
6764 * on the curve. */
6765 for (;;) {
6766 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
6767 goto fail;
6768
6769 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
6770 ctx) != 1) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006771#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006772 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6773 * return an error from EC_POINT_set_affine_coordinates_GFp()
6774 * when the point is not on the curve. */
6775 break;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006776#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006777 goto fail;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006778#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006779 }
6780
6781 if (!EC_POINT_is_on_curve(group, point, ctx))
6782 break;
6783 }
6784
6785 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
6786 curve->prime_len) < 0 ||
6787 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
6788 curve->prime_len) < 0)
6789 goto fail;
6790
6791 ret = 0;
6792fail:
6793 if (ret < 0)
6794 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
6795 BN_free(x);
6796 BN_free(y);
6797 EC_POINT_free(point);
6798 BN_CTX_free(ctx);
6799
6800 return ret;
6801}
6802#endif /* CONFIG_TESTING_OPTIONS */
6803
6804
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006805static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
6806{
6807 EC_KEY *X_ec = NULL;
6808 const EC_POINT *X_point;
6809 BN_CTX *bnctx = NULL;
Hai Shalomf1c97642019-07-19 23:42:07 +00006810 const EC_GROUP *group;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006811 EC_POINT *Qi = NULL, *M = NULL;
6812 struct wpabuf *M_buf = NULL;
6813 BIGNUM *Mx = NULL, *My = NULL;
6814 struct wpabuf *msg = NULL;
6815 size_t attr_len;
6816 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006817
6818 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
6819
6820 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6821 bnctx = BN_CTX_new();
6822 if (!bnctx)
6823 goto fail;
6824 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
6825 pkex->identifier, bnctx, &group);
6826 if (!Qi)
6827 goto fail;
6828
6829 /* Generate a random ephemeral keypair x/X */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006830#ifdef CONFIG_TESTING_OPTIONS
6831 if (dpp_pkex_ephemeral_key_override_len) {
6832 const struct dpp_curve_params *tmp_curve;
6833
6834 wpa_printf(MSG_INFO,
6835 "DPP: TESTING - override ephemeral key x/X");
6836 pkex->x = dpp_set_keypair(&tmp_curve,
6837 dpp_pkex_ephemeral_key_override,
6838 dpp_pkex_ephemeral_key_override_len);
6839 } else {
6840 pkex->x = dpp_gen_keypair(curve);
6841 }
6842#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006843 pkex->x = dpp_gen_keypair(curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006844#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006845 if (!pkex->x)
6846 goto fail;
6847
6848 /* M = X + Qi */
6849 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
6850 if (!X_ec)
6851 goto fail;
6852 X_point = EC_KEY_get0_public_key(X_ec);
6853 if (!X_point)
6854 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006855 dpp_debug_print_point("DPP: X", group, X_point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006856 M = EC_POINT_new(group);
6857 Mx = BN_new();
6858 My = BN_new();
6859 if (!M || !Mx || !My ||
6860 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
6861 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
6862 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006863 dpp_debug_print_point("DPP: M", group, M);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006864
6865 /* Initiator -> Responder: group, [identifier,] M */
6866 attr_len = 4 + 2;
6867 if (pkex->identifier)
6868 attr_len += 4 + os_strlen(pkex->identifier);
6869 attr_len += 4 + 2 * curve->prime_len;
6870 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
6871 if (!msg)
6872 goto fail;
6873
Roshan Pius3a1667e2018-07-03 15:17:14 -07006874#ifdef CONFIG_TESTING_OPTIONS
6875 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
6876 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
6877 goto skip_finite_cyclic_group;
6878 }
6879#endif /* CONFIG_TESTING_OPTIONS */
6880
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006881 /* Finite Cyclic Group attribute */
6882 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6883 wpabuf_put_le16(msg, 2);
6884 wpabuf_put_le16(msg, curve->ike_group);
6885
Roshan Pius3a1667e2018-07-03 15:17:14 -07006886#ifdef CONFIG_TESTING_OPTIONS
6887skip_finite_cyclic_group:
6888#endif /* CONFIG_TESTING_OPTIONS */
6889
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006890 /* Code Identifier attribute */
6891 if (pkex->identifier) {
6892 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6893 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6894 wpabuf_put_str(msg, pkex->identifier);
6895 }
6896
Roshan Pius3a1667e2018-07-03 15:17:14 -07006897#ifdef CONFIG_TESTING_OPTIONS
6898 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6899 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6900 goto out;
6901 }
6902#endif /* CONFIG_TESTING_OPTIONS */
6903
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006904 /* M in Encrypted Key attribute */
6905 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6906 wpabuf_put_le16(msg, 2 * curve->prime_len);
6907
Roshan Pius3a1667e2018-07-03 15:17:14 -07006908#ifdef CONFIG_TESTING_OPTIONS
6909 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6910 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
6911 if (dpp_test_gen_invalid_key(msg, curve) < 0)
6912 goto fail;
6913 goto out;
6914 }
6915#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006916
Roshan Pius3a1667e2018-07-03 15:17:14 -07006917 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
6918 curve->prime_len) < 0 ||
6919 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
6920 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
6921 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006922 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006923
6924out:
6925 wpabuf_free(M_buf);
6926 EC_KEY_free(X_ec);
6927 EC_POINT_free(M);
6928 EC_POINT_free(Qi);
6929 BN_clear_free(Mx);
6930 BN_clear_free(My);
6931 BN_CTX_free(bnctx);
6932 return msg;
6933fail:
6934 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
6935 wpabuf_free(msg);
6936 msg = NULL;
6937 goto out;
6938}
6939
6940
Roshan Pius3a1667e2018-07-03 15:17:14 -07006941static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
6942{
6943 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
6944}
6945
6946
6947struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006948 const u8 *own_mac,
6949 const char *identifier,
6950 const char *code)
6951{
6952 struct dpp_pkex *pkex;
6953
Roshan Pius3a1667e2018-07-03 15:17:14 -07006954#ifdef CONFIG_TESTING_OPTIONS
6955 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
6956 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
6957 MAC2STR(dpp_pkex_own_mac_override));
6958 own_mac = dpp_pkex_own_mac_override;
6959 }
6960#endif /* CONFIG_TESTING_OPTIONS */
6961
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006962 pkex = os_zalloc(sizeof(*pkex));
6963 if (!pkex)
6964 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006965 pkex->msg_ctx = msg_ctx;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006966 pkex->initiator = 1;
6967 pkex->own_bi = bi;
6968 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6969 if (identifier) {
6970 pkex->identifier = os_strdup(identifier);
6971 if (!pkex->identifier)
6972 goto fail;
6973 }
6974 pkex->code = os_strdup(code);
6975 if (!pkex->code)
6976 goto fail;
6977 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
6978 if (!pkex->exchange_req)
6979 goto fail;
6980 return pkex;
6981fail:
6982 dpp_pkex_free(pkex);
6983 return NULL;
6984}
6985
6986
Roshan Pius3a1667e2018-07-03 15:17:14 -07006987static struct wpabuf *
6988dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
6989 enum dpp_status_error status,
6990 const BIGNUM *Nx, const BIGNUM *Ny)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006991{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006992 struct wpabuf *msg = NULL;
6993 size_t attr_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006994 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006995
6996 /* Initiator -> Responder: DPP Status, [identifier,] N */
6997 attr_len = 4 + 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006998 if (pkex->identifier)
6999 attr_len += 4 + os_strlen(pkex->identifier);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007000 attr_len += 4 + 2 * curve->prime_len;
7001 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
7002 if (!msg)
7003 goto fail;
7004
Roshan Pius3a1667e2018-07-03 15:17:14 -07007005#ifdef CONFIG_TESTING_OPTIONS
7006 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
7007 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
7008 goto skip_status;
7009 }
7010
7011 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
7012 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
7013 status = 255;
7014 }
7015#endif /* CONFIG_TESTING_OPTIONS */
7016
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007017 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07007018 dpp_build_attr_status(msg, status);
7019
7020#ifdef CONFIG_TESTING_OPTIONS
7021skip_status:
7022#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007023
7024 /* Code Identifier attribute */
7025 if (pkex->identifier) {
7026 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
7027 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
7028 wpabuf_put_str(msg, pkex->identifier);
7029 }
7030
Roshan Pius3a1667e2018-07-03 15:17:14 -07007031 if (status != DPP_STATUS_OK)
7032 goto skip_encrypted_key;
7033
7034#ifdef CONFIG_TESTING_OPTIONS
7035 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7036 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
7037 goto skip_encrypted_key;
7038 }
7039#endif /* CONFIG_TESTING_OPTIONS */
7040
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007041 /* N in Encrypted Key attribute */
7042 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
7043 wpabuf_put_le16(msg, 2 * curve->prime_len);
7044
Roshan Pius3a1667e2018-07-03 15:17:14 -07007045#ifdef CONFIG_TESTING_OPTIONS
7046 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7047 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
7048 if (dpp_test_gen_invalid_key(msg, curve) < 0)
7049 goto fail;
7050 goto skip_encrypted_key;
7051 }
7052#endif /* CONFIG_TESTING_OPTIONS */
7053
7054 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
7055 curve->prime_len) < 0 ||
7056 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
7057 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
7058 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007059 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007060
Roshan Pius3a1667e2018-07-03 15:17:14 -07007061skip_encrypted_key:
7062 if (status == DPP_STATUS_BAD_GROUP) {
7063 /* Finite Cyclic Group attribute */
7064 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
7065 wpabuf_put_le16(msg, 2);
7066 wpabuf_put_le16(msg, curve->ike_group);
7067 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007068
Roshan Pius3a1667e2018-07-03 15:17:14 -07007069 return msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007070fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07007071 wpabuf_free(msg);
7072 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007073}
7074
7075
7076static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
7077 const u8 *Mx, size_t Mx_len,
7078 const u8 *Nx, size_t Nx_len,
7079 const char *code,
7080 const u8 *Kx, size_t Kx_len,
7081 u8 *z, unsigned int hash_len)
7082{
7083 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
7084 int res;
7085 u8 *info, *pos;
7086 size_t info_len;
7087
7088 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7089 */
7090
7091 /* HKDF-Extract(<>, IKM=K.x) */
7092 os_memset(salt, 0, hash_len);
7093 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
7094 return -1;
7095 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
7096 prk, hash_len);
7097 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
7098 info = os_malloc(info_len);
7099 if (!info)
7100 return -1;
7101 pos = info;
7102 os_memcpy(pos, mac_init, ETH_ALEN);
7103 pos += ETH_ALEN;
7104 os_memcpy(pos, mac_resp, ETH_ALEN);
7105 pos += ETH_ALEN;
7106 os_memcpy(pos, Mx, Mx_len);
7107 pos += Mx_len;
7108 os_memcpy(pos, Nx, Nx_len);
7109 pos += Nx_len;
7110 os_memcpy(pos, code, os_strlen(code));
7111
7112 /* HKDF-Expand(PRK, info, L) */
7113 if (hash_len == 32)
7114 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
7115 z, hash_len);
7116 else if (hash_len == 48)
7117 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
7118 z, hash_len);
7119 else if (hash_len == 64)
7120 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
7121 z, hash_len);
7122 else
7123 res = -1;
7124 os_free(info);
7125 os_memset(prk, 0, hash_len);
7126 if (res < 0)
7127 return -1;
7128
7129 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
7130 z, hash_len);
7131 return 0;
7132}
7133
7134
Hai Shalom74f70d42019-02-11 14:42:39 -08007135static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
7136 const char *identifier)
7137{
7138 if (!attr_id && identifier) {
7139 wpa_printf(MSG_DEBUG,
7140 "DPP: No PKEX code identifier received, but expected one");
7141 return 0;
7142 }
7143
7144 if (attr_id && !identifier) {
7145 wpa_printf(MSG_DEBUG,
7146 "DPP: PKEX code identifier received, but not expecting one");
7147 return 0;
7148 }
7149
7150 if (attr_id && identifier &&
7151 (os_strlen(identifier) != attr_id_len ||
7152 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
7153 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
7154 return 0;
7155 }
7156
7157 return 1;
7158}
7159
7160
Roshan Pius3a1667e2018-07-03 15:17:14 -07007161struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
7162 struct dpp_bootstrap_info *bi,
7163 const u8 *own_mac,
7164 const u8 *peer_mac,
7165 const char *identifier,
7166 const char *code,
7167 const u8 *buf, size_t len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007168{
Roshan Pius3a1667e2018-07-03 15:17:14 -07007169 const u8 *attr_group, *attr_id, *attr_key;
7170 u16 attr_group_len, attr_id_len, attr_key_len;
7171 const struct dpp_curve_params *curve = bi->curve;
7172 u16 ike_group;
7173 struct dpp_pkex *pkex = NULL;
7174 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007175 BN_CTX *bnctx = NULL;
Hai Shalomf1c97642019-07-19 23:42:07 +00007176 const EC_GROUP *group;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007177 BIGNUM *Mx = NULL, *My = NULL;
7178 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
7179 const EC_POINT *Y_point;
7180 BIGNUM *Nx = NULL, *Ny = NULL;
7181 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
7182 size_t Kx_len;
7183 int res;
7184 EVP_PKEY_CTX *ctx = NULL;
7185
7186 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
7187 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7188 "PKEX counter t limit reached - ignore message");
7189 return NULL;
7190 }
7191
7192#ifdef CONFIG_TESTING_OPTIONS
7193 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
7194 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
7195 MAC2STR(dpp_pkex_peer_mac_override));
7196 peer_mac = dpp_pkex_peer_mac_override;
7197 }
7198 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
7199 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
7200 MAC2STR(dpp_pkex_own_mac_override));
7201 own_mac = dpp_pkex_own_mac_override;
7202 }
7203#endif /* CONFIG_TESTING_OPTIONS */
7204
Hai Shalom74f70d42019-02-11 14:42:39 -08007205 attr_id_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007206 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
7207 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08007208 if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
Roshan Pius3a1667e2018-07-03 15:17:14 -07007209 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007210
7211 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
7212 &attr_group_len);
7213 if (!attr_group || attr_group_len != 2) {
7214 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7215 "Missing or invalid Finite Cyclic Group attribute");
7216 return NULL;
7217 }
7218 ike_group = WPA_GET_LE16(attr_group);
7219 if (ike_group != curve->ike_group) {
7220 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7221 "Mismatching PKEX curve: peer=%u own=%u",
7222 ike_group, curve->ike_group);
7223 pkex = os_zalloc(sizeof(*pkex));
7224 if (!pkex)
7225 goto fail;
7226 pkex->own_bi = bi;
7227 pkex->failed = 1;
7228 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
7229 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
7230 if (!pkex->exchange_resp)
7231 goto fail;
7232 return pkex;
7233 }
7234
7235 /* M in Encrypted Key attribute */
7236 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
7237 &attr_key_len);
7238 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
7239 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
7240 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7241 "Missing Encrypted Key attribute");
7242 return NULL;
7243 }
7244
7245 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7246 bnctx = BN_CTX_new();
7247 if (!bnctx)
7248 goto fail;
7249 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
7250 &group);
7251 if (!Qi)
7252 goto fail;
7253
7254 /* X' = M - Qi */
7255 X = EC_POINT_new(group);
7256 M = EC_POINT_new(group);
7257 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
7258 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
7259 if (!X || !M || !Mx || !My ||
7260 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
7261 EC_POINT_is_at_infinity(group, M) ||
7262 !EC_POINT_is_on_curve(group, M, bnctx) ||
7263 EC_POINT_invert(group, Qi, bnctx) != 1 ||
7264 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
7265 EC_POINT_is_at_infinity(group, X) ||
7266 !EC_POINT_is_on_curve(group, X, bnctx)) {
7267 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7268 "Invalid Encrypted Key value");
7269 bi->pkex_t++;
7270 goto fail;
7271 }
7272 dpp_debug_print_point("DPP: M", group, M);
7273 dpp_debug_print_point("DPP: X'", group, X);
7274
7275 pkex = os_zalloc(sizeof(*pkex));
7276 if (!pkex)
7277 goto fail;
7278 pkex->t = bi->pkex_t;
7279 pkex->msg_ctx = msg_ctx;
7280 pkex->own_bi = bi;
7281 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
7282 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
7283 if (identifier) {
7284 pkex->identifier = os_strdup(identifier);
7285 if (!pkex->identifier)
7286 goto fail;
7287 }
7288 pkex->code = os_strdup(code);
7289 if (!pkex->code)
7290 goto fail;
7291
7292 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
7293
7294 X_ec = EC_KEY_new();
7295 if (!X_ec ||
7296 EC_KEY_set_group(X_ec, group) != 1 ||
7297 EC_KEY_set_public_key(X_ec, X) != 1)
7298 goto fail;
7299 pkex->x = EVP_PKEY_new();
7300 if (!pkex->x ||
7301 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
7302 goto fail;
7303
7304 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7305 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
7306 if (!Qr)
7307 goto fail;
7308
7309 /* Generate a random ephemeral keypair y/Y */
7310#ifdef CONFIG_TESTING_OPTIONS
7311 if (dpp_pkex_ephemeral_key_override_len) {
7312 const struct dpp_curve_params *tmp_curve;
7313
7314 wpa_printf(MSG_INFO,
7315 "DPP: TESTING - override ephemeral key y/Y");
7316 pkex->y = dpp_set_keypair(&tmp_curve,
7317 dpp_pkex_ephemeral_key_override,
7318 dpp_pkex_ephemeral_key_override_len);
7319 } else {
7320 pkex->y = dpp_gen_keypair(curve);
7321 }
7322#else /* CONFIG_TESTING_OPTIONS */
7323 pkex->y = dpp_gen_keypair(curve);
7324#endif /* CONFIG_TESTING_OPTIONS */
7325 if (!pkex->y)
7326 goto fail;
7327
7328 /* N = Y + Qr */
7329 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
7330 if (!Y_ec)
7331 goto fail;
7332 Y_point = EC_KEY_get0_public_key(Y_ec);
7333 if (!Y_point)
7334 goto fail;
7335 dpp_debug_print_point("DPP: Y", group, Y_point);
7336 N = EC_POINT_new(group);
7337 Nx = BN_new();
7338 Ny = BN_new();
7339 if (!N || !Nx || !Ny ||
7340 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
7341 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
7342 goto fail;
7343 dpp_debug_print_point("DPP: N", group, N);
7344
7345 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
7346 Nx, Ny);
7347 if (!pkex->exchange_resp)
7348 goto fail;
7349
7350 /* K = y * X' */
7351 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
7352 if (!ctx ||
7353 EVP_PKEY_derive_init(ctx) != 1 ||
7354 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
7355 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
7356 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
7357 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
7358 wpa_printf(MSG_ERROR,
7359 "DPP: Failed to derive ECDH shared secret: %s",
7360 ERR_error_string(ERR_get_error(), NULL));
7361 goto fail;
7362 }
7363
7364 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7365 Kx, Kx_len);
7366
7367 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7368 */
7369 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
7370 pkex->Mx, curve->prime_len,
7371 pkex->Nx, curve->prime_len, pkex->code,
7372 Kx, Kx_len, pkex->z, curve->hash_len);
7373 os_memset(Kx, 0, Kx_len);
7374 if (res < 0)
7375 goto fail;
7376
7377 pkex->exchange_done = 1;
7378
7379out:
7380 EVP_PKEY_CTX_free(ctx);
7381 BN_CTX_free(bnctx);
7382 EC_POINT_free(Qi);
7383 EC_POINT_free(Qr);
7384 BN_free(Mx);
7385 BN_free(My);
7386 BN_free(Nx);
7387 BN_free(Ny);
7388 EC_POINT_free(M);
7389 EC_POINT_free(N);
7390 EC_POINT_free(X);
7391 EC_KEY_free(X_ec);
7392 EC_KEY_free(Y_ec);
7393 return pkex;
7394fail:
7395 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
7396 dpp_pkex_free(pkex);
7397 pkex = NULL;
7398 goto out;
7399}
7400
7401
7402static struct wpabuf *
7403dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
7404 const struct wpabuf *A_pub, const u8 *u)
7405{
7406 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7407 struct wpabuf *msg = NULL;
7408 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007409 struct wpabuf *clear = NULL;
7410 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007411 u8 octet;
7412 const u8 *addr[2];
7413 size_t len[2];
7414
7415 /* {A, u, [bootstrapping info]}z */
7416 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
7417 clear = wpabuf_alloc(clear_len);
7418 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7419#ifdef CONFIG_TESTING_OPTIONS
7420 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
7421 attr_len += 5;
7422#endif /* CONFIG_TESTING_OPTIONS */
7423 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
7424 if (!clear || !msg)
7425 goto fail;
7426
7427#ifdef CONFIG_TESTING_OPTIONS
7428 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
7429 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
7430 goto skip_bootstrap_key;
7431 }
7432 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
7433 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
7434 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7435 wpabuf_put_le16(clear, 2 * curve->prime_len);
7436 if (dpp_test_gen_invalid_key(clear, curve) < 0)
7437 goto fail;
7438 goto skip_bootstrap_key;
7439 }
7440#endif /* CONFIG_TESTING_OPTIONS */
7441
7442 /* A in Bootstrap Key attribute */
7443 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7444 wpabuf_put_le16(clear, wpabuf_len(A_pub));
7445 wpabuf_put_buf(clear, A_pub);
7446
7447#ifdef CONFIG_TESTING_OPTIONS
7448skip_bootstrap_key:
7449 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
7450 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
7451 goto skip_i_auth_tag;
7452 }
7453 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
7454 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
7455 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
7456 wpabuf_put_le16(clear, curve->hash_len);
7457 wpabuf_put_data(clear, u, curve->hash_len - 1);
7458 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
7459 goto skip_i_auth_tag;
7460 }
7461#endif /* CONFIG_TESTING_OPTIONS */
7462
7463 /* u in I-Auth tag attribute */
7464 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
7465 wpabuf_put_le16(clear, curve->hash_len);
7466 wpabuf_put_data(clear, u, curve->hash_len);
7467
7468#ifdef CONFIG_TESTING_OPTIONS
7469skip_i_auth_tag:
7470 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
7471 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
7472 goto skip_wrapped_data;
7473 }
7474#endif /* CONFIG_TESTING_OPTIONS */
7475
7476 addr[0] = wpabuf_head_u8(msg) + 2;
7477 len[0] = DPP_HDR_LEN;
7478 octet = 0;
7479 addr[1] = &octet;
7480 len[1] = sizeof(octet);
7481 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7482 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7483
7484 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7485 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7486 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7487
7488 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7489 if (aes_siv_encrypt(pkex->z, curve->hash_len,
7490 wpabuf_head(clear), wpabuf_len(clear),
7491 2, addr, len, wrapped) < 0)
7492 goto fail;
7493 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7494 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
7495
7496#ifdef CONFIG_TESTING_OPTIONS
7497 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
7498 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
7499 dpp_build_attr_status(msg, DPP_STATUS_OK);
7500 }
7501skip_wrapped_data:
7502#endif /* CONFIG_TESTING_OPTIONS */
7503
7504out:
7505 wpabuf_free(clear);
7506 return msg;
7507
7508fail:
7509 wpabuf_free(msg);
7510 msg = NULL;
7511 goto out;
7512}
7513
7514
7515struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
7516 const u8 *peer_mac,
7517 const u8 *buf, size_t buflen)
7518{
7519 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
7520 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
Hai Shalomf1c97642019-07-19 23:42:07 +00007521 const EC_GROUP *group;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007522 BN_CTX *bnctx = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007523 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7524 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7525 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
7526 BIGNUM *Nx = NULL, *Ny = NULL;
7527 EVP_PKEY_CTX *ctx = NULL;
7528 EC_KEY *Y_ec = NULL;
7529 size_t Jx_len, Kx_len;
7530 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
7531 const u8 *addr[4];
7532 size_t len[4];
7533 u8 u[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007534 int res;
7535
Roshan Pius3a1667e2018-07-03 15:17:14 -07007536 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
7537 return NULL;
7538
7539#ifdef CONFIG_TESTING_OPTIONS
7540 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
7541 wpa_printf(MSG_INFO,
7542 "DPP: TESTING - stop at PKEX Exchange Response");
7543 pkex->failed = 1;
7544 return NULL;
7545 }
7546
7547 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
7548 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
7549 MAC2STR(dpp_pkex_peer_mac_override));
7550 peer_mac = dpp_pkex_peer_mac_override;
7551 }
7552#endif /* CONFIG_TESTING_OPTIONS */
7553
7554 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
7555
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007556 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
7557 &attr_status_len);
7558 if (!attr_status || attr_status_len != 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007559 dpp_pkex_fail(pkex, "No DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007560 return NULL;
7561 }
7562 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007563
7564 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
7565 attr_group = dpp_get_attr(buf, buflen,
7566 DPP_ATTR_FINITE_CYCLIC_GROUP,
7567 &attr_group_len);
7568 if (attr_group && attr_group_len == 2) {
7569 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7570 "Peer indicated mismatching PKEX group - proposed %u",
7571 WPA_GET_LE16(attr_group));
7572 return NULL;
7573 }
7574 }
7575
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007576 if (attr_status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007577 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007578 return NULL;
7579 }
7580
Hai Shalom74f70d42019-02-11 14:42:39 -08007581 attr_id_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007582 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
7583 &attr_id_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08007584 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
7585 pkex->identifier)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007586 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007587 return NULL;
7588 }
7589
7590 /* N in Encrypted Key attribute */
7591 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
7592 &attr_key_len);
7593 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007594 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007595 return NULL;
7596 }
7597
7598 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7599 bnctx = BN_CTX_new();
7600 if (!bnctx)
7601 goto fail;
7602 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
7603 pkex->identifier, bnctx, &group);
7604 if (!Qr)
7605 goto fail;
7606
7607 /* Y' = N - Qr */
7608 Y = EC_POINT_new(group);
7609 N = EC_POINT_new(group);
7610 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
7611 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
7612 if (!Y || !N || !Nx || !Ny ||
7613 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
7614 EC_POINT_is_at_infinity(group, N) ||
7615 !EC_POINT_is_on_curve(group, N, bnctx) ||
7616 EC_POINT_invert(group, Qr, bnctx) != 1 ||
7617 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
7618 EC_POINT_is_at_infinity(group, Y) ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07007619 !EC_POINT_is_on_curve(group, Y, bnctx)) {
7620 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
7621 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007622 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007623 }
7624 dpp_debug_print_point("DPP: N", group, N);
7625 dpp_debug_print_point("DPP: Y'", group, Y);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007626
7627 pkex->exchange_done = 1;
7628
7629 /* ECDH: J = a * Y’ */
7630 Y_ec = EC_KEY_new();
7631 if (!Y_ec ||
7632 EC_KEY_set_group(Y_ec, group) != 1 ||
7633 EC_KEY_set_public_key(Y_ec, Y) != 1)
7634 goto fail;
7635 pkex->y = EVP_PKEY_new();
7636 if (!pkex->y ||
7637 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
7638 goto fail;
7639 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7640 if (!ctx ||
7641 EVP_PKEY_derive_init(ctx) != 1 ||
7642 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
7643 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
7644 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
7645 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
7646 wpa_printf(MSG_ERROR,
7647 "DPP: Failed to derive ECDH shared secret: %s",
7648 ERR_error_string(ERR_get_error(), NULL));
7649 goto fail;
7650 }
7651
7652 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7653 Jx, Jx_len);
7654
7655 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7656 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
7657 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7658 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7659 if (!A_pub || !Y_pub || !X_pub)
7660 goto fail;
7661 addr[0] = pkex->own_mac;
7662 len[0] = ETH_ALEN;
7663 addr[1] = wpabuf_head(A_pub);
7664 len[1] = wpabuf_len(A_pub) / 2;
7665 addr[2] = wpabuf_head(Y_pub);
7666 len[2] = wpabuf_len(Y_pub) / 2;
7667 addr[3] = wpabuf_head(X_pub);
7668 len[3] = wpabuf_len(X_pub) / 2;
7669 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
7670 goto fail;
7671 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
7672
7673 /* K = x * Y’ */
7674 EVP_PKEY_CTX_free(ctx);
7675 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
7676 if (!ctx ||
7677 EVP_PKEY_derive_init(ctx) != 1 ||
7678 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
7679 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
7680 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
7681 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
7682 wpa_printf(MSG_ERROR,
7683 "DPP: Failed to derive ECDH shared secret: %s",
7684 ERR_error_string(ERR_get_error(), NULL));
7685 goto fail;
7686 }
7687
7688 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7689 Kx, Kx_len);
7690
7691 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7692 */
7693 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
7694 pkex->Mx, curve->prime_len,
7695 attr_key /* N.x */, attr_key_len / 2,
7696 pkex->code, Kx, Kx_len,
7697 pkex->z, curve->hash_len);
7698 os_memset(Kx, 0, Kx_len);
7699 if (res < 0)
7700 goto fail;
7701
Roshan Pius3a1667e2018-07-03 15:17:14 -07007702 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
7703 if (!msg)
7704 goto fail;
7705
7706out:
7707 wpabuf_free(A_pub);
7708 wpabuf_free(X_pub);
7709 wpabuf_free(Y_pub);
7710 EC_POINT_free(Qr);
7711 EC_POINT_free(Y);
7712 EC_POINT_free(N);
7713 BN_free(Nx);
7714 BN_free(Ny);
7715 EC_KEY_free(Y_ec);
7716 EVP_PKEY_CTX_free(ctx);
7717 BN_CTX_free(bnctx);
7718 return msg;
7719fail:
7720 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
7721 goto out;
7722}
7723
7724
7725static struct wpabuf *
7726dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
7727 const struct wpabuf *B_pub, const u8 *v)
7728{
7729 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7730 struct wpabuf *msg = NULL;
7731 const u8 *addr[2];
7732 size_t len[2];
7733 u8 octet;
7734 u8 *wrapped;
7735 struct wpabuf *clear = NULL;
7736 size_t clear_len, attr_len;
7737
7738 /* {B, v [bootstrapping info]}z */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007739 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
7740 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007741 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7742#ifdef CONFIG_TESTING_OPTIONS
7743 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
7744 attr_len += 5;
7745#endif /* CONFIG_TESTING_OPTIONS */
7746 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007747 if (!clear || !msg)
7748 goto fail;
7749
Roshan Pius3a1667e2018-07-03 15:17:14 -07007750#ifdef CONFIG_TESTING_OPTIONS
7751 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
7752 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
7753 goto skip_bootstrap_key;
7754 }
7755 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
7756 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
7757 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7758 wpabuf_put_le16(clear, 2 * curve->prime_len);
7759 if (dpp_test_gen_invalid_key(clear, curve) < 0)
7760 goto fail;
7761 goto skip_bootstrap_key;
7762 }
7763#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007764
Roshan Pius3a1667e2018-07-03 15:17:14 -07007765 /* B in Bootstrap Key attribute */
7766 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7767 wpabuf_put_le16(clear, wpabuf_len(B_pub));
7768 wpabuf_put_buf(clear, B_pub);
7769
7770#ifdef CONFIG_TESTING_OPTIONS
7771skip_bootstrap_key:
7772 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
7773 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
7774 goto skip_r_auth_tag;
7775 }
7776 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
7777 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
7778 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
7779 wpabuf_put_le16(clear, curve->hash_len);
7780 wpabuf_put_data(clear, v, curve->hash_len - 1);
7781 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
7782 goto skip_r_auth_tag;
7783 }
7784#endif /* CONFIG_TESTING_OPTIONS */
7785
7786 /* v in R-Auth tag attribute */
7787 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007788 wpabuf_put_le16(clear, curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007789 wpabuf_put_data(clear, v, curve->hash_len);
7790
7791#ifdef CONFIG_TESTING_OPTIONS
7792skip_r_auth_tag:
7793 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
7794 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
7795 goto skip_wrapped_data;
7796 }
7797#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007798
7799 addr[0] = wpabuf_head_u8(msg) + 2;
7800 len[0] = DPP_HDR_LEN;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007801 octet = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007802 addr[1] = &octet;
7803 len[1] = sizeof(octet);
7804 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7805 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7806
7807 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7808 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7809 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7810
7811 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7812 if (aes_siv_encrypt(pkex->z, curve->hash_len,
7813 wpabuf_head(clear), wpabuf_len(clear),
7814 2, addr, len, wrapped) < 0)
7815 goto fail;
7816 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7817 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
7818
Roshan Pius3a1667e2018-07-03 15:17:14 -07007819#ifdef CONFIG_TESTING_OPTIONS
7820 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
7821 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
7822 dpp_build_attr_status(msg, DPP_STATUS_OK);
7823 }
7824skip_wrapped_data:
7825#endif /* CONFIG_TESTING_OPTIONS */
7826
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007827out:
7828 wpabuf_free(clear);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007829 return msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007830
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007831fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007832 wpabuf_free(msg);
7833 msg = NULL;
7834 goto out;
7835}
7836
7837
7838struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
7839 const u8 *hdr,
7840 const u8 *buf, size_t buflen)
7841{
7842 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007843 EVP_PKEY_CTX *ctx = NULL;
7844 size_t Jx_len, Lx_len;
7845 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007846 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
7847 const u8 *wrapped_data, *b_key, *peer_u;
7848 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
7849 const u8 *addr[4];
7850 size_t len[4];
7851 u8 octet;
7852 u8 *unwrapped = NULL;
7853 size_t unwrapped_len = 0;
7854 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7855 struct wpabuf *B_pub = NULL;
7856 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007857
Roshan Pius3a1667e2018-07-03 15:17:14 -07007858#ifdef CONFIG_TESTING_OPTIONS
7859 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
7860 wpa_printf(MSG_INFO,
7861 "DPP: TESTING - stop at PKEX CR Request");
7862 pkex->failed = 1;
7863 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007864 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07007865#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007866
Roshan Pius3a1667e2018-07-03 15:17:14 -07007867 if (!pkex->exchange_done || pkex->failed ||
7868 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007869 goto fail;
7870
7871 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7872 &wrapped_data_len);
7873 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007874 dpp_pkex_fail(pkex,
7875 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007876 goto fail;
7877 }
7878
7879 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7880 wrapped_data, wrapped_data_len);
7881 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7882 unwrapped = os_malloc(unwrapped_len);
7883 if (!unwrapped)
7884 goto fail;
7885
7886 addr[0] = hdr;
7887 len[0] = DPP_HDR_LEN;
7888 octet = 0;
7889 addr[1] = &octet;
7890 len[1] = sizeof(octet);
7891 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7892 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7893
7894 if (aes_siv_decrypt(pkex->z, curve->hash_len,
7895 wrapped_data, wrapped_data_len,
7896 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007897 dpp_pkex_fail(pkex,
7898 "AES-SIV decryption failed - possible PKEX code mismatch");
7899 pkex->failed = 1;
7900 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007901 goto fail;
7902 }
7903 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7904 unwrapped, unwrapped_len);
7905
7906 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007907 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007908 goto fail;
7909 }
7910
7911 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7912 &b_key_len);
7913 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007914 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007915 goto fail;
7916 }
7917 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7918 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007919 if (!pkex->peer_bootstrap_key) {
7920 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007921 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007922 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007923 dpp_debug_print_key("DPP: Peer bootstrap public key",
7924 pkex->peer_bootstrap_key);
7925
7926 /* ECDH: J' = y * A' */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007927 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
7928 if (!ctx ||
7929 EVP_PKEY_derive_init(ctx) != 1 ||
7930 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
7931 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
7932 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
7933 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
7934 wpa_printf(MSG_ERROR,
7935 "DPP: Failed to derive ECDH shared secret: %s",
7936 ERR_error_string(ERR_get_error(), NULL));
7937 goto fail;
7938 }
7939
7940 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7941 Jx, Jx_len);
7942
7943 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7944 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7945 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7946 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7947 if (!A_pub || !Y_pub || !X_pub)
7948 goto fail;
7949 addr[0] = pkex->peer_mac;
7950 len[0] = ETH_ALEN;
7951 addr[1] = wpabuf_head(A_pub);
7952 len[1] = wpabuf_len(A_pub) / 2;
7953 addr[2] = wpabuf_head(Y_pub);
7954 len[2] = wpabuf_len(Y_pub) / 2;
7955 addr[3] = wpabuf_head(X_pub);
7956 len[3] = wpabuf_len(X_pub) / 2;
7957 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
7958 goto fail;
7959
7960 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
7961 &peer_u_len);
7962 if (!peer_u || peer_u_len != curve->hash_len ||
7963 os_memcmp(peer_u, u, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007964 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007965 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
7966 u, curve->hash_len);
7967 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007968 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007969 goto fail;
7970 }
7971 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
7972
7973 /* ECDH: L = b * X' */
7974 EVP_PKEY_CTX_free(ctx);
7975 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7976 if (!ctx ||
7977 EVP_PKEY_derive_init(ctx) != 1 ||
7978 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
7979 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
7980 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
7981 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
7982 wpa_printf(MSG_ERROR,
7983 "DPP: Failed to derive ECDH shared secret: %s",
7984 ERR_error_string(ERR_get_error(), NULL));
7985 goto fail;
7986 }
7987
7988 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7989 Lx, Lx_len);
7990
7991 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7992 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
7993 if (!B_pub)
7994 goto fail;
7995 addr[0] = pkex->own_mac;
7996 len[0] = ETH_ALEN;
7997 addr[1] = wpabuf_head(B_pub);
7998 len[1] = wpabuf_len(B_pub) / 2;
7999 addr[2] = wpabuf_head(X_pub);
8000 len[2] = wpabuf_len(X_pub) / 2;
8001 addr[3] = wpabuf_head(Y_pub);
8002 len[3] = wpabuf_len(Y_pub) / 2;
8003 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8004 goto fail;
8005 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
8006
Roshan Pius3a1667e2018-07-03 15:17:14 -07008007 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
8008 if (!msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008009 goto fail;
8010
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008011out:
8012 EVP_PKEY_CTX_free(ctx);
8013 os_free(unwrapped);
8014 wpabuf_free(A_pub);
8015 wpabuf_free(B_pub);
8016 wpabuf_free(X_pub);
8017 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008018 return msg;
8019fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07008020 wpa_printf(MSG_DEBUG,
8021 "DPP: PKEX Commit-Reveal Request processing failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008022 goto out;
8023}
8024
8025
8026int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
8027 const u8 *buf, size_t buflen)
8028{
8029 const struct dpp_curve_params *curve = pkex->own_bi->curve;
8030 const u8 *wrapped_data, *b_key, *peer_v;
8031 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
8032 const u8 *addr[4];
8033 size_t len[4];
8034 u8 octet;
8035 u8 *unwrapped = NULL;
8036 size_t unwrapped_len = 0;
8037 int ret = -1;
8038 u8 v[DPP_MAX_HASH_LEN];
8039 size_t Lx_len;
8040 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
8041 EVP_PKEY_CTX *ctx = NULL;
8042 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8043
Roshan Pius3a1667e2018-07-03 15:17:14 -07008044#ifdef CONFIG_TESTING_OPTIONS
8045 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
8046 wpa_printf(MSG_INFO,
8047 "DPP: TESTING - stop at PKEX CR Response");
8048 pkex->failed = 1;
8049 goto fail;
8050 }
8051#endif /* CONFIG_TESTING_OPTIONS */
8052
8053 if (!pkex->exchange_done || pkex->failed ||
8054 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
8055 goto fail;
8056
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008057 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
8058 &wrapped_data_len);
8059 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008060 dpp_pkex_fail(pkex,
8061 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008062 goto fail;
8063 }
8064
8065 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8066 wrapped_data, wrapped_data_len);
8067 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
8068 unwrapped = os_malloc(unwrapped_len);
8069 if (!unwrapped)
8070 goto fail;
8071
8072 addr[0] = hdr;
8073 len[0] = DPP_HDR_LEN;
8074 octet = 1;
8075 addr[1] = &octet;
8076 len[1] = sizeof(octet);
8077 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8078 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8079
8080 if (aes_siv_decrypt(pkex->z, curve->hash_len,
8081 wrapped_data, wrapped_data_len,
8082 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008083 dpp_pkex_fail(pkex,
8084 "AES-SIV decryption failed - possible PKEX code mismatch");
8085 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008086 goto fail;
8087 }
8088 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
8089 unwrapped, unwrapped_len);
8090
8091 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008092 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008093 goto fail;
8094 }
8095
8096 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
8097 &b_key_len);
8098 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008099 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008100 goto fail;
8101 }
8102 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
8103 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008104 if (!pkex->peer_bootstrap_key) {
8105 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008106 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008107 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008108 dpp_debug_print_key("DPP: Peer bootstrap public key",
8109 pkex->peer_bootstrap_key);
8110
8111 /* ECDH: L' = x * B' */
8112 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
8113 if (!ctx ||
8114 EVP_PKEY_derive_init(ctx) != 1 ||
8115 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
8116 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
8117 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
8118 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
8119 wpa_printf(MSG_ERROR,
8120 "DPP: Failed to derive ECDH shared secret: %s",
8121 ERR_error_string(ERR_get_error(), NULL));
8122 goto fail;
8123 }
8124
8125 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
8126 Lx, Lx_len);
8127
8128 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8129 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
8130 X_pub = dpp_get_pubkey_point(pkex->x, 0);
8131 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8132 if (!B_pub || !X_pub || !Y_pub)
8133 goto fail;
8134 addr[0] = pkex->peer_mac;
8135 len[0] = ETH_ALEN;
8136 addr[1] = wpabuf_head(B_pub);
8137 len[1] = wpabuf_len(B_pub) / 2;
8138 addr[2] = wpabuf_head(X_pub);
8139 len[2] = wpabuf_len(X_pub) / 2;
8140 addr[3] = wpabuf_head(Y_pub);
8141 len[3] = wpabuf_len(Y_pub) / 2;
8142 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8143 goto fail;
8144
8145 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
8146 &peer_v_len);
8147 if (!peer_v || peer_v_len != curve->hash_len ||
8148 os_memcmp(peer_v, v, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07008149 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008150 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
8151 v, curve->hash_len);
8152 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008153 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008154 goto fail;
8155 }
8156 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
8157
8158 ret = 0;
8159out:
8160 wpabuf_free(B_pub);
8161 wpabuf_free(X_pub);
8162 wpabuf_free(Y_pub);
8163 EVP_PKEY_CTX_free(ctx);
8164 os_free(unwrapped);
8165 return ret;
8166fail:
8167 goto out;
8168}
8169
8170
8171void dpp_pkex_free(struct dpp_pkex *pkex)
8172{
8173 if (!pkex)
8174 return;
8175
8176 os_free(pkex->identifier);
8177 os_free(pkex->code);
8178 EVP_PKEY_free(pkex->x);
8179 EVP_PKEY_free(pkex->y);
8180 EVP_PKEY_free(pkex->peer_bootstrap_key);
8181 wpabuf_free(pkex->exchange_req);
8182 wpabuf_free(pkex->exchange_resp);
8183 os_free(pkex);
8184}
Roshan Pius3a1667e2018-07-03 15:17:14 -07008185
8186
8187#ifdef CONFIG_TESTING_OPTIONS
8188char * dpp_corrupt_connector_signature(const char *connector)
8189{
8190 char *tmp, *pos, *signed3 = NULL;
8191 unsigned char *signature = NULL;
8192 size_t signature_len = 0, signed3_len;
8193
8194 tmp = os_zalloc(os_strlen(connector) + 5);
8195 if (!tmp)
8196 goto fail;
8197 os_memcpy(tmp, connector, os_strlen(connector));
8198
8199 pos = os_strchr(tmp, '.');
8200 if (!pos)
8201 goto fail;
8202
8203 pos = os_strchr(pos + 1, '.');
8204 if (!pos)
8205 goto fail;
8206 pos++;
8207
8208 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
8209 pos);
8210 signature = base64_url_decode((const unsigned char *) pos,
8211 os_strlen(pos), &signature_len);
8212 if (!signature || signature_len == 0)
8213 goto fail;
8214 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
8215 signature, signature_len);
8216 signature[signature_len - 1] ^= 0x01;
8217 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
8218 signature, signature_len);
8219 signed3 = (char *) base64_url_encode(signature, signature_len,
8220 &signed3_len, 0);
8221 if (!signed3)
8222 goto fail;
8223 os_memcpy(pos, signed3, signed3_len);
8224 pos[signed3_len] = '\0';
8225 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
8226 pos);
8227
8228out:
8229 os_free(signature);
8230 os_free(signed3);
8231 return tmp;
8232fail:
8233 os_free(tmp);
8234 tmp = NULL;
8235 goto out;
8236}
8237#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom021b0b52019-04-10 11:17:58 -07008238
8239
8240#ifdef CONFIG_DPP2
8241
8242struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
8243 size_t net_access_key_len)
8244{
8245 struct wpabuf *pub = NULL;
8246 EVP_PKEY *own_key;
8247 struct dpp_pfs *pfs;
8248
8249 pfs = os_zalloc(sizeof(*pfs));
8250 if (!pfs)
8251 return NULL;
8252
8253 own_key = dpp_set_keypair(&pfs->curve, net_access_key,
8254 net_access_key_len);
8255 if (!own_key) {
8256 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
8257 goto fail;
8258 }
8259 EVP_PKEY_free(own_key);
8260
8261 pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
8262 if (!pfs->ecdh)
8263 goto fail;
8264
8265 pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
8266 pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
8267 if (!pub)
8268 goto fail;
8269
8270 pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
8271 if (!pfs->ie)
8272 goto fail;
8273 wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
8274 wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
8275 wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
8276 wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
8277 wpabuf_put_buf(pfs->ie, pub);
8278 wpabuf_free(pub);
8279 wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
8280 pfs->ie);
8281
8282 return pfs;
8283fail:
8284 wpabuf_free(pub);
8285 dpp_pfs_free(pfs);
8286 return NULL;
8287}
8288
8289
8290int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
8291{
8292 if (peer_ie_len < 2)
8293 return -1;
8294 if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
8295 wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
8296 return -1;
8297 }
8298
8299 pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
8300 peer_ie_len - 2);
8301 pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
8302 if (!pfs->secret) {
8303 wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
8304 return -1;
8305 }
8306 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
8307 return 0;
8308}
8309
8310
8311void dpp_pfs_free(struct dpp_pfs *pfs)
8312{
8313 if (!pfs)
8314 return;
8315 crypto_ecdh_deinit(pfs->ecdh);
8316 wpabuf_free(pfs->ie);
8317 wpabuf_clear_free(pfs->secret);
8318 os_free(pfs);
8319}
8320
8321#endif /* CONFIG_DPP2 */
8322
8323
8324static unsigned int dpp_next_id(struct dpp_global *dpp)
8325{
8326 struct dpp_bootstrap_info *bi;
8327 unsigned int max_id = 0;
8328
8329 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8330 if (bi->id > max_id)
8331 max_id = bi->id;
8332 }
8333 return max_id + 1;
8334}
8335
8336
8337static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
8338{
8339 struct dpp_bootstrap_info *bi, *tmp;
8340 int found = 0;
8341
8342 if (!dpp)
8343 return -1;
8344
8345 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
8346 struct dpp_bootstrap_info, list) {
8347 if (id && bi->id != id)
8348 continue;
8349 found = 1;
8350 dl_list_del(&bi->list);
8351 dpp_bootstrap_info_free(bi);
8352 }
8353
8354 if (id == 0)
8355 return 0; /* flush succeeds regardless of entries found */
8356 return found ? 0 : -1;
8357}
8358
8359
8360struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
8361 const char *uri)
8362{
8363 struct dpp_bootstrap_info *bi;
8364
8365 if (!dpp)
8366 return NULL;
8367
8368 bi = dpp_parse_qr_code(uri);
8369 if (!bi)
8370 return NULL;
8371
8372 bi->id = dpp_next_id(dpp);
8373 dl_list_add(&dpp->bootstrap, &bi->list);
8374 return bi;
8375}
8376
8377
8378int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
8379{
8380 char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
8381 char *key = NULL;
8382 u8 *privkey = NULL;
8383 size_t privkey_len = 0;
8384 size_t len;
8385 int ret = -1;
8386 struct dpp_bootstrap_info *bi;
8387
8388 if (!dpp)
8389 return -1;
8390
8391 bi = os_zalloc(sizeof(*bi));
8392 if (!bi)
8393 goto fail;
8394
8395 if (os_strstr(cmd, "type=qrcode"))
8396 bi->type = DPP_BOOTSTRAP_QR_CODE;
8397 else if (os_strstr(cmd, "type=pkex"))
8398 bi->type = DPP_BOOTSTRAP_PKEX;
8399 else
8400 goto fail;
8401
8402 chan = get_param(cmd, " chan=");
8403 mac = get_param(cmd, " mac=");
8404 info = get_param(cmd, " info=");
8405 curve = get_param(cmd, " curve=");
8406 key = get_param(cmd, " key=");
8407
8408 if (key) {
8409 privkey_len = os_strlen(key) / 2;
8410 privkey = os_malloc(privkey_len);
8411 if (!privkey ||
8412 hexstr2bin(key, privkey, privkey_len) < 0)
8413 goto fail;
8414 }
8415
8416 pk = dpp_keygen(bi, curve, privkey, privkey_len);
8417 if (!pk)
8418 goto fail;
8419
8420 len = 4; /* "DPP:" */
8421 if (chan) {
8422 if (dpp_parse_uri_chan_list(bi, chan) < 0)
8423 goto fail;
8424 len += 3 + os_strlen(chan); /* C:...; */
8425 }
8426 if (mac) {
8427 if (dpp_parse_uri_mac(bi, mac) < 0)
8428 goto fail;
8429 len += 3 + os_strlen(mac); /* M:...; */
8430 }
8431 if (info) {
8432 if (dpp_parse_uri_info(bi, info) < 0)
8433 goto fail;
8434 len += 3 + os_strlen(info); /* I:...; */
8435 }
8436 len += 4 + os_strlen(pk);
8437 bi->uri = os_malloc(len + 1);
8438 if (!bi->uri)
8439 goto fail;
8440 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8441 chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
8442 mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
8443 info ? "I:" : "", info ? info : "", info ? ";" : "",
8444 pk);
8445 bi->id = dpp_next_id(dpp);
8446 dl_list_add(&dpp->bootstrap, &bi->list);
8447 ret = bi->id;
8448 bi = NULL;
8449fail:
8450 os_free(curve);
8451 os_free(pk);
8452 os_free(chan);
8453 os_free(mac);
8454 os_free(info);
8455 str_clear_free(key);
8456 bin_clear_free(privkey, privkey_len);
8457 dpp_bootstrap_info_free(bi);
8458 return ret;
8459}
8460
8461
8462struct dpp_bootstrap_info *
8463dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
8464{
8465 struct dpp_bootstrap_info *bi;
8466
8467 if (!dpp)
8468 return NULL;
8469
8470 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8471 if (bi->id == id)
8472 return bi;
8473 }
8474 return NULL;
8475}
8476
8477
8478int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
8479{
8480 unsigned int id_val;
8481
8482 if (os_strcmp(id, "*") == 0) {
8483 id_val = 0;
8484 } else {
8485 id_val = atoi(id);
8486 if (id_val == 0)
8487 return -1;
8488 }
8489
8490 return dpp_bootstrap_del(dpp, id_val);
8491}
8492
8493
8494struct dpp_bootstrap_info *
8495dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
8496 unsigned int freq)
8497{
8498 struct dpp_bootstrap_info *bi;
8499
8500 bi = os_zalloc(sizeof(*bi));
8501 if (!bi)
8502 return NULL;
8503 bi->id = dpp_next_id(dpp);
8504 bi->type = DPP_BOOTSTRAP_PKEX;
8505 os_memcpy(bi->mac_addr, peer, ETH_ALEN);
8506 bi->num_freq = 1;
8507 bi->freq[0] = freq;
8508 bi->curve = pkex->own_bi->curve;
8509 bi->pubkey = pkex->peer_bootstrap_key;
8510 pkex->peer_bootstrap_key = NULL;
8511 if (dpp_bootstrap_key_hash(bi) < 0) {
8512 dpp_bootstrap_info_free(bi);
8513 return NULL;
8514 }
8515 dpp_pkex_free(pkex);
8516 dl_list_add(&dpp->bootstrap, &bi->list);
8517 return bi;
8518}
8519
8520
8521const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
8522{
8523 struct dpp_bootstrap_info *bi;
8524
8525 bi = dpp_bootstrap_get_id(dpp, id);
8526 if (!bi)
8527 return NULL;
8528 return bi->uri;
8529}
8530
8531
8532int dpp_bootstrap_info(struct dpp_global *dpp, int id,
8533 char *reply, int reply_size)
8534{
8535 struct dpp_bootstrap_info *bi;
8536
8537 bi = dpp_bootstrap_get_id(dpp, id);
8538 if (!bi)
8539 return -1;
8540 return os_snprintf(reply, reply_size, "type=%s\n"
8541 "mac_addr=" MACSTR "\n"
8542 "info=%s\n"
8543 "num_freq=%u\n"
Hai Shalomf1c97642019-07-19 23:42:07 +00008544 "curve=%s\n",
Hai Shalom021b0b52019-04-10 11:17:58 -07008545 dpp_bootstrap_type_txt(bi->type),
8546 MAC2STR(bi->mac_addr),
8547 bi->info ? bi->info : "",
8548 bi->num_freq,
Hai Shalomf1c97642019-07-19 23:42:07 +00008549 bi->curve->name);
Hai Shalom021b0b52019-04-10 11:17:58 -07008550}
8551
8552
8553void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
8554 const u8 *r_bootstrap,
8555 struct dpp_bootstrap_info **own_bi,
8556 struct dpp_bootstrap_info **peer_bi)
8557{
8558 struct dpp_bootstrap_info *bi;
8559
8560 *own_bi = NULL;
8561 *peer_bi = NULL;
8562 if (!dpp)
8563 return;
8564
8565 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8566 if (!*own_bi && bi->own &&
8567 os_memcmp(bi->pubkey_hash, r_bootstrap,
8568 SHA256_MAC_LEN) == 0) {
8569 wpa_printf(MSG_DEBUG,
8570 "DPP: Found matching own bootstrapping information");
8571 *own_bi = bi;
8572 }
8573
8574 if (!*peer_bi && !bi->own &&
8575 os_memcmp(bi->pubkey_hash, i_bootstrap,
8576 SHA256_MAC_LEN) == 0) {
8577 wpa_printf(MSG_DEBUG,
8578 "DPP: Found matching peer bootstrapping information");
8579 *peer_bi = bi;
8580 }
8581
8582 if (*own_bi && *peer_bi)
8583 break;
8584 }
8585
8586}
8587
8588
8589static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
8590{
8591 struct dpp_configurator *conf;
8592 unsigned int max_id = 0;
8593
8594 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
8595 list) {
8596 if (conf->id > max_id)
8597 max_id = conf->id;
8598 }
8599 return max_id + 1;
8600}
8601
8602
8603int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
8604{
8605 char *curve = NULL;
8606 char *key = NULL;
8607 u8 *privkey = NULL;
8608 size_t privkey_len = 0;
8609 int ret = -1;
8610 struct dpp_configurator *conf = NULL;
8611
8612 curve = get_param(cmd, " curve=");
8613 key = get_param(cmd, " key=");
8614
8615 if (key) {
8616 privkey_len = os_strlen(key) / 2;
8617 privkey = os_malloc(privkey_len);
8618 if (!privkey ||
8619 hexstr2bin(key, privkey, privkey_len) < 0)
8620 goto fail;
8621 }
8622
8623 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
8624 if (!conf)
8625 goto fail;
8626
8627 conf->id = dpp_next_configurator_id(dpp);
8628 dl_list_add(&dpp->configurator, &conf->list);
8629 ret = conf->id;
8630 conf = NULL;
8631fail:
8632 os_free(curve);
8633 str_clear_free(key);
8634 bin_clear_free(privkey, privkey_len);
8635 dpp_configurator_free(conf);
8636 return ret;
8637}
8638
8639
8640static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
8641{
8642 struct dpp_configurator *conf, *tmp;
8643 int found = 0;
8644
8645 if (!dpp)
8646 return -1;
8647
8648 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
8649 struct dpp_configurator, list) {
8650 if (id && conf->id != id)
8651 continue;
8652 found = 1;
8653 dl_list_del(&conf->list);
8654 dpp_configurator_free(conf);
8655 }
8656
8657 if (id == 0)
8658 return 0; /* flush succeeds regardless of entries found */
8659 return found ? 0 : -1;
8660}
8661
8662
8663int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
8664{
8665 unsigned int id_val;
8666
8667 if (os_strcmp(id, "*") == 0) {
8668 id_val = 0;
8669 } else {
8670 id_val = atoi(id);
8671 if (id_val == 0)
8672 return -1;
8673 }
8674
8675 return dpp_configurator_del(dpp, id_val);
8676}
8677
8678
8679int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
8680 char *buf, size_t buflen)
8681{
8682 struct dpp_configurator *conf;
8683
8684 conf = dpp_configurator_get_id(dpp, id);
8685 if (!conf)
8686 return -1;
8687
8688 return dpp_configurator_get_key(conf, buf, buflen);
8689}
8690
8691
Hai Shalomf1c97642019-07-19 23:42:07 +00008692struct dpp_global * dpp_global_init(void)
Hai Shalom021b0b52019-04-10 11:17:58 -07008693{
8694 struct dpp_global *dpp;
8695
8696 dpp = os_zalloc(sizeof(*dpp));
8697 if (!dpp)
8698 return NULL;
8699
8700 dl_list_init(&dpp->bootstrap);
8701 dl_list_init(&dpp->configurator);
8702
8703 return dpp;
8704}
8705
8706
8707void dpp_global_clear(struct dpp_global *dpp)
8708{
8709 if (!dpp)
8710 return;
8711
8712 dpp_bootstrap_del(dpp, 0);
8713 dpp_configurator_del(dpp, 0);
8714}
8715
8716
8717void dpp_global_deinit(struct dpp_global *dpp)
8718{
8719 dpp_global_clear(dpp);
8720 os_free(dpp);
8721}