Path: blob/main/contrib/libfido2/fuzz/fuzz_pcsc.c
104880 views
/*1* Copyright (c) 2022 Yubico AB. All rights reserved.2* Use of this source code is governed by a BSD-style3* license that can be found in the LICENSE file.4* SPDX-License-Identifier: BSD-2-Clause5*/67#define _FIDO_INTERNAL89#include <assert.h>10#include <stdint.h>11#include <stdlib.h>12#include <string.h>13#include <stdio.h>14#include <winscard.h>1516#include "mutator_aux.h"17#include "wiredata_fido2.h"18#include "dummy.h"1920#include "../src/extern.h"2122struct param {23int seed;24char path[MAXSTR];25struct blob pcsc_list;26struct blob tx_apdu;27struct blob wiredata_init;28struct blob wiredata_msg;29};3031static const uint8_t dummy_tx_apdu[] = { WIREDATA_CTAP_EXTENDED_APDU };32static const uint8_t dummy_wiredata_init[] = { WIREDATA_CTAP_NFC_INIT };33static const uint8_t dummy_wiredata_msg[] = { WIREDATA_CTAP_NFC_MSG };3435struct param *36unpack(const uint8_t *ptr, size_t len)37{38cbor_item_t *item = NULL, **v;39struct cbor_load_result cbor;40struct param *p;41int ok = -1;4243if ((p = calloc(1, sizeof(*p))) == NULL ||44(item = cbor_load(ptr, len, &cbor)) == NULL ||45cbor.read != len ||46cbor_isa_array(item) == false ||47cbor_array_is_definite(item) == false ||48cbor_array_size(item) != 6 ||49(v = cbor_array_handle(item)) == NULL)50goto fail;5152if (unpack_int(v[0], &p->seed) < 0 ||53unpack_string(v[1], p->path) < 0 ||54unpack_blob(v[2], &p->pcsc_list) < 0 ||55unpack_blob(v[3], &p->tx_apdu) < 0 ||56unpack_blob(v[4], &p->wiredata_init) < 0 ||57unpack_blob(v[5], &p->wiredata_msg) < 0)58goto fail;5960ok = 0;61fail:62if (ok < 0) {63free(p);64p = NULL;65}6667if (item)68cbor_decref(&item);6970return p;71}7273size_t74pack(uint8_t *ptr, size_t len, const struct param *p)75{76cbor_item_t *argv[6], *array = NULL;77size_t cbor_alloc_len, cbor_len = 0;78unsigned char *cbor = NULL;7980memset(argv, 0, sizeof(argv));8182if ((array = cbor_new_definite_array(6)) == NULL ||83(argv[0] = pack_int(p->seed)) == NULL ||84(argv[1] = pack_string(p->path)) == NULL ||85(argv[2] = pack_blob(&p->pcsc_list)) == NULL ||86(argv[3] = pack_blob(&p->tx_apdu)) == NULL ||87(argv[4] = pack_blob(&p->wiredata_init)) == NULL ||88(argv[5] = pack_blob(&p->wiredata_msg)) == NULL)89goto fail;9091for (size_t i = 0; i < 6; i++)92if (cbor_array_push(array, argv[i]) == false)93goto fail;9495if ((cbor_len = cbor_serialize_alloc(array, &cbor,96&cbor_alloc_len)) == 0 || cbor_len > len) {97cbor_len = 0;98goto fail;99}100101memcpy(ptr, cbor, cbor_len);102fail:103for (size_t i = 0; i < 6; i++)104if (argv[i])105cbor_decref(&argv[i]);106107if (array)108cbor_decref(&array);109110free(cbor);111112return cbor_len;113}114115size_t116pack_dummy(uint8_t *ptr, size_t len)117{118struct param dummy;119uint8_t blob[MAXCORPUS];120size_t blob_len;121122memset(&dummy, 0, sizeof(dummy));123124strlcpy(dummy.path, dummy_pcsc_path, sizeof(dummy.path));125126dummy.pcsc_list.len = sizeof(dummy_pcsc_list);127memcpy(&dummy.pcsc_list.body, &dummy_pcsc_list, dummy.pcsc_list.len);128129dummy.tx_apdu.len = sizeof(dummy_tx_apdu);130memcpy(&dummy.tx_apdu.body, &dummy_tx_apdu, dummy.tx_apdu.len);131132dummy.wiredata_init.len = sizeof(dummy_wiredata_init);133memcpy(&dummy.wiredata_init.body, &dummy_wiredata_init,134dummy.wiredata_init.len);135136dummy.wiredata_msg.len = sizeof(dummy_wiredata_msg);137memcpy(&dummy.wiredata_msg.body, &dummy_wiredata_msg,138dummy.wiredata_msg.len);139140assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);141142if (blob_len > len) {143memcpy(ptr, blob, len);144return len;145}146147memcpy(ptr, blob, blob_len);148149return blob_len;150}151152static void153test_manifest(void)154{155size_t ndevs, nfound;156fido_dev_info_t *devlist = NULL;157int16_t vendor_id, product_id;158int r;159160r = fido_pcsc_manifest(NULL, 0, &nfound);161assert(r == FIDO_OK && nfound == 0);162r = fido_pcsc_manifest(NULL, 1, &nfound);163assert(r == FIDO_ERR_INVALID_ARGUMENT);164165ndevs = uniform_random(64);166if ((devlist = fido_dev_info_new(ndevs)) == NULL ||167fido_pcsc_manifest(devlist, ndevs, &nfound) != FIDO_OK)168goto out;169170for (size_t i = 0; i < nfound; i++) {171const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);172consume_str(fido_dev_info_path(di));173consume_str(fido_dev_info_manufacturer_string(di));174consume_str(fido_dev_info_product_string(di));175vendor_id = fido_dev_info_vendor(di);176product_id = fido_dev_info_product(di);177consume(&vendor_id, sizeof(vendor_id));178consume(&product_id, sizeof(product_id));179}180181out:182fido_dev_info_free(&devlist, ndevs);183}184185static void186test_tx(const char *path, const struct blob *apdu, uint8_t cmd, u_char *rx_buf,187size_t rx_len)188{189fido_dev_t dev;190const u_char *tx_ptr = NULL;191size_t tx_len = 0;192int n;193194memset(&dev, 0, sizeof(dev));195196if (fido_dev_set_pcsc(&dev) < 0)197return;198if ((dev.io_handle = fido_pcsc_open(path)) == NULL)199return;200201if (apdu) {202tx_ptr = apdu->body;203tx_len = apdu->len;204}205206fido_pcsc_tx(&dev, cmd, tx_ptr, tx_len);207208if ((n = fido_pcsc_rx(&dev, cmd, rx_buf, rx_len, -1)) >= 0)209consume(rx_buf, n);210211fido_pcsc_close(dev.io_handle);212}213214static void215test_misc(void)216{217assert(fido_pcsc_open(NULL) == NULL);218assert(fido_pcsc_write(NULL, NULL, INT_MAX + 1LL) == -1);219}220221void222test(const struct param *p)223{224u_char buf[512];225226prng_init((unsigned int)p->seed);227fuzz_clock_reset();228fido_init(FIDO_DEBUG);229fido_set_log_handler(consume_str);230231set_pcsc_parameters(&p->pcsc_list);232set_pcsc_io_functions(nfc_read, nfc_write, consume);233234set_wire_data(p->wiredata_init.body, p->wiredata_init.len);235test_manifest();236237test_misc();238239set_wire_data(p->wiredata_init.body, p->wiredata_init.len);240test_tx(p->path, NULL, CTAP_CMD_INIT, buf, uniform_random(20));241242set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);243test_tx(p->path, &p->tx_apdu, CTAP_CMD_MSG, buf, sizeof(buf));244245set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);246test_tx(p->path, &p->tx_apdu, CTAP_CMD_CBOR, buf, sizeof(buf));247248set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);249test_tx(p->path, &p->tx_apdu, CTAP_CMD_LOCK, buf, sizeof(buf));250}251252void253mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN254{255if (flags & MUTATE_SEED)256p->seed = (int)seed;257258if (flags & MUTATE_PARAM) {259mutate_string(p->path);260mutate_blob(&p->pcsc_list);261mutate_blob(&p->tx_apdu);262}263264if (flags & MUTATE_WIREDATA) {265mutate_blob(&p->wiredata_init);266mutate_blob(&p->wiredata_msg);267}268}269270271