xref: /netbsd-src/external/bsd/libfido2/dist/fuzz/fuzz_largeblob.c (revision 2d40c4512a84c0d064ec30a492c5e2a14d230bc3)
195dbdf32Schristos /*
295dbdf32Schristos  * Copyright (c) 2020 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 <stdio.h>
1195dbdf32Schristos #include <stdlib.h>
1295dbdf32Schristos #include <string.h>
1395dbdf32Schristos 
1495dbdf32Schristos #include "mutator_aux.h"
1595dbdf32Schristos #include "wiredata_fido2.h"
1695dbdf32Schristos #include "dummy.h"
1795dbdf32Schristos 
1895dbdf32Schristos #include "../openbsd-compat/openbsd-compat.h"
1995dbdf32Schristos 
2095dbdf32Schristos /* Parameter set defining a FIDO2 "large blob" operation. */
2195dbdf32Schristos struct param {
2295dbdf32Schristos 	char pin[MAXSTR];
2395dbdf32Schristos 	int seed;
2495dbdf32Schristos 	struct blob key;
2595dbdf32Schristos 	struct blob get_wiredata;
2695dbdf32Schristos 	struct blob set_wiredata;
2795dbdf32Schristos };
2895dbdf32Schristos 
2995dbdf32Schristos /*
3095dbdf32Schristos  * Collection of HID reports from an authenticator issued with a FIDO2
3195dbdf32Schristos  * 'authenticatorLargeBlobs' 'get' command.
3295dbdf32Schristos  */
3395dbdf32Schristos static const uint8_t dummy_get_wiredata[] = {
3495dbdf32Schristos 	WIREDATA_CTAP_INIT,
3595dbdf32Schristos 	WIREDATA_CTAP_CBOR_INFO,
3695dbdf32Schristos 	WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY
3795dbdf32Schristos };
3895dbdf32Schristos 
3995dbdf32Schristos /*
4095dbdf32Schristos  * Collection of HID reports from an authenticator issued with a FIDO2
4195dbdf32Schristos  * 'authenticatorLargeBlobs' 'set' command.
4295dbdf32Schristos  */
4395dbdf32Schristos static const uint8_t dummy_set_wiredata[] = {
4495dbdf32Schristos 	WIREDATA_CTAP_INIT,
4595dbdf32Schristos 	WIREDATA_CTAP_CBOR_INFO,
4695dbdf32Schristos 	WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY,
4795dbdf32Schristos 	WIREDATA_CTAP_CBOR_AUTHKEY,
4895dbdf32Schristos 	WIREDATA_CTAP_CBOR_PINTOKEN,
4995dbdf32Schristos 	WIREDATA_CTAP_CBOR_STATUS
5095dbdf32Schristos };
5195dbdf32Schristos 
5295dbdf32Schristos /*
5395dbdf32Schristos  * XXX this needs to match the encrypted blob embedded in
5495dbdf32Schristos  * WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY.
5595dbdf32Schristos  */
5695dbdf32Schristos static const uint8_t dummy_key[] = {
5795dbdf32Schristos 	0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79,
5895dbdf32Schristos 	0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6,
5995dbdf32Schristos 	0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32,
6095dbdf32Schristos 	0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b
6195dbdf32Schristos };
6295dbdf32Schristos 
6395dbdf32Schristos struct param *
unpack(const uint8_t * ptr,size_t len)6495dbdf32Schristos unpack(const uint8_t *ptr, size_t len)
6595dbdf32Schristos {
6695dbdf32Schristos 	cbor_item_t *item = NULL, **v;
6795dbdf32Schristos 	struct cbor_load_result cbor;
6895dbdf32Schristos 	struct param *p;
6995dbdf32Schristos 	int ok = -1;
7095dbdf32Schristos 
7195dbdf32Schristos 	if ((p = calloc(1, sizeof(*p))) == NULL ||
7295dbdf32Schristos 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
7395dbdf32Schristos 	    cbor.read != len ||
7495dbdf32Schristos 	    cbor_isa_array(item) == false ||
7595dbdf32Schristos 	    cbor_array_is_definite(item) == false ||
7695dbdf32Schristos 	    cbor_array_size(item) != 5 ||
7795dbdf32Schristos 	    (v = cbor_array_handle(item)) == NULL)
7895dbdf32Schristos 		goto fail;
7995dbdf32Schristos 
8095dbdf32Schristos 	if (unpack_int(v[0], &p->seed) < 0 ||
8195dbdf32Schristos 	    unpack_string(v[1], p->pin) < 0 ||
8295dbdf32Schristos 	    unpack_blob(v[2], &p->key) < 0 ||
8395dbdf32Schristos 	    unpack_blob(v[3], &p->get_wiredata) < 0 ||
8495dbdf32Schristos 	    unpack_blob(v[4], &p->set_wiredata) < 0)
8595dbdf32Schristos 		goto fail;
8695dbdf32Schristos 
8795dbdf32Schristos 	ok = 0;
8895dbdf32Schristos fail:
8995dbdf32Schristos 	if (ok < 0) {
9095dbdf32Schristos 		free(p);
9195dbdf32Schristos 		p = NULL;
9295dbdf32Schristos 	}
9395dbdf32Schristos 
9495dbdf32Schristos 	if (item)
9595dbdf32Schristos 		cbor_decref(&item);
9695dbdf32Schristos 
9795dbdf32Schristos 	return p;
9895dbdf32Schristos }
9995dbdf32Schristos 
10095dbdf32Schristos size_t
pack(uint8_t * ptr,size_t len,const struct param * p)10195dbdf32Schristos pack(uint8_t *ptr, size_t len, const struct param *p)
10295dbdf32Schristos {
10395dbdf32Schristos 	cbor_item_t *argv[5], *array = NULL;
10495dbdf32Schristos 	size_t cbor_alloc_len, cbor_len = 0;
10595dbdf32Schristos 	unsigned char *cbor = NULL;
10695dbdf32Schristos 
10795dbdf32Schristos 	memset(argv, 0, sizeof(argv));
10895dbdf32Schristos 
10995dbdf32Schristos 	if ((array = cbor_new_definite_array(5)) == NULL ||
11095dbdf32Schristos 	    (argv[0] = pack_int(p->seed)) == NULL ||
11195dbdf32Schristos 	    (argv[1] = pack_string(p->pin)) == NULL ||
11295dbdf32Schristos 	    (argv[2] = pack_blob(&p->key)) == NULL ||
11395dbdf32Schristos 	    (argv[3] = pack_blob(&p->get_wiredata)) == NULL ||
11495dbdf32Schristos 	    (argv[4] = pack_blob(&p->set_wiredata)) == NULL)
11595dbdf32Schristos 		goto fail;
11695dbdf32Schristos 
11795dbdf32Schristos 	for (size_t i = 0; i < 5; i++)
11895dbdf32Schristos 		if (cbor_array_push(array, argv[i]) == false)
11995dbdf32Schristos 			goto fail;
12095dbdf32Schristos 
12195dbdf32Schristos 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
122*2d40c451Schristos 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
12395dbdf32Schristos 		cbor_len = 0;
12495dbdf32Schristos 		goto fail;
12595dbdf32Schristos 	}
12695dbdf32Schristos 
12795dbdf32Schristos 	memcpy(ptr, cbor, cbor_len);
12895dbdf32Schristos fail:
12995dbdf32Schristos 	for (size_t i = 0; i < 5; i++)
13095dbdf32Schristos 		if (argv[i])
13195dbdf32Schristos 			cbor_decref(&argv[i]);
13295dbdf32Schristos 
13395dbdf32Schristos 	if (array)
13495dbdf32Schristos 		cbor_decref(&array);
13595dbdf32Schristos 
13695dbdf32Schristos 	free(cbor);
13795dbdf32Schristos 
13895dbdf32Schristos 	return cbor_len;
13995dbdf32Schristos }
14095dbdf32Schristos 
14195dbdf32Schristos size_t
pack_dummy(uint8_t * ptr,size_t len)14295dbdf32Schristos pack_dummy(uint8_t *ptr, size_t len)
14395dbdf32Schristos {
14495dbdf32Schristos 	struct param dummy;
145*2d40c451Schristos 	uint8_t blob[MAXCORPUS];
14695dbdf32Schristos 	size_t blob_len;
14795dbdf32Schristos 
14895dbdf32Schristos 	memset(&dummy, 0, sizeof(dummy));
14995dbdf32Schristos 
15095dbdf32Schristos 	strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
15195dbdf32Schristos 
15295dbdf32Schristos 	dummy.get_wiredata.len = sizeof(dummy_get_wiredata);
15395dbdf32Schristos 	dummy.set_wiredata.len = sizeof(dummy_set_wiredata);
15495dbdf32Schristos 	dummy.key.len = sizeof(dummy_key);
15595dbdf32Schristos 
15695dbdf32Schristos 	memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata,
15795dbdf32Schristos 	    dummy.get_wiredata.len);
15895dbdf32Schristos 	memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata,
15995dbdf32Schristos 	    dummy.set_wiredata.len);
16095dbdf32Schristos 	memcpy(&dummy.key.body, &dummy_key, dummy.key.len);
16195dbdf32Schristos 
16295dbdf32Schristos 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
16395dbdf32Schristos 
16495dbdf32Schristos 	if (blob_len > len) {
16595dbdf32Schristos 		memcpy(ptr, blob, len);
16695dbdf32Schristos 		return len;
16795dbdf32Schristos 	}
16895dbdf32Schristos 
16995dbdf32Schristos 	memcpy(ptr, blob, blob_len);
17095dbdf32Schristos 
17195dbdf32Schristos 	return blob_len;
17295dbdf32Schristos }
17395dbdf32Schristos 
17495dbdf32Schristos static fido_dev_t *
prepare_dev(void)17595dbdf32Schristos prepare_dev(void)
17695dbdf32Schristos {
17795dbdf32Schristos 	fido_dev_t *dev;
17895dbdf32Schristos 
17995dbdf32Schristos 	if ((dev = open_dev(0)) == NULL)
18095dbdf32Schristos 		return NULL;
18195dbdf32Schristos 
18295dbdf32Schristos 	return dev;
18395dbdf32Schristos }
18495dbdf32Schristos 
18595dbdf32Schristos static void
get_blob(const struct param * p,int array)18695dbdf32Schristos get_blob(const struct param *p, int array)
18795dbdf32Schristos {
18895dbdf32Schristos 	fido_dev_t *dev;
18995dbdf32Schristos 	u_char *ptr = NULL;
19095dbdf32Schristos 	size_t len = 0;
19195dbdf32Schristos 
19295dbdf32Schristos 	set_wire_data(p->get_wiredata.body, p->get_wiredata.len);
19395dbdf32Schristos 
19495dbdf32Schristos 	if ((dev = prepare_dev()) == NULL)
19595dbdf32Schristos 		return;
19695dbdf32Schristos 
19795dbdf32Schristos 	if (array)
19895dbdf32Schristos 		fido_dev_largeblob_get_array(dev, &ptr, &len);
19995dbdf32Schristos 	else
20095dbdf32Schristos 		fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len);
20195dbdf32Schristos 	consume(ptr, len);
20295dbdf32Schristos 	free(ptr);
20395dbdf32Schristos 
20495dbdf32Schristos 	fido_dev_close(dev);
20595dbdf32Schristos 	fido_dev_free(&dev);
20695dbdf32Schristos }
20795dbdf32Schristos 
20895dbdf32Schristos 
20995dbdf32Schristos static void
set_blob(const struct param * p,int op)21095dbdf32Schristos set_blob(const struct param *p, int op)
21195dbdf32Schristos {
21295dbdf32Schristos 	fido_dev_t *dev;
21395dbdf32Schristos 	const char *pin;
21495dbdf32Schristos 
21595dbdf32Schristos 	set_wire_data(p->set_wiredata.body, p->set_wiredata.len);
21695dbdf32Schristos 
21795dbdf32Schristos 	if ((dev = prepare_dev()) == NULL)
21895dbdf32Schristos 		return;
21995dbdf32Schristos 	pin = p->pin;
22095dbdf32Schristos 	if (strlen(pin) == 0)
22195dbdf32Schristos 		pin = NULL;
22295dbdf32Schristos 
22395dbdf32Schristos 	switch (op) {
22495dbdf32Schristos 	case 0:
22595dbdf32Schristos 		fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin);
22695dbdf32Schristos 		break;
22795dbdf32Schristos 	case 1:
22895dbdf32Schristos 		/* XXX reuse p->get_wiredata as the blob to be set */
22995dbdf32Schristos 		fido_dev_largeblob_set(dev, p->key.body, p->key.len,
23095dbdf32Schristos 		    p->get_wiredata.body, p->get_wiredata.len, pin);
23195dbdf32Schristos 		break;
23295dbdf32Schristos 	case 2:
23395dbdf32Schristos 		/* XXX reuse p->get_wiredata as the body of the cbor array */
23495dbdf32Schristos 		fido_dev_largeblob_set_array(dev, p->get_wiredata.body,
23595dbdf32Schristos 		    p->get_wiredata.len, pin);
23695dbdf32Schristos 	}
23795dbdf32Schristos 
23895dbdf32Schristos 	fido_dev_close(dev);
23995dbdf32Schristos 	fido_dev_free(&dev);
24095dbdf32Schristos }
24195dbdf32Schristos 
24295dbdf32Schristos void
test(const struct param * p)24395dbdf32Schristos test(const struct param *p)
24495dbdf32Schristos {
24595dbdf32Schristos 	prng_init((unsigned int)p->seed);
246*2d40c451Schristos 	fuzz_clock_reset();
24795dbdf32Schristos 	fido_init(FIDO_DEBUG);
24895dbdf32Schristos 	fido_set_log_handler(consume_str);
24995dbdf32Schristos 
25095dbdf32Schristos 	get_blob(p, 0);
25195dbdf32Schristos 	get_blob(p, 1);
25295dbdf32Schristos 	set_blob(p, 0);
25395dbdf32Schristos 	set_blob(p, 1);
25495dbdf32Schristos 	set_blob(p, 2);
25595dbdf32Schristos }
25695dbdf32Schristos 
25795dbdf32Schristos void
mutate(struct param * p,unsigned int seed,unsigned int flags)25895dbdf32Schristos mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
25995dbdf32Schristos {
26095dbdf32Schristos 	if (flags & MUTATE_SEED)
26195dbdf32Schristos 		p->seed = (int)seed;
26295dbdf32Schristos 
26395dbdf32Schristos 	if (flags & MUTATE_PARAM) {
26495dbdf32Schristos 		mutate_blob(&p->key);
26595dbdf32Schristos 		mutate_string(p->pin);
26695dbdf32Schristos 	}
26795dbdf32Schristos 
26895dbdf32Schristos 	if (flags & MUTATE_WIREDATA) {
26995dbdf32Schristos 		mutate_blob(&p->get_wiredata);
27095dbdf32Schristos 		mutate_blob(&p->set_wiredata);
27195dbdf32Schristos 	}
27295dbdf32Schristos }
273