Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/fuzz/fuzz_pcsc.c
39586 views
1
/*
2
* Copyright (c) 2022 Yubico AB. All rights reserved.
3
* Use of this source code is governed by a BSD-style
4
* license that can be found in the LICENSE file.
5
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#define _FIDO_INTERNAL
9
10
#include <assert.h>
11
#include <stdint.h>
12
#include <stdlib.h>
13
#include <string.h>
14
#include <stdio.h>
15
#include <winscard.h>
16
17
#include "mutator_aux.h"
18
#include "wiredata_fido2.h"
19
#include "dummy.h"
20
21
#include "../src/extern.h"
22
23
struct param {
24
int seed;
25
char path[MAXSTR];
26
struct blob pcsc_list;
27
struct blob tx_apdu;
28
struct blob wiredata_init;
29
struct blob wiredata_msg;
30
};
31
32
static const uint8_t dummy_tx_apdu[] = { WIREDATA_CTAP_EXTENDED_APDU };
33
static const uint8_t dummy_wiredata_init[] = { WIREDATA_CTAP_NFC_INIT };
34
static const uint8_t dummy_wiredata_msg[] = { WIREDATA_CTAP_NFC_MSG };
35
36
struct param *
37
unpack(const uint8_t *ptr, size_t len)
38
{
39
cbor_item_t *item = NULL, **v;
40
struct cbor_load_result cbor;
41
struct param *p;
42
int ok = -1;
43
44
if ((p = calloc(1, sizeof(*p))) == NULL ||
45
(item = cbor_load(ptr, len, &cbor)) == NULL ||
46
cbor.read != len ||
47
cbor_isa_array(item) == false ||
48
cbor_array_is_definite(item) == false ||
49
cbor_array_size(item) != 6 ||
50
(v = cbor_array_handle(item)) == NULL)
51
goto fail;
52
53
if (unpack_int(v[0], &p->seed) < 0 ||
54
unpack_string(v[1], p->path) < 0 ||
55
unpack_blob(v[2], &p->pcsc_list) < 0 ||
56
unpack_blob(v[3], &p->tx_apdu) < 0 ||
57
unpack_blob(v[4], &p->wiredata_init) < 0 ||
58
unpack_blob(v[5], &p->wiredata_msg) < 0)
59
goto fail;
60
61
ok = 0;
62
fail:
63
if (ok < 0) {
64
free(p);
65
p = NULL;
66
}
67
68
if (item)
69
cbor_decref(&item);
70
71
return p;
72
}
73
74
size_t
75
pack(uint8_t *ptr, size_t len, const struct param *p)
76
{
77
cbor_item_t *argv[6], *array = NULL;
78
size_t cbor_alloc_len, cbor_len = 0;
79
unsigned char *cbor = NULL;
80
81
memset(argv, 0, sizeof(argv));
82
83
if ((array = cbor_new_definite_array(6)) == NULL ||
84
(argv[0] = pack_int(p->seed)) == NULL ||
85
(argv[1] = pack_string(p->path)) == NULL ||
86
(argv[2] = pack_blob(&p->pcsc_list)) == NULL ||
87
(argv[3] = pack_blob(&p->tx_apdu)) == NULL ||
88
(argv[4] = pack_blob(&p->wiredata_init)) == NULL ||
89
(argv[5] = pack_blob(&p->wiredata_msg)) == NULL)
90
goto fail;
91
92
for (size_t i = 0; i < 6; i++)
93
if (cbor_array_push(array, argv[i]) == false)
94
goto fail;
95
96
if ((cbor_len = cbor_serialize_alloc(array, &cbor,
97
&cbor_alloc_len)) == 0 || cbor_len > len) {
98
cbor_len = 0;
99
goto fail;
100
}
101
102
memcpy(ptr, cbor, cbor_len);
103
fail:
104
for (size_t i = 0; i < 6; i++)
105
if (argv[i])
106
cbor_decref(&argv[i]);
107
108
if (array)
109
cbor_decref(&array);
110
111
free(cbor);
112
113
return cbor_len;
114
}
115
116
size_t
117
pack_dummy(uint8_t *ptr, size_t len)
118
{
119
struct param dummy;
120
uint8_t blob[MAXCORPUS];
121
size_t blob_len;
122
123
memset(&dummy, 0, sizeof(dummy));
124
125
strlcpy(dummy.path, dummy_pcsc_path, sizeof(dummy.path));
126
127
dummy.pcsc_list.len = sizeof(dummy_pcsc_list);
128
memcpy(&dummy.pcsc_list.body, &dummy_pcsc_list, dummy.pcsc_list.len);
129
130
dummy.tx_apdu.len = sizeof(dummy_tx_apdu);
131
memcpy(&dummy.tx_apdu.body, &dummy_tx_apdu, dummy.tx_apdu.len);
132
133
dummy.wiredata_init.len = sizeof(dummy_wiredata_init);
134
memcpy(&dummy.wiredata_init.body, &dummy_wiredata_init,
135
dummy.wiredata_init.len);
136
137
dummy.wiredata_msg.len = sizeof(dummy_wiredata_msg);
138
memcpy(&dummy.wiredata_msg.body, &dummy_wiredata_msg,
139
dummy.wiredata_msg.len);
140
141
assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
142
143
if (blob_len > len) {
144
memcpy(ptr, blob, len);
145
return len;
146
}
147
148
memcpy(ptr, blob, blob_len);
149
150
return blob_len;
151
}
152
153
static void
154
test_manifest(void)
155
{
156
size_t ndevs, nfound;
157
fido_dev_info_t *devlist = NULL;
158
int16_t vendor_id, product_id;
159
int r;
160
161
r = fido_pcsc_manifest(NULL, 0, &nfound);
162
assert(r == FIDO_OK && nfound == 0);
163
r = fido_pcsc_manifest(NULL, 1, &nfound);
164
assert(r == FIDO_ERR_INVALID_ARGUMENT);
165
166
ndevs = uniform_random(64);
167
if ((devlist = fido_dev_info_new(ndevs)) == NULL ||
168
fido_pcsc_manifest(devlist, ndevs, &nfound) != FIDO_OK)
169
goto out;
170
171
for (size_t i = 0; i < nfound; i++) {
172
const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
173
consume_str(fido_dev_info_path(di));
174
consume_str(fido_dev_info_manufacturer_string(di));
175
consume_str(fido_dev_info_product_string(di));
176
vendor_id = fido_dev_info_vendor(di);
177
product_id = fido_dev_info_product(di);
178
consume(&vendor_id, sizeof(vendor_id));
179
consume(&product_id, sizeof(product_id));
180
}
181
182
out:
183
fido_dev_info_free(&devlist, ndevs);
184
}
185
186
static void
187
test_tx(const char *path, const struct blob *apdu, uint8_t cmd, u_char *rx_buf,
188
size_t rx_len)
189
{
190
fido_dev_t dev;
191
const u_char *tx_ptr = NULL;
192
size_t tx_len = 0;
193
int n;
194
195
memset(&dev, 0, sizeof(dev));
196
197
if (fido_dev_set_pcsc(&dev) < 0)
198
return;
199
if ((dev.io_handle = fido_pcsc_open(path)) == NULL)
200
return;
201
202
if (apdu) {
203
tx_ptr = apdu->body;
204
tx_len = apdu->len;
205
}
206
207
fido_pcsc_tx(&dev, cmd, tx_ptr, tx_len);
208
209
if ((n = fido_pcsc_rx(&dev, cmd, rx_buf, rx_len, -1)) >= 0)
210
consume(rx_buf, n);
211
212
fido_pcsc_close(dev.io_handle);
213
}
214
215
static void
216
test_misc(void)
217
{
218
assert(fido_pcsc_open(NULL) == NULL);
219
assert(fido_pcsc_write(NULL, NULL, INT_MAX + 1LL) == -1);
220
}
221
222
void
223
test(const struct param *p)
224
{
225
u_char buf[512];
226
227
prng_init((unsigned int)p->seed);
228
fuzz_clock_reset();
229
fido_init(FIDO_DEBUG);
230
fido_set_log_handler(consume_str);
231
232
set_pcsc_parameters(&p->pcsc_list);
233
set_pcsc_io_functions(nfc_read, nfc_write, consume);
234
235
set_wire_data(p->wiredata_init.body, p->wiredata_init.len);
236
test_manifest();
237
238
test_misc();
239
240
set_wire_data(p->wiredata_init.body, p->wiredata_init.len);
241
test_tx(p->path, NULL, CTAP_CMD_INIT, buf, uniform_random(20));
242
243
set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
244
test_tx(p->path, &p->tx_apdu, CTAP_CMD_MSG, buf, sizeof(buf));
245
246
set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
247
test_tx(p->path, &p->tx_apdu, CTAP_CMD_CBOR, buf, sizeof(buf));
248
249
set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
250
test_tx(p->path, &p->tx_apdu, CTAP_CMD_LOCK, buf, sizeof(buf));
251
}
252
253
void
254
mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
255
{
256
if (flags & MUTATE_SEED)
257
p->seed = (int)seed;
258
259
if (flags & MUTATE_PARAM) {
260
mutate_string(p->path);
261
mutate_blob(&p->pcsc_list);
262
mutate_blob(&p->tx_apdu);
263
}
264
265
if (flags & MUTATE_WIREDATA) {
266
mutate_blob(&p->wiredata_init);
267
mutate_blob(&p->wiredata_msg);
268
}
269
}
270
271