Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/fuzz/fuzz_bio.c
39586 views
1
/*
2
* Copyright (c) 2019 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
#include <assert.h>
9
#include <stdint.h>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
14
#include "mutator_aux.h"
15
#include "wiredata_fido2.h"
16
#include "dummy.h"
17
18
#include "../openbsd-compat/openbsd-compat.h"
19
20
/* Parameter set defining a FIDO2 credential management operation. */
21
struct param {
22
char pin[MAXSTR];
23
char name[MAXSTR];
24
int seed;
25
struct blob id;
26
struct blob info_wire_data;
27
struct blob enroll_wire_data;
28
struct blob list_wire_data;
29
struct blob set_name_wire_data;
30
struct blob remove_wire_data;
31
};
32
33
/*
34
* Collection of HID reports from an authenticator issued with a FIDO2
35
* 'getFingerprintSensorInfo' bio enrollment command.
36
*/
37
static const uint8_t dummy_info_wire_data[] = {
38
WIREDATA_CTAP_INIT,
39
WIREDATA_CTAP_CBOR_INFO,
40
WIREDATA_CTAP_CBOR_BIO_INFO,
41
};
42
43
/*
44
* Collection of HID reports from an authenticator issued with FIDO2
45
* 'enrollBegin' + 'enrollCaptureNextSample' bio enrollment commands.
46
*/
47
static const uint8_t dummy_enroll_wire_data[] = {
48
WIREDATA_CTAP_INIT,
49
WIREDATA_CTAP_CBOR_INFO,
50
WIREDATA_CTAP_CBOR_AUTHKEY,
51
WIREDATA_CTAP_CBOR_PINTOKEN,
52
WIREDATA_CTAP_CBOR_BIO_ENROLL,
53
};
54
55
/*
56
* Collection of HID reports from an authenticator issued with a FIDO2
57
* 'enumerateEnrollments' bio enrollment command.
58
*/
59
static const uint8_t dummy_list_wire_data[] = {
60
WIREDATA_CTAP_INIT,
61
WIREDATA_CTAP_CBOR_INFO,
62
WIREDATA_CTAP_CBOR_AUTHKEY,
63
WIREDATA_CTAP_CBOR_PINTOKEN,
64
WIREDATA_CTAP_CBOR_BIO_ENUM,
65
};
66
67
/*
68
* Collection of HID reports from an authenticator issued with a FIDO2
69
* 'setFriendlyName' bio enrollment command.
70
*/
71
static const uint8_t dummy_set_name_wire_data[] = {
72
WIREDATA_CTAP_INIT,
73
WIREDATA_CTAP_CBOR_INFO,
74
WIREDATA_CTAP_CBOR_AUTHKEY,
75
WIREDATA_CTAP_CBOR_PINTOKEN,
76
WIREDATA_CTAP_CBOR_STATUS,
77
};
78
79
/*
80
* Collection of HID reports from an authenticator issued with a FIDO2
81
* 'removeEnrollment' bio enrollment command.
82
*/
83
static const uint8_t dummy_remove_wire_data[] = {
84
WIREDATA_CTAP_INIT,
85
WIREDATA_CTAP_CBOR_INFO,
86
WIREDATA_CTAP_CBOR_AUTHKEY,
87
WIREDATA_CTAP_CBOR_PINTOKEN,
88
WIREDATA_CTAP_CBOR_STATUS,
89
};
90
91
struct param *
92
unpack(const uint8_t *ptr, size_t len)
93
{
94
cbor_item_t *item = NULL, **v;
95
struct cbor_load_result cbor;
96
struct param *p;
97
int ok = -1;
98
99
if ((p = calloc(1, sizeof(*p))) == NULL ||
100
(item = cbor_load(ptr, len, &cbor)) == NULL ||
101
cbor.read != len ||
102
cbor_isa_array(item) == false ||
103
cbor_array_is_definite(item) == false ||
104
cbor_array_size(item) != 9 ||
105
(v = cbor_array_handle(item)) == NULL)
106
goto fail;
107
108
if (unpack_int(v[0], &p->seed) < 0 ||
109
unpack_string(v[1], p->pin) < 0 ||
110
unpack_string(v[2], p->name) < 0 ||
111
unpack_blob(v[3], &p->id) < 0 ||
112
unpack_blob(v[4], &p->info_wire_data) < 0 ||
113
unpack_blob(v[5], &p->enroll_wire_data) < 0 ||
114
unpack_blob(v[6], &p->list_wire_data) < 0 ||
115
unpack_blob(v[7], &p->set_name_wire_data) < 0 ||
116
unpack_blob(v[8], &p->remove_wire_data) < 0)
117
goto fail;
118
119
ok = 0;
120
fail:
121
if (ok < 0) {
122
free(p);
123
p = NULL;
124
}
125
126
if (item)
127
cbor_decref(&item);
128
129
return p;
130
}
131
132
size_t
133
pack(uint8_t *ptr, size_t len, const struct param *p)
134
{
135
cbor_item_t *argv[9], *array = NULL;
136
size_t cbor_alloc_len, cbor_len = 0;
137
unsigned char *cbor = NULL;
138
139
memset(argv, 0, sizeof(argv));
140
141
if ((array = cbor_new_definite_array(9)) == NULL ||
142
(argv[0] = pack_int(p->seed)) == NULL ||
143
(argv[1] = pack_string(p->pin)) == NULL ||
144
(argv[2] = pack_string(p->name)) == NULL ||
145
(argv[3] = pack_blob(&p->id)) == NULL ||
146
(argv[4] = pack_blob(&p->info_wire_data)) == NULL ||
147
(argv[5] = pack_blob(&p->enroll_wire_data)) == NULL ||
148
(argv[6] = pack_blob(&p->list_wire_data)) == NULL ||
149
(argv[7] = pack_blob(&p->set_name_wire_data)) == NULL ||
150
(argv[8] = pack_blob(&p->remove_wire_data)) == NULL)
151
goto fail;
152
153
for (size_t i = 0; i < 9; i++)
154
if (cbor_array_push(array, argv[i]) == false)
155
goto fail;
156
157
if ((cbor_len = cbor_serialize_alloc(array, &cbor,
158
&cbor_alloc_len)) == 0 || cbor_len > len) {
159
cbor_len = 0;
160
goto fail;
161
}
162
163
memcpy(ptr, cbor, cbor_len);
164
fail:
165
for (size_t i = 0; i < 9; i++)
166
if (argv[i])
167
cbor_decref(&argv[i]);
168
169
if (array)
170
cbor_decref(&array);
171
172
free(cbor);
173
174
return cbor_len;
175
}
176
177
size_t
178
pack_dummy(uint8_t *ptr, size_t len)
179
{
180
struct param dummy;
181
uint8_t blob[MAXCORPUS];
182
size_t blob_len;
183
184
memset(&dummy, 0, sizeof(dummy));
185
186
strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
187
strlcpy(dummy.name, dummy_name, sizeof(dummy.name));
188
189
dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
190
dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data);
191
dummy.list_wire_data.len = sizeof(dummy_list_wire_data);
192
dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data);
193
dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data);
194
dummy.id.len = sizeof(dummy_id);
195
196
memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
197
dummy.info_wire_data.len);
198
memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data,
199
dummy.enroll_wire_data.len);
200
memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data,
201
dummy.list_wire_data.len);
202
memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data,
203
dummy.set_name_wire_data.len);
204
memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data,
205
dummy.remove_wire_data.len);
206
memcpy(&dummy.id.body, &dummy_id, dummy.id.len);
207
208
assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
209
210
if (blob_len > len) {
211
memcpy(ptr, blob, len);
212
return len;
213
}
214
215
memcpy(ptr, blob, blob_len);
216
217
return blob_len;
218
}
219
220
static fido_dev_t *
221
prepare_dev(void)
222
{
223
fido_dev_t *dev;
224
bool x;
225
226
if ((dev = open_dev(0)) == NULL)
227
return NULL;
228
229
x = fido_dev_is_fido2(dev);
230
consume(&x, sizeof(x));
231
x = fido_dev_supports_pin(dev);
232
consume(&x, sizeof(x));
233
x = fido_dev_has_pin(dev);
234
consume(&x, sizeof(x));
235
x = fido_dev_supports_uv(dev);
236
consume(&x, sizeof(x));
237
x = fido_dev_has_uv(dev);
238
consume(&x, sizeof(x));
239
240
return dev;
241
}
242
243
static void
244
get_info(const struct param *p)
245
{
246
fido_dev_t *dev = NULL;
247
fido_bio_info_t *i = NULL;
248
uint8_t type;
249
uint8_t max_samples;
250
int r;
251
252
set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
253
254
if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL)
255
goto done;
256
257
r = fido_bio_dev_get_info(dev, i);
258
consume_str(fido_strerr(r));
259
260
type = fido_bio_info_type(i);
261
max_samples = fido_bio_info_max_samples(i);
262
consume(&type, sizeof(type));
263
consume(&max_samples, sizeof(max_samples));
264
265
done:
266
if (dev)
267
fido_dev_close(dev);
268
269
fido_dev_free(&dev);
270
fido_bio_info_free(&i);
271
}
272
273
static void
274
consume_template(const fido_bio_template_t *t)
275
{
276
consume_str(fido_bio_template_name(t));
277
consume(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t));
278
}
279
280
static void
281
consume_enroll(fido_bio_enroll_t *e)
282
{
283
uint8_t last_status;
284
uint8_t remaining_samples;
285
286
last_status = fido_bio_enroll_last_status(e);
287
remaining_samples = fido_bio_enroll_remaining_samples(e);
288
consume(&last_status, sizeof(last_status));
289
consume(&remaining_samples, sizeof(remaining_samples));
290
}
291
292
static void
293
enroll(const struct param *p)
294
{
295
fido_dev_t *dev = NULL;
296
fido_bio_template_t *t = NULL;
297
fido_bio_enroll_t *e = NULL;
298
size_t cnt = 0;
299
300
set_wire_data(p->enroll_wire_data.body, p->enroll_wire_data.len);
301
302
if ((dev = prepare_dev()) == NULL ||
303
(t = fido_bio_template_new()) == NULL ||
304
(e = fido_bio_enroll_new()) == NULL)
305
goto done;
306
307
fido_bio_dev_enroll_begin(dev, t, e, (uint32_t)p->seed, p->pin);
308
309
consume_template(t);
310
consume_enroll(e);
311
312
while (fido_bio_enroll_remaining_samples(e) > 0 && cnt++ < 5) {
313
fido_bio_dev_enroll_continue(dev, t, e, p->seed);
314
consume_template(t);
315
consume_enroll(e);
316
}
317
318
done:
319
if (dev)
320
fido_dev_close(dev);
321
322
fido_dev_free(&dev);
323
fido_bio_template_free(&t);
324
fido_bio_enroll_free(&e);
325
}
326
327
static void
328
list(const struct param *p)
329
{
330
fido_dev_t *dev = NULL;
331
fido_bio_template_array_t *ta = NULL;
332
const fido_bio_template_t *t = NULL;
333
334
set_wire_data(p->list_wire_data.body, p->list_wire_data.len);
335
336
if ((dev = prepare_dev()) == NULL ||
337
(ta = fido_bio_template_array_new()) == NULL)
338
goto done;
339
340
fido_bio_dev_get_template_array(dev, ta, p->pin);
341
342
/* +1 on purpose */
343
for (size_t i = 0; i < fido_bio_template_array_count(ta) + 1; i++)
344
if ((t = fido_bio_template(ta, i)) != NULL)
345
consume_template(t);
346
347
done:
348
if (dev)
349
fido_dev_close(dev);
350
351
fido_dev_free(&dev);
352
fido_bio_template_array_free(&ta);
353
}
354
355
static void
356
set_name(const struct param *p)
357
{
358
fido_dev_t *dev = NULL;
359
fido_bio_template_t *t = NULL;
360
361
set_wire_data(p->set_name_wire_data.body, p->set_name_wire_data.len);
362
363
if ((dev = prepare_dev()) == NULL ||
364
(t = fido_bio_template_new()) == NULL)
365
goto done;
366
367
fido_bio_template_set_name(t, p->name);
368
fido_bio_template_set_id(t, p->id.body, p->id.len);
369
consume_template(t);
370
371
fido_bio_dev_set_template_name(dev, t, p->pin);
372
373
done:
374
if (dev)
375
fido_dev_close(dev);
376
377
fido_dev_free(&dev);
378
fido_bio_template_free(&t);
379
}
380
381
static void
382
del(const struct param *p)
383
{
384
fido_dev_t *dev = NULL;
385
fido_bio_template_t *t = NULL;
386
int r;
387
388
set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len);
389
390
if ((dev = prepare_dev()) == NULL ||
391
(t = fido_bio_template_new()) == NULL)
392
goto done;
393
394
r = fido_bio_template_set_id(t, p->id.body, p->id.len);
395
consume_template(t);
396
consume_str(fido_strerr(r));
397
398
fido_bio_dev_enroll_remove(dev, t, p->pin);
399
400
done:
401
if (dev)
402
fido_dev_close(dev);
403
404
fido_dev_free(&dev);
405
fido_bio_template_free(&t);
406
}
407
408
void
409
test(const struct param *p)
410
{
411
prng_init((unsigned int)p->seed);
412
fuzz_clock_reset();
413
fido_init(FIDO_DEBUG);
414
fido_set_log_handler(consume_str);
415
416
get_info(p);
417
enroll(p);
418
list(p);
419
set_name(p);
420
del(p);
421
}
422
423
void
424
mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
425
{
426
if (flags & MUTATE_SEED)
427
p->seed = (int)seed;
428
429
if (flags & MUTATE_PARAM) {
430
mutate_blob(&p->id);
431
mutate_string(p->pin);
432
mutate_string(p->name);
433
}
434
435
if (flags & MUTATE_WIREDATA) {
436
mutate_blob(&p->info_wire_data);
437
mutate_blob(&p->enroll_wire_data);
438
mutate_blob(&p->list_wire_data);
439
mutate_blob(&p->set_name_wire_data);
440
mutate_blob(&p->remove_wire_data);
441
}
442
}
443
444