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