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