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