]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/common/dpp.c
DPP: Remove obsolete TODO comment on discovery object
[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);
2265353a 3438 wpabuf_put_str(buf, "\"},");
461d39af
JM
3439
3440 return buf;
3441}
3442
3443
3444static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
3445{
3446 int num_bytes, offset;
3447
3448 num_bytes = BN_num_bytes(bn);
3449 if ((size_t) num_bytes > len)
3450 return -1;
3451 offset = len - num_bytes;
3452 os_memset(pos, 0, offset);
3453 BN_bn2bin(bn, pos + offset);
3454 return 0;
3455}
3456
3457
3458static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
3459 const char *kid, const struct dpp_curve_params *curve)
3460{
3461 struct wpabuf *pub;
3462 const u8 *pos;
3463 char *x = NULL, *y = NULL;
3464 int ret = -1;
3465
3466 pub = dpp_get_pubkey_point(key, 0);
3467 if (!pub)
3468 goto fail;
3469 pos = wpabuf_head(pub);
3470 x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
3471 pos += curve->prime_len;
3472 y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
58efbcbc
JM
3473 if (!x || !y)
3474 goto fail;
461d39af
JM
3475
3476 wpabuf_put_str(buf, "\"");
3477 wpabuf_put_str(buf, name);
3478 wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
3479 wpabuf_put_str(buf, curve->jwk_crv);
3480 wpabuf_put_str(buf, "\",\"x\":\"");
3481 wpabuf_put_str(buf, x);
3482 wpabuf_put_str(buf, "\",\"y\":\"");
3483 wpabuf_put_str(buf, y);
3484 if (kid) {
3485 wpabuf_put_str(buf, "\",\"kid\":\"");
3486 wpabuf_put_str(buf, kid);
3487 }
3488 wpabuf_put_str(buf, "\"}");
3489 ret = 0;
58efbcbc 3490fail:
461d39af
JM
3491 wpabuf_free(pub);
3492 os_free(x);
3493 os_free(y);
3494 return ret;
461d39af
JM
3495}
3496
3497
3498static struct wpabuf *
3499dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
3500 struct dpp_configuration *conf)
3501{
3502 struct wpabuf *buf = NULL;
3503 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
3504 size_t tailroom;
3505 const struct dpp_curve_params *curve;
3506 char jws_prot_hdr[100];
3507 size_t signed1_len, signed2_len, signed3_len;
3508 struct wpabuf *dppcon = NULL;
3509 unsigned char *signature = NULL;
3510 const unsigned char *p;
3511 size_t signature_len;
3512 EVP_MD_CTX *md_ctx = NULL;
3513 ECDSA_SIG *sig = NULL;
3514 char *dot = ".";
461d39af
JM
3515 const EVP_MD *sign_md;
3516 const BIGNUM *r, *s;
3517 size_t extra_len = 1000;
3518
3519 if (!auth->conf) {
3520 wpa_printf(MSG_INFO,
3521 "DPP: No configurator specified - cannot generate DPP config object");
3522 goto fail;
3523 }
3524 curve = auth->conf->curve;
3525 if (curve->hash_len == SHA256_MAC_LEN) {
461d39af
JM
3526 sign_md = EVP_sha256();
3527 } else if (curve->hash_len == SHA384_MAC_LEN) {
461d39af
JM
3528 sign_md = EVP_sha384();
3529 } else if (curve->hash_len == SHA512_MAC_LEN) {
461d39af
JM
3530 sign_md = EVP_sha512();
3531 } else {
3532 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
3533 goto fail;
3534 }
3535
3536#ifdef CONFIG_TESTING_OPTIONS
3537 if (auth->groups_override)
3538 extra_len += os_strlen(auth->groups_override);
461d39af
JM
3539#endif /* CONFIG_TESTING_OPTIONS */
3540
3541 /* Connector (JSON dppCon object) */
3542 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
3543 if (!dppcon)
3544 goto fail;
3545#ifdef CONFIG_TESTING_OPTIONS
a4bf0078 3546 if (auth->groups_override) {
461d39af
JM
3547 wpabuf_put_u8(dppcon, '{');
3548 if (auth->groups_override) {
3549 wpa_printf(MSG_DEBUG,
3550 "DPP: TESTING - groups override: '%s'",
3551 auth->groups_override);
3552 wpabuf_put_str(dppcon, "\"groups\":");
3553 wpabuf_put_str(dppcon, auth->groups_override);
3554 wpabuf_put_u8(dppcon, ',');
3555 }
461d39af
JM
3556 goto skip_groups;
3557 }
3558#endif /* CONFIG_TESTING_OPTIONS */
3559 wpabuf_put_str(dppcon, "{\"groups\":[{\"groupId\":\"*\",");
3560 wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
3561#ifdef CONFIG_TESTING_OPTIONS
3562skip_groups:
3563#endif /* CONFIG_TESTING_OPTIONS */
3564 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
3565 auth->curve) < 0) {
3566 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
3567 goto fail;
3568 }
3569 if (conf->netaccesskey_expiry) {
3570 struct os_tm tm;
3571
3572 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
3573 wpa_printf(MSG_DEBUG,
3574 "DPP: Failed to generate expiry string");
3575 goto fail;
3576 }
3577 wpabuf_printf(dppcon,
3578 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
3579 tm.year, tm.month, tm.day,
3580 tm.hour, tm.min, tm.sec);
3581 }
3582 wpabuf_put_u8(dppcon, '}');
3583 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
3584 (const char *) wpabuf_head(dppcon));
3585
3586 os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
3587 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
31f03cb0 3588 auth->conf->kid, curve->jws_alg);
461d39af
JM
3589 signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
3590 os_strlen(jws_prot_hdr),
3591 &signed1_len, 0);
3592 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
3593 wpabuf_len(dppcon),
3594 &signed2_len, 0);
3595 if (!signed1 || !signed2)
3596 goto fail;
3597
3598 md_ctx = EVP_MD_CTX_create();
3599 if (!md_ctx)
3600 goto fail;
3601
3602 ERR_clear_error();
3603 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
3604 auth->conf->csign) != 1) {
3605 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
3606 ERR_error_string(ERR_get_error(), NULL));
3607 goto fail;
3608 }
3609 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
3610 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
3611 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
3612 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
3613 ERR_error_string(ERR_get_error(), NULL));
3614 goto fail;
3615 }
3616 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
3617 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
3618 ERR_error_string(ERR_get_error(), NULL));
3619 goto fail;
3620 }
3621 signature = os_malloc(signature_len);
3622 if (!signature)
3623 goto fail;
3624 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
3625 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
3626 ERR_error_string(ERR_get_error(), NULL));
3627 goto fail;
3628 }
3629 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
3630 signature, signature_len);
3631 /* Convert to raw coordinates r,s */
3632 p = signature;
3633 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
3634 if (!sig)
3635 goto fail;
3636 ECDSA_SIG_get0(sig, &r, &s);
3637 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
3638 dpp_bn2bin_pad(s, signature + curve->prime_len,
3639 curve->prime_len) < 0)
3640 goto fail;
3641 signature_len = 2 * curve->prime_len;
3642 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
3643 signature, signature_len);
3644 signed3 = (char *) base64_url_encode(signature, signature_len,
3645 &signed3_len, 0);
3646 if (!signed3)
3647 goto fail;
3648
3649 tailroom = 1000;
3650 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
3651 tailroom += signed1_len + signed2_len + signed3_len;
3652 buf = dpp_build_conf_start(auth, conf, tailroom);
3653 if (!buf)
3654 return NULL;
3655
3656 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
3657 wpabuf_put_str(buf, signed1);
3658 wpabuf_put_u8(buf, '.');
3659 wpabuf_put_str(buf, signed2);
3660 wpabuf_put_u8(buf, '.');
3661 wpabuf_put_str(buf, signed3);
3662 wpabuf_put_str(buf, "\",");
3663 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
3664 curve) < 0) {
3665 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
3666 goto fail;
3667 }
461d39af
JM
3668
3669 wpabuf_put_str(buf, "}}");
3670
3671 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
3672 wpabuf_head(buf), wpabuf_len(buf));
3673
3674out:
3675 EVP_MD_CTX_destroy(md_ctx);
3676 ECDSA_SIG_free(sig);
3677 os_free(signed1);
3678 os_free(signed2);
3679 os_free(signed3);
3680 os_free(signature);
3681 wpabuf_free(dppcon);
3682 return buf;
3683fail:
3684 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
3685 wpabuf_free(buf);
3686 buf = NULL;
3687 goto out;
3688}
3689
3690
3691static struct wpabuf *
3692dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
3693 struct dpp_configuration *conf)
3694{
3695 struct wpabuf *buf;
3696
3697 buf = dpp_build_conf_start(auth, conf, 1000);
3698 if (!buf)
3699 return NULL;
3700
3701 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"psk\",");
3702 if (conf->passphrase) {
3703 char pass[63 * 6 + 1];
3704
3705 if (os_strlen(conf->passphrase) > 63) {
3706 wpabuf_free(buf);
3707 return NULL;
3708 }
3709
3710 json_escape_string(pass, sizeof(pass), conf->passphrase,
3711 os_strlen(conf->passphrase));
3712 wpabuf_put_str(buf, "\"pass\":\"");
3713 wpabuf_put_str(buf, pass);
3714 wpabuf_put_str(buf, "\"");
3715 } else {
3716 char psk[2 * sizeof(conf->psk) + 1];
3717
3718 wpa_snprintf_hex(psk, sizeof(psk),
3719 conf->psk, sizeof(conf->psk));
3720 wpabuf_put_str(buf, "\"psk_hex\":\"");
3721 wpabuf_put_str(buf, psk);
3722 wpabuf_put_str(buf, "\"");
3723 }
3724 wpabuf_put_str(buf, "}}");
3725
3726 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
3727 wpabuf_head(buf), wpabuf_len(buf));
3728
3729 return buf;
3730}
3731
3732
3733static struct wpabuf *
3734dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
3735{
3736 struct dpp_configuration *conf;
3737
3738#ifdef CONFIG_TESTING_OPTIONS
3739 if (auth->config_obj_override) {
3740 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
3741 return wpabuf_alloc_copy(auth->config_obj_override,
3742 os_strlen(auth->config_obj_override));
3743 }
3744#endif /* CONFIG_TESTING_OPTIONS */
3745
3746 conf = ap ? auth->conf_ap : auth->conf_sta;
3747 if (!conf) {
3748 wpa_printf(MSG_DEBUG,
3749 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
3750 ap ? "ap" : "sta");
3751 return NULL;
3752 }
3753
3754 if (conf->dpp)
3755 return dpp_build_conf_obj_dpp(auth, ap, conf);
3756 return dpp_build_conf_obj_legacy(auth, ap, conf);
3757}
3758
3759
3760static struct wpabuf *
3761dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
3762 u16 e_nonce_len, int ap)
3763{
3764 struct wpabuf *conf;
60239f60 3765 size_t clear_len, attr_len;
461d39af
JM
3766 struct wpabuf *clear = NULL, *msg = NULL;
3767 u8 *wrapped;
3768 const u8 *addr[1];
3769 size_t len[1];
3770 enum dpp_status_error status;
3771
3772 conf = dpp_build_conf_obj(auth, ap);
3773 if (conf) {
3774 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3775 wpabuf_head(conf), wpabuf_len(conf));
3776 }
3777 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
3778
3779 /* { E-nonce, configurationObject}ke */
3780 clear_len = 4 + e_nonce_len;
3781 if (conf)
3782 clear_len += 4 + wpabuf_len(conf);
3783 clear = wpabuf_alloc(clear_len);
60239f60
JM
3784 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
3785#ifdef CONFIG_TESTING_OPTIONS
3786 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
3787 attr_len += 4;
3788#endif /* CONFIG_TESTING_OPTIONS */
3789 msg = wpabuf_alloc(attr_len);
461d39af
JM
3790 if (!clear || !msg)
3791 goto fail;
3792
3793 /* E-nonce */
3794 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3795 wpabuf_put_le16(clear, e_nonce_len);
3796 wpabuf_put_data(clear, e_nonce, e_nonce_len);
3797
3798 if (conf) {
3799 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
3800 wpabuf_put_le16(clear, wpabuf_len(conf));
3801 wpabuf_put_buf(clear, conf);
3802 wpabuf_free(conf);
3803 conf = NULL;
3804 }
3805
3806 /* DPP Status */
3807 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
3808 wpabuf_put_le16(msg, 1);
3809 wpabuf_put_u8(msg, status);
3810
3811 addr[0] = wpabuf_head(msg);
3812 len[0] = wpabuf_len(msg);
3813 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3814
3815 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3816 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3817 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3818
3819 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3820 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3821 wpabuf_head(clear), wpabuf_len(clear),
3822 1, addr, len, wrapped) < 0)
3823 goto fail;
3824 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3825 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
3826 wpabuf_free(clear);
3827 clear = NULL;
3828
60239f60
JM
3829#ifdef CONFIG_TESTING_OPTIONS
3830 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
3831 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
3832 wpabuf_put_le16(msg, DPP_ATTR_TESTING);
3833 wpabuf_put_le16(msg, 0);
3834 }
3835#endif /* CONFIG_TESTING_OPTIONS */
3836
461d39af
JM
3837 wpa_hexdump_buf(MSG_DEBUG,
3838 "DPP: Configuration Response attributes", msg);
3839 return msg;
3840fail:
3841 wpabuf_free(conf);
3842 wpabuf_free(clear);
3843 wpabuf_free(msg);
3844 return NULL;
3845}
3846
3847
3848struct wpabuf *
3849dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
3850 size_t attr_len)
3851{
3852 const u8 *wrapped_data, *e_nonce, *config_attr;
3853 u16 wrapped_data_len, e_nonce_len, config_attr_len;
3854 u8 *unwrapped = NULL;
3855 size_t unwrapped_len = 0;
3856 struct wpabuf *resp = NULL;
3857 struct json_token *root = NULL, *token;
3858 int ap;
3859
3860 if (dpp_check_attrs(attr_start, attr_len) < 0) {
3861 wpa_printf(MSG_DEBUG,
3862 "DPP: Invalid attribute in config request");
3863 return NULL;
3864 }
3865
3866 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3867 &wrapped_data_len);
3868 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3869 wpa_printf(MSG_DEBUG,
3870 "DPP: Missing or invalid required Wrapped data attribute");
3871 return NULL;
3872 }
3873
3874 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3875 wrapped_data, wrapped_data_len);
3876 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3877 unwrapped = os_malloc(unwrapped_len);
3878 if (!unwrapped)
3879 return NULL;
3880 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3881 wrapped_data, wrapped_data_len,
3882 0, NULL, NULL, unwrapped) < 0) {
3883 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
3884 goto fail;
3885 }
3886 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3887 unwrapped, unwrapped_len);
3888
3889 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3890 wpa_printf(MSG_DEBUG,
3891 "DPP: Invalid attribute in unwrapped data");
3892 goto fail;
3893 }
3894
3895 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3896 DPP_ATTR_ENROLLEE_NONCE,
3897 &e_nonce_len);
3898 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3899 wpa_printf(MSG_DEBUG,
3900 "DPP: Missing or invalid Enrollee Nonce attribute");
3901 goto fail;
3902 }
3903 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3904
3905 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
3906 DPP_ATTR_CONFIG_ATTR_OBJ,
3907 &config_attr_len);
3908 if (!config_attr) {
3909 wpa_printf(MSG_DEBUG,
3910 "DPP: Missing or invalid Config Attributes attribute");
3911 goto fail;
3912 }
3913 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
3914 config_attr, config_attr_len);
3915
3916 root = json_parse((const char *) config_attr, config_attr_len);
3917 if (!root) {
3918 wpa_printf(MSG_DEBUG, "DPP: Could not parse Config Attributes");
3919 goto fail;
3920 }
3921
3922 token = json_get_member(root, "name");
3923 if (!token || token->type != JSON_STRING) {
3924 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - name");
3925 goto fail;
3926 }
3927 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
3928
3929 token = json_get_member(root, "wi-fi_tech");
3930 if (!token || token->type != JSON_STRING) {
3931 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - wi-fi_tech");
3932 goto fail;
3933 }
3934 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
3935 if (os_strcmp(token->string, "infra") != 0) {
3936 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
3937 token->string);
3938 goto fail;
3939 }
3940
3941 token = json_get_member(root, "netRole");
3942 if (!token || token->type != JSON_STRING) {
3943 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - netRole");
3944 goto fail;
3945 }
3946 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
3947 if (os_strcmp(token->string, "sta") == 0) {
3948 ap = 0;
3949 } else if (os_strcmp(token->string, "ap") == 0) {
3950 ap = 1;
3951 } else {
3952 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
3953 token->string);
3954 goto fail;
3955 }
3956
3957 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
3958
3959fail:
3960 json_free(root);
3961 os_free(unwrapped);
3962 return resp;
3963}
3964
3965
3966static struct wpabuf *
6095b479
JM
3967dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
3968 const u8 *prot_hdr, u16 prot_hdr_len,
461d39af
JM
3969 const EVP_MD **ret_md)
3970{
3971 struct json_token *root, *token;
3972 struct wpabuf *kid = NULL;
3973
3974 root = json_parse((const char *) prot_hdr, prot_hdr_len);
3975 if (!root) {
3976 wpa_printf(MSG_DEBUG,
3977 "DPP: JSON parsing failed for JWS Protected Header");
3978 goto fail;
3979 }
3980
3981 if (root->type != JSON_OBJECT) {
3982 wpa_printf(MSG_DEBUG,
3983 "DPP: JWS Protected Header root is not an object");
3984 goto fail;
3985 }
3986
3987 token = json_get_member(root, "typ");
3988 if (!token || token->type != JSON_STRING) {
3989 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
3990 goto fail;
3991 }
3992 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
3993 token->string);
3994 if (os_strcmp(token->string, "dppCon") != 0) {
3995 wpa_printf(MSG_DEBUG,
3996 "DPP: Unsupported JWS Protected Header typ=%s",
3997 token->string);
3998 goto fail;
3999 }
4000
4001 token = json_get_member(root, "alg");
4002 if (!token || token->type != JSON_STRING) {
4003 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
4004 goto fail;
4005 }
4006 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
4007 token->string);
6095b479
JM
4008 if (os_strcmp(token->string, curve->jws_alg) != 0) {
4009 wpa_printf(MSG_DEBUG,
4010 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4011 token->string, curve->jws_alg);
4012 goto fail;
4013 }
31f03cb0
JM
4014 if (os_strcmp(token->string, "ES256") == 0 ||
4015 os_strcmp(token->string, "BS256") == 0)
461d39af 4016 *ret_md = EVP_sha256();
31f03cb0
JM
4017 else if (os_strcmp(token->string, "ES384") == 0 ||
4018 os_strcmp(token->string, "BS384") == 0)
461d39af 4019 *ret_md = EVP_sha384();
31f03cb0
JM
4020 else if (os_strcmp(token->string, "ES512") == 0 ||
4021 os_strcmp(token->string, "BS512") == 0)
461d39af
JM
4022 *ret_md = EVP_sha512();
4023 else
4024 *ret_md = NULL;
4025 if (!*ret_md) {
4026 wpa_printf(MSG_DEBUG,
4027 "DPP: Unsupported JWS Protected Header alg=%s",
4028 token->string);
4029 goto fail;
4030 }
4031
4032 kid = json_get_member_base64url(root, "kid");
4033 if (!kid) {
4034 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
4035 goto fail;
4036 }
4037 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
4038 kid);
4039
4040fail:
4041 json_free(root);
4042 return kid;
4043}
4044
4045
4046static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
4047 struct json_token *cred)
4048{
4049 struct json_token *pass, *psk_hex;
461d39af
JM
4050
4051 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
4052
4053 pass = json_get_member(cred, "pass");
4054 psk_hex = json_get_member(cred, "psk_hex");
4055
4056 if (pass && pass->type == JSON_STRING) {
8528994e
JM
4057 size_t len = os_strlen(pass->string);
4058
461d39af 4059 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
8528994e
JM
4060 pass->string, len);
4061 if (len < 8 || len > 63)
4062 return -1;
4063 os_strlcpy(auth->passphrase, pass->string,
4064 sizeof(auth->passphrase));
461d39af 4065 } else if (psk_hex && psk_hex->type == JSON_STRING) {
8528994e
JM
4066 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
4067 hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
461d39af
JM
4068 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
4069 return -1;
4070 }
8528994e
JM
4071 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
4072 auth->psk, PMK_LEN);
4073 auth->psk_set = 1;
461d39af
JM
4074 } else {
4075 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
4076 return -1;
4077 }
4078
4079 return 0;
4080}
4081
4082
4083static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
4084 const struct dpp_curve_params **key_curve)
4085{
4086 struct json_token *token;
4087 const struct dpp_curve_params *curve;
4088 struct wpabuf *x = NULL, *y = NULL;
4089 EC_GROUP *group;
4090 EVP_PKEY *pkey = NULL;
4091
4092 token = json_get_member(jwk, "kty");
4093 if (!token || token->type != JSON_STRING) {
4094 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
4095 goto fail;
4096 }
4097 if (os_strcmp(token->string, "EC") != 0) {
4098 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s",
4099 token->string);
4100 goto fail;
4101 }
4102
4103 token = json_get_member(jwk, "crv");
4104 if (!token || token->type != JSON_STRING) {
4105 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
4106 goto fail;
4107 }
4108 curve = dpp_get_curve_jwk_crv(token->string);
4109 if (!curve) {
4110 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
4111 token->string);
4112 goto fail;
4113 }
4114
4115 x = json_get_member_base64url(jwk, "x");
4116 if (!x) {
4117 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
4118 goto fail;
4119 }
f1f4fa79 4120 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
461d39af
JM
4121 if (wpabuf_len(x) != curve->prime_len) {
4122 wpa_printf(MSG_DEBUG,
f1f4fa79 4123 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
461d39af
JM
4124 (unsigned int) wpabuf_len(x),
4125 (unsigned int) curve->prime_len, curve->name);
4126 goto fail;
4127 }
4128
4129 y = json_get_member_base64url(jwk, "y");
4130 if (!y) {
4131 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
4132 goto fail;
4133 }
f1f4fa79 4134 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
461d39af
JM
4135 if (wpabuf_len(y) != curve->prime_len) {
4136 wpa_printf(MSG_DEBUG,
f1f4fa79 4137 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
461d39af
JM
4138 (unsigned int) wpabuf_len(y),
4139 (unsigned int) curve->prime_len, curve->name);
4140 goto fail;
4141 }
4142
4143 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
4144 if (!group) {
4145 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
4146 goto fail;
4147 }
4148
4149 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
4150 wpabuf_len(x));
4151 *key_curve = curve;
4152
4153fail:
4154 wpabuf_free(x);
4155 wpabuf_free(y);
4156
4157 return pkey;
4158}
4159
4160
4161int dpp_key_expired(const char *timestamp, os_time_t *expiry)
4162{
4163 struct os_time now;
4164 unsigned int year, month, day, hour, min, sec;
4165 os_time_t utime;
4166 const char *pos;
4167
4168 /* ISO 8601 date and time:
4169 * <date>T<time>
4170 * YYYY-MM-DDTHH:MM:SSZ
4171 * YYYY-MM-DDTHH:MM:SS+03:00
4172 */
4173 if (os_strlen(timestamp) < 19) {
4174 wpa_printf(MSG_DEBUG,
4175 "DPP: Too short timestamp - assume expired key");
4176 return 1;
4177 }
4178 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
4179 &year, &month, &day, &hour, &min, &sec) != 6) {
4180 wpa_printf(MSG_DEBUG,
4181 "DPP: Failed to parse expiration day - assume expired key");
4182 return 1;
4183 }
4184
4185 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
4186 wpa_printf(MSG_DEBUG,
4187 "DPP: Invalid date/time information - assume expired key");
4188 return 1;
4189 }
4190
4191 pos = timestamp + 19;
4192 if (*pos == 'Z' || *pos == '\0') {
4193 /* In UTC - no need to adjust */
4194 } else if (*pos == '-' || *pos == '+') {
4195 int items;
4196
4197 /* Adjust local time to UTC */
4198 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
4199 if (items < 1) {
4200 wpa_printf(MSG_DEBUG,
4201 "DPP: Invalid time zone designator (%s) - assume expired key",
4202 pos);
4203 return 1;
4204 }
4205 if (*pos == '-')
4206 utime += 3600 * hour;
4207 if (*pos == '+')
4208 utime -= 3600 * hour;
4209 if (items > 1) {
4210 if (*pos == '-')
4211 utime += 60 * min;
4212 if (*pos == '+')
4213 utime -= 60 * min;
4214 }
4215 } else {
4216 wpa_printf(MSG_DEBUG,
4217 "DPP: Invalid time zone designator (%s) - assume expired key",
4218 pos);
4219 return 1;
4220 }
4221 if (expiry)
4222 *expiry = utime;
4223
4224 if (os_get_time(&now) < 0) {
4225 wpa_printf(MSG_DEBUG,
4226 "DPP: Cannot get current time - assume expired key");
4227 return 1;
4228 }
4229
4230 if (now.sec > utime) {
4231 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
4232 utime, now.sec);
4233 return 1;
4234 }
4235
4236 return 0;
4237}
4238
4239
4240static int dpp_parse_connector(struct dpp_authentication *auth,
4241 const unsigned char *payload,
4242 u16 payload_len)
4243{
a4bf0078 4244 struct json_token *root, *groups, *netkey, *token;
461d39af
JM
4245 int ret = -1;
4246 EVP_PKEY *key = NULL;
4247 const struct dpp_curve_params *curve;
4248 unsigned int rules = 0;
4249
4250 root = json_parse((const char *) payload, payload_len);
4251 if (!root) {
4252 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4253 goto fail;
4254 }
4255
4256 groups = json_get_member(root, "groups");
4257 if (!groups || groups->type != JSON_ARRAY) {
4258 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
4259 goto skip_groups;
4260 }
4261 for (token = groups->child; token; token = token->sibling) {
4262 struct json_token *id, *role;
4263
4264 id = json_get_member(token, "groupId");
4265 if (!id || id->type != JSON_STRING) {
4266 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
4267 goto fail;
4268 }
4269
4270 role = json_get_member(token, "netRole");
4271 if (!role || role->type != JSON_STRING) {
4272 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
4273 goto fail;
4274 }
4275 wpa_printf(MSG_DEBUG,
4276 "DPP: connector group: groupId='%s' netRole='%s'",
4277 id->string, role->string);
4278 rules++;
4279 }
4280skip_groups:
4281
461d39af
JM
4282 if (!rules) {
4283 wpa_printf(MSG_DEBUG,
a4bf0078 4284 "DPP: Connector includes no groups");
461d39af
JM
4285 goto fail;
4286 }
4287
4288 token = json_get_member(root, "expiry");
4289 if (!token || token->type != JSON_STRING) {
4290 wpa_printf(MSG_DEBUG,
4291 "DPP: No expiry string found - connector does not expire");
4292 } else {
4293 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4294 if (dpp_key_expired(token->string,
4295 &auth->net_access_key_expiry)) {
4296 wpa_printf(MSG_DEBUG,
4297 "DPP: Connector (netAccessKey) has expired");
4298 goto fail;
4299 }
4300 }
4301
4302 netkey = json_get_member(root, "netAccessKey");
4303 if (!netkey || netkey->type != JSON_OBJECT) {
4304 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4305 goto fail;
4306 }
4307
4308 key = dpp_parse_jwk(netkey, &curve);
4309 if (!key)
4310 goto fail;
4311 dpp_debug_print_key("DPP: Received netAccessKey", key);
4312
4313 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
4314 wpa_printf(MSG_DEBUG,
4315 "DPP: netAccessKey in connector does not match own protocol key");
4316#ifdef CONFIG_TESTING_OPTIONS
4317 if (auth->ignore_netaccesskey_mismatch) {
4318 wpa_printf(MSG_DEBUG,
4319 "DPP: TESTING - skip netAccessKey mismatch");
4320 } else {
4321 goto fail;
4322 }
4323#else /* CONFIG_TESTING_OPTIONS */
4324 goto fail;
4325#endif /* CONFIG_TESTING_OPTIONS */
4326 }
4327
4328 ret = 0;
4329fail:
4330 EVP_PKEY_free(key);
4331 json_free(root);
4332 return ret;
4333}
4334
4335
4336static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
4337{
4338 struct wpabuf *uncomp;
4339 int res;
4340 u8 hash[SHA256_MAC_LEN];
4341 const u8 *addr[1];
4342 size_t len[1];
4343
4344 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
4345 return -1;
4346 uncomp = dpp_get_pubkey_point(pub, 1);
4347 if (!uncomp)
4348 return -1;
4349 addr[0] = wpabuf_head(uncomp);
4350 len[0] = wpabuf_len(uncomp);
4351 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
4352 addr[0], len[0]);
4353 res = sha256_vector(1, addr, len, hash);
4354 wpabuf_free(uncomp);
4355 if (res < 0)
4356 return -1;
4357 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
4358 wpa_printf(MSG_DEBUG,
4359 "DPP: Received hash value does not match calculated public key hash value");
4360 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
4361 hash, SHA256_MAC_LEN);
4362 return -1;
4363 }
4364 return 0;
4365}
4366
4367
4368static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
4369{
4370 unsigned char *der = NULL;
4371 int der_len;
4372
4373 der_len = i2d_PUBKEY(csign, &der);
4374 if (der_len <= 0)
4375 return;
4376 wpabuf_free(auth->c_sign_key);
4377 auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
4378 OPENSSL_free(der);
4379}
4380
4381
4382static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
4383{
4384 unsigned char *der = NULL;
4385 int der_len;
4386 EC_KEY *eckey;
4387
4388 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
4389 if (!eckey)
4390 return;
4391
4392 der_len = i2d_ECPrivateKey(eckey, &der);
4393 if (der_len <= 0) {
4394 EC_KEY_free(eckey);
4395 return;
4396 }
4397 wpabuf_free(auth->net_access_key);
4398 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
4399 OPENSSL_free(der);
4400 EC_KEY_free(eckey);
4401}
4402
4403
4404struct dpp_signed_connector_info {
4405 unsigned char *payload;
4406 size_t payload_len;
4407};
4408
e85b6601 4409static enum dpp_status_error
461d39af
JM
4410dpp_process_signed_connector(struct dpp_signed_connector_info *info,
4411 EVP_PKEY *csign_pub, const char *connector)
4412{
e85b6601 4413 enum dpp_status_error ret = 255;
461d39af
JM
4414 const char *pos, *end, *signed_start, *signed_end;
4415 struct wpabuf *kid = NULL;
4416 unsigned char *prot_hdr = NULL, *signature = NULL;
4417 size_t prot_hdr_len = 0, signature_len = 0;
4418 const EVP_MD *sign_md = NULL;
4419 unsigned char *der = NULL;
4420 int der_len;
4421 int res;
4422 EVP_MD_CTX *md_ctx = NULL;
4423 ECDSA_SIG *sig = NULL;
4424 BIGNUM *r = NULL, *s = NULL;
6095b479
JM
4425 const struct dpp_curve_params *curve;
4426 EC_KEY *eckey;
4427 const EC_GROUP *group;
4428 int nid;
461d39af 4429
6095b479
JM
4430 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
4431 if (!eckey)
4432 goto fail;
4433 group = EC_KEY_get0_group(eckey);
4434 if (!group)
4435 goto fail;
4436 nid = EC_GROUP_get_curve_name(group);
4437 curve = dpp_get_curve_nid(nid);
4438 if (!curve)
4439 goto fail;
4440 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
461d39af
JM
4441 os_memset(info, 0, sizeof(*info));
4442
4443 signed_start = pos = connector;
4444 end = os_strchr(pos, '.');
4445 if (!end) {
4446 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
e85b6601 4447 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4448 goto fail;
4449 }
4450 prot_hdr = base64_url_decode((const unsigned char *) pos,
4451 end - pos, &prot_hdr_len);
4452 if (!prot_hdr) {
4453 wpa_printf(MSG_DEBUG,
4454 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
e85b6601 4455 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4456 goto fail;
4457 }
4458 wpa_hexdump_ascii(MSG_DEBUG,
4459 "DPP: signedConnector - JWS Protected Header",
4460 prot_hdr, prot_hdr_len);
6095b479 4461 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
e85b6601
JM
4462 if (!kid) {
4463 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af 4464 goto fail;
e85b6601 4465 }
461d39af
JM
4466 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
4467 wpa_printf(MSG_DEBUG,
4468 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
4469 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
e85b6601 4470 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4471 goto fail;
4472 }
4473
4474 pos = end + 1;
4475 end = os_strchr(pos, '.');
4476 if (!end) {
4477 wpa_printf(MSG_DEBUG,
4478 "DPP: Missing dot(2) in signedConnector");
e85b6601 4479 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4480 goto fail;
4481 }
4482 signed_end = end - 1;
4483 info->payload = base64_url_decode((const unsigned char *) pos,
4484 end - pos, &info->payload_len);
4485 if (!info->payload) {
4486 wpa_printf(MSG_DEBUG,
4487 "DPP: Failed to base64url decode signedConnector JWS Payload");
e85b6601 4488 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4489 goto fail;
4490 }
4491 wpa_hexdump_ascii(MSG_DEBUG,
4492 "DPP: signedConnector - JWS Payload",
4493 info->payload, info->payload_len);
4494 pos = end + 1;
4495 signature = base64_url_decode((const unsigned char *) pos,
4496 os_strlen(pos), &signature_len);
4497 if (!signature) {
4498 wpa_printf(MSG_DEBUG,
4499 "DPP: Failed to base64url decode signedConnector signature");
e85b6601 4500 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4501 goto fail;
4502 }
4503 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
4504 signature, signature_len);
4505
e85b6601
JM
4506 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
4507 ret = DPP_STATUS_NO_MATCH;
461d39af 4508 goto fail;
e85b6601 4509 }
461d39af
JM
4510
4511 if (signature_len & 0x01) {
4512 wpa_printf(MSG_DEBUG,
4513 "DPP: Unexpected signedConnector signature length (%d)",
4514 (int) signature_len);
e85b6601 4515 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4516 goto fail;
4517 }
4518
4519 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
4520 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
4521 r = BN_bin2bn(signature, signature_len / 2, NULL);
4522 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
4523 sig = ECDSA_SIG_new();
4524 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
4525 goto fail;
4526 r = NULL;
4527 s = NULL;
4528
4529 der_len = i2d_ECDSA_SIG(sig, &der);
4530 if (der_len <= 0) {
4531 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
4532 goto fail;
4533 }
4534 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
4535 md_ctx = EVP_MD_CTX_create();
4536 if (!md_ctx)
4537 goto fail;
4538
4539 ERR_clear_error();
4540 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
4541 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
4542 ERR_error_string(ERR_get_error(), NULL));
4543 goto fail;
4544 }
4545 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
4546 signed_end - signed_start + 1) != 1) {
4547 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
4548 ERR_error_string(ERR_get_error(), NULL));
4549 goto fail;
4550 }
4551 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
4552 if (res != 1) {
4553 wpa_printf(MSG_DEBUG,
4554 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
4555 res, ERR_error_string(ERR_get_error(), NULL));
e85b6601 4556 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
4557 goto fail;
4558 }
4559
e85b6601 4560 ret = DPP_STATUS_OK;
461d39af 4561fail:
6095b479 4562 EC_KEY_free(eckey);
461d39af
JM
4563 EVP_MD_CTX_destroy(md_ctx);
4564 os_free(prot_hdr);
4565 wpabuf_free(kid);
4566 os_free(signature);
4567 ECDSA_SIG_free(sig);
4568 BN_free(r);
4569 BN_free(s);
4570 OPENSSL_free(der);
4571 return ret;
4572}
4573
4574
4575static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
4576 struct json_token *cred)
4577{
4578 struct dpp_signed_connector_info info;
4579 struct json_token *token, *csign;
4580 int ret = -1;
4581 EVP_PKEY *csign_pub = NULL;
4582 const struct dpp_curve_params *key_curve = NULL;
4583 const char *signed_connector;
4584
4585 os_memset(&info, 0, sizeof(info));
4586
4587 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
4588
4589 csign = json_get_member(cred, "csign");
4590 if (!csign || csign->type != JSON_OBJECT) {
4591 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
4592 goto fail;
4593 }
4594
4595 csign_pub = dpp_parse_jwk(csign, &key_curve);
4596 if (!csign_pub) {
4597 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
4598 goto fail;
4599 }
4600 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
4601
461d39af
JM
4602 token = json_get_member(cred, "signedConnector");
4603 if (!token || token->type != JSON_STRING) {
4604 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
4605 goto fail;
4606 }
4607 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
4608 token->string, os_strlen(token->string));
4609 signed_connector = token->string;
4610
4611 if (os_strchr(signed_connector, '"') ||
4612 os_strchr(signed_connector, '\n')) {
4613 wpa_printf(MSG_DEBUG,
4614 "DPP: Unexpected character in signedConnector");
4615 goto fail;
4616 }
4617
4618 if (dpp_process_signed_connector(&info, csign_pub,
e85b6601 4619 signed_connector) != DPP_STATUS_OK)
461d39af
JM
4620 goto fail;
4621
4622 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
4623 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
4624 goto fail;
4625 }
4626
4627 os_free(auth->connector);
4628 auth->connector = os_strdup(signed_connector);
4629
4630 dpp_copy_csign(auth, csign_pub);
4631 dpp_copy_netaccesskey(auth);
4632
4633 ret = 0;
4634fail:
4635 EVP_PKEY_free(csign_pub);
4636 os_free(info.payload);
4637 return ret;
4638}
4639
4640
4641static int dpp_parse_conf_obj(struct dpp_authentication *auth,
4642 const u8 *conf_obj, u16 conf_obj_len)
4643{
4644 int ret = -1;
4645 struct json_token *root, *token, *discovery, *cred;
4646
4647 root = json_parse((const char *) conf_obj, conf_obj_len);
4648 if (!root)
4649 return -1;
4650 if (root->type != JSON_OBJECT) {
4651 wpa_printf(MSG_DEBUG, "DPP: JSON root is not an object");
4652 goto fail;
4653 }
4654
4655 token = json_get_member(root, "wi-fi_tech");
4656 if (!token || token->type != JSON_STRING) {
4657 wpa_printf(MSG_DEBUG, "DPP: No wi-fi_tech string value found");
4658 goto fail;
4659 }
4660 if (os_strcmp(token->string, "infra") != 0) {
4661 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
4662 token->string);
4663 goto fail;
4664 }
4665
4666 discovery = json_get_member(root, "discovery");
4667 if (!discovery || discovery->type != JSON_OBJECT) {
4668 wpa_printf(MSG_DEBUG, "DPP: No discovery object in JSON");
4669 goto fail;
4670 }
4671
4672 token = json_get_member(discovery, "ssid");
4673 if (!token || token->type != JSON_STRING) {
4674 wpa_printf(MSG_DEBUG,
4675 "DPP: No discovery::ssid string value found");
4676 goto fail;
4677 }
4678 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
4679 token->string, os_strlen(token->string));
4680 if (os_strlen(token->string) > SSID_MAX_LEN) {
4681 wpa_printf(MSG_DEBUG,
4682 "DPP: Too long discovery::ssid string value");
4683 goto fail;
4684 }
4685 auth->ssid_len = os_strlen(token->string);
4686 os_memcpy(auth->ssid, token->string, auth->ssid_len);
4687
4688 cred = json_get_member(root, "cred");
4689 if (!cred || cred->type != JSON_OBJECT) {
4690 wpa_printf(MSG_DEBUG, "DPP: No cred object in JSON");
4691 goto fail;
4692 }
4693
4694 token = json_get_member(cred, "akm");
4695 if (!token || token->type != JSON_STRING) {
4696 wpa_printf(MSG_DEBUG,
4697 "DPP: No cred::akm string value found");
4698 goto fail;
4699 }
4700 if (os_strcmp(token->string, "psk") == 0) {
4701 if (dpp_parse_cred_legacy(auth, cred) < 0)
4702 goto fail;
4703 } else if (os_strcmp(token->string, "dpp") == 0) {
4704 if (dpp_parse_cred_dpp(auth, cred) < 0)
4705 goto fail;
4706 } else {
4707 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
4708 token->string);
4709 goto fail;
4710 }
4711
4712 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
4713 ret = 0;
4714fail:
4715 json_free(root);
4716 return ret;
4717}
4718
4719
4720int dpp_conf_resp_rx(struct dpp_authentication *auth,
4721 const struct wpabuf *resp)
4722{
4723 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
4724 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
4725 const u8 *addr[1];
4726 size_t len[1];
4727 u8 *unwrapped = NULL;
4728 size_t unwrapped_len = 0;
4729 int ret = -1;
4730
4731 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
4732 wpa_printf(MSG_DEBUG,
4733 "DPP: Invalid attribute in config response");
4734 return -1;
4735 }
4736
4737 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
4738 DPP_ATTR_WRAPPED_DATA,
4739 &wrapped_data_len);
4740 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4741 wpa_printf(MSG_DEBUG,
4742 "DPP: Missing or invalid required Wrapped data attribute");
4743 return -1;
4744 }
4745
4746 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4747 wrapped_data, wrapped_data_len);
4748 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4749 unwrapped = os_malloc(unwrapped_len);
4750 if (!unwrapped)
4751 return -1;
4752
4753 addr[0] = wpabuf_head(resp);
4754 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
4755 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4756
4757 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4758 wrapped_data, wrapped_data_len,
4759 1, addr, len, unwrapped) < 0) {
4760 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
4761 goto fail;
4762 }
4763 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4764 unwrapped, unwrapped_len);
4765
4766 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4767 wpa_printf(MSG_DEBUG,
4768 "DPP: Invalid attribute in unwrapped data");
4769 goto fail;
4770 }
4771
4772 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4773 DPP_ATTR_ENROLLEE_NONCE,
4774 &e_nonce_len);
4775 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
4776 wpa_printf(MSG_DEBUG,
4777 "DPP: Missing or invalid Enrollee Nonce attribute");
4778 goto fail;
4779 }
4780 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4781 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
4782 wpa_printf(MSG_DEBUG, "Enrollee Nonce mismatch");
4783 goto fail;
4784 }
4785
4786 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
4787 DPP_ATTR_STATUS, &status_len);
4788 if (!status || status_len < 1) {
4789 wpa_printf(MSG_DEBUG,
4790 "DPP: Missing or invalid required DPP Status attribute");
4791 goto fail;
4792 }
4793 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
4794 if (status[0] != DPP_STATUS_OK) {
4795 wpa_printf(MSG_DEBUG, "DPP: Configuration failed");
4796 goto fail;
4797 }
4798
4799 conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
4800 DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
4801 if (!conf_obj) {
4802 wpa_printf(MSG_DEBUG,
4803 "DPP: Missing required Configuration Object attribute");
4804 goto fail;
4805 }
4806 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4807 conf_obj, conf_obj_len);
4808 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
4809 goto fail;
4810
4811 ret = 0;
4812
4813fail:
4814 os_free(unwrapped);
4815 return ret;
4816}
4817
4818
4819void dpp_configurator_free(struct dpp_configurator *conf)
4820{
4821 if (!conf)
4822 return;
4823 EVP_PKEY_free(conf->csign);
4824 os_free(conf->kid);
4825 os_free(conf);
4826}
4827
4828
4829struct dpp_configurator *
4830dpp_keygen_configurator(const char *curve, const u8 *privkey,
4831 size_t privkey_len)
4832{
4833 struct dpp_configurator *conf;
4834 struct wpabuf *csign_pub = NULL;
4835 u8 kid_hash[SHA256_MAC_LEN];
4836 const u8 *addr[1];
4837 size_t len[1];
4838
4839 conf = os_zalloc(sizeof(*conf));
4840 if (!conf)
4841 return NULL;
4842
4843 if (!curve) {
4844 conf->curve = &dpp_curves[0];
4845 } else {
4846 conf->curve = dpp_get_curve_name(curve);
4847 if (!conf->curve) {
4848 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
4849 curve);
4850 return NULL;
4851 }
4852 }
4853 if (privkey)
4854 conf->csign = dpp_set_keypair(&conf->curve, privkey,
4855 privkey_len);
4856 else
4857 conf->csign = dpp_gen_keypair(conf->curve);
4858 if (!conf->csign)
4859 goto fail;
4860 conf->own = 1;
4861
4862 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
4863 if (!csign_pub) {
4864 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
4865 goto fail;
4866 }
4867
4868 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
4869 addr[0] = wpabuf_head(csign_pub);
4870 len[0] = wpabuf_len(csign_pub);
4871 if (sha256_vector(1, addr, len, kid_hash) < 0) {
4872 wpa_printf(MSG_DEBUG,
4873 "DPP: Failed to derive kid for C-sign-key");
4874 goto fail;
4875 }
4876
4877 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
4878 NULL, 0);
4879 if (!conf->kid)
4880 goto fail;
4881out:
4882 wpabuf_free(csign_pub);
4883 return conf;
4884fail:
4885 dpp_configurator_free(conf);
4886 conf = NULL;
4887 goto out;
4888}
650a70a7
JM
4889
4890
f522bb23
JM
4891int dpp_configurator_own_config(struct dpp_authentication *auth,
4892 const char *curve)
4893{
4894 struct wpabuf *conf_obj;
4895 int ret = -1;
4896
4897 if (!auth->conf) {
4898 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
4899 return -1;
4900 }
4901
4902 if (!curve) {
4903 auth->curve = &dpp_curves[0];
4904 } else {
4905 auth->curve = dpp_get_curve_name(curve);
4906 if (!auth->curve) {
4907 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
4908 curve);
4909 return -1;
4910 }
4911 }
4912 wpa_printf(MSG_DEBUG,
4913 "DPP: Building own configuration/connector with curve %s",
4914 auth->curve->name);
4915
4916 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
4917 if (!auth->own_protocol_key)
4918 return -1;
4919 dpp_copy_netaccesskey(auth);
4920 auth->peer_protocol_key = auth->own_protocol_key;
4921 dpp_copy_csign(auth, auth->conf->csign);
4922
4923 conf_obj = dpp_build_conf_obj(auth, 0);
4924 if (!conf_obj)
4925 goto fail;
4926 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
4927 wpabuf_len(conf_obj));
4928fail:
4929 wpabuf_free(conf_obj);
4930 auth->peer_protocol_key = NULL;
4931 return ret;
4932}
4933
4934
650a70a7
JM
4935static int dpp_compatible_netrole(const char *role1, const char *role2)
4936{
4937 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
4938 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
4939}
4940
4941
4942static int dpp_connector_compatible_group(struct json_token *root,
4943 const char *group_id,
4944 const char *net_role)
4945{
4946 struct json_token *groups, *token;
4947
4948 groups = json_get_member(root, "groups");
4949 if (!groups || groups->type != JSON_ARRAY)
4950 return 0;
4951
4952 for (token = groups->child; token; token = token->sibling) {
4953 struct json_token *id, *role;
4954
4955 id = json_get_member(token, "groupId");
4956 if (!id || id->type != JSON_STRING)
4957 continue;
4958
4959 role = json_get_member(token, "netRole");
4960 if (!role || role->type != JSON_STRING)
4961 continue;
4962
4963 if (os_strcmp(id->string, "*") != 0 &&
4964 os_strcmp(group_id, "*") != 0 &&
4965 os_strcmp(id->string, group_id) != 0)
4966 continue;
4967
4968 if (dpp_compatible_netrole(role->string, net_role))
4969 return 1;
4970 }
4971
4972 return 0;
4973}
4974
4975
4976static int dpp_connector_match_groups(struct json_token *own_root,
4977 struct json_token *peer_root)
4978{
4979 struct json_token *groups, *token;
4980
4981 groups = json_get_member(peer_root, "groups");
4982 if (!groups || groups->type != JSON_ARRAY) {
4983 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
4984 return 0;
4985 }
4986
4987 for (token = groups->child; token; token = token->sibling) {
4988 struct json_token *id, *role;
4989
4990 id = json_get_member(token, "groupId");
4991 if (!id || id->type != JSON_STRING) {
4992 wpa_printf(MSG_DEBUG,
4993 "DPP: Missing peer groupId string");
4994 continue;
4995 }
4996
4997 role = json_get_member(token, "netRole");
4998 if (!role || role->type != JSON_STRING) {
4999 wpa_printf(MSG_DEBUG,
5000 "DPP: Missing peer groups::netRole string");
5001 continue;
5002 }
5003 wpa_printf(MSG_DEBUG,
5004 "DPP: peer connector group: groupId='%s' netRole='%s'",
5005 id->string, role->string);
5006 if (dpp_connector_compatible_group(own_root, id->string,
5007 role->string)) {
5008 wpa_printf(MSG_DEBUG,
5009 "DPP: Compatible group/netRole in own connector");
5010 return 1;
5011 }
5012 }
5013
5014 return 0;
5015}
5016
5017
650a70a7
JM
5018static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
5019 unsigned int hash_len)
5020{
5021 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5022 const char *info = "DPP PMK";
b9d47b48 5023 int res;
650a70a7
JM
5024
5025 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5026
5027 /* HKDF-Extract(<>, N.x) */
5028 os_memset(salt, 0, hash_len);
b9d47b48 5029 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
650a70a7 5030 return -1;
650a70a7
JM
5031 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5032 prk, hash_len);
5033
5034 /* HKDF-Expand(PRK, info, L) */
b9d47b48 5035 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
650a70a7
JM
5036 os_memset(prk, 0, hash_len);
5037 if (res < 0)
5038 return -1;
5039
5040 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5041 pmk, hash_len);
5042 return 0;
5043}
5044
5045
5046static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
5047 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
5048{
5049 struct wpabuf *nkx, *pkx;
5050 int ret = -1, res;
5051 const u8 *addr[2];
5052 size_t len[2];
c2d4f2eb 5053 u8 hash[SHA256_MAC_LEN];
650a70a7
JM
5054
5055 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5056 nkx = dpp_get_pubkey_point(own_key, 0);
5057 pkx = dpp_get_pubkey_point(peer_key, 0);
5058 if (!nkx || !pkx)
5059 goto fail;
5060 addr[0] = wpabuf_head(nkx);
5061 len[0] = wpabuf_len(nkx) / 2;
5062 addr[1] = wpabuf_head(pkx);
5063 len[1] = wpabuf_len(pkx) / 2;
5064 if (len[0] != len[1])
5065 goto fail;
5066 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
5067 addr[0] = wpabuf_head(pkx);
5068 addr[1] = wpabuf_head(nkx);
5069 }
650a70a7
JM
5070 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
5071 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
c2d4f2eb 5072 res = sha256_vector(2, addr, len, hash);
650a70a7
JM
5073 if (res < 0)
5074 goto fail;
c2d4f2eb 5075 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
650a70a7
JM
5076 os_memcpy(pmkid, hash, PMKID_LEN);
5077 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
5078 ret = 0;
5079fail:
5080 wpabuf_free(nkx);
5081 wpabuf_free(pkx);
5082 return ret;
5083}
5084
5085
e85b6601
JM
5086enum dpp_status_error
5087dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
5088 const u8 *net_access_key, size_t net_access_key_len,
5089 const u8 *csign_key, size_t csign_key_len,
5090 const u8 *peer_connector, size_t peer_connector_len,
5091 os_time_t *expiry)
650a70a7
JM
5092{
5093 struct json_token *root = NULL, *netkey, *token;
5094 struct json_token *own_root = NULL;
e85b6601 5095 enum dpp_status_error ret = 255, res;
650a70a7
JM
5096 EVP_PKEY *own_key = NULL, *peer_key = NULL;
5097 struct wpabuf *own_key_pub = NULL;
650a70a7
JM
5098 const struct dpp_curve_params *curve, *own_curve;
5099 struct dpp_signed_connector_info info;
5100 const unsigned char *p;
5101 EVP_PKEY *csign = NULL;
5102 char *signed_connector = NULL;
5103 const char *pos, *end;
5104 unsigned char *own_conn = NULL;
5105 size_t own_conn_len;
5106 EVP_PKEY_CTX *ctx = NULL;
5107 size_t Nx_len;
5108 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
650a70a7
JM
5109
5110 os_memset(intro, 0, sizeof(*intro));
5111 os_memset(&info, 0, sizeof(info));
787615b3
JM
5112 if (expiry)
5113 *expiry = 0;
650a70a7
JM
5114
5115 p = csign_key;
5116 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
5117 if (!csign) {
5118 wpa_printf(MSG_ERROR,
5119 "DPP: Failed to parse local C-sign-key information");
5120 goto fail;
5121 }
5122
5123 own_key = dpp_set_keypair(&own_curve, net_access_key,
5124 net_access_key_len);
5125 if (!own_key) {
5126 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
5127 goto fail;
5128 }
650a70a7
JM
5129
5130 pos = os_strchr(own_connector, '.');
43fbb8db
JM
5131 if (!pos) {
5132 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
650a70a7 5133 goto fail;
43fbb8db 5134 }
650a70a7
JM
5135 pos++;
5136 end = os_strchr(pos, '.');
43fbb8db
JM
5137 if (!end) {
5138 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
650a70a7 5139 goto fail;
43fbb8db 5140 }
650a70a7
JM
5141 own_conn = base64_url_decode((const unsigned char *) pos,
5142 end - pos, &own_conn_len);
5143 if (!own_conn) {
5144 wpa_printf(MSG_DEBUG,
5145 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5146 goto fail;
5147 }
5148
5149 own_root = json_parse((const char *) own_conn, own_conn_len);
5150 if (!own_root) {
5151 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
5152 goto fail;
5153 }
5154
5155 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
5156 peer_connector, peer_connector_len);
5157 signed_connector = os_malloc(peer_connector_len + 1);
5158 if (!signed_connector)
5159 goto fail;
5160 os_memcpy(signed_connector, peer_connector, peer_connector_len);
5161 signed_connector[peer_connector_len] = '\0';
5162
e85b6601
JM
5163 res = dpp_process_signed_connector(&info, csign, signed_connector);
5164 if (res != DPP_STATUS_OK) {
5165 ret = res;
650a70a7 5166 goto fail;
e85b6601 5167 }
650a70a7
JM
5168
5169 root = json_parse((const char *) info.payload, info.payload_len);
5170 if (!root) {
5171 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
e85b6601 5172 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5173 goto fail;
5174 }
5175
a4bf0078 5176 if (!dpp_connector_match_groups(own_root, root)) {
650a70a7 5177 wpa_printf(MSG_DEBUG,
a4bf0078 5178 "DPP: Peer connector does not include compatible group netrole with own connector");
e85b6601 5179 ret = DPP_STATUS_NO_MATCH;
650a70a7
JM
5180 goto fail;
5181 }
5182
5183 token = json_get_member(root, "expiry");
5184 if (!token || token->type != JSON_STRING) {
5185 wpa_printf(MSG_DEBUG,
5186 "DPP: No expiry string found - connector does not expire");
5187 } else {
5188 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
787615b3 5189 if (dpp_key_expired(token->string, expiry)) {
650a70a7
JM
5190 wpa_printf(MSG_DEBUG,
5191 "DPP: Connector (netAccessKey) has expired");
e85b6601 5192 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5193 goto fail;
5194 }
5195 }
5196
5197 netkey = json_get_member(root, "netAccessKey");
5198 if (!netkey || netkey->type != JSON_OBJECT) {
5199 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
e85b6601 5200 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5201 goto fail;
5202 }
5203
5204 peer_key = dpp_parse_jwk(netkey, &curve);
e85b6601
JM
5205 if (!peer_key) {
5206 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7 5207 goto fail;
e85b6601 5208 }
650a70a7
JM
5209 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
5210
5211 if (own_curve != curve) {
5212 wpa_printf(MSG_DEBUG,
5213 "DPP: Mismatching netAccessKey curves (%s != %s)",
5214 own_curve->name, curve->name);
e85b6601 5215 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
5216 goto fail;
5217 }
5218
5219 /* ECDH: N = nk * PK */
5220 ctx = EVP_PKEY_CTX_new(own_key, NULL);
5221 if (!ctx ||
5222 EVP_PKEY_derive_init(ctx) != 1 ||
5223 EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
5224 EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
5225 Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
5226 EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
5227 wpa_printf(MSG_ERROR,
5228 "DPP: Failed to derive ECDH shared secret: %s",
5229 ERR_error_string(ERR_get_error(), NULL));
5230 goto fail;
5231 }
5232
5233 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
5234 Nx, Nx_len);
5235
5236 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5237 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
5238 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
5239 goto fail;
5240 }
5241 intro->pmk_len = curve->hash_len;
5242
5243 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5244 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
5245 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
5246 goto fail;
5247 }
5248
e85b6601 5249 ret = DPP_STATUS_OK;
650a70a7 5250fail:
e85b6601 5251 if (ret != DPP_STATUS_OK)
650a70a7
JM
5252 os_memset(intro, 0, sizeof(*intro));
5253 os_memset(Nx, 0, sizeof(Nx));
5254 EVP_PKEY_CTX_free(ctx);
5255 os_free(own_conn);
5256 os_free(signed_connector);
5257 os_free(info.payload);
5258 EVP_PKEY_free(own_key);
5259 wpabuf_free(own_key_pub);
650a70a7
JM
5260 EVP_PKEY_free(peer_key);
5261 EVP_PKEY_free(csign);
5262 json_free(root);
5263 json_free(own_root);
5264 return ret;
5265}
500ed7f0
JM
5266
5267
5268static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
5269 int init)
5270{
5271 EC_GROUP *group;
5272 size_t len = curve->prime_len;
5273 const u8 *x, *y;
5274
5275 switch (curve->ike_group) {
5276 case 19:
5277 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
5278 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
5279 break;
5280 case 20:
5281 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
5282 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
5283 break;
5284 case 21:
5285 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
5286 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
5287 break;
5288 case 28:
5289 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
5290 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
5291 break;
5292 case 29:
5293 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
5294 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
5295 break;
5296 case 30:
5297 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
5298 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
5299 break;
5300 default:
5301 return NULL;
5302 }
5303
5304 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5305 if (!group)
5306 return NULL;
5307 return dpp_set_pubkey_point_group(group, x, y, len);
5308}
5309
5310
5311static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
5312 const u8 *mac_init, const char *code,
5313 const char *identifier, BN_CTX *bnctx,
5314 const EC_GROUP **ret_group)
5315{
5316 u8 hash[DPP_MAX_HASH_LEN];
5317 const u8 *addr[3];
5318 size_t len[3];
5319 unsigned int num_elem = 0;
5320 EC_POINT *Qi = NULL;
5321 EVP_PKEY *Pi = NULL;
5322 EC_KEY *Pi_ec = NULL;
5323 const EC_POINT *Pi_point;
5324 BIGNUM *hash_bn = NULL;
5325 const EC_GROUP *group = NULL;
5326 EC_GROUP *group2 = NULL;
5327
5328 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5329
5330 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
5331 addr[num_elem] = mac_init;
5332 len[num_elem] = ETH_ALEN;
5333 num_elem++;
5334 if (identifier) {
5335 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
5336 identifier);
5337 addr[num_elem] = (const u8 *) identifier;
5338 len[num_elem] = os_strlen(identifier);
5339 num_elem++;
5340 }
5341 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
5342 addr[num_elem] = (const u8 *) code;
5343 len[num_elem] = os_strlen(code);
5344 num_elem++;
5345 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
5346 goto fail;
5347 wpa_hexdump_key(MSG_DEBUG,
5348 "DPP: H(MAC-Initiator | [identifier |] code)",
5349 hash, curve->hash_len);
5350 Pi = dpp_pkex_get_role_elem(curve, 1);
5351 if (!Pi)
5352 goto fail;
5353 dpp_debug_print_key("DPP: Pi", Pi);
5354 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
5355 if (!Pi_ec)
5356 goto fail;
5357 Pi_point = EC_KEY_get0_public_key(Pi_ec);
5358
5359 group = EC_KEY_get0_group(Pi_ec);
5360 if (!group)
5361 goto fail;
5362 group2 = EC_GROUP_dup(group);
5363 if (!group2)
5364 goto fail;
5365 Qi = EC_POINT_new(group2);
5366 if (!Qi) {
5367 EC_GROUP_free(group2);
5368 goto fail;
5369 }
5370 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
5371 if (!hash_bn ||
5372 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
5373 goto fail;
65731717
JM
5374 if (EC_POINT_is_at_infinity(group, Qi)) {
5375 wpa_printf(MSG_INFO, "PDP: Qi is the point-at-infinity");
5376 goto fail;
5377 }
500ed7f0
JM
5378out:
5379 EC_KEY_free(Pi_ec);
5380 EVP_PKEY_free(Pi);
5381 BN_clear_free(hash_bn);
5382 if (ret_group)
5383 *ret_group = group2;
5384 return Qi;
5385fail:
5386 EC_POINT_free(Qi);
5387 Qi = NULL;
5388 goto out;
5389}
5390
5391
5392static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
5393 const u8 *mac_resp, const char *code,
5394 const char *identifier, BN_CTX *bnctx,
5395 const EC_GROUP **ret_group)
5396{
5397 u8 hash[DPP_MAX_HASH_LEN];
5398 const u8 *addr[3];
5399 size_t len[3];
5400 unsigned int num_elem = 0;
5401 EC_POINT *Qr = NULL;
5402 EVP_PKEY *Pr = NULL;
5403 EC_KEY *Pr_ec = NULL;
5404 const EC_POINT *Pr_point;
5405 BIGNUM *hash_bn = NULL;
5406 const EC_GROUP *group = NULL;
5407 EC_GROUP *group2 = NULL;
5408
5409 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5410
5411 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
5412 addr[num_elem] = mac_resp;
5413 len[num_elem] = ETH_ALEN;
5414 num_elem++;
5415 if (identifier) {
5416 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
5417 identifier);
5418 addr[num_elem] = (const u8 *) identifier;
5419 len[num_elem] = os_strlen(identifier);
5420 num_elem++;
5421 }
5422 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
5423 addr[num_elem] = (const u8 *) code;
5424 len[num_elem] = os_strlen(code);
5425 num_elem++;
5426 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
5427 goto fail;
5428 wpa_hexdump_key(MSG_DEBUG,
5429 "DPP: H(MAC-Responder | [identifier |] code)",
5430 hash, curve->hash_len);
5431 Pr = dpp_pkex_get_role_elem(curve, 0);
5432 if (!Pr)
5433 goto fail;
5434 dpp_debug_print_key("DPP: Pr", Pr);
5435 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
5436 if (!Pr_ec)
5437 goto fail;
5438 Pr_point = EC_KEY_get0_public_key(Pr_ec);
5439
5440 group = EC_KEY_get0_group(Pr_ec);
5441 if (!group)
5442 goto fail;
5443 group2 = EC_GROUP_dup(group);
5444 if (!group2)
5445 goto fail;
5446 Qr = EC_POINT_new(group2);
5447 if (!Qr) {
5448 EC_GROUP_free(group2);
5449 goto fail;
5450 }
5451 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
5452 if (!hash_bn ||
5453 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
5454 goto fail;
5455out:
5456 EC_KEY_free(Pr_ec);
5457 EVP_PKEY_free(Pr);
5458 BN_clear_free(hash_bn);
5459 if (ret_group)
5460 *ret_group = group2;
5461 return Qr;
5462fail:
5463 EC_POINT_free(Qr);
5464 Qr = NULL;
5465 goto out;
5466}
5467
5468
1cfcbd32
JM
5469#ifdef CONFIG_TESTING_OPTIONS
5470static int dpp_test_gen_invalid_key(struct wpabuf *msg,
5471 const struct dpp_curve_params *curve)
5472{
5473 BN_CTX *ctx;
5474 BIGNUM *x, *y;
5475 int num_bytes, offset;
5476 int ret = -1;
5477 EC_GROUP *group;
5478 EC_POINT *point;
5479
5480 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5481 if (!group)
5482 return NULL;
5483
5484 ctx = BN_CTX_new();
5485 point = EC_POINT_new(group);
5486 x = BN_new();
5487 y = BN_new();
5488 if (!ctx || !point || !x || !y)
5489 goto fail;
5490
5491 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
5492 goto fail;
5493
5494 /* Generate a random y coordinate that results in a point that is not
5495 * on the curve. */
5496 for (;;) {
5497 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
5498 goto fail;
5499
5500 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
5501 ctx) != 1)
5502 goto fail;
5503
5504 if (!EC_POINT_is_on_curve(group, point, ctx))
5505 break;
5506 }
5507
5508 num_bytes = BN_num_bytes(x);
5509 if ((size_t) num_bytes > curve->prime_len)
5510 goto fail;
5511 if (curve->prime_len > (size_t) num_bytes)
5512 offset = curve->prime_len - num_bytes;
5513 else
5514 offset = 0;
5515 os_memset(wpabuf_put(msg, offset), 0, offset);
5516 BN_bn2bin(x, wpabuf_put(msg, num_bytes));
5517
5518 num_bytes = BN_num_bytes(y);
5519 if ((size_t) num_bytes > curve->prime_len)
5520 goto fail;
5521 if (curve->prime_len > (size_t) num_bytes)
5522 offset = curve->prime_len - num_bytes;
5523 else
5524 offset = 0;
5525 os_memset(wpabuf_put(msg, offset), 0, offset);
5526 BN_bn2bin(y, wpabuf_put(msg, num_bytes));
5527
5528 ret = 0;
5529fail:
5530 BN_free(x);
5531 BN_free(y);
5532 EC_POINT_free(point);
5533 BN_CTX_free(ctx);
5534
5535 return ret;
5536}
5537#endif /* CONFIG_TESTING_OPTIONS */
5538
5539
500ed7f0
JM
5540static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
5541{
5542 EC_KEY *X_ec = NULL;
5543 const EC_POINT *X_point;
5544 BN_CTX *bnctx = NULL;
5545 const EC_GROUP *group;
5546 EC_POINT *Qi = NULL, *M = NULL;
5547 struct wpabuf *M_buf = NULL;
5548 BIGNUM *Mx = NULL, *My = NULL;
5549 struct wpabuf *msg = NULL;
5550 size_t attr_len;
5551 const struct dpp_curve_params *curve = pkex->own_bi->curve;
5552 int num_bytes, offset;
5553
5554 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
5555
5556 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5557 bnctx = BN_CTX_new();
5558 if (!bnctx)
5559 goto fail;
5560 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
5561 pkex->identifier, bnctx, &group);
5562 if (!Qi)
5563 goto fail;
5564
5565 /* Generate a random ephemeral keypair x/X */
5566 pkex->x = dpp_gen_keypair(curve);
5567 if (!pkex->x)
5568 goto fail;
5569
5570 /* M = X + Qi */
5571 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
5572 if (!X_ec)
5573 goto fail;
5574 X_point = EC_KEY_get0_public_key(X_ec);
5575 if (!X_point)
5576 goto fail;
5577 M = EC_POINT_new(group);
5578 Mx = BN_new();
5579 My = BN_new();
5580 if (!M || !Mx || !My ||
5581 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
5582 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
5583 goto fail;
5584
5585 /* Initiator -> Responder: group, [identifier,] M */
5586 attr_len = 4 + 2;
5587 if (pkex->identifier)
5588 attr_len += 4 + os_strlen(pkex->identifier);
5589 attr_len += 4 + 2 * curve->prime_len;
5590 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
5591 if (!msg)
5592 goto fail;
5593
61f9f27f
JM
5594#ifdef CONFIG_TESTING_OPTIONS
5595 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
5596 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
5597 goto skip_finite_cyclic_group;
5598 }
5599#endif /* CONFIG_TESTING_OPTIONS */
5600
500ed7f0
JM
5601 /* Finite Cyclic Group attribute */
5602 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
5603 wpabuf_put_le16(msg, 2);
5604 wpabuf_put_le16(msg, curve->ike_group);
5605
61f9f27f
JM
5606#ifdef CONFIG_TESTING_OPTIONS
5607skip_finite_cyclic_group:
5608#endif /* CONFIG_TESTING_OPTIONS */
5609
500ed7f0
JM
5610 /* Code Identifier attribute */
5611 if (pkex->identifier) {
5612 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
5613 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
5614 wpabuf_put_str(msg, pkex->identifier);
5615 }
5616
61f9f27f
JM
5617#ifdef CONFIG_TESTING_OPTIONS
5618 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
5619 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
5620 goto out;
5621 }
5622#endif /* CONFIG_TESTING_OPTIONS */
5623
500ed7f0
JM
5624 /* M in Encrypted Key attribute */
5625 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
5626 wpabuf_put_le16(msg, 2 * curve->prime_len);
5627
1cfcbd32
JM
5628#ifdef CONFIG_TESTING_OPTIONS
5629 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
5630 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
5631 if (dpp_test_gen_invalid_key(msg, curve) < 0)
5632 goto fail;
5633 goto out;
5634 }
5635#endif /* CONFIG_TESTING_OPTIONS */
5636
500ed7f0
JM
5637 num_bytes = BN_num_bytes(Mx);
5638 if ((size_t) num_bytes > curve->prime_len)
5639 goto fail;
5640 if (curve->prime_len > (size_t) num_bytes)
5641 offset = curve->prime_len - num_bytes;
5642 else
5643 offset = 0;
5644 os_memset(wpabuf_put(msg, offset), 0, offset);
5645 BN_bn2bin(Mx, wpabuf_put(msg, num_bytes));
5646 os_memset(pkex->Mx, 0, offset);
5647 BN_bn2bin(Mx, pkex->Mx + offset);
5648
5649 num_bytes = BN_num_bytes(My);
5650 if ((size_t) num_bytes > curve->prime_len)
5651 goto fail;
5652 if (curve->prime_len > (size_t) num_bytes)
5653 offset = curve->prime_len - num_bytes;
5654 else
5655 offset = 0;
5656 os_memset(wpabuf_put(msg, offset), 0, offset);
5657 BN_bn2bin(My, wpabuf_put(msg, num_bytes));
5658
5659out:
5660 wpabuf_free(M_buf);
5661 EC_KEY_free(X_ec);
5662 EC_POINT_free(M);
5663 EC_POINT_free(Qi);
5664 BN_clear_free(Mx);
5665 BN_clear_free(My);
5666 BN_CTX_free(bnctx);
5667 return msg;
5668fail:
5669 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
5670 wpabuf_free(msg);
5671 msg = NULL;
5672 goto out;
5673}
5674
5675
219d4c9f
JM
5676static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
5677{
5678 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
5679}
5680
5681
5682struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
500ed7f0
JM
5683 const u8 *own_mac,
5684 const char *identifier,
5685 const char *code)
5686{
5687 struct dpp_pkex *pkex;
5688
5689 pkex = os_zalloc(sizeof(*pkex));
5690 if (!pkex)
5691 return NULL;
219d4c9f 5692 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
5693 pkex->initiator = 1;
5694 pkex->own_bi = bi;
5695 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
5696 if (identifier) {
5697 pkex->identifier = os_strdup(identifier);
5698 if (!pkex->identifier)
5699 goto fail;
5700 }
5701 pkex->code = os_strdup(code);
5702 if (!pkex->code)
5703 goto fail;
5704 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
5705 if (!pkex->exchange_req)
5706 goto fail;
5707 return pkex;
5708fail:
5709 dpp_pkex_free(pkex);
5710 return NULL;
5711}
5712
5713
a5c3b41b
JM
5714static struct wpabuf * dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
5715 const char *identifier,
5716 const BIGNUM *Nx,
5717 const BIGNUM *Ny)
5718{
5719 struct wpabuf *msg = NULL;
5720 size_t attr_len;
5721 int num_bytes, offset;
5722 const struct dpp_curve_params *curve = pkex->own_bi->curve;
5723
5724 /* Initiator -> Responder: DPP Status, [identifier,] N */
5725 attr_len = 4 + 1;
5726 if (identifier)
5727 attr_len += 4 + os_strlen(identifier);
5728 attr_len += 4 + 2 * curve->prime_len;
5729 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
5730 if (!msg)
5731 goto fail;
5732
61f9f27f
JM
5733#ifdef CONFIG_TESTING_OPTIONS
5734 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
5735 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
5736 goto skip_status;
5737 }
5738#endif /* CONFIG_TESTING_OPTIONS */
5739
a5c3b41b
JM
5740 /* DPP Status */
5741 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
5742 wpabuf_put_le16(msg, 1);
5743 wpabuf_put_u8(msg, DPP_STATUS_OK);
5744
61f9f27f
JM
5745#ifdef CONFIG_TESTING_OPTIONS
5746skip_status:
5747#endif /* CONFIG_TESTING_OPTIONS */
5748
a5c3b41b
JM
5749 /* Code Identifier attribute */
5750 if (pkex->identifier) {
5751 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
5752 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
5753 wpabuf_put_str(msg, pkex->identifier);
5754 }
5755
61f9f27f
JM
5756#ifdef CONFIG_TESTING_OPTIONS
5757 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
5758 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
5759 goto skip_encrypted_key;
5760 }
5761#endif /* CONFIG_TESTING_OPTIONS */
5762
a5c3b41b
JM
5763 /* N in Encrypted Key attribute */
5764 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
5765 wpabuf_put_le16(msg, 2 * curve->prime_len);
5766
1cfcbd32
JM
5767#ifdef CONFIG_TESTING_OPTIONS
5768 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
5769 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
5770 if (dpp_test_gen_invalid_key(msg, curve) < 0)
5771 goto fail;
5772 goto skip_encrypted_key;
5773 }
5774#endif /* CONFIG_TESTING_OPTIONS */
5775
a5c3b41b
JM
5776 num_bytes = BN_num_bytes(Nx);
5777 if ((size_t) num_bytes > curve->prime_len)
5778 goto fail;
5779 if (curve->prime_len > (size_t) num_bytes)
5780 offset = curve->prime_len - num_bytes;
5781 else
5782 offset = 0;
5783 os_memset(wpabuf_put(msg, offset), 0, offset);
5784 BN_bn2bin(Nx, wpabuf_put(msg, num_bytes));
5785 os_memset(pkex->Nx, 0, offset);
5786 BN_bn2bin(Nx, pkex->Nx + offset);
5787
5788 num_bytes = BN_num_bytes(Ny);
5789 if ((size_t) num_bytes > curve->prime_len)
5790 goto fail;
5791 if (curve->prime_len > (size_t) num_bytes)
5792 offset = curve->prime_len - num_bytes;
5793 else
5794 offset = 0;
5795 os_memset(wpabuf_put(msg, offset), 0, offset);
5796 BN_bn2bin(Ny, wpabuf_put(msg, num_bytes));
5797
61f9f27f
JM
5798#ifdef CONFIG_TESTING_OPTIONS
5799skip_encrypted_key:
5800#endif /* CONFIG_TESTING_OPTIONS */
a5c3b41b
JM
5801 return msg;
5802fail:
5803 wpabuf_free(msg);
5804 return NULL;
5805}
5806
5807
219d4c9f
JM
5808struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
5809 struct dpp_bootstrap_info *bi,
500ed7f0
JM
5810 const u8 *own_mac,
5811 const u8 *peer_mac,
5812 const char *identifier,
5813 const char *code,
5814 const u8 *buf, size_t len)
5815{
5816 const u8 *attr_group, *attr_id, *attr_key;
5817 u16 attr_group_len, attr_id_len, attr_key_len;
5818 const struct dpp_curve_params *curve = bi->curve;
5819 u16 ike_group;
5820 struct dpp_pkex *pkex = NULL;
5821 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
5822 BN_CTX *bnctx = NULL;
5823 const EC_GROUP *group;
5824 BIGNUM *Mx = NULL, *My = NULL;
5825 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
5826 const EC_POINT *Y_point;
5827 BIGNUM *Nx = NULL, *Ny = NULL;
500ed7f0
JM
5828
5829 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
5830 &attr_id_len);
5831 if (!attr_id && identifier) {
5832 wpa_printf(MSG_DEBUG,
5833 "DPP: No PKEX code identifier received, but expected one");
5834 return NULL;
5835 }
5836 if (attr_id && identifier &&
5837 (os_strlen(identifier) != attr_id_len ||
5838 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
5839 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
5840 return NULL;
5841 }
5842
5843 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
5844 &attr_group_len);
5845 if (!attr_group || attr_group_len != 2) {
d7e7b712
JM
5846 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
5847 "Missing or invalid Finite Cyclic Group attribute");
500ed7f0
JM
5848 return NULL;
5849 }
5850 ike_group = WPA_GET_LE16(attr_group);
5851 if (ike_group != curve->ike_group) {
d7e7b712
JM
5852 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
5853 "Mismatching PKEX curve: peer=%u own=%u",
5854 ike_group, curve->ike_group);
500ed7f0
JM
5855 /* TODO: error response with suggested curve:
5856 * DPP Status, group */
5857 return NULL;
5858 }
5859
5860 /* M in Encrypted Key attribute */
5861 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
5862 &attr_key_len);
5863 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
5864 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
d7e7b712
JM
5865 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
5866 "Missing Encrypted Key attribute");
500ed7f0
JM
5867 return NULL;
5868 }
5869
5870 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
5871 bnctx = BN_CTX_new();
5872 if (!bnctx)
5873 goto fail;
5874 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
5875 &group);
5876 if (!Qi)
5877 goto fail;
5878
5879 /* X' = M - Qi */
5880 X = EC_POINT_new(group);
5881 M = EC_POINT_new(group);
5882 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
5883 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
5884 if (!X || !M || !Mx || !My ||
5885 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
5886 EC_POINT_is_at_infinity(group, M) ||
5887 !EC_POINT_is_on_curve(group, M, bnctx) ||
5888 EC_POINT_invert(group, Qi, bnctx) != 1 ||
5889 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
5890 EC_POINT_is_at_infinity(group, X) ||
d7e7b712
JM
5891 !EC_POINT_is_on_curve(group, X, bnctx)) {
5892 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
5893 "Invalid Encrypted Key value");
500ed7f0 5894 goto fail;
d7e7b712 5895 }
500ed7f0
JM
5896
5897 pkex = os_zalloc(sizeof(*pkex));
5898 if (!pkex)
5899 goto fail;
219d4c9f 5900 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
5901 pkex->own_bi = bi;
5902 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
5903 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
5904 if (identifier) {
5905 pkex->identifier = os_strdup(identifier);
5906 if (!pkex->identifier)
5907 goto fail;
5908 }
5909 pkex->code = os_strdup(code);
5910 if (!pkex->code)
5911 goto fail;
5912
5913 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
5914
5915 X_ec = EC_KEY_new();
5916 if (!X_ec ||
5917 EC_KEY_set_group(X_ec, group) != 1 ||
5918 EC_KEY_set_public_key(X_ec, X) != 1)
5919 goto fail;
5920 pkex->x = EVP_PKEY_new();
5921 if (!pkex->x ||
5922 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
5923 goto fail;
5924
5925 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
5926 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
5927 if (!Qr)
5928 goto fail;
5929
5930 /* Generate a random ephemeral keypair y/Y */
5931 pkex->y = dpp_gen_keypair(curve);
5932 if (!pkex->y)
5933 goto fail;
5934
5935 /* N = Y + Qr */
5936 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
5937 if (!Y_ec)
5938 goto fail;
5939 Y_point = EC_KEY_get0_public_key(Y_ec);
5940 if (!Y_point)
5941 goto fail;
5942 N = EC_POINT_new(group);
5943 Nx = BN_new();
5944 Ny = BN_new();
5945 if (!N || !Nx || !Ny ||
5946 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
5947 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
5948 goto fail;
5949
a5c3b41b
JM
5950 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, identifier,
5951 Nx, Ny);
5952 if (!pkex->exchange_resp)
500ed7f0
JM
5953 goto fail;
5954
500ed7f0
JM
5955 pkex->exchange_done = 1;
5956
5957out:
500ed7f0
JM
5958 BN_CTX_free(bnctx);
5959 EC_POINT_free(Qi);
5960 EC_POINT_free(Qr);
5961 BN_free(Mx);
5962 BN_free(My);
5963 BN_free(Nx);
5964 BN_free(Ny);
5965 EC_POINT_free(M);
5966 EC_POINT_free(N);
5967 EC_POINT_free(X);
5968 EC_KEY_free(X_ec);
5969 EC_KEY_free(Y_ec);
5970 return pkex;
5971fail:
60b9dd86 5972 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
500ed7f0
JM
5973 dpp_pkex_free(pkex);
5974 pkex = NULL;
5975 goto out;
5976}
5977
5978
5979static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
5980 const u8 *Mx, size_t Mx_len,
5981 const u8 *Nx, size_t Nx_len,
5982 const char *code,
0e6709a4 5983 const u8 *Kx, size_t Kx_len,
500ed7f0
JM
5984 u8 *z, unsigned int hash_len)
5985{
5986 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5987 int res;
5988 u8 *info, *pos;
5989 size_t info_len;
5990
0e6709a4 5991 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
500ed7f0
JM
5992 */
5993
0e6709a4 5994 /* HKDF-Extract(<>, IKM=K.x) */
500ed7f0 5995 os_memset(salt, 0, hash_len);
0e6709a4 5996 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
500ed7f0
JM
5997 return -1;
5998 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
5999 prk, hash_len);
6000 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
6001 info = os_malloc(info_len);
6002 if (!info)
6003 return -1;
6004 pos = info;
6005 os_memcpy(pos, mac_init, ETH_ALEN);
6006 pos += ETH_ALEN;
6007 os_memcpy(pos, mac_resp, ETH_ALEN);
6008 pos += ETH_ALEN;
6009 os_memcpy(pos, Mx, Mx_len);
6010 pos += Mx_len;
6011 os_memcpy(pos, Nx, Nx_len);
6012 pos += Nx_len;
6013 os_memcpy(pos, code, os_strlen(code));
6014
6015 /* HKDF-Expand(PRK, info, L) */
6016 if (hash_len == 32)
6017 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
6018 z, hash_len);
6019 else if (hash_len == 48)
6020 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
6021 z, hash_len);
6022 else if (hash_len == 64)
6023 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
6024 z, hash_len);
6025 else
6026 res = -1;
6027 os_free(info);
6028 os_memset(prk, 0, hash_len);
6029 if (res < 0)
6030 return -1;
6031
6032 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
6033 z, hash_len);
6034 return 0;
6035}
6036
6037
b0626c2a
JM
6038static struct wpabuf *
6039dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
6040 const struct wpabuf *A_pub, const u8 *u)
6041{
6042 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6043 struct wpabuf *msg = NULL;
6044 size_t clear_len, attr_len;
6045 struct wpabuf *clear = NULL;
6046 u8 *wrapped;
6047 u8 octet;
6048 const u8 *addr[2];
6049 size_t len[2];
6050
6051 /* {A, u, [bootstrapping info]}z */
6052 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
6053 clear = wpabuf_alloc(clear_len);
6054 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6055#ifdef CONFIG_TESTING_OPTIONS
6056 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
6057 attr_len += 4;
6058#endif /* CONFIG_TESTING_OPTIONS */
6059 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
6060 if (!clear || !msg)
6061 goto fail;
6062
61f9f27f
JM
6063#ifdef CONFIG_TESTING_OPTIONS
6064 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
6065 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
6066 goto skip_bootstrap_key;
6067 }
6068#endif /* CONFIG_TESTING_OPTIONS */
6069
b0626c2a
JM
6070 /* A in Bootstrap Key attribute */
6071 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6072 wpabuf_put_le16(clear, wpabuf_len(A_pub));
6073 wpabuf_put_buf(clear, A_pub);
6074
61f9f27f
JM
6075#ifdef CONFIG_TESTING_OPTIONS
6076skip_bootstrap_key:
6077 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
6078 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
6079 goto skip_i_auth_tag;
6080 }
6081#endif /* CONFIG_TESTING_OPTIONS */
6082
b0626c2a
JM
6083 /* u in I-Auth tag attribute */
6084 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
6085 wpabuf_put_le16(clear, curve->hash_len);
6086 wpabuf_put_data(clear, u, curve->hash_len);
6087
61f9f27f
JM
6088#ifdef CONFIG_TESTING_OPTIONS
6089skip_i_auth_tag:
6090 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
6091 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
6092 goto skip_wrapped_data;
6093 }
6094#endif /* CONFIG_TESTING_OPTIONS */
6095
b0626c2a
JM
6096 addr[0] = wpabuf_head_u8(msg) + 2;
6097 len[0] = DPP_HDR_LEN;
6098 octet = 0;
6099 addr[1] = &octet;
6100 len[1] = sizeof(octet);
6101 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6102 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6103
6104 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6105 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6106 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6107
6108 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6109 if (aes_siv_encrypt(pkex->z, curve->hash_len,
6110 wpabuf_head(clear), wpabuf_len(clear),
6111 2, addr, len, wrapped) < 0)
6112 goto fail;
6113 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6114 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6115
6116#ifdef CONFIG_TESTING_OPTIONS
6117 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
6118 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
6119 wpabuf_put_le16(msg, DPP_ATTR_TESTING);
6120 wpabuf_put_le16(msg, 0);
6121 }
61f9f27f 6122skip_wrapped_data:
b0626c2a
JM
6123#endif /* CONFIG_TESTING_OPTIONS */
6124
6125out:
6126 wpabuf_free(clear);
6127 return msg;
6128
6129fail:
6130 wpabuf_free(msg);
6131 msg = NULL;
6132 goto out;
6133}
6134
6135
500ed7f0
JM
6136struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
6137 const u8 *buf, size_t buflen)
6138{
6139 const u8 *attr_status, *attr_id, *attr_key;
6140 u16 attr_status_len, attr_id_len, attr_key_len;
6141 const EC_GROUP *group;
6142 BN_CTX *bnctx = NULL;
500ed7f0
JM
6143 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6144 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6145 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
6146 BIGNUM *Nx = NULL, *Ny = NULL;
6147 EVP_PKEY_CTX *ctx = NULL;
6148 EC_KEY *Y_ec = NULL;
0e6709a4
JM
6149 size_t Jx_len, Kx_len;
6150 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
6151 const u8 *addr[4];
6152 size_t len[4];
6153 u8 u[DPP_MAX_HASH_LEN];
6254045a 6154 int res;
500ed7f0
JM
6155
6156 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
6157 &attr_status_len);
6158 if (!attr_status || attr_status_len != 1) {
d7e7b712 6159 dpp_pkex_fail(pkex, "No DPP Status attribute");
500ed7f0
JM
6160 return NULL;
6161 }
6162 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
6163 if (attr_status[0] != DPP_STATUS_OK) {
d7e7b712 6164 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
500ed7f0
JM
6165 return NULL;
6166 }
6167
6168 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
6169 &attr_id_len);
6170 if (!attr_id && pkex->identifier) {
6171 wpa_printf(MSG_DEBUG,
6172 "DPP: No PKEX code identifier received, but expected one");
6173 return NULL;
6174 }
6175 if (attr_id && pkex->identifier &&
6176 (os_strlen(pkex->identifier) != attr_id_len ||
6177 os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) {
d7e7b712 6178 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
500ed7f0
JM
6179 return NULL;
6180 }
6181
6182 /* N in Encrypted Key attribute */
6183 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
6184 &attr_key_len);
6185 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
d7e7b712 6186 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
500ed7f0
JM
6187 return NULL;
6188 }
6189
6190 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
6191 bnctx = BN_CTX_new();
6192 if (!bnctx)
6193 goto fail;
6194 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
6195 pkex->identifier, bnctx, &group);
6196 if (!Qr)
6197 goto fail;
6198
6199 /* Y' = N - Qr */
6200 Y = EC_POINT_new(group);
6201 N = EC_POINT_new(group);
6202 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
6203 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
6204 if (!Y || !N || !Nx || !Ny ||
6205 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
6206 EC_POINT_is_at_infinity(group, N) ||
6207 !EC_POINT_is_on_curve(group, N, bnctx) ||
6208 EC_POINT_invert(group, Qr, bnctx) != 1 ||
6209 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
6210 EC_POINT_is_at_infinity(group, Y) ||
d7e7b712
JM
6211 !EC_POINT_is_on_curve(group, Y, bnctx)) {
6212 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
500ed7f0 6213 goto fail;
d7e7b712 6214 }
500ed7f0
JM
6215
6216 pkex->exchange_done = 1;
6217
6218 /* ECDH: J = a * Y’ */
6219 Y_ec = EC_KEY_new();
6220 if (!Y_ec ||
6221 EC_KEY_set_group(Y_ec, group) != 1 ||
6222 EC_KEY_set_public_key(Y_ec, Y) != 1)
6223 goto fail;
6224 pkex->y = EVP_PKEY_new();
6225 if (!pkex->y ||
6226 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
6227 goto fail;
6228 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
6229 if (!ctx ||
6230 EVP_PKEY_derive_init(ctx) != 1 ||
6231 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
6232 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
6233 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
6234 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
6235 wpa_printf(MSG_ERROR,
6236 "DPP: Failed to derive ECDH shared secret: %s",
6237 ERR_error_string(ERR_get_error(), NULL));
6238 goto fail;
6239 }
6240
6241 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
6242 Jx, Jx_len);
6243
6244 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
6245 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
6246 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
6247 X_pub = dpp_get_pubkey_point(pkex->x, 0);
6248 if (!A_pub || !Y_pub || !X_pub)
6249 goto fail;
6250 addr[0] = pkex->own_mac;
6251 len[0] = ETH_ALEN;
6252 addr[1] = wpabuf_head(A_pub);
6253 len[1] = wpabuf_len(A_pub) / 2;
6254 addr[2] = wpabuf_head(Y_pub);
6255 len[2] = wpabuf_len(Y_pub) / 2;
6256 addr[3] = wpabuf_head(X_pub);
6257 len[3] = wpabuf_len(X_pub) / 2;
6258 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
6259 goto fail;
6260 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
6261
0e6709a4 6262 /* K = x * Y’ */
500ed7f0
JM
6263 EVP_PKEY_CTX_free(ctx);
6264 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
6265 if (!ctx ||
6266 EVP_PKEY_derive_init(ctx) != 1 ||
6267 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
0e6709a4
JM
6268 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
6269 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
6270 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
500ed7f0
JM
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
0e6709a4
JM
6277 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6278 Kx, Kx_len);
500ed7f0 6279
0e6709a4 6280 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
500ed7f0 6281 */
6254045a
JM
6282 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
6283 pkex->Mx, curve->prime_len,
6284 attr_key /* N.x */, attr_key_len / 2,
6285 pkex->code, Kx, Kx_len,
6286 pkex->z, curve->hash_len);
6287 os_memset(Kx, 0, Kx_len);
6288 if (res < 0)
500ed7f0
JM
6289 goto fail;
6290
b0626c2a
JM
6291 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
6292 if (!msg)
500ed7f0 6293 goto fail;
60239f60 6294
500ed7f0 6295out:
500ed7f0
JM
6296 wpabuf_free(A_pub);
6297 wpabuf_free(X_pub);
6298 wpabuf_free(Y_pub);
6299 EC_POINT_free(Qr);
6300 EC_POINT_free(Y);
6301 EC_POINT_free(N);
6302 BN_free(Nx);
6303 BN_free(Ny);
6304 EC_KEY_free(Y_ec);
6305 EVP_PKEY_CTX_free(ctx);
6306 BN_CTX_free(bnctx);
6307 return msg;
6308fail:
60b9dd86 6309 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
500ed7f0
JM
6310 goto out;
6311}
6312
6313
b3e4cc5c
JM
6314static struct wpabuf *
6315dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
6316 const struct wpabuf *B_pub, const u8 *v)
6317{
6318 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6319 struct wpabuf *msg = NULL;
6320 const u8 *addr[2];
6321 size_t len[2];
6322 u8 octet;
6323 u8 *wrapped;
6324 struct wpabuf *clear = NULL;
6325 size_t clear_len, attr_len;
6326
6327 /* {B, v [bootstrapping info]}z */
6328 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
6329 clear = wpabuf_alloc(clear_len);
6330 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6331#ifdef CONFIG_TESTING_OPTIONS
6332 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
6333 attr_len += 4;
6334#endif /* CONFIG_TESTING_OPTIONS */
6335 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
6336 if (!clear || !msg)
6337 goto fail;
6338
61f9f27f
JM
6339#ifdef CONFIG_TESTING_OPTIONS
6340 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
6341 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
6342 goto skip_bootstrap_key;
6343 }
6344#endif /* CONFIG_TESTING_OPTIONS */
6345
6346 /* B in Bootstrap Key attribute */
b3e4cc5c
JM
6347 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6348 wpabuf_put_le16(clear, wpabuf_len(B_pub));
6349 wpabuf_put_buf(clear, B_pub);
6350
61f9f27f
JM
6351#ifdef CONFIG_TESTING_OPTIONS
6352skip_bootstrap_key:
6353 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
6354 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
6355 goto skip_r_auth_tag;
6356 }
6357#endif /* CONFIG_TESTING_OPTIONS */
6358
b3e4cc5c
JM
6359 /* v in R-Auth tag attribute */
6360 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
6361 wpabuf_put_le16(clear, curve->hash_len);
6362 wpabuf_put_data(clear, v, curve->hash_len);
6363
61f9f27f
JM
6364#ifdef CONFIG_TESTING_OPTIONS
6365skip_r_auth_tag:
6366 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
6367 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
6368 goto skip_wrapped_data;
6369 }
6370#endif /* CONFIG_TESTING_OPTIONS */
6371
b3e4cc5c
JM
6372 addr[0] = wpabuf_head_u8(msg) + 2;
6373 len[0] = DPP_HDR_LEN;
6374 octet = 1;
6375 addr[1] = &octet;
6376 len[1] = sizeof(octet);
6377 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6378 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6379
6380 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6381 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6382 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6383
6384 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6385 if (aes_siv_encrypt(pkex->z, curve->hash_len,
6386 wpabuf_head(clear), wpabuf_len(clear),
6387 2, addr, len, wrapped) < 0)
6388 goto fail;
6389 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6390 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6391
6392#ifdef CONFIG_TESTING_OPTIONS
6393 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
6394 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
6395 wpabuf_put_le16(msg, DPP_ATTR_TESTING);
6396 wpabuf_put_le16(msg, 0);
6397 }
61f9f27f 6398skip_wrapped_data:
b3e4cc5c
JM
6399#endif /* CONFIG_TESTING_OPTIONS */
6400
6401out:
6402 wpabuf_free(clear);
6403 return msg;
6404
6405fail:
6406 wpabuf_free(msg);
6407 msg = NULL;
6408 goto out;
6409}
6410
6411
500ed7f0 6412struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
4be5bc98 6413 const u8 *hdr,
500ed7f0
JM
6414 const u8 *buf, size_t buflen)
6415{
6416 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6417 EVP_PKEY_CTX *ctx;
0e6709a4
JM
6418 size_t Jx_len, Kx_len, Lx_len;
6419 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
6420 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
6421 const u8 *wrapped_data, *b_key, *peer_u;
6422 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
6423 const u8 *addr[4];
6424 size_t len[4];
6425 u8 octet;
6426 u8 *unwrapped = NULL;
6427 size_t unwrapped_len = 0;
6428 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6429 struct wpabuf *B_pub = NULL;
6430 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
6254045a 6431 int res;
500ed7f0 6432
0e6709a4 6433 /* K = y * X' */
500ed7f0
JM
6434 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
6435 if (!ctx ||
6436 EVP_PKEY_derive_init(ctx) != 1 ||
6437 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
0e6709a4
JM
6438 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
6439 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
6440 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
500ed7f0
JM
6441 wpa_printf(MSG_ERROR,
6442 "DPP: Failed to derive ECDH shared secret: %s",
6443 ERR_error_string(ERR_get_error(), NULL));
6444 goto fail;
6445 }
6446
0e6709a4
JM
6447 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6448 Kx, Kx_len);
500ed7f0 6449
0e6709a4 6450 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
500ed7f0 6451 */
6254045a
JM
6452 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
6453 pkex->Mx, curve->prime_len,
6454 pkex->Nx, curve->prime_len, pkex->code,
6455 Kx, Kx_len, pkex->z, curve->hash_len);
6456 os_memset(Kx, 0, Kx_len);
6457 if (res < 0)
500ed7f0
JM
6458 goto fail;
6459
6460 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
6461 &wrapped_data_len);
6462 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
6463 dpp_pkex_fail(pkex,
6464 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
6465 goto fail;
6466 }
6467
6468 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6469 wrapped_data, wrapped_data_len);
6470 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6471 unwrapped = os_malloc(unwrapped_len);
6472 if (!unwrapped)
6473 goto fail;
6474
4be5bc98
JM
6475 addr[0] = hdr;
6476 len[0] = DPP_HDR_LEN;
500ed7f0 6477 octet = 0;
4be5bc98
JM
6478 addr[1] = &octet;
6479 len[1] = sizeof(octet);
6480 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6481 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
6482
6483 if (aes_siv_decrypt(pkex->z, curve->hash_len,
6484 wrapped_data, wrapped_data_len,
4be5bc98 6485 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
6486 dpp_pkex_fail(pkex,
6487 "AES-SIV decryption failed - possible PKEX code mismatch");
500ed7f0
JM
6488 goto fail;
6489 }
6490 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6491 unwrapped, unwrapped_len);
6492
6493 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 6494 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
6495 goto fail;
6496 }
6497
6498 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
6499 &b_key_len);
6500 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 6501 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
6502 goto fail;
6503 }
6504 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
6505 b_key_len);
d7e7b712
JM
6506 if (!pkex->peer_bootstrap_key) {
6507 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 6508 goto fail;
d7e7b712 6509 }
500ed7f0
JM
6510 dpp_debug_print_key("DPP: Peer bootstrap public key",
6511 pkex->peer_bootstrap_key);
6512
6513 /* ECDH: J' = y * A' */
6514 EVP_PKEY_CTX_free(ctx);
6515 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
6516 if (!ctx ||
6517 EVP_PKEY_derive_init(ctx) != 1 ||
6518 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
6519 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
6520 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
6521 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
6522 wpa_printf(MSG_ERROR,
6523 "DPP: Failed to derive ECDH shared secret: %s",
6524 ERR_error_string(ERR_get_error(), NULL));
6525 goto fail;
6526 }
6527
6528 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
6529 Jx, Jx_len);
6530
6531 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
6532 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
6533 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
6534 X_pub = dpp_get_pubkey_point(pkex->x, 0);
6535 if (!A_pub || !Y_pub || !X_pub)
6536 goto fail;
6537 addr[0] = pkex->peer_mac;
6538 len[0] = ETH_ALEN;
6539 addr[1] = wpabuf_head(A_pub);
6540 len[1] = wpabuf_len(A_pub) / 2;
6541 addr[2] = wpabuf_head(Y_pub);
6542 len[2] = wpabuf_len(Y_pub) / 2;
6543 addr[3] = wpabuf_head(X_pub);
6544 len[3] = wpabuf_len(X_pub) / 2;
6545 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
6546 goto fail;
6547
6548 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
6549 &peer_u_len);
6550 if (!peer_u || peer_u_len != curve->hash_len ||
6551 os_memcmp(peer_u, u, curve->hash_len) != 0) {
d7e7b712 6552 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
500ed7f0
JM
6553 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
6554 u, curve->hash_len);
6555 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
6556 goto fail;
6557 }
6558 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
6559
6560 /* ECDH: L = b * X' */
6561 EVP_PKEY_CTX_free(ctx);
6562 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
6563 if (!ctx ||
6564 EVP_PKEY_derive_init(ctx) != 1 ||
6565 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
6566 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
6567 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
6568 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
6569 wpa_printf(MSG_ERROR,
6570 "DPP: Failed to derive ECDH shared secret: %s",
6571 ERR_error_string(ERR_get_error(), NULL));
6572 goto fail;
6573 }
6574
6575 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
6576 Lx, Lx_len);
6577
6578 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
6579 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
6580 if (!B_pub)
6581 goto fail;
6582 addr[0] = pkex->own_mac;
6583 len[0] = ETH_ALEN;
6584 addr[1] = wpabuf_head(B_pub);
6585 len[1] = wpabuf_len(B_pub) / 2;
6586 addr[2] = wpabuf_head(X_pub);
6587 len[2] = wpabuf_len(X_pub) / 2;
6588 addr[3] = wpabuf_head(Y_pub);
6589 len[3] = wpabuf_len(Y_pub) / 2;
6590 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
6591 goto fail;
6592 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
6593
b3e4cc5c
JM
6594 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
6595 if (!msg)
500ed7f0 6596 goto fail;
60239f60 6597
500ed7f0
JM
6598out:
6599 EVP_PKEY_CTX_free(ctx);
6600 os_free(unwrapped);
6601 wpabuf_free(A_pub);
6602 wpabuf_free(B_pub);
6603 wpabuf_free(X_pub);
6604 wpabuf_free(Y_pub);
500ed7f0
JM
6605 return msg;
6606fail:
b3e4cc5c
JM
6607 wpa_printf(MSG_DEBUG,
6608 "DPP: PKEX Commit-Reveal Request processing failed");
500ed7f0
JM
6609 goto out;
6610}
6611
6612
4be5bc98 6613int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
500ed7f0
JM
6614 const u8 *buf, size_t buflen)
6615{
6616 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6617 const u8 *wrapped_data, *b_key, *peer_v;
6618 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
6619 const u8 *addr[4];
6620 size_t len[4];
6621 u8 octet;
6622 u8 *unwrapped = NULL;
6623 size_t unwrapped_len = 0;
6624 int ret = -1;
6625 u8 v[DPP_MAX_HASH_LEN];
6626 size_t Lx_len;
6627 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
6628 EVP_PKEY_CTX *ctx = NULL;
6629 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6630
6631 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
6632 &wrapped_data_len);
6633 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
6634 dpp_pkex_fail(pkex,
6635 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
6636 goto fail;
6637 }
6638
6639 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6640 wrapped_data, wrapped_data_len);
6641 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6642 unwrapped = os_malloc(unwrapped_len);
6643 if (!unwrapped)
6644 goto fail;
6645
4be5bc98
JM
6646 addr[0] = hdr;
6647 len[0] = DPP_HDR_LEN;
500ed7f0 6648 octet = 1;
4be5bc98
JM
6649 addr[1] = &octet;
6650 len[1] = sizeof(octet);
6651 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6652 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
6653
6654 if (aes_siv_decrypt(pkex->z, curve->hash_len,
6655 wrapped_data, wrapped_data_len,
4be5bc98 6656 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
6657 dpp_pkex_fail(pkex,
6658 "AES-SIV decryption failed - possible PKEX code mismatch");
500ed7f0
JM
6659 goto fail;
6660 }
6661 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6662 unwrapped, unwrapped_len);
6663
6664 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 6665 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
6666 goto fail;
6667 }
6668
6669 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
6670 &b_key_len);
6671 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 6672 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
6673 goto fail;
6674 }
6675 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
6676 b_key_len);
d7e7b712
JM
6677 if (!pkex->peer_bootstrap_key) {
6678 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 6679 goto fail;
d7e7b712 6680 }
500ed7f0
JM
6681 dpp_debug_print_key("DPP: Peer bootstrap public key",
6682 pkex->peer_bootstrap_key);
6683
6684 /* ECDH: L' = x * B' */
6685 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
6686 if (!ctx ||
6687 EVP_PKEY_derive_init(ctx) != 1 ||
6688 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
6689 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
6690 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
6691 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
6692 wpa_printf(MSG_ERROR,
6693 "DPP: Failed to derive ECDH shared secret: %s",
6694 ERR_error_string(ERR_get_error(), NULL));
6695 goto fail;
6696 }
6697
6698 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
6699 Lx, Lx_len);
6700
6701 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
6702 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
6703 X_pub = dpp_get_pubkey_point(pkex->x, 0);
6704 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
6705 if (!B_pub || !X_pub || !Y_pub)
6706 goto fail;
6707 addr[0] = pkex->peer_mac;
6708 len[0] = ETH_ALEN;
6709 addr[1] = wpabuf_head(B_pub);
6710 len[1] = wpabuf_len(B_pub) / 2;
6711 addr[2] = wpabuf_head(X_pub);
6712 len[2] = wpabuf_len(X_pub) / 2;
6713 addr[3] = wpabuf_head(Y_pub);
6714 len[3] = wpabuf_len(Y_pub) / 2;
6715 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
6716 goto fail;
6717
6718 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
6719 &peer_v_len);
6720 if (!peer_v || peer_v_len != curve->hash_len ||
6721 os_memcmp(peer_v, v, curve->hash_len) != 0) {
d7e7b712 6722 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
500ed7f0
JM
6723 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
6724 v, curve->hash_len);
6725 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
6726 goto fail;
6727 }
6728 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
6729
6730 ret = 0;
6731out:
6732 wpabuf_free(B_pub);
6733 wpabuf_free(X_pub);
6734 wpabuf_free(Y_pub);
6735 EVP_PKEY_CTX_free(ctx);
6736 os_free(unwrapped);
6737 return ret;
6738fail:
6739 goto out;
6740}
6741
6742
6743void dpp_pkex_free(struct dpp_pkex *pkex)
6744{
6745 if (!pkex)
6746 return;
6747
6748 os_free(pkex->identifier);
6749 os_free(pkex->code);
6750 EVP_PKEY_free(pkex->x);
6751 EVP_PKEY_free(pkex->y);
6752 EVP_PKEY_free(pkex->peer_bootstrap_key);
6753 wpabuf_free(pkex->exchange_req);
6754 wpabuf_free(pkex->exchange_resp);
6755 os_free(pkex);
6756}