Home | History | Annotate | Line # | Download | only in fuzz
      1 /*
      2  * Copyright (c) 2020 Yubico AB. All rights reserved.
      3  * Use of this source code is governed by a BSD-style
      4  * license that can be found in the LICENSE file.
      5  * SPDX-License-Identifier: BSD-2-Clause
      6  */
      7 
      8 #include <assert.h>
      9 #include <stdint.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 
     14 #include "mutator_aux.h"
     15 #include "wiredata_fido2.h"
     16 #include "dummy.h"
     17 
     18 #include "../openbsd-compat/openbsd-compat.h"
     19 
     20 /* Parameter set defining a FIDO2 "large blob" operation. */
     21 struct param {
     22 	char pin[MAXSTR];
     23 	int seed;
     24 	struct blob key;
     25 	struct blob get_wiredata;
     26 	struct blob set_wiredata;
     27 };
     28 
     29 /*
     30  * Collection of HID reports from an authenticator issued with a FIDO2
     31  * 'authenticatorLargeBlobs' 'get' command.
     32  */
     33 static const uint8_t dummy_get_wiredata[] = {
     34 	WIREDATA_CTAP_INIT,
     35 	WIREDATA_CTAP_CBOR_INFO,
     36 	WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY
     37 };
     38 
     39 /*
     40  * Collection of HID reports from an authenticator issued with a FIDO2
     41  * 'authenticatorLargeBlobs' 'set' command.
     42  */
     43 static const uint8_t dummy_set_wiredata[] = {
     44 	WIREDATA_CTAP_INIT,
     45 	WIREDATA_CTAP_CBOR_INFO,
     46 	WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY,
     47 	WIREDATA_CTAP_CBOR_AUTHKEY,
     48 	WIREDATA_CTAP_CBOR_PINTOKEN,
     49 	WIREDATA_CTAP_CBOR_STATUS
     50 };
     51 
     52 /*
     53  * XXX this needs to match the encrypted blob embedded in
     54  * WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY.
     55  */
     56 static const uint8_t dummy_key[] = {
     57 	0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79,
     58 	0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6,
     59 	0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32,
     60 	0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b
     61 };
     62 
     63 struct param *
     64 unpack(const uint8_t *ptr, size_t len)
     65 {
     66 	cbor_item_t *item = NULL, **v;
     67 	struct cbor_load_result cbor;
     68 	struct param *p;
     69 	int ok = -1;
     70 
     71 	if ((p = calloc(1, sizeof(*p))) == NULL ||
     72 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
     73 	    cbor.read != len ||
     74 	    cbor_isa_array(item) == false ||
     75 	    cbor_array_is_definite(item) == false ||
     76 	    cbor_array_size(item) != 5 ||
     77 	    (v = cbor_array_handle(item)) == NULL)
     78 		goto fail;
     79 
     80 	if (unpack_int(v[0], &p->seed) < 0 ||
     81 	    unpack_string(v[1], p->pin) < 0 ||
     82 	    unpack_blob(v[2], &p->key) < 0 ||
     83 	    unpack_blob(v[3], &p->get_wiredata) < 0 ||
     84 	    unpack_blob(v[4], &p->set_wiredata) < 0)
     85 		goto fail;
     86 
     87 	ok = 0;
     88 fail:
     89 	if (ok < 0) {
     90 		free(p);
     91 		p = NULL;
     92 	}
     93 
     94 	if (item)
     95 		cbor_decref(&item);
     96 
     97 	return p;
     98 }
     99 
    100 size_t
    101 pack(uint8_t *ptr, size_t len, const struct param *p)
    102 {
    103 	cbor_item_t *argv[5], *array = NULL;
    104 	size_t cbor_alloc_len, cbor_len = 0;
    105 	unsigned char *cbor = NULL;
    106 
    107 	memset(argv, 0, sizeof(argv));
    108 
    109 	if ((array = cbor_new_definite_array(5)) == NULL ||
    110 	    (argv[0] = pack_int(p->seed)) == NULL ||
    111 	    (argv[1] = pack_string(p->pin)) == NULL ||
    112 	    (argv[2] = pack_blob(&p->key)) == NULL ||
    113 	    (argv[3] = pack_blob(&p->get_wiredata)) == NULL ||
    114 	    (argv[4] = pack_blob(&p->set_wiredata)) == NULL)
    115 		goto fail;
    116 
    117 	for (size_t i = 0; i < 5; i++)
    118 		if (cbor_array_push(array, argv[i]) == false)
    119 			goto fail;
    120 
    121 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
    122 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
    123 		cbor_len = 0;
    124 		goto fail;
    125 	}
    126 
    127 	memcpy(ptr, cbor, cbor_len);
    128 fail:
    129 	for (size_t i = 0; i < 5; i++)
    130 		if (argv[i])
    131 			cbor_decref(&argv[i]);
    132 
    133 	if (array)
    134 		cbor_decref(&array);
    135 
    136 	free(cbor);
    137 
    138 	return cbor_len;
    139 }
    140 
    141 size_t
    142 pack_dummy(uint8_t *ptr, size_t len)
    143 {
    144 	struct param dummy;
    145 	uint8_t blob[MAXCORPUS];
    146 	size_t blob_len;
    147 
    148 	memset(&dummy, 0, sizeof(dummy));
    149 
    150 	strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
    151 
    152 	dummy.get_wiredata.len = sizeof(dummy_get_wiredata);
    153 	dummy.set_wiredata.len = sizeof(dummy_set_wiredata);
    154 	dummy.key.len = sizeof(dummy_key);
    155 
    156 	memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata,
    157 	    dummy.get_wiredata.len);
    158 	memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata,
    159 	    dummy.set_wiredata.len);
    160 	memcpy(&dummy.key.body, &dummy_key, dummy.key.len);
    161 
    162 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
    163 
    164 	if (blob_len > len) {
    165 		memcpy(ptr, blob, len);
    166 		return len;
    167 	}
    168 
    169 	memcpy(ptr, blob, blob_len);
    170 
    171 	return blob_len;
    172 }
    173 
    174 static fido_dev_t *
    175 prepare_dev(void)
    176 {
    177 	fido_dev_t *dev;
    178 
    179 	if ((dev = open_dev(0)) == NULL)
    180 		return NULL;
    181 
    182 	return dev;
    183 }
    184 
    185 static void
    186 get_blob(const struct param *p, int array)
    187 {
    188 	fido_dev_t *dev;
    189 	u_char *ptr = NULL;
    190 	size_t len = 0;
    191 
    192 	set_wire_data(p->get_wiredata.body, p->get_wiredata.len);
    193 
    194 	if ((dev = prepare_dev()) == NULL)
    195 		return;
    196 
    197 	if (array)
    198 		fido_dev_largeblob_get_array(dev, &ptr, &len);
    199 	else
    200 		fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len);
    201 	consume(ptr, len);
    202 	free(ptr);
    203 
    204 	fido_dev_close(dev);
    205 	fido_dev_free(&dev);
    206 }
    207 
    208 
    209 static void
    210 set_blob(const struct param *p, int op)
    211 {
    212 	fido_dev_t *dev;
    213 	const char *pin;
    214 
    215 	set_wire_data(p->set_wiredata.body, p->set_wiredata.len);
    216 
    217 	if ((dev = prepare_dev()) == NULL)
    218 		return;
    219 	pin = p->pin;
    220 	if (strlen(pin) == 0)
    221 		pin = NULL;
    222 
    223 	switch (op) {
    224 	case 0:
    225 		fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin);
    226 		break;
    227 	case 1:
    228 		/* XXX reuse p->get_wiredata as the blob to be set */
    229 		fido_dev_largeblob_set(dev, p->key.body, p->key.len,
    230 		    p->get_wiredata.body, p->get_wiredata.len, pin);
    231 		break;
    232 	case 2:
    233 		/* XXX reuse p->get_wiredata as the body of the cbor array */
    234 		fido_dev_largeblob_set_array(dev, p->get_wiredata.body,
    235 		    p->get_wiredata.len, pin);
    236 	}
    237 
    238 	fido_dev_close(dev);
    239 	fido_dev_free(&dev);
    240 }
    241 
    242 void
    243 test(const struct param *p)
    244 {
    245 	prng_init((unsigned int)p->seed);
    246 	fuzz_clock_reset();
    247 	fido_init(FIDO_DEBUG);
    248 	fido_set_log_handler(consume_str);
    249 
    250 	get_blob(p, 0);
    251 	get_blob(p, 1);
    252 	set_blob(p, 0);
    253 	set_blob(p, 1);
    254 	set_blob(p, 2);
    255 }
    256 
    257 void
    258 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
    259 {
    260 	if (flags & MUTATE_SEED)
    261 		p->seed = (int)seed;
    262 
    263 	if (flags & MUTATE_PARAM) {
    264 		mutate_blob(&p->key);
    265 		mutate_string(p->pin);
    266 	}
    267 
    268 	if (flags & MUTATE_WIREDATA) {
    269 		mutate_blob(&p->get_wiredata);
    270 		mutate_blob(&p->set_wiredata);
    271 	}
    272 }
    273