xref: /netbsd-src/external/bsd/libfido2/dist/fuzz/fuzz_hid.c (revision 2d40c4512a84c0d064ec30a492c5e2a14d230bc3)
195dbdf32Schristos /*
2*2d40c451Schristos  * Copyright (c) 2020-2021 Yubico AB. All rights reserved.
395dbdf32Schristos  * Use of this source code is governed by a BSD-style
495dbdf32Schristos  * license that can be found in the LICENSE file.
5*2d40c451Schristos  * SPDX-License-Identifier: BSD-2-Clause
695dbdf32Schristos  */
795dbdf32Schristos 
895dbdf32Schristos #include <assert.h>
995dbdf32Schristos #include <stdint.h>
1095dbdf32Schristos #include <stdlib.h>
1195dbdf32Schristos #include <string.h>
1295dbdf32Schristos #include <stdio.h>
1395dbdf32Schristos 
1495dbdf32Schristos #include "../openbsd-compat/openbsd-compat.h"
1595dbdf32Schristos #include "mutator_aux.h"
16*2d40c451Schristos #include "dummy.h"
1795dbdf32Schristos 
1895dbdf32Schristos extern int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *);
1995dbdf32Schristos extern int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *);
20ede6d7f8Schristos extern void set_udev_parameters(const char *, const struct blob *);
2195dbdf32Schristos 
2295dbdf32Schristos struct param {
2395dbdf32Schristos 	int seed;
24ede6d7f8Schristos 	char uevent[MAXSTR];
2595dbdf32Schristos 	struct blob report_descriptor;
26*2d40c451Schristos 	struct blob netlink_wiredata;
2795dbdf32Schristos };
2895dbdf32Schristos 
2995dbdf32Schristos /*
3095dbdf32Schristos  * Sample HID report descriptor from the FIDO HID interface of a YubiKey 5.
3195dbdf32Schristos  */
3295dbdf32Schristos static const uint8_t dummy_report_descriptor[] = {
3395dbdf32Schristos 	0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09,
3495dbdf32Schristos 	0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08,
3595dbdf32Schristos 	0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00,
3695dbdf32Schristos 	0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x40, 0x91,
3795dbdf32Schristos 	0x02, 0xc0
3895dbdf32Schristos };
3995dbdf32Schristos 
40ede6d7f8Schristos /*
41ede6d7f8Schristos  * Sample uevent file from a Yubico Security Key.
42ede6d7f8Schristos  */
43ede6d7f8Schristos static const char dummy_uevent[] =
44ede6d7f8Schristos 	"DRIVER=hid-generic\n"
45ede6d7f8Schristos 	"HID_ID=0003:00001050:00000120\n"
46ede6d7f8Schristos 	"HID_NAME=Yubico Security Key by Yubico\n"
47ede6d7f8Schristos 	"HID_PHYS=usb-0000:00:14.0-3/input0\n"
48ede6d7f8Schristos 	"HID_UNIQ=\n"
49ede6d7f8Schristos 	"MODALIAS=hid:b0003g0001v00001050p00000120\n";
50ede6d7f8Schristos 
5195dbdf32Schristos struct param *
unpack(const uint8_t * ptr,size_t len)5295dbdf32Schristos unpack(const uint8_t *ptr, size_t len)
5395dbdf32Schristos {
5495dbdf32Schristos 	cbor_item_t *item = NULL, **v;
5595dbdf32Schristos 	struct cbor_load_result cbor;
5695dbdf32Schristos 	struct param *p;
5795dbdf32Schristos 	int ok = -1;
5895dbdf32Schristos 
5995dbdf32Schristos 	if ((p = calloc(1, sizeof(*p))) == NULL ||
6095dbdf32Schristos 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
6195dbdf32Schristos 	    cbor.read != len ||
6295dbdf32Schristos 	    cbor_isa_array(item) == false ||
6395dbdf32Schristos 	    cbor_array_is_definite(item) == false ||
64*2d40c451Schristos 	    cbor_array_size(item) != 4 ||
6595dbdf32Schristos 	    (v = cbor_array_handle(item)) == NULL)
6695dbdf32Schristos 		goto fail;
6795dbdf32Schristos 
6895dbdf32Schristos 	if (unpack_int(v[0], &p->seed) < 0 ||
69ede6d7f8Schristos 	    unpack_string(v[1], p->uevent) < 0 ||
70*2d40c451Schristos 	    unpack_blob(v[2], &p->report_descriptor) < 0 ||
71*2d40c451Schristos 	    unpack_blob(v[3], &p->netlink_wiredata) < 0)
7295dbdf32Schristos 		goto fail;
7395dbdf32Schristos 
7495dbdf32Schristos 	ok = 0;
7595dbdf32Schristos fail:
7695dbdf32Schristos 	if (ok < 0) {
7795dbdf32Schristos 		free(p);
7895dbdf32Schristos 		p = NULL;
7995dbdf32Schristos 	}
8095dbdf32Schristos 
8195dbdf32Schristos 	if (item)
8295dbdf32Schristos 		cbor_decref(&item);
8395dbdf32Schristos 
8495dbdf32Schristos 	return p;
8595dbdf32Schristos }
8695dbdf32Schristos 
8795dbdf32Schristos size_t
pack(uint8_t * ptr,size_t len,const struct param * p)8895dbdf32Schristos pack(uint8_t *ptr, size_t len, const struct param *p)
8995dbdf32Schristos {
90*2d40c451Schristos 	cbor_item_t *argv[4], *array = NULL;
9195dbdf32Schristos 	size_t cbor_alloc_len, cbor_len = 0;
9295dbdf32Schristos 	unsigned char *cbor = NULL;
9395dbdf32Schristos 
9495dbdf32Schristos 	memset(argv, 0, sizeof(argv));
9595dbdf32Schristos 
96*2d40c451Schristos 	if ((array = cbor_new_definite_array(4)) == NULL ||
9795dbdf32Schristos 	    (argv[0] = pack_int(p->seed)) == NULL ||
98ede6d7f8Schristos 	    (argv[1] = pack_string(p->uevent)) == NULL ||
99*2d40c451Schristos 	    (argv[2] = pack_blob(&p->report_descriptor)) == NULL ||
100*2d40c451Schristos 	    (argv[3] = pack_blob(&p->netlink_wiredata)) == NULL)
10195dbdf32Schristos 		goto fail;
10295dbdf32Schristos 
103*2d40c451Schristos 	for (size_t i = 0; i < 4; i++)
10495dbdf32Schristos 		if (cbor_array_push(array, argv[i]) == false)
10595dbdf32Schristos 			goto fail;
10695dbdf32Schristos 
10795dbdf32Schristos 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
108*2d40c451Schristos 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
10995dbdf32Schristos 		cbor_len = 0;
11095dbdf32Schristos 		goto fail;
11195dbdf32Schristos 	}
11295dbdf32Schristos 
11395dbdf32Schristos 	memcpy(ptr, cbor, cbor_len);
11495dbdf32Schristos fail:
115*2d40c451Schristos 	for (size_t i = 0; i < 4; i++)
11695dbdf32Schristos 		if (argv[i])
11795dbdf32Schristos 			cbor_decref(&argv[i]);
11895dbdf32Schristos 
11995dbdf32Schristos 	if (array)
12095dbdf32Schristos 		cbor_decref(&array);
12195dbdf32Schristos 
12295dbdf32Schristos 	free(cbor);
12395dbdf32Schristos 
12495dbdf32Schristos 	return cbor_len;
12595dbdf32Schristos }
12695dbdf32Schristos 
12795dbdf32Schristos size_t
pack_dummy(uint8_t * ptr,size_t len)12895dbdf32Schristos pack_dummy(uint8_t *ptr, size_t len)
12995dbdf32Schristos {
13095dbdf32Schristos 	struct param dummy;
131*2d40c451Schristos 	uint8_t	blob[MAXCORPUS];
13295dbdf32Schristos 	size_t blob_len;
13395dbdf32Schristos 
13495dbdf32Schristos 	memset(&dummy, 0, sizeof(dummy));
13595dbdf32Schristos 
13695dbdf32Schristos 	dummy.report_descriptor.len = sizeof(dummy_report_descriptor);
137ede6d7f8Schristos 	strlcpy(dummy.uevent, dummy_uevent, sizeof(dummy.uevent));
13895dbdf32Schristos 	memcpy(&dummy.report_descriptor.body, &dummy_report_descriptor,
13995dbdf32Schristos 	    dummy.report_descriptor.len);
140*2d40c451Schristos 	dummy.netlink_wiredata.len = sizeof(dummy_netlink_wiredata);
141*2d40c451Schristos 	memcpy(&dummy.netlink_wiredata.body, &dummy_netlink_wiredata,
142*2d40c451Schristos 	    dummy.netlink_wiredata.len);
14395dbdf32Schristos 
14495dbdf32Schristos 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
145ede6d7f8Schristos 	if (blob_len > len)
146ede6d7f8Schristos 		blob_len = len;
14795dbdf32Schristos 
14895dbdf32Schristos 	memcpy(ptr, blob, blob_len);
14995dbdf32Schristos 
15095dbdf32Schristos 	return blob_len;
15195dbdf32Schristos }
15295dbdf32Schristos 
15395dbdf32Schristos static void
get_usage(const struct param * p)15495dbdf32Schristos get_usage(const struct param *p)
15595dbdf32Schristos {
15695dbdf32Schristos 	uint32_t usage_page = 0;
15795dbdf32Schristos 
15895dbdf32Schristos 	fido_hid_get_usage(p->report_descriptor.body, p->report_descriptor.len,
15995dbdf32Schristos 	    &usage_page);
16095dbdf32Schristos 	consume(&usage_page, sizeof(usage_page));
16195dbdf32Schristos }
16295dbdf32Schristos 
16395dbdf32Schristos static void
get_report_len(const struct param * p)16495dbdf32Schristos get_report_len(const struct param *p)
16595dbdf32Schristos {
16695dbdf32Schristos 	size_t report_in_len = 0;
16795dbdf32Schristos 	size_t report_out_len = 0;
16895dbdf32Schristos 
16995dbdf32Schristos 	fido_hid_get_report_len(p->report_descriptor.body,
17095dbdf32Schristos 	    p->report_descriptor.len, &report_in_len, &report_out_len);
17195dbdf32Schristos 	consume(&report_in_len, sizeof(report_in_len));
17295dbdf32Schristos 	consume(&report_out_len, sizeof(report_out_len));
17395dbdf32Schristos }
17495dbdf32Schristos 
175ede6d7f8Schristos static void
manifest(const struct param * p)176ede6d7f8Schristos manifest(const struct param *p)
177ede6d7f8Schristos {
178ede6d7f8Schristos 	size_t ndevs, nfound;
179*2d40c451Schristos 	fido_dev_info_t *devlist = NULL, *devlist_set = NULL;
180ede6d7f8Schristos 	int16_t vendor_id, product_id;
181*2d40c451Schristos 	fido_dev_io_t io;
182*2d40c451Schristos 	fido_dev_transport_t t;
183ede6d7f8Schristos 
184*2d40c451Schristos 	memset(&io, 0, sizeof(io));
185*2d40c451Schristos 	memset(&t, 0, sizeof(t));
186*2d40c451Schristos 	set_netlink_io_functions(fd_read, fd_write);
187*2d40c451Schristos 	set_wire_data(p->netlink_wiredata.body, p->netlink_wiredata.len);
188ede6d7f8Schristos 	set_udev_parameters(p->uevent, &p->report_descriptor);
189*2d40c451Schristos 
190ede6d7f8Schristos 	ndevs = uniform_random(64);
191ede6d7f8Schristos 	if ((devlist = fido_dev_info_new(ndevs)) == NULL ||
192*2d40c451Schristos 	    (devlist_set = fido_dev_info_new(1)) == NULL ||
193ede6d7f8Schristos 	    fido_dev_info_manifest(devlist, ndevs, &nfound) != FIDO_OK)
194ede6d7f8Schristos 		goto out;
195ede6d7f8Schristos 	for (size_t i = 0; i < nfound; i++) {
196ede6d7f8Schristos 		const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
197ede6d7f8Schristos 		consume_str(fido_dev_info_path(di));
198ede6d7f8Schristos 		consume_str(fido_dev_info_manufacturer_string(di));
199ede6d7f8Schristos 		consume_str(fido_dev_info_product_string(di));
200ede6d7f8Schristos 		vendor_id = fido_dev_info_vendor(di);
201ede6d7f8Schristos 		product_id = fido_dev_info_product(di);
202ede6d7f8Schristos 		consume(&vendor_id, sizeof(vendor_id));
203ede6d7f8Schristos 		consume(&product_id, sizeof(product_id));
204*2d40c451Schristos 		fido_dev_info_set(devlist_set, 0, fido_dev_info_path(di),
205*2d40c451Schristos 		    fido_dev_info_manufacturer_string(di),
206*2d40c451Schristos 		    fido_dev_info_product_string(di), &io, &t);
207ede6d7f8Schristos 	}
208ede6d7f8Schristos out:
209ede6d7f8Schristos 	fido_dev_info_free(&devlist, ndevs);
210*2d40c451Schristos 	fido_dev_info_free(&devlist_set, 1);
211ede6d7f8Schristos }
212ede6d7f8Schristos 
21395dbdf32Schristos void
test(const struct param * p)21495dbdf32Schristos test(const struct param *p)
21595dbdf32Schristos {
21695dbdf32Schristos 	prng_init((unsigned int)p->seed);
217*2d40c451Schristos 	fuzz_clock_reset();
21895dbdf32Schristos 	fido_init(FIDO_DEBUG);
21995dbdf32Schristos 	fido_set_log_handler(consume_str);
22095dbdf32Schristos 
22195dbdf32Schristos 	get_usage(p);
22295dbdf32Schristos 	get_report_len(p);
223ede6d7f8Schristos 	manifest(p);
22495dbdf32Schristos }
22595dbdf32Schristos 
22695dbdf32Schristos void
mutate(struct param * p,unsigned int seed,unsigned int flags)22795dbdf32Schristos mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
22895dbdf32Schristos {
22995dbdf32Schristos 	if (flags & MUTATE_SEED)
23095dbdf32Schristos 		p->seed = (int)seed;
23195dbdf32Schristos 
232ede6d7f8Schristos 	if (flags & MUTATE_PARAM) {
23395dbdf32Schristos 		mutate_blob(&p->report_descriptor);
234ede6d7f8Schristos 		mutate_string(p->uevent);
235ede6d7f8Schristos 	}
236*2d40c451Schristos 
237*2d40c451Schristos 	if (flags & MUTATE_WIREDATA)
238*2d40c451Schristos 		mutate_blob(&p->netlink_wiredata);
23995dbdf32Schristos }
240