xref: /freebsd/contrib/libfido2/fuzz/fuzz_hid.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
2f540a430SEd Maste  * Copyright (c) 2020-2021 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <assert.h>
90afa8e06SEd Maste #include <stdint.h>
100afa8e06SEd Maste #include <stdlib.h>
110afa8e06SEd Maste #include <string.h>
120afa8e06SEd Maste #include <stdio.h>
130afa8e06SEd Maste 
140afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
150afa8e06SEd Maste #include "mutator_aux.h"
16f540a430SEd Maste #include "dummy.h"
170afa8e06SEd Maste 
180afa8e06SEd Maste extern int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *);
190afa8e06SEd Maste extern int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *);
200afa8e06SEd Maste extern void set_udev_parameters(const char *, const struct blob *);
210afa8e06SEd Maste 
220afa8e06SEd Maste struct param {
230afa8e06SEd Maste 	int seed;
240afa8e06SEd Maste 	char uevent[MAXSTR];
250afa8e06SEd Maste 	struct blob report_descriptor;
26f540a430SEd Maste 	struct blob netlink_wiredata;
270afa8e06SEd Maste };
280afa8e06SEd Maste 
290afa8e06SEd Maste /*
300afa8e06SEd Maste  * Sample HID report descriptor from the FIDO HID interface of a YubiKey 5.
310afa8e06SEd Maste  */
320afa8e06SEd Maste static const uint8_t dummy_report_descriptor[] = {
330afa8e06SEd Maste 	0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09,
340afa8e06SEd Maste 	0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08,
350afa8e06SEd Maste 	0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00,
360afa8e06SEd Maste 	0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x40, 0x91,
370afa8e06SEd Maste 	0x02, 0xc0
380afa8e06SEd Maste };
390afa8e06SEd Maste 
400afa8e06SEd Maste /*
410afa8e06SEd Maste  * Sample uevent file from a Yubico Security Key.
420afa8e06SEd Maste  */
430afa8e06SEd Maste static const char dummy_uevent[] =
440afa8e06SEd Maste 	"DRIVER=hid-generic\n"
450afa8e06SEd Maste 	"HID_ID=0003:00001050:00000120\n"
460afa8e06SEd Maste 	"HID_NAME=Yubico Security Key by Yubico\n"
470afa8e06SEd Maste 	"HID_PHYS=usb-0000:00:14.0-3/input0\n"
480afa8e06SEd Maste 	"HID_UNIQ=\n"
490afa8e06SEd Maste 	"MODALIAS=hid:b0003g0001v00001050p00000120\n";
500afa8e06SEd Maste 
510afa8e06SEd Maste struct param *
unpack(const uint8_t * ptr,size_t len)520afa8e06SEd Maste unpack(const uint8_t *ptr, size_t len)
530afa8e06SEd Maste {
540afa8e06SEd Maste 	cbor_item_t *item = NULL, **v;
550afa8e06SEd Maste 	struct cbor_load_result cbor;
560afa8e06SEd Maste 	struct param *p;
570afa8e06SEd Maste 	int ok = -1;
580afa8e06SEd Maste 
590afa8e06SEd Maste 	if ((p = calloc(1, sizeof(*p))) == NULL ||
600afa8e06SEd Maste 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
610afa8e06SEd Maste 	    cbor.read != len ||
620afa8e06SEd Maste 	    cbor_isa_array(item) == false ||
630afa8e06SEd Maste 	    cbor_array_is_definite(item) == false ||
64f540a430SEd Maste 	    cbor_array_size(item) != 4 ||
650afa8e06SEd Maste 	    (v = cbor_array_handle(item)) == NULL)
660afa8e06SEd Maste 		goto fail;
670afa8e06SEd Maste 
680afa8e06SEd Maste 	if (unpack_int(v[0], &p->seed) < 0 ||
690afa8e06SEd Maste 	    unpack_string(v[1], p->uevent) < 0 ||
70f540a430SEd Maste 	    unpack_blob(v[2], &p->report_descriptor) < 0 ||
71f540a430SEd Maste 	    unpack_blob(v[3], &p->netlink_wiredata) < 0)
720afa8e06SEd Maste 		goto fail;
730afa8e06SEd Maste 
740afa8e06SEd Maste 	ok = 0;
750afa8e06SEd Maste fail:
760afa8e06SEd Maste 	if (ok < 0) {
770afa8e06SEd Maste 		free(p);
780afa8e06SEd Maste 		p = NULL;
790afa8e06SEd Maste 	}
800afa8e06SEd Maste 
810afa8e06SEd Maste 	if (item)
820afa8e06SEd Maste 		cbor_decref(&item);
830afa8e06SEd Maste 
840afa8e06SEd Maste 	return p;
850afa8e06SEd Maste }
860afa8e06SEd Maste 
870afa8e06SEd Maste size_t
pack(uint8_t * ptr,size_t len,const struct param * p)880afa8e06SEd Maste pack(uint8_t *ptr, size_t len, const struct param *p)
890afa8e06SEd Maste {
90f540a430SEd Maste 	cbor_item_t *argv[4], *array = NULL;
910afa8e06SEd Maste 	size_t cbor_alloc_len, cbor_len = 0;
920afa8e06SEd Maste 	unsigned char *cbor = NULL;
930afa8e06SEd Maste 
940afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
950afa8e06SEd Maste 
96f540a430SEd Maste 	if ((array = cbor_new_definite_array(4)) == NULL ||
970afa8e06SEd Maste 	    (argv[0] = pack_int(p->seed)) == NULL ||
980afa8e06SEd Maste 	    (argv[1] = pack_string(p->uevent)) == NULL ||
99f540a430SEd Maste 	    (argv[2] = pack_blob(&p->report_descriptor)) == NULL ||
100f540a430SEd Maste 	    (argv[3] = pack_blob(&p->netlink_wiredata)) == NULL)
1010afa8e06SEd Maste 		goto fail;
1020afa8e06SEd Maste 
103f540a430SEd Maste 	for (size_t i = 0; i < 4; i++)
1040afa8e06SEd Maste 		if (cbor_array_push(array, argv[i]) == false)
1050afa8e06SEd Maste 			goto fail;
1060afa8e06SEd Maste 
1070afa8e06SEd Maste 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
108*2ccfa855SEd Maste 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
1090afa8e06SEd Maste 		cbor_len = 0;
1100afa8e06SEd Maste 		goto fail;
1110afa8e06SEd Maste 	}
1120afa8e06SEd Maste 
1130afa8e06SEd Maste 	memcpy(ptr, cbor, cbor_len);
1140afa8e06SEd Maste fail:
115f540a430SEd Maste 	for (size_t i = 0; i < 4; i++)
1160afa8e06SEd Maste 		if (argv[i])
1170afa8e06SEd Maste 			cbor_decref(&argv[i]);
1180afa8e06SEd Maste 
1190afa8e06SEd Maste 	if (array)
1200afa8e06SEd Maste 		cbor_decref(&array);
1210afa8e06SEd Maste 
1220afa8e06SEd Maste 	free(cbor);
1230afa8e06SEd Maste 
1240afa8e06SEd Maste 	return cbor_len;
1250afa8e06SEd Maste }
1260afa8e06SEd Maste 
1270afa8e06SEd Maste size_t
pack_dummy(uint8_t * ptr,size_t len)1280afa8e06SEd Maste pack_dummy(uint8_t *ptr, size_t len)
1290afa8e06SEd Maste {
1300afa8e06SEd Maste 	struct param dummy;
131*2ccfa855SEd Maste 	uint8_t	blob[MAXCORPUS];
1320afa8e06SEd Maste 	size_t blob_len;
1330afa8e06SEd Maste 
1340afa8e06SEd Maste 	memset(&dummy, 0, sizeof(dummy));
1350afa8e06SEd Maste 
1360afa8e06SEd Maste 	dummy.report_descriptor.len = sizeof(dummy_report_descriptor);
1370afa8e06SEd Maste 	strlcpy(dummy.uevent, dummy_uevent, sizeof(dummy.uevent));
1380afa8e06SEd Maste 	memcpy(&dummy.report_descriptor.body, &dummy_report_descriptor,
1390afa8e06SEd Maste 	    dummy.report_descriptor.len);
140f540a430SEd Maste 	dummy.netlink_wiredata.len = sizeof(dummy_netlink_wiredata);
141f540a430SEd Maste 	memcpy(&dummy.netlink_wiredata.body, &dummy_netlink_wiredata,
142f540a430SEd Maste 	    dummy.netlink_wiredata.len);
1430afa8e06SEd Maste 
1440afa8e06SEd Maste 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
1450afa8e06SEd Maste 	if (blob_len > len)
1460afa8e06SEd Maste 		blob_len = len;
1470afa8e06SEd Maste 
1480afa8e06SEd Maste 	memcpy(ptr, blob, blob_len);
1490afa8e06SEd Maste 
1500afa8e06SEd Maste 	return blob_len;
1510afa8e06SEd Maste }
1520afa8e06SEd Maste 
1530afa8e06SEd Maste static void
get_usage(const struct param * p)1540afa8e06SEd Maste get_usage(const struct param *p)
1550afa8e06SEd Maste {
1560afa8e06SEd Maste 	uint32_t usage_page = 0;
1570afa8e06SEd Maste 
1580afa8e06SEd Maste 	fido_hid_get_usage(p->report_descriptor.body, p->report_descriptor.len,
1590afa8e06SEd Maste 	    &usage_page);
1600afa8e06SEd Maste 	consume(&usage_page, sizeof(usage_page));
1610afa8e06SEd Maste }
1620afa8e06SEd Maste 
1630afa8e06SEd Maste static void
get_report_len(const struct param * p)1640afa8e06SEd Maste get_report_len(const struct param *p)
1650afa8e06SEd Maste {
1660afa8e06SEd Maste 	size_t report_in_len = 0;
1670afa8e06SEd Maste 	size_t report_out_len = 0;
1680afa8e06SEd Maste 
1690afa8e06SEd Maste 	fido_hid_get_report_len(p->report_descriptor.body,
1700afa8e06SEd Maste 	    p->report_descriptor.len, &report_in_len, &report_out_len);
1710afa8e06SEd Maste 	consume(&report_in_len, sizeof(report_in_len));
1720afa8e06SEd Maste 	consume(&report_out_len, sizeof(report_out_len));
1730afa8e06SEd Maste }
1740afa8e06SEd Maste 
1750afa8e06SEd Maste static void
manifest(const struct param * p)1760afa8e06SEd Maste manifest(const struct param *p)
1770afa8e06SEd Maste {
1780afa8e06SEd Maste 	size_t ndevs, nfound;
1793e696dfbSEd Maste 	fido_dev_info_t *devlist = NULL, *devlist_set = NULL;
1800afa8e06SEd Maste 	int16_t vendor_id, product_id;
1813e696dfbSEd Maste 	fido_dev_io_t io;
1823e696dfbSEd Maste 	fido_dev_transport_t t;
1830afa8e06SEd Maste 
1843e696dfbSEd Maste 	memset(&io, 0, sizeof(io));
1853e696dfbSEd Maste 	memset(&t, 0, sizeof(t));
186f540a430SEd Maste 	set_netlink_io_functions(fd_read, fd_write);
187f540a430SEd Maste 	set_wire_data(p->netlink_wiredata.body, p->netlink_wiredata.len);
1880afa8e06SEd Maste 	set_udev_parameters(p->uevent, &p->report_descriptor);
189f540a430SEd Maste 
1900afa8e06SEd Maste 	ndevs = uniform_random(64);
1910afa8e06SEd Maste 	if ((devlist = fido_dev_info_new(ndevs)) == NULL ||
1923e696dfbSEd Maste 	    (devlist_set = fido_dev_info_new(1)) == NULL ||
1930afa8e06SEd Maste 	    fido_dev_info_manifest(devlist, ndevs, &nfound) != FIDO_OK)
1940afa8e06SEd Maste 		goto out;
1950afa8e06SEd Maste 	for (size_t i = 0; i < nfound; i++) {
1960afa8e06SEd Maste 		const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
1970afa8e06SEd Maste 		consume_str(fido_dev_info_path(di));
1980afa8e06SEd Maste 		consume_str(fido_dev_info_manufacturer_string(di));
1990afa8e06SEd Maste 		consume_str(fido_dev_info_product_string(di));
2000afa8e06SEd Maste 		vendor_id = fido_dev_info_vendor(di);
2010afa8e06SEd Maste 		product_id = fido_dev_info_product(di);
2020afa8e06SEd Maste 		consume(&vendor_id, sizeof(vendor_id));
2030afa8e06SEd Maste 		consume(&product_id, sizeof(product_id));
2043e696dfbSEd Maste 		fido_dev_info_set(devlist_set, 0, fido_dev_info_path(di),
2053e696dfbSEd Maste 		    fido_dev_info_manufacturer_string(di),
2063e696dfbSEd Maste 		    fido_dev_info_product_string(di), &io, &t);
2070afa8e06SEd Maste 	}
2080afa8e06SEd Maste out:
2090afa8e06SEd Maste 	fido_dev_info_free(&devlist, ndevs);
2103e696dfbSEd Maste 	fido_dev_info_free(&devlist_set, 1);
2110afa8e06SEd Maste }
2120afa8e06SEd Maste 
2130afa8e06SEd Maste void
test(const struct param * p)2140afa8e06SEd Maste test(const struct param *p)
2150afa8e06SEd Maste {
2160afa8e06SEd Maste 	prng_init((unsigned int)p->seed);
217f540a430SEd Maste 	fuzz_clock_reset();
2180afa8e06SEd Maste 	fido_init(FIDO_DEBUG);
2190afa8e06SEd Maste 	fido_set_log_handler(consume_str);
2200afa8e06SEd Maste 
2210afa8e06SEd Maste 	get_usage(p);
2220afa8e06SEd Maste 	get_report_len(p);
2230afa8e06SEd Maste 	manifest(p);
2240afa8e06SEd Maste }
2250afa8e06SEd Maste 
2260afa8e06SEd Maste void
mutate(struct param * p,unsigned int seed,unsigned int flags)2270afa8e06SEd Maste mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
2280afa8e06SEd Maste {
2290afa8e06SEd Maste 	if (flags & MUTATE_SEED)
2300afa8e06SEd Maste 		p->seed = (int)seed;
2310afa8e06SEd Maste 
2320afa8e06SEd Maste 	if (flags & MUTATE_PARAM) {
2330afa8e06SEd Maste 		mutate_blob(&p->report_descriptor);
2340afa8e06SEd Maste 		mutate_string(p->uevent);
2350afa8e06SEd Maste 	}
236f540a430SEd Maste 
237f540a430SEd Maste 	if (flags & MUTATE_WIREDATA)
238f540a430SEd Maste 		mutate_blob(&p->netlink_wiredata);
2390afa8e06SEd Maste }
240