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