xref: /freebsd/contrib/libfido2/fuzz/fuzz_largeblob.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
20afa8e06SEd Maste  * Copyright (c) 2020 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 <stdio.h>
110afa8e06SEd Maste #include <stdlib.h>
120afa8e06SEd Maste #include <string.h>
130afa8e06SEd Maste 
140afa8e06SEd Maste #include "mutator_aux.h"
150afa8e06SEd Maste #include "wiredata_fido2.h"
160afa8e06SEd Maste #include "dummy.h"
170afa8e06SEd Maste 
180afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
190afa8e06SEd Maste 
200afa8e06SEd Maste /* Parameter set defining a FIDO2 "large blob" operation. */
210afa8e06SEd Maste struct param {
220afa8e06SEd Maste 	char pin[MAXSTR];
230afa8e06SEd Maste 	int seed;
240afa8e06SEd Maste 	struct blob key;
250afa8e06SEd Maste 	struct blob get_wiredata;
260afa8e06SEd Maste 	struct blob set_wiredata;
270afa8e06SEd Maste };
280afa8e06SEd Maste 
290afa8e06SEd Maste /*
300afa8e06SEd Maste  * Collection of HID reports from an authenticator issued with a FIDO2
310afa8e06SEd Maste  * 'authenticatorLargeBlobs' 'get' command.
320afa8e06SEd Maste  */
330afa8e06SEd Maste static const uint8_t dummy_get_wiredata[] = {
340afa8e06SEd Maste 	WIREDATA_CTAP_INIT,
350afa8e06SEd Maste 	WIREDATA_CTAP_CBOR_INFO,
360afa8e06SEd Maste 	WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY
370afa8e06SEd Maste };
380afa8e06SEd Maste 
390afa8e06SEd Maste /*
400afa8e06SEd Maste  * Collection of HID reports from an authenticator issued with a FIDO2
410afa8e06SEd Maste  * 'authenticatorLargeBlobs' 'set' command.
420afa8e06SEd Maste  */
430afa8e06SEd Maste static const uint8_t dummy_set_wiredata[] = {
440afa8e06SEd Maste 	WIREDATA_CTAP_INIT,
450afa8e06SEd Maste 	WIREDATA_CTAP_CBOR_INFO,
460afa8e06SEd Maste 	WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY,
470afa8e06SEd Maste 	WIREDATA_CTAP_CBOR_AUTHKEY,
480afa8e06SEd Maste 	WIREDATA_CTAP_CBOR_PINTOKEN,
490afa8e06SEd Maste 	WIREDATA_CTAP_CBOR_STATUS
500afa8e06SEd Maste };
510afa8e06SEd Maste 
520afa8e06SEd Maste /*
530afa8e06SEd Maste  * XXX this needs to match the encrypted blob embedded in
540afa8e06SEd Maste  * WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY.
550afa8e06SEd Maste  */
560afa8e06SEd Maste static const uint8_t dummy_key[] = {
570afa8e06SEd Maste 	0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79,
580afa8e06SEd Maste 	0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6,
590afa8e06SEd Maste 	0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32,
600afa8e06SEd Maste 	0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b
610afa8e06SEd Maste };
620afa8e06SEd Maste 
630afa8e06SEd Maste struct param *
unpack(const uint8_t * ptr,size_t len)640afa8e06SEd Maste unpack(const uint8_t *ptr, size_t len)
650afa8e06SEd Maste {
660afa8e06SEd Maste 	cbor_item_t *item = NULL, **v;
670afa8e06SEd Maste 	struct cbor_load_result cbor;
680afa8e06SEd Maste 	struct param *p;
690afa8e06SEd Maste 	int ok = -1;
700afa8e06SEd Maste 
710afa8e06SEd Maste 	if ((p = calloc(1, sizeof(*p))) == NULL ||
720afa8e06SEd Maste 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
730afa8e06SEd Maste 	    cbor.read != len ||
740afa8e06SEd Maste 	    cbor_isa_array(item) == false ||
750afa8e06SEd Maste 	    cbor_array_is_definite(item) == false ||
760afa8e06SEd Maste 	    cbor_array_size(item) != 5 ||
770afa8e06SEd Maste 	    (v = cbor_array_handle(item)) == NULL)
780afa8e06SEd Maste 		goto fail;
790afa8e06SEd Maste 
800afa8e06SEd Maste 	if (unpack_int(v[0], &p->seed) < 0 ||
810afa8e06SEd Maste 	    unpack_string(v[1], p->pin) < 0 ||
820afa8e06SEd Maste 	    unpack_blob(v[2], &p->key) < 0 ||
830afa8e06SEd Maste 	    unpack_blob(v[3], &p->get_wiredata) < 0 ||
840afa8e06SEd Maste 	    unpack_blob(v[4], &p->set_wiredata) < 0)
850afa8e06SEd Maste 		goto fail;
860afa8e06SEd Maste 
870afa8e06SEd Maste 	ok = 0;
880afa8e06SEd Maste fail:
890afa8e06SEd Maste 	if (ok < 0) {
900afa8e06SEd Maste 		free(p);
910afa8e06SEd Maste 		p = NULL;
920afa8e06SEd Maste 	}
930afa8e06SEd Maste 
940afa8e06SEd Maste 	if (item)
950afa8e06SEd Maste 		cbor_decref(&item);
960afa8e06SEd Maste 
970afa8e06SEd Maste 	return p;
980afa8e06SEd Maste }
990afa8e06SEd Maste 
1000afa8e06SEd Maste size_t
pack(uint8_t * ptr,size_t len,const struct param * p)1010afa8e06SEd Maste pack(uint8_t *ptr, size_t len, const struct param *p)
1020afa8e06SEd Maste {
1030afa8e06SEd Maste 	cbor_item_t *argv[5], *array = NULL;
1040afa8e06SEd Maste 	size_t cbor_alloc_len, cbor_len = 0;
1050afa8e06SEd Maste 	unsigned char *cbor = NULL;
1060afa8e06SEd Maste 
1070afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
1080afa8e06SEd Maste 
1090afa8e06SEd Maste 	if ((array = cbor_new_definite_array(5)) == NULL ||
1100afa8e06SEd Maste 	    (argv[0] = pack_int(p->seed)) == NULL ||
1110afa8e06SEd Maste 	    (argv[1] = pack_string(p->pin)) == NULL ||
1120afa8e06SEd Maste 	    (argv[2] = pack_blob(&p->key)) == NULL ||
1130afa8e06SEd Maste 	    (argv[3] = pack_blob(&p->get_wiredata)) == NULL ||
1140afa8e06SEd Maste 	    (argv[4] = pack_blob(&p->set_wiredata)) == NULL)
1150afa8e06SEd Maste 		goto fail;
1160afa8e06SEd Maste 
1170afa8e06SEd Maste 	for (size_t i = 0; i < 5; i++)
1180afa8e06SEd Maste 		if (cbor_array_push(array, argv[i]) == false)
1190afa8e06SEd Maste 			goto fail;
1200afa8e06SEd Maste 
1210afa8e06SEd Maste 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
122*2ccfa855SEd Maste 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
1230afa8e06SEd Maste 		cbor_len = 0;
1240afa8e06SEd Maste 		goto fail;
1250afa8e06SEd Maste 	}
1260afa8e06SEd Maste 
1270afa8e06SEd Maste 	memcpy(ptr, cbor, cbor_len);
1280afa8e06SEd Maste fail:
1290afa8e06SEd Maste 	for (size_t i = 0; i < 5; i++)
1300afa8e06SEd Maste 		if (argv[i])
1310afa8e06SEd Maste 			cbor_decref(&argv[i]);
1320afa8e06SEd Maste 
1330afa8e06SEd Maste 	if (array)
1340afa8e06SEd Maste 		cbor_decref(&array);
1350afa8e06SEd Maste 
1360afa8e06SEd Maste 	free(cbor);
1370afa8e06SEd Maste 
1380afa8e06SEd Maste 	return cbor_len;
1390afa8e06SEd Maste }
1400afa8e06SEd Maste 
1410afa8e06SEd Maste size_t
pack_dummy(uint8_t * ptr,size_t len)1420afa8e06SEd Maste pack_dummy(uint8_t *ptr, size_t len)
1430afa8e06SEd Maste {
1440afa8e06SEd Maste 	struct param dummy;
145*2ccfa855SEd Maste 	uint8_t blob[MAXCORPUS];
1460afa8e06SEd Maste 	size_t blob_len;
1470afa8e06SEd Maste 
1480afa8e06SEd Maste 	memset(&dummy, 0, sizeof(dummy));
1490afa8e06SEd Maste 
1500afa8e06SEd Maste 	strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
1510afa8e06SEd Maste 
1520afa8e06SEd Maste 	dummy.get_wiredata.len = sizeof(dummy_get_wiredata);
1530afa8e06SEd Maste 	dummy.set_wiredata.len = sizeof(dummy_set_wiredata);
1540afa8e06SEd Maste 	dummy.key.len = sizeof(dummy_key);
1550afa8e06SEd Maste 
1560afa8e06SEd Maste 	memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata,
1570afa8e06SEd Maste 	    dummy.get_wiredata.len);
1580afa8e06SEd Maste 	memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata,
1590afa8e06SEd Maste 	    dummy.set_wiredata.len);
1600afa8e06SEd Maste 	memcpy(&dummy.key.body, &dummy_key, dummy.key.len);
1610afa8e06SEd Maste 
1620afa8e06SEd Maste 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
1630afa8e06SEd Maste 
1640afa8e06SEd Maste 	if (blob_len > len) {
1650afa8e06SEd Maste 		memcpy(ptr, blob, len);
1660afa8e06SEd Maste 		return len;
1670afa8e06SEd Maste 	}
1680afa8e06SEd Maste 
1690afa8e06SEd Maste 	memcpy(ptr, blob, blob_len);
1700afa8e06SEd Maste 
1710afa8e06SEd Maste 	return blob_len;
1720afa8e06SEd Maste }
1730afa8e06SEd Maste 
1740afa8e06SEd Maste static fido_dev_t *
prepare_dev(void)1750afa8e06SEd Maste prepare_dev(void)
1760afa8e06SEd Maste {
1770afa8e06SEd Maste 	fido_dev_t *dev;
1780afa8e06SEd Maste 
1790afa8e06SEd Maste 	if ((dev = open_dev(0)) == NULL)
1800afa8e06SEd Maste 		return NULL;
1810afa8e06SEd Maste 
1820afa8e06SEd Maste 	return dev;
1830afa8e06SEd Maste }
1840afa8e06SEd Maste 
1850afa8e06SEd Maste static void
get_blob(const struct param * p,int array)1860afa8e06SEd Maste get_blob(const struct param *p, int array)
1870afa8e06SEd Maste {
1880afa8e06SEd Maste 	fido_dev_t *dev;
1890afa8e06SEd Maste 	u_char *ptr = NULL;
1900afa8e06SEd Maste 	size_t len = 0;
1910afa8e06SEd Maste 
1920afa8e06SEd Maste 	set_wire_data(p->get_wiredata.body, p->get_wiredata.len);
1930afa8e06SEd Maste 
1940afa8e06SEd Maste 	if ((dev = prepare_dev()) == NULL)
1950afa8e06SEd Maste 		return;
1960afa8e06SEd Maste 
1970afa8e06SEd Maste 	if (array)
1980afa8e06SEd Maste 		fido_dev_largeblob_get_array(dev, &ptr, &len);
1990afa8e06SEd Maste 	else
2000afa8e06SEd Maste 		fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len);
2010afa8e06SEd Maste 	consume(ptr, len);
2020afa8e06SEd Maste 	free(ptr);
2030afa8e06SEd Maste 
2040afa8e06SEd Maste 	fido_dev_close(dev);
2050afa8e06SEd Maste 	fido_dev_free(&dev);
2060afa8e06SEd Maste }
2070afa8e06SEd Maste 
2080afa8e06SEd Maste 
2090afa8e06SEd Maste static void
set_blob(const struct param * p,int op)2100afa8e06SEd Maste set_blob(const struct param *p, int op)
2110afa8e06SEd Maste {
2120afa8e06SEd Maste 	fido_dev_t *dev;
2130afa8e06SEd Maste 	const char *pin;
2140afa8e06SEd Maste 
2150afa8e06SEd Maste 	set_wire_data(p->set_wiredata.body, p->set_wiredata.len);
2160afa8e06SEd Maste 
2170afa8e06SEd Maste 	if ((dev = prepare_dev()) == NULL)
2180afa8e06SEd Maste 		return;
2190afa8e06SEd Maste 	pin = p->pin;
2200afa8e06SEd Maste 	if (strlen(pin) == 0)
2210afa8e06SEd Maste 		pin = NULL;
2220afa8e06SEd Maste 
2230afa8e06SEd Maste 	switch (op) {
2240afa8e06SEd Maste 	case 0:
2250afa8e06SEd Maste 		fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin);
2260afa8e06SEd Maste 		break;
2270afa8e06SEd Maste 	case 1:
2280afa8e06SEd Maste 		/* XXX reuse p->get_wiredata as the blob to be set */
2290afa8e06SEd Maste 		fido_dev_largeblob_set(dev, p->key.body, p->key.len,
2300afa8e06SEd Maste 		    p->get_wiredata.body, p->get_wiredata.len, pin);
2310afa8e06SEd Maste 		break;
2320afa8e06SEd Maste 	case 2:
2330afa8e06SEd Maste 		/* XXX reuse p->get_wiredata as the body of the cbor array */
2340afa8e06SEd Maste 		fido_dev_largeblob_set_array(dev, p->get_wiredata.body,
2350afa8e06SEd Maste 		    p->get_wiredata.len, pin);
2360afa8e06SEd Maste 	}
2370afa8e06SEd Maste 
2380afa8e06SEd Maste 	fido_dev_close(dev);
2390afa8e06SEd Maste 	fido_dev_free(&dev);
2400afa8e06SEd Maste }
2410afa8e06SEd Maste 
2420afa8e06SEd Maste void
test(const struct param * p)2430afa8e06SEd Maste test(const struct param *p)
2440afa8e06SEd Maste {
2450afa8e06SEd Maste 	prng_init((unsigned int)p->seed);
246f540a430SEd Maste 	fuzz_clock_reset();
2470afa8e06SEd Maste 	fido_init(FIDO_DEBUG);
2480afa8e06SEd Maste 	fido_set_log_handler(consume_str);
2490afa8e06SEd Maste 
2500afa8e06SEd Maste 	get_blob(p, 0);
2510afa8e06SEd Maste 	get_blob(p, 1);
2520afa8e06SEd Maste 	set_blob(p, 0);
2530afa8e06SEd Maste 	set_blob(p, 1);
2540afa8e06SEd Maste 	set_blob(p, 2);
2550afa8e06SEd Maste }
2560afa8e06SEd Maste 
2570afa8e06SEd Maste void
mutate(struct param * p,unsigned int seed,unsigned int flags)2580afa8e06SEd Maste mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
2590afa8e06SEd Maste {
2600afa8e06SEd Maste 	if (flags & MUTATE_SEED)
2610afa8e06SEd Maste 		p->seed = (int)seed;
2620afa8e06SEd Maste 
2630afa8e06SEd Maste 	if (flags & MUTATE_PARAM) {
2640afa8e06SEd Maste 		mutate_blob(&p->key);
2650afa8e06SEd Maste 		mutate_string(p->pin);
2660afa8e06SEd Maste 	}
2670afa8e06SEd Maste 
2680afa8e06SEd Maste 	if (flags & MUTATE_WIREDATA) {
2690afa8e06SEd Maste 		mutate_blob(&p->get_wiredata);
2700afa8e06SEd Maste 		mutate_blob(&p->set_wiredata);
2710afa8e06SEd Maste 	}
2720afa8e06SEd Maste }
273