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