xref: /netbsd-src/external/bsd/libfido2/dist/fuzz/fuzz_pcsc.c (revision 2d40c4512a84c0d064ec30a492c5e2a14d230bc3)
1*2d40c451Schristos /*
2*2d40c451Schristos  * Copyright (c) 2022 Yubico AB. All rights reserved.
3*2d40c451Schristos  * Use of this source code is governed by a BSD-style
4*2d40c451Schristos  * license that can be found in the LICENSE file.
5*2d40c451Schristos  * SPDX-License-Identifier: BSD-2-Clause
6*2d40c451Schristos  */
7*2d40c451Schristos 
8*2d40c451Schristos #define _FIDO_INTERNAL
9*2d40c451Schristos 
10*2d40c451Schristos #include <assert.h>
11*2d40c451Schristos #include <stdint.h>
12*2d40c451Schristos #include <stdlib.h>
13*2d40c451Schristos #include <string.h>
14*2d40c451Schristos #include <stdio.h>
15*2d40c451Schristos #include <winscard.h>
16*2d40c451Schristos 
17*2d40c451Schristos #include "mutator_aux.h"
18*2d40c451Schristos #include "wiredata_fido2.h"
19*2d40c451Schristos #include "dummy.h"
20*2d40c451Schristos 
21*2d40c451Schristos #include "../src/extern.h"
22*2d40c451Schristos 
23*2d40c451Schristos struct param {
24*2d40c451Schristos 	int seed;
25*2d40c451Schristos 	char path[MAXSTR];
26*2d40c451Schristos 	struct blob pcsc_list;
27*2d40c451Schristos 	struct blob tx_apdu;
28*2d40c451Schristos 	struct blob wiredata_init;
29*2d40c451Schristos 	struct blob wiredata_msg;
30*2d40c451Schristos };
31*2d40c451Schristos 
32*2d40c451Schristos static const uint8_t dummy_tx_apdu[] = { WIREDATA_CTAP_EXTENDED_APDU };
33*2d40c451Schristos static const uint8_t dummy_wiredata_init[] = { WIREDATA_CTAP_NFC_INIT };
34*2d40c451Schristos static const uint8_t dummy_wiredata_msg[] = { WIREDATA_CTAP_NFC_MSG };
35*2d40c451Schristos 
36*2d40c451Schristos struct param *
unpack(const uint8_t * ptr,size_t len)37*2d40c451Schristos unpack(const uint8_t *ptr, size_t len)
38*2d40c451Schristos {
39*2d40c451Schristos 	cbor_item_t *item = NULL, **v;
40*2d40c451Schristos 	struct cbor_load_result cbor;
41*2d40c451Schristos 	struct param *p;
42*2d40c451Schristos 	int ok = -1;
43*2d40c451Schristos 
44*2d40c451Schristos 	if ((p = calloc(1, sizeof(*p))) == NULL ||
45*2d40c451Schristos 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
46*2d40c451Schristos 	    cbor.read != len ||
47*2d40c451Schristos 	    cbor_isa_array(item) == false ||
48*2d40c451Schristos 	    cbor_array_is_definite(item) == false ||
49*2d40c451Schristos 	    cbor_array_size(item) != 6 ||
50*2d40c451Schristos 	    (v = cbor_array_handle(item)) == NULL)
51*2d40c451Schristos 		goto fail;
52*2d40c451Schristos 
53*2d40c451Schristos 	if (unpack_int(v[0], &p->seed) < 0 ||
54*2d40c451Schristos 	    unpack_string(v[1], p->path) < 0 ||
55*2d40c451Schristos 	    unpack_blob(v[2], &p->pcsc_list) < 0 ||
56*2d40c451Schristos 	    unpack_blob(v[3], &p->tx_apdu) < 0 ||
57*2d40c451Schristos 	    unpack_blob(v[4], &p->wiredata_init) < 0 ||
58*2d40c451Schristos 	    unpack_blob(v[5], &p->wiredata_msg) < 0)
59*2d40c451Schristos 		goto fail;
60*2d40c451Schristos 
61*2d40c451Schristos 	ok = 0;
62*2d40c451Schristos fail:
63*2d40c451Schristos 	if (ok < 0) {
64*2d40c451Schristos 		free(p);
65*2d40c451Schristos 		p = NULL;
66*2d40c451Schristos 	}
67*2d40c451Schristos 
68*2d40c451Schristos 	if (item)
69*2d40c451Schristos 		cbor_decref(&item);
70*2d40c451Schristos 
71*2d40c451Schristos 	return p;
72*2d40c451Schristos }
73*2d40c451Schristos 
74*2d40c451Schristos size_t
pack(uint8_t * ptr,size_t len,const struct param * p)75*2d40c451Schristos pack(uint8_t *ptr, size_t len, const struct param *p)
76*2d40c451Schristos {
77*2d40c451Schristos 	cbor_item_t *argv[6], *array = NULL;
78*2d40c451Schristos 	size_t cbor_alloc_len, cbor_len = 0;
79*2d40c451Schristos 	unsigned char *cbor = NULL;
80*2d40c451Schristos 
81*2d40c451Schristos 	memset(argv, 0, sizeof(argv));
82*2d40c451Schristos 
83*2d40c451Schristos 	if ((array = cbor_new_definite_array(6)) == NULL ||
84*2d40c451Schristos 	    (argv[0] = pack_int(p->seed)) == NULL ||
85*2d40c451Schristos 	    (argv[1] = pack_string(p->path)) == NULL ||
86*2d40c451Schristos 	    (argv[2] = pack_blob(&p->pcsc_list)) == NULL ||
87*2d40c451Schristos 	    (argv[3] = pack_blob(&p->tx_apdu)) == NULL ||
88*2d40c451Schristos 	    (argv[4] = pack_blob(&p->wiredata_init)) == NULL ||
89*2d40c451Schristos 	    (argv[5] = pack_blob(&p->wiredata_msg)) == NULL)
90*2d40c451Schristos 		goto fail;
91*2d40c451Schristos 
92*2d40c451Schristos 	for (size_t i = 0; i < 6; i++)
93*2d40c451Schristos 		if (cbor_array_push(array, argv[i]) == false)
94*2d40c451Schristos 			goto fail;
95*2d40c451Schristos 
96*2d40c451Schristos 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
97*2d40c451Schristos 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
98*2d40c451Schristos 		cbor_len = 0;
99*2d40c451Schristos 		goto fail;
100*2d40c451Schristos 	}
101*2d40c451Schristos 
102*2d40c451Schristos 	memcpy(ptr, cbor, cbor_len);
103*2d40c451Schristos fail:
104*2d40c451Schristos 	for (size_t i = 0; i < 6; i++)
105*2d40c451Schristos 		if (argv[i])
106*2d40c451Schristos 			cbor_decref(&argv[i]);
107*2d40c451Schristos 
108*2d40c451Schristos 	if (array)
109*2d40c451Schristos 		cbor_decref(&array);
110*2d40c451Schristos 
111*2d40c451Schristos 	free(cbor);
112*2d40c451Schristos 
113*2d40c451Schristos 	return cbor_len;
114*2d40c451Schristos }
115*2d40c451Schristos 
116*2d40c451Schristos size_t
pack_dummy(uint8_t * ptr,size_t len)117*2d40c451Schristos pack_dummy(uint8_t *ptr, size_t len)
118*2d40c451Schristos {
119*2d40c451Schristos 	struct param dummy;
120*2d40c451Schristos 	uint8_t	blob[MAXCORPUS];
121*2d40c451Schristos 	size_t blob_len;
122*2d40c451Schristos 
123*2d40c451Schristos 	memset(&dummy, 0, sizeof(dummy));
124*2d40c451Schristos 
125*2d40c451Schristos 	strlcpy(dummy.path, dummy_pcsc_path, sizeof(dummy.path));
126*2d40c451Schristos 
127*2d40c451Schristos 	dummy.pcsc_list.len = sizeof(dummy_pcsc_list);
128*2d40c451Schristos 	memcpy(&dummy.pcsc_list.body, &dummy_pcsc_list, dummy.pcsc_list.len);
129*2d40c451Schristos 
130*2d40c451Schristos 	dummy.tx_apdu.len = sizeof(dummy_tx_apdu);
131*2d40c451Schristos 	memcpy(&dummy.tx_apdu.body, &dummy_tx_apdu, dummy.tx_apdu.len);
132*2d40c451Schristos 
133*2d40c451Schristos 	dummy.wiredata_init.len = sizeof(dummy_wiredata_init);
134*2d40c451Schristos 	memcpy(&dummy.wiredata_init.body, &dummy_wiredata_init,
135*2d40c451Schristos 	    dummy.wiredata_init.len);
136*2d40c451Schristos 
137*2d40c451Schristos 	dummy.wiredata_msg.len = sizeof(dummy_wiredata_msg);
138*2d40c451Schristos 	memcpy(&dummy.wiredata_msg.body, &dummy_wiredata_msg,
139*2d40c451Schristos 	    dummy.wiredata_msg.len);
140*2d40c451Schristos 
141*2d40c451Schristos 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
142*2d40c451Schristos 
143*2d40c451Schristos 	if (blob_len > len) {
144*2d40c451Schristos 		memcpy(ptr, blob, len);
145*2d40c451Schristos 		return len;
146*2d40c451Schristos 	}
147*2d40c451Schristos 
148*2d40c451Schristos 	memcpy(ptr, blob, blob_len);
149*2d40c451Schristos 
150*2d40c451Schristos 	return blob_len;
151*2d40c451Schristos }
152*2d40c451Schristos 
153*2d40c451Schristos static void
test_manifest(void)154*2d40c451Schristos test_manifest(void)
155*2d40c451Schristos {
156*2d40c451Schristos 	size_t ndevs, nfound;
157*2d40c451Schristos 	fido_dev_info_t *devlist = NULL;
158*2d40c451Schristos 	int16_t vendor_id, product_id;
159*2d40c451Schristos 	int r;
160*2d40c451Schristos 
161*2d40c451Schristos 	r = fido_pcsc_manifest(NULL, 0, &nfound);
162*2d40c451Schristos 	assert(r == FIDO_OK && nfound == 0);
163*2d40c451Schristos 	r = fido_pcsc_manifest(NULL, 1, &nfound);
164*2d40c451Schristos 	assert(r == FIDO_ERR_INVALID_ARGUMENT);
165*2d40c451Schristos 
166*2d40c451Schristos 	ndevs = uniform_random(64);
167*2d40c451Schristos 	if ((devlist = fido_dev_info_new(ndevs)) == NULL ||
168*2d40c451Schristos 	    fido_pcsc_manifest(devlist, ndevs, &nfound) != FIDO_OK)
169*2d40c451Schristos 		goto out;
170*2d40c451Schristos 
171*2d40c451Schristos 	for (size_t i = 0; i < nfound; i++) {
172*2d40c451Schristos 		const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
173*2d40c451Schristos 		consume_str(fido_dev_info_path(di));
174*2d40c451Schristos 		consume_str(fido_dev_info_manufacturer_string(di));
175*2d40c451Schristos 		consume_str(fido_dev_info_product_string(di));
176*2d40c451Schristos 		vendor_id = fido_dev_info_vendor(di);
177*2d40c451Schristos 		product_id = fido_dev_info_product(di);
178*2d40c451Schristos 		consume(&vendor_id, sizeof(vendor_id));
179*2d40c451Schristos 		consume(&product_id, sizeof(product_id));
180*2d40c451Schristos 	}
181*2d40c451Schristos 
182*2d40c451Schristos out:
183*2d40c451Schristos 	fido_dev_info_free(&devlist, ndevs);
184*2d40c451Schristos }
185*2d40c451Schristos 
186*2d40c451Schristos static void
test_tx(const char * path,const struct blob * apdu,uint8_t cmd,u_char * rx_buf,size_t rx_len)187*2d40c451Schristos test_tx(const char *path, const struct blob *apdu, uint8_t cmd, u_char *rx_buf,
188*2d40c451Schristos     size_t rx_len)
189*2d40c451Schristos {
190*2d40c451Schristos 	fido_dev_t dev;
191*2d40c451Schristos 	const u_char *tx_ptr = NULL;
192*2d40c451Schristos 	size_t tx_len = 0;
193*2d40c451Schristos 	int n;
194*2d40c451Schristos 
195*2d40c451Schristos 	memset(&dev, 0, sizeof(dev));
196*2d40c451Schristos 
197*2d40c451Schristos 	if (fido_dev_set_pcsc(&dev) < 0)
198*2d40c451Schristos 		return;
199*2d40c451Schristos 	if ((dev.io_handle = fido_pcsc_open(path)) == NULL)
200*2d40c451Schristos 		return;
201*2d40c451Schristos 
202*2d40c451Schristos 	if (apdu) {
203*2d40c451Schristos 		tx_ptr = apdu->body;
204*2d40c451Schristos 		tx_len = apdu->len;
205*2d40c451Schristos 	}
206*2d40c451Schristos 
207*2d40c451Schristos 	fido_pcsc_tx(&dev, cmd, tx_ptr, tx_len);
208*2d40c451Schristos 
209*2d40c451Schristos 	if ((n = fido_pcsc_rx(&dev, cmd, rx_buf, rx_len, -1)) >= 0)
210*2d40c451Schristos 		consume(rx_buf, n);
211*2d40c451Schristos 
212*2d40c451Schristos 	fido_pcsc_close(dev.io_handle);
213*2d40c451Schristos }
214*2d40c451Schristos 
215*2d40c451Schristos static void
test_misc(void)216*2d40c451Schristos test_misc(void)
217*2d40c451Schristos {
218*2d40c451Schristos 	assert(fido_pcsc_open(NULL) == NULL);
219*2d40c451Schristos 	assert(fido_pcsc_write(NULL, NULL, INT_MAX + 1LL) == -1);
220*2d40c451Schristos }
221*2d40c451Schristos 
222*2d40c451Schristos void
test(const struct param * p)223*2d40c451Schristos test(const struct param *p)
224*2d40c451Schristos {
225*2d40c451Schristos 	u_char buf[512];
226*2d40c451Schristos 
227*2d40c451Schristos 	prng_init((unsigned int)p->seed);
228*2d40c451Schristos 	fuzz_clock_reset();
229*2d40c451Schristos 	fido_init(FIDO_DEBUG);
230*2d40c451Schristos 	fido_set_log_handler(consume_str);
231*2d40c451Schristos 
232*2d40c451Schristos 	set_pcsc_parameters(&p->pcsc_list);
233*2d40c451Schristos 	set_pcsc_io_functions(nfc_read, nfc_write, consume);
234*2d40c451Schristos 
235*2d40c451Schristos 	set_wire_data(p->wiredata_init.body, p->wiredata_init.len);
236*2d40c451Schristos 	test_manifest();
237*2d40c451Schristos 
238*2d40c451Schristos 	test_misc();
239*2d40c451Schristos 
240*2d40c451Schristos 	set_wire_data(p->wiredata_init.body, p->wiredata_init.len);
241*2d40c451Schristos 	test_tx(p->path, NULL, CTAP_CMD_INIT, buf, uniform_random(20));
242*2d40c451Schristos 
243*2d40c451Schristos 	set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
244*2d40c451Schristos 	test_tx(p->path, &p->tx_apdu, CTAP_CMD_MSG, buf, sizeof(buf));
245*2d40c451Schristos 
246*2d40c451Schristos 	set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
247*2d40c451Schristos 	test_tx(p->path, &p->tx_apdu, CTAP_CMD_CBOR, buf, sizeof(buf));
248*2d40c451Schristos 
249*2d40c451Schristos 	set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
250*2d40c451Schristos 	test_tx(p->path, &p->tx_apdu, CTAP_CMD_LOCK, buf, sizeof(buf));
251*2d40c451Schristos }
252*2d40c451Schristos 
253*2d40c451Schristos void
mutate(struct param * p,unsigned int seed,unsigned int flags)254*2d40c451Schristos mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
255*2d40c451Schristos {
256*2d40c451Schristos 	if (flags & MUTATE_SEED)
257*2d40c451Schristos 		p->seed = (int)seed;
258*2d40c451Schristos 
259*2d40c451Schristos 	if (flags & MUTATE_PARAM) {
260*2d40c451Schristos 		mutate_string(p->path);
261*2d40c451Schristos 		mutate_blob(&p->pcsc_list);
262*2d40c451Schristos 		mutate_blob(&p->tx_apdu);
263*2d40c451Schristos 	}
264*2d40c451Schristos 
265*2d40c451Schristos 	if (flags & MUTATE_WIREDATA) {
266*2d40c451Schristos 		mutate_blob(&p->wiredata_init);
267*2d40c451Schristos 		mutate_blob(&p->wiredata_msg);
268*2d40c451Schristos 	}
269*2d40c451Schristos }
270