summaryrefslogtreecommitdiff
path: root/fuzz/u2f_fuzz.cc
blob: 0c1a682375a7048b0552e7355649c36a0d7a6a77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/* Copyright 2021 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <fuzzer/FuzzedDataProvider.h>

#include <cstdint>
#include <memory>
#include <string>
#include <vector>

#define HIDE_EC_STDLIB
extern "C" {
#include "physical_presence.h"
#include "u2f_cmds.h"
#include "u2f_impl.h"
#include "internal.h"
}

extern "C" {
/******************************************************************************/
/* Mock implementations of cr50 board.
 */
int system_get_chip_unique_id(uint8_t **id)
{
	return P256_NBYTES;
}

/******************************************************************************/
/* Mock implementations of Dcrypto functionality.
 */
size_t DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x,
				      const p256_int *pk_y,
				      const p256_int *serial, const char *name,
				      uint8_t *cert, const size_t n)
{
	memset(cert, 1, n);
	return n;
}

enum dcrypto_result DCRYPTO_p256_key_from_bytes(
	p256_int *x, p256_int *y, p256_int *d,
	const uint8_t key_bytes[P256_NBYTES])
{
	p256_int key;

	p256_from_bin(key_bytes, &key);

	// The actual condition for this function to fail happens rarely,
	// and not able to to control. So we assume it fails for some inputs
	// for fuzz purpose.
	if (P256_DIGIT(&key, 0) % 10 == 0) {
		return DCRYPTO_RETRY;
	}

	if (p256_lt_blinded(&key, &SECP256r1_nMin2) >= 0)
		return DCRYPTO_RETRY;
	p256_add_d(&key, 1, d);
	if (x == NULL || y == NULL)
		return DCRYPTO_OK;
	memset(x, 0, P256_NBYTES);
	memset(y, 0, P256_NBYTES);
	return DCRYPTO_OK;
}

enum dcrypto_result dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg,
					    const p256_int *key,
					    const p256_int *message,
					    p256_int *r, p256_int *s)
{
	memset(r, 0, sizeof(p256_int));
	memset(s, 0, sizeof(p256_int));
	return DCRYPTO_OK;
}

/******************************************************************************/
/* Mock implementations of U2F functionality.
 */
static struct u2f_state ustate;
struct u2f_state *u2f_get_state(void)
{
	return &ustate;
}

static enum touch_state tstate;
enum touch_state pop_check_presence(int consume)
{
	return tstate;
}

uint8_t buffer[512];

int test_fuzz_one_input(const uint8_t *data, unsigned int size)
{
	FuzzedDataProvider data_provider(data, size);

	if (data_provider.ConsumeBool()) {
		ustate.drbg_entropy_size = 64;
	} else {
		ustate.drbg_entropy_size = 32;
	}

	if (data_provider.ConsumeBool()) {
		tstate = POP_TOUCH_YES;
	} else {
		tstate = POP_TOUCH_NO;
	}

	while (data_provider.remaining_bytes() > 0) {
		std::vector<uint8_t> bytes;
		int command_num = data_provider.ConsumeIntegralInRange(0, 2);

		size_t request_size, response_size;
		struct u2f_generate_req *generate_req;
		struct u2f_generate_resp *generate_resp_v0;
		struct u2f_generate_versioned_resp *generate_resp_v1;
		struct u2f_generate_versioned_resp_v2 *generate_resp_v2;
		struct u2f_sign_req *sign_req_v0;
		struct u2f_sign_versioned_req *sign_req_v1;
		struct u2f_sign_versioned_req_v2 *sign_req_v2;
		struct u2f_attest_req *attest_req;
		struct g2f_register_msg_v0 *g2f_msg_v0;
		uint8_t appId[U2F_APPID_SIZE];
		uint8_t userSecret[U2F_USER_SECRET_SIZE];
		uint8_t authTimeSecretHash[U2F_AUTH_TIME_SECRET_SIZE];
		uint8_t flags;
		struct u2f_key_handle kh_0;
		struct u2f_versioned_key_handle kh_1;
		struct u2f_key_handle_v2 kh_2;
		struct u2f_ec_point public_key;
		int kh_version;
		vendor_cmd_rc rc;

		switch (command_num) {
		case 0:
			bytes = data_provider.ConsumeBytes<uint8_t>(
				sizeof(struct u2f_generate_req));
			memcpy(buffer, bytes.data(), bytes.size());
			generate_req = (u2f_generate_req *)buffer;
			memcpy(appId, generate_req->appId, U2F_APPID_SIZE);
			memcpy(userSecret, generate_req->userSecret,
			       U2F_USER_SECRET_SIZE);
			memcpy(authTimeSecretHash,
			       generate_req->authTimeSecretHash,
			       U2F_AUTH_TIME_SECRET_SIZE);
			flags = generate_req->flags;
			response_size = 512;
			rc = u2f_generate_cmd(VENDOR_CC_U2F_GENERATE, buffer,
					      sizeof(struct u2f_generate_req),
					      &response_size);
			if (rc != VENDOR_RC_SUCCESS) {
				break;
			}
			if (response_size == sizeof(struct u2f_generate_resp)) {
				kh_version = 0;
			} else if (response_size ==
				   sizeof(struct u2f_generate_versioned_resp)) {
				kh_version = 1;
			} else if (response_size ==
				   sizeof(struct u2f_generate_versioned_resp_v2)) {
				kh_version = 2;
			} else {
				exit(1);
			}
			if (kh_version == 0) {
				generate_resp_v0 = (u2f_generate_resp *)buffer;
				kh_0 = generate_resp_v0->keyHandle;
				public_key = generate_resp_v0->pubKey;
				sign_req_v0 = (u2f_sign_req *)buffer;
				memcpy(sign_req_v0->appId, appId,
				       U2F_APPID_SIZE);
				memcpy(sign_req_v0->userSecret, userSecret,
				       U2F_USER_SECRET_SIZE);
				sign_req_v0->flags = flags;
				sign_req_v0->keyHandle = kh_0;
				bytes = data_provider.ConsumeBytes<uint8_t>(
					U2F_P256_SIZE);
				memcpy(sign_req_v0->hash, bytes.data(),
				       bytes.size());
				request_size = sizeof(struct u2f_sign_req);
			} else if (kh_version == 1) {
				generate_resp_v1 =
					(u2f_generate_versioned_resp *)buffer;
				kh_1 = generate_resp_v1->keyHandle;
				sign_req_v1 = (u2f_sign_versioned_req *)buffer;
				memcpy(sign_req_v1->appId, appId,
				       U2F_APPID_SIZE);
				memcpy(sign_req_v1->userSecret, userSecret,
				       U2F_USER_SECRET_SIZE);
				sign_req_v1->flags = flags;
				sign_req_v1->keyHandle = kh_1;
				bytes = data_provider.ConsumeBytes<uint8_t>(
					U2F_P256_SIZE);
				memcpy(sign_req_v1->hash, bytes.data(),
				       bytes.size());
				request_size =
					sizeof(struct u2f_sign_versioned_req);
			} else {
				generate_resp_v2 =
					(u2f_generate_versioned_resp_v2 *)buffer;
				kh_2 = generate_resp_v2->keyHandle;
				sign_req_v2 =
					(u2f_sign_versioned_req_v2 *)buffer;
				memcpy(sign_req_v2->appId, appId,
				       U2F_APPID_SIZE);
				memcpy(sign_req_v2->userSecret, userSecret,
				       U2F_USER_SECRET_SIZE);
				memcpy(sign_req_v2->authTimeSecret,
				       authTimeSecretHash,
				       U2F_AUTH_TIME_SECRET_SIZE);
				sign_req_v2->flags = flags;
				sign_req_v2->keyHandle = kh_2;
				bytes = data_provider.ConsumeBytes<uint8_t>(
					U2F_P256_SIZE);
				memcpy(sign_req_v2->hash, bytes.data(),
				       bytes.size());
				request_size = sizeof(
					struct u2f_sign_versioned_req_v2);
			}
			response_size = 512;
			u2f_sign_cmd(VENDOR_CC_U2F_SIGN, buffer, request_size,
				     &response_size);
			if (kh_version == 0) {
				attest_req = (u2f_attest_req *)buffer;
				attest_req->format = U2F_ATTEST_FORMAT_REG_RESP;
				attest_req->dataLen =
					sizeof(struct g2f_register_msg_v0);
				memcpy(attest_req->userSecret, userSecret,
				       U2F_USER_SECRET_SIZE);
				g2f_msg_v0 =
					(g2f_register_msg_v0 *)attest_req->data;
				g2f_msg_v0->reserved = 0;
				memcpy(g2f_msg_v0->app_id, appId,
				       U2F_APPID_SIZE);
				memcpy(g2f_msg_v0->key_handle.hmac, kh_0.hmac,
				       sizeof(kh_0.hmac));
				memcpy(g2f_msg_v0->key_handle.origin_seed,
				       kh_0.origin_seed,
				       sizeof(kh_0.origin_seed));
				g2f_msg_v0->public_key = public_key;
				bytes = data_provider.ConsumeBytes<uint8_t>(
					U2F_CHAL_SIZE);
				memcpy(g2f_msg_v0->challenge, bytes.data(),
				       bytes.size());
				response_size = 512;
				u2f_attest_cmd(VENDOR_CC_U2F_ATTEST, buffer,
					       sizeof(struct u2f_attest_req),
					       &response_size);
			}
			break;
		case 1: {
			int version =
				data_provider.ConsumeIntegralInRange(0, 2);
			request_size =
				(version == 0) ?
					      sizeof(struct u2f_sign_req) :
				(version == 1) ?
					      sizeof(struct u2f_sign_versioned_req) :
					      sizeof(struct u2f_sign_versioned_req_v2);
			bytes = data_provider.ConsumeBytes<uint8_t>(
				request_size);
			memcpy(buffer, bytes.data(), bytes.size());
			response_size = 512;
			u2f_sign_cmd(VENDOR_CC_U2F_SIGN, buffer, request_size,
				     &response_size);
			break;
		}
		case 2:
			auto str = data_provider.ConsumeRandomLengthString(256);
			memcpy(buffer, str.data(), str.size());
			attest_req = (u2f_attest_req *)buffer;
			attest_req->dataLen =
				sizeof(struct g2f_register_msg_v0);
			response_size = 512;
			u2f_attest_cmd(VENDOR_CC_U2F_ATTEST, buffer, str.size(),
				       &response_size);
			break;
		}
		break;
	}
	return 0;
}
}