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