blob: bcb694b5ab0074257a0bf7f0bf780320e11b96d5 [file] [log] [blame]
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001/*
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"
10#include <openssl/opensslv.h>
11#include <openssl/err.h>
Roshan Pius3a1667e2018-07-03 15:17:14 -070012#include <openssl/asn1.h>
13#include <openssl/asn1t.h>
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070014
15#include "utils/common.h"
16#include "utils/base64.h"
17#include "utils/json.h"
18#include "common/ieee802_11_common.h"
19#include "common/ieee802_11_defs.h"
20#include "common/wpa_ctrl.h"
21#include "crypto/crypto.h"
22#include "crypto/random.h"
23#include "crypto/aes.h"
24#include "crypto/aes_siv.h"
25#include "crypto/sha384.h"
26#include "crypto/sha512.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070027#include "drivers/driver.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070028#include "dpp.h"
29
30
Roshan Pius3a1667e2018-07-03 15:17:14 -070031#ifdef CONFIG_TESTING_OPTIONS
32enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
33u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
34u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
35u8 dpp_pkex_ephemeral_key_override[600];
36size_t dpp_pkex_ephemeral_key_override_len = 0;
37u8 dpp_protocol_key_override[600];
38size_t dpp_protocol_key_override_len = 0;
39u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
40size_t dpp_nonce_override_len = 0;
41
42static int dpp_test_gen_invalid_key(struct wpabuf *msg,
43 const struct dpp_curve_params *curve);
44#endif /* CONFIG_TESTING_OPTIONS */
45
46#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
47 (defined(LIBRESSL_VERSION_NUMBER) && \
48 LIBRESSL_VERSION_NUMBER < 0x20700000L)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070049/* Compatibility wrappers for older versions. */
50
51static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
52{
53 sig->r = r;
54 sig->s = s;
55 return 1;
56}
57
58
59static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
60 const BIGNUM **ps)
61{
62 if (pr)
63 *pr = sig->r;
64 if (ps)
65 *ps = sig->s;
66}
67
68#endif
69
70
71static const struct dpp_curve_params dpp_curves[] = {
72 /* The mandatory to support and the default NIST P-256 curve needs to
73 * be the first entry on this list. */
74 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
75 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
76 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
77 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
78 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
79 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
80 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
81};
82
83
84/* Role-specific elements for PKEX */
85
86/* NIST P-256 */
87static const u8 pkex_init_x_p256[32] = {
88 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
89 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
90 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
91 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
92 };
93static const u8 pkex_init_y_p256[32] = {
94 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
95 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
96 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
97 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
98 };
99static const u8 pkex_resp_x_p256[32] = {
100 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
101 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
102 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
103 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
104};
105static const u8 pkex_resp_y_p256[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700106 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
107 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
108 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
109 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700110};
111
112/* NIST P-384 */
113static const u8 pkex_init_x_p384[48] = {
114 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
115 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
116 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
117 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
118 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
119 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
120};
121static const u8 pkex_init_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700122 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
123 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
124 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
125 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
126 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
127 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700128};
129static const u8 pkex_resp_x_p384[48] = {
130 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
131 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
132 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
133 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
134 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
135 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
136};
137static const u8 pkex_resp_y_p384[48] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700138 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
139 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
140 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
141 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
142 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
143 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700144};
145
146/* NIST P-521 */
147static const u8 pkex_init_x_p521[66] = {
148 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
149 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
150 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
151 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
152 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
153 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
154 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
155 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
156 0x97, 0x76
157};
158static const u8 pkex_init_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700159 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
160 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
161 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
162 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
163 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
164 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
165 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
166 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
167 0x03, 0xa8
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700168};
169static const u8 pkex_resp_x_p521[66] = {
170 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
171 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
172 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
173 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
174 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
175 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
176 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
177 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
178 0x84, 0xb4
179};
180static const u8 pkex_resp_y_p521[66] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700181 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
182 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
183 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
184 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
185 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
186 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
187 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
188 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
189 0xce, 0xe1
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700190};
191
192/* Brainpool P-256r1 */
193static const u8 pkex_init_x_bp_p256r1[32] = {
194 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
195 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
196 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
197 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
198};
199static const u8 pkex_init_y_bp_p256r1[32] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700200 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
201 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
202 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
203 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700204};
205static const u8 pkex_resp_x_bp_p256r1[32] = {
206 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
207 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
208 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
209 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
210};
211static const u8 pkex_resp_y_bp_p256r1[32] = {
212 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
213 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
214 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
215 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
216};
217
218/* Brainpool P-384r1 */
219static const u8 pkex_init_x_bp_p384r1[48] = {
220 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
221 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
222 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
223 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
224 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
225 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
226};
227static const u8 pkex_init_y_bp_p384r1[48] = {
228 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
229 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
230 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
231 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
232 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
233 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
234};
235static const u8 pkex_resp_x_bp_p384r1[48] = {
236 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
237 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
238 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
239 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
240 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
241 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
242};
243static const u8 pkex_resp_y_bp_p384r1[48] = {
244 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
245 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
246 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
247 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
248 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
249 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
250};
251
252/* Brainpool P-512r1 */
253static const u8 pkex_init_x_bp_p512r1[64] = {
254 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
255 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
256 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
257 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
258 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
259 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
260 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
261 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
262};
263static const u8 pkex_init_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700264 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
265 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
266 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
267 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
268 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
269 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
270 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
271 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700272};
273static const u8 pkex_resp_x_bp_p512r1[64] = {
274 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
275 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
276 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
277 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
278 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
279 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
280 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
281 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
282};
283static const u8 pkex_resp_y_bp_p512r1[64] = {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700284 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
285 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
286 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
287 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
288 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
289 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
290 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
291 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700292};
293
294
Roshan Pius3a1667e2018-07-03 15:17:14 -0700295static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
296 const EC_POINT *point)
297{
298 BIGNUM *x, *y;
299 BN_CTX *ctx;
300 char *x_str = NULL, *y_str = NULL;
301
302 if (!wpa_debug_show_keys)
303 return;
304
305 ctx = BN_CTX_new();
306 x = BN_new();
307 y = BN_new();
308 if (!ctx || !x || !y ||
309 EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
310 goto fail;
311
312 x_str = BN_bn2hex(x);
313 y_str = BN_bn2hex(y);
314 if (!x_str || !y_str)
315 goto fail;
316
317 wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
318
319fail:
320 OPENSSL_free(x_str);
321 OPENSSL_free(y_str);
322 BN_free(x);
323 BN_free(y);
324 BN_CTX_free(ctx);
325}
326
327
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700328static int dpp_hash_vector(const struct dpp_curve_params *curve,
329 size_t num_elem, const u8 *addr[], const size_t *len,
330 u8 *mac)
331{
332 if (curve->hash_len == 32)
333 return sha256_vector(num_elem, addr, len, mac);
334 if (curve->hash_len == 48)
335 return sha384_vector(num_elem, addr, len, mac);
336 if (curve->hash_len == 64)
337 return sha512_vector(num_elem, addr, len, mac);
338 return -1;
339}
340
341
342static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
343 const char *label, u8 *out, size_t outlen)
344{
345 if (hash_len == 32)
346 return hmac_sha256_kdf(secret, secret_len, NULL,
347 (const u8 *) label, os_strlen(label),
348 out, outlen);
349 if (hash_len == 48)
350 return hmac_sha384_kdf(secret, secret_len, NULL,
351 (const u8 *) label, os_strlen(label),
352 out, outlen);
353 if (hash_len == 64)
354 return hmac_sha512_kdf(secret, secret_len, NULL,
355 (const u8 *) label, os_strlen(label),
356 out, outlen);
357 return -1;
358}
359
360
361static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
362 size_t num_elem, const u8 *addr[],
363 const size_t *len, u8 *mac)
364{
365 if (hash_len == 32)
366 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
367 mac);
368 if (hash_len == 48)
369 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
370 mac);
371 if (hash_len == 64)
372 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
373 mac);
374 return -1;
375}
376
377
378static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
379 const u8 *data, size_t data_len, u8 *mac)
380{
381 if (hash_len == 32)
382 return hmac_sha256(key, key_len, data, data_len, mac);
383 if (hash_len == 48)
384 return hmac_sha384(key, key_len, data, data_len, mac);
385 if (hash_len == 64)
386 return hmac_sha512(key, key_len, data, data_len, mac);
387 return -1;
388}
389
390
Roshan Pius3a1667e2018-07-03 15:17:14 -0700391static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
392{
393 int num_bytes, offset;
394
395 num_bytes = BN_num_bytes(bn);
396 if ((size_t) num_bytes > len)
397 return -1;
398 offset = len - num_bytes;
399 os_memset(pos, 0, offset);
400 BN_bn2bin(bn, pos + offset);
401 return 0;
402}
403
404
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700405static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
406{
407 int len, res;
408 EC_KEY *eckey;
409 struct wpabuf *buf;
410 unsigned char *pos;
411
412 eckey = EVP_PKEY_get1_EC_KEY(pkey);
413 if (!eckey)
414 return NULL;
415 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
416 len = i2o_ECPublicKey(eckey, NULL);
417 if (len <= 0) {
418 wpa_printf(MSG_ERROR,
419 "DDP: Failed to determine public key encoding length");
420 EC_KEY_free(eckey);
421 return NULL;
422 }
423
424 buf = wpabuf_alloc(len);
425 if (!buf) {
426 EC_KEY_free(eckey);
427 return NULL;
428 }
429
430 pos = wpabuf_put(buf, len);
431 res = i2o_ECPublicKey(eckey, &pos);
432 EC_KEY_free(eckey);
433 if (res != len) {
434 wpa_printf(MSG_ERROR,
435 "DDP: Failed to encode public key (res=%d/%d)",
436 res, len);
437 wpabuf_free(buf);
438 return NULL;
439 }
440
441 if (!prefix) {
442 /* Remove 0x04 prefix to match DPP definition */
443 pos = wpabuf_mhead(buf);
444 os_memmove(pos, pos + 1, len - 1);
445 buf->used--;
446 }
447
448 return buf;
449}
450
451
452static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
453 const u8 *buf_x, const u8 *buf_y,
454 size_t len)
455{
456 EC_KEY *eckey = NULL;
457 BN_CTX *ctx;
458 EC_POINT *point = NULL;
459 BIGNUM *x = NULL, *y = NULL;
460 EVP_PKEY *pkey = NULL;
461
462 ctx = BN_CTX_new();
463 if (!ctx) {
464 wpa_printf(MSG_ERROR, "DPP: Out of memory");
465 return NULL;
466 }
467
468 point = EC_POINT_new(group);
469 x = BN_bin2bn(buf_x, len, NULL);
470 y = BN_bin2bn(buf_y, len, NULL);
471 if (!point || !x || !y) {
472 wpa_printf(MSG_ERROR, "DPP: Out of memory");
473 goto fail;
474 }
475
476 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
477 wpa_printf(MSG_ERROR,
478 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
479 ERR_error_string(ERR_get_error(), NULL));
480 goto fail;
481 }
482
483 if (!EC_POINT_is_on_curve(group, point, ctx) ||
484 EC_POINT_is_at_infinity(group, point)) {
485 wpa_printf(MSG_ERROR, "DPP: Invalid point");
486 goto fail;
487 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700488 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700489
490 eckey = EC_KEY_new();
491 if (!eckey ||
492 EC_KEY_set_group(eckey, group) != 1 ||
493 EC_KEY_set_public_key(eckey, point) != 1) {
494 wpa_printf(MSG_ERROR,
495 "DPP: Failed to set EC_KEY: %s",
496 ERR_error_string(ERR_get_error(), NULL));
497 goto fail;
498 }
499 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
500
501 pkey = EVP_PKEY_new();
502 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
503 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
504 goto fail;
505 }
506
507out:
508 BN_free(x);
509 BN_free(y);
510 EC_KEY_free(eckey);
511 EC_POINT_free(point);
512 BN_CTX_free(ctx);
513 return pkey;
514fail:
515 EVP_PKEY_free(pkey);
516 pkey = NULL;
517 goto out;
518}
519
520
521static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
522 const u8 *buf, size_t len)
523{
524 EC_KEY *eckey;
525 const EC_GROUP *group;
526 EVP_PKEY *pkey = NULL;
527
528 if (len & 1)
529 return NULL;
530
531 eckey = EVP_PKEY_get1_EC_KEY(group_key);
532 if (!eckey) {
533 wpa_printf(MSG_ERROR,
534 "DPP: Could not get EC_KEY from group_key");
535 return NULL;
536 }
537
538 group = EC_KEY_get0_group(eckey);
539 if (group)
540 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
541 len / 2);
542 else
543 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
544
545 EC_KEY_free(eckey);
546 return pkey;
547}
548
549
Roshan Pius3a1667e2018-07-03 15:17:14 -0700550static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
551{
552 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
553}
554
555
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700556struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
557 size_t len)
558{
559 struct wpabuf *msg;
560
561 msg = wpabuf_alloc(8 + len);
562 if (!msg)
563 return NULL;
564 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
565 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
566 wpabuf_put_be24(msg, OUI_WFA);
567 wpabuf_put_u8(msg, DPP_OUI_TYPE);
568 wpabuf_put_u8(msg, 1); /* Crypto Suite */
569 wpabuf_put_u8(msg, type);
570 return msg;
571}
572
573
574const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
575{
576 u16 id, alen;
577 const u8 *pos = buf, *end = buf + len;
578
579 while (end - pos >= 4) {
580 id = WPA_GET_LE16(pos);
581 pos += 2;
582 alen = WPA_GET_LE16(pos);
583 pos += 2;
584 if (alen > end - pos)
585 return NULL;
586 if (id == req_id) {
587 *ret_len = alen;
588 return pos;
589 }
590 pos += alen;
591 }
592
593 return NULL;
594}
595
596
597int dpp_check_attrs(const u8 *buf, size_t len)
598{
599 const u8 *pos, *end;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700600 int wrapped_data = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700601
602 pos = buf;
603 end = buf + len;
604 while (end - pos >= 4) {
605 u16 id, alen;
606
607 id = WPA_GET_LE16(pos);
608 pos += 2;
609 alen = WPA_GET_LE16(pos);
610 pos += 2;
611 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
612 id, alen);
613 if (alen > end - pos) {
614 wpa_printf(MSG_DEBUG,
615 "DPP: Truncated message - not enough room for the attribute - dropped");
616 return -1;
617 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700618 if (wrapped_data) {
619 wpa_printf(MSG_DEBUG,
620 "DPP: An unexpected attribute included after the Wrapped Data attribute");
621 return -1;
622 }
623 if (id == DPP_ATTR_WRAPPED_DATA)
624 wrapped_data = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700625 pos += alen;
626 }
627
628 if (end != pos) {
629 wpa_printf(MSG_DEBUG,
630 "DPP: Unexpected octets (%d) after the last attribute",
631 (int) (end - pos));
632 return -1;
633 }
634
635 return 0;
636}
637
638
639void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
640{
641 if (!info)
642 return;
643 os_free(info->uri);
644 os_free(info->info);
645 EVP_PKEY_free(info->pubkey);
646 os_free(info);
647}
648
649
650const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
651{
652 switch (type) {
653 case DPP_BOOTSTRAP_QR_CODE:
654 return "QRCODE";
655 case DPP_BOOTSTRAP_PKEX:
656 return "PKEX";
657 }
658 return "??";
659}
660
661
662static int dpp_uri_valid_info(const char *info)
663{
664 while (*info) {
665 unsigned char val = *info++;
666
667 if (val < 0x20 || val > 0x7e || val == 0x3b)
668 return 0;
669 }
670
671 return 1;
672}
673
674
675static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
676{
677 bi->uri = os_strdup(uri);
678 return bi->uri ? 0 : -1;
679}
680
681
682int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
683 const char *chan_list)
684{
685 const char *pos = chan_list;
686 int opclass, channel, freq;
687
688 while (pos && *pos && *pos != ';') {
689 opclass = atoi(pos);
690 if (opclass <= 0)
691 goto fail;
692 pos = os_strchr(pos, '/');
693 if (!pos)
694 goto fail;
695 pos++;
696 channel = atoi(pos);
697 if (channel <= 0)
698 goto fail;
699 while (*pos >= '0' && *pos <= '9')
700 pos++;
701 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
702 wpa_printf(MSG_DEBUG,
703 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
704 opclass, channel, freq);
705 if (freq < 0) {
706 wpa_printf(MSG_DEBUG,
707 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
708 opclass, channel);
709 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
710 wpa_printf(MSG_DEBUG,
711 "DPP: Too many channels in URI channel-list - ignore list");
712 bi->num_freq = 0;
713 break;
714 } else {
715 bi->freq[bi->num_freq++] = freq;
716 }
717
718 if (*pos == ';' || *pos == '\0')
719 break;
720 if (*pos != ',')
721 goto fail;
722 pos++;
723 }
724
725 return 0;
726fail:
727 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
728 return -1;
729}
730
731
732int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
733{
734 if (!mac)
735 return 0;
736
737 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
738 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
739 return -1;
740 }
741
742 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
743
744 return 0;
745}
746
747
748int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
749{
750 const char *end;
751
752 if (!info)
753 return 0;
754
755 end = os_strchr(info, ';');
756 if (!end)
757 end = info + os_strlen(info);
758 bi->info = os_malloc(end - info + 1);
759 if (!bi->info)
760 return -1;
761 os_memcpy(bi->info, info, end - info);
762 bi->info[end - info] = '\0';
763 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
764 if (!dpp_uri_valid_info(bi->info)) {
765 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
766 return -1;
767 }
768
769 return 0;
770}
771
772
773static const struct dpp_curve_params *
774dpp_get_curve_oid(const ASN1_OBJECT *poid)
775{
776 ASN1_OBJECT *oid;
777 int i;
778
779 for (i = 0; dpp_curves[i].name; i++) {
780 oid = OBJ_txt2obj(dpp_curves[i].name, 0);
781 if (oid && OBJ_cmp(poid, oid) == 0)
782 return &dpp_curves[i];
783 }
784 return NULL;
785}
786
787
788static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
789{
790 int i, tmp;
791
792 if (!nid)
793 return NULL;
794 for (i = 0; dpp_curves[i].name; i++) {
795 tmp = OBJ_txt2nid(dpp_curves[i].name);
796 if (tmp == nid)
797 return &dpp_curves[i];
798 }
799 return NULL;
800}
801
802
803static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
804{
805 const char *end;
806 u8 *data;
807 size_t data_len;
808 EVP_PKEY *pkey;
809 const unsigned char *p;
810 int res;
811 X509_PUBKEY *pub = NULL;
812 ASN1_OBJECT *ppkalg;
813 const unsigned char *pk;
814 int ppklen;
815 X509_ALGOR *pa;
Hai Shalom39bc25d2019-02-06 16:32:13 -0800816#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
817 (defined(LIBRESSL_VERSION_NUMBER) && \
818 LIBRESSL_VERSION_NUMBER < 0x20800000L)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700819 ASN1_OBJECT *pa_oid;
820#else
821 const ASN1_OBJECT *pa_oid;
822#endif
823 const void *pval;
824 int ptype;
825 const ASN1_OBJECT *poid;
826 char buf[100];
827
828 end = os_strchr(info, ';');
829 if (!end)
830 return -1;
831
832 data = base64_decode((const unsigned char *) info, end - info,
833 &data_len);
834 if (!data) {
835 wpa_printf(MSG_DEBUG,
836 "DPP: Invalid base64 encoding on URI public-key");
837 return -1;
838 }
839 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
840 data, data_len);
841
842 if (sha256_vector(1, (const u8 **) &data, &data_len,
843 bi->pubkey_hash) < 0) {
844 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800845 os_free(data);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700846 return -1;
847 }
848 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
849 bi->pubkey_hash, SHA256_MAC_LEN);
850
851 /* DER encoded ASN.1 SubjectPublicKeyInfo
852 *
853 * SubjectPublicKeyInfo ::= SEQUENCE {
854 * algorithm AlgorithmIdentifier,
855 * subjectPublicKey BIT STRING }
856 *
857 * AlgorithmIdentifier ::= SEQUENCE {
858 * algorithm OBJECT IDENTIFIER,
859 * parameters ANY DEFINED BY algorithm OPTIONAL }
860 *
861 * subjectPublicKey = compressed format public key per ANSI X9.63
862 * algorithm = ecPublicKey (1.2.840.10045.2.1)
863 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
864 * prime256v1 (1.2.840.10045.3.1.7)
865 */
866
867 p = data;
868 pkey = d2i_PUBKEY(NULL, &p, data_len);
869 os_free(data);
870
871 if (!pkey) {
872 wpa_printf(MSG_DEBUG,
873 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
874 return -1;
875 }
876
877 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
878 wpa_printf(MSG_DEBUG,
879 "DPP: SubjectPublicKeyInfo does not describe an EC key");
880 EVP_PKEY_free(pkey);
881 return -1;
882 }
883
884 res = X509_PUBKEY_set(&pub, pkey);
885 if (res != 1) {
886 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
887 goto fail;
888 }
889
890 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
891 if (res != 1) {
892 wpa_printf(MSG_DEBUG,
893 "DPP: Could not extract SubjectPublicKeyInfo parameters");
894 goto fail;
895 }
896 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
897 if (res < 0 || (size_t) res >= sizeof(buf)) {
898 wpa_printf(MSG_DEBUG,
899 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
900 goto fail;
901 }
902 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
903 if (os_strcmp(buf, "id-ecPublicKey") != 0) {
904 wpa_printf(MSG_DEBUG,
905 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
906 goto fail;
907 }
908
909 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
910 if (ptype != V_ASN1_OBJECT) {
911 wpa_printf(MSG_DEBUG,
912 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
913 goto fail;
914 }
915 poid = pval;
916 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
917 if (res < 0 || (size_t) res >= sizeof(buf)) {
918 wpa_printf(MSG_DEBUG,
919 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
920 goto fail;
921 }
922 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
923 bi->curve = dpp_get_curve_oid(poid);
924 if (!bi->curve) {
925 wpa_printf(MSG_DEBUG,
926 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
927 buf);
928 goto fail;
929 }
930
931 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
932
933 X509_PUBKEY_free(pub);
934 bi->pubkey = pkey;
935 return 0;
936fail:
937 X509_PUBKEY_free(pub);
938 EVP_PKEY_free(pkey);
939 return -1;
940}
941
942
943static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
944{
945 const char *pos = uri;
946 const char *end;
947 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
948 struct dpp_bootstrap_info *bi;
949
950 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
951
952 if (os_strncmp(pos, "DPP:", 4) != 0) {
953 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
954 return NULL;
955 }
956 pos += 4;
957
958 for (;;) {
959 end = os_strchr(pos, ';');
960 if (!end)
961 break;
962
963 if (end == pos) {
964 /* Handle terminating ";;" and ignore unexpected ";"
965 * for parsing robustness. */
966 pos++;
967 continue;
968 }
969
970 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
971 chan_list = pos + 2;
972 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
973 mac = pos + 2;
974 else if (pos[0] == 'I' && pos[1] == ':' && !info)
975 info = pos + 2;
976 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
977 pk = pos + 2;
978 else
979 wpa_hexdump_ascii(MSG_DEBUG,
980 "DPP: Ignore unrecognized URI parameter",
981 pos, end - pos);
982 pos = end + 1;
983 }
984
985 if (!pk) {
986 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
987 return NULL;
988 }
989
990 bi = os_zalloc(sizeof(*bi));
991 if (!bi)
992 return NULL;
993
994 if (dpp_clone_uri(bi, uri) < 0 ||
995 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
996 dpp_parse_uri_mac(bi, mac) < 0 ||
997 dpp_parse_uri_info(bi, info) < 0 ||
998 dpp_parse_uri_pk(bi, pk) < 0) {
999 dpp_bootstrap_info_free(bi);
1000 bi = NULL;
1001 }
1002
1003 return bi;
1004}
1005
1006
1007struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
1008{
1009 struct dpp_bootstrap_info *bi;
1010
1011 bi = dpp_parse_uri(uri);
1012 if (bi)
1013 bi->type = DPP_BOOTSTRAP_QR_CODE;
1014 return bi;
1015}
1016
1017
1018static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
1019{
1020 EC_KEY *eckey;
1021 BIO *out;
1022 size_t rlen;
1023 char *txt;
1024 int res;
1025 unsigned char *der = NULL;
1026 int der_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001027 const EC_GROUP *group;
1028 const EC_POINT *point;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001029
1030 out = BIO_new(BIO_s_mem());
1031 if (!out)
1032 return;
1033
1034 EVP_PKEY_print_private(out, key, 0, NULL);
1035 rlen = BIO_ctrl_pending(out);
1036 txt = os_malloc(rlen + 1);
1037 if (txt) {
1038 res = BIO_read(out, txt, rlen);
1039 if (res > 0) {
1040 txt[res] = '\0';
1041 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
1042 }
1043 os_free(txt);
1044 }
1045 BIO_free(out);
1046
1047 eckey = EVP_PKEY_get1_EC_KEY(key);
1048 if (!eckey)
1049 return;
1050
Roshan Pius3a1667e2018-07-03 15:17:14 -07001051 group = EC_KEY_get0_group(eckey);
1052 point = EC_KEY_get0_public_key(eckey);
1053 if (group && point)
1054 dpp_debug_print_point(title, group, point);
1055
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001056 der_len = i2d_ECPrivateKey(eckey, &der);
1057 if (der_len > 0)
1058 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1059 OPENSSL_free(der);
1060 if (der_len <= 0) {
1061 der = NULL;
1062 der_len = i2d_EC_PUBKEY(eckey, &der);
1063 if (der_len > 0)
1064 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1065 OPENSSL_free(der);
1066 }
1067
1068 EC_KEY_free(eckey);
1069}
1070
1071
1072static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1073{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001074 EVP_PKEY_CTX *kctx = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001075 EC_KEY *ec_params;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001076 EVP_PKEY *params = NULL, *key = NULL;
1077 int nid;
1078
1079 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1080
1081 nid = OBJ_txt2nid(curve->name);
1082 if (nid == NID_undef) {
1083 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1084 return NULL;
1085 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001086
1087 ec_params = EC_KEY_new_by_curve_name(nid);
1088 if (!ec_params) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001089 wpa_printf(MSG_ERROR,
1090 "DPP: Failed to generate EC_KEY parameters");
1091 goto fail;
1092 }
1093 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
1094 params = EVP_PKEY_new();
1095 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
1096 wpa_printf(MSG_ERROR,
1097 "DPP: Failed to generate EVP_PKEY parameters");
1098 goto fail;
1099 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001100
1101 kctx = EVP_PKEY_CTX_new(params, NULL);
1102 if (!kctx ||
1103 EVP_PKEY_keygen_init(kctx) != 1 ||
1104 EVP_PKEY_keygen(kctx, &key) != 1) {
1105 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
1106 goto fail;
1107 }
1108
1109 if (wpa_debug_show_keys)
1110 dpp_debug_print_key("Own generated key", key);
1111
1112 EVP_PKEY_free(params);
1113 EVP_PKEY_CTX_free(kctx);
1114 return key;
1115fail:
1116 EVP_PKEY_CTX_free(kctx);
1117 EVP_PKEY_free(params);
1118 return NULL;
1119}
1120
1121
1122static const struct dpp_curve_params *
1123dpp_get_curve_name(const char *name)
1124{
1125 int i;
1126
1127 for (i = 0; dpp_curves[i].name; i++) {
1128 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
1129 (dpp_curves[i].jwk_crv &&
1130 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
1131 return &dpp_curves[i];
1132 }
1133 return NULL;
1134}
1135
1136
1137static const struct dpp_curve_params *
1138dpp_get_curve_jwk_crv(const char *name)
1139{
1140 int i;
1141
1142 for (i = 0; dpp_curves[i].name; i++) {
1143 if (dpp_curves[i].jwk_crv &&
1144 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
1145 return &dpp_curves[i];
1146 }
1147 return NULL;
1148}
1149
1150
1151static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1152 const u8 *privkey, size_t privkey_len)
1153{
1154 EVP_PKEY *pkey;
1155 EC_KEY *eckey;
1156 const EC_GROUP *group;
1157 int nid;
1158
1159 pkey = EVP_PKEY_new();
1160 if (!pkey)
1161 return NULL;
1162 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1163 if (!eckey) {
1164 wpa_printf(MSG_INFO,
1165 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1166 ERR_error_string(ERR_get_error(), NULL));
1167 EVP_PKEY_free(pkey);
1168 return NULL;
1169 }
1170 group = EC_KEY_get0_group(eckey);
1171 if (!group) {
1172 EC_KEY_free(eckey);
1173 EVP_PKEY_free(pkey);
1174 return NULL;
1175 }
1176 nid = EC_GROUP_get_curve_name(group);
1177 *curve = dpp_get_curve_nid(nid);
1178 if (!*curve) {
1179 wpa_printf(MSG_INFO,
1180 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1181 nid);
1182 EC_KEY_free(eckey);
1183 EVP_PKEY_free(pkey);
1184 return NULL;
1185 }
1186
1187 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1188 EC_KEY_free(eckey);
1189 EVP_PKEY_free(pkey);
1190 return NULL;
1191 }
1192 return pkey;
1193}
1194
1195
Roshan Pius3a1667e2018-07-03 15:17:14 -07001196typedef struct {
1197 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1198 * as an OID identifying the curve */
1199 X509_ALGOR *alg;
1200 /* Compressed format public key per ANSI X9.63 */
1201 ASN1_BIT_STRING *pub_key;
1202} DPP_BOOTSTRAPPING_KEY;
1203
1204ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
1205 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
1206 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
1207} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
1208
1209IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1210
1211
1212static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001213{
1214 unsigned char *der = NULL;
1215 int der_len;
1216 EC_KEY *eckey;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001217 struct wpabuf *ret = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001218 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001219 const EC_GROUP *group;
1220 const EC_POINT *point;
1221 BN_CTX *ctx;
1222 DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1223 int nid;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001224
Roshan Pius3a1667e2018-07-03 15:17:14 -07001225 ctx = BN_CTX_new();
1226 eckey = EVP_PKEY_get1_EC_KEY(key);
1227 if (!ctx || !eckey)
1228 goto fail;
1229
1230 group = EC_KEY_get0_group(eckey);
1231 point = EC_KEY_get0_public_key(eckey);
1232 if (!group || !point)
1233 goto fail;
1234 dpp_debug_print_point("DPP: bootstrap public key", group, point);
1235 nid = EC_GROUP_get_curve_name(group);
1236
1237 bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1238 if (!bootstrap ||
1239 X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1240 V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1241 goto fail;
1242
1243 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1244 NULL, 0, ctx);
1245 if (len == 0)
1246 goto fail;
1247
1248 der = OPENSSL_malloc(len);
1249 if (!der)
1250 goto fail;
1251 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1252 der, len, ctx);
1253
1254 OPENSSL_free(bootstrap->pub_key->data);
1255 bootstrap->pub_key->data = der;
1256 der = NULL;
1257 bootstrap->pub_key->length = len;
1258 /* No unused bits */
1259 bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
1260 bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
1261
1262 der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001263 if (der_len <= 0) {
1264 wpa_printf(MSG_ERROR,
1265 "DDP: Failed to build DER encoded public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001266 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001267 }
1268
Roshan Pius3a1667e2018-07-03 15:17:14 -07001269 ret = wpabuf_alloc_copy(der, der_len);
1270fail:
1271 DPP_BOOTSTRAPPING_KEY_free(bootstrap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001272 OPENSSL_free(der);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001273 EC_KEY_free(eckey);
1274 BN_CTX_free(ctx);
1275 return ret;
1276}
1277
1278
1279int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
1280{
1281 struct wpabuf *der;
1282 int res;
1283 const u8 *addr[1];
1284 size_t len[1];
1285
1286 der = dpp_bootstrap_key_der(bi->pubkey);
1287 if (!der)
1288 return -1;
1289 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1290 der);
1291
1292 addr[0] = wpabuf_head(der);
1293 len[0] = wpabuf_len(der);
1294 res = sha256_vector(1, addr, len, bi->pubkey_hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001295 if (res < 0)
1296 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001297 else
1298 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1299 SHA256_MAC_LEN);
1300 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001301 return res;
1302}
1303
1304
1305char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1306 const u8 *privkey, size_t privkey_len)
1307{
1308 unsigned char *base64 = NULL;
1309 char *pos, *end;
1310 size_t len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001311 struct wpabuf *der = NULL;
1312 const u8 *addr[1];
1313 int res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001314
1315 if (!curve) {
1316 bi->curve = &dpp_curves[0];
1317 } else {
1318 bi->curve = dpp_get_curve_name(curve);
1319 if (!bi->curve) {
1320 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1321 curve);
1322 return NULL;
1323 }
1324 }
1325 if (privkey)
1326 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1327 else
1328 bi->pubkey = dpp_gen_keypair(bi->curve);
1329 if (!bi->pubkey)
1330 goto fail;
1331 bi->own = 1;
1332
Roshan Pius3a1667e2018-07-03 15:17:14 -07001333 der = dpp_bootstrap_key_der(bi->pubkey);
1334 if (!der)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001335 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001336 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1337 der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001338
Roshan Pius3a1667e2018-07-03 15:17:14 -07001339 addr[0] = wpabuf_head(der);
1340 len = wpabuf_len(der);
1341 res = sha256_vector(1, addr, &len, bi->pubkey_hash);
1342 if (res < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001343 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1344 goto fail;
1345 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001346 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1347 SHA256_MAC_LEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001348
Roshan Pius3a1667e2018-07-03 15:17:14 -07001349 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1350 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001351 der = NULL;
1352 if (!base64)
1353 goto fail;
1354 pos = (char *) base64;
1355 end = pos + len;
1356 for (;;) {
1357 pos = os_strchr(pos, '\n');
1358 if (!pos)
1359 break;
1360 os_memmove(pos, pos + 1, end - pos);
1361 }
1362 return (char *) base64;
1363fail:
1364 os_free(base64);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001365 wpabuf_free(der);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001366 return NULL;
1367}
1368
1369
1370static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1371 unsigned int hash_len)
1372{
1373 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1374 const char *info = "first intermediate key";
1375 int res;
1376
1377 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1378
1379 /* HKDF-Extract(<>, M.x) */
1380 os_memset(salt, 0, hash_len);
1381 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
1382 return -1;
1383 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1384 prk, hash_len);
1385
1386 /* HKDF-Expand(PRK, info, L) */
1387 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
1388 os_memset(prk, 0, hash_len);
1389 if (res < 0)
1390 return -1;
1391
1392 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1393 k1, hash_len);
1394 return 0;
1395}
1396
1397
1398static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1399 unsigned int hash_len)
1400{
1401 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1402 const char *info = "second intermediate key";
1403 int res;
1404
1405 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1406
1407 /* HKDF-Extract(<>, N.x) */
1408 os_memset(salt, 0, hash_len);
1409 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
1410 if (res < 0)
1411 return -1;
1412 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1413 prk, hash_len);
1414
1415 /* HKDF-Expand(PRK, info, L) */
1416 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
1417 os_memset(prk, 0, hash_len);
1418 if (res < 0)
1419 return -1;
1420
1421 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1422 k2, hash_len);
1423 return 0;
1424}
1425
1426
1427static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1428 unsigned int hash_len)
1429{
1430 size_t nonce_len;
1431 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1432 const char *info_ke = "DPP Key";
1433 u8 prk[DPP_MAX_HASH_LEN];
1434 int res;
1435 const u8 *addr[3];
1436 size_t len[3];
1437 size_t num_elem = 0;
1438
Roshan Pius3a1667e2018-07-03 15:17:14 -07001439 if (!auth->Mx_len || !auth->Nx_len) {
1440 wpa_printf(MSG_DEBUG,
1441 "DPP: Mx/Nx not available - cannot derive ke");
1442 return -1;
1443 }
1444
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001445 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1446
1447 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1448 nonce_len = auth->curve->nonce_len;
1449 os_memcpy(nonces, auth->i_nonce, nonce_len);
1450 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1451 addr[num_elem] = auth->Mx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001452 len[num_elem] = auth->Mx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001453 num_elem++;
1454 addr[num_elem] = auth->Nx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001455 len[num_elem] = auth->Nx_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001456 num_elem++;
1457 if (auth->peer_bi && auth->own_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001458 if (!auth->Lx_len) {
1459 wpa_printf(MSG_DEBUG,
1460 "DPP: Lx not available - cannot derive ke");
1461 return -1;
1462 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001463 addr[num_elem] = auth->Lx;
1464 len[num_elem] = auth->secret_len;
1465 num_elem++;
1466 }
1467 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1468 num_elem, addr, len, prk);
1469 if (res < 0)
1470 return -1;
1471 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1472 prk, hash_len);
1473
1474 /* HKDF-Expand(PRK, info, L) */
1475 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
1476 os_memset(prk, 0, hash_len);
1477 if (res < 0)
1478 return -1;
1479
1480 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1481 ke, hash_len);
1482 return 0;
1483}
1484
1485
Roshan Pius3a1667e2018-07-03 15:17:14 -07001486static void dpp_build_attr_status(struct wpabuf *msg,
1487 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001488{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001489 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
1490 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1491 wpabuf_put_le16(msg, 1);
1492 wpabuf_put_u8(msg, status);
1493}
1494
1495
1496static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1497 const u8 *hash)
1498{
1499 if (hash) {
1500 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1501 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1502 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1503 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1504 }
1505}
1506
1507
1508static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1509 const u8 *hash)
1510{
1511 if (hash) {
1512 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1513 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1514 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1515 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1516 }
1517}
1518
1519
1520static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1521 const struct wpabuf *pi,
1522 size_t nonce_len,
1523 const u8 *r_pubkey_hash,
1524 const u8 *i_pubkey_hash,
1525 unsigned int neg_freq)
1526{
1527 struct wpabuf *msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001528 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1529 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1530 u8 *pos;
1531 const u8 *addr[2];
1532 size_t len[2], siv_len, attr_len;
1533 u8 *attr_start, *attr_end;
1534
Roshan Pius3a1667e2018-07-03 15:17:14 -07001535 /* Build DPP Authentication Request frame attributes */
1536 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
1537 4 + sizeof(wrapped_data);
1538 if (neg_freq > 0)
1539 attr_len += 4 + 2;
1540#ifdef CONFIG_TESTING_OPTIONS
1541 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1542 attr_len += 5;
1543#endif /* CONFIG_TESTING_OPTIONS */
1544 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1545 if (!msg)
1546 return NULL;
1547
1548 attr_start = wpabuf_put(msg, 0);
1549
1550 /* Responder Bootstrapping Key Hash */
1551 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1552
1553 /* Initiator Bootstrapping Key Hash */
1554 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1555
1556 /* Initiator Protocol Key */
1557 if (pi) {
1558 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1559 wpabuf_put_le16(msg, wpabuf_len(pi));
1560 wpabuf_put_buf(msg, pi);
1561 }
1562
1563 /* Channel */
1564 if (neg_freq > 0) {
1565 u8 op_class, channel;
1566
1567 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1568 &channel) ==
1569 NUM_HOSTAPD_MODES) {
1570 wpa_printf(MSG_INFO,
1571 "DPP: Unsupported negotiation frequency request: %d",
1572 neg_freq);
1573 wpabuf_free(msg);
1574 return NULL;
1575 }
1576 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1577 wpabuf_put_le16(msg, 2);
1578 wpabuf_put_u8(msg, op_class);
1579 wpabuf_put_u8(msg, channel);
1580 }
1581
1582#ifdef CONFIG_TESTING_OPTIONS
1583 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1584 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1585 goto skip_wrapped_data;
1586 }
1587#endif /* CONFIG_TESTING_OPTIONS */
1588
1589 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1590 pos = clear;
1591
1592#ifdef CONFIG_TESTING_OPTIONS
1593 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1594 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1595 goto skip_i_nonce;
1596 }
1597 if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1598 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1599 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1600 pos += 2;
1601 WPA_PUT_LE16(pos, nonce_len - 1);
1602 pos += 2;
1603 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1604 pos += nonce_len - 1;
1605 goto skip_i_nonce;
1606 }
1607#endif /* CONFIG_TESTING_OPTIONS */
1608
1609 /* I-nonce */
1610 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1611 pos += 2;
1612 WPA_PUT_LE16(pos, nonce_len);
1613 pos += 2;
1614 os_memcpy(pos, auth->i_nonce, nonce_len);
1615 pos += nonce_len;
1616
1617#ifdef CONFIG_TESTING_OPTIONS
1618skip_i_nonce:
1619 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1620 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1621 goto skip_i_capab;
1622 }
1623#endif /* CONFIG_TESTING_OPTIONS */
1624
1625 /* I-capabilities */
1626 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1627 pos += 2;
1628 WPA_PUT_LE16(pos, 1);
1629 pos += 2;
1630 auth->i_capab = auth->allowed_roles;
1631 *pos++ = auth->i_capab;
1632#ifdef CONFIG_TESTING_OPTIONS
1633 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1634 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1635 pos[-1] = 0;
1636 }
1637skip_i_capab:
1638#endif /* CONFIG_TESTING_OPTIONS */
1639
1640 attr_end = wpabuf_put(msg, 0);
1641
1642 /* OUI, OUI type, Crypto Suite, DPP frame type */
1643 addr[0] = wpabuf_head_u8(msg) + 2;
1644 len[0] = 3 + 1 + 1 + 1;
1645 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1646
1647 /* Attributes before Wrapped Data */
1648 addr[1] = attr_start;
1649 len[1] = attr_end - attr_start;
1650 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1651
1652 siv_len = pos - clear;
1653 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1654 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1655 2, addr, len, wrapped_data) < 0) {
1656 wpabuf_free(msg);
1657 return NULL;
1658 }
1659 siv_len += AES_BLOCK_SIZE;
1660 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1661 wrapped_data, siv_len);
1662
1663 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1664 wpabuf_put_le16(msg, siv_len);
1665 wpabuf_put_data(msg, wrapped_data, siv_len);
1666
1667#ifdef CONFIG_TESTING_OPTIONS
1668 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1669 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1670 dpp_build_attr_status(msg, DPP_STATUS_OK);
1671 }
1672skip_wrapped_data:
1673#endif /* CONFIG_TESTING_OPTIONS */
1674
1675 wpa_hexdump_buf(MSG_DEBUG,
1676 "DPP: Authentication Request frame attributes", msg);
1677
1678 return msg;
1679}
1680
1681
1682static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1683 enum dpp_status_error status,
1684 const struct wpabuf *pr,
1685 size_t nonce_len,
1686 const u8 *r_pubkey_hash,
1687 const u8 *i_pubkey_hash,
1688 const u8 *r_nonce, const u8 *i_nonce,
1689 const u8 *wrapped_r_auth,
1690 size_t wrapped_r_auth_len,
1691 const u8 *siv_key)
1692{
1693 struct wpabuf *msg;
1694#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1695 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1696 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1697 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1698 const u8 *addr[2];
1699 size_t len[2], siv_len, attr_len;
1700 u8 *attr_start, *attr_end, *pos;
1701
1702 auth->waiting_auth_conf = 1;
1703 auth->auth_resp_tries = 0;
1704
1705 /* Build DPP Authentication Response frame attributes */
1706 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1707 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
1708#ifdef CONFIG_TESTING_OPTIONS
1709 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1710 attr_len += 5;
1711#endif /* CONFIG_TESTING_OPTIONS */
1712 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1713 if (!msg)
1714 return NULL;
1715
1716 attr_start = wpabuf_put(msg, 0);
1717
1718 /* DPP Status */
1719 if (status != 255)
1720 dpp_build_attr_status(msg, status);
1721
1722 /* Responder Bootstrapping Key Hash */
1723 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1724
1725 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1726 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1727
1728 /* Responder Protocol Key */
1729 if (pr) {
1730 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1731 wpabuf_put_le16(msg, wpabuf_len(pr));
1732 wpabuf_put_buf(msg, pr);
1733 }
1734
1735 attr_end = wpabuf_put(msg, 0);
1736
1737#ifdef CONFIG_TESTING_OPTIONS
1738 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
1739 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1740 goto skip_wrapped_data;
1741 }
1742#endif /* CONFIG_TESTING_OPTIONS */
1743
1744 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1745 pos = clear;
1746
1747 if (r_nonce) {
1748 /* R-nonce */
1749 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1750 pos += 2;
1751 WPA_PUT_LE16(pos, nonce_len);
1752 pos += 2;
1753 os_memcpy(pos, r_nonce, nonce_len);
1754 pos += nonce_len;
1755 }
1756
1757 if (i_nonce) {
1758 /* I-nonce */
1759 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1760 pos += 2;
1761 WPA_PUT_LE16(pos, nonce_len);
1762 pos += 2;
1763 os_memcpy(pos, i_nonce, nonce_len);
1764#ifdef CONFIG_TESTING_OPTIONS
1765 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
1766 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
1767 pos[nonce_len / 2] ^= 0x01;
1768 }
1769#endif /* CONFIG_TESTING_OPTIONS */
1770 pos += nonce_len;
1771 }
1772
1773#ifdef CONFIG_TESTING_OPTIONS
1774 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
1775 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
1776 goto skip_r_capab;
1777 }
1778#endif /* CONFIG_TESTING_OPTIONS */
1779
1780 /* R-capabilities */
1781 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1782 pos += 2;
1783 WPA_PUT_LE16(pos, 1);
1784 pos += 2;
1785 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1786 DPP_CAPAB_ENROLLEE;
1787 *pos++ = auth->r_capab;
1788#ifdef CONFIG_TESTING_OPTIONS
1789 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
1790 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
1791 pos[-1] = 0;
1792 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
1793 wpa_printf(MSG_INFO,
1794 "DPP: TESTING - incompatible R-capabilities");
1795 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
1796 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
1797 pos[-1] = 0;
1798 else
1799 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
1800 DPP_CAPAB_CONFIGURATOR;
1801 }
1802skip_r_capab:
1803#endif /* CONFIG_TESTING_OPTIONS */
1804
1805 if (wrapped_r_auth) {
1806 /* {R-auth}ke */
1807 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1808 pos += 2;
1809 WPA_PUT_LE16(pos, wrapped_r_auth_len);
1810 pos += 2;
1811 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1812 pos += wrapped_r_auth_len;
1813 }
1814
1815 /* OUI, OUI type, Crypto Suite, DPP frame type */
1816 addr[0] = wpabuf_head_u8(msg) + 2;
1817 len[0] = 3 + 1 + 1 + 1;
1818 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1819
1820 /* Attributes before Wrapped Data */
1821 addr[1] = attr_start;
1822 len[1] = attr_end - attr_start;
1823 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1824
1825 siv_len = pos - clear;
1826 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1827 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
1828 2, addr, len, wrapped_data) < 0) {
1829 wpabuf_free(msg);
1830 return NULL;
1831 }
1832 siv_len += AES_BLOCK_SIZE;
1833 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1834 wrapped_data, siv_len);
1835
1836 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1837 wpabuf_put_le16(msg, siv_len);
1838 wpabuf_put_data(msg, wrapped_data, siv_len);
1839
1840#ifdef CONFIG_TESTING_OPTIONS
1841 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
1842 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1843 dpp_build_attr_status(msg, DPP_STATUS_OK);
1844 }
1845skip_wrapped_data:
1846#endif /* CONFIG_TESTING_OPTIONS */
1847
1848 wpa_hexdump_buf(MSG_DEBUG,
1849 "DPP: Authentication Response frame attributes", msg);
1850 return msg;
1851}
1852
1853
1854static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
1855 u16 num_modes, unsigned int freq)
1856{
1857 u16 m;
1858 int c, flag;
1859
1860 if (!own_modes || !num_modes)
1861 return 1;
1862
1863 for (m = 0; m < num_modes; m++) {
1864 for (c = 0; c < own_modes[m].num_channels; c++) {
1865 if ((unsigned int) own_modes[m].channels[c].freq !=
1866 freq)
1867 continue;
1868 flag = own_modes[m].channels[c].flag;
1869 if (!(flag & (HOSTAPD_CHAN_DISABLED |
1870 HOSTAPD_CHAN_NO_IR |
1871 HOSTAPD_CHAN_RADAR)))
1872 return 1;
1873 }
1874 }
1875
1876 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
1877 return 0;
1878}
1879
1880
1881static int freq_included(const unsigned int freqs[], unsigned int num,
1882 unsigned int freq)
1883{
1884 while (num > 0) {
1885 if (freqs[--num] == freq)
1886 return 1;
1887 }
1888 return 0;
1889}
1890
1891
1892static void freq_to_start(unsigned int freqs[], unsigned int num,
1893 unsigned int freq)
1894{
1895 unsigned int i;
1896
1897 for (i = 0; i < num; i++) {
1898 if (freqs[i] == freq)
1899 break;
1900 }
1901 if (i == 0 || i >= num)
1902 return;
1903 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
1904 freqs[0] = freq;
1905}
1906
1907
1908static int dpp_channel_intersect(struct dpp_authentication *auth,
1909 struct hostapd_hw_modes *own_modes,
1910 u16 num_modes)
1911{
1912 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
1913 unsigned int i, freq;
1914
1915 for (i = 0; i < peer_bi->num_freq; i++) {
1916 freq = peer_bi->freq[i];
1917 if (freq_included(auth->freq, auth->num_freq, freq))
1918 continue;
1919 if (dpp_channel_ok_init(own_modes, num_modes, freq))
1920 auth->freq[auth->num_freq++] = freq;
1921 }
1922 if (!auth->num_freq) {
1923 wpa_printf(MSG_INFO,
1924 "DPP: No available channels for initiating DPP Authentication");
1925 return -1;
1926 }
1927 auth->curr_freq = auth->freq[0];
1928 return 0;
1929}
1930
1931
1932static int dpp_channel_local_list(struct dpp_authentication *auth,
1933 struct hostapd_hw_modes *own_modes,
1934 u16 num_modes)
1935{
1936 u16 m;
1937 int c, flag;
1938 unsigned int freq;
1939
1940 auth->num_freq = 0;
1941
1942 if (!own_modes || !num_modes) {
1943 auth->freq[0] = 2412;
1944 auth->freq[1] = 2437;
1945 auth->freq[2] = 2462;
1946 auth->num_freq = 3;
1947 return 0;
1948 }
1949
1950 for (m = 0; m < num_modes; m++) {
1951 for (c = 0; c < own_modes[m].num_channels; c++) {
1952 freq = own_modes[m].channels[c].freq;
1953 flag = own_modes[m].channels[c].flag;
1954 if (flag & (HOSTAPD_CHAN_DISABLED |
1955 HOSTAPD_CHAN_NO_IR |
1956 HOSTAPD_CHAN_RADAR))
1957 continue;
1958 if (freq_included(auth->freq, auth->num_freq, freq))
1959 continue;
1960 auth->freq[auth->num_freq++] = freq;
1961 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
1962 m = num_modes;
1963 break;
1964 }
1965 }
1966 }
1967
1968 return auth->num_freq == 0 ? -1 : 0;
1969}
1970
1971
1972static int dpp_prepare_channel_list(struct dpp_authentication *auth,
1973 struct hostapd_hw_modes *own_modes,
1974 u16 num_modes)
1975{
1976 int res;
1977 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
1978 unsigned int i;
1979
1980 if (auth->peer_bi->num_freq > 0)
1981 res = dpp_channel_intersect(auth, own_modes, num_modes);
1982 else
1983 res = dpp_channel_local_list(auth, own_modes, num_modes);
1984 if (res < 0)
1985 return res;
1986
1987 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1988 * likely channels first. */
1989 freq_to_start(auth->freq, auth->num_freq, 2462);
1990 freq_to_start(auth->freq, auth->num_freq, 2412);
1991 freq_to_start(auth->freq, auth->num_freq, 2437);
1992
1993 auth->freq_idx = 0;
1994 auth->curr_freq = auth->freq[0];
1995
1996 pos = freqs;
1997 end = pos + sizeof(freqs);
1998 for (i = 0; i < auth->num_freq; i++) {
1999 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
2000 if (os_snprintf_error(end - pos, res))
2001 break;
2002 pos += res;
2003 }
2004 *pos = '\0';
2005 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
2006 freqs);
2007
2008 return 0;
2009}
2010
2011
2012static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
2013{
2014 struct dpp_bootstrap_info *bi;
2015 char *pk = NULL;
2016 size_t len;
2017
2018 if (auth->own_bi)
2019 return 0; /* already generated */
2020
2021 bi = os_zalloc(sizeof(*bi));
2022 if (!bi)
2023 return -1;
2024 bi->type = DPP_BOOTSTRAP_QR_CODE;
2025 pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
2026 if (!pk)
2027 goto fail;
2028
2029 len = 4; /* "DPP:" */
2030 len += 4 + os_strlen(pk);
2031 bi->uri = os_malloc(len + 1);
2032 if (!bi->uri)
2033 goto fail;
2034 os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
2035 wpa_printf(MSG_DEBUG,
2036 "DPP: Auto-generated own bootstrapping key info: URI %s",
2037 bi->uri);
2038
2039 auth->tmp_own_bi = auth->own_bi = bi;
2040
2041 os_free(pk);
2042
2043 return 0;
2044fail:
2045 os_free(pk);
2046 dpp_bootstrap_info_free(bi);
2047 return -1;
2048}
2049
2050
2051struct dpp_authentication * dpp_auth_init(void *msg_ctx,
2052 struct dpp_bootstrap_info *peer_bi,
2053 struct dpp_bootstrap_info *own_bi,
2054 u8 dpp_allowed_roles,
2055 unsigned int neg_freq,
2056 struct hostapd_hw_modes *own_modes,
2057 u16 num_modes)
2058{
2059 struct dpp_authentication *auth;
2060 size_t nonce_len;
2061 EVP_PKEY_CTX *ctx = NULL;
2062 size_t secret_len;
2063 struct wpabuf *pi = NULL;
2064 const u8 *r_pubkey_hash, *i_pubkey_hash;
2065#ifdef CONFIG_TESTING_OPTIONS
2066 u8 test_hash[SHA256_MAC_LEN];
2067#endif /* CONFIG_TESTING_OPTIONS */
2068
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002069 auth = os_zalloc(sizeof(*auth));
2070 if (!auth)
2071 return NULL;
2072 auth->msg_ctx = msg_ctx;
2073 auth->initiator = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002074 auth->waiting_auth_resp = 1;
2075 auth->allowed_roles = dpp_allowed_roles;
2076 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002077 auth->peer_bi = peer_bi;
2078 auth->own_bi = own_bi;
2079 auth->curve = peer_bi->curve;
2080
Roshan Pius3a1667e2018-07-03 15:17:14 -07002081 if (dpp_autogen_bootstrap_key(auth) < 0 ||
2082 dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
2083 goto fail;
2084
2085#ifdef CONFIG_TESTING_OPTIONS
2086 if (dpp_nonce_override_len > 0) {
2087 wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
2088 nonce_len = dpp_nonce_override_len;
2089 os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
2090 } else {
2091 nonce_len = auth->curve->nonce_len;
2092 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2093 wpa_printf(MSG_ERROR,
2094 "DPP: Failed to generate I-nonce");
2095 goto fail;
2096 }
2097 }
2098#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002099 nonce_len = auth->curve->nonce_len;
2100 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2101 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
2102 goto fail;
2103 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002104#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002105 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2106
Roshan Pius3a1667e2018-07-03 15:17:14 -07002107#ifdef CONFIG_TESTING_OPTIONS
2108 if (dpp_protocol_key_override_len) {
2109 const struct dpp_curve_params *tmp_curve;
2110
2111 wpa_printf(MSG_INFO,
2112 "DPP: TESTING - override protocol key");
2113 auth->own_protocol_key = dpp_set_keypair(
2114 &tmp_curve, dpp_protocol_key_override,
2115 dpp_protocol_key_override_len);
2116 } else {
2117 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2118 }
2119#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002120 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002121#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002122 if (!auth->own_protocol_key)
2123 goto fail;
2124
2125 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2126 if (!pi)
2127 goto fail;
2128
2129 /* ECDH: M = pI * BR */
2130 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2131 if (!ctx ||
2132 EVP_PKEY_derive_init(ctx) != 1 ||
2133 EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
2134 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2135 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2136 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
2137 wpa_printf(MSG_ERROR,
2138 "DPP: Failed to derive ECDH shared secret: %s",
2139 ERR_error_string(ERR_get_error(), NULL));
2140 goto fail;
2141 }
2142 auth->secret_len = secret_len;
2143 EVP_PKEY_CTX_free(ctx);
2144 ctx = NULL;
2145
2146 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2147 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002148 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002149
2150 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2151 auth->curve->hash_len) < 0)
2152 goto fail;
2153
Roshan Pius3a1667e2018-07-03 15:17:14 -07002154 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2155 i_pubkey_hash = auth->own_bi->pubkey_hash;
2156
2157#ifdef CONFIG_TESTING_OPTIONS
2158 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2159 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2160 r_pubkey_hash = NULL;
2161 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2162 wpa_printf(MSG_INFO,
2163 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2164 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2165 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2166 r_pubkey_hash = test_hash;
2167 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2168 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2169 i_pubkey_hash = NULL;
2170 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2171 wpa_printf(MSG_INFO,
2172 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2173 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2174 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2175 i_pubkey_hash = test_hash;
2176 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2177 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2178 wpabuf_free(pi);
2179 pi = NULL;
2180 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2181 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2182 wpabuf_free(pi);
2183 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2184 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2185 goto fail;
2186 }
2187#endif /* CONFIG_TESTING_OPTIONS */
2188
2189 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
2190 i_pubkey_hash, neg_freq);
2191 if (!auth->req_msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002192 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002193
Roshan Pius3a1667e2018-07-03 15:17:14 -07002194out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002195 wpabuf_free(pi);
2196 EVP_PKEY_CTX_free(ctx);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002197 return auth;
2198fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002199 dpp_auth_deinit(auth);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002200 auth = NULL;
2201 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002202}
2203
2204
2205struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2206 const char *json)
2207{
2208 size_t nonce_len;
2209 size_t json_len, clear_len;
2210 struct wpabuf *clear = NULL, *msg = NULL;
2211 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002212 size_t attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002213
2214 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2215
2216 nonce_len = auth->curve->nonce_len;
2217 if (random_get_bytes(auth->e_nonce, nonce_len)) {
2218 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2219 goto fail;
2220 }
2221 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2222 json_len = os_strlen(json);
2223 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
2224
2225 /* { E-nonce, configAttrib }ke */
2226 clear_len = 4 + nonce_len + 4 + json_len;
2227 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002228 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2229#ifdef CONFIG_TESTING_OPTIONS
2230 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
2231 attr_len += 5;
2232#endif /* CONFIG_TESTING_OPTIONS */
2233 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002234 if (!clear || !msg)
2235 goto fail;
2236
Roshan Pius3a1667e2018-07-03 15:17:14 -07002237#ifdef CONFIG_TESTING_OPTIONS
2238 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2239 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2240 goto skip_e_nonce;
2241 }
2242 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
2243 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
2244 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2245 wpabuf_put_le16(clear, nonce_len - 1);
2246 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
2247 goto skip_e_nonce;
2248 }
2249 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2250 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2251 goto skip_wrapped_data;
2252 }
2253#endif /* CONFIG_TESTING_OPTIONS */
2254
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002255 /* E-nonce */
2256 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2257 wpabuf_put_le16(clear, nonce_len);
2258 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2259
Roshan Pius3a1667e2018-07-03 15:17:14 -07002260#ifdef CONFIG_TESTING_OPTIONS
2261skip_e_nonce:
2262 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2263 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2264 goto skip_conf_attr_obj;
2265 }
2266#endif /* CONFIG_TESTING_OPTIONS */
2267
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002268 /* configAttrib */
2269 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2270 wpabuf_put_le16(clear, json_len);
2271 wpabuf_put_data(clear, json, json_len);
2272
Roshan Pius3a1667e2018-07-03 15:17:14 -07002273#ifdef CONFIG_TESTING_OPTIONS
2274skip_conf_attr_obj:
2275#endif /* CONFIG_TESTING_OPTIONS */
2276
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002277 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2278 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2279 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2280
2281 /* No AES-SIV AD */
2282 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2283 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2284 wpabuf_head(clear), wpabuf_len(clear),
2285 0, NULL, NULL, wrapped) < 0)
2286 goto fail;
2287 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2288 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2289
Roshan Pius3a1667e2018-07-03 15:17:14 -07002290#ifdef CONFIG_TESTING_OPTIONS
2291 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2292 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2293 dpp_build_attr_status(msg, DPP_STATUS_OK);
2294 }
2295skip_wrapped_data:
2296#endif /* CONFIG_TESTING_OPTIONS */
2297
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002298 wpa_hexdump_buf(MSG_DEBUG,
2299 "DPP: Configuration Request frame attributes", msg);
2300 wpabuf_free(clear);
2301 return msg;
2302
2303fail:
2304 wpabuf_free(clear);
2305 wpabuf_free(msg);
2306 return NULL;
2307}
2308
2309
2310static void dpp_auth_success(struct dpp_authentication *auth)
2311{
2312 wpa_printf(MSG_DEBUG,
2313 "DPP: Authentication success - clear temporary keys");
2314 os_memset(auth->Mx, 0, sizeof(auth->Mx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002315 auth->Mx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002316 os_memset(auth->Nx, 0, sizeof(auth->Nx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002317 auth->Nx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002318 os_memset(auth->Lx, 0, sizeof(auth->Lx));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002319 auth->Lx_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002320 os_memset(auth->k1, 0, sizeof(auth->k1));
2321 os_memset(auth->k2, 0, sizeof(auth->k2));
2322
2323 auth->auth_success = 1;
2324}
2325
2326
2327static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2328{
2329 struct wpabuf *pix, *prx, *bix, *brx;
2330 const u8 *addr[7];
2331 size_t len[7];
2332 size_t i, num_elem = 0;
2333 size_t nonce_len;
2334 u8 zero = 0;
2335 int res = -1;
2336
2337 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2338 nonce_len = auth->curve->nonce_len;
2339
2340 if (auth->initiator) {
2341 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2342 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2343 if (auth->own_bi)
2344 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2345 else
2346 bix = NULL;
2347 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2348 } else {
2349 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2350 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2351 if (auth->peer_bi)
2352 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2353 else
2354 bix = NULL;
2355 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2356 }
2357 if (!pix || !prx || !brx)
2358 goto fail;
2359
2360 addr[num_elem] = auth->i_nonce;
2361 len[num_elem] = nonce_len;
2362 num_elem++;
2363
2364 addr[num_elem] = auth->r_nonce;
2365 len[num_elem] = nonce_len;
2366 num_elem++;
2367
2368 addr[num_elem] = wpabuf_head(pix);
2369 len[num_elem] = wpabuf_len(pix) / 2;
2370 num_elem++;
2371
2372 addr[num_elem] = wpabuf_head(prx);
2373 len[num_elem] = wpabuf_len(prx) / 2;
2374 num_elem++;
2375
2376 if (bix) {
2377 addr[num_elem] = wpabuf_head(bix);
2378 len[num_elem] = wpabuf_len(bix) / 2;
2379 num_elem++;
2380 }
2381
2382 addr[num_elem] = wpabuf_head(brx);
2383 len[num_elem] = wpabuf_len(brx) / 2;
2384 num_elem++;
2385
2386 addr[num_elem] = &zero;
2387 len[num_elem] = 1;
2388 num_elem++;
2389
2390 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2391 for (i = 0; i < num_elem; i++)
2392 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2393 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
2394 if (res == 0)
2395 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2396 auth->curve->hash_len);
2397fail:
2398 wpabuf_free(pix);
2399 wpabuf_free(prx);
2400 wpabuf_free(bix);
2401 wpabuf_free(brx);
2402 return res;
2403}
2404
2405
2406static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2407{
2408 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2409 const u8 *addr[7];
2410 size_t len[7];
2411 size_t i, num_elem = 0;
2412 size_t nonce_len;
2413 u8 one = 1;
2414 int res = -1;
2415
2416 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2417 nonce_len = auth->curve->nonce_len;
2418
2419 if (auth->initiator) {
2420 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2421 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2422 if (auth->own_bi)
2423 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2424 else
2425 bix = NULL;
2426 if (!auth->peer_bi)
2427 goto fail;
2428 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2429 } else {
2430 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2431 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2432 if (auth->peer_bi)
2433 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2434 else
2435 bix = NULL;
2436 if (!auth->own_bi)
2437 goto fail;
2438 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2439 }
2440 if (!pix || !prx || !brx)
2441 goto fail;
2442
2443 addr[num_elem] = auth->r_nonce;
2444 len[num_elem] = nonce_len;
2445 num_elem++;
2446
2447 addr[num_elem] = auth->i_nonce;
2448 len[num_elem] = nonce_len;
2449 num_elem++;
2450
2451 addr[num_elem] = wpabuf_head(prx);
2452 len[num_elem] = wpabuf_len(prx) / 2;
2453 num_elem++;
2454
2455 addr[num_elem] = wpabuf_head(pix);
2456 len[num_elem] = wpabuf_len(pix) / 2;
2457 num_elem++;
2458
2459 addr[num_elem] = wpabuf_head(brx);
2460 len[num_elem] = wpabuf_len(brx) / 2;
2461 num_elem++;
2462
2463 if (bix) {
2464 addr[num_elem] = wpabuf_head(bix);
2465 len[num_elem] = wpabuf_len(bix) / 2;
2466 num_elem++;
2467 }
2468
2469 addr[num_elem] = &one;
2470 len[num_elem] = 1;
2471 num_elem++;
2472
2473 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2474 for (i = 0; i < num_elem; i++)
2475 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2476 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
2477 if (res == 0)
2478 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2479 auth->curve->hash_len);
2480fail:
2481 wpabuf_free(pix);
2482 wpabuf_free(prx);
2483 wpabuf_free(bix);
2484 wpabuf_free(brx);
2485 return res;
2486}
2487
2488
2489static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2490{
2491 const EC_GROUP *group;
2492 EC_POINT *l = NULL;
2493 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2494 const EC_POINT *BI_point;
2495 BN_CTX *bnctx;
2496 BIGNUM *lx, *sum, *q;
2497 const BIGNUM *bR_bn, *pR_bn;
2498 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002499
2500 /* L = ((bR + pR) modulo q) * BI */
2501
2502 bnctx = BN_CTX_new();
2503 sum = BN_new();
2504 q = BN_new();
2505 lx = BN_new();
2506 if (!bnctx || !sum || !q || !lx)
2507 goto fail;
2508 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2509 if (!BI)
2510 goto fail;
2511 BI_point = EC_KEY_get0_public_key(BI);
2512 group = EC_KEY_get0_group(BI);
2513 if (!group)
2514 goto fail;
2515
2516 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2517 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2518 if (!bR || !pR)
2519 goto fail;
2520 bR_bn = EC_KEY_get0_private_key(bR);
2521 pR_bn = EC_KEY_get0_private_key(pR);
2522 if (!bR_bn || !pR_bn)
2523 goto fail;
2524 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2525 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2526 goto fail;
2527 l = EC_POINT_new(group);
2528 if (!l ||
2529 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2530 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2531 bnctx) != 1) {
2532 wpa_printf(MSG_ERROR,
2533 "OpenSSL: failed: %s",
2534 ERR_error_string(ERR_get_error(), NULL));
2535 goto fail;
2536 }
2537
Roshan Pius3a1667e2018-07-03 15:17:14 -07002538 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002539 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002540 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002541 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002542 ret = 0;
2543fail:
2544 EC_POINT_clear_free(l);
2545 EC_KEY_free(BI);
2546 EC_KEY_free(bR);
2547 EC_KEY_free(pR);
2548 BN_clear_free(lx);
2549 BN_clear_free(sum);
2550 BN_free(q);
2551 BN_CTX_free(bnctx);
2552 return ret;
2553}
2554
2555
2556static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2557{
2558 const EC_GROUP *group;
2559 EC_POINT *l = NULL, *sum = NULL;
2560 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2561 const EC_POINT *BR_point, *PR_point;
2562 BN_CTX *bnctx;
2563 BIGNUM *lx;
2564 const BIGNUM *bI_bn;
2565 int ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002566
2567 /* L = bI * (BR + PR) */
2568
2569 bnctx = BN_CTX_new();
2570 lx = BN_new();
2571 if (!bnctx || !lx)
2572 goto fail;
2573 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2574 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
2575 if (!BR || !PR)
2576 goto fail;
2577 BR_point = EC_KEY_get0_public_key(BR);
2578 PR_point = EC_KEY_get0_public_key(PR);
2579
2580 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2581 if (!bI)
2582 goto fail;
2583 group = EC_KEY_get0_group(bI);
2584 bI_bn = EC_KEY_get0_private_key(bI);
2585 if (!group || !bI_bn)
2586 goto fail;
2587 sum = EC_POINT_new(group);
2588 l = EC_POINT_new(group);
2589 if (!sum || !l ||
2590 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
2591 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
2592 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2593 bnctx) != 1) {
2594 wpa_printf(MSG_ERROR,
2595 "OpenSSL: failed: %s",
2596 ERR_error_string(ERR_get_error(), NULL));
2597 goto fail;
2598 }
2599
Roshan Pius3a1667e2018-07-03 15:17:14 -07002600 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002601 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002602 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002603 auth->Lx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002604 ret = 0;
2605fail:
2606 EC_POINT_clear_free(l);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002607 EC_POINT_clear_free(sum);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002608 EC_KEY_free(bI);
2609 EC_KEY_free(BR);
2610 EC_KEY_free(PR);
2611 BN_clear_free(lx);
2612 BN_CTX_free(bnctx);
2613 return ret;
2614}
2615
2616
Roshan Pius3a1667e2018-07-03 15:17:14 -07002617static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002618{
2619 size_t nonce_len;
2620 EVP_PKEY_CTX *ctx = NULL;
2621 size_t secret_len;
2622 struct wpabuf *msg, *pr = NULL;
2623 u8 r_auth[4 + DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07002624 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002625 size_t wrapped_r_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002626 int ret = -1;
2627 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
2628 enum dpp_status_error status = DPP_STATUS_OK;
2629#ifdef CONFIG_TESTING_OPTIONS
2630 u8 test_hash[SHA256_MAC_LEN];
2631#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002632
2633 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
Roshan Pius3a1667e2018-07-03 15:17:14 -07002634 if (!auth->own_bi)
2635 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002636
Roshan Pius3a1667e2018-07-03 15:17:14 -07002637#ifdef CONFIG_TESTING_OPTIONS
2638 if (dpp_nonce_override_len > 0) {
2639 wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
2640 nonce_len = dpp_nonce_override_len;
2641 os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
2642 } else {
2643 nonce_len = auth->curve->nonce_len;
2644 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2645 wpa_printf(MSG_ERROR,
2646 "DPP: Failed to generate R-nonce");
2647 goto fail;
2648 }
2649 }
2650#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002651 nonce_len = auth->curve->nonce_len;
2652 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2653 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
2654 goto fail;
2655 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07002656#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002657 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
2658
Roshan Pius3a1667e2018-07-03 15:17:14 -07002659#ifdef CONFIG_TESTING_OPTIONS
2660 if (dpp_protocol_key_override_len) {
2661 const struct dpp_curve_params *tmp_curve;
2662
2663 wpa_printf(MSG_INFO,
2664 "DPP: TESTING - override protocol key");
2665 auth->own_protocol_key = dpp_set_keypair(
2666 &tmp_curve, dpp_protocol_key_override,
2667 dpp_protocol_key_override_len);
2668 } else {
2669 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2670 }
2671#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002672 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002673#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002674 if (!auth->own_protocol_key)
2675 goto fail;
2676
2677 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2678 if (!pr)
2679 goto fail;
2680
2681 /* ECDH: N = pR * PI */
2682 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2683 if (!ctx ||
2684 EVP_PKEY_derive_init(ctx) != 1 ||
2685 EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
2686 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2687 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2688 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
2689 wpa_printf(MSG_ERROR,
2690 "DPP: Failed to derive ECDH shared secret: %s",
2691 ERR_error_string(ERR_get_error(), NULL));
2692 goto fail;
2693 }
2694 EVP_PKEY_CTX_free(ctx);
2695 ctx = NULL;
2696
2697 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
2698 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002699 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002700
2701 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2702 auth->curve->hash_len) < 0)
2703 goto fail;
2704
2705 if (auth->own_bi && auth->peer_bi) {
2706 /* Mutual authentication */
2707 if (dpp_auth_derive_l_responder(auth) < 0)
2708 goto fail;
2709 }
2710
2711 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2712 goto fail;
2713
2714 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2715 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
2716 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002717 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
2718 goto fail;
2719#ifdef CONFIG_TESTING_OPTIONS
2720 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
2721 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
2722 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
2723 }
2724#endif /* CONFIG_TESTING_OPTIONS */
2725 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002726 r_auth, 4 + auth->curve->hash_len,
2727 0, NULL, NULL, wrapped_r_auth) < 0)
2728 goto fail;
2729 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
2730 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
2731 wrapped_r_auth, wrapped_r_auth_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002732 w_r_auth = wrapped_r_auth;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002733
Roshan Pius3a1667e2018-07-03 15:17:14 -07002734 r_pubkey_hash = auth->own_bi->pubkey_hash;
2735 if (auth->peer_bi)
2736 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2737 else
2738 i_pubkey_hash = NULL;
2739
2740 i_nonce = auth->i_nonce;
2741 r_nonce = auth->r_nonce;
2742
2743#ifdef CONFIG_TESTING_OPTIONS
2744 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2745 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2746 r_pubkey_hash = NULL;
2747 } else if (dpp_test ==
2748 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2749 wpa_printf(MSG_INFO,
2750 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2751 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2752 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2753 r_pubkey_hash = test_hash;
2754 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2755 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2756 i_pubkey_hash = NULL;
2757 } else if (dpp_test ==
2758 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2759 wpa_printf(MSG_INFO,
2760 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2761 if (i_pubkey_hash)
2762 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2763 else
2764 os_memset(test_hash, 0, SHA256_MAC_LEN);
2765 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2766 i_pubkey_hash = test_hash;
2767 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
2768 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
2769 wpabuf_free(pr);
2770 pr = NULL;
2771 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
2772 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
2773 wpabuf_free(pr);
2774 pr = wpabuf_alloc(2 * auth->curve->prime_len);
2775 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
2776 goto fail;
2777 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
2778 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
2779 w_r_auth = NULL;
2780 wrapped_r_auth_len = 0;
2781 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2782 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2783 status = 255;
2784 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
2785 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2786 status = 254;
2787 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
2788 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
2789 r_nonce = NULL;
2790 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2791 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2792 i_nonce = NULL;
2793 }
2794#endif /* CONFIG_TESTING_OPTIONS */
2795
2796 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
2797 r_pubkey_hash, i_pubkey_hash,
2798 r_nonce, i_nonce,
2799 w_r_auth, wrapped_r_auth_len,
2800 auth->k2);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002801 if (!msg)
2802 goto fail;
2803 wpabuf_free(auth->resp_msg);
2804 auth->resp_msg = msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002805 ret = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002806fail:
2807 wpabuf_free(pr);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002808 return ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002809}
2810
2811
2812static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
2813 enum dpp_status_error status)
2814{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002815 struct wpabuf *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002816 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
2817#ifdef CONFIG_TESTING_OPTIONS
2818 u8 test_hash[SHA256_MAC_LEN];
2819#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002820
Roshan Pius3a1667e2018-07-03 15:17:14 -07002821 if (!auth->own_bi)
2822 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002823 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2824
Roshan Pius3a1667e2018-07-03 15:17:14 -07002825 r_pubkey_hash = auth->own_bi->pubkey_hash;
2826 if (auth->peer_bi)
2827 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2828 else
2829 i_pubkey_hash = NULL;
2830
2831 i_nonce = auth->i_nonce;
2832
2833#ifdef CONFIG_TESTING_OPTIONS
2834 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2835 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2836 r_pubkey_hash = NULL;
2837 } else if (dpp_test ==
2838 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2839 wpa_printf(MSG_INFO,
2840 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2841 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2842 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2843 r_pubkey_hash = test_hash;
2844 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2845 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2846 i_pubkey_hash = NULL;
2847 } else if (dpp_test ==
2848 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2849 wpa_printf(MSG_INFO,
2850 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2851 if (i_pubkey_hash)
2852 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2853 else
2854 os_memset(test_hash, 0, SHA256_MAC_LEN);
2855 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2856 i_pubkey_hash = test_hash;
2857 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2858 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
Hai Shalom39bc25d2019-02-06 16:32:13 -08002859 status = 255;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002860 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2861 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2862 i_nonce = NULL;
2863 }
2864#endif /* CONFIG_TESTING_OPTIONS */
2865
2866 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
2867 r_pubkey_hash, i_pubkey_hash,
2868 NULL, i_nonce, NULL, 0, auth->k1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002869 if (!msg)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002870 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002871 wpabuf_free(auth->resp_msg);
2872 auth->resp_msg = msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002873 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002874}
2875
2876
2877struct dpp_authentication *
2878dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
2879 struct dpp_bootstrap_info *peer_bi,
2880 struct dpp_bootstrap_info *own_bi,
2881 unsigned int freq, const u8 *hdr, const u8 *attr_start,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002882 size_t attr_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002883{
2884 EVP_PKEY *pi = NULL;
2885 EVP_PKEY_CTX *ctx = NULL;
2886 size_t secret_len;
2887 const u8 *addr[2];
2888 size_t len[2];
2889 u8 *unwrapped = NULL;
2890 size_t unwrapped_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002891 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
2892 *channel;
2893 u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
2894 i_bootstrap_len, channel_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002895 struct dpp_authentication *auth = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002896
Roshan Pius3a1667e2018-07-03 15:17:14 -07002897#ifdef CONFIG_TESTING_OPTIONS
2898 if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
2899 wpa_printf(MSG_INFO,
2900 "DPP: TESTING - stop at Authentication Request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002901 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002902 }
2903#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002904
Roshan Pius3a1667e2018-07-03 15:17:14 -07002905 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2906 &wrapped_data_len);
2907 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
2908 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
2909 "Missing or invalid required Wrapped Data attribute");
2910 return NULL;
2911 }
2912 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
2913 wrapped_data, wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002914 attr_len = wrapped_data - 4 - attr_start;
2915
2916 auth = os_zalloc(sizeof(*auth));
2917 if (!auth)
2918 goto fail;
2919 auth->msg_ctx = msg_ctx;
2920 auth->peer_bi = peer_bi;
2921 auth->own_bi = own_bi;
2922 auth->curve = own_bi->curve;
2923 auth->curr_freq = freq;
2924
Roshan Pius3a1667e2018-07-03 15:17:14 -07002925 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
2926 &channel_len);
2927 if (channel) {
2928 int neg_freq;
2929
2930 if (channel_len < 2) {
2931 dpp_auth_fail(auth, "Too short Channel attribute");
2932 goto fail;
2933 }
2934
2935 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
2936 wpa_printf(MSG_DEBUG,
2937 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2938 channel[0], channel[1], neg_freq);
2939 if (neg_freq < 0) {
2940 dpp_auth_fail(auth,
2941 "Unsupported Channel attribute value");
2942 goto fail;
2943 }
2944
2945 if (auth->curr_freq != (unsigned int) neg_freq) {
2946 wpa_printf(MSG_DEBUG,
2947 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2948 freq, neg_freq);
2949 auth->curr_freq = neg_freq;
2950 }
2951 }
2952
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002953 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
2954 &i_proto_len);
2955 if (!i_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002956 dpp_auth_fail(auth,
2957 "Missing required Initiator Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002958 goto fail;
2959 }
2960 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
2961 i_proto, i_proto_len);
2962
2963 /* M = bR * PI */
2964 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
2965 if (!pi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002966 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002967 goto fail;
2968 }
2969 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
2970
2971 ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
2972 if (!ctx ||
2973 EVP_PKEY_derive_init(ctx) != 1 ||
2974 EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
2975 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2976 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2977 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
2978 wpa_printf(MSG_ERROR,
2979 "DPP: Failed to derive ECDH shared secret: %s",
2980 ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002981 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002982 goto fail;
2983 }
2984 auth->secret_len = secret_len;
2985 EVP_PKEY_CTX_free(ctx);
2986 ctx = NULL;
2987
2988 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2989 auth->Mx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002990 auth->Mx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002991
2992 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2993 auth->curve->hash_len) < 0)
2994 goto fail;
2995
2996 addr[0] = hdr;
2997 len[0] = DPP_HDR_LEN;
2998 addr[1] = attr_start;
2999 len[1] = attr_len;
3000 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3001 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3002 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3003 wrapped_data, wrapped_data_len);
3004 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3005 unwrapped = os_malloc(unwrapped_len);
3006 if (!unwrapped)
3007 goto fail;
3008 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3009 wrapped_data, wrapped_data_len,
3010 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003011 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003012 goto fail;
3013 }
3014 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3015 unwrapped, unwrapped_len);
3016
3017 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003018 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003019 goto fail;
3020 }
3021
3022 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3023 &i_nonce_len);
3024 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003025 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003026 goto fail;
3027 }
3028 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3029 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
3030
3031 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
3032 DPP_ATTR_I_CAPABILITIES,
3033 &i_capab_len);
3034 if (!i_capab || i_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003035 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003036 goto fail;
3037 }
3038 auth->i_capab = i_capab[0];
3039 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
3040
3041 bin_clear_free(unwrapped, unwrapped_len);
3042 unwrapped = NULL;
3043
3044 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
3045 case DPP_CAPAB_ENROLLEE:
3046 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
3047 wpa_printf(MSG_DEBUG,
3048 "DPP: Local policy does not allow Configurator role");
3049 goto not_compatible;
3050 }
3051 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3052 auth->configurator = 1;
3053 break;
3054 case DPP_CAPAB_CONFIGURATOR:
3055 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
3056 wpa_printf(MSG_DEBUG,
3057 "DPP: Local policy does not allow Enrollee role");
3058 goto not_compatible;
3059 }
3060 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3061 auth->configurator = 0;
3062 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003063 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
3064 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
3065 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3066 auth->configurator = 0;
3067 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
3068 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3069 auth->configurator = 1;
3070 } else {
3071 wpa_printf(MSG_DEBUG,
3072 "DPP: Local policy does not allow Configurator/Enrollee role");
3073 goto not_compatible;
3074 }
3075 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003076 default:
3077 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003078 wpa_msg(auth->msg_ctx, MSG_INFO,
3079 DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
3080 auth->i_capab & DPP_CAPAB_ROLE_MASK);
3081 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003082 }
3083
3084 auth->peer_protocol_key = pi;
3085 pi = NULL;
3086 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
3087 char hex[SHA256_MAC_LEN * 2 + 1];
3088
3089 wpa_printf(MSG_DEBUG,
3090 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3091 if (dpp_auth_build_resp_status(auth,
3092 DPP_STATUS_RESPONSE_PENDING) < 0)
3093 goto fail;
3094 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3095 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3096 &i_bootstrap_len);
3097 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
3098 auth->response_pending = 1;
3099 os_memcpy(auth->waiting_pubkey_hash,
3100 i_bootstrap, i_bootstrap_len);
3101 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
3102 i_bootstrap_len);
3103 } else {
3104 hex[0] = '\0';
3105 }
3106
3107 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
3108 "%s", hex);
3109 return auth;
3110 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003111 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003112 goto fail;
3113
3114 return auth;
3115
3116not_compatible:
3117 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3118 "i-capab=0x%02x", auth->i_capab);
3119 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
3120 auth->configurator = 1;
3121 else
3122 auth->configurator = 0;
3123 auth->peer_protocol_key = pi;
3124 pi = NULL;
3125 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
3126 goto fail;
3127
3128 auth->remove_on_tx_status = 1;
3129 return auth;
3130fail:
3131 bin_clear_free(unwrapped, unwrapped_len);
3132 EVP_PKEY_free(pi);
3133 EVP_PKEY_CTX_free(ctx);
3134 dpp_auth_deinit(auth);
3135 return NULL;
3136}
3137
3138
3139int dpp_notify_new_qr_code(struct dpp_authentication *auth,
3140 struct dpp_bootstrap_info *peer_bi)
3141{
3142 if (!auth || !auth->response_pending ||
3143 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
3144 SHA256_MAC_LEN) != 0)
3145 return 0;
3146
3147 wpa_printf(MSG_DEBUG,
3148 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3149 MACSTR, MAC2STR(auth->peer_mac_addr));
3150 auth->peer_bi = peer_bi;
3151
Roshan Pius3a1667e2018-07-03 15:17:14 -07003152 if (dpp_auth_build_resp_ok(auth) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003153 return -1;
3154
3155 return 1;
3156}
3157
3158
Roshan Pius3a1667e2018-07-03 15:17:14 -07003159static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
3160 enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003161{
3162 struct wpabuf *msg;
3163 u8 i_auth[4 + DPP_MAX_HASH_LEN];
3164 size_t i_auth_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003165 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3166 size_t r_nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003167 const u8 *addr[2];
3168 size_t len[2], attr_len;
3169 u8 *wrapped_i_auth;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003170 u8 *wrapped_r_nonce;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003171 u8 *attr_start, *attr_end;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003172 const u8 *r_pubkey_hash, *i_pubkey_hash;
3173#ifdef CONFIG_TESTING_OPTIONS
3174 u8 test_hash[SHA256_MAC_LEN];
3175#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003176
3177 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3178
3179 i_auth_len = 4 + auth->curve->hash_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003180 r_nonce_len = 4 + auth->curve->nonce_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003181 /* Build DPP Authentication Confirmation frame attributes */
3182 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
Roshan Pius3a1667e2018-07-03 15:17:14 -07003183 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
3184#ifdef CONFIG_TESTING_OPTIONS
3185 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
3186 attr_len += 5;
3187#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003188 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
3189 if (!msg)
3190 goto fail;
3191
3192 attr_start = wpabuf_put(msg, 0);
3193
Roshan Pius3a1667e2018-07-03 15:17:14 -07003194 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3195 if (auth->own_bi)
3196 i_pubkey_hash = auth->own_bi->pubkey_hash;
3197 else
3198 i_pubkey_hash = NULL;
3199
3200#ifdef CONFIG_TESTING_OPTIONS
3201 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3202 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3203 goto skip_status;
3204 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3205 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3206 status = 254;
3207 }
3208#endif /* CONFIG_TESTING_OPTIONS */
3209
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003210 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003211 dpp_build_attr_status(msg, status);
3212
3213#ifdef CONFIG_TESTING_OPTIONS
3214skip_status:
3215 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3216 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3217 r_pubkey_hash = NULL;
3218 } else if (dpp_test ==
3219 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3220 wpa_printf(MSG_INFO,
3221 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3222 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3223 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3224 r_pubkey_hash = test_hash;
3225 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3226 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3227 i_pubkey_hash = NULL;
3228 } else if (dpp_test ==
3229 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3230 wpa_printf(MSG_INFO,
3231 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3232 if (i_pubkey_hash)
3233 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3234 else
3235 os_memset(test_hash, 0, SHA256_MAC_LEN);
3236 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3237 i_pubkey_hash = test_hash;
3238 }
3239#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003240
3241 /* Responder Bootstrapping Key Hash */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003242 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003243
Roshan Pius3a1667e2018-07-03 15:17:14 -07003244 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3245 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
3246
3247#ifdef CONFIG_TESTING_OPTIONS
3248 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3249 goto skip_wrapped_data;
3250 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3251 i_auth_len = 0;
3252#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003253
3254 attr_end = wpabuf_put(msg, 0);
3255
3256 /* OUI, OUI type, Crypto Suite, DPP frame type */
3257 addr[0] = wpabuf_head_u8(msg) + 2;
3258 len[0] = 3 + 1 + 1 + 1;
3259 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3260
3261 /* Attributes before Wrapped Data */
3262 addr[1] = attr_start;
3263 len[1] = attr_end - attr_start;
3264 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3265
Roshan Pius3a1667e2018-07-03 15:17:14 -07003266 if (status == DPP_STATUS_OK) {
3267 /* I-auth wrapped with ke */
3268 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3269 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3270 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
3271
3272#ifdef CONFIG_TESTING_OPTIONS
3273 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3274 goto skip_i_auth;
3275#endif /* CONFIG_TESTING_OPTIONS */
3276
3277 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3278 * 1) */
3279 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3280 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3281 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3282 goto fail;
3283
3284#ifdef CONFIG_TESTING_OPTIONS
3285 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3286 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3287 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3288 }
3289skip_i_auth:
3290#endif /* CONFIG_TESTING_OPTIONS */
3291 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3292 i_auth, i_auth_len,
3293 2, addr, len, wrapped_i_auth) < 0)
3294 goto fail;
3295 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3296 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3297 } else {
3298 /* R-nonce wrapped with k2 */
3299 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3300 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3301 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3302
3303 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3304 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3305 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3306
3307 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3308 r_nonce, r_nonce_len,
3309 2, addr, len, wrapped_r_nonce) < 0)
3310 goto fail;
3311 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3312 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3313 }
3314
3315#ifdef CONFIG_TESTING_OPTIONS
3316 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3317 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
3318 dpp_build_attr_status(msg, DPP_STATUS_OK);
3319 }
3320skip_wrapped_data:
3321#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003322
3323 wpa_hexdump_buf(MSG_DEBUG,
3324 "DPP: Authentication Confirmation frame attributes",
3325 msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003326 if (status == DPP_STATUS_OK)
3327 dpp_auth_success(auth);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003328
3329 return msg;
3330
3331fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07003332 wpabuf_free(msg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003333 return NULL;
3334}
3335
3336
3337static void
3338dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
3339 const u8 *attr_start, size_t attr_len,
3340 const u8 *wrapped_data, u16 wrapped_data_len,
3341 enum dpp_status_error status)
3342{
3343 const u8 *addr[2];
3344 size_t len[2];
3345 u8 *unwrapped = NULL;
3346 size_t unwrapped_len = 0;
3347 const u8 *i_nonce, *r_capab;
3348 u16 i_nonce_len, r_capab_len;
3349
3350 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3351 wpa_printf(MSG_DEBUG,
3352 "DPP: Responder reported incompatible roles");
3353 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3354 wpa_printf(MSG_DEBUG,
3355 "DPP: Responder reported more time needed");
3356 } else {
3357 wpa_printf(MSG_DEBUG,
3358 "DPP: Responder reported failure (status %d)",
3359 status);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003360 dpp_auth_fail(auth, "Responder reported failure");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003361 return;
3362 }
3363
3364 addr[0] = hdr;
3365 len[0] = DPP_HDR_LEN;
3366 addr[1] = attr_start;
3367 len[1] = attr_len;
3368 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3369 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3370 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3371 wrapped_data, wrapped_data_len);
3372 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3373 unwrapped = os_malloc(unwrapped_len);
3374 if (!unwrapped)
3375 goto fail;
3376 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3377 wrapped_data, wrapped_data_len,
3378 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003379 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003380 goto fail;
3381 }
3382 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3383 unwrapped, unwrapped_len);
3384
3385 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003386 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003387 goto fail;
3388 }
3389
3390 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3391 &i_nonce_len);
3392 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003393 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003394 goto fail;
3395 }
3396 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3397 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003398 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003399 goto fail;
3400 }
3401
3402 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3403 DPP_ATTR_R_CAPABILITIES,
3404 &r_capab_len);
3405 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003406 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003407 goto fail;
3408 }
3409 auth->r_capab = r_capab[0];
3410 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3411 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3412 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3413 "r-capab=0x%02x", auth->r_capab);
3414 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003415 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3416
3417 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3418 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3419 wpa_msg(auth->msg_ctx, MSG_INFO,
3420 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3421 role);
3422 } else {
3423 wpa_printf(MSG_DEBUG,
3424 "DPP: Continue waiting for full DPP Authentication Response");
3425 wpa_msg(auth->msg_ctx, MSG_INFO,
3426 DPP_EVENT_RESPONSE_PENDING "%s",
3427 auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
3428 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003429 }
3430fail:
3431 bin_clear_free(unwrapped, unwrapped_len);
3432}
3433
3434
3435struct wpabuf *
3436dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3437 const u8 *attr_start, size_t attr_len)
3438{
3439 EVP_PKEY *pr;
3440 EVP_PKEY_CTX *ctx = NULL;
3441 size_t secret_len;
3442 const u8 *addr[2];
3443 size_t len[2];
3444 u8 *unwrapped = NULL, *unwrapped2 = NULL;
3445 size_t unwrapped_len = 0, unwrapped2_len = 0;
3446 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3447 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3448 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3449 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3450 wrapped2_len, r_auth_len;
3451 u8 r_auth2[DPP_MAX_HASH_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07003452 u8 role;
3453
3454#ifdef CONFIG_TESTING_OPTIONS
3455 if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
3456 wpa_printf(MSG_INFO,
3457 "DPP: TESTING - stop at Authentication Response");
3458 return NULL;
3459 }
3460#endif /* CONFIG_TESTING_OPTIONS */
3461
Hai Shalom39bc25d2019-02-06 16:32:13 -08003462 if (!auth->initiator || !auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003463 dpp_auth_fail(auth, "Unexpected Authentication Response");
3464 return NULL;
3465 }
3466
3467 auth->waiting_auth_resp = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003468
3469 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3470 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003471 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3472 dpp_auth_fail(auth,
3473 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003474 return NULL;
3475 }
3476 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3477 wrapped_data, wrapped_data_len);
3478
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003479 attr_len = wrapped_data - 4 - attr_start;
3480
3481 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3482 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3483 &r_bootstrap_len);
3484 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003485 dpp_auth_fail(auth,
3486 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003487 return NULL;
3488 }
3489 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3490 r_bootstrap, r_bootstrap_len);
3491 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3492 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003493 dpp_auth_fail(auth,
3494 "Unexpected Responder Bootstrapping Key Hash value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003495 wpa_hexdump(MSG_DEBUG,
3496 "DPP: Expected Responder Bootstrapping Key Hash",
3497 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3498 return NULL;
3499 }
3500
3501 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3502 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3503 &i_bootstrap_len);
3504 if (i_bootstrap) {
3505 if (i_bootstrap_len != SHA256_MAC_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003506 dpp_auth_fail(auth,
3507 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003508 return NULL;
3509 }
3510 wpa_hexdump(MSG_MSGDUMP,
3511 "DPP: Initiator Bootstrapping Key Hash",
3512 i_bootstrap, i_bootstrap_len);
3513 if (!auth->own_bi ||
3514 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3515 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003516 dpp_auth_fail(auth,
3517 "Initiator Bootstrapping Key Hash attribute did not match");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003518 return NULL;
3519 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003520 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3521 /* PKEX bootstrapping mandates use of mutual authentication */
3522 dpp_auth_fail(auth,
3523 "Missing Initiator Bootstrapping Key Hash attribute");
3524 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003525 }
3526
3527 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3528 &status_len);
3529 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003530 dpp_auth_fail(auth,
3531 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003532 return NULL;
3533 }
3534 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3535 auth->auth_resp_status = status[0];
3536 if (status[0] != DPP_STATUS_OK) {
3537 dpp_auth_resp_rx_status(auth, hdr, attr_start,
3538 attr_len, wrapped_data,
3539 wrapped_data_len, status[0]);
3540 return NULL;
3541 }
3542
Roshan Pius3a1667e2018-07-03 15:17:14 -07003543 if (!i_bootstrap && auth->own_bi) {
3544 wpa_printf(MSG_DEBUG,
3545 "DPP: Responder decided not to use mutual authentication");
3546 auth->own_bi = NULL;
3547 }
3548
3549 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
3550 auth->own_bi != NULL);
3551
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003552 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3553 &r_proto_len);
3554 if (!r_proto) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003555 dpp_auth_fail(auth,
3556 "Missing required Responder Protocol Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003557 return NULL;
3558 }
3559 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3560 r_proto, r_proto_len);
3561
3562 /* N = pI * PR */
3563 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3564 if (!pr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003565 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003566 return NULL;
3567 }
3568 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3569
3570 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
3571 if (!ctx ||
3572 EVP_PKEY_derive_init(ctx) != 1 ||
3573 EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
3574 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
3575 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
3576 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
3577 wpa_printf(MSG_ERROR,
3578 "DPP: Failed to derive ECDH shared secret: %s",
3579 ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003580 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003581 goto fail;
3582 }
3583 EVP_PKEY_CTX_free(ctx);
3584 ctx = NULL;
3585 auth->peer_protocol_key = pr;
3586 pr = NULL;
3587
3588 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3589 auth->Nx, auth->secret_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003590 auth->Nx_len = auth->secret_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003591
3592 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3593 auth->curve->hash_len) < 0)
3594 goto fail;
3595
3596 addr[0] = hdr;
3597 len[0] = DPP_HDR_LEN;
3598 addr[1] = attr_start;
3599 len[1] = attr_len;
3600 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3601 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3602 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3603 wrapped_data, wrapped_data_len);
3604 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3605 unwrapped = os_malloc(unwrapped_len);
3606 if (!unwrapped)
3607 goto fail;
3608 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3609 wrapped_data, wrapped_data_len,
3610 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003611 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003612 goto fail;
3613 }
3614 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3615 unwrapped, unwrapped_len);
3616
3617 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003618 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003619 goto fail;
3620 }
3621
3622 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3623 &r_nonce_len);
3624 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003625 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003626 goto fail;
3627 }
3628 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
3629 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
3630
3631 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3632 &i_nonce_len);
3633 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003634 dpp_auth_fail(auth, "Missing or invalid I-nonce");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003635 goto fail;
3636 }
3637 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3638 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003639 dpp_auth_fail(auth, "I-nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003640 goto fail;
3641 }
3642
Hai Shalom39bc25d2019-02-06 16:32:13 -08003643 if (auth->own_bi) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003644 /* Mutual authentication */
3645 if (dpp_auth_derive_l_initiator(auth) < 0)
3646 goto fail;
3647 }
3648
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003649 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3650 DPP_ATTR_R_CAPABILITIES,
3651 &r_capab_len);
3652 if (!r_capab || r_capab_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003653 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003654 goto fail;
3655 }
3656 auth->r_capab = r_capab[0];
3657 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003658 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3659 if ((auth->allowed_roles ==
3660 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
3661 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
3662 /* Peer selected its role, so move from "either role" to the
3663 * role that is compatible with peer's selection. */
3664 auth->configurator = role == DPP_CAPAB_ENROLLEE;
3665 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
3666 auth->configurator ? "Configurator" : "Enrollee");
3667 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3668 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003669 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003670 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3671 "Unexpected role in R-capabilities 0x%02x",
3672 role);
3673 if (role != DPP_CAPAB_ENROLLEE &&
3674 role != DPP_CAPAB_CONFIGURATOR)
3675 goto fail;
3676 bin_clear_free(unwrapped, unwrapped_len);
3677 auth->remove_on_tx_status = 1;
3678 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003679 }
3680
3681 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
3682 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
3683 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003684 dpp_auth_fail(auth,
3685 "Missing or invalid Secondary Wrapped Data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003686 goto fail;
3687 }
3688
3689 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3690 wrapped2, wrapped2_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003691
3692 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3693 goto fail;
3694
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003695 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
3696 unwrapped2 = os_malloc(unwrapped2_len);
3697 if (!unwrapped2)
3698 goto fail;
3699 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3700 wrapped2, wrapped2_len,
3701 0, NULL, NULL, unwrapped2) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003702 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003703 goto fail;
3704 }
3705 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3706 unwrapped2, unwrapped2_len);
3707
3708 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003709 dpp_auth_fail(auth,
3710 "Invalid attribute in secondary unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003711 goto fail;
3712 }
3713
3714 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
3715 &r_auth_len);
3716 if (!r_auth || r_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003717 dpp_auth_fail(auth,
3718 "Missing or invalid Responder Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003719 goto fail;
3720 }
3721 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
3722 r_auth, r_auth_len);
3723 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3724 if (dpp_gen_r_auth(auth, r_auth2) < 0)
3725 goto fail;
3726 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
3727 r_auth2, r_auth_len);
3728 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003729 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
3730 bin_clear_free(unwrapped, unwrapped_len);
3731 bin_clear_free(unwrapped2, unwrapped2_len);
3732 auth->remove_on_tx_status = 1;
3733 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003734 }
3735
3736 bin_clear_free(unwrapped, unwrapped_len);
3737 bin_clear_free(unwrapped2, unwrapped2_len);
3738
Roshan Pius3a1667e2018-07-03 15:17:14 -07003739#ifdef CONFIG_TESTING_OPTIONS
3740 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
3741 wpa_printf(MSG_INFO,
3742 "DPP: TESTING - Authentication Response in place of Confirm");
3743 if (dpp_auth_build_resp_ok(auth) < 0)
3744 return NULL;
3745 return wpabuf_dup(auth->resp_msg);
3746 }
3747#endif /* CONFIG_TESTING_OPTIONS */
3748
3749 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003750
3751fail:
3752 bin_clear_free(unwrapped, unwrapped_len);
3753 bin_clear_free(unwrapped2, unwrapped2_len);
3754 EVP_PKEY_free(pr);
3755 EVP_PKEY_CTX_free(ctx);
3756 return NULL;
3757}
3758
3759
Roshan Pius3a1667e2018-07-03 15:17:14 -07003760static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
3761 const u8 *hdr,
3762 const u8 *attr_start, size_t attr_len,
3763 const u8 *wrapped_data,
3764 u16 wrapped_data_len,
3765 enum dpp_status_error status)
3766{
3767 const u8 *addr[2];
3768 size_t len[2];
3769 u8 *unwrapped = NULL;
3770 size_t unwrapped_len = 0;
3771 const u8 *r_nonce;
3772 u16 r_nonce_len;
3773
3774 /* Authentication Confirm failure cases are expected to include
3775 * {R-nonce}k2 in the Wrapped Data attribute. */
3776
3777 addr[0] = hdr;
3778 len[0] = DPP_HDR_LEN;
3779 addr[1] = attr_start;
3780 len[1] = attr_len;
3781 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3782 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3783 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3784 wrapped_data, wrapped_data_len);
3785 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3786 unwrapped = os_malloc(unwrapped_len);
3787 if (!unwrapped) {
3788 dpp_auth_fail(auth, "Authentication failed");
3789 goto fail;
3790 }
3791 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3792 wrapped_data, wrapped_data_len,
3793 2, addr, len, unwrapped) < 0) {
3794 dpp_auth_fail(auth, "AES-SIV decryption failed");
3795 goto fail;
3796 }
3797 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3798 unwrapped, unwrapped_len);
3799
3800 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3801 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3802 goto fail;
3803 }
3804
3805 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3806 &r_nonce_len);
3807 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3808 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3809 goto fail;
3810 }
3811 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
3812 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
3813 r_nonce, r_nonce_len);
3814 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
3815 auth->r_nonce, r_nonce_len);
3816 dpp_auth_fail(auth, "R-nonce mismatch");
3817 goto fail;
3818 }
3819
3820 if (status == DPP_STATUS_NOT_COMPATIBLE)
3821 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
3822 else if (status == DPP_STATUS_AUTH_FAILURE)
3823 dpp_auth_fail(auth, "Peer reported authentication failure)");
3824
3825fail:
3826 bin_clear_free(unwrapped, unwrapped_len);
3827 return -1;
3828}
3829
3830
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003831int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
3832 const u8 *attr_start, size_t attr_len)
3833{
3834 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
3835 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3836 i_auth_len;
3837 const u8 *addr[2];
3838 size_t len[2];
3839 u8 *unwrapped = NULL;
3840 size_t unwrapped_len = 0;
3841 u8 i_auth2[DPP_MAX_HASH_LEN];
3842
Roshan Pius3a1667e2018-07-03 15:17:14 -07003843#ifdef CONFIG_TESTING_OPTIONS
3844 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
3845 wpa_printf(MSG_INFO,
3846 "DPP: TESTING - stop at Authentication Confirm");
3847 return -1;
3848 }
3849#endif /* CONFIG_TESTING_OPTIONS */
3850
Hai Shalom39bc25d2019-02-06 16:32:13 -08003851 if (auth->initiator || !auth->own_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003852 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
3853 return -1;
3854 }
3855
3856 auth->waiting_auth_conf = 0;
3857
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003858 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3859 &wrapped_data_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003860 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3861 dpp_auth_fail(auth,
3862 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003863 return -1;
3864 }
3865 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3866 wrapped_data, wrapped_data_len);
3867
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003868 attr_len = wrapped_data - 4 - attr_start;
3869
3870 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3871 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3872 &r_bootstrap_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003873 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3874 dpp_auth_fail(auth,
3875 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003876 return -1;
3877 }
3878 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3879 r_bootstrap, r_bootstrap_len);
3880 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
3881 SHA256_MAC_LEN) != 0) {
3882 wpa_hexdump(MSG_DEBUG,
3883 "DPP: Expected Responder Bootstrapping Key Hash",
3884 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003885 dpp_auth_fail(auth,
3886 "Responder Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003887 return -1;
3888 }
3889
3890 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3891 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3892 &i_bootstrap_len);
3893 if (i_bootstrap) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003894 if (i_bootstrap_len != SHA256_MAC_LEN) {
3895 dpp_auth_fail(auth,
3896 "Invalid Initiator Bootstrapping Key Hash attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003897 return -1;
3898 }
3899 wpa_hexdump(MSG_MSGDUMP,
3900 "DPP: Initiator Bootstrapping Key Hash",
3901 i_bootstrap, i_bootstrap_len);
3902 if (!auth->peer_bi ||
3903 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
3904 SHA256_MAC_LEN) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003905 dpp_auth_fail(auth,
3906 "Initiator Bootstrapping Key Hash mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003907 return -1;
3908 }
Hai Shalom39bc25d2019-02-06 16:32:13 -08003909 } else if (auth->peer_bi) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003910 /* Mutual authentication and peer did not include its
3911 * Bootstrapping Key Hash attribute. */
3912 dpp_auth_fail(auth,
3913 "Missing Initiator Bootstrapping Key Hash attribute");
3914 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003915 }
3916
3917 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3918 &status_len);
3919 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003920 dpp_auth_fail(auth,
3921 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003922 return -1;
3923 }
3924 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003925 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
3926 status[0] == DPP_STATUS_AUTH_FAILURE)
3927 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
3928 attr_len, wrapped_data,
3929 wrapped_data_len, status[0]);
3930
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003931 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003932 dpp_auth_fail(auth, "Authentication failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003933 return -1;
3934 }
3935
3936 addr[0] = hdr;
3937 len[0] = DPP_HDR_LEN;
3938 addr[1] = attr_start;
3939 len[1] = attr_len;
3940 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3941 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3942 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3943 wrapped_data, wrapped_data_len);
3944 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3945 unwrapped = os_malloc(unwrapped_len);
3946 if (!unwrapped)
3947 return -1;
3948 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3949 wrapped_data, wrapped_data_len,
3950 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003951 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003952 goto fail;
3953 }
3954 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3955 unwrapped, unwrapped_len);
3956
3957 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003958 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003959 goto fail;
3960 }
3961
3962 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
3963 &i_auth_len);
3964 if (!i_auth || i_auth_len != auth->curve->hash_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003965 dpp_auth_fail(auth,
3966 "Missing or invalid Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003967 goto fail;
3968 }
3969 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
3970 i_auth, i_auth_len);
3971 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3972 if (dpp_gen_i_auth(auth, i_auth2) < 0)
3973 goto fail;
3974 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
3975 i_auth2, i_auth_len);
3976 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003977 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003978 goto fail;
3979 }
3980
3981 bin_clear_free(unwrapped, unwrapped_len);
3982 dpp_auth_success(auth);
3983 return 0;
3984fail:
3985 bin_clear_free(unwrapped, unwrapped_len);
3986 return -1;
3987}
3988
3989
3990void dpp_configuration_free(struct dpp_configuration *conf)
3991{
3992 if (!conf)
3993 return;
3994 str_clear_free(conf->passphrase);
Hai Shalomce48b4a2018-09-05 11:41:35 -07003995 os_free(conf->group_id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003996 bin_clear_free(conf, sizeof(*conf));
3997}
3998
3999
4000void dpp_auth_deinit(struct dpp_authentication *auth)
4001{
4002 if (!auth)
4003 return;
4004 dpp_configuration_free(auth->conf_ap);
4005 dpp_configuration_free(auth->conf_sta);
4006 EVP_PKEY_free(auth->own_protocol_key);
4007 EVP_PKEY_free(auth->peer_protocol_key);
4008 wpabuf_free(auth->req_msg);
4009 wpabuf_free(auth->resp_msg);
4010 wpabuf_free(auth->conf_req);
4011 os_free(auth->connector);
4012 wpabuf_free(auth->net_access_key);
4013 wpabuf_free(auth->c_sign_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004014 dpp_bootstrap_info_free(auth->tmp_own_bi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004015#ifdef CONFIG_TESTING_OPTIONS
4016 os_free(auth->config_obj_override);
4017 os_free(auth->discovery_override);
4018 os_free(auth->groups_override);
4019#endif /* CONFIG_TESTING_OPTIONS */
4020 bin_clear_free(auth, sizeof(*auth));
4021}
4022
4023
4024static struct wpabuf *
4025dpp_build_conf_start(struct dpp_authentication *auth,
4026 struct dpp_configuration *conf, size_t tailroom)
4027{
4028 struct wpabuf *buf;
4029 char ssid[6 * sizeof(conf->ssid) + 1];
4030
4031#ifdef CONFIG_TESTING_OPTIONS
4032 if (auth->discovery_override)
4033 tailroom += os_strlen(auth->discovery_override);
4034#endif /* CONFIG_TESTING_OPTIONS */
4035
4036 buf = wpabuf_alloc(200 + tailroom);
4037 if (!buf)
4038 return NULL;
4039 wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4040#ifdef CONFIG_TESTING_OPTIONS
4041 if (auth->discovery_override) {
4042 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
4043 auth->discovery_override);
4044 wpabuf_put_str(buf, auth->discovery_override);
4045 wpabuf_put_u8(buf, ',');
4046 return buf;
4047 }
4048#endif /* CONFIG_TESTING_OPTIONS */
4049 wpabuf_put_str(buf, "{\"ssid\":\"");
4050 json_escape_string(ssid, sizeof(ssid),
4051 (const char *) conf->ssid, conf->ssid_len);
4052 wpabuf_put_str(buf, ssid);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004053 wpabuf_put_str(buf, "\"},");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004054
4055 return buf;
4056}
4057
4058
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004059static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
4060 const char *kid, const struct dpp_curve_params *curve)
4061{
4062 struct wpabuf *pub;
4063 const u8 *pos;
4064 char *x = NULL, *y = NULL;
4065 int ret = -1;
4066
4067 pub = dpp_get_pubkey_point(key, 0);
4068 if (!pub)
4069 goto fail;
4070 pos = wpabuf_head(pub);
4071 x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
4072 pos += curve->prime_len;
4073 y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
4074 if (!x || !y)
4075 goto fail;
4076
4077 wpabuf_put_str(buf, "\"");
4078 wpabuf_put_str(buf, name);
4079 wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
4080 wpabuf_put_str(buf, curve->jwk_crv);
4081 wpabuf_put_str(buf, "\",\"x\":\"");
4082 wpabuf_put_str(buf, x);
4083 wpabuf_put_str(buf, "\",\"y\":\"");
4084 wpabuf_put_str(buf, y);
4085 if (kid) {
4086 wpabuf_put_str(buf, "\",\"kid\":\"");
4087 wpabuf_put_str(buf, kid);
4088 }
4089 wpabuf_put_str(buf, "\"}");
4090 ret = 0;
4091fail:
4092 wpabuf_free(pub);
4093 os_free(x);
4094 os_free(y);
4095 return ret;
4096}
4097
4098
4099static struct wpabuf *
4100dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
4101 struct dpp_configuration *conf)
4102{
4103 struct wpabuf *buf = NULL;
4104 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
4105 size_t tailroom;
4106 const struct dpp_curve_params *curve;
4107 char jws_prot_hdr[100];
4108 size_t signed1_len, signed2_len, signed3_len;
4109 struct wpabuf *dppcon = NULL;
4110 unsigned char *signature = NULL;
4111 const unsigned char *p;
4112 size_t signature_len;
4113 EVP_MD_CTX *md_ctx = NULL;
4114 ECDSA_SIG *sig = NULL;
4115 char *dot = ".";
4116 const EVP_MD *sign_md;
4117 const BIGNUM *r, *s;
4118 size_t extra_len = 1000;
4119
4120 if (!auth->conf) {
4121 wpa_printf(MSG_INFO,
4122 "DPP: No configurator specified - cannot generate DPP config object");
4123 goto fail;
4124 }
4125 curve = auth->conf->curve;
4126 if (curve->hash_len == SHA256_MAC_LEN) {
4127 sign_md = EVP_sha256();
4128 } else if (curve->hash_len == SHA384_MAC_LEN) {
4129 sign_md = EVP_sha384();
4130 } else if (curve->hash_len == SHA512_MAC_LEN) {
4131 sign_md = EVP_sha512();
4132 } else {
4133 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
4134 goto fail;
4135 }
4136
4137#ifdef CONFIG_TESTING_OPTIONS
4138 if (auth->groups_override)
4139 extra_len += os_strlen(auth->groups_override);
4140#endif /* CONFIG_TESTING_OPTIONS */
4141
Hai Shalomce48b4a2018-09-05 11:41:35 -07004142 if (conf->group_id)
4143 extra_len += os_strlen(conf->group_id);
4144
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004145 /* Connector (JSON dppCon object) */
4146 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
4147 if (!dppcon)
4148 goto fail;
4149#ifdef CONFIG_TESTING_OPTIONS
4150 if (auth->groups_override) {
4151 wpabuf_put_u8(dppcon, '{');
4152 if (auth->groups_override) {
4153 wpa_printf(MSG_DEBUG,
4154 "DPP: TESTING - groups override: '%s'",
4155 auth->groups_override);
4156 wpabuf_put_str(dppcon, "\"groups\":");
4157 wpabuf_put_str(dppcon, auth->groups_override);
4158 wpabuf_put_u8(dppcon, ',');
4159 }
4160 goto skip_groups;
4161 }
4162#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomce48b4a2018-09-05 11:41:35 -07004163 wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
4164 conf->group_id ? conf->group_id : "*");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004165 wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
4166#ifdef CONFIG_TESTING_OPTIONS
4167skip_groups:
4168#endif /* CONFIG_TESTING_OPTIONS */
4169 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
4170 auth->curve) < 0) {
4171 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
4172 goto fail;
4173 }
4174 if (conf->netaccesskey_expiry) {
4175 struct os_tm tm;
4176
4177 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
4178 wpa_printf(MSG_DEBUG,
4179 "DPP: Failed to generate expiry string");
4180 goto fail;
4181 }
4182 wpabuf_printf(dppcon,
4183 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4184 tm.year, tm.month, tm.day,
4185 tm.hour, tm.min, tm.sec);
4186 }
4187 wpabuf_put_u8(dppcon, '}');
4188 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
4189 (const char *) wpabuf_head(dppcon));
4190
4191 os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
4192 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4193 auth->conf->kid, curve->jws_alg);
4194 signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
4195 os_strlen(jws_prot_hdr),
4196 &signed1_len, 0);
4197 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
4198 wpabuf_len(dppcon),
4199 &signed2_len, 0);
4200 if (!signed1 || !signed2)
4201 goto fail;
4202
4203 md_ctx = EVP_MD_CTX_create();
4204 if (!md_ctx)
4205 goto fail;
4206
4207 ERR_clear_error();
4208 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
4209 auth->conf->csign) != 1) {
4210 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
4211 ERR_error_string(ERR_get_error(), NULL));
4212 goto fail;
4213 }
4214 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
4215 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
4216 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
4217 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
4218 ERR_error_string(ERR_get_error(), NULL));
4219 goto fail;
4220 }
4221 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
4222 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4223 ERR_error_string(ERR_get_error(), NULL));
4224 goto fail;
4225 }
4226 signature = os_malloc(signature_len);
4227 if (!signature)
4228 goto fail;
4229 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
4230 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4231 ERR_error_string(ERR_get_error(), NULL));
4232 goto fail;
4233 }
4234 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
4235 signature, signature_len);
4236 /* Convert to raw coordinates r,s */
4237 p = signature;
4238 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
4239 if (!sig)
4240 goto fail;
4241 ECDSA_SIG_get0(sig, &r, &s);
4242 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4243 dpp_bn2bin_pad(s, signature + curve->prime_len,
4244 curve->prime_len) < 0)
4245 goto fail;
4246 signature_len = 2 * curve->prime_len;
4247 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4248 signature, signature_len);
4249 signed3 = (char *) base64_url_encode(signature, signature_len,
4250 &signed3_len, 0);
4251 if (!signed3)
4252 goto fail;
4253
4254 tailroom = 1000;
4255 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4256 tailroom += signed1_len + signed2_len + signed3_len;
4257 buf = dpp_build_conf_start(auth, conf, tailroom);
4258 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004259 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004260
4261 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
4262 wpabuf_put_str(buf, signed1);
4263 wpabuf_put_u8(buf, '.');
4264 wpabuf_put_str(buf, signed2);
4265 wpabuf_put_u8(buf, '.');
4266 wpabuf_put_str(buf, signed3);
4267 wpabuf_put_str(buf, "\",");
4268 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4269 curve) < 0) {
4270 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4271 goto fail;
4272 }
4273
4274 wpabuf_put_str(buf, "}}");
4275
4276 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4277 wpabuf_head(buf), wpabuf_len(buf));
4278
4279out:
4280 EVP_MD_CTX_destroy(md_ctx);
4281 ECDSA_SIG_free(sig);
4282 os_free(signed1);
4283 os_free(signed2);
4284 os_free(signed3);
4285 os_free(signature);
4286 wpabuf_free(dppcon);
4287 return buf;
4288fail:
4289 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4290 wpabuf_free(buf);
4291 buf = NULL;
4292 goto out;
4293}
4294
4295
4296static struct wpabuf *
4297dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
4298 struct dpp_configuration *conf)
4299{
4300 struct wpabuf *buf;
4301
4302 buf = dpp_build_conf_start(auth, conf, 1000);
4303 if (!buf)
4304 return NULL;
4305
Roshan Pius3a1667e2018-07-03 15:17:14 -07004306 wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004307 if (conf->passphrase) {
4308 char pass[63 * 6 + 1];
4309
4310 if (os_strlen(conf->passphrase) > 63) {
4311 wpabuf_free(buf);
4312 return NULL;
4313 }
4314
4315 json_escape_string(pass, sizeof(pass), conf->passphrase,
4316 os_strlen(conf->passphrase));
4317 wpabuf_put_str(buf, "\"pass\":\"");
4318 wpabuf_put_str(buf, pass);
4319 wpabuf_put_str(buf, "\"");
4320 } else {
4321 char psk[2 * sizeof(conf->psk) + 1];
4322
4323 wpa_snprintf_hex(psk, sizeof(psk),
4324 conf->psk, sizeof(conf->psk));
4325 wpabuf_put_str(buf, "\"psk_hex\":\"");
4326 wpabuf_put_str(buf, psk);
4327 wpabuf_put_str(buf, "\"");
4328 }
4329 wpabuf_put_str(buf, "}}");
4330
4331 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4332 wpabuf_head(buf), wpabuf_len(buf));
4333
4334 return buf;
4335}
4336
4337
4338static struct wpabuf *
4339dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
4340{
4341 struct dpp_configuration *conf;
4342
4343#ifdef CONFIG_TESTING_OPTIONS
4344 if (auth->config_obj_override) {
4345 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
4346 return wpabuf_alloc_copy(auth->config_obj_override,
4347 os_strlen(auth->config_obj_override));
4348 }
4349#endif /* CONFIG_TESTING_OPTIONS */
4350
4351 conf = ap ? auth->conf_ap : auth->conf_sta;
4352 if (!conf) {
4353 wpa_printf(MSG_DEBUG,
4354 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4355 ap ? "ap" : "sta");
4356 return NULL;
4357 }
4358
Roshan Pius3a1667e2018-07-03 15:17:14 -07004359 if (conf->akm == DPP_AKM_DPP)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004360 return dpp_build_conf_obj_dpp(auth, ap, conf);
4361 return dpp_build_conf_obj_legacy(auth, ap, conf);
4362}
4363
4364
4365static struct wpabuf *
4366dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4367 u16 e_nonce_len, int ap)
4368{
4369 struct wpabuf *conf;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004370 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004371 struct wpabuf *clear = NULL, *msg = NULL;
4372 u8 *wrapped;
4373 const u8 *addr[1];
4374 size_t len[1];
4375 enum dpp_status_error status;
4376
4377 conf = dpp_build_conf_obj(auth, ap);
4378 if (conf) {
4379 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4380 wpabuf_head(conf), wpabuf_len(conf));
4381 }
4382 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
4383
4384 /* { E-nonce, configurationObject}ke */
4385 clear_len = 4 + e_nonce_len;
4386 if (conf)
4387 clear_len += 4 + wpabuf_len(conf);
4388 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004389 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
4390#ifdef CONFIG_TESTING_OPTIONS
4391 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
4392 attr_len += 5;
4393#endif /* CONFIG_TESTING_OPTIONS */
4394 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004395 if (!clear || !msg)
4396 goto fail;
4397
Roshan Pius3a1667e2018-07-03 15:17:14 -07004398#ifdef CONFIG_TESTING_OPTIONS
4399 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
4400 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
4401 goto skip_e_nonce;
4402 }
4403 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
4404 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
4405 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4406 wpabuf_put_le16(clear, e_nonce_len);
4407 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
4408 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
4409 goto skip_e_nonce;
4410 }
4411 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
4412 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
4413 goto skip_wrapped_data;
4414 }
4415#endif /* CONFIG_TESTING_OPTIONS */
4416
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004417 /* E-nonce */
4418 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4419 wpabuf_put_le16(clear, e_nonce_len);
4420 wpabuf_put_data(clear, e_nonce, e_nonce_len);
4421
Roshan Pius3a1667e2018-07-03 15:17:14 -07004422#ifdef CONFIG_TESTING_OPTIONS
4423skip_e_nonce:
4424 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
4425 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
4426 goto skip_config_obj;
4427 }
4428#endif /* CONFIG_TESTING_OPTIONS */
4429
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004430 if (conf) {
4431 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4432 wpabuf_put_le16(clear, wpabuf_len(conf));
4433 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004434 }
4435
Roshan Pius3a1667e2018-07-03 15:17:14 -07004436#ifdef CONFIG_TESTING_OPTIONS
4437skip_config_obj:
4438 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4439 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4440 goto skip_status;
4441 }
4442 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4443 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4444 status = 255;
4445 }
4446#endif /* CONFIG_TESTING_OPTIONS */
4447
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004448 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07004449 dpp_build_attr_status(msg, status);
4450
4451#ifdef CONFIG_TESTING_OPTIONS
4452skip_status:
4453#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004454
4455 addr[0] = wpabuf_head(msg);
4456 len[0] = wpabuf_len(msg);
4457 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4458
4459 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
4460 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4461 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4462
4463 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
4464 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
4465 wpabuf_head(clear), wpabuf_len(clear),
4466 1, addr, len, wrapped) < 0)
4467 goto fail;
4468 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4469 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004470
4471#ifdef CONFIG_TESTING_OPTIONS
4472 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
4473 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
4474 dpp_build_attr_status(msg, DPP_STATUS_OK);
4475 }
4476skip_wrapped_data:
4477#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004478
4479 wpa_hexdump_buf(MSG_DEBUG,
4480 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004481out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004482 wpabuf_free(conf);
4483 wpabuf_free(clear);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004484
4485 return msg;
4486fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004487 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004488 msg = NULL;
4489 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004490}
4491
4492
4493struct wpabuf *
4494dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4495 size_t attr_len)
4496{
4497 const u8 *wrapped_data, *e_nonce, *config_attr;
4498 u16 wrapped_data_len, e_nonce_len, config_attr_len;
4499 u8 *unwrapped = NULL;
4500 size_t unwrapped_len = 0;
4501 struct wpabuf *resp = NULL;
4502 struct json_token *root = NULL, *token;
4503 int ap;
4504
Roshan Pius3a1667e2018-07-03 15:17:14 -07004505#ifdef CONFIG_TESTING_OPTIONS
4506 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
4507 wpa_printf(MSG_INFO,
4508 "DPP: TESTING - stop at Config Request");
4509 return NULL;
4510 }
4511#endif /* CONFIG_TESTING_OPTIONS */
4512
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004513 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004514 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004515 return NULL;
4516 }
4517
4518 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4519 &wrapped_data_len);
4520 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004521 dpp_auth_fail(auth,
4522 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004523 return NULL;
4524 }
4525
4526 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4527 wrapped_data, wrapped_data_len);
4528 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4529 unwrapped = os_malloc(unwrapped_len);
4530 if (!unwrapped)
4531 return NULL;
4532 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4533 wrapped_data, wrapped_data_len,
4534 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004535 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004536 goto fail;
4537 }
4538 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4539 unwrapped, unwrapped_len);
4540
4541 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004542 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004543 goto fail;
4544 }
4545
4546 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4547 DPP_ATTR_ENROLLEE_NONCE,
4548 &e_nonce_len);
4549 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004550 dpp_auth_fail(auth,
4551 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004552 goto fail;
4553 }
4554 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4555
4556 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
4557 DPP_ATTR_CONFIG_ATTR_OBJ,
4558 &config_attr_len);
4559 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004560 dpp_auth_fail(auth,
4561 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004562 goto fail;
4563 }
4564 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
4565 config_attr, config_attr_len);
4566
4567 root = json_parse((const char *) config_attr, config_attr_len);
4568 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004569 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004570 goto fail;
4571 }
4572
4573 token = json_get_member(root, "name");
4574 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004575 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004576 goto fail;
4577 }
4578 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
4579
4580 token = json_get_member(root, "wi-fi_tech");
4581 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004582 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004583 goto fail;
4584 }
4585 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
4586 if (os_strcmp(token->string, "infra") != 0) {
4587 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
4588 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004589 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004590 goto fail;
4591 }
4592
4593 token = json_get_member(root, "netRole");
4594 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004595 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004596 goto fail;
4597 }
4598 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
4599 if (os_strcmp(token->string, "sta") == 0) {
4600 ap = 0;
4601 } else if (os_strcmp(token->string, "ap") == 0) {
4602 ap = 1;
4603 } else {
4604 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
4605 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004606 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004607 goto fail;
4608 }
4609
4610 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
4611
4612fail:
4613 json_free(root);
4614 os_free(unwrapped);
4615 return resp;
4616}
4617
4618
4619static struct wpabuf *
4620dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
4621 const u8 *prot_hdr, u16 prot_hdr_len,
4622 const EVP_MD **ret_md)
4623{
4624 struct json_token *root, *token;
4625 struct wpabuf *kid = NULL;
4626
4627 root = json_parse((const char *) prot_hdr, prot_hdr_len);
4628 if (!root) {
4629 wpa_printf(MSG_DEBUG,
4630 "DPP: JSON parsing failed for JWS Protected Header");
4631 goto fail;
4632 }
4633
4634 if (root->type != JSON_OBJECT) {
4635 wpa_printf(MSG_DEBUG,
4636 "DPP: JWS Protected Header root is not an object");
4637 goto fail;
4638 }
4639
4640 token = json_get_member(root, "typ");
4641 if (!token || token->type != JSON_STRING) {
4642 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
4643 goto fail;
4644 }
4645 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
4646 token->string);
4647 if (os_strcmp(token->string, "dppCon") != 0) {
4648 wpa_printf(MSG_DEBUG,
4649 "DPP: Unsupported JWS Protected Header typ=%s",
4650 token->string);
4651 goto fail;
4652 }
4653
4654 token = json_get_member(root, "alg");
4655 if (!token || token->type != JSON_STRING) {
4656 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
4657 goto fail;
4658 }
4659 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
4660 token->string);
4661 if (os_strcmp(token->string, curve->jws_alg) != 0) {
4662 wpa_printf(MSG_DEBUG,
4663 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4664 token->string, curve->jws_alg);
4665 goto fail;
4666 }
4667 if (os_strcmp(token->string, "ES256") == 0 ||
4668 os_strcmp(token->string, "BS256") == 0)
4669 *ret_md = EVP_sha256();
4670 else if (os_strcmp(token->string, "ES384") == 0 ||
4671 os_strcmp(token->string, "BS384") == 0)
4672 *ret_md = EVP_sha384();
4673 else if (os_strcmp(token->string, "ES512") == 0 ||
4674 os_strcmp(token->string, "BS512") == 0)
4675 *ret_md = EVP_sha512();
4676 else
4677 *ret_md = NULL;
4678 if (!*ret_md) {
4679 wpa_printf(MSG_DEBUG,
4680 "DPP: Unsupported JWS Protected Header alg=%s",
4681 token->string);
4682 goto fail;
4683 }
4684
4685 kid = json_get_member_base64url(root, "kid");
4686 if (!kid) {
4687 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
4688 goto fail;
4689 }
4690 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
4691 kid);
4692
4693fail:
4694 json_free(root);
4695 return kid;
4696}
4697
4698
4699static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
4700 struct json_token *cred)
4701{
4702 struct json_token *pass, *psk_hex;
4703
4704 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
4705
4706 pass = json_get_member(cred, "pass");
4707 psk_hex = json_get_member(cred, "psk_hex");
4708
4709 if (pass && pass->type == JSON_STRING) {
4710 size_t len = os_strlen(pass->string);
4711
4712 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
4713 pass->string, len);
4714 if (len < 8 || len > 63)
4715 return -1;
4716 os_strlcpy(auth->passphrase, pass->string,
4717 sizeof(auth->passphrase));
4718 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004719 if (auth->akm == DPP_AKM_SAE) {
4720 wpa_printf(MSG_DEBUG,
4721 "DPP: Unexpected psk_hex with akm=sae");
4722 return -1;
4723 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004724 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
4725 hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
4726 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
4727 return -1;
4728 }
4729 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
4730 auth->psk, PMK_LEN);
4731 auth->psk_set = 1;
4732 } else {
4733 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
4734 return -1;
4735 }
4736
Roshan Pius3a1667e2018-07-03 15:17:14 -07004737 if ((auth->akm == DPP_AKM_SAE || auth->akm == DPP_AKM_PSK_SAE) &&
4738 !auth->passphrase[0]) {
4739 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
4740 return -1;
4741 }
4742
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004743 return 0;
4744}
4745
4746
4747static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
4748 const struct dpp_curve_params **key_curve)
4749{
4750 struct json_token *token;
4751 const struct dpp_curve_params *curve;
4752 struct wpabuf *x = NULL, *y = NULL;
4753 EC_GROUP *group;
4754 EVP_PKEY *pkey = NULL;
4755
4756 token = json_get_member(jwk, "kty");
4757 if (!token || token->type != JSON_STRING) {
4758 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
4759 goto fail;
4760 }
4761 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom39bc25d2019-02-06 16:32:13 -08004762 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004763 token->string);
4764 goto fail;
4765 }
4766
4767 token = json_get_member(jwk, "crv");
4768 if (!token || token->type != JSON_STRING) {
4769 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
4770 goto fail;
4771 }
4772 curve = dpp_get_curve_jwk_crv(token->string);
4773 if (!curve) {
4774 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
4775 token->string);
4776 goto fail;
4777 }
4778
4779 x = json_get_member_base64url(jwk, "x");
4780 if (!x) {
4781 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
4782 goto fail;
4783 }
4784 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
4785 if (wpabuf_len(x) != curve->prime_len) {
4786 wpa_printf(MSG_DEBUG,
4787 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4788 (unsigned int) wpabuf_len(x),
4789 (unsigned int) curve->prime_len, curve->name);
4790 goto fail;
4791 }
4792
4793 y = json_get_member_base64url(jwk, "y");
4794 if (!y) {
4795 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
4796 goto fail;
4797 }
4798 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
4799 if (wpabuf_len(y) != curve->prime_len) {
4800 wpa_printf(MSG_DEBUG,
4801 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4802 (unsigned int) wpabuf_len(y),
4803 (unsigned int) curve->prime_len, curve->name);
4804 goto fail;
4805 }
4806
4807 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
4808 if (!group) {
4809 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
4810 goto fail;
4811 }
4812
4813 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
4814 wpabuf_len(x));
4815 *key_curve = curve;
4816
4817fail:
4818 wpabuf_free(x);
4819 wpabuf_free(y);
4820
4821 return pkey;
4822}
4823
4824
4825int dpp_key_expired(const char *timestamp, os_time_t *expiry)
4826{
4827 struct os_time now;
4828 unsigned int year, month, day, hour, min, sec;
4829 os_time_t utime;
4830 const char *pos;
4831
4832 /* ISO 8601 date and time:
4833 * <date>T<time>
4834 * YYYY-MM-DDTHH:MM:SSZ
4835 * YYYY-MM-DDTHH:MM:SS+03:00
4836 */
4837 if (os_strlen(timestamp) < 19) {
4838 wpa_printf(MSG_DEBUG,
4839 "DPP: Too short timestamp - assume expired key");
4840 return 1;
4841 }
4842 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
4843 &year, &month, &day, &hour, &min, &sec) != 6) {
4844 wpa_printf(MSG_DEBUG,
4845 "DPP: Failed to parse expiration day - assume expired key");
4846 return 1;
4847 }
4848
4849 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
4850 wpa_printf(MSG_DEBUG,
4851 "DPP: Invalid date/time information - assume expired key");
4852 return 1;
4853 }
4854
4855 pos = timestamp + 19;
4856 if (*pos == 'Z' || *pos == '\0') {
4857 /* In UTC - no need to adjust */
4858 } else if (*pos == '-' || *pos == '+') {
4859 int items;
4860
4861 /* Adjust local time to UTC */
4862 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
4863 if (items < 1) {
4864 wpa_printf(MSG_DEBUG,
4865 "DPP: Invalid time zone designator (%s) - assume expired key",
4866 pos);
4867 return 1;
4868 }
4869 if (*pos == '-')
4870 utime += 3600 * hour;
4871 if (*pos == '+')
4872 utime -= 3600 * hour;
4873 if (items > 1) {
4874 if (*pos == '-')
4875 utime += 60 * min;
4876 if (*pos == '+')
4877 utime -= 60 * min;
4878 }
4879 } else {
4880 wpa_printf(MSG_DEBUG,
4881 "DPP: Invalid time zone designator (%s) - assume expired key",
4882 pos);
4883 return 1;
4884 }
4885 if (expiry)
4886 *expiry = utime;
4887
4888 if (os_get_time(&now) < 0) {
4889 wpa_printf(MSG_DEBUG,
4890 "DPP: Cannot get current time - assume expired key");
4891 return 1;
4892 }
4893
4894 if (now.sec > utime) {
4895 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
4896 utime, now.sec);
4897 return 1;
4898 }
4899
4900 return 0;
4901}
4902
4903
4904static int dpp_parse_connector(struct dpp_authentication *auth,
4905 const unsigned char *payload,
4906 u16 payload_len)
4907{
4908 struct json_token *root, *groups, *netkey, *token;
4909 int ret = -1;
4910 EVP_PKEY *key = NULL;
4911 const struct dpp_curve_params *curve;
4912 unsigned int rules = 0;
4913
4914 root = json_parse((const char *) payload, payload_len);
4915 if (!root) {
4916 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4917 goto fail;
4918 }
4919
4920 groups = json_get_member(root, "groups");
4921 if (!groups || groups->type != JSON_ARRAY) {
4922 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
4923 goto skip_groups;
4924 }
4925 for (token = groups->child; token; token = token->sibling) {
4926 struct json_token *id, *role;
4927
4928 id = json_get_member(token, "groupId");
4929 if (!id || id->type != JSON_STRING) {
4930 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
4931 goto fail;
4932 }
4933
4934 role = json_get_member(token, "netRole");
4935 if (!role || role->type != JSON_STRING) {
4936 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
4937 goto fail;
4938 }
4939 wpa_printf(MSG_DEBUG,
4940 "DPP: connector group: groupId='%s' netRole='%s'",
4941 id->string, role->string);
4942 rules++;
4943 }
4944skip_groups:
4945
4946 if (!rules) {
4947 wpa_printf(MSG_DEBUG,
4948 "DPP: Connector includes no groups");
4949 goto fail;
4950 }
4951
4952 token = json_get_member(root, "expiry");
4953 if (!token || token->type != JSON_STRING) {
4954 wpa_printf(MSG_DEBUG,
4955 "DPP: No expiry string found - connector does not expire");
4956 } else {
4957 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4958 if (dpp_key_expired(token->string,
4959 &auth->net_access_key_expiry)) {
4960 wpa_printf(MSG_DEBUG,
4961 "DPP: Connector (netAccessKey) has expired");
4962 goto fail;
4963 }
4964 }
4965
4966 netkey = json_get_member(root, "netAccessKey");
4967 if (!netkey || netkey->type != JSON_OBJECT) {
4968 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4969 goto fail;
4970 }
4971
4972 key = dpp_parse_jwk(netkey, &curve);
4973 if (!key)
4974 goto fail;
4975 dpp_debug_print_key("DPP: Received netAccessKey", key);
4976
4977 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
4978 wpa_printf(MSG_DEBUG,
4979 "DPP: netAccessKey in connector does not match own protocol key");
4980#ifdef CONFIG_TESTING_OPTIONS
4981 if (auth->ignore_netaccesskey_mismatch) {
4982 wpa_printf(MSG_DEBUG,
4983 "DPP: TESTING - skip netAccessKey mismatch");
4984 } else {
4985 goto fail;
4986 }
4987#else /* CONFIG_TESTING_OPTIONS */
4988 goto fail;
4989#endif /* CONFIG_TESTING_OPTIONS */
4990 }
4991
4992 ret = 0;
4993fail:
4994 EVP_PKEY_free(key);
4995 json_free(root);
4996 return ret;
4997}
4998
4999
5000static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
5001{
5002 struct wpabuf *uncomp;
5003 int res;
5004 u8 hash[SHA256_MAC_LEN];
5005 const u8 *addr[1];
5006 size_t len[1];
5007
5008 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
5009 return -1;
5010 uncomp = dpp_get_pubkey_point(pub, 1);
5011 if (!uncomp)
5012 return -1;
5013 addr[0] = wpabuf_head(uncomp);
5014 len[0] = wpabuf_len(uncomp);
5015 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
5016 addr[0], len[0]);
5017 res = sha256_vector(1, addr, len, hash);
5018 wpabuf_free(uncomp);
5019 if (res < 0)
5020 return -1;
5021 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
5022 wpa_printf(MSG_DEBUG,
5023 "DPP: Received hash value does not match calculated public key hash value");
5024 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
5025 hash, SHA256_MAC_LEN);
5026 return -1;
5027 }
5028 return 0;
5029}
5030
5031
5032static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
5033{
5034 unsigned char *der = NULL;
5035 int der_len;
5036
5037 der_len = i2d_PUBKEY(csign, &der);
5038 if (der_len <= 0)
5039 return;
5040 wpabuf_free(auth->c_sign_key);
5041 auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
5042 OPENSSL_free(der);
5043}
5044
5045
5046static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
5047{
5048 unsigned char *der = NULL;
5049 int der_len;
5050 EC_KEY *eckey;
5051
5052 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
5053 if (!eckey)
5054 return;
5055
5056 der_len = i2d_ECPrivateKey(eckey, &der);
5057 if (der_len <= 0) {
5058 EC_KEY_free(eckey);
5059 return;
5060 }
5061 wpabuf_free(auth->net_access_key);
5062 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
5063 OPENSSL_free(der);
5064 EC_KEY_free(eckey);
5065}
5066
5067
5068struct dpp_signed_connector_info {
5069 unsigned char *payload;
5070 size_t payload_len;
5071};
5072
Roshan Pius3a1667e2018-07-03 15:17:14 -07005073static enum dpp_status_error
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005074dpp_process_signed_connector(struct dpp_signed_connector_info *info,
5075 EVP_PKEY *csign_pub, const char *connector)
5076{
Roshan Pius3a1667e2018-07-03 15:17:14 -07005077 enum dpp_status_error ret = 255;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005078 const char *pos, *end, *signed_start, *signed_end;
5079 struct wpabuf *kid = NULL;
5080 unsigned char *prot_hdr = NULL, *signature = NULL;
5081 size_t prot_hdr_len = 0, signature_len = 0;
5082 const EVP_MD *sign_md = NULL;
5083 unsigned char *der = NULL;
5084 int der_len;
5085 int res;
5086 EVP_MD_CTX *md_ctx = NULL;
5087 ECDSA_SIG *sig = NULL;
5088 BIGNUM *r = NULL, *s = NULL;
5089 const struct dpp_curve_params *curve;
5090 EC_KEY *eckey;
5091 const EC_GROUP *group;
5092 int nid;
5093
5094 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
5095 if (!eckey)
5096 goto fail;
5097 group = EC_KEY_get0_group(eckey);
5098 if (!group)
5099 goto fail;
5100 nid = EC_GROUP_get_curve_name(group);
5101 curve = dpp_get_curve_nid(nid);
5102 if (!curve)
5103 goto fail;
5104 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
5105 os_memset(info, 0, sizeof(*info));
5106
5107 signed_start = pos = connector;
5108 end = os_strchr(pos, '.');
5109 if (!end) {
5110 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005111 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005112 goto fail;
5113 }
5114 prot_hdr = base64_url_decode((const unsigned char *) pos,
5115 end - pos, &prot_hdr_len);
5116 if (!prot_hdr) {
5117 wpa_printf(MSG_DEBUG,
5118 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005119 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005120 goto fail;
5121 }
5122 wpa_hexdump_ascii(MSG_DEBUG,
5123 "DPP: signedConnector - JWS Protected Header",
5124 prot_hdr, prot_hdr_len);
5125 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005126 if (!kid) {
5127 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005128 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005129 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005130 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
5131 wpa_printf(MSG_DEBUG,
5132 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5133 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005134 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005135 goto fail;
5136 }
5137
5138 pos = end + 1;
5139 end = os_strchr(pos, '.');
5140 if (!end) {
5141 wpa_printf(MSG_DEBUG,
5142 "DPP: Missing dot(2) in signedConnector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005143 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005144 goto fail;
5145 }
5146 signed_end = end - 1;
5147 info->payload = base64_url_decode((const unsigned char *) pos,
5148 end - pos, &info->payload_len);
5149 if (!info->payload) {
5150 wpa_printf(MSG_DEBUG,
5151 "DPP: Failed to base64url decode signedConnector JWS Payload");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005152 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005153 goto fail;
5154 }
5155 wpa_hexdump_ascii(MSG_DEBUG,
5156 "DPP: signedConnector - JWS Payload",
5157 info->payload, info->payload_len);
5158 pos = end + 1;
5159 signature = base64_url_decode((const unsigned char *) pos,
5160 os_strlen(pos), &signature_len);
5161 if (!signature) {
5162 wpa_printf(MSG_DEBUG,
5163 "DPP: Failed to base64url decode signedConnector signature");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005164 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005165 goto fail;
5166 }
5167 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5168 signature, signature_len);
5169
Roshan Pius3a1667e2018-07-03 15:17:14 -07005170 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5171 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005172 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005173 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005174
5175 if (signature_len & 0x01) {
5176 wpa_printf(MSG_DEBUG,
5177 "DPP: Unexpected signedConnector signature length (%d)",
5178 (int) signature_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005179 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005180 goto fail;
5181 }
5182
5183 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5184 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5185 r = BN_bin2bn(signature, signature_len / 2, NULL);
5186 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
5187 sig = ECDSA_SIG_new();
5188 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
5189 goto fail;
5190 r = NULL;
5191 s = NULL;
5192
5193 der_len = i2d_ECDSA_SIG(sig, &der);
5194 if (der_len <= 0) {
5195 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
5196 goto fail;
5197 }
5198 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
5199 md_ctx = EVP_MD_CTX_create();
5200 if (!md_ctx)
5201 goto fail;
5202
5203 ERR_clear_error();
5204 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
5205 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
5206 ERR_error_string(ERR_get_error(), NULL));
5207 goto fail;
5208 }
5209 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
5210 signed_end - signed_start + 1) != 1) {
5211 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
5212 ERR_error_string(ERR_get_error(), NULL));
5213 goto fail;
5214 }
5215 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
5216 if (res != 1) {
5217 wpa_printf(MSG_DEBUG,
5218 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5219 res, ERR_error_string(ERR_get_error(), NULL));
Roshan Pius3a1667e2018-07-03 15:17:14 -07005220 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005221 goto fail;
5222 }
5223
Roshan Pius3a1667e2018-07-03 15:17:14 -07005224 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005225fail:
5226 EC_KEY_free(eckey);
5227 EVP_MD_CTX_destroy(md_ctx);
5228 os_free(prot_hdr);
5229 wpabuf_free(kid);
5230 os_free(signature);
5231 ECDSA_SIG_free(sig);
5232 BN_free(r);
5233 BN_free(s);
5234 OPENSSL_free(der);
5235 return ret;
5236}
5237
5238
5239static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5240 struct json_token *cred)
5241{
5242 struct dpp_signed_connector_info info;
5243 struct json_token *token, *csign;
5244 int ret = -1;
5245 EVP_PKEY *csign_pub = NULL;
5246 const struct dpp_curve_params *key_curve = NULL;
5247 const char *signed_connector;
5248
5249 os_memset(&info, 0, sizeof(info));
5250
5251 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5252
5253 csign = json_get_member(cred, "csign");
5254 if (!csign || csign->type != JSON_OBJECT) {
5255 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5256 goto fail;
5257 }
5258
5259 csign_pub = dpp_parse_jwk(csign, &key_curve);
5260 if (!csign_pub) {
5261 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5262 goto fail;
5263 }
5264 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5265
5266 token = json_get_member(cred, "signedConnector");
5267 if (!token || token->type != JSON_STRING) {
5268 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5269 goto fail;
5270 }
5271 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5272 token->string, os_strlen(token->string));
5273 signed_connector = token->string;
5274
5275 if (os_strchr(signed_connector, '"') ||
5276 os_strchr(signed_connector, '\n')) {
5277 wpa_printf(MSG_DEBUG,
5278 "DPP: Unexpected character in signedConnector");
5279 goto fail;
5280 }
5281
5282 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005283 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005284 goto fail;
5285
5286 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
5287 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5288 goto fail;
5289 }
5290
5291 os_free(auth->connector);
5292 auth->connector = os_strdup(signed_connector);
5293
5294 dpp_copy_csign(auth, csign_pub);
5295 dpp_copy_netaccesskey(auth);
5296
5297 ret = 0;
5298fail:
5299 EVP_PKEY_free(csign_pub);
5300 os_free(info.payload);
5301 return ret;
5302}
5303
5304
Roshan Pius3a1667e2018-07-03 15:17:14 -07005305const char * dpp_akm_str(enum dpp_akm akm)
5306{
5307 switch (akm) {
5308 case DPP_AKM_DPP:
5309 return "dpp";
5310 case DPP_AKM_PSK:
5311 return "psk";
5312 case DPP_AKM_SAE:
5313 return "sae";
5314 case DPP_AKM_PSK_SAE:
5315 return "psk+sae";
5316 default:
5317 return "??";
5318 }
5319}
5320
5321
5322static enum dpp_akm dpp_akm_from_str(const char *akm)
5323{
5324 if (os_strcmp(akm, "psk") == 0)
5325 return DPP_AKM_PSK;
5326 if (os_strcmp(akm, "sae") == 0)
5327 return DPP_AKM_SAE;
5328 if (os_strcmp(akm, "psk+sae") == 0)
5329 return DPP_AKM_PSK_SAE;
5330 if (os_strcmp(akm, "dpp") == 0)
5331 return DPP_AKM_DPP;
5332 return DPP_AKM_UNKNOWN;
5333}
5334
5335
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005336static int dpp_parse_conf_obj(struct dpp_authentication *auth,
5337 const u8 *conf_obj, u16 conf_obj_len)
5338{
5339 int ret = -1;
5340 struct json_token *root, *token, *discovery, *cred;
5341
5342 root = json_parse((const char *) conf_obj, conf_obj_len);
5343 if (!root)
5344 return -1;
5345 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005346 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005347 goto fail;
5348 }
5349
5350 token = json_get_member(root, "wi-fi_tech");
5351 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005352 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005353 goto fail;
5354 }
5355 if (os_strcmp(token->string, "infra") != 0) {
5356 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5357 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005358 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005359 goto fail;
5360 }
5361
5362 discovery = json_get_member(root, "discovery");
5363 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005364 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005365 goto fail;
5366 }
5367
5368 token = json_get_member(discovery, "ssid");
5369 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005370 dpp_auth_fail(auth, "No discovery::ssid string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005371 goto fail;
5372 }
5373 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
5374 token->string, os_strlen(token->string));
5375 if (os_strlen(token->string) > SSID_MAX_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005376 dpp_auth_fail(auth, "Too long discovery::ssid string value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005377 goto fail;
5378 }
5379 auth->ssid_len = os_strlen(token->string);
5380 os_memcpy(auth->ssid, token->string, auth->ssid_len);
5381
5382 cred = json_get_member(root, "cred");
5383 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005384 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005385 goto fail;
5386 }
5387
5388 token = json_get_member(cred, "akm");
5389 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005390 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005391 goto fail;
5392 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07005393 auth->akm = dpp_akm_from_str(token->string);
5394
5395 if (auth->akm == DPP_AKM_PSK || auth->akm == DPP_AKM_SAE ||
5396 auth->akm == DPP_AKM_PSK_SAE) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005397 if (dpp_parse_cred_legacy(auth, cred) < 0)
5398 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005399 } else if (auth->akm == DPP_AKM_DPP) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005400 if (dpp_parse_cred_dpp(auth, cred) < 0)
5401 goto fail;
5402 } else {
5403 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5404 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005405 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005406 goto fail;
5407 }
5408
5409 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5410 ret = 0;
5411fail:
5412 json_free(root);
5413 return ret;
5414}
5415
5416
5417int dpp_conf_resp_rx(struct dpp_authentication *auth,
5418 const struct wpabuf *resp)
5419{
5420 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5421 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5422 const u8 *addr[1];
5423 size_t len[1];
5424 u8 *unwrapped = NULL;
5425 size_t unwrapped_len = 0;
5426 int ret = -1;
5427
5428 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005429 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005430 return -1;
5431 }
5432
5433 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5434 DPP_ATTR_WRAPPED_DATA,
5435 &wrapped_data_len);
5436 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005437 dpp_auth_fail(auth,
5438 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005439 return -1;
5440 }
5441
5442 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5443 wrapped_data, wrapped_data_len);
5444 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5445 unwrapped = os_malloc(unwrapped_len);
5446 if (!unwrapped)
5447 return -1;
5448
5449 addr[0] = wpabuf_head(resp);
5450 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
5451 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5452
5453 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5454 wrapped_data, wrapped_data_len,
5455 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005456 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005457 goto fail;
5458 }
5459 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5460 unwrapped, unwrapped_len);
5461
5462 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005463 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005464 goto fail;
5465 }
5466
5467 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5468 DPP_ATTR_ENROLLEE_NONCE,
5469 &e_nonce_len);
5470 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005471 dpp_auth_fail(auth,
5472 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005473 goto fail;
5474 }
5475 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5476 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005477 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005478 goto fail;
5479 }
5480
5481 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5482 DPP_ATTR_STATUS, &status_len);
5483 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005484 dpp_auth_fail(auth,
5485 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005486 goto fail;
5487 }
5488 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5489 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005490 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005491 goto fail;
5492 }
5493
5494 conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
5495 DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
5496 if (!conf_obj) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005497 dpp_auth_fail(auth,
5498 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005499 goto fail;
5500 }
5501 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
5502 conf_obj, conf_obj_len);
5503 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
5504 goto fail;
5505
5506 ret = 0;
5507
5508fail:
5509 os_free(unwrapped);
5510 return ret;
5511}
5512
5513
5514void dpp_configurator_free(struct dpp_configurator *conf)
5515{
5516 if (!conf)
5517 return;
5518 EVP_PKEY_free(conf->csign);
5519 os_free(conf->kid);
5520 os_free(conf);
5521}
5522
5523
Roshan Pius3a1667e2018-07-03 15:17:14 -07005524int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
5525 size_t buflen)
5526{
5527 EC_KEY *eckey;
5528 int key_len, ret = -1;
5529 unsigned char *key = NULL;
5530
5531 if (!conf->csign)
5532 return -1;
5533
5534 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
5535 if (!eckey)
5536 return -1;
5537
5538 key_len = i2d_ECPrivateKey(eckey, &key);
5539 if (key_len > 0)
5540 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
5541
5542 EC_KEY_free(eckey);
5543 OPENSSL_free(key);
5544 return ret;
5545}
5546
5547
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005548struct dpp_configurator *
5549dpp_keygen_configurator(const char *curve, const u8 *privkey,
5550 size_t privkey_len)
5551{
5552 struct dpp_configurator *conf;
5553 struct wpabuf *csign_pub = NULL;
5554 u8 kid_hash[SHA256_MAC_LEN];
5555 const u8 *addr[1];
5556 size_t len[1];
5557
5558 conf = os_zalloc(sizeof(*conf));
5559 if (!conf)
5560 return NULL;
5561
5562 if (!curve) {
5563 conf->curve = &dpp_curves[0];
5564 } else {
5565 conf->curve = dpp_get_curve_name(curve);
5566 if (!conf->curve) {
5567 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5568 curve);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005569 os_free(conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005570 return NULL;
5571 }
5572 }
5573 if (privkey)
5574 conf->csign = dpp_set_keypair(&conf->curve, privkey,
5575 privkey_len);
5576 else
5577 conf->csign = dpp_gen_keypair(conf->curve);
5578 if (!conf->csign)
5579 goto fail;
5580 conf->own = 1;
5581
5582 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
5583 if (!csign_pub) {
5584 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
5585 goto fail;
5586 }
5587
5588 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5589 addr[0] = wpabuf_head(csign_pub);
5590 len[0] = wpabuf_len(csign_pub);
5591 if (sha256_vector(1, addr, len, kid_hash) < 0) {
5592 wpa_printf(MSG_DEBUG,
5593 "DPP: Failed to derive kid for C-sign-key");
5594 goto fail;
5595 }
5596
5597 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
5598 NULL, 0);
5599 if (!conf->kid)
5600 goto fail;
5601out:
5602 wpabuf_free(csign_pub);
5603 return conf;
5604fail:
5605 dpp_configurator_free(conf);
5606 conf = NULL;
5607 goto out;
5608}
5609
5610
5611int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005612 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005613{
5614 struct wpabuf *conf_obj;
5615 int ret = -1;
5616
5617 if (!auth->conf) {
5618 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
5619 return -1;
5620 }
5621
5622 if (!curve) {
5623 auth->curve = &dpp_curves[0];
5624 } else {
5625 auth->curve = dpp_get_curve_name(curve);
5626 if (!auth->curve) {
5627 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5628 curve);
5629 return -1;
5630 }
5631 }
5632 wpa_printf(MSG_DEBUG,
5633 "DPP: Building own configuration/connector with curve %s",
5634 auth->curve->name);
5635
5636 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
5637 if (!auth->own_protocol_key)
5638 return -1;
5639 dpp_copy_netaccesskey(auth);
5640 auth->peer_protocol_key = auth->own_protocol_key;
5641 dpp_copy_csign(auth, auth->conf->csign);
5642
Roshan Pius3a1667e2018-07-03 15:17:14 -07005643 conf_obj = dpp_build_conf_obj(auth, ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005644 if (!conf_obj)
5645 goto fail;
5646 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
5647 wpabuf_len(conf_obj));
5648fail:
5649 wpabuf_free(conf_obj);
5650 auth->peer_protocol_key = NULL;
5651 return ret;
5652}
5653
5654
5655static int dpp_compatible_netrole(const char *role1, const char *role2)
5656{
5657 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
5658 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
5659}
5660
5661
5662static int dpp_connector_compatible_group(struct json_token *root,
5663 const char *group_id,
5664 const char *net_role)
5665{
5666 struct json_token *groups, *token;
5667
5668 groups = json_get_member(root, "groups");
5669 if (!groups || groups->type != JSON_ARRAY)
5670 return 0;
5671
5672 for (token = groups->child; token; token = token->sibling) {
5673 struct json_token *id, *role;
5674
5675 id = json_get_member(token, "groupId");
5676 if (!id || id->type != JSON_STRING)
5677 continue;
5678
5679 role = json_get_member(token, "netRole");
5680 if (!role || role->type != JSON_STRING)
5681 continue;
5682
5683 if (os_strcmp(id->string, "*") != 0 &&
5684 os_strcmp(group_id, "*") != 0 &&
5685 os_strcmp(id->string, group_id) != 0)
5686 continue;
5687
5688 if (dpp_compatible_netrole(role->string, net_role))
5689 return 1;
5690 }
5691
5692 return 0;
5693}
5694
5695
5696static int dpp_connector_match_groups(struct json_token *own_root,
5697 struct json_token *peer_root)
5698{
5699 struct json_token *groups, *token;
5700
5701 groups = json_get_member(peer_root, "groups");
5702 if (!groups || groups->type != JSON_ARRAY) {
5703 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
5704 return 0;
5705 }
5706
5707 for (token = groups->child; token; token = token->sibling) {
5708 struct json_token *id, *role;
5709
5710 id = json_get_member(token, "groupId");
5711 if (!id || id->type != JSON_STRING) {
5712 wpa_printf(MSG_DEBUG,
5713 "DPP: Missing peer groupId string");
5714 continue;
5715 }
5716
5717 role = json_get_member(token, "netRole");
5718 if (!role || role->type != JSON_STRING) {
5719 wpa_printf(MSG_DEBUG,
5720 "DPP: Missing peer groups::netRole string");
5721 continue;
5722 }
5723 wpa_printf(MSG_DEBUG,
5724 "DPP: peer connector group: groupId='%s' netRole='%s'",
5725 id->string, role->string);
5726 if (dpp_connector_compatible_group(own_root, id->string,
5727 role->string)) {
5728 wpa_printf(MSG_DEBUG,
5729 "DPP: Compatible group/netRole in own connector");
5730 return 1;
5731 }
5732 }
5733
5734 return 0;
5735}
5736
5737
5738static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
5739 unsigned int hash_len)
5740{
5741 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5742 const char *info = "DPP PMK";
5743 int res;
5744
5745 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5746
5747 /* HKDF-Extract(<>, N.x) */
5748 os_memset(salt, 0, hash_len);
5749 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
5750 return -1;
5751 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5752 prk, hash_len);
5753
5754 /* HKDF-Expand(PRK, info, L) */
5755 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
5756 os_memset(prk, 0, hash_len);
5757 if (res < 0)
5758 return -1;
5759
5760 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5761 pmk, hash_len);
5762 return 0;
5763}
5764
5765
5766static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
5767 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
5768{
5769 struct wpabuf *nkx, *pkx;
5770 int ret = -1, res;
5771 const u8 *addr[2];
5772 size_t len[2];
5773 u8 hash[SHA256_MAC_LEN];
5774
5775 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5776 nkx = dpp_get_pubkey_point(own_key, 0);
5777 pkx = dpp_get_pubkey_point(peer_key, 0);
5778 if (!nkx || !pkx)
5779 goto fail;
5780 addr[0] = wpabuf_head(nkx);
5781 len[0] = wpabuf_len(nkx) / 2;
5782 addr[1] = wpabuf_head(pkx);
5783 len[1] = wpabuf_len(pkx) / 2;
5784 if (len[0] != len[1])
5785 goto fail;
5786 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
5787 addr[0] = wpabuf_head(pkx);
5788 addr[1] = wpabuf_head(nkx);
5789 }
5790 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
5791 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
5792 res = sha256_vector(2, addr, len, hash);
5793 if (res < 0)
5794 goto fail;
5795 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
5796 os_memcpy(pmkid, hash, PMKID_LEN);
5797 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
5798 ret = 0;
5799fail:
5800 wpabuf_free(nkx);
5801 wpabuf_free(pkx);
5802 return ret;
5803}
5804
5805
Roshan Pius3a1667e2018-07-03 15:17:14 -07005806enum dpp_status_error
5807dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
5808 const u8 *net_access_key, size_t net_access_key_len,
5809 const u8 *csign_key, size_t csign_key_len,
5810 const u8 *peer_connector, size_t peer_connector_len,
5811 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005812{
5813 struct json_token *root = NULL, *netkey, *token;
5814 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005815 enum dpp_status_error ret = 255, res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005816 EVP_PKEY *own_key = NULL, *peer_key = NULL;
5817 struct wpabuf *own_key_pub = NULL;
5818 const struct dpp_curve_params *curve, *own_curve;
5819 struct dpp_signed_connector_info info;
5820 const unsigned char *p;
5821 EVP_PKEY *csign = NULL;
5822 char *signed_connector = NULL;
5823 const char *pos, *end;
5824 unsigned char *own_conn = NULL;
5825 size_t own_conn_len;
5826 EVP_PKEY_CTX *ctx = NULL;
5827 size_t Nx_len;
5828 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
5829
5830 os_memset(intro, 0, sizeof(*intro));
5831 os_memset(&info, 0, sizeof(info));
5832 if (expiry)
5833 *expiry = 0;
5834
5835 p = csign_key;
5836 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
5837 if (!csign) {
5838 wpa_printf(MSG_ERROR,
5839 "DPP: Failed to parse local C-sign-key information");
5840 goto fail;
5841 }
5842
5843 own_key = dpp_set_keypair(&own_curve, net_access_key,
5844 net_access_key_len);
5845 if (!own_key) {
5846 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
5847 goto fail;
5848 }
5849
5850 pos = os_strchr(own_connector, '.');
5851 if (!pos) {
5852 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
5853 goto fail;
5854 }
5855 pos++;
5856 end = os_strchr(pos, '.');
5857 if (!end) {
5858 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
5859 goto fail;
5860 }
5861 own_conn = base64_url_decode((const unsigned char *) pos,
5862 end - pos, &own_conn_len);
5863 if (!own_conn) {
5864 wpa_printf(MSG_DEBUG,
5865 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5866 goto fail;
5867 }
5868
5869 own_root = json_parse((const char *) own_conn, own_conn_len);
5870 if (!own_root) {
5871 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
5872 goto fail;
5873 }
5874
5875 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
5876 peer_connector, peer_connector_len);
5877 signed_connector = os_malloc(peer_connector_len + 1);
5878 if (!signed_connector)
5879 goto fail;
5880 os_memcpy(signed_connector, peer_connector, peer_connector_len);
5881 signed_connector[peer_connector_len] = '\0';
5882
Roshan Pius3a1667e2018-07-03 15:17:14 -07005883 res = dpp_process_signed_connector(&info, csign, signed_connector);
5884 if (res != DPP_STATUS_OK) {
5885 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005886 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005887 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005888
5889 root = json_parse((const char *) info.payload, info.payload_len);
5890 if (!root) {
5891 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005892 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005893 goto fail;
5894 }
5895
5896 if (!dpp_connector_match_groups(own_root, root)) {
5897 wpa_printf(MSG_DEBUG,
5898 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005899 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005900 goto fail;
5901 }
5902
5903 token = json_get_member(root, "expiry");
5904 if (!token || token->type != JSON_STRING) {
5905 wpa_printf(MSG_DEBUG,
5906 "DPP: No expiry string found - connector does not expire");
5907 } else {
5908 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5909 if (dpp_key_expired(token->string, expiry)) {
5910 wpa_printf(MSG_DEBUG,
5911 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005912 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005913 goto fail;
5914 }
5915 }
5916
5917 netkey = json_get_member(root, "netAccessKey");
5918 if (!netkey || netkey->type != JSON_OBJECT) {
5919 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005920 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005921 goto fail;
5922 }
5923
5924 peer_key = dpp_parse_jwk(netkey, &curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005925 if (!peer_key) {
5926 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005927 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005928 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005929 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
5930
5931 if (own_curve != curve) {
5932 wpa_printf(MSG_DEBUG,
5933 "DPP: Mismatching netAccessKey curves (%s != %s)",
5934 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005935 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005936 goto fail;
5937 }
5938
5939 /* ECDH: N = nk * PK */
5940 ctx = EVP_PKEY_CTX_new(own_key, NULL);
5941 if (!ctx ||
5942 EVP_PKEY_derive_init(ctx) != 1 ||
5943 EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
5944 EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
5945 Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
5946 EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
5947 wpa_printf(MSG_ERROR,
5948 "DPP: Failed to derive ECDH shared secret: %s",
5949 ERR_error_string(ERR_get_error(), NULL));
5950 goto fail;
5951 }
5952
5953 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
5954 Nx, Nx_len);
5955
5956 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5957 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
5958 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
5959 goto fail;
5960 }
5961 intro->pmk_len = curve->hash_len;
5962
5963 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5964 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
5965 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
5966 goto fail;
5967 }
5968
Roshan Pius3a1667e2018-07-03 15:17:14 -07005969 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005970fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07005971 if (ret != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005972 os_memset(intro, 0, sizeof(*intro));
5973 os_memset(Nx, 0, sizeof(Nx));
5974 EVP_PKEY_CTX_free(ctx);
5975 os_free(own_conn);
5976 os_free(signed_connector);
5977 os_free(info.payload);
5978 EVP_PKEY_free(own_key);
5979 wpabuf_free(own_key_pub);
5980 EVP_PKEY_free(peer_key);
5981 EVP_PKEY_free(csign);
5982 json_free(root);
5983 json_free(own_root);
5984 return ret;
5985}
5986
5987
5988static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
5989 int init)
5990{
5991 EC_GROUP *group;
5992 size_t len = curve->prime_len;
5993 const u8 *x, *y;
5994
5995 switch (curve->ike_group) {
5996 case 19:
5997 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
5998 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
5999 break;
6000 case 20:
6001 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
6002 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
6003 break;
6004 case 21:
6005 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
6006 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
6007 break;
6008 case 28:
6009 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
6010 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
6011 break;
6012 case 29:
6013 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
6014 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
6015 break;
6016 case 30:
6017 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
6018 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
6019 break;
6020 default:
6021 return NULL;
6022 }
6023
6024 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6025 if (!group)
6026 return NULL;
6027 return dpp_set_pubkey_point_group(group, x, y, len);
6028}
6029
6030
6031static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
6032 const u8 *mac_init, const char *code,
6033 const char *identifier, BN_CTX *bnctx,
6034 const EC_GROUP **ret_group)
6035{
6036 u8 hash[DPP_MAX_HASH_LEN];
6037 const u8 *addr[3];
6038 size_t len[3];
6039 unsigned int num_elem = 0;
6040 EC_POINT *Qi = NULL;
6041 EVP_PKEY *Pi = NULL;
6042 EC_KEY *Pi_ec = NULL;
6043 const EC_POINT *Pi_point;
6044 BIGNUM *hash_bn = NULL;
6045 const EC_GROUP *group = NULL;
6046 EC_GROUP *group2 = NULL;
6047
6048 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6049
6050 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
6051 addr[num_elem] = mac_init;
6052 len[num_elem] = ETH_ALEN;
6053 num_elem++;
6054 if (identifier) {
6055 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6056 identifier);
6057 addr[num_elem] = (const u8 *) identifier;
6058 len[num_elem] = os_strlen(identifier);
6059 num_elem++;
6060 }
6061 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
6062 addr[num_elem] = (const u8 *) code;
6063 len[num_elem] = os_strlen(code);
6064 num_elem++;
6065 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6066 goto fail;
6067 wpa_hexdump_key(MSG_DEBUG,
6068 "DPP: H(MAC-Initiator | [identifier |] code)",
6069 hash, curve->hash_len);
6070 Pi = dpp_pkex_get_role_elem(curve, 1);
6071 if (!Pi)
6072 goto fail;
6073 dpp_debug_print_key("DPP: Pi", Pi);
6074 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
6075 if (!Pi_ec)
6076 goto fail;
6077 Pi_point = EC_KEY_get0_public_key(Pi_ec);
6078
6079 group = EC_KEY_get0_group(Pi_ec);
6080 if (!group)
6081 goto fail;
6082 group2 = EC_GROUP_dup(group);
6083 if (!group2)
6084 goto fail;
6085 Qi = EC_POINT_new(group2);
6086 if (!Qi) {
6087 EC_GROUP_free(group2);
6088 goto fail;
6089 }
6090 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6091 if (!hash_bn ||
6092 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
6093 goto fail;
6094 if (EC_POINT_is_at_infinity(group, Qi)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006095 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006096 goto fail;
6097 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07006098 dpp_debug_print_point("DPP: Qi", group, Qi);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006099out:
6100 EC_KEY_free(Pi_ec);
6101 EVP_PKEY_free(Pi);
6102 BN_clear_free(hash_bn);
6103 if (ret_group)
6104 *ret_group = group2;
6105 return Qi;
6106fail:
6107 EC_POINT_free(Qi);
6108 Qi = NULL;
6109 goto out;
6110}
6111
6112
6113static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
6114 const u8 *mac_resp, const char *code,
6115 const char *identifier, BN_CTX *bnctx,
6116 const EC_GROUP **ret_group)
6117{
6118 u8 hash[DPP_MAX_HASH_LEN];
6119 const u8 *addr[3];
6120 size_t len[3];
6121 unsigned int num_elem = 0;
6122 EC_POINT *Qr = NULL;
6123 EVP_PKEY *Pr = NULL;
6124 EC_KEY *Pr_ec = NULL;
6125 const EC_POINT *Pr_point;
6126 BIGNUM *hash_bn = NULL;
6127 const EC_GROUP *group = NULL;
6128 EC_GROUP *group2 = NULL;
6129
6130 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6131
6132 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
6133 addr[num_elem] = mac_resp;
6134 len[num_elem] = ETH_ALEN;
6135 num_elem++;
6136 if (identifier) {
6137 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6138 identifier);
6139 addr[num_elem] = (const u8 *) identifier;
6140 len[num_elem] = os_strlen(identifier);
6141 num_elem++;
6142 }
6143 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
6144 addr[num_elem] = (const u8 *) code;
6145 len[num_elem] = os_strlen(code);
6146 num_elem++;
6147 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6148 goto fail;
6149 wpa_hexdump_key(MSG_DEBUG,
6150 "DPP: H(MAC-Responder | [identifier |] code)",
6151 hash, curve->hash_len);
6152 Pr = dpp_pkex_get_role_elem(curve, 0);
6153 if (!Pr)
6154 goto fail;
6155 dpp_debug_print_key("DPP: Pr", Pr);
6156 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
6157 if (!Pr_ec)
6158 goto fail;
6159 Pr_point = EC_KEY_get0_public_key(Pr_ec);
6160
6161 group = EC_KEY_get0_group(Pr_ec);
6162 if (!group)
6163 goto fail;
6164 group2 = EC_GROUP_dup(group);
6165 if (!group2)
6166 goto fail;
6167 Qr = EC_POINT_new(group2);
6168 if (!Qr) {
6169 EC_GROUP_free(group2);
6170 goto fail;
6171 }
6172 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6173 if (!hash_bn ||
6174 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
6175 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006176 if (EC_POINT_is_at_infinity(group, Qr)) {
6177 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
6178 goto fail;
6179 }
6180 dpp_debug_print_point("DPP: Qr", group, Qr);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006181out:
6182 EC_KEY_free(Pr_ec);
6183 EVP_PKEY_free(Pr);
6184 BN_clear_free(hash_bn);
6185 if (ret_group)
6186 *ret_group = group2;
6187 return Qr;
6188fail:
6189 EC_POINT_free(Qr);
6190 Qr = NULL;
6191 goto out;
6192}
6193
6194
Roshan Pius3a1667e2018-07-03 15:17:14 -07006195#ifdef CONFIG_TESTING_OPTIONS
6196static int dpp_test_gen_invalid_key(struct wpabuf *msg,
6197 const struct dpp_curve_params *curve)
6198{
6199 BN_CTX *ctx;
6200 BIGNUM *x, *y;
6201 int ret = -1;
6202 EC_GROUP *group;
6203 EC_POINT *point;
6204
6205 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6206 if (!group)
6207 return -1;
6208
6209 ctx = BN_CTX_new();
6210 point = EC_POINT_new(group);
6211 x = BN_new();
6212 y = BN_new();
6213 if (!ctx || !point || !x || !y)
6214 goto fail;
6215
6216 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
6217 goto fail;
6218
6219 /* Generate a random y coordinate that results in a point that is not
6220 * on the curve. */
6221 for (;;) {
6222 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
6223 goto fail;
6224
6225 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
6226 ctx) != 1) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006227#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006228 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6229 * return an error from EC_POINT_set_affine_coordinates_GFp()
6230 * when the point is not on the curve. */
6231 break;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006232#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006233 goto fail;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006234#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006235 }
6236
6237 if (!EC_POINT_is_on_curve(group, point, ctx))
6238 break;
6239 }
6240
6241 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
6242 curve->prime_len) < 0 ||
6243 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
6244 curve->prime_len) < 0)
6245 goto fail;
6246
6247 ret = 0;
6248fail:
6249 if (ret < 0)
6250 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
6251 BN_free(x);
6252 BN_free(y);
6253 EC_POINT_free(point);
6254 BN_CTX_free(ctx);
6255
6256 return ret;
6257}
6258#endif /* CONFIG_TESTING_OPTIONS */
6259
6260
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006261static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
6262{
6263 EC_KEY *X_ec = NULL;
6264 const EC_POINT *X_point;
6265 BN_CTX *bnctx = NULL;
6266 const EC_GROUP *group;
6267 EC_POINT *Qi = NULL, *M = NULL;
6268 struct wpabuf *M_buf = NULL;
6269 BIGNUM *Mx = NULL, *My = NULL;
6270 struct wpabuf *msg = NULL;
6271 size_t attr_len;
6272 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006273
6274 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
6275
6276 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6277 bnctx = BN_CTX_new();
6278 if (!bnctx)
6279 goto fail;
6280 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
6281 pkex->identifier, bnctx, &group);
6282 if (!Qi)
6283 goto fail;
6284
6285 /* Generate a random ephemeral keypair x/X */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006286#ifdef CONFIG_TESTING_OPTIONS
6287 if (dpp_pkex_ephemeral_key_override_len) {
6288 const struct dpp_curve_params *tmp_curve;
6289
6290 wpa_printf(MSG_INFO,
6291 "DPP: TESTING - override ephemeral key x/X");
6292 pkex->x = dpp_set_keypair(&tmp_curve,
6293 dpp_pkex_ephemeral_key_override,
6294 dpp_pkex_ephemeral_key_override_len);
6295 } else {
6296 pkex->x = dpp_gen_keypair(curve);
6297 }
6298#else /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006299 pkex->x = dpp_gen_keypair(curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006300#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006301 if (!pkex->x)
6302 goto fail;
6303
6304 /* M = X + Qi */
6305 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
6306 if (!X_ec)
6307 goto fail;
6308 X_point = EC_KEY_get0_public_key(X_ec);
6309 if (!X_point)
6310 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006311 dpp_debug_print_point("DPP: X", group, X_point);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006312 M = EC_POINT_new(group);
6313 Mx = BN_new();
6314 My = BN_new();
6315 if (!M || !Mx || !My ||
6316 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
6317 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
6318 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006319 dpp_debug_print_point("DPP: M", group, M);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006320
6321 /* Initiator -> Responder: group, [identifier,] M */
6322 attr_len = 4 + 2;
6323 if (pkex->identifier)
6324 attr_len += 4 + os_strlen(pkex->identifier);
6325 attr_len += 4 + 2 * curve->prime_len;
6326 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
6327 if (!msg)
6328 goto fail;
6329
Roshan Pius3a1667e2018-07-03 15:17:14 -07006330#ifdef CONFIG_TESTING_OPTIONS
6331 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
6332 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
6333 goto skip_finite_cyclic_group;
6334 }
6335#endif /* CONFIG_TESTING_OPTIONS */
6336
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006337 /* Finite Cyclic Group attribute */
6338 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6339 wpabuf_put_le16(msg, 2);
6340 wpabuf_put_le16(msg, curve->ike_group);
6341
Roshan Pius3a1667e2018-07-03 15:17:14 -07006342#ifdef CONFIG_TESTING_OPTIONS
6343skip_finite_cyclic_group:
6344#endif /* CONFIG_TESTING_OPTIONS */
6345
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006346 /* Code Identifier attribute */
6347 if (pkex->identifier) {
6348 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6349 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6350 wpabuf_put_str(msg, pkex->identifier);
6351 }
6352
Roshan Pius3a1667e2018-07-03 15:17:14 -07006353#ifdef CONFIG_TESTING_OPTIONS
6354 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6355 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6356 goto out;
6357 }
6358#endif /* CONFIG_TESTING_OPTIONS */
6359
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006360 /* M in Encrypted Key attribute */
6361 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6362 wpabuf_put_le16(msg, 2 * curve->prime_len);
6363
Roshan Pius3a1667e2018-07-03 15:17:14 -07006364#ifdef CONFIG_TESTING_OPTIONS
6365 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6366 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
6367 if (dpp_test_gen_invalid_key(msg, curve) < 0)
6368 goto fail;
6369 goto out;
6370 }
6371#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006372
Roshan Pius3a1667e2018-07-03 15:17:14 -07006373 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
6374 curve->prime_len) < 0 ||
6375 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
6376 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
6377 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006378 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006379
6380out:
6381 wpabuf_free(M_buf);
6382 EC_KEY_free(X_ec);
6383 EC_POINT_free(M);
6384 EC_POINT_free(Qi);
6385 BN_clear_free(Mx);
6386 BN_clear_free(My);
6387 BN_CTX_free(bnctx);
6388 return msg;
6389fail:
6390 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
6391 wpabuf_free(msg);
6392 msg = NULL;
6393 goto out;
6394}
6395
6396
Roshan Pius3a1667e2018-07-03 15:17:14 -07006397static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
6398{
6399 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
6400}
6401
6402
6403struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006404 const u8 *own_mac,
6405 const char *identifier,
6406 const char *code)
6407{
6408 struct dpp_pkex *pkex;
6409
Roshan Pius3a1667e2018-07-03 15:17:14 -07006410#ifdef CONFIG_TESTING_OPTIONS
6411 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
6412 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
6413 MAC2STR(dpp_pkex_own_mac_override));
6414 own_mac = dpp_pkex_own_mac_override;
6415 }
6416#endif /* CONFIG_TESTING_OPTIONS */
6417
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006418 pkex = os_zalloc(sizeof(*pkex));
6419 if (!pkex)
6420 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006421 pkex->msg_ctx = msg_ctx;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006422 pkex->initiator = 1;
6423 pkex->own_bi = bi;
6424 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6425 if (identifier) {
6426 pkex->identifier = os_strdup(identifier);
6427 if (!pkex->identifier)
6428 goto fail;
6429 }
6430 pkex->code = os_strdup(code);
6431 if (!pkex->code)
6432 goto fail;
6433 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
6434 if (!pkex->exchange_req)
6435 goto fail;
6436 return pkex;
6437fail:
6438 dpp_pkex_free(pkex);
6439 return NULL;
6440}
6441
6442
Roshan Pius3a1667e2018-07-03 15:17:14 -07006443static struct wpabuf *
6444dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
6445 enum dpp_status_error status,
6446 const BIGNUM *Nx, const BIGNUM *Ny)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006447{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006448 struct wpabuf *msg = NULL;
6449 size_t attr_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006450 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006451
6452 /* Initiator -> Responder: DPP Status, [identifier,] N */
6453 attr_len = 4 + 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006454 if (pkex->identifier)
6455 attr_len += 4 + os_strlen(pkex->identifier);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006456 attr_len += 4 + 2 * curve->prime_len;
6457 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
6458 if (!msg)
6459 goto fail;
6460
Roshan Pius3a1667e2018-07-03 15:17:14 -07006461#ifdef CONFIG_TESTING_OPTIONS
6462 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
6463 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
6464 goto skip_status;
6465 }
6466
6467 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
6468 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
6469 status = 255;
6470 }
6471#endif /* CONFIG_TESTING_OPTIONS */
6472
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006473 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006474 dpp_build_attr_status(msg, status);
6475
6476#ifdef CONFIG_TESTING_OPTIONS
6477skip_status:
6478#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006479
6480 /* Code Identifier attribute */
6481 if (pkex->identifier) {
6482 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6483 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6484 wpabuf_put_str(msg, pkex->identifier);
6485 }
6486
Roshan Pius3a1667e2018-07-03 15:17:14 -07006487 if (status != DPP_STATUS_OK)
6488 goto skip_encrypted_key;
6489
6490#ifdef CONFIG_TESTING_OPTIONS
6491 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
6492 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6493 goto skip_encrypted_key;
6494 }
6495#endif /* CONFIG_TESTING_OPTIONS */
6496
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006497 /* N in Encrypted Key attribute */
6498 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6499 wpabuf_put_le16(msg, 2 * curve->prime_len);
6500
Roshan Pius3a1667e2018-07-03 15:17:14 -07006501#ifdef CONFIG_TESTING_OPTIONS
6502 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
6503 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
6504 if (dpp_test_gen_invalid_key(msg, curve) < 0)
6505 goto fail;
6506 goto skip_encrypted_key;
6507 }
6508#endif /* CONFIG_TESTING_OPTIONS */
6509
6510 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
6511 curve->prime_len) < 0 ||
6512 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
6513 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
6514 curve->prime_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006515 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006516
Roshan Pius3a1667e2018-07-03 15:17:14 -07006517skip_encrypted_key:
6518 if (status == DPP_STATUS_BAD_GROUP) {
6519 /* Finite Cyclic Group attribute */
6520 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6521 wpabuf_put_le16(msg, 2);
6522 wpabuf_put_le16(msg, curve->ike_group);
6523 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006524
Roshan Pius3a1667e2018-07-03 15:17:14 -07006525 return msg;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006526fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07006527 wpabuf_free(msg);
6528 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006529}
6530
6531
6532static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
6533 const u8 *Mx, size_t Mx_len,
6534 const u8 *Nx, size_t Nx_len,
6535 const char *code,
6536 const u8 *Kx, size_t Kx_len,
6537 u8 *z, unsigned int hash_len)
6538{
6539 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6540 int res;
6541 u8 *info, *pos;
6542 size_t info_len;
6543
6544 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6545 */
6546
6547 /* HKDF-Extract(<>, IKM=K.x) */
6548 os_memset(salt, 0, hash_len);
6549 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
6550 return -1;
6551 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
6552 prk, hash_len);
6553 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
6554 info = os_malloc(info_len);
6555 if (!info)
6556 return -1;
6557 pos = info;
6558 os_memcpy(pos, mac_init, ETH_ALEN);
6559 pos += ETH_ALEN;
6560 os_memcpy(pos, mac_resp, ETH_ALEN);
6561 pos += ETH_ALEN;
6562 os_memcpy(pos, Mx, Mx_len);
6563 pos += Mx_len;
6564 os_memcpy(pos, Nx, Nx_len);
6565 pos += Nx_len;
6566 os_memcpy(pos, code, os_strlen(code));
6567
6568 /* HKDF-Expand(PRK, info, L) */
6569 if (hash_len == 32)
6570 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
6571 z, hash_len);
6572 else if (hash_len == 48)
6573 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
6574 z, hash_len);
6575 else if (hash_len == 64)
6576 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
6577 z, hash_len);
6578 else
6579 res = -1;
6580 os_free(info);
6581 os_memset(prk, 0, hash_len);
6582 if (res < 0)
6583 return -1;
6584
6585 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
6586 z, hash_len);
6587 return 0;
6588}
6589
6590
Hai Shalom39bc25d2019-02-06 16:32:13 -08006591static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
6592 const char *identifier)
6593{
6594 if (!attr_id && identifier) {
6595 wpa_printf(MSG_DEBUG,
6596 "DPP: No PKEX code identifier received, but expected one");
6597 return 0;
6598 }
6599
6600 if (attr_id && !identifier) {
6601 wpa_printf(MSG_DEBUG,
6602 "DPP: PKEX code identifier received, but not expecting one");
6603 return 0;
6604 }
6605
6606 if (attr_id && identifier &&
6607 (os_strlen(identifier) != attr_id_len ||
6608 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
6609 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
6610 return 0;
6611 }
6612
6613 return 1;
6614}
6615
6616
Roshan Pius3a1667e2018-07-03 15:17:14 -07006617struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
6618 struct dpp_bootstrap_info *bi,
6619 const u8 *own_mac,
6620 const u8 *peer_mac,
6621 const char *identifier,
6622 const char *code,
6623 const u8 *buf, size_t len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006624{
Roshan Pius3a1667e2018-07-03 15:17:14 -07006625 const u8 *attr_group, *attr_id, *attr_key;
6626 u16 attr_group_len, attr_id_len, attr_key_len;
6627 const struct dpp_curve_params *curve = bi->curve;
6628 u16 ike_group;
6629 struct dpp_pkex *pkex = NULL;
6630 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006631 BN_CTX *bnctx = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006632 const EC_GROUP *group;
6633 BIGNUM *Mx = NULL, *My = NULL;
6634 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
6635 const EC_POINT *Y_point;
6636 BIGNUM *Nx = NULL, *Ny = NULL;
6637 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
6638 size_t Kx_len;
6639 int res;
6640 EVP_PKEY_CTX *ctx = NULL;
6641
6642 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
6643 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6644 "PKEX counter t limit reached - ignore message");
6645 return NULL;
6646 }
6647
6648#ifdef CONFIG_TESTING_OPTIONS
6649 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
6650 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
6651 MAC2STR(dpp_pkex_peer_mac_override));
6652 peer_mac = dpp_pkex_peer_mac_override;
6653 }
6654 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
6655 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
6656 MAC2STR(dpp_pkex_own_mac_override));
6657 own_mac = dpp_pkex_own_mac_override;
6658 }
6659#endif /* CONFIG_TESTING_OPTIONS */
6660
Hai Shalom39bc25d2019-02-06 16:32:13 -08006661 attr_id_len = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006662 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
6663 &attr_id_len);
Hai Shalom39bc25d2019-02-06 16:32:13 -08006664 if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
Roshan Pius3a1667e2018-07-03 15:17:14 -07006665 return NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006666
6667 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
6668 &attr_group_len);
6669 if (!attr_group || attr_group_len != 2) {
6670 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6671 "Missing or invalid Finite Cyclic Group attribute");
6672 return NULL;
6673 }
6674 ike_group = WPA_GET_LE16(attr_group);
6675 if (ike_group != curve->ike_group) {
6676 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6677 "Mismatching PKEX curve: peer=%u own=%u",
6678 ike_group, curve->ike_group);
6679 pkex = os_zalloc(sizeof(*pkex));
6680 if (!pkex)
6681 goto fail;
6682 pkex->own_bi = bi;
6683 pkex->failed = 1;
6684 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
6685 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
6686 if (!pkex->exchange_resp)
6687 goto fail;
6688 return pkex;
6689 }
6690
6691 /* M in Encrypted Key attribute */
6692 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
6693 &attr_key_len);
6694 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
6695 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
6696 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6697 "Missing Encrypted Key attribute");
6698 return NULL;
6699 }
6700
6701 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6702 bnctx = BN_CTX_new();
6703 if (!bnctx)
6704 goto fail;
6705 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
6706 &group);
6707 if (!Qi)
6708 goto fail;
6709
6710 /* X' = M - Qi */
6711 X = EC_POINT_new(group);
6712 M = EC_POINT_new(group);
6713 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
6714 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
6715 if (!X || !M || !Mx || !My ||
6716 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
6717 EC_POINT_is_at_infinity(group, M) ||
6718 !EC_POINT_is_on_curve(group, M, bnctx) ||
6719 EC_POINT_invert(group, Qi, bnctx) != 1 ||
6720 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
6721 EC_POINT_is_at_infinity(group, X) ||
6722 !EC_POINT_is_on_curve(group, X, bnctx)) {
6723 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
6724 "Invalid Encrypted Key value");
6725 bi->pkex_t++;
6726 goto fail;
6727 }
6728 dpp_debug_print_point("DPP: M", group, M);
6729 dpp_debug_print_point("DPP: X'", group, X);
6730
6731 pkex = os_zalloc(sizeof(*pkex));
6732 if (!pkex)
6733 goto fail;
6734 pkex->t = bi->pkex_t;
6735 pkex->msg_ctx = msg_ctx;
6736 pkex->own_bi = bi;
6737 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
6738 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
6739 if (identifier) {
6740 pkex->identifier = os_strdup(identifier);
6741 if (!pkex->identifier)
6742 goto fail;
6743 }
6744 pkex->code = os_strdup(code);
6745 if (!pkex->code)
6746 goto fail;
6747
6748 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
6749
6750 X_ec = EC_KEY_new();
6751 if (!X_ec ||
6752 EC_KEY_set_group(X_ec, group) != 1 ||
6753 EC_KEY_set_public_key(X_ec, X) != 1)
6754 goto fail;
6755 pkex->x = EVP_PKEY_new();
6756 if (!pkex->x ||
6757 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
6758 goto fail;
6759
6760 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6761 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
6762 if (!Qr)
6763 goto fail;
6764
6765 /* Generate a random ephemeral keypair y/Y */
6766#ifdef CONFIG_TESTING_OPTIONS
6767 if (dpp_pkex_ephemeral_key_override_len) {
6768 const struct dpp_curve_params *tmp_curve;
6769
6770 wpa_printf(MSG_INFO,
6771 "DPP: TESTING - override ephemeral key y/Y");
6772 pkex->y = dpp_set_keypair(&tmp_curve,
6773 dpp_pkex_ephemeral_key_override,
6774 dpp_pkex_ephemeral_key_override_len);
6775 } else {
6776 pkex->y = dpp_gen_keypair(curve);
6777 }
6778#else /* CONFIG_TESTING_OPTIONS */
6779 pkex->y = dpp_gen_keypair(curve);
6780#endif /* CONFIG_TESTING_OPTIONS */
6781 if (!pkex->y)
6782 goto fail;
6783
6784 /* N = Y + Qr */
6785 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
6786 if (!Y_ec)
6787 goto fail;
6788 Y_point = EC_KEY_get0_public_key(Y_ec);
6789 if (!Y_point)
6790 goto fail;
6791 dpp_debug_print_point("DPP: Y", group, Y_point);
6792 N = EC_POINT_new(group);
6793 Nx = BN_new();
6794 Ny = BN_new();
6795 if (!N || !Nx || !Ny ||
6796 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
6797 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
6798 goto fail;
6799 dpp_debug_print_point("DPP: N", group, N);
6800
6801 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
6802 Nx, Ny);
6803 if (!pkex->exchange_resp)
6804 goto fail;
6805
6806 /* K = y * X' */
6807 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
6808 if (!ctx ||
6809 EVP_PKEY_derive_init(ctx) != 1 ||
6810 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
6811 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
6812 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
6813 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
6814 wpa_printf(MSG_ERROR,
6815 "DPP: Failed to derive ECDH shared secret: %s",
6816 ERR_error_string(ERR_get_error(), NULL));
6817 goto fail;
6818 }
6819
6820 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
6821 Kx, Kx_len);
6822
6823 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
6824 */
6825 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
6826 pkex->Mx, curve->prime_len,
6827 pkex->Nx, curve->prime_len, pkex->code,
6828 Kx, Kx_len, pkex->z, curve->hash_len);
6829 os_memset(Kx, 0, Kx_len);
6830 if (res < 0)
6831 goto fail;
6832
6833 pkex->exchange_done = 1;
6834
6835out:
6836 EVP_PKEY_CTX_free(ctx);
6837 BN_CTX_free(bnctx);
6838 EC_POINT_free(Qi);
6839 EC_POINT_free(Qr);
6840 BN_free(Mx);
6841 BN_free(My);
6842 BN_free(Nx);
6843 BN_free(Ny);
6844 EC_POINT_free(M);
6845 EC_POINT_free(N);
6846 EC_POINT_free(X);
6847 EC_KEY_free(X_ec);
6848 EC_KEY_free(Y_ec);
6849 return pkex;
6850fail:
6851 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
6852 dpp_pkex_free(pkex);
6853 pkex = NULL;
6854 goto out;
6855}
6856
6857
6858static struct wpabuf *
6859dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
6860 const struct wpabuf *A_pub, const u8 *u)
6861{
6862 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6863 struct wpabuf *msg = NULL;
6864 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006865 struct wpabuf *clear = NULL;
6866 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006867 u8 octet;
6868 const u8 *addr[2];
6869 size_t len[2];
6870
6871 /* {A, u, [bootstrapping info]}z */
6872 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
6873 clear = wpabuf_alloc(clear_len);
6874 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6875#ifdef CONFIG_TESTING_OPTIONS
6876 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
6877 attr_len += 5;
6878#endif /* CONFIG_TESTING_OPTIONS */
6879 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
6880 if (!clear || !msg)
6881 goto fail;
6882
6883#ifdef CONFIG_TESTING_OPTIONS
6884 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
6885 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
6886 goto skip_bootstrap_key;
6887 }
6888 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
6889 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
6890 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6891 wpabuf_put_le16(clear, 2 * curve->prime_len);
6892 if (dpp_test_gen_invalid_key(clear, curve) < 0)
6893 goto fail;
6894 goto skip_bootstrap_key;
6895 }
6896#endif /* CONFIG_TESTING_OPTIONS */
6897
6898 /* A in Bootstrap Key attribute */
6899 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
6900 wpabuf_put_le16(clear, wpabuf_len(A_pub));
6901 wpabuf_put_buf(clear, A_pub);
6902
6903#ifdef CONFIG_TESTING_OPTIONS
6904skip_bootstrap_key:
6905 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
6906 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
6907 goto skip_i_auth_tag;
6908 }
6909 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
6910 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
6911 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
6912 wpabuf_put_le16(clear, curve->hash_len);
6913 wpabuf_put_data(clear, u, curve->hash_len - 1);
6914 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
6915 goto skip_i_auth_tag;
6916 }
6917#endif /* CONFIG_TESTING_OPTIONS */
6918
6919 /* u in I-Auth tag attribute */
6920 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
6921 wpabuf_put_le16(clear, curve->hash_len);
6922 wpabuf_put_data(clear, u, curve->hash_len);
6923
6924#ifdef CONFIG_TESTING_OPTIONS
6925skip_i_auth_tag:
6926 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
6927 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
6928 goto skip_wrapped_data;
6929 }
6930#endif /* CONFIG_TESTING_OPTIONS */
6931
6932 addr[0] = wpabuf_head_u8(msg) + 2;
6933 len[0] = DPP_HDR_LEN;
6934 octet = 0;
6935 addr[1] = &octet;
6936 len[1] = sizeof(octet);
6937 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6938 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6939
6940 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6941 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6942 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6943
6944 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6945 if (aes_siv_encrypt(pkex->z, curve->hash_len,
6946 wpabuf_head(clear), wpabuf_len(clear),
6947 2, addr, len, wrapped) < 0)
6948 goto fail;
6949 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6950 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
6951
6952#ifdef CONFIG_TESTING_OPTIONS
6953 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
6954 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
6955 dpp_build_attr_status(msg, DPP_STATUS_OK);
6956 }
6957skip_wrapped_data:
6958#endif /* CONFIG_TESTING_OPTIONS */
6959
6960out:
6961 wpabuf_free(clear);
6962 return msg;
6963
6964fail:
6965 wpabuf_free(msg);
6966 msg = NULL;
6967 goto out;
6968}
6969
6970
6971struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
6972 const u8 *peer_mac,
6973 const u8 *buf, size_t buflen)
6974{
6975 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
6976 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
6977 const EC_GROUP *group;
6978 BN_CTX *bnctx = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006979 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
6980 const struct dpp_curve_params *curve = pkex->own_bi->curve;
6981 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
6982 BIGNUM *Nx = NULL, *Ny = NULL;
6983 EVP_PKEY_CTX *ctx = NULL;
6984 EC_KEY *Y_ec = NULL;
6985 size_t Jx_len, Kx_len;
6986 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
6987 const u8 *addr[4];
6988 size_t len[4];
6989 u8 u[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006990 int res;
6991
Roshan Pius3a1667e2018-07-03 15:17:14 -07006992 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
6993 return NULL;
6994
6995#ifdef CONFIG_TESTING_OPTIONS
6996 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
6997 wpa_printf(MSG_INFO,
6998 "DPP: TESTING - stop at PKEX Exchange Response");
6999 pkex->failed = 1;
7000 return NULL;
7001 }
7002
7003 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
7004 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
7005 MAC2STR(dpp_pkex_peer_mac_override));
7006 peer_mac = dpp_pkex_peer_mac_override;
7007 }
7008#endif /* CONFIG_TESTING_OPTIONS */
7009
7010 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
7011
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007012 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
7013 &attr_status_len);
7014 if (!attr_status || attr_status_len != 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007015 dpp_pkex_fail(pkex, "No DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007016 return NULL;
7017 }
7018 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007019
7020 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
7021 attr_group = dpp_get_attr(buf, buflen,
7022 DPP_ATTR_FINITE_CYCLIC_GROUP,
7023 &attr_group_len);
7024 if (attr_group && attr_group_len == 2) {
7025 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7026 "Peer indicated mismatching PKEX group - proposed %u",
7027 WPA_GET_LE16(attr_group));
7028 return NULL;
7029 }
7030 }
7031
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007032 if (attr_status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007033 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007034 return NULL;
7035 }
7036
Hai Shalom39bc25d2019-02-06 16:32:13 -08007037 attr_id_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007038 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
7039 &attr_id_len);
Hai Shalom39bc25d2019-02-06 16:32:13 -08007040 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
7041 pkex->identifier)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007042 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007043 return NULL;
7044 }
7045
7046 /* N in Encrypted Key attribute */
7047 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
7048 &attr_key_len);
7049 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007050 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007051 return NULL;
7052 }
7053
7054 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7055 bnctx = BN_CTX_new();
7056 if (!bnctx)
7057 goto fail;
7058 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
7059 pkex->identifier, bnctx, &group);
7060 if (!Qr)
7061 goto fail;
7062
7063 /* Y' = N - Qr */
7064 Y = EC_POINT_new(group);
7065 N = EC_POINT_new(group);
7066 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
7067 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
7068 if (!Y || !N || !Nx || !Ny ||
7069 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
7070 EC_POINT_is_at_infinity(group, N) ||
7071 !EC_POINT_is_on_curve(group, N, bnctx) ||
7072 EC_POINT_invert(group, Qr, bnctx) != 1 ||
7073 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
7074 EC_POINT_is_at_infinity(group, Y) ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07007075 !EC_POINT_is_on_curve(group, Y, bnctx)) {
7076 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
7077 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007078 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007079 }
7080 dpp_debug_print_point("DPP: N", group, N);
7081 dpp_debug_print_point("DPP: Y'", group, Y);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007082
7083 pkex->exchange_done = 1;
7084
7085 /* ECDH: J = a * Y’ */
7086 Y_ec = EC_KEY_new();
7087 if (!Y_ec ||
7088 EC_KEY_set_group(Y_ec, group) != 1 ||
7089 EC_KEY_set_public_key(Y_ec, Y) != 1)
7090 goto fail;
7091 pkex->y = EVP_PKEY_new();
7092 if (!pkex->y ||
7093 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
7094 goto fail;
7095 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7096 if (!ctx ||
7097 EVP_PKEY_derive_init(ctx) != 1 ||
7098 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
7099 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
7100 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
7101 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
7102 wpa_printf(MSG_ERROR,
7103 "DPP: Failed to derive ECDH shared secret: %s",
7104 ERR_error_string(ERR_get_error(), NULL));
7105 goto fail;
7106 }
7107
7108 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7109 Jx, Jx_len);
7110
7111 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7112 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
7113 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7114 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7115 if (!A_pub || !Y_pub || !X_pub)
7116 goto fail;
7117 addr[0] = pkex->own_mac;
7118 len[0] = ETH_ALEN;
7119 addr[1] = wpabuf_head(A_pub);
7120 len[1] = wpabuf_len(A_pub) / 2;
7121 addr[2] = wpabuf_head(Y_pub);
7122 len[2] = wpabuf_len(Y_pub) / 2;
7123 addr[3] = wpabuf_head(X_pub);
7124 len[3] = wpabuf_len(X_pub) / 2;
7125 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
7126 goto fail;
7127 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
7128
7129 /* K = x * Y’ */
7130 EVP_PKEY_CTX_free(ctx);
7131 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
7132 if (!ctx ||
7133 EVP_PKEY_derive_init(ctx) != 1 ||
7134 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
7135 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
7136 Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
7137 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
7138 wpa_printf(MSG_ERROR,
7139 "DPP: Failed to derive ECDH shared secret: %s",
7140 ERR_error_string(ERR_get_error(), NULL));
7141 goto fail;
7142 }
7143
7144 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7145 Kx, Kx_len);
7146
7147 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7148 */
7149 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
7150 pkex->Mx, curve->prime_len,
7151 attr_key /* N.x */, attr_key_len / 2,
7152 pkex->code, Kx, Kx_len,
7153 pkex->z, curve->hash_len);
7154 os_memset(Kx, 0, Kx_len);
7155 if (res < 0)
7156 goto fail;
7157
Roshan Pius3a1667e2018-07-03 15:17:14 -07007158 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
7159 if (!msg)
7160 goto fail;
7161
7162out:
7163 wpabuf_free(A_pub);
7164 wpabuf_free(X_pub);
7165 wpabuf_free(Y_pub);
7166 EC_POINT_free(Qr);
7167 EC_POINT_free(Y);
7168 EC_POINT_free(N);
7169 BN_free(Nx);
7170 BN_free(Ny);
7171 EC_KEY_free(Y_ec);
7172 EVP_PKEY_CTX_free(ctx);
7173 BN_CTX_free(bnctx);
7174 return msg;
7175fail:
7176 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
7177 goto out;
7178}
7179
7180
7181static struct wpabuf *
7182dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
7183 const struct wpabuf *B_pub, const u8 *v)
7184{
7185 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7186 struct wpabuf *msg = NULL;
7187 const u8 *addr[2];
7188 size_t len[2];
7189 u8 octet;
7190 u8 *wrapped;
7191 struct wpabuf *clear = NULL;
7192 size_t clear_len, attr_len;
7193
7194 /* {B, v [bootstrapping info]}z */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007195 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
7196 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007197 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7198#ifdef CONFIG_TESTING_OPTIONS
7199 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
7200 attr_len += 5;
7201#endif /* CONFIG_TESTING_OPTIONS */
7202 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007203 if (!clear || !msg)
7204 goto fail;
7205
Roshan Pius3a1667e2018-07-03 15:17:14 -07007206#ifdef CONFIG_TESTING_OPTIONS
7207 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
7208 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
7209 goto skip_bootstrap_key;
7210 }
7211 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
7212 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
7213 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7214 wpabuf_put_le16(clear, 2 * curve->prime_len);
7215 if (dpp_test_gen_invalid_key(clear, curve) < 0)
7216 goto fail;
7217 goto skip_bootstrap_key;
7218 }
7219#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007220
Roshan Pius3a1667e2018-07-03 15:17:14 -07007221 /* B in Bootstrap Key attribute */
7222 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7223 wpabuf_put_le16(clear, wpabuf_len(B_pub));
7224 wpabuf_put_buf(clear, B_pub);
7225
7226#ifdef CONFIG_TESTING_OPTIONS
7227skip_bootstrap_key:
7228 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
7229 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
7230 goto skip_r_auth_tag;
7231 }
7232 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
7233 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
7234 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
7235 wpabuf_put_le16(clear, curve->hash_len);
7236 wpabuf_put_data(clear, v, curve->hash_len - 1);
7237 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
7238 goto skip_r_auth_tag;
7239 }
7240#endif /* CONFIG_TESTING_OPTIONS */
7241
7242 /* v in R-Auth tag attribute */
7243 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007244 wpabuf_put_le16(clear, curve->hash_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007245 wpabuf_put_data(clear, v, curve->hash_len);
7246
7247#ifdef CONFIG_TESTING_OPTIONS
7248skip_r_auth_tag:
7249 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
7250 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
7251 goto skip_wrapped_data;
7252 }
7253#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007254
7255 addr[0] = wpabuf_head_u8(msg) + 2;
7256 len[0] = DPP_HDR_LEN;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007257 octet = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007258 addr[1] = &octet;
7259 len[1] = sizeof(octet);
7260 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7261 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7262
7263 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7264 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7265 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7266
7267 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7268 if (aes_siv_encrypt(pkex->z, curve->hash_len,
7269 wpabuf_head(clear), wpabuf_len(clear),
7270 2, addr, len, wrapped) < 0)
7271 goto fail;
7272 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7273 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
7274
Roshan Pius3a1667e2018-07-03 15:17:14 -07007275#ifdef CONFIG_TESTING_OPTIONS
7276 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
7277 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
7278 dpp_build_attr_status(msg, DPP_STATUS_OK);
7279 }
7280skip_wrapped_data:
7281#endif /* CONFIG_TESTING_OPTIONS */
7282
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007283out:
7284 wpabuf_free(clear);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007285 return msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007286
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007287fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007288 wpabuf_free(msg);
7289 msg = NULL;
7290 goto out;
7291}
7292
7293
7294struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
7295 const u8 *hdr,
7296 const u8 *buf, size_t buflen)
7297{
7298 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007299 EVP_PKEY_CTX *ctx = NULL;
7300 size_t Jx_len, Lx_len;
7301 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007302 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
7303 const u8 *wrapped_data, *b_key, *peer_u;
7304 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
7305 const u8 *addr[4];
7306 size_t len[4];
7307 u8 octet;
7308 u8 *unwrapped = NULL;
7309 size_t unwrapped_len = 0;
7310 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7311 struct wpabuf *B_pub = NULL;
7312 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007313
Roshan Pius3a1667e2018-07-03 15:17:14 -07007314#ifdef CONFIG_TESTING_OPTIONS
7315 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
7316 wpa_printf(MSG_INFO,
7317 "DPP: TESTING - stop at PKEX CR Request");
7318 pkex->failed = 1;
7319 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007320 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07007321#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007322
Roshan Pius3a1667e2018-07-03 15:17:14 -07007323 if (!pkex->exchange_done || pkex->failed ||
7324 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007325 goto fail;
7326
7327 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7328 &wrapped_data_len);
7329 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007330 dpp_pkex_fail(pkex,
7331 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007332 goto fail;
7333 }
7334
7335 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7336 wrapped_data, wrapped_data_len);
7337 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7338 unwrapped = os_malloc(unwrapped_len);
7339 if (!unwrapped)
7340 goto fail;
7341
7342 addr[0] = hdr;
7343 len[0] = DPP_HDR_LEN;
7344 octet = 0;
7345 addr[1] = &octet;
7346 len[1] = sizeof(octet);
7347 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7348 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7349
7350 if (aes_siv_decrypt(pkex->z, curve->hash_len,
7351 wrapped_data, wrapped_data_len,
7352 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007353 dpp_pkex_fail(pkex,
7354 "AES-SIV decryption failed - possible PKEX code mismatch");
7355 pkex->failed = 1;
7356 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007357 goto fail;
7358 }
7359 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7360 unwrapped, unwrapped_len);
7361
7362 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007363 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007364 goto fail;
7365 }
7366
7367 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7368 &b_key_len);
7369 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007370 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007371 goto fail;
7372 }
7373 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7374 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007375 if (!pkex->peer_bootstrap_key) {
7376 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007377 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007378 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007379 dpp_debug_print_key("DPP: Peer bootstrap public key",
7380 pkex->peer_bootstrap_key);
7381
7382 /* ECDH: J' = y * A' */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007383 ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
7384 if (!ctx ||
7385 EVP_PKEY_derive_init(ctx) != 1 ||
7386 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
7387 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
7388 Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
7389 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
7390 wpa_printf(MSG_ERROR,
7391 "DPP: Failed to derive ECDH shared secret: %s",
7392 ERR_error_string(ERR_get_error(), NULL));
7393 goto fail;
7394 }
7395
7396 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7397 Jx, Jx_len);
7398
7399 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7400 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7401 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7402 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7403 if (!A_pub || !Y_pub || !X_pub)
7404 goto fail;
7405 addr[0] = pkex->peer_mac;
7406 len[0] = ETH_ALEN;
7407 addr[1] = wpabuf_head(A_pub);
7408 len[1] = wpabuf_len(A_pub) / 2;
7409 addr[2] = wpabuf_head(Y_pub);
7410 len[2] = wpabuf_len(Y_pub) / 2;
7411 addr[3] = wpabuf_head(X_pub);
7412 len[3] = wpabuf_len(X_pub) / 2;
7413 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
7414 goto fail;
7415
7416 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
7417 &peer_u_len);
7418 if (!peer_u || peer_u_len != curve->hash_len ||
7419 os_memcmp(peer_u, u, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007420 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007421 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
7422 u, curve->hash_len);
7423 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007424 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007425 goto fail;
7426 }
7427 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
7428
7429 /* ECDH: L = b * X' */
7430 EVP_PKEY_CTX_free(ctx);
7431 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
7432 if (!ctx ||
7433 EVP_PKEY_derive_init(ctx) != 1 ||
7434 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
7435 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
7436 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
7437 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
7438 wpa_printf(MSG_ERROR,
7439 "DPP: Failed to derive ECDH shared secret: %s",
7440 ERR_error_string(ERR_get_error(), NULL));
7441 goto fail;
7442 }
7443
7444 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7445 Lx, Lx_len);
7446
7447 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
7448 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
7449 if (!B_pub)
7450 goto fail;
7451 addr[0] = pkex->own_mac;
7452 len[0] = ETH_ALEN;
7453 addr[1] = wpabuf_head(B_pub);
7454 len[1] = wpabuf_len(B_pub) / 2;
7455 addr[2] = wpabuf_head(X_pub);
7456 len[2] = wpabuf_len(X_pub) / 2;
7457 addr[3] = wpabuf_head(Y_pub);
7458 len[3] = wpabuf_len(Y_pub) / 2;
7459 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
7460 goto fail;
7461 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
7462
Roshan Pius3a1667e2018-07-03 15:17:14 -07007463 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
7464 if (!msg)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007465 goto fail;
7466
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007467out:
7468 EVP_PKEY_CTX_free(ctx);
7469 os_free(unwrapped);
7470 wpabuf_free(A_pub);
7471 wpabuf_free(B_pub);
7472 wpabuf_free(X_pub);
7473 wpabuf_free(Y_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007474 return msg;
7475fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07007476 wpa_printf(MSG_DEBUG,
7477 "DPP: PKEX Commit-Reveal Request processing failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007478 goto out;
7479}
7480
7481
7482int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
7483 const u8 *buf, size_t buflen)
7484{
7485 const struct dpp_curve_params *curve = pkex->own_bi->curve;
7486 const u8 *wrapped_data, *b_key, *peer_v;
7487 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
7488 const u8 *addr[4];
7489 size_t len[4];
7490 u8 octet;
7491 u8 *unwrapped = NULL;
7492 size_t unwrapped_len = 0;
7493 int ret = -1;
7494 u8 v[DPP_MAX_HASH_LEN];
7495 size_t Lx_len;
7496 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
7497 EVP_PKEY_CTX *ctx = NULL;
7498 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7499
Roshan Pius3a1667e2018-07-03 15:17:14 -07007500#ifdef CONFIG_TESTING_OPTIONS
7501 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
7502 wpa_printf(MSG_INFO,
7503 "DPP: TESTING - stop at PKEX CR Response");
7504 pkex->failed = 1;
7505 goto fail;
7506 }
7507#endif /* CONFIG_TESTING_OPTIONS */
7508
7509 if (!pkex->exchange_done || pkex->failed ||
7510 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
7511 goto fail;
7512
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007513 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7514 &wrapped_data_len);
7515 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007516 dpp_pkex_fail(pkex,
7517 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007518 goto fail;
7519 }
7520
7521 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7522 wrapped_data, wrapped_data_len);
7523 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7524 unwrapped = os_malloc(unwrapped_len);
7525 if (!unwrapped)
7526 goto fail;
7527
7528 addr[0] = hdr;
7529 len[0] = DPP_HDR_LEN;
7530 octet = 1;
7531 addr[1] = &octet;
7532 len[1] = sizeof(octet);
7533 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7534 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7535
7536 if (aes_siv_decrypt(pkex->z, curve->hash_len,
7537 wrapped_data, wrapped_data_len,
7538 2, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007539 dpp_pkex_fail(pkex,
7540 "AES-SIV decryption failed - possible PKEX code mismatch");
7541 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007542 goto fail;
7543 }
7544 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7545 unwrapped, unwrapped_len);
7546
7547 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007548 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007549 goto fail;
7550 }
7551
7552 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7553 &b_key_len);
7554 if (!b_key || b_key_len != 2 * curve->prime_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007555 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007556 goto fail;
7557 }
7558 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7559 b_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007560 if (!pkex->peer_bootstrap_key) {
7561 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007562 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007563 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007564 dpp_debug_print_key("DPP: Peer bootstrap public key",
7565 pkex->peer_bootstrap_key);
7566
7567 /* ECDH: L' = x * B' */
7568 ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
7569 if (!ctx ||
7570 EVP_PKEY_derive_init(ctx) != 1 ||
7571 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
7572 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
7573 Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
7574 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
7575 wpa_printf(MSG_ERROR,
7576 "DPP: Failed to derive ECDH shared secret: %s",
7577 ERR_error_string(ERR_get_error(), NULL));
7578 goto fail;
7579 }
7580
7581 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
7582 Lx, Lx_len);
7583
7584 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
7585 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7586 X_pub = dpp_get_pubkey_point(pkex->x, 0);
7587 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7588 if (!B_pub || !X_pub || !Y_pub)
7589 goto fail;
7590 addr[0] = pkex->peer_mac;
7591 len[0] = ETH_ALEN;
7592 addr[1] = wpabuf_head(B_pub);
7593 len[1] = wpabuf_len(B_pub) / 2;
7594 addr[2] = wpabuf_head(X_pub);
7595 len[2] = wpabuf_len(X_pub) / 2;
7596 addr[3] = wpabuf_head(Y_pub);
7597 len[3] = wpabuf_len(Y_pub) / 2;
7598 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
7599 goto fail;
7600
7601 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
7602 &peer_v_len);
7603 if (!peer_v || peer_v_len != curve->hash_len ||
7604 os_memcmp(peer_v, v, curve->hash_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007605 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007606 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
7607 v, curve->hash_len);
7608 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007609 pkex->t++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007610 goto fail;
7611 }
7612 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
7613
7614 ret = 0;
7615out:
7616 wpabuf_free(B_pub);
7617 wpabuf_free(X_pub);
7618 wpabuf_free(Y_pub);
7619 EVP_PKEY_CTX_free(ctx);
7620 os_free(unwrapped);
7621 return ret;
7622fail:
7623 goto out;
7624}
7625
7626
7627void dpp_pkex_free(struct dpp_pkex *pkex)
7628{
7629 if (!pkex)
7630 return;
7631
7632 os_free(pkex->identifier);
7633 os_free(pkex->code);
7634 EVP_PKEY_free(pkex->x);
7635 EVP_PKEY_free(pkex->y);
7636 EVP_PKEY_free(pkex->peer_bootstrap_key);
7637 wpabuf_free(pkex->exchange_req);
7638 wpabuf_free(pkex->exchange_resp);
7639 os_free(pkex);
7640}
Roshan Pius3a1667e2018-07-03 15:17:14 -07007641
7642
7643#ifdef CONFIG_TESTING_OPTIONS
7644char * dpp_corrupt_connector_signature(const char *connector)
7645{
7646 char *tmp, *pos, *signed3 = NULL;
7647 unsigned char *signature = NULL;
7648 size_t signature_len = 0, signed3_len;
7649
7650 tmp = os_zalloc(os_strlen(connector) + 5);
7651 if (!tmp)
7652 goto fail;
7653 os_memcpy(tmp, connector, os_strlen(connector));
7654
7655 pos = os_strchr(tmp, '.');
7656 if (!pos)
7657 goto fail;
7658
7659 pos = os_strchr(pos + 1, '.');
7660 if (!pos)
7661 goto fail;
7662 pos++;
7663
7664 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
7665 pos);
7666 signature = base64_url_decode((const unsigned char *) pos,
7667 os_strlen(pos), &signature_len);
7668 if (!signature || signature_len == 0)
7669 goto fail;
7670 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
7671 signature, signature_len);
7672 signature[signature_len - 1] ^= 0x01;
7673 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
7674 signature, signature_len);
7675 signed3 = (char *) base64_url_encode(signature, signature_len,
7676 &signed3_len, 0);
7677 if (!signed3)
7678 goto fail;
7679 os_memcpy(pos, signed3, signed3_len);
7680 pos[signed3_len] = '\0';
7681 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
7682 pos);
7683
7684out:
7685 os_free(signature);
7686 os_free(signed3);
7687 return tmp;
7688fail:
7689 os_free(tmp);
7690 tmp = NULL;
7691 goto out;
7692}
7693#endif /* CONFIG_TESTING_OPTIONS */