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