summaryrefslogtreecommitdiff
path: root/fuzz/fuzz_bio.c
diff options
context:
space:
mode:
Diffstat (limited to 'fuzz/fuzz_bio.c')
-rw-r--r--fuzz/fuzz_bio.c335
1 files changed, 175 insertions, 160 deletions
diff --git a/fuzz/fuzz_bio.c b/fuzz/fuzz_bio.c
index 05f6ce3..5051a34 100644
--- a/fuzz/fuzz_bio.c
+++ b/fuzz/fuzz_bio.c
@@ -19,27 +19,17 @@
19 19
20#include "../openbsd-compat/openbsd-compat.h" 20#include "../openbsd-compat/openbsd-compat.h"
21 21
22#define TAG_PIN 0x01
23#define TAG_NAME 0x02
24#define TAG_SEED 0x03
25#define TAG_ID 0x04
26#define TAG_INFO_WIRE_DATA 0x05
27#define TAG_ENROLL_WIRE_DATA 0x06
28#define TAG_LIST_WIRE_DATA 0x07
29#define TAG_SET_NAME_WIRE_DATA 0x08
30#define TAG_REMOVE_WIRE_DATA 0x09
31
32/* Parameter set defining a FIDO2 credential management operation. */ 22/* Parameter set defining a FIDO2 credential management operation. */
33struct param { 23struct param {
34 char pin[MAXSTR]; 24 char pin[MAXSTR];
35 char name[MAXSTR]; 25 char name[MAXSTR];
36 int seed; 26 int seed;
37 struct blob id; 27 struct blob id;
38 struct blob info_wire_data; 28 struct blob info_wire_data;
39 struct blob enroll_wire_data; 29 struct blob enroll_wire_data;
40 struct blob list_wire_data; 30 struct blob list_wire_data;
41 struct blob set_name_wire_data; 31 struct blob set_name_wire_data;
42 struct blob remove_wire_data; 32 struct blob remove_wire_data;
43}; 33};
44 34
45/* 35/*
@@ -100,58 +90,141 @@ static const uint8_t dummy_remove_wire_data[] = {
100 WIREDATA_CTAP_CBOR_STATUS, 90 WIREDATA_CTAP_CBOR_STATUS,
101}; 91};
102 92
103int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 93struct param *
104size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 94unpack(const uint8_t *ptr, size_t len)
105
106static int
107unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
108{ 95{
109 uint8_t **pp = (void *)&ptr; 96 cbor_item_t *item = NULL, **v;
110 97 struct cbor_load_result cbor;
111 if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 98 struct param *p;
112 unpack_string(TAG_NAME, pp, &len, p->name) < 0 || 99 int ok = -1;
113 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 100
114 unpack_blob(TAG_ID, pp, &len, &p->id) < 0 || 101 if ((p = calloc(1, sizeof(*p))) == NULL ||
115 unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || 102 (item = cbor_load(ptr, len, &cbor)) == NULL ||
116 unpack_blob(TAG_ENROLL_WIRE_DATA, pp, &len, &p->enroll_wire_data) < 0 || 103 cbor.read != len ||
117 unpack_blob(TAG_LIST_WIRE_DATA, pp, &len, &p->list_wire_data) < 0 || 104 cbor_isa_array(item) == false ||
118 unpack_blob(TAG_SET_NAME_WIRE_DATA, pp, &len, &p->set_name_wire_data) < 0 || 105 cbor_array_is_definite(item) == false ||
119 unpack_blob(TAG_REMOVE_WIRE_DATA, pp, &len, &p->remove_wire_data) < 0) 106 cbor_array_size(item) != 9 ||
120 return (-1); 107 (v = cbor_array_handle(item)) == NULL)
121 108 goto fail;
122 return (0); 109
110 if (unpack_int(v[0], &p->seed) < 0 ||
111 unpack_string(v[1], p->pin) < 0 ||
112 unpack_string(v[2], p->name) < 0 ||
113 unpack_blob(v[3], &p->id) < 0 ||
114 unpack_blob(v[4], &p->info_wire_data) < 0 ||
115 unpack_blob(v[5], &p->enroll_wire_data) < 0 ||
116 unpack_blob(v[6], &p->list_wire_data) < 0 ||
117 unpack_blob(v[7], &p->set_name_wire_data) < 0 ||
118 unpack_blob(v[8], &p->remove_wire_data) < 0)
119 goto fail;
120
121 ok = 0;
122fail:
123 if (ok < 0) {
124 free(p);
125 p = NULL;
126 }
127
128 if (item)
129 cbor_decref(&item);
130
131 return p;
123} 132}
124 133
125static size_t 134size_t
126pack(uint8_t *ptr, size_t len, const struct param *p) 135pack(uint8_t *ptr, size_t len, const struct param *p)
127{ 136{
128 const size_t max = len; 137 cbor_item_t *argv[9], *array = NULL;
129 138 size_t cbor_alloc_len, cbor_len = 0;
130 if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 139 unsigned char *cbor = NULL;
131 pack_string(TAG_NAME, &ptr, &len, p->name) < 0 || 140
132 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 141 memset(argv, 0, sizeof(argv));
133 pack_blob(TAG_ID, &ptr, &len, &p->id) < 0 || 142
134 pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || 143 if ((array = cbor_new_definite_array(9)) == NULL ||
135 pack_blob(TAG_ENROLL_WIRE_DATA, &ptr, &len, &p->enroll_wire_data) < 0 || 144 (argv[0] = pack_int(p->seed)) == NULL ||
136 pack_blob(TAG_LIST_WIRE_DATA, &ptr, &len, &p->list_wire_data) < 0 || 145 (argv[1] = pack_string(p->pin)) == NULL ||
137 pack_blob(TAG_SET_NAME_WIRE_DATA, &ptr, &len, &p->set_name_wire_data) < 0 || 146 (argv[2] = pack_string(p->name)) == NULL ||
138 pack_blob(TAG_REMOVE_WIRE_DATA, &ptr, &len, &p->remove_wire_data) < 0) 147 (argv[3] = pack_blob(&p->id)) == NULL ||
139 return (0); 148 (argv[4] = pack_blob(&p->info_wire_data)) == NULL ||
140 149 (argv[5] = pack_blob(&p->enroll_wire_data)) == NULL ||
141 return (max - len); 150 (argv[6] = pack_blob(&p->list_wire_data)) == NULL ||
151 (argv[7] = pack_blob(&p->set_name_wire_data)) == NULL ||
152 (argv[8] = pack_blob(&p->remove_wire_data)) == NULL)
153 goto fail;
154
155 for (size_t i = 0; i < 9; i++)
156 if (cbor_array_push(array, argv[i]) == false)
157 goto fail;
158
159 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
160 &cbor_alloc_len)) > len) {
161 cbor_len = 0;
162 goto fail;
163 }
164
165 memcpy(ptr, cbor, cbor_len);
166fail:
167 for (size_t i = 0; i < 9; i++)
168 if (argv[i])
169 cbor_decref(&argv[i]);
170
171 if (array)
172 cbor_decref(&array);
173
174 free(cbor);
175
176 return cbor_len;
142} 177}
143 178
144static size_t 179size_t
145input_len(int max) 180pack_dummy(uint8_t *ptr, size_t len)
146{ 181{
147 return (2 * len_string(max) + len_int() + 6 * len_blob(max)); 182 struct param dummy;
183 uint8_t blob[4096];
184 size_t blob_len;
185
186 memset(&dummy, 0, sizeof(dummy));
187
188 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
189 strlcpy(dummy.name, dummy_name, sizeof(dummy.name));
190
191 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
192 dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data);
193 dummy.list_wire_data.len = sizeof(dummy_list_wire_data);
194 dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data);
195 dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data);
196 dummy.id.len = sizeof(dummy_id);
197
198 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
199 dummy.info_wire_data.len);
200 memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data,
201 dummy.enroll_wire_data.len);
202 memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data,
203 dummy.list_wire_data.len);
204 memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data,
205 dummy.set_name_wire_data.len);
206 memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data,
207 dummy.remove_wire_data.len);
208 memcpy(&dummy.id.body, &dummy_id, dummy.id.len);
209
210 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
211
212 if (blob_len > len) {
213 memcpy(ptr, blob, len);
214 return len;
215 }
216
217 memcpy(ptr, blob, blob_len);
218
219 return blob_len;
148} 220}
149 221
150static fido_dev_t * 222static fido_dev_t *
151prepare_dev() 223prepare_dev(void)
152{ 224{
153 fido_dev_t *dev; 225 fido_dev_t *dev;
154 fido_dev_io_t io; 226 fido_dev_io_t io;
227 bool x;
155 228
156 memset(&io, 0, sizeof(io)); 229 memset(&io, 0, sizeof(io));
157 230
@@ -163,26 +236,35 @@ prepare_dev()
163 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 236 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
164 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 237 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
165 fido_dev_free(&dev); 238 fido_dev_free(&dev);
166 return (NULL); 239 return NULL;
167 } 240 }
168 241
169 return (dev); 242 x = fido_dev_is_fido2(dev);
243 consume(&x, sizeof(x));
244 x = fido_dev_supports_pin(dev);
245 consume(&x, sizeof(x));
246 x = fido_dev_has_pin(dev);
247 consume(&x, sizeof(x));
248
249 return dev;
170} 250}
171 251
172static void 252static void
173get_info(struct param *p) 253get_info(const struct param *p)
174{ 254{
175 fido_dev_t *dev = NULL; 255 fido_dev_t *dev = NULL;
176 fido_bio_info_t *i = NULL; 256 fido_bio_info_t *i = NULL;
177 uint8_t type; 257 uint8_t type;
178 uint8_t max_samples; 258 uint8_t max_samples;
259 int r;
179 260
180 set_wire_data(p->info_wire_data.body, p->info_wire_data.len); 261 set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
181 262
182 if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) 263 if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL)
183 goto done; 264 goto done;
184 265
185 fido_bio_dev_get_info(dev, i); 266 r = fido_bio_dev_get_info(dev, i);
267 consume_str(fido_strerr(r));
186 268
187 type = fido_bio_info_type(i); 269 type = fido_bio_info_type(i);
188 max_samples = fido_bio_info_max_samples(i); 270 max_samples = fido_bio_info_max_samples(i);
@@ -217,7 +299,7 @@ consume_enroll(fido_bio_enroll_t *e)
217} 299}
218 300
219static void 301static void
220enroll(struct param *p) 302enroll(const struct param *p)
221{ 303{
222 fido_dev_t *dev = NULL; 304 fido_dev_t *dev = NULL;
223 fido_bio_template_t *t = NULL; 305 fido_bio_template_t *t = NULL;
@@ -252,7 +334,7 @@ done:
252} 334}
253 335
254static void 336static void
255list(struct param *p) 337list(const struct param *p)
256{ 338{
257 fido_dev_t *dev = NULL; 339 fido_dev_t *dev = NULL;
258 fido_bio_template_array_t *ta = NULL; 340 fido_bio_template_array_t *ta = NULL;
@@ -280,7 +362,7 @@ done:
280} 362}
281 363
282static void 364static void
283set_name(struct param *p) 365set_name(const struct param *p)
284{ 366{
285 fido_dev_t *dev = NULL; 367 fido_dev_t *dev = NULL;
286 fido_bio_template_t *t = NULL; 368 fido_bio_template_t *t = NULL;
@@ -306,10 +388,11 @@ done:
306} 388}
307 389
308static void 390static void
309del(struct param *p) 391del(const struct param *p)
310{ 392{
311 fido_dev_t *dev = NULL; 393 fido_dev_t *dev = NULL;
312 fido_bio_template_t *t = NULL; 394 fido_bio_template_t *t = NULL;
395 int r;
313 396
314 set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); 397 set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len);
315 398
@@ -317,8 +400,9 @@ del(struct param *p)
317 (t = fido_bio_template_new()) == NULL) 400 (t = fido_bio_template_new()) == NULL)
318 goto done; 401 goto done;
319 402
320 fido_bio_template_set_id(t, p->id.body, p->id.len); 403 r = fido_bio_template_set_id(t, p->id.body, p->id.len);
321 consume_template(t); 404 consume_template(t);
405 consume_str(fido_strerr(r));
322 406
323 fido_bio_dev_enroll_remove(dev, t, p->pin); 407 fido_bio_dev_enroll_remove(dev, t, p->pin);
324 408
@@ -330,106 +414,37 @@ done:
330 fido_bio_template_free(&t); 414 fido_bio_template_free(&t);
331} 415}
332 416
333int 417void
334LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 418test(const struct param *p)
335{ 419{
336 struct param p; 420 prng_init((unsigned int)p->seed);
337
338 memset(&p, 0, sizeof(p));
339
340 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
341 unpack(data, size, &p) < 0)
342 return (0);
343
344 prng_init((unsigned int)p.seed);
345
346 fido_init(FIDO_DEBUG); 421 fido_init(FIDO_DEBUG);
347 fido_set_log_handler(consume_str); 422 fido_set_log_handler(consume_str);
348 423
349 get_info(&p); 424 get_info(p);
350 enroll(&p); 425 enroll(p);
351 list(&p); 426 list(p);
352 set_name(&p); 427 set_name(p);
353 del(&p); 428 del(p);
354
355 return (0);
356} 429}
357 430
358static size_t 431void
359pack_dummy(uint8_t *ptr, size_t len) 432mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
360{ 433{
361 struct param dummy; 434 if (flags & MUTATE_SEED)
362 uint8_t blob[32768]; 435 p->seed = (int)seed;
363 size_t blob_len;
364
365 memset(&dummy, 0, sizeof(dummy));
366
367 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
368 strlcpy(dummy.name, dummy_name, sizeof(dummy.name));
369
370 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
371 dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data);
372 dummy.list_wire_data.len = sizeof(dummy_list_wire_data);
373 dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data);
374 dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data);
375 dummy.id.len = sizeof(dummy_id);
376
377 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
378 dummy.info_wire_data.len);
379 memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data,
380 dummy.enroll_wire_data.len);
381 memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data,
382 dummy.list_wire_data.len);
383 memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data,
384 dummy.set_name_wire_data.len);
385 memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data,
386 dummy.remove_wire_data.len);
387 memcpy(&dummy.id.body, &dummy_id, dummy.id.len);
388
389 blob_len = pack(blob, sizeof(blob), &dummy);
390 assert(blob_len != 0);
391 436
392 if (blob_len > len) { 437 if (flags & MUTATE_PARAM) {
393 memcpy(ptr, blob, len); 438 mutate_blob(&p->id);
394 return (len); 439 mutate_string(p->pin);
440 mutate_string(p->name);
395 } 441 }
396 442
397 memcpy(ptr, blob, blob_len); 443 if (flags & MUTATE_WIREDATA) {
398 444 mutate_blob(&p->info_wire_data);
399 return (blob_len); 445 mutate_blob(&p->enroll_wire_data);
400} 446 mutate_blob(&p->list_wire_data);
401 447 mutate_blob(&p->set_name_wire_data);
402size_t 448 mutate_blob(&p->remove_wire_data);
403LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 449 }
404 unsigned int seed) NO_MSAN
405{
406 struct param p;
407 uint8_t blob[16384];
408 size_t blob_len;
409
410 memset(&p, 0, sizeof(p));
411
412 if (unpack(data, size, &p) < 0)
413 return (pack_dummy(data, maxsize));
414
415 p.seed = (int)seed;
416
417 mutate_blob(&p.id);
418 mutate_blob(&p.info_wire_data);
419 mutate_blob(&p.enroll_wire_data);
420 mutate_blob(&p.list_wire_data);
421 mutate_blob(&p.set_name_wire_data);
422 mutate_blob(&p.remove_wire_data);
423
424 mutate_string(p.pin);
425 mutate_string(p.name);
426
427 blob_len = pack(blob, sizeof(blob), &p);
428
429 if (blob_len == 0 || blob_len > maxsize)
430 return (0);
431
432 memcpy(data, blob, blob_len);
433
434 return (blob_len);
435} 450}