diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..f013df4 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (c) 2018 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause + +list(APPEND COMPAT_SOURCES + ../openbsd-compat/clock_gettime.c + ../openbsd-compat/getopt_long.c + ../openbsd-compat/strlcat.c + ../openbsd-compat/strlcpy.c +) + +if(WIN32 AND BUILD_SHARED_LIBS AND NOT CYGWIN AND NOT MSYS) + list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c) +endif() + +# enable -Wconversion -Wsign-conversion +if(NOT MSVC) + set_source_files_properties(assert.c cred.c info.c manifest.c reset.c + retries.c setpin.c util.c PROPERTIES COMPILE_FLAGS + "-Wconversion -Wsign-conversion") +endif() + +# manifest +add_executable(manifest manifest.c ${COMPAT_SOURCES}) +target_link_libraries(manifest ${_FIDO2_LIBRARY}) + +# info +add_executable(info info.c ${COMPAT_SOURCES}) +target_link_libraries(info ${_FIDO2_LIBRARY}) + +# reset +add_executable(reset reset.c util.c ${COMPAT_SOURCES}) +target_link_libraries(reset ${_FIDO2_LIBRARY}) + +# cred +add_executable(cred cred.c util.c ${COMPAT_SOURCES}) +target_link_libraries(cred ${_FIDO2_LIBRARY}) + +# assert +add_executable(assert assert.c util.c ${COMPAT_SOURCES}) +target_link_libraries(assert ${_FIDO2_LIBRARY}) + +# setpin +add_executable(setpin setpin.c ${COMPAT_SOURCES}) +target_link_libraries(setpin ${_FIDO2_LIBRARY}) + +# retries +add_executable(retries retries.c ${COMPAT_SOURCES}) +target_link_libraries(retries ${_FIDO2_LIBRARY}) + +# select +add_executable(select select.c ${COMPAT_SOURCES}) +target_link_libraries(select ${_FIDO2_LIBRARY}) + +if(MINGW) + # needed for nanosleep() in mingw + target_link_libraries(select winpthread) +endif() diff --git a/examples/README.adoc b/examples/README.adoc new file mode 100644 index 0000000..6151b70 --- /dev/null +++ b/examples/README.adoc @@ -0,0 +1,100 @@ += Examples + +=== Definitions + +The following definitions are used in the description below: + +- + + The file system path or subsystem-specific identification string of a + FIDO device. + +- , [oldpin] + + Strings passed directly in the executed command's argument vector. + +- + + The file system path of a file containing a FIDO credential ID in + binary representation. + +- + + The file system path of a file containing a public key in PEM format. + +- + + A credential's associated CTAP 2.1 "largeBlob" symmetric key. + +=== Description + +The following examples are provided: + +- manifest + + Prints a list of configured FIDO devices. + +- info + + Prints information about . + +- reset + + Performs a factory reset on . + +- setpin [oldpin] + + Configures as the new PIN of . If [oldpin] is provided, + the device's PIN is changed from [oldpin] to . + +- cred [-t es256|es384|rs256|eddsa] [-k pubkey] [-ei cred_id] [-P pin] + [-T seconds] [-b blobkey] [-hruv] [-c cred_protect] + + Creates a new credential on and verify that the credential + was signed by the authenticator. The device's attestation certificate + is not verified. If option -k is specified, the credential's public + key is stored in . If option -i is specified, the credential + ID is stored in . The -e option may be used to add + to the list of excluded credentials. If option -h is specified, + the hmac-secret FIDO2 extension is enabled on the generated + credential. If option -r is specified, the generated credential + will involve a resident key. User verification may be requested + through the -v option. If option -u is specified, the credential + is generated using U2F (CTAP1) instead of FIDO2 (CTAP2) commands. + The -T option may be used to enforce a timeout of . If the + option -b is specified, the credential's "largeBlob" key is stored in + . If the option -c is specified the the generated credential + will be bound by the specified protection policy. + +- assert [-t es256|es384|rs256|eddsa] [-a cred_id] [-h hmac_secret] [-P pin] + [-s hmac_salt] [-T seconds] [-b blobkey] [-puv] + + Asks for a FIDO2 assertion corresponding to [cred_id], + which may be omitted for resident keys. The obtained assertion + is verified using . The -p option requests that the user + be present and checks whether the user presence bit was signed by the + authenticator. The -v option requests user verification and checks + whether the user verification bit was signed by the authenticator. + If option -u is specified, the assertion is generated using + U2F (CTAP1) instead of FIDO2 (CTAP2) commands. If option -s is + specified, a FIDO2 hmac-secret is requested from the authenticator, + and the contents of are used as the salt. If option -h + is specified, the resulting hmac-secret is stored in . + The -T option may be used to enforce a timeout of . If the + option -b specified, the credential's "largeBlob" key is stored in + . + +- retries + Get the number of PIN attempts left on before lockout. + +- select + + Enumerates available FIDO devices and, if more than one is present, + simultaneously requests touch on all of them, printing information + about the device touched. + +Debugging is possible through the use of the FIDO_DEBUG environment variable. +If set, libfido2 will produce a log of its transactions with the authenticator. + +Additionally, an example of a WebAuthn client using libfido2 is available at +https://github.com/martelletto/fido2-webauthn-client. diff --git a/examples/assert.c b/examples/assert.c new file mode 100644 index 0000000..32ba97b --- /dev/null +++ b/examples/assert.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "../openbsd-compat/openbsd-compat.h" +#include "extern.h" + +static const unsigned char cd[32] = { + 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, + 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, + 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, + 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, +}; + +static void +usage(void) +{ + fprintf(stderr, "usage: assert [-t es256|es384|rs256|eddsa] " + "[-a cred_id] [-h hmac_secret] [-s hmac_salt] [-P pin] " + "[-T seconds] [-b blobkey] [-puv] \n"); + exit(EXIT_FAILURE); +} + +static void +verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len, + const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext, + const char *key) +{ + fido_assert_t *assert = NULL; + EC_KEY *ec = NULL; + RSA *rsa = NULL; + EVP_PKEY *eddsa = NULL; + es256_pk_t *es256_pk = NULL; + es384_pk_t *es384_pk = NULL; + rs256_pk_t *rs256_pk = NULL; + eddsa_pk_t *eddsa_pk = NULL; + void *pk; + int r; + + /* credential pubkey */ + switch (type) { + case COSE_ES256: + if ((ec = read_ec_pubkey(key)) == NULL) + errx(1, "read_ec_pubkey"); + + if ((es256_pk = es256_pk_new()) == NULL) + errx(1, "es256_pk_new"); + + if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) + errx(1, "es256_pk_from_EC_KEY"); + + pk = es256_pk; + EC_KEY_free(ec); + ec = NULL; + + break; + case COSE_ES384: + if ((ec = read_ec_pubkey(key)) == NULL) + errx(1, "read_ec_pubkey"); + + if ((es384_pk = es384_pk_new()) == NULL) + errx(1, "es384_pk_new"); + + if (es384_pk_from_EC_KEY(es384_pk, ec) != FIDO_OK) + errx(1, "es384_pk_from_EC_KEY"); + + pk = es384_pk; + EC_KEY_free(ec); + ec = NULL; + + break; + case COSE_RS256: + if ((rsa = read_rsa_pubkey(key)) == NULL) + errx(1, "read_rsa_pubkey"); + + if ((rs256_pk = rs256_pk_new()) == NULL) + errx(1, "rs256_pk_new"); + + if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) + errx(1, "rs256_pk_from_RSA"); + + pk = rs256_pk; + RSA_free(rsa); + rsa = NULL; + + break; + case COSE_EDDSA: + if ((eddsa = read_eddsa_pubkey(key)) == NULL) + errx(1, "read_eddsa_pubkey"); + + if ((eddsa_pk = eddsa_pk_new()) == NULL) + errx(1, "eddsa_pk_new"); + + if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) + errx(1, "eddsa_pk_from_EVP_PKEY"); + + pk = eddsa_pk; + EVP_PKEY_free(eddsa); + eddsa = NULL; + + break; + default: + errx(1, "unknown credential type %d", type); + } + + if ((assert = fido_assert_new()) == NULL) + errx(1, "fido_assert_new"); + + /* client data hash */ + r = fido_assert_set_clientdata(assert, cd, sizeof(cd)); + if (r != FIDO_OK) + errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r); + + /* relying party */ + r = fido_assert_set_rp(assert, "localhost"); + if (r != FIDO_OK) + errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); + + /* authdata */ + r = fido_assert_set_count(assert, 1); + if (r != FIDO_OK) + errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r); + r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len); + if (r != FIDO_OK) + errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r); + + /* extension */ + r = fido_assert_set_extensions(assert, ext); + if (r != FIDO_OK) + errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), + r); + + /* user presence */ + if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); + + /* user verification */ + if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); + + /* sig */ + r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len); + if (r != FIDO_OK) + errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r); + + r = fido_assert_verify(assert, 0, type, pk); + if (r != FIDO_OK) + errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r); + + es256_pk_free(&es256_pk); + es384_pk_free(&es384_pk); + rs256_pk_free(&rs256_pk); + eddsa_pk_free(&eddsa_pk); + + fido_assert_free(&assert); +} + +int +main(int argc, char **argv) +{ + bool up = false; + bool uv = false; + bool u2f = false; + fido_dev_t *dev = NULL; + fido_assert_t *assert = NULL; + const char *pin = NULL; + const char *blobkey_out = NULL; + const char *hmac_out = NULL; + unsigned char *body = NULL; + long long ms = 0; + size_t len; + int type = COSE_ES256; + int ext = 0; + int ch; + int r; + + if ((assert = fido_assert_new()) == NULL) + errx(1, "fido_assert_new"); + + while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) { + switch (ch) { + case 'P': + pin = optarg; + break; + case 'T': + if (base10(optarg, &ms) < 0) + errx(1, "base10: %s", optarg); + if (ms <= 0 || ms > 30) + errx(1, "-T: %s must be in (0,30]", optarg); + ms *= 1000; /* seconds to milliseconds */ + break; + case 'a': + if (read_blob(optarg, &body, &len) < 0) + errx(1, "read_blob: %s", optarg); + if ((r = fido_assert_allow_cred(assert, body, + len)) != FIDO_OK) + errx(1, "fido_assert_allow_cred: %s (0x%x)", + fido_strerr(r), r); + free(body); + body = NULL; + break; + case 'b': + ext |= FIDO_EXT_LARGEBLOB_KEY; + blobkey_out = optarg; + break; + case 'h': + hmac_out = optarg; + break; + case 'p': + up = true; + break; + case 's': + ext |= FIDO_EXT_HMAC_SECRET; + if (read_blob(optarg, &body, &len) < 0) + errx(1, "read_blob: %s", optarg); + if ((r = fido_assert_set_hmac_salt(assert, body, + len)) != FIDO_OK) + errx(1, "fido_assert_set_hmac_salt: %s (0x%x)", + fido_strerr(r), r); + free(body); + body = NULL; + break; + case 't': + if (strcmp(optarg, "es256") == 0) + type = COSE_ES256; + else if (strcmp(optarg, "es384") == 0) + type = COSE_ES384; + else if (strcmp(optarg, "rs256") == 0) + type = COSE_RS256; + else if (strcmp(optarg, "eddsa") == 0) + type = COSE_EDDSA; + else + errx(1, "unknown type %s", optarg); + break; + case 'u': + u2f = true; + break; + case 'v': + uv = true; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + + fido_init(0); + + if ((dev = fido_dev_new()) == NULL) + errx(1, "fido_dev_new"); + + r = fido_dev_open(dev, argv[1]); + if (r != FIDO_OK) + errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); + if (u2f) + fido_dev_force_u2f(dev); + + /* client data hash */ + r = fido_assert_set_clientdata(assert, cd, sizeof(cd)); + if (r != FIDO_OK) + errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r); + + /* relying party */ + r = fido_assert_set_rp(assert, "localhost"); + if (r != FIDO_OK) + errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); + + /* extensions */ + r = fido_assert_set_extensions(assert, ext); + if (r != FIDO_OK) + errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), + r); + + /* user presence */ + if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); + + /* user verification */ + if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); + + /* timeout */ + if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK) + errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r); + + if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) { + fido_dev_cancel(dev); + errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r); + } + + r = fido_dev_close(dev); + if (r != FIDO_OK) + errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); + + fido_dev_free(&dev); + + if (fido_assert_count(assert) != 1) + errx(1, "fido_assert_count: %d signatures returned", + (int)fido_assert_count(assert)); + + /* when verifying, pin implies uv */ + if (pin) + uv = true; + + verify_assert(type, fido_assert_authdata_ptr(assert, 0), + fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), + fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); + + if (hmac_out != NULL) { + /* extract the hmac secret */ + if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0), + fido_assert_hmac_secret_len(assert, 0)) < 0) + errx(1, "write_blob"); + } + + if (blobkey_out != NULL) { + /* extract the hmac secret */ + if (write_blob(blobkey_out, + fido_assert_largeblob_key_ptr(assert, 0), + fido_assert_largeblob_key_len(assert, 0)) < 0) + errx(1, "write_blob"); + } + + fido_assert_free(&assert); + + exit(0); +} diff --git a/examples/cred.c b/examples/cred.c new file mode 100644 index 0000000..5a2a27f --- /dev/null +++ b/examples/cred.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2018-2023 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "../openbsd-compat/openbsd-compat.h" +#include "extern.h" + +static const unsigned char cd[32] = { + 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, + 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, + 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, + 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, +}; + +static const unsigned char user_id[32] = { + 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, + 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, + 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, + 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, +}; + +static void +usage(void) +{ + fprintf(stderr, "usage: cred [-t es256|es384|rs256|eddsa] [-k pubkey] " + "[-ei cred_id] [-P pin] [-T seconds] [-b blobkey] [-c cred_protect] [-hruv] " + "\n"); + exit(EXIT_FAILURE); +} + +static void +verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr, + size_t authdata_len, const unsigned char *attstmt_ptr, size_t attstmt_len, + bool rk, bool uv, int ext, int cred_protect, const char *key_out, + const char *id_out) +{ + fido_cred_t *cred; + int r; + + if ((cred = fido_cred_new()) == NULL) + errx(1, "fido_cred_new"); + + /* type */ + r = fido_cred_set_type(cred, type); + if (r != FIDO_OK) + errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); + + /* client data */ + r = fido_cred_set_clientdata(cred, cd, sizeof(cd)); + if (r != FIDO_OK) + errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r); + + /* relying party */ + r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); + if (r != FIDO_OK) + errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); + + /* authdata */ + r = fido_cred_set_authdata(cred, authdata_ptr, authdata_len); + if (r != FIDO_OK) + errx(1, "fido_cred_set_authdata: %s (0x%x)", fido_strerr(r), r); + + /* extensions */ + r = fido_cred_set_extensions(cred, ext); + if (r != FIDO_OK) + errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); + + /* resident key */ + if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); + + /* user verification */ + if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); + + /* credProt */ + if (cred_protect != 0 && (r = fido_cred_set_prot(cred, + cred_protect)) != FIDO_OK) + errx(1, "fido_cred_set_prot: %s (0x%x)", fido_strerr(r), r); + + /* fmt */ + r = fido_cred_set_fmt(cred, fmt); + if (r != FIDO_OK) + errx(1, "fido_cred_set_fmt: %s (0x%x)", fido_strerr(r), r); + + if (!strcmp(fido_cred_fmt(cred), "none")) { + warnx("no attestation data, skipping credential verification"); + goto out; + } + + /* attestation statement */ + r = fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len); + if (r != FIDO_OK) + errx(1, "fido_cred_set_attstmt: %s (0x%x)", fido_strerr(r), r); + + r = fido_cred_verify(cred); + if (r != FIDO_OK) + errx(1, "fido_cred_verify: %s (0x%x)", fido_strerr(r), r); + +out: + if (key_out != NULL) { + /* extract the credential pubkey */ + if (type == COSE_ES256) { + if (write_es256_pubkey(key_out, + fido_cred_pubkey_ptr(cred), + fido_cred_pubkey_len(cred)) < 0) + errx(1, "write_es256_pubkey"); + } else if (type == COSE_ES384) { + if (write_es384_pubkey(key_out, + fido_cred_pubkey_ptr(cred), + fido_cred_pubkey_len(cred)) < 0) + errx(1, "write_es384_pubkey"); + } else if (type == COSE_RS256) { + if (write_rs256_pubkey(key_out, + fido_cred_pubkey_ptr(cred), + fido_cred_pubkey_len(cred)) < 0) + errx(1, "write_rs256_pubkey"); + } else if (type == COSE_EDDSA) { + if (write_eddsa_pubkey(key_out, + fido_cred_pubkey_ptr(cred), + fido_cred_pubkey_len(cred)) < 0) + errx(1, "write_eddsa_pubkey"); + } + } + + if (id_out != NULL) { + /* extract the credential id */ + if (write_blob(id_out, fido_cred_id_ptr(cred), + fido_cred_id_len(cred)) < 0) + errx(1, "write_blob"); + } + + fido_cred_free(&cred); +} + +int +main(int argc, char **argv) +{ + bool rk = false; + bool uv = false; + bool u2f = false; + fido_dev_t *dev; + fido_cred_t *cred = NULL; + const char *pin = NULL; + const char *blobkey_out = NULL; + const char *key_out = NULL; + const char *id_out = NULL; + unsigned char *body = NULL; + long long ms = 0; + size_t len; + int type = COSE_ES256; + int ext = 0; + int ch; + int r; + long long cred_protect = 0; + + if ((cred = fido_cred_new()) == NULL) + errx(1, "fido_cred_new"); + + while ((ch = getopt(argc, argv, "P:T:b:e:hi:k:rt:uvc:")) != -1) { + switch (ch) { + case 'P': + pin = optarg; + break; + case 'T': + if (base10(optarg, &ms) < 0) + errx(1, "base10: %s", optarg); + if (ms <= 0 || ms > 30) + errx(1, "-T: %s must be in (0,30]", optarg); + ms *= 1000; /* seconds to milliseconds */ + break; + case 'b': + ext |= FIDO_EXT_LARGEBLOB_KEY; + blobkey_out = optarg; + break; + case 'e': + if (read_blob(optarg, &body, &len) < 0) + errx(1, "read_blob: %s", optarg); + r = fido_cred_exclude(cred, body, len); + if (r != FIDO_OK) + errx(1, "fido_cred_exclude: %s (0x%x)", + fido_strerr(r), r); + free(body); + body = NULL; + break; + case 'h': + ext |= FIDO_EXT_HMAC_SECRET; + break; + case 'c': + if (base10(optarg, &cred_protect) < 0) + errx(1, "base10: %s", optarg); + if (cred_protect <= 0 || cred_protect > 3) + errx(1, "-c: %s must be in (1,3)", optarg); + ext |= FIDO_EXT_CRED_PROTECT; + break; + case 'i': + id_out = optarg; + break; + case 'k': + key_out = optarg; + break; + case 'r': + rk = true; + break; + case 't': + if (strcmp(optarg, "es256") == 0) + type = COSE_ES256; + else if (strcmp(optarg, "es384") == 0) + type = COSE_ES384; + else if (strcmp(optarg, "rs256") == 0) + type = COSE_RS256; + else if (strcmp(optarg, "eddsa") == 0) + type = COSE_EDDSA; + else + errx(1, "unknown type %s", optarg); + break; + case 'u': + u2f = true; + break; + case 'v': + uv = true; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + fido_init(0); + + if ((dev = fido_dev_new()) == NULL) + errx(1, "fido_dev_new"); + + r = fido_dev_open(dev, argv[0]); + if (r != FIDO_OK) + errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); + if (u2f) + fido_dev_force_u2f(dev); + + /* type */ + r = fido_cred_set_type(cred, type); + if (r != FIDO_OK) + errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); + + /* client data */ + r = fido_cred_set_clientdata(cred, cd, sizeof(cd)); + if (r != FIDO_OK) + errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r); + + /* relying party */ + r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); + if (r != FIDO_OK) + errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); + + /* user */ + r = fido_cred_set_user(cred, user_id, sizeof(user_id), "john smith", + "jsmith", NULL); + if (r != FIDO_OK) + errx(1, "fido_cred_set_user: %s (0x%x)", fido_strerr(r), r); + + /* extensions */ + r = fido_cred_set_extensions(cred, ext); + if (r != FIDO_OK) + errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); + + /* resident key */ + if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); + + /* user verification */ + if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) + errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); + + /* credProt */ + if (cred_protect != 0 && (r = fido_cred_set_prot(cred, + (int)cred_protect)) != FIDO_OK) + errx(1, "fido_cred_set_prot: %s (0x%x)", fido_strerr(r), r); + + /* timeout */ + if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK) + errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r); + + if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) { + fido_dev_cancel(dev); + errx(1, "fido_makecred: %s (0x%x)", fido_strerr(r), r); + } + + r = fido_dev_close(dev); + if (r != FIDO_OK) + errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); + + fido_dev_free(&dev); + + /* when verifying, pin implies uv */ + if (pin) + uv = true; + + verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), + fido_cred_authdata_len(cred), fido_cred_attstmt_ptr(cred), + fido_cred_attstmt_len(cred), rk, uv, ext, fido_cred_prot(cred), + key_out, id_out); + + if (blobkey_out != NULL) { + /* extract the "largeBlob" key */ + if (write_blob(blobkey_out, fido_cred_largeblob_key_ptr(cred), + fido_cred_largeblob_key_len(cred)) < 0) + errx(1, "write_blob"); + } + + fido_cred_free(&cred); + + exit(0); +} diff --git a/examples/extern.h b/examples/extern.h new file mode 100644 index 0000000..5cffd7f --- /dev/null +++ b/examples/extern.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _EXTERN_H_ +#define _EXTERN_H_ + +#include +#include +#include + +/* util.c */ +EC_KEY *read_ec_pubkey(const char *); +RSA *read_rsa_pubkey(const char *); +EVP_PKEY *read_eddsa_pubkey(const char *); +int base10(const char *, long long *); +int read_blob(const char *, unsigned char **, size_t *); +int write_blob(const char *, const unsigned char *, size_t); +int write_es256_pubkey(const char *, const void *, size_t); +int write_es384_pubkey(const char *, const void *, size_t); +int write_rs256_pubkey(const char *, const void *, size_t); +int write_eddsa_pubkey(const char *, const void *, size_t); + +#endif /* _EXTERN_H_ */ diff --git a/examples/info.c b/examples/info.c new file mode 100644 index 0000000..a10a50c --- /dev/null +++ b/examples/info.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" + +/* + * Pretty-print a device's capabilities flags and return the result. + */ +static void +format_flags(char *ret, size_t retlen, uint8_t flags) +{ + memset(ret, 0, retlen); + + if (flags & FIDO_CAP_WINK) { + if (strlcat(ret, "wink,", retlen) >= retlen) + goto toolong; + } else { + if (strlcat(ret, "nowink,", retlen) >= retlen) + goto toolong; + } + + if (flags & FIDO_CAP_CBOR) { + if (strlcat(ret, " cbor,", retlen) >= retlen) + goto toolong; + } else { + if (strlcat(ret, " nocbor,", retlen) >= retlen) + goto toolong; + } + + if (flags & FIDO_CAP_NMSG) { + if (strlcat(ret, " nomsg", retlen) >= retlen) + goto toolong; + } else { + if (strlcat(ret, " msg", retlen) >= retlen) + goto toolong; + } + + return; +toolong: + strlcpy(ret, "toolong", retlen); +} + +/* + * Print a FIDO device's attributes on stdout. + */ +static void +print_attr(const fido_dev_t *dev) +{ + char flags_txt[128]; + + printf("proto: 0x%02x\n", fido_dev_protocol(dev)); + printf("major: 0x%02x\n", fido_dev_major(dev)); + printf("minor: 0x%02x\n", fido_dev_minor(dev)); + printf("build: 0x%02x\n", fido_dev_build(dev)); + + format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); + printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); +} + +/* + * Auxiliary function to print an array of strings on stdout. + */ +static void +print_str_array(const char *label, char * const *sa, size_t len) +{ + if (len == 0) + return; + + printf("%s strings: ", label); + + for (size_t i = 0; i < len; i++) + printf("%s%s", i > 0 ? ", " : "", sa[i]); + + printf("\n"); +} + +/* + * Auxiliary function to print (char *, bool) pairs on stdout. + */ +static void +print_opt_array(const char *label, char * const *name, const bool *value, + size_t len) +{ + if (len == 0) + return; + + printf("%s: ", label); + + for (size_t i = 0; i < len; i++) + printf("%s%s%s", i > 0 ? ", " : "", + value[i] ? "" : "no", name[i]); + + printf("\n"); +} + +/* + * Auxiliary function to print (char *, uint64_t) pairs on stdout. + */ +static void +print_cert_array(const char *label, char * const *name, const uint64_t *value, + size_t len) +{ + if (len == 0) + return; + + printf("%s: ", label); + + for (size_t i = 0; i < len; i++) + printf("%s%s %llu", i > 0 ? ", " : "", name[i], + (unsigned long long)value[i]); + + printf("\n"); +} + +/* + * Auxiliary function to print a list of supported COSE algorithms on stdout. + */ +static void +print_algorithms(const fido_cbor_info_t *ci) +{ + const char *cose, *type; + size_t len; + + if ((len = fido_cbor_info_algorithm_count(ci)) == 0) + return; + + printf("algorithms: "); + + for (size_t i = 0; i < len; i++) { + cose = type = "unknown"; + switch (fido_cbor_info_algorithm_cose(ci, i)) { + case COSE_ES256: + cose = "es256"; + break; + case COSE_ES384: + cose = "es384"; + break; + case COSE_RS256: + cose = "rs256"; + break; + case COSE_EDDSA: + cose = "eddsa"; + break; + } + if (fido_cbor_info_algorithm_type(ci, i) != NULL) + type = fido_cbor_info_algorithm_type(ci, i); + printf("%s%s (%s)", i > 0 ? ", " : "", cose, type); + } + + printf("\n"); +} + +/* + * Auxiliary function to print an authenticator's AAGUID on stdout. + */ +static void +print_aaguid(const unsigned char *buf, size_t buflen) +{ + printf("aaguid: "); + + while (buflen--) + printf("%02x", *buf++); + + printf("\n"); +} + +/* + * Auxiliary function to print an authenticator's maximum message size on + * stdout. + */ +static void +print_maxmsgsiz(uint64_t maxmsgsiz) +{ + printf("maxmsgsiz: %d\n", (int)maxmsgsiz); +} + +/* + * Auxiliary function to print an authenticator's maximum number of credentials + * in a credential list on stdout. + */ +static void +print_maxcredcntlst(uint64_t maxcredcntlst) +{ + printf("maxcredcntlst: %d\n", (int)maxcredcntlst); +} + +/* + * Auxiliary function to print an authenticator's maximum credential ID length + * on stdout. + */ +static void +print_maxcredidlen(uint64_t maxcredidlen) +{ + printf("maxcredlen: %d\n", (int)maxcredidlen); +} + +/* + * Auxiliary function to print the maximum size of an authenticator's + * serialized largeBlob array. + */ +static void +print_maxlargeblob(uint64_t maxlargeblob) +{ + printf("maxlargeblob: %d\n", (int)maxlargeblob); +} + +/* + * Auxiliary function to print the authenticator's estimated number of + * remaining resident credentials. + */ +static void +print_rk_remaining(int64_t rk_remaining) +{ + printf("remaining rk(s): "); + + if (rk_remaining == -1) + printf("undefined\n"); + else + printf("%d\n", (int)rk_remaining); +} + +/* + * Auxiliary function to print the minimum pin length observed by the + * authenticator. + */ +static void +print_minpinlen(uint64_t minpinlen) +{ + printf("minpinlen: %d\n", (int)minpinlen); +} + +/* + * Auxiliary function to print the authenticator's preferred (platform) + * UV attempts. + */ +static void +print_uv_attempts(uint64_t uv_attempts) +{ + printf("platform uv attempt(s): %d\n", (int)uv_attempts); +} + +/* + * Auxiliary function to print an authenticator's firmware version on stdout. + */ +static void +print_fwversion(uint64_t fwversion) +{ + printf("fwversion: 0x%x\n", (int)fwversion); +} + +/* + * Auxiliary function to print an array of bytes on stdout. + */ +static void +print_byte_array(const char *label, const uint8_t *ba, size_t len) +{ + if (len == 0) + return; + + printf("%s: ", label); + + for (size_t i = 0; i < len; i++) + printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); + + printf("\n"); +} + +static void +getinfo(const char *path) +{ + fido_dev_t *dev; + fido_cbor_info_t *ci; + int r; + + fido_init(0); + + if ((dev = fido_dev_new()) == NULL) + errx(1, "fido_dev_new"); + if ((r = fido_dev_open(dev, path)) != FIDO_OK) + errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); + + print_attr(dev); + + if (fido_dev_is_fido2(dev) == false) + goto end; + if ((ci = fido_cbor_info_new()) == NULL) + errx(1, "fido_cbor_info_new"); + if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) + errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); + + /* print supported protocol versions */ + print_str_array("version", fido_cbor_info_versions_ptr(ci), + fido_cbor_info_versions_len(ci)); + + /* print supported extensions */ + print_str_array("extension", fido_cbor_info_extensions_ptr(ci), + fido_cbor_info_extensions_len(ci)); + + /* print supported transports */ + print_str_array("transport", fido_cbor_info_transports_ptr(ci), + fido_cbor_info_transports_len(ci)); + + /* print supported algorithms */ + print_algorithms(ci); + + /* print aaguid */ + print_aaguid(fido_cbor_info_aaguid_ptr(ci), + fido_cbor_info_aaguid_len(ci)); + + /* print supported options */ + print_opt_array("options", fido_cbor_info_options_name_ptr(ci), + fido_cbor_info_options_value_ptr(ci), + fido_cbor_info_options_len(ci)); + + /* print certifications */ + print_cert_array("certifications", fido_cbor_info_certs_name_ptr(ci), + fido_cbor_info_certs_value_ptr(ci), + fido_cbor_info_certs_len(ci)); + + /* print firmware version */ + print_fwversion(fido_cbor_info_fwversion(ci)); + + /* print maximum message size */ + print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); + + /* print maximum number of credentials allowed in credential lists */ + print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci)); + + /* print maximum length of a credential ID */ + print_maxcredidlen(fido_cbor_info_maxcredidlen(ci)); + + /* print maximum length of largeBlob array */ + print_maxlargeblob(fido_cbor_info_maxlargeblob(ci)); + + /* print number of remaining resident credentials */ + print_rk_remaining(fido_cbor_info_rk_remaining(ci)); + + /* print minimum pin length */ + print_minpinlen(fido_cbor_info_minpinlen(ci)); + + /* print supported pin protocols */ + print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), + fido_cbor_info_protocols_len(ci)); + + /* print whether a new pin is required */ + printf("pin change required: %s\n", + fido_cbor_info_new_pin_required(ci) ? "true" : "false"); + + /* print platform uv attempts */ + print_uv_attempts(fido_cbor_info_uv_attempts(ci)); + + fido_cbor_info_free(&ci); +end: + if ((r = fido_dev_close(dev)) != FIDO_OK) + errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); + + fido_dev_free(&dev); +} + +int +main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "usage: info \n"); + exit(EXIT_FAILURE); + } + + getinfo(argv[1]); + + exit(0); +} diff --git a/examples/manifest.c b/examples/manifest.c new file mode 100644 index 0000000..c2b3bf1 --- /dev/null +++ b/examples/manifest.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" + +int +main(void) +{ + fido_dev_info_t *devlist; + size_t ndevs; + int r; + + fido_init(0); + + if ((devlist = fido_dev_info_new(64)) == NULL) + errx(1, "fido_dev_info_new"); + + if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) + errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); + + for (size_t i = 0; i < ndevs; i++) { + const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); + printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n", + fido_dev_info_path(di), + (uint16_t)fido_dev_info_vendor(di), + (uint16_t)fido_dev_info_product(di), + fido_dev_info_manufacturer_string(di), + fido_dev_info_product_string(di)); + } + + fido_dev_info_free(&devlist, ndevs); + + exit(0); +} diff --git a/examples/reset.c b/examples/reset.c new file mode 100644 index 0000000..767a162 --- /dev/null +++ b/examples/reset.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * Perform a factory reset on a given authenticator. + */ + +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" +#include "extern.h" + +int +main(int argc, char **argv) +{ + fido_dev_t *dev; + int r; + + if (argc != 2) { + fprintf(stderr, "usage: reset \n"); + exit(EXIT_FAILURE); + } + + fido_init(0); + + if ((dev = fido_dev_new()) == NULL) + errx(1, "fido_dev_new"); + + if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK) + errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); + + if ((r = fido_dev_reset(dev)) != FIDO_OK) { + fido_dev_cancel(dev); + errx(1, "fido_dev_reset: %s (0x%x)", fido_strerr(r), r); + } + + if ((r = fido_dev_close(dev)) != FIDO_OK) + errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); + + fido_dev_free(&dev); + + exit(0); +} diff --git a/examples/retries.c b/examples/retries.c new file mode 100644 index 0000000..a0610fe --- /dev/null +++ b/examples/retries.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * Get an authenticator's number of PIN attempts left. + */ + +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" + +int +main(int argc, char **argv) +{ + fido_dev_t *dev; + int n; + int r; + + if (argc != 2) { + fprintf(stderr, "usage: retries \n"); + exit(EXIT_FAILURE); + } + + fido_init(0); + + if ((dev = fido_dev_new()) == NULL) + errx(1, "fido_dev_new"); + + if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK) + errx(1, "fido_open: %s (0x%x)", fido_strerr(r), r); + + if ((r = fido_dev_get_retry_count(dev, &n)) != FIDO_OK) + errx(1, "fido_dev_get_retry_count: %s (0x%x)", fido_strerr(r), r); + + if ((r = fido_dev_close(dev)) != FIDO_OK) + errx(1, "fido_close: %s (0x%x)", fido_strerr(r), r); + + fido_dev_free(&dev); + + printf("%d\n", n); + + exit(0); +} diff --git a/examples/select.c b/examples/select.c new file mode 100644 index 0000000..008eb2e --- /dev/null +++ b/examples/select.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2020-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" + +#define FIDO_POLL_MS 50 + +#if defined(_MSC_VER) +static int +nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + if (rmtp != NULL) { + errno = EINVAL; + return (-1); + } + + Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000)); + + return (0); +} +#endif + +static fido_dev_t * +open_dev(const fido_dev_info_t *di) +{ + fido_dev_t *dev; + int r; + + if ((dev = fido_dev_new()) == NULL) { + warnx("%s: fido_dev_new", __func__); + return (NULL); + } + + if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) { + warnx("%s: fido_dev_open %s: %s", __func__, + fido_dev_info_path(di), fido_strerr(r)); + fido_dev_free(&dev); + return (NULL); + } + + printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di), + fido_dev_info_vendor(di), fido_dev_info_product(di), + fido_dev_is_fido2(dev) ? "fido2" : "u2f"); + + return (dev); +} + +static int +select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev, + size_t *idx, int secs) +{ + const fido_dev_info_t *di; + fido_dev_t **devtab; + struct timespec ts_start; + struct timespec ts_now; + struct timespec ts_delta; + struct timespec ts_pause; + size_t nopen = 0; + int touched; + int r; + long ms_remain; + + *dev = NULL; + *idx = 0; + + printf("%u authenticator(s) detected\n", (unsigned)ndevs); + + if (ndevs == 0) + return (0); /* nothing to do */ + + if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) { + warn("%s: calloc", __func__); + return (-1); + } + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if ((devtab[i] = open_dev(di)) != NULL) { + *idx = i; + nopen++; + } + } + + printf("%u authenticator(s) opened\n", (unsigned)nopen); + + if (nopen < 2) { + if (nopen == 1) + *dev = devtab[*idx]; /* single candidate */ + r = 0; + goto out; + } + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if (devtab[i] == NULL) + continue; /* failed to open */ + if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) { + warnx("%s: fido_dev_get_touch_begin %s: %s", __func__, + fido_dev_info_path(di), fido_strerr(r)); + r = -1; + goto out; + } + } + + if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) { + warn("%s: clock_gettime", __func__); + r = -1; + goto out; + } + + ts_pause.tv_sec = 0; + ts_pause.tv_nsec = 200000000; /* 200ms */ + + do { + nanosleep(&ts_pause, NULL); + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if (devtab[i] == NULL) { + /* failed to open or discarded */ + continue; + } + if ((r = fido_dev_get_touch_status(devtab[i], &touched, + FIDO_POLL_MS)) != FIDO_OK) { + warnx("%s: fido_dev_get_touch_status %s: %s", + __func__, fido_dev_info_path(di), + fido_strerr(r)); + fido_dev_close(devtab[i]); + fido_dev_free(&devtab[i]); + continue; /* discard */ + } + if (touched) { + *dev = devtab[i]; + *idx = i; + r = 0; + goto out; + } + } + + if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) { + warn("%s: clock_gettime", __func__); + r = -1; + goto out; + } + + timespecsub(&ts_now, &ts_start, &ts_delta); + ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) + + ((long)ts_delta.tv_nsec / 1000000); + } while (ms_remain > FIDO_POLL_MS); + + printf("timeout after %d seconds\n", secs); + r = -1; +out: + if (r != 0) { + *dev = NULL; + *idx = 0; + } + + for (size_t i = 0; i < ndevs; i++) { + if (devtab[i] && devtab[i] != *dev) { + fido_dev_cancel(devtab[i]); + fido_dev_close(devtab[i]); + fido_dev_free(&devtab[i]); + } + } + + free(devtab); + + return (r); +} + +int +main(void) +{ + const fido_dev_info_t *di; + fido_dev_info_t *devlist; + fido_dev_t *dev; + size_t idx; + size_t ndevs; + int r; + + fido_init(0); + + if ((devlist = fido_dev_info_new(64)) == NULL) + errx(1, "fido_dev_info_new"); + + if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) + errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); + if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0) + errx(1, "select_dev"); + if (dev == NULL) + errx(1, "no authenticator found"); + + di = fido_dev_info_ptr(devlist, idx); + printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di), + fido_dev_info_product_string(di), + fido_dev_info_manufacturer_string(di), + fido_dev_has_pin(dev) ? "" : "un"); + + fido_dev_close(dev); + fido_dev_free(&dev); + fido_dev_info_free(&devlist, ndevs); + + exit(0); +} diff --git a/examples/setpin.c b/examples/setpin.c new file mode 100644 index 0000000..72e08e4 --- /dev/null +++ b/examples/setpin.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * Configure a PIN on a given authenticator. + */ + +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" + +static void +setpin(const char *path, const char *pin, const char *oldpin) +{ + fido_dev_t *dev; + int r; + + fido_init(0); + + if ((dev = fido_dev_new()) == NULL) + errx(1, "fido_dev_new"); + + if ((r = fido_dev_open(dev, path)) != FIDO_OK) + errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); + + if ((r = fido_dev_set_pin(dev, pin, oldpin)) != FIDO_OK) + errx(1, "fido_dev_set_pin: %s (0x%x)", fido_strerr(r), r); + + if ((r = fido_dev_close(dev)) != FIDO_OK) + errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); + + fido_dev_free(&dev); +} + +int +main(int argc, char **argv) +{ + if (argc < 3 || argc > 4) { + fprintf(stderr, "usage: setpin [oldpin] \n"); + exit(EXIT_FAILURE); + } + + if (argc == 3) + setpin(argv[2], argv[1], NULL); + else + setpin(argv[3], argv[1], argv[2]); + + exit(0); +} diff --git a/examples/util.c b/examples/util.c new file mode 100644 index 0000000..0c0c77a --- /dev/null +++ b/examples/util.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _MSC_VER +#include "../openbsd-compat/posix_win.h" +#endif +#include "../openbsd-compat/openbsd-compat.h" +#include "extern.h" + +int +base10(const char *str, long long *ll) +{ + char *ep; + + *ll = strtoll(str, &ep, 10); + if (str == ep || *ep != '\0') + return (-1); + else if (*ll == LLONG_MIN && errno == ERANGE) + return (-1); + else if (*ll == LLONG_MAX && errno == ERANGE) + return (-1); + + return (0); +} + +int +write_blob(const char *path, const unsigned char *ptr, size_t len) +{ + int fd, ok = -1; + ssize_t n; + + if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) { + warn("open %s", path); + goto fail; + } + + if ((n = write(fd, ptr, len)) < 0) { + warn("write"); + goto fail; + } + if ((size_t)n != len) { + warnx("write"); + goto fail; + } + + ok = 0; +fail: + if (fd != -1) { + close(fd); + } + + return (ok); +} + +int +read_blob(const char *path, unsigned char **ptr, size_t *len) +{ + int fd, ok = -1; + struct stat st; + ssize_t n; + + *ptr = NULL; + *len = 0; + + if ((fd = open(path, O_RDONLY)) < 0) { + warn("open %s", path); + goto fail; + } + if (fstat(fd, &st) < 0) { + warn("stat %s", path); + goto fail; + } + if (st.st_size < 0) { + warnx("stat %s: invalid size", path); + goto fail; + } + *len = (size_t)st.st_size; + if ((*ptr = malloc(*len)) == NULL) { + warn("malloc"); + goto fail; + } + if ((n = read(fd, *ptr, *len)) < 0) { + warn("read"); + goto fail; + } + if ((size_t)n != *len) { + warnx("read"); + goto fail; + } + + ok = 0; +fail: + if (fd != -1) { + close(fd); + } + if (ok < 0) { + free(*ptr); + *ptr = NULL; + *len = 0; + } + + return (ok); +} + +EC_KEY * +read_ec_pubkey(const char *path) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + EC_KEY *ec = NULL; + + if ((fp = fopen(path, "r")) == NULL) { + warn("fopen"); + goto fail; + } + + if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { + warnx("PEM_read_PUBKEY"); + goto fail; + } + if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { + warnx("EVP_PKEY_get1_EC_KEY"); + goto fail; + } + +fail: + if (fp != NULL) { + fclose(fp); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + + return (ec); +} + +int +write_es256_pubkey(const char *path, const void *ptr, size_t len) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + es256_pk_t *pk = NULL; + int fd = -1; + int ok = -1; + + if ((pk = es256_pk_new()) == NULL) { + warnx("es256_pk_new"); + goto fail; + } + + if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { + warnx("es256_pk_from_ptr"); + goto fail; + } + + if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { + warn("open %s", path); + goto fail; + } + + if ((fp = fdopen(fd, "w")) == NULL) { + warn("fdopen"); + goto fail; + } + fd = -1; /* owned by fp now */ + + if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { + warnx("es256_pk_to_EVP_PKEY"); + goto fail; + } + + if (PEM_write_PUBKEY(fp, pkey) == 0) { + warnx("PEM_write_PUBKEY"); + goto fail; + } + + ok = 0; +fail: + es256_pk_free(&pk); + + if (fp != NULL) { + fclose(fp); + } + if (fd != -1) { + close(fd); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + + return (ok); +} + +int +write_es384_pubkey(const char *path, const void *ptr, size_t len) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + es384_pk_t *pk = NULL; + int fd = -1; + int ok = -1; + + if ((pk = es384_pk_new()) == NULL) { + warnx("es384_pk_new"); + goto fail; + } + + if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) { + warnx("es384_pk_from_ptr"); + goto fail; + } + + if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { + warn("open %s", path); + goto fail; + } + + if ((fp = fdopen(fd, "w")) == NULL) { + warn("fdopen"); + goto fail; + } + fd = -1; /* owned by fp now */ + + if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) { + warnx("es384_pk_to_EVP_PKEY"); + goto fail; + } + + if (PEM_write_PUBKEY(fp, pkey) == 0) { + warnx("PEM_write_PUBKEY"); + goto fail; + } + + ok = 0; +fail: + es384_pk_free(&pk); + + if (fp != NULL) { + fclose(fp); + } + if (fd != -1) { + close(fd); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + + return (ok); +} + +RSA * +read_rsa_pubkey(const char *path) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + + if ((fp = fopen(path, "r")) == NULL) { + warn("fopen"); + goto fail; + } + + if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { + warnx("PEM_read_PUBKEY"); + goto fail; + } + if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { + warnx("EVP_PKEY_get1_RSA"); + goto fail; + } + +fail: + if (fp != NULL) { + fclose(fp); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + + return (rsa); +} + +int +write_rs256_pubkey(const char *path, const void *ptr, size_t len) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + rs256_pk_t *pk = NULL; + int fd = -1; + int ok = -1; + + if ((pk = rs256_pk_new()) == NULL) { + warnx("rs256_pk_new"); + goto fail; + } + + if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { + warnx("rs256_pk_from_ptr"); + goto fail; + } + + if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { + warn("open %s", path); + goto fail; + } + + if ((fp = fdopen(fd, "w")) == NULL) { + warn("fdopen"); + goto fail; + } + fd = -1; /* owned by fp now */ + + if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { + warnx("rs256_pk_to_EVP_PKEY"); + goto fail; + } + + if (PEM_write_PUBKEY(fp, pkey) == 0) { + warnx("PEM_write_PUBKEY"); + goto fail; + } + + ok = 0; +fail: + rs256_pk_free(&pk); + + if (fp != NULL) { + fclose(fp); + } + if (fd != -1) { + close(fd); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + + return (ok); +} + +EVP_PKEY * +read_eddsa_pubkey(const char *path) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + + if ((fp = fopen(path, "r")) == NULL) { + warn("fopen"); + goto fail; + } + + if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { + warnx("PEM_read_PUBKEY"); + goto fail; + } + +fail: + if (fp) { + fclose(fp); + } + + return (pkey); +} + +int +write_eddsa_pubkey(const char *path, const void *ptr, size_t len) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + eddsa_pk_t *pk = NULL; + int fd = -1; + int ok = -1; + + if ((pk = eddsa_pk_new()) == NULL) { + warnx("eddsa_pk_new"); + goto fail; + } + + if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { + warnx("eddsa_pk_from_ptr"); + goto fail; + } + + if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { + warn("open %s", path); + goto fail; + } + + if ((fp = fdopen(fd, "w")) == NULL) { + warn("fdopen"); + goto fail; + } + fd = -1; /* owned by fp now */ + + if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { + warnx("eddsa_pk_to_EVP_PKEY"); + goto fail; + } + + if (PEM_write_PUBKEY(fp, pkey) == 0) { + warnx("PEM_write_PUBKEY"); + goto fail; + } + + ok = 0; +fail: + eddsa_pk_free(&pk); + + if (fp != NULL) { + fclose(fp); + } + if (fd != -1) { + close(fd); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + + return (ok); +} diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt new file mode 100644 index 0000000..ca272bb --- /dev/null +++ b/fuzz/CMakeLists.txt @@ -0,0 +1,89 @@ +# Copyright (c) 2019-2024 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause + +list(APPEND COMPAT_SOURCES + ../openbsd-compat/strlcpy.c + ../openbsd-compat/strlcat.c +) + +list(APPEND COMMON_SOURCES + libfuzzer.c + mutator_aux.c +) + +# XXX: OSS-Fuzz require linking using CXX +set(FUZZ_LINKER_LANGUAGE "C" CACHE STRING "Linker language for fuzz harnesses") +mark_as_advanced(FUZZ_LINKER_LANGUAGE) +enable_language(${FUZZ_LINKER_LANGUAGE}) + +# fuzz_cred +add_executable(fuzz_cred fuzz_cred.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_cred PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_cred fido2_shared) + +# fuzz_assert +add_executable(fuzz_assert fuzz_assert.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_assert PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_assert fido2_shared) + +# fuzz_mgmt +add_executable(fuzz_mgmt fuzz_mgmt.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_mgmt PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_mgmt fido2_shared) + +# fuzz_credman +add_executable(fuzz_credman fuzz_credman.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_credman PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_credman fido2_shared) + +# fuzz_bio +add_executable(fuzz_bio fuzz_bio.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_bio PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_bio fido2_shared) + +# fuzz_hid +add_executable(fuzz_hid fuzz_hid.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_hid PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_hid fido2_shared) + +# fuzz_netlink +add_executable(fuzz_netlink fuzz_netlink.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_netlink PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_netlink fido2_shared) + +# fuzz_largeblob +add_executable(fuzz_largeblob fuzz_largeblob.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_largeblob PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_largeblob fido2_shared) + +# fuzz_pcsc +add_executable(fuzz_pcsc fuzz_pcsc.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_pcsc PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_pcsc fido2_shared) + +# fuzz_attobj +add_executable(fuzz_attobj fuzz_attobj.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_attobj PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_attobj fido2_shared) diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile new file mode 100644 index 0000000..68d40fa --- /dev/null +++ b/fuzz/Dockerfile @@ -0,0 +1,16 @@ +# Copyright (c) 2019-2023 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause + +FROM alpine:latest +ENV CC=clang +ENV CXX=clang++ +RUN apk -q update +RUN apk add build-base clang clang-analyzer cmake compiler-rt coreutils +RUN apk add eudev-dev git linux-headers llvm openssl-dev pcsc-lite-dev +RUN apk add sudo tar zlib-dev +RUN git clone --branch v0.11.0 --depth=1 https://github.com/PJK/libcbor +RUN git clone --depth=1 https://github.com/yubico/libfido2 +WORKDIR /libfido2 +RUN ./fuzz/build-coverage /libcbor /libfido2 diff --git a/fuzz/Makefile b/fuzz/Makefile new file mode 100644 index 0000000..ab84b99 --- /dev/null +++ b/fuzz/Makefile @@ -0,0 +1,90 @@ +# Copyright (c) 2019-2023 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause + +IMAGE := libfido2-coverage:1.15.0 +RUNNER := libfido2-runner +PROFDATA := llvm-profdata +COV := llvm-cov +TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_hid \ + fuzz_largeblob fuzz_netlink fuzz_mgmt fuzz_pcsc +CORPORA := $(foreach f,${TARGETS},${f}/corpus) +MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus) +REMOTE := gs://libfido2-corpus.clusterfuzz-external.appspot.com +.DEFAULT_GOAL := all + +all: ${TARGETS} + +build: + docker build -t ${IMAGE} - < Dockerfile + +run: build + -docker run -it -d --name ${RUNNER} ${IMAGE} + docker start ${RUNNER} + +sync: run + tar Ccf .. - src fuzz | docker exec -i ${RUNNER} tar Cxf /libfido2 - + docker exec ${RUNNER} make -C /libfido2/build + +corpus: sync + docker exec ${RUNNER} /bin/sh -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}' + docker exec ${RUNNER} tar Czxf /libfido2/fuzz /libfido2/fuzz/corpus.tgz + +${TARGETS}: corpus sync + docker exec -e LLVM_PROFILE_FILE=/profraw/$@ ${RUNNER} \ + /bin/sh -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ + -runs=1 /libfido2/fuzz/$@' + +${MINIFY}: /minify/%/corpus: % + docker exec ${RUNNER} /bin/sh -c 'rm -rf $@ && mkdir -p $@ && \ + /libfido2/build/fuzz/$< -use_value_profile=1 -merge=1 $@ \ + /libfido2/fuzz/$ $@ + +profdata: run + docker exec ${RUNNER} /bin/sh -c 'rm -f /$@ && ${PROFDATA} \ + merge -sparse /profraw/* -o /$@' + +report.tgz: profdata + docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \ + ${COV} show -format=html -tab-size=8 -instr-profile=/$< \ + -ignore-filename-regex=pcsclite.h --show-branch-summary=false \ + -output-dir=/report /libfido2/build/src/libfido2.so' + docker exec -i ${RUNNER} tar Czcf / - report > $@ + +summary.txt: profdata + docker exec ${RUNNER} ${COV} report -use-color=false \ + -ignore-filename-regex=pcsclite.h --show-branch-summary=false \ + /libfido2/build/src/libfido2.so -instr-profile=/$< > $@ + +functions.txt: profdata + docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \ + -ignore-filename-regex=pcsclite.h -show-functions \ + --show-branch-summary=false -instr-profile=/$< \ + /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@ + +clean: run + docker exec ${RUNNER} /bin/sh -c 'rm -rf /profraw /profdata && \ + make -C /libfido2/build clean' + -docker stop ${RUNNER} + rm -rf ${TARGETS} + +${CORPORA}: + -mkdir -p $@ + gsutil -q -m rsync -d -r ${REMOTE}/libFuzzer/libfido2_$(@:/corpus=) $@ + +fetch-oss-fuzz: ${CORPORA} + find ${TARGETS} -type f -size +8192c -print0 | xargs -0 rm + +fetch-franz: + ssh franz tar -C corpus -cf- . | tar -xf- + +corpus.tgz: + tar zcf $@ ${TARGETS} + +.PHONY: build run sync corpus ${TARGETS} ${CORPORA} +.PHONY: report.tgz summary.txt functions.txt +.PHONY: fetch-oss-fuzz fetch-franz corpus.tgz diff --git a/fuzz/README b/fuzz/README new file mode 100644 index 0000000..427625c --- /dev/null +++ b/fuzz/README @@ -0,0 +1,43 @@ +libfido2 can be fuzzed using AFL or libFuzzer, with or without +ASAN/MSAN/UBSAN. + +AFL is more convenient when fuzzing the path from the authenticator to +libfido2 in an existing application. To do so, use preload-snoop.c with a real +authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=ON, and +use preload-fuzz.c to read device data from stdin. + +libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, +fuzz_assert.c, fuzz_hid.c, and fuzz_mgmt.c for examples. To build these +harnesses, use -DCMAKE_C_FLAGS=-fsanitize=fuzzer-no-link +-DFUZZ_LDFLAGS=-fsanitize=fuzzer -DFUZZ=ON. + +If -DFUZZ=ON is enabled, symbols listed in wrapped.sym are wrapped in the +resulting shared object. The wrapper functions simulate failure according to a +deterministic RNG and probabilities defined in wrap.c. Harnesses wishing to +use this functionality should call prng_init() with a seed obtained from the +corpus. To mutate only the seed part of a libFuzzer harness's corpora, +use '-reduce_inputs=0 --fido-mutate=seed'. + +To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of +libcbor and OpenSSL built with the respective sanitiser. In order to keep +memory utilisation at a manageable level, you can either enforce limits at +the OS level (e.g. cgroups on Linux), or patch libcbor with the diff below. +N.B., the patch below is relative to libcbor 0.10.1. + +diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c +index bbea63c..3f7c9af 100644 +--- src/cbor/internal/memory_utils.c ++++ src/cbor/internal/memory_utils.c +@@ -41,7 +41,11 @@ size_t _cbor_safe_signaling_add(size_t a, size_t b) { + + void* _cbor_alloc_multiple(size_t item_size, size_t item_count) { + if (_cbor_safe_to_multiply(item_size, item_count)) { +- return _cbor_malloc(item_size * item_count); ++ if (item_count > 1000) { ++ return NULL; ++ } else { ++ return _cbor_malloc(item_size * item_count); ++ } + } else { + return NULL; + } diff --git a/fuzz/build-coverage b/fuzz/build-coverage new file mode 100644 index 0000000..6cc5041 --- /dev/null +++ b/fuzz/build-coverage @@ -0,0 +1,34 @@ +#!/bin/sh -eux + +# Copyright (c) 2019 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause + +LIBCBOR="$1" +LIBFIDO2="$2" + +CC="${CC:-clang}" +CXX="${CXX:-clang++}" +PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig}" +export CC PKG_CONFIG_PATH + +# Clean up. +rm -rf "${LIBCBOR}/build" "${LIBCBOR}/install" "${LIBFIDO2}/build" + +# Patch, build, and install libcbor. +(cd "${LIBCBOR}" && patch -N -l -s -p0 < "${LIBFIDO2}/fuzz/README") || true +mkdir "${LIBCBOR}/build" "${LIBCBOR}/install" +(cd "${LIBCBOR}/build" && cmake -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..) +make -C "${LIBCBOR}/build" VERBOSE=1 all install + +# Build libfido2. +mkdir -p "${LIBFIDO2}/build" +export CFLAGS="-fprofile-instr-generate -fcoverage-mapping" +export CFLAGS="${CFLAGS} -fsanitize=fuzzer-no-link" +export LDFLAGS="${CFLAGS}" +export FUZZ_LDFLAGS="${LDFLAGS} -fsanitize=fuzzer" +(cd "${LIBFIDO2}/build" && cmake -DFUZZ=ON -DFUZZ_LDFLAGS="${FUZZ_LDFLAGS}" \ + -DCMAKE_BUILD_TYPE=Debug ..) +make -C "${LIBFIDO2}/build" diff --git a/fuzz/clock.c b/fuzz/clock.c new file mode 100644 index 0000000..bd758ea --- /dev/null +++ b/fuzz/clock.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include "mutator_aux.h" + +/* + * A pseudo-random monotonic clock with a probabilistic discontinuity to + * the end of time (as measured by struct timespec). + */ + +extern int prng_up; +extern int __wrap_clock_gettime(clockid_t, struct timespec *); +extern int __real_clock_gettime(clockid_t, struct timespec *); +extern int __wrap_usleep(unsigned int); +static TLS struct timespec fuzz_clock; + +static void +tick(unsigned int usec) +{ + long long drift; + + /* + * Simulate a jump to the end of time with 0.125% probability. + * This condition should be gracefully handled by callers of + * clock_gettime(). + */ + if (uniform_random(800) < 1) { + fuzz_clock.tv_sec = LLONG_MAX; + fuzz_clock.tv_nsec = LONG_MAX; + return; + } + + drift = usec * 1000LL + (long long)uniform_random(10000000); /* 10ms */ + if (LLONG_MAX - drift < (long long)fuzz_clock.tv_nsec) { + fuzz_clock_reset(); /* Not much we can do here. */ + } else if (drift + (long long)fuzz_clock.tv_nsec < 1000000000) { + fuzz_clock.tv_nsec += (long)(drift); + } else { + fuzz_clock.tv_sec += (long)(drift / 1000000000); + fuzz_clock.tv_nsec += (long)(drift % 1000000000); + } +} + +int +__wrap_clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + if (!prng_up || clk_id != CLOCK_MONOTONIC) + return __real_clock_gettime(clk_id, tp); + if (uniform_random(400) < 1) + return -1; + + tick(0); + *tp = fuzz_clock; + + return 0; +} + +int +__wrap_usleep(unsigned int usec) +{ + if (uniform_random(400) < 1) + return -1; + + tick(usec); + + return 0; +} + +void +fuzz_clock_reset(void) +{ + memset(&fuzz_clock, 0, sizeof(fuzz_clock)); +} diff --git a/fuzz/dummy.h b/fuzz/dummy.h new file mode 100644 index 0000000..fc4bfc5 --- /dev/null +++ b/fuzz/dummy.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2020-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _DUMMY_H +#define _DUMMY_H + +#include + +const char dummy_name[] = "finger1"; +const char dummy_pin1[] = "skepp cg0u3;Y.."; +const char dummy_pin2[] = "bastilha 6rJrfQZI."; +const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; +const char dummy_rp_id[] = "localhost"; +const char dummy_rp_name[] = "sweet home localhost"; +const char dummy_user_icon[] = "an icon"; +const char dummy_user_name[] = "john smith"; +const char dummy_user_nick[] = "jsmith"; +const char dummy_pcsc_list[] = "reader1\0reader2\0reader3\0\0"; +const char dummy_pcsc_path[] = "pcsc://slot7"; +const uint8_t dummy_id[] = { 0x5e, 0xd2 }; + +const uint8_t dummy_user_id[] = { + 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, + 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, + 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, + 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, +}; + +const uint8_t dummy_cred_id[] = { + 0x4f, 0x72, 0x98, 0x42, 0x4a, 0xe1, 0x17, 0xa5, + 0x85, 0xa0, 0xef, 0x3b, 0x11, 0x24, 0x4a, 0x3d, +}; + +const uint8_t dummy_cdh[] = { + 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, + 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, + 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, + 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, +}; + +const uint8_t dummy_es256[] = { + 0xcc, 0x1b, 0x50, 0xac, 0xc4, 0x19, 0xf8, 0x3a, + 0xee, 0x0a, 0x77, 0xd6, 0xf3, 0x53, 0xdb, 0xef, + 0xf2, 0xb9, 0x5c, 0x2d, 0x8b, 0x1e, 0x52, 0x58, + 0x88, 0xf4, 0x0b, 0x85, 0x1f, 0x40, 0x6d, 0x18, + 0x15, 0xb3, 0xcc, 0x25, 0x7c, 0x38, 0x3d, 0xec, + 0xdf, 0xad, 0xbd, 0x46, 0x91, 0xc3, 0xac, 0x30, + 0x94, 0x2a, 0xf7, 0x78, 0x35, 0x70, 0x59, 0x6f, + 0x28, 0xcb, 0x8e, 0x07, 0x85, 0xb5, 0x91, 0x96, +}; + +const uint8_t dummy_rs256[] = { + 0xd2, 0xa8, 0xc0, 0x11, 0x82, 0x9e, 0x57, 0x2e, + 0x60, 0xae, 0x8c, 0xb0, 0x09, 0xe1, 0x58, 0x2b, + 0x99, 0xec, 0xc3, 0x11, 0x1b, 0xef, 0x81, 0x49, + 0x34, 0x53, 0x6a, 0x01, 0x65, 0x2c, 0x24, 0x09, + 0x30, 0x87, 0x98, 0x51, 0x6e, 0x30, 0x4f, 0x60, + 0xbd, 0x54, 0xd2, 0x54, 0xbd, 0x94, 0x42, 0xdd, + 0x63, 0xe5, 0x2c, 0xc6, 0x04, 0x32, 0xc0, 0x8f, + 0x72, 0xd5, 0xb4, 0xf0, 0x4f, 0x42, 0xe5, 0xb0, + 0xa2, 0x95, 0x11, 0xfe, 0xd8, 0xb0, 0x65, 0x34, + 0xff, 0xfb, 0x44, 0x97, 0x52, 0xfc, 0x67, 0x23, + 0x0b, 0xad, 0xf3, 0x3a, 0x82, 0xd4, 0x96, 0x10, + 0x87, 0x6b, 0xfa, 0xd6, 0x51, 0x60, 0x3e, 0x1c, + 0xae, 0x19, 0xb8, 0xce, 0x08, 0xae, 0x9a, 0xee, + 0x78, 0x16, 0x22, 0xcc, 0x92, 0xcb, 0xa8, 0x95, + 0x34, 0xe5, 0xb9, 0x42, 0x6a, 0xf0, 0x2e, 0x82, + 0x1f, 0x4c, 0x7d, 0x84, 0x94, 0x68, 0x7b, 0x97, + 0x2b, 0xf7, 0x7d, 0x67, 0x83, 0xbb, 0xc7, 0x8a, + 0x31, 0x5a, 0xf3, 0x2a, 0x95, 0xdf, 0x63, 0xe7, + 0x4e, 0xee, 0x26, 0xda, 0x87, 0x00, 0xe2, 0x23, + 0x4a, 0x33, 0x9a, 0xa0, 0x1b, 0xce, 0x60, 0x1f, + 0x98, 0xa1, 0xb0, 0xdb, 0xbf, 0x20, 0x59, 0x27, + 0xf2, 0x06, 0xd9, 0xbe, 0x37, 0xa4, 0x03, 0x6b, + 0x6a, 0x4e, 0xaf, 0x22, 0x68, 0xf3, 0xff, 0x28, + 0x59, 0x05, 0xc9, 0xf1, 0x28, 0xf4, 0xbb, 0x35, + 0xe0, 0xc2, 0x68, 0xc2, 0xaa, 0x54, 0xac, 0x8c, + 0xc1, 0x69, 0x9e, 0x4b, 0x32, 0xfc, 0x53, 0x58, + 0x85, 0x7d, 0x3f, 0x51, 0xd1, 0xc9, 0x03, 0x02, + 0x13, 0x61, 0x62, 0xda, 0xf8, 0xfe, 0x3e, 0xc8, + 0x95, 0x12, 0xfb, 0x0c, 0xdf, 0x06, 0x65, 0x6f, + 0x23, 0xc7, 0x83, 0x7c, 0x50, 0x2d, 0x27, 0x25, + 0x4d, 0xbf, 0x94, 0xf0, 0x89, 0x04, 0xb9, 0x2d, + 0xc4, 0xa5, 0x32, 0xa9, 0x25, 0x0a, 0x99, 0x59, + 0x01, 0x00, 0x01, +}; + +const uint8_t dummy_eddsa[] = { + 0xfe, 0x8b, 0x61, 0x50, 0x31, 0x7a, 0xe6, 0xdf, + 0xb1, 0x04, 0x9d, 0x4d, 0xb5, 0x7a, 0x5e, 0x96, + 0x4c, 0xb2, 0xf9, 0x5f, 0x72, 0x47, 0xb5, 0x18, + 0xe2, 0x39, 0xdf, 0x2f, 0x87, 0x19, 0xb3, 0x02, +}; + +const uint8_t dummy_netlink_wiredata[] = { + 0xd8, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x6e, 0x66, 0x63, 0x00, 0x06, 0x00, 0x01, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x00, + 0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0e, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x07, 0x00, + 0x18, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x9d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9d, 0x2e, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x93, 0xb9, 0x25, 0x00 +}; + +#endif /* !_DUMMY_H */ diff --git a/fuzz/export.gnu b/fuzz/export.gnu new file mode 100644 index 0000000..c23831c --- /dev/null +++ b/fuzz/export.gnu @@ -0,0 +1,289 @@ +{ + global: + eddsa_pk_free; + eddsa_pk_from_EVP_PKEY; + eddsa_pk_from_ptr; + eddsa_pk_new; + eddsa_pk_to_EVP_PKEY; + es256_pk_free; + es256_pk_from_EC_KEY; + es256_pk_from_EVP_PKEY; + es256_pk_from_ptr; + es256_pk_new; + es256_pk_to_EVP_PKEY; + es384_pk_free; + es384_pk_from_EC_KEY; + es384_pk_from_EVP_PKEY; + es384_pk_from_ptr; + es384_pk_new; + es384_pk_to_EVP_PKEY; + fido_assert_allow_cred; + fido_assert_authdata_len; + fido_assert_authdata_ptr; + fido_assert_authdata_raw_len; + fido_assert_authdata_raw_ptr; + fido_assert_blob_len; + fido_assert_blob_ptr; + fido_assert_clientdata_hash_len; + fido_assert_clientdata_hash_ptr; + fido_assert_count; + fido_assert_flags; + fido_assert_free; + fido_assert_hmac_secret_len; + fido_assert_hmac_secret_ptr; + fido_assert_id_len; + fido_assert_id_ptr; + fido_assert_largeblob_key_len; + fido_assert_largeblob_key_ptr; + fido_assert_new; + fido_assert_rp_id; + fido_assert_set_authdata; + fido_assert_set_authdata_raw; + fido_assert_set_clientdata; + fido_assert_set_clientdata_hash; + fido_assert_set_count; + fido_assert_set_extensions; + fido_assert_set_hmac_salt; + fido_assert_set_hmac_secret; + fido_assert_set_options; + fido_assert_set_rp; + fido_assert_set_sig; + fido_assert_set_up; + fido_assert_set_uv; + fido_assert_sigcount; + fido_assert_sig_len; + fido_assert_sig_ptr; + fido_assert_user_display_name; + fido_assert_user_icon; + fido_assert_user_id_len; + fido_assert_user_id_ptr; + fido_assert_user_name; + fido_assert_verify; + fido_bio_dev_enroll_begin; + fido_bio_dev_enroll_cancel; + fido_bio_dev_enroll_continue; + fido_bio_dev_enroll_remove; + fido_bio_dev_get_info; + fido_bio_dev_get_template_array; + fido_bio_dev_set_template_name; + fido_bio_enroll_free; + fido_bio_enroll_last_status; + fido_bio_enroll_new; + fido_bio_enroll_remaining_samples; + fido_bio_info_free; + fido_bio_info_max_samples; + fido_bio_info_new; + fido_bio_info_type; + fido_bio_template; + fido_bio_template_array_count; + fido_bio_template_array_free; + fido_bio_template_array_new; + fido_bio_template_free; + fido_bio_template_id_len; + fido_bio_template_id_ptr; + fido_bio_template_name; + fido_bio_template_new; + fido_bio_template_set_id; + fido_bio_template_set_name; + fido_cbor_info_aaguid_len; + fido_cbor_info_aaguid_ptr; + fido_cbor_info_algorithm_cose; + fido_cbor_info_algorithm_count; + fido_cbor_info_algorithm_type; + fido_cbor_info_certs_len; + fido_cbor_info_certs_name_ptr; + fido_cbor_info_certs_value_ptr; + fido_cbor_info_extensions_len; + fido_cbor_info_extensions_ptr; + fido_cbor_info_free; + fido_cbor_info_fwversion; + fido_cbor_info_maxcredbloblen; + fido_cbor_info_maxcredcntlst; + fido_cbor_info_maxcredidlen; + fido_cbor_info_maxlargeblob; + fido_cbor_info_maxmsgsiz; + fido_cbor_info_maxrpid_minpinlen; + fido_cbor_info_minpinlen; + fido_cbor_info_new; + fido_cbor_info_new_pin_required; + fido_cbor_info_options_len; + fido_cbor_info_options_name_ptr; + fido_cbor_info_options_value_ptr; + fido_cbor_info_protocols_len; + fido_cbor_info_protocols_ptr; + fido_cbor_info_rk_remaining; + fido_cbor_info_transports_len; + fido_cbor_info_transports_ptr; + fido_cbor_info_uv_attempts; + fido_cbor_info_uv_modality; + fido_cbor_info_versions_len; + fido_cbor_info_versions_ptr; + fido_cred_attstmt_len; + fido_cred_attstmt_ptr; + fido_cred_authdata_len; + fido_cred_authdata_ptr; + fido_cred_authdata_raw_len; + fido_cred_authdata_raw_ptr; + fido_cred_clientdata_hash_len; + fido_cred_clientdata_hash_ptr; + fido_cred_display_name; + fido_cred_exclude; + fido_cred_flags; + fido_cred_largeblob_key_len; + fido_cred_largeblob_key_ptr; + fido_cred_sigcount; + fido_cred_fmt; + fido_cred_free; + fido_cred_id_len; + fido_cred_id_ptr; + fido_cred_aaguid_len; + fido_cred_aaguid_ptr; + fido_credman_del_dev_rk; + fido_credman_get_dev_metadata; + fido_credman_get_dev_rk; + fido_credman_get_dev_rp; + fido_credman_metadata_free; + fido_credman_metadata_new; + fido_credman_rk; + fido_credman_rk_count; + fido_credman_rk_existing; + fido_credman_rk_free; + fido_credman_rk_new; + fido_credman_rk_remaining; + fido_credman_rp_count; + fido_credman_rp_free; + fido_credman_rp_id; + fido_credman_rp_id_hash_len; + fido_credman_rp_id_hash_ptr; + fido_credman_rp_name; + fido_credman_rp_new; + fido_credman_set_dev_rk; + fido_cred_new; + fido_cred_pin_minlen; + fido_cred_prot; + fido_cred_pubkey_len; + fido_cred_pubkey_ptr; + fido_cred_rp_id; + fido_cred_rp_name; + fido_cred_set_attstmt; + fido_cred_set_attobj; + fido_cred_set_authdata; + fido_cred_set_authdata_raw; + fido_cred_set_blob; + fido_cred_set_clientdata; + fido_cred_set_clientdata_hash; + fido_cred_set_extensions; + fido_cred_set_fmt; + fido_cred_set_id; + fido_cred_set_options; + fido_cred_set_pin_minlen; + fido_cred_set_prot; + fido_cred_set_rk; + fido_cred_set_rp; + fido_cred_set_sig; + fido_cred_set_type; + fido_cred_set_user; + fido_cred_set_uv; + fido_cred_set_x509; + fido_cred_sig_len; + fido_cred_sig_ptr; + fido_cred_type; + fido_cred_user_id_len; + fido_cred_user_id_ptr; + fido_cred_user_name; + fido_cred_verify; + fido_cred_verify_self; + fido_cred_x5c_len; + fido_cred_x5c_list_count; + fido_cred_x5c_list_len; + fido_cred_x5c_list_ptr; + fido_cred_x5c_ptr; + fido_dev_build; + fido_dev_cancel; + fido_dev_close; + fido_dev_enable_entattest; + fido_dev_flags; + fido_dev_force_fido2; + fido_dev_force_pin_change; + fido_dev_force_u2f; + fido_dev_free; + fido_dev_get_assert; + fido_dev_get_cbor_info; + fido_dev_get_retry_count; + fido_dev_get_uv_retry_count; + fido_dev_get_touch_begin; + fido_dev_get_touch_status; + fido_dev_has_pin; + fido_dev_has_uv; + fido_dev_info_free; + fido_dev_info_manifest; + fido_dev_info_manufacturer_string; + fido_dev_info_new; + fido_dev_info_path; + fido_dev_info_product; + fido_dev_info_product_string; + fido_dev_info_ptr; + fido_dev_info_set; + fido_dev_info_vendor; + fido_dev_is_fido2; + fido_dev_major; + fido_dev_make_cred; + fido_dev_minor; + fido_dev_new; + fido_dev_open; + fido_dev_protocol; + fido_dev_reset; + fido_dev_set_io_functions; + fido_dev_set_pcsc; + fido_dev_set_pin; + fido_dev_set_pin_minlen; + fido_dev_set_pin_minlen_rpid; + fido_dev_set_timeout; + fido_dev_set_transport_functions; + fido_dev_supports_cred_prot; + fido_dev_supports_credman; + fido_dev_supports_permissions; + fido_dev_supports_pin; + fido_dev_supports_uv; + fido_dev_toggle_always_uv; + fido_dev_largeblob_get; + fido_dev_largeblob_get_array; + fido_dev_largeblob_remove; + fido_dev_largeblob_set; + fido_dev_largeblob_set_array; + fido_hid_get_report_len; + fido_hid_get_usage; + fido_init; + fido_nfc_rx; + fido_nfc_tx; + fido_nl_free; + fido_nl_get_nfc_target; + fido_nl_new; + fido_nl_power_nfc; + fido_pcsc_close; + fido_pcsc_manifest; + fido_pcsc_open; + fido_pcsc_read; + fido_pcsc_rx; + fido_pcsc_tx; + fido_pcsc_write; + fido_set_log_handler; + fido_strerr; + rs256_pk_free; + rs256_pk_from_ptr; + rs256_pk_from_EVP_PKEY; + rs256_pk_from_RSA; + rs256_pk_new; + rs256_pk_to_EVP_PKEY; + prng_init; + prng_up; + fuzz_clock_reset; + fuzz_save_corpus; + set_netlink_io_functions; + set_pcsc_parameters; + set_pcsc_io_functions; + set_udev_parameters; + uniform_random; + local: + *; +}; diff --git a/fuzz/functions.txt b/fuzz/functions.txt new file mode 100644 index 0000000..a96618c --- /dev/null +++ b/fuzz/functions.txt @@ -0,0 +1,956 @@ +File '/libfido2/src/aes256.c': +Name Regions Miss Cover Lines Miss Cover +-------------------------------------------------------------------------------------------------------- +aes256_cbc_enc 4 0 100.00% 4 0 100.00% +aes256_cbc_dec 4 0 100.00% 4 0 100.00% +aes256_gcm_enc 1 0 100.00% 3 0 100.00% +aes256_gcm_dec 1 0 100.00% 3 0 100.00% +aes256.c:aes256_cbc_fips 26 1 96.15% 42 4 90.48% +aes256.c:aes256_cbc 29 1 96.55% 36 3 91.67% +aes256.c:aes256_cbc_proto1 1 0 100.00% 5 0 100.00% +aes256.c:aes256_gcm 52 1 98.08% 60 4 93.33% +-------------------------------------------------------------------------------------------------------- +TOTAL 118 3 97.46% 157 11 92.99% + +File '/libfido2/src/assert.c': +Name Regions Miss Cover Lines Miss Cover +----------------------------------------------------------------------------------------------------------------- +fido_dev_get_assert 40 0 100.00% 35 0 100.00% +fido_check_flags 13 0 100.00% 15 0 100.00% +fido_get_signed_hash 20 1 95.00% 34 3 91.18% +fido_assert_verify 50 4 92.00% 70 7 90.00% +fido_assert_set_clientdata 12 12 0.00% 11 11 0.00% +fido_assert_set_clientdata_hash 8 0 100.00% 6 0 100.00% +fido_assert_set_hmac_salt 10 0 100.00% 6 0 100.00% +fido_assert_set_hmac_secret 12 12 0.00% 7 7 0.00% +fido_assert_set_rp 12 0 100.00% 11 0 100.00% +fido_assert_set_winhello_appid 2 2 0.00% 5 5 0.00% +fido_assert_allow_cred 13 2 84.62% 22 3 86.36% +fido_assert_empty_allow_list 2 0 100.00% 5 0 100.00% +fido_assert_set_extensions 14 0 100.00% 10 0 100.00% +fido_assert_set_options 8 8 0.00% 5 5 0.00% +fido_assert_set_up 2 0 100.00% 4 0 100.00% +fido_assert_set_uv 2 0 100.00% 4 0 100.00% +fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% +fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% +fido_assert_new 1 0 100.00% 3 0 100.00% +fido_assert_reset_tx 1 0 100.00% 13 0 100.00% +fido_assert_reset_rx 4 0 100.00% 20 0 100.00% +fido_assert_free 6 0 100.00% 9 0 100.00% +fido_assert_count 1 0 100.00% 3 0 100.00% +fido_assert_rp_id 1 0 100.00% 3 0 100.00% +fido_assert_flags 4 0 100.00% 5 0 100.00% +fido_assert_sigcount 4 0 100.00% 5 0 100.00% +fido_assert_authdata_ptr 4 0 100.00% 5 0 100.00% +fido_assert_authdata_len 4 0 100.00% 5 0 100.00% +fido_assert_authdata_raw_ptr 4 0 100.00% 5 0 100.00% +fido_assert_authdata_raw_len 4 0 100.00% 5 0 100.00% +fido_assert_sig_ptr 4 0 100.00% 5 0 100.00% +fido_assert_sig_len 4 0 100.00% 5 0 100.00% +fido_assert_id_ptr 4 0 100.00% 5 0 100.00% +fido_assert_id_len 4 0 100.00% 5 0 100.00% +fido_assert_user_id_ptr 4 0 100.00% 5 0 100.00% +fido_assert_user_id_len 4 0 100.00% 5 0 100.00% +fido_assert_user_icon 4 0 100.00% 5 0 100.00% +fido_assert_user_name 4 0 100.00% 5 0 100.00% +fido_assert_user_display_name 4 0 100.00% 5 0 100.00% +fido_assert_hmac_secret_ptr 4 0 100.00% 5 0 100.00% +fido_assert_hmac_secret_len 4 0 100.00% 5 0 100.00% +fido_assert_largeblob_key_ptr 4 0 100.00% 5 0 100.00% +fido_assert_largeblob_key_len 4 0 100.00% 5 0 100.00% +fido_assert_blob_ptr 4 0 100.00% 5 0 100.00% +fido_assert_blob_len 4 0 100.00% 5 0 100.00% +fido_assert_set_authdata 28 0 100.00% 33 0 100.00% +fido_assert_set_authdata_raw 28 0 100.00% 32 0 100.00% +fido_assert_set_sig 14 0 100.00% 7 0 100.00% +fido_assert_set_count 10 0 100.00% 17 0 100.00% +assert.c:fido_dev_get_assert_wait 21 0 100.00% 14 0 100.00% +assert.c:fido_dev_get_assert_tx 56 2 96.43% 62 5 91.94% +assert.c:fido_dev_get_assert_rx 27 0 100.00% 36 0 100.00% +assert.c:adjust_assert_count 24 0 100.00% 26 0 100.00% +assert.c:parse_assert_reply 15 0 100.00% 28 0 100.00% +assert.c:fido_get_next_assert_tx 8 0 100.00% 8 0 100.00% +assert.c:fido_get_next_assert_rx 23 2 91.30% 29 5 82.76% +assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00% +assert.c:get_es256_hash 16 0 100.00% 17 0 100.00% +assert.c:get_es384_hash 16 0 100.00% 17 0 100.00% +assert.c:get_eddsa_hash 6 0 100.00% 9 0 100.00% +assert.c:check_extensions 5 0 100.00% 9 0 100.00% +assert.c:fido_assert_reset_extattr 1 0 100.00% 5 0 100.00% +assert.c:fido_assert_clean_authdata 1 0 100.00% 6 0 100.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 628 45 92.83% 782 51 93.48% + +File '/libfido2/src/authkey.c': +Name Regions Miss Cover Lines Miss Cover +----------------------------------------------------------------------------------------------------------------- +fido_dev_authkey 1 0 100.00% 3 0 100.00% +authkey.c:fido_dev_authkey_wait 10 0 100.00% 7 0 100.00% +authkey.c:fido_dev_authkey_tx 19 0 100.00% 25 0 100.00% +authkey.c:fido_dev_authkey_rx 14 0 100.00% 21 0 100.00% +authkey.c:parse_authkey 8 0 100.00% 10 0 100.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 52 0 100.00% 66 0 100.00% + +File '/libfido2/src/bio.c': +Name Regions Miss Cover Lines Miss Cover +----------------------------------------------------------------------------------------------------------------- +fido_bio_dev_get_template_array 5 2 60.00% 6 1 83.33% +fido_bio_dev_set_template_name 7 0 100.00% 6 0 100.00% +fido_bio_dev_enroll_begin 25 2 92.00% 31 1 96.77% +fido_bio_dev_enroll_continue 5 2 60.00% 6 1 83.33% +fido_bio_dev_enroll_cancel 1 1 0.00% 4 4 0.00% +fido_bio_dev_enroll_remove 1 0 100.00% 4 0 100.00% +fido_bio_dev_get_info 1 0 100.00% 4 0 100.00% +fido_bio_template_name 1 0 100.00% 3 0 100.00% +fido_bio_template_id_ptr 1 0 100.00% 3 0 100.00% +fido_bio_template_id_len 1 0 100.00% 3 0 100.00% +fido_bio_template_array_count 1 0 100.00% 3 0 100.00% +fido_bio_template_array_new 1 0 100.00% 3 0 100.00% +fido_bio_template_new 1 0 100.00% 3 0 100.00% +fido_bio_template_array_free 6 0 100.00% 8 0 100.00% +fido_bio_template_free 6 0 100.00% 8 0 100.00% +fido_bio_template_set_name 8 0 100.00% 7 0 100.00% +fido_bio_template_set_id 8 0 100.00% 6 0 100.00% +fido_bio_template 4 0 100.00% 5 0 100.00% +fido_bio_enroll_new 1 0 100.00% 3 0 100.00% +fido_bio_info_new 1 0 100.00% 3 0 100.00% +fido_bio_info_type 1 0 100.00% 3 0 100.00% +fido_bio_info_max_samples 1 0 100.00% 3 0 100.00% +fido_bio_enroll_free 6 0 100.00% 8 0 100.00% +fido_bio_info_free 6 0 100.00% 7 0 100.00% +fido_bio_enroll_remaining_samples 1 0 100.00% 3 0 100.00% +fido_bio_enroll_last_status 1 0 100.00% 3 0 100.00% +bio.c:bio_get_template_array_wait 11 0 100.00% 7 0 100.00% +bio.c:bio_tx 42 0 100.00% 55 0 100.00% +bio.c:bio_get_cmd 8 0 100.00% 5 0 100.00% +bio.c:bio_prepare_hmac 18 0 100.00% 29 0 100.00% +bio.c:bio_rx_template_array 19 0 100.00% 24 0 100.00% +bio.c:bio_parse_template_array 26 1 96.15% 27 4 85.19% +bio.c:decode_template_array 12 1 91.67% 18 3 83.33% +bio.c:decode_template 9 0 100.00% 15 0 100.00% +bio.c:bio_set_template_name_wait 19 0 100.00% 20 0 100.00% +bio.c:bio_enroll_begin_wait 17 0 100.00% 19 0 100.00% +bio.c:bio_rx_enroll_begin 23 0 100.00% 31 0 100.00% +bio.c:bio_parse_enroll_status 20 0 100.00% 28 0 100.00% +bio.c:bio_parse_template_id 8 0 100.00% 10 0 100.00% +bio.c:bio_enroll_continue_wait 19 0 100.00% 20 0 100.00% +bio.c:bio_rx_enroll_continue 19 0 100.00% 25 0 100.00% +bio.c:bio_enroll_cancel_wait 11 11 0.00% 10 10 0.00% +bio.c:bio_enroll_remove_wait 17 0 100.00% 19 0 100.00% +bio.c:bio_get_info_wait 11 0 100.00% 10 0 100.00% +bio.c:bio_rx_info 19 0 100.00% 24 0 100.00% +bio.c:bio_reset_info 1 0 100.00% 4 0 100.00% +bio.c:bio_parse_info 20 0 100.00% 28 0 100.00% +bio.c:bio_reset_template_array 4 0 100.00% 7 0 100.00% +bio.c:bio_reset_template 1 0 100.00% 5 0 100.00% +bio.c:bio_reset_enroll 3 0 100.00% 6 0 100.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 458 20 95.63% 592 24 95.95% + +File '/libfido2/src/blob.c': +Name Regions Miss Cover Lines Miss Cover +----------------------------------------------------------------------------------------------------------------- +fido_blob_new 1 0 100.00% 3 0 100.00% +fido_blob_reset 1 0 100.00% 4 0 100.00% +fido_blob_set 9 0 100.00% 15 0 100.00% +fido_blob_append 12 1 91.67% 20 3 85.00% +fido_blob_free 6 0 100.00% 8 0 100.00% +fido_free_blob_array 7 0 100.00% 12 0 100.00% +fido_blob_encode 6 0 100.00% 5 0 100.00% +fido_blob_decode 1 0 100.00% 3 0 100.00% +fido_blob_is_empty 3 0 100.00% 3 0 100.00% +fido_blob_serialise 7 1 85.71% 10 1 90.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 53 2 96.23% 83 4 95.18% + +File '/libfido2/src/buf.c': +Name Regions Miss Cover Lines Miss Cover +----------------------------------------------------------------------------------------------------------------- +fido_buf_read 4 0 100.00% 8 0 100.00% +fido_buf_write 4 0 100.00% 8 0 100.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 8 0 100.00% 16 0 100.00% + +File '/libfido2/src/cbor.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------ +cbor_map_iter 20 1 95.00% 26 4 84.62% +cbor_array_iter 12 0 100.00% 16 0 100.00% +cbor_parse_reply 27 0 100.00% 36 0 100.00% +cbor_vector_free 6 0 100.00% 5 0 100.00% +cbor_bytestring_copy 14 0 100.00% 18 0 100.00% +cbor_string_copy 14 0 100.00% 18 0 100.00% +cbor_add_bytestring 14 0 100.00% 21 0 100.00% +cbor_add_string 14 0 100.00% 21 0 100.00% +cbor_add_bool 14 0 100.00% 21 0 100.00% +cbor_flatten_vector 14 1 92.86% 16 1 93.75% +cbor_build_frame 15 0 100.00% 25 0 100.00% +cbor_encode_rp_entity 13 0 100.00% 11 0 100.00% +cbor_encode_user_entity 21 0 100.00% 15 0 100.00% +cbor_encode_pubkey_param 36 0 100.00% 39 0 100.00% +cbor_encode_pubkey 10 0 100.00% 11 0 100.00% +cbor_encode_pubkey_list 18 0 100.00% 19 0 100.00% +cbor_encode_str_array 18 0 100.00% 19 0 100.00% +cbor_encode_cred_ext 55 0 100.00% 50 0 100.00% +cbor_encode_cred_opt 13 0 100.00% 11 0 100.00% +cbor_encode_assert_opt 13 0 100.00% 11 0 100.00% +cbor_encode_pin_auth 21 1 95.24% 22 3 86.36% +cbor_encode_pin_opt 4 0 100.00% 8 0 100.00% +cbor_encode_change_pin_auth 32 1 96.88% 36 3 91.67% +cbor_encode_assert_ext 33 0 100.00% 32 0 100.00% +cbor_decode_fmt 13 0 100.00% 15 0 100.00% +cbor_decode_pubkey 26 1 96.15% 36 2 94.44% +cbor_decode_cred_authdata 31 1 96.77% 35 3 91.43% +cbor_decode_assert_authdata 21 1 95.24% 32 3 90.62% +cbor_decode_attstmt 13 0 100.00% 16 0 100.00% +cbor_decode_uint64 4 0 100.00% 8 0 100.00% +cbor_decode_cred_id 8 0 100.00% 9 0 100.00% +cbor_decode_user 8 0 100.00% 9 0 100.00% +cbor_decode_rp_entity 8 0 100.00% 9 0 100.00% +cbor_decode_bool 10 0 100.00% 11 0 100.00% +cbor_build_uint 10 1 90.00% 9 1 88.89% +cbor_array_append 17 0 100.00% 21 0 100.00% +cbor_array_drop 18 0 100.00% 17 0 100.00% +cbor.c:ctap_check_cbor 28 0 100.00% 26 0 100.00% +cbor.c:check_key_type 8 0 100.00% 7 0 100.00% +cbor.c:cbor_add_arg 13 0 100.00% 21 0 100.00% +cbor.c:cbor_add_uint8 14 0 100.00% 21 0 100.00% +cbor.c:cbor_encode_largeblob_key_ext 6 0 100.00% 6 0 100.00% +cbor.c:cbor_encode_hmac_secret_param 59 4 93.22% 66 8 87.88% +cbor.c:get_cose_alg 46 0 100.00% 45 0 100.00% +cbor.c:find_cose_alg 35 0 100.00% 33 0 100.00% +cbor.c:decode_attcred 25 0 100.00% 44 0 100.00% +cbor.c:decode_cred_extensions 14 0 100.00% 24 0 100.00% +cbor.c:decode_cred_extension 41 0 100.00% 45 0 100.00% +cbor.c:decode_assert_extensions 14 0 100.00% 23 0 100.00% +cbor.c:decode_assert_extension 19 0 100.00% 27 0 100.00% +cbor.c:decode_attstmt_entry 56 0 100.00% 51 0 100.00% +cbor.c:decode_x5c 4 0 100.00% 6 0 100.00% +cbor.c:decode_cred_id_entry 10 0 100.00% 19 0 100.00% +cbor.c:decode_user_entry 25 0 100.00% 35 0 100.00% +cbor.c:decode_rp_entity_entry 15 0 100.00% 25 0 100.00% +------------------------------------------------------------------------------------------------------------------ +TOTAL 1070 12 98.88% 1258 28 97.77% + +File '/libfido2/src/compress.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------ +fido_compress 1 0 100.00% 3 0 100.00% +fido_uncompress 6 0 100.00% 5 0 100.00% +compress.c:rfc1951_deflate 33 4 87.88% 47 6 87.23% +compress.c:rfc1950_inflate 27 2 92.59% 22 4 81.82% +compress.c:rfc1951_inflate 38 8 78.95% 45 14 68.89% +------------------------------------------------------------------------------------------------------------------ +TOTAL 105 14 86.67% 122 24 80.33% + +File '/libfido2/src/config.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_dev_enable_entattest 1 0 100.00% 4 0 100.00% +fido_dev_toggle_always_uv 1 0 100.00% 4 0 100.00% +fido_dev_set_pin_minlen 1 0 100.00% 4 0 100.00% +fido_dev_force_pin_change 1 0 100.00% 4 0 100.00% +fido_dev_set_pin_minlen_rpid 6 0 100.00% 15 0 100.00% +config.c:config_enable_entattest_wait 6 0 100.00% 7 0 100.00% +config.c:config_tx 39 0 100.00% 49 0 100.00% +config.c:config_prepare_hmac 10 0 100.00% 21 0 100.00% +config.c:config_toggle_always_uv_wait 6 0 100.00% 7 0 100.00% +config.c:config_pin_minlen 5 0 100.00% 7 0 100.00% +config.c:config_pin_minlen_tx 36 0 100.00% 32 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 112 0 100.00% 154 0 100.00% + +File '/libfido2/src/cred.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_dev_make_cred 12 0 100.00% 10 0 100.00% +fido_check_rp_id 4 0 100.00% 11 0 100.00% +fido_cred_verify 59 2 96.61% 75 4 94.67% +fido_cred_verify_self 60 4 93.33% 87 7 91.95% +fido_cred_new 1 0 100.00% 3 0 100.00% +fido_cred_reset_tx 1 0 100.00% 18 0 100.00% +fido_cred_reset_rx 1 0 100.00% 7 0 100.00% +fido_cred_free 6 0 100.00% 9 0 100.00% +fido_cred_set_authdata 23 0 100.00% 28 0 100.00% +fido_cred_set_authdata_raw 25 0 100.00% 29 0 100.00% +fido_cred_set_id 6 0 100.00% 5 0 100.00% +fido_cred_set_x509 6 0 100.00% 5 0 100.00% +fido_cred_set_sig 6 0 100.00% 5 0 100.00% +fido_cred_set_attstmt 20 0 100.00% 23 0 100.00% +fido_cred_exclude 14 2 85.71% 19 3 84.21% +fido_cred_empty_exclude_list 2 0 100.00% 5 0 100.00% +fido_cred_set_clientdata 12 12 0.00% 11 11 0.00% +fido_cred_set_clientdata_hash 8 0 100.00% 6 0 100.00% +fido_cred_set_rp 18 0 100.00% 22 0 100.00% +fido_cred_set_user 32 0 100.00% 41 0 100.00% +fido_cred_set_extensions 16 0 100.00% 10 0 100.00% +fido_cred_set_options 8 8 0.00% 5 5 0.00% +fido_cred_set_rk 2 0 100.00% 4 0 100.00% +fido_cred_set_uv 2 0 100.00% 4 0 100.00% +fido_cred_set_prot 21 0 100.00% 14 0 100.00% +fido_cred_set_pin_minlen 7 0 100.00% 8 0 100.00% +fido_cred_set_blob 13 0 100.00% 8 0 100.00% +fido_cred_set_fmt 20 4 80.00% 12 2 83.33% +fido_cred_set_type 23 2 91.30% 9 1 88.89% +fido_cred_type 1 0 100.00% 3 0 100.00% +fido_cred_flags 1 0 100.00% 3 0 100.00% +fido_cred_sigcount 1 0 100.00% 3 0 100.00% +fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% +fido_cred_clientdata_hash_len 1 0 100.00% 3 0 100.00% +fido_cred_x5c_ptr 1 0 100.00% 3 0 100.00% +fido_cred_x5c_len 1 0 100.00% 3 0 100.00% +fido_cred_sig_ptr 1 0 100.00% 3 0 100.00% +fido_cred_sig_len 1 0 100.00% 3 0 100.00% +fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% +fido_cred_authdata_len 1 0 100.00% 3 0 100.00% +fido_cred_authdata_raw_ptr 1 0 100.00% 3 0 100.00% +fido_cred_authdata_raw_len 1 0 100.00% 3 0 100.00% +fido_cred_attstmt_ptr 1 0 100.00% 3 0 100.00% +fido_cred_attstmt_len 1 0 100.00% 3 0 100.00% +fido_cred_pubkey_ptr 11 0 100.00% 21 0 100.00% +fido_cred_pubkey_len 11 0 100.00% 21 0 100.00% +fido_cred_id_ptr 1 0 100.00% 3 0 100.00% +fido_cred_id_len 1 0 100.00% 3 0 100.00% +fido_cred_aaguid_ptr 1 0 100.00% 3 0 100.00% +fido_cred_aaguid_len 1 0 100.00% 3 0 100.00% +fido_cred_prot 1 0 100.00% 3 0 100.00% +fido_cred_pin_minlen 1 0 100.00% 3 0 100.00% +fido_cred_fmt 1 0 100.00% 3 0 100.00% +fido_cred_rp_id 1 0 100.00% 3 0 100.00% +fido_cred_rp_name 1 0 100.00% 3 0 100.00% +fido_cred_user_name 1 0 100.00% 3 0 100.00% +fido_cred_display_name 1 0 100.00% 3 0 100.00% +fido_cred_user_id_ptr 1 0 100.00% 3 0 100.00% +fido_cred_user_id_len 1 0 100.00% 3 0 100.00% +fido_cred_largeblob_key_ptr 1 0 100.00% 3 0 100.00% +fido_cred_largeblob_key_len 1 0 100.00% 3 0 100.00% +cred.c:fido_dev_make_cred_wait 10 0 100.00% 7 0 100.00% +cred.c:fido_dev_make_cred_tx 64 0 100.00% 70 0 100.00% +cred.c:fido_dev_make_cred_rx 29 0 100.00% 32 0 100.00% +cred.c:parse_makecred_reply 14 0 100.00% 27 0 100.00% +cred.c:check_extensions 2 0 100.00% 6 0 100.00% +cred.c:get_signed_hash_u2f 27 0 100.00% 27 0 100.00% +cred.c:verify_attstmt 25 2 92.00% 43 6 86.05% +cred.c:fido_cred_clean_authdata 1 0 100.00% 8 0 100.00% +cred.c:fido_cred_clean_attstmt 1 0 100.00% 8 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 653 36 94.49% 853 39 95.43% + +File '/libfido2/src/credman.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_credman_get_dev_metadata 1 0 100.00% 4 0 100.00% +fido_credman_get_dev_rk 1 0 100.00% 4 0 100.00% +fido_credman_del_dev_rk 1 0 100.00% 4 0 100.00% +fido_credman_get_dev_rp 1 0 100.00% 4 0 100.00% +fido_credman_set_dev_rk 1 0 100.00% 4 0 100.00% +fido_credman_rk_new 1 0 100.00% 3 0 100.00% +fido_credman_rk_free 6 1 83.33% 8 1 87.50% +fido_credman_rk_count 1 0 100.00% 3 0 100.00% +fido_credman_rk 4 0 100.00% 5 0 100.00% +fido_credman_metadata_new 1 0 100.00% 3 0 100.00% +fido_credman_metadata_free 6 1 83.33% 7 1 85.71% +fido_credman_rk_existing 1 0 100.00% 3 0 100.00% +fido_credman_rk_remaining 1 0 100.00% 3 0 100.00% +fido_credman_rp_new 1 0 100.00% 3 0 100.00% +fido_credman_rp_free 6 1 83.33% 8 1 87.50% +fido_credman_rp_count 1 0 100.00% 3 0 100.00% +fido_credman_rp_id 4 0 100.00% 5 0 100.00% +fido_credman_rp_name 4 0 100.00% 5 0 100.00% +fido_credman_rp_id_hash_len 4 0 100.00% 5 0 100.00% +fido_credman_rp_id_hash_ptr 4 0 100.00% 5 0 100.00% +credman.c:credman_get_metadata_wait 11 0 100.00% 8 0 100.00% +credman.c:credman_tx 35 0 100.00% 50 0 100.00% +credman.c:credman_get_cmd 7 0 100.00% 5 0 100.00% +credman.c:credman_prepare_hmac 31 1 96.77% 50 2 96.00% +credman.c:credman_rx_metadata 19 0 100.00% 24 0 100.00% +credman.c:credman_parse_metadata 9 0 100.00% 17 0 100.00% +credman.c:credman_get_rk_wait 27 0 100.00% 23 0 100.00% +credman.c:credman_rx_rk 27 0 100.00% 35 0 100.00% +credman.c:credman_parse_rk_count 16 0 100.00% 20 0 100.00% +credman.c:credman_grow_array 17 2 88.24% 21 5 76.19% +credman.c:credman_parse_rk 23 0 100.00% 31 0 100.00% +credman.c:credman_rx_next_rk 23 2 91.30% 29 5 82.76% +credman.c:credman_del_rk_wait 16 0 100.00% 15 0 100.00% +credman.c:credman_get_rp_wait 23 0 100.00% 15 0 100.00% +credman.c:credman_rx_rp 27 0 100.00% 35 0 100.00% +credman.c:credman_parse_rp_count 16 0 100.00% 20 0 100.00% +credman.c:credman_parse_rp 9 0 100.00% 17 0 100.00% +credman.c:credman_rx_next_rp 23 2 91.30% 29 5 82.76% +credman.c:credman_set_dev_rk_wait 11 0 100.00% 8 0 100.00% +credman.c:credman_reset_rk 4 0 100.00% 9 0 100.00% +credman.c:credman_reset_rp 4 0 100.00% 12 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 428 10 97.66% 562 20 96.44% + +File '/libfido2/src/dev.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_dev_info_manifest 2 0 100.00% 11 0 100.00% +fido_dev_open_with_info 5 5 0.00% 6 6 0.00% +fido_dev_open 13 4 69.23% 16 6 62.50% +fido_dev_close 9 2 77.78% 8 1 87.50% +fido_dev_set_sigmask 18 18 0.00% 11 11 0.00% +fido_dev_cancel 11 0 100.00% 8 0 100.00% +fido_dev_set_io_functions 18 4 77.78% 14 6 57.14% +fido_dev_set_transport_functions 6 2 66.67% 9 3 66.67% +fido_dev_io_handle 1 1 0.00% 3 3 0.00% +fido_init 8 1 87.50% 5 0 100.00% +fido_dev_new 5 0 100.00% 14 0 100.00% +fido_dev_new_with_info 10 10 0.00% 16 16 0.00% +fido_dev_free 6 0 100.00% 8 0 100.00% +fido_dev_protocol 1 0 100.00% 3 0 100.00% +fido_dev_major 1 0 100.00% 3 0 100.00% +fido_dev_minor 1 0 100.00% 3 0 100.00% +fido_dev_build 1 0 100.00% 3 0 100.00% +fido_dev_flags 1 0 100.00% 3 0 100.00% +fido_dev_is_fido2 2 0 100.00% 3 0 100.00% +fido_dev_is_winhello 2 2 0.00% 3 3 0.00% +fido_dev_supports_pin 3 0 100.00% 3 0 100.00% +fido_dev_has_pin 2 0 100.00% 3 0 100.00% +fido_dev_supports_cred_prot 2 0 100.00% 3 0 100.00% +fido_dev_supports_credman 3 0 100.00% 3 0 100.00% +fido_dev_supports_uv 3 0 100.00% 3 0 100.00% +fido_dev_has_uv 2 0 100.00% 3 0 100.00% +fido_dev_supports_permissions 2 0 100.00% 3 0 100.00% +fido_dev_force_u2f 2 0 100.00% 4 0 100.00% +fido_dev_force_fido2 2 2 0.00% 3 3 0.00% +fido_dev_get_pin_protocol 11 0 100.00% 7 0 100.00% +fido_dev_maxmsgsize 1 0 100.00% 3 0 100.00% +fido_dev_set_timeout 6 2 66.67% 6 1 83.33% +dev.c:run_manifest 10 0 100.00% 13 0 100.00% +dev.c:fido_dev_open_wait 10 0 100.00% 7 0 100.00% +dev.c:fido_dev_open_tx 56 11 80.36% 56 20 64.29% +dev.c:set_random_report_len 11 0 100.00% 6 0 100.00% +dev.c:fido_dev_open_rx 36 1 97.22% 53 1 98.11% +dev.c:fido_dev_set_flags 1 0 100.00% 5 0 100.00% +dev.c:fido_dev_set_extension_flags 7 0 100.00% 7 0 100.00% +dev.c:fido_dev_set_option_flags 42 0 100.00% 25 0 100.00% +dev.c:fido_dev_set_protocol_flags 11 0 100.00% 17 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 344 65 81.10% 383 80 79.11% + +File '/libfido2/src/ecdh.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_do_ecdh 29 0 100.00% 36 0 100.00% +ecdh.c:do_ecdh 37 0 100.00% 44 0 100.00% +ecdh.c:kdf 19 1 94.74% 28 2 92.86% +ecdh.c:hkdf_sha256 32 1 96.88% 38 3 92.11% +------------------------------------------------------------------------------------------------------------------- +TOTAL 117 2 98.29% 146 5 96.58% + +File '/libfido2/src/eddsa.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +eddsa_pk_decode 8 0 100.00% 9 0 100.00% +eddsa_pk_new 1 0 100.00% 3 0 100.00% +eddsa_pk_free 6 0 100.00% 7 0 100.00% +eddsa_pk_from_ptr 10 0 100.00% 12 0 100.00% +eddsa_pk_to_EVP_PKEY 3 0 100.00% 7 0 100.00% +eddsa_pk_from_EVP_PKEY 18 2 88.89% 12 1 91.67% +eddsa_verify_sig 19 2 89.47% 30 6 80.00% +eddsa_pk_verify_sig 7 1 85.71% 13 2 84.62% +eddsa.c:decode_pubkey_point 8 0 100.00% 11 0 100.00% +eddsa.c:decode_coord 8 0 100.00% 10 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 88 5 94.32% 114 9 92.11% + +File '/libfido2/src/err.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_strerr 122 10 91.80% 126 10 92.06% +------------------------------------------------------------------------------------------------------------------- +TOTAL 122 10 91.80% 126 10 92.06% + +File '/libfido2/src/es256.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +es256_pk_decode 8 0 100.00% 9 0 100.00% +es256_pk_encode 56 0 100.00% 48 0 100.00% +es256_sk_new 1 0 100.00% 3 0 100.00% +es256_sk_free 6 0 100.00% 7 0 100.00% +es256_pk_new 1 0 100.00% 3 0 100.00% +es256_pk_free 6 0 100.00% 7 0 100.00% +es256_pk_from_ptr 15 0 100.00% 17 0 100.00% +es256_pk_set_x 1 0 100.00% 4 0 100.00% +es256_pk_set_y 1 0 100.00% 4 0 100.00% +es256_sk_create 39 0 100.00% 40 0 100.00% +es256_pk_to_EVP_PKEY 42 0 100.00% 53 0 100.00% +es256_pk_from_EC_KEY 42 2 95.24% 47 4 91.49% +es256_pk_from_EVP_PKEY 8 0 100.00% 7 0 100.00% +es256_sk_to_EVP_PKEY 28 0 100.00% 39 0 100.00% +es256_derive_pk 25 0 100.00% 29 0 100.00% +es256_verify_sig 12 2 83.33% 19 5 73.68% +es256_pk_verify_sig 7 1 85.71% 13 2 84.62% +es256.c:decode_pubkey_point 9 0 100.00% 13 0 100.00% +es256.c:decode_coord 8 0 100.00% 10 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 315 5 98.41% 372 11 97.04% + +File '/libfido2/src/es384.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +es384_pk_decode 8 0 100.00% 9 0 100.00% +es384_pk_new 1 0 100.00% 3 0 100.00% +es384_pk_free 6 0 100.00% 7 0 100.00% +es384_pk_from_ptr 15 0 100.00% 17 0 100.00% +es384_pk_to_EVP_PKEY 42 0 100.00% 53 0 100.00% +es384_pk_from_EC_KEY 42 2 95.24% 47 4 91.49% +es384_pk_from_EVP_PKEY 8 0 100.00% 7 0 100.00% +es384_verify_sig 12 2 83.33% 19 5 73.68% +es384_pk_verify_sig 7 1 85.71% 13 2 84.62% +es384.c:decode_pubkey_point 9 0 100.00% 13 0 100.00% +es384.c:decode_coord 8 0 100.00% 10 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 158 5 96.84% 198 11 94.44% + +File '/libfido2/src/extern.h': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- + +File '/libfido2/src/fallthrough.h': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- + +File '/libfido2/src/fido.h': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- + +File '/libfido2/src/hid.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_hid_get_usage 13 0 100.00% 22 0 100.00% +fido_hid_get_report_len 19 0 100.00% 27 0 100.00% +fido_dev_info_new 1 0 100.00% 3 0 100.00% +fido_dev_info_free 9 0 100.00% 9 0 100.00% +fido_dev_info_ptr 1 0 100.00% 3 0 100.00% +fido_dev_info_set 26 2 92.31% 30 3 90.00% +fido_dev_info_path 1 0 100.00% 3 0 100.00% +fido_dev_info_vendor 1 0 100.00% 3 0 100.00% +fido_dev_info_product 1 0 100.00% 3 0 100.00% +fido_dev_info_manufacturer_string 1 0 100.00% 3 0 100.00% +fido_dev_info_product_string 1 0 100.00% 3 0 100.00% +hid.c:get_key_len 6 0 100.00% 12 0 100.00% +hid.c:get_key_val 6 0 100.00% 18 0 100.00% +hid.c:fido_dev_info_reset 1 0 100.00% 6 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 87 2 97.70% 145 3 97.93% + +File '/libfido2/src/hid_linux.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_hid_manifest 35 4 88.57% 41 2 95.12% +fido_hid_open 33 33 0.00% 51 51 0.00% +fido_hid_close 3 3 0.00% 6 6 0.00% +fido_hid_set_sigmask 2 2 0.00% 6 6 0.00% +fido_hid_read 15 15 0.00% 21 21 0.00% +fido_hid_write 12 12 0.00% 17 17 0.00% +fido_hid_report_in_len 1 1 0.00% 4 4 0.00% +fido_hid_report_out_len 1 1 0.00% 4 4 0.00% +hid_linux.c:copy_info 38 0 100.00% 53 0 100.00% +hid_linux.c:is_fido 15 1 93.33% 16 1 93.75% +hid_linux.c:get_parent_attr 6 0 100.00% 9 0 100.00% +hid_linux.c:parse_uevent 26 0 100.00% 29 0 100.00% +hid_linux.c:get_usb_attr 1 0 100.00% 3 0 100.00% +hid_linux.c:get_report_descriptor 14 1 92.86% 17 3 82.35% +------------------------------------------------------------------------------------------------------------------- +TOTAL 202 73 63.86% 277 115 58.48% + +File '/libfido2/src/hid_unix.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_hid_unix_open 18 11 38.89% 22 14 36.36% +fido_hid_unix_wait 11 10 9.09% 21 12 42.86% +------------------------------------------------------------------------------------------------------------------- +TOTAL 29 21 27.59% 43 26 39.53% + +File '/libfido2/src/info.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_dev_get_cbor_info_wait 10 0 100.00% 7 0 100.00% +fido_dev_get_cbor_info 1 0 100.00% 4 0 100.00% +fido_cbor_info_new 4 0 100.00% 7 0 100.00% +fido_cbor_info_reset 1 0 100.00% 10 0 100.00% +fido_cbor_info_free 6 0 100.00% 8 0 100.00% +fido_cbor_info_versions_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_versions_len 1 0 100.00% 3 0 100.00% +fido_cbor_info_extensions_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_extensions_len 1 0 100.00% 3 0 100.00% +fido_cbor_info_transports_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_transports_len 1 0 100.00% 3 0 100.00% +fido_cbor_info_aaguid_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_aaguid_len 1 0 100.00% 3 0 100.00% +fido_cbor_info_options_name_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% +fido_cbor_info_maxcredbloblen 1 0 100.00% 3 0 100.00% +fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% +fido_cbor_info_maxcredcntlst 1 0 100.00% 3 0 100.00% +fido_cbor_info_maxcredidlen 1 0 100.00% 3 0 100.00% +fido_cbor_info_maxlargeblob 1 0 100.00% 3 0 100.00% +fido_cbor_info_fwversion 1 0 100.00% 3 0 100.00% +fido_cbor_info_minpinlen 1 0 100.00% 3 0 100.00% +fido_cbor_info_maxrpid_minpinlen 1 0 100.00% 3 0 100.00% +fido_cbor_info_uv_attempts 1 0 100.00% 3 0 100.00% +fido_cbor_info_uv_modality 1 0 100.00% 3 0 100.00% +fido_cbor_info_rk_remaining 1 0 100.00% 3 0 100.00% +fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% +fido_cbor_info_algorithm_count 1 0 100.00% 3 0 100.00% +fido_cbor_info_algorithm_type 4 0 100.00% 5 0 100.00% +fido_cbor_info_algorithm_cose 4 0 100.00% 5 0 100.00% +fido_cbor_info_new_pin_required 1 0 100.00% 3 0 100.00% +fido_cbor_info_certs_name_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_certs_value_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_certs_len 1 0 100.00% 3 0 100.00% +info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 9 0 100.00% +info.c:fido_dev_get_cbor_info_rx 14 0 100.00% 21 0 100.00% +info.c:parse_reply_element 32 0 100.00% 59 0 100.00% +info.c:decode_string_array 12 0 100.00% 17 0 100.00% +info.c:decode_string 4 0 100.00% 10 0 100.00% +info.c:decode_aaguid 8 0 100.00% 10 0 100.00% +info.c:decode_options 11 0 100.00% 15 0 100.00% +info.c:decode_option 7 0 100.00% 15 0 100.00% +info.c:decode_protocols 12 0 100.00% 17 0 100.00% +info.c:decode_protocol 6 0 100.00% 12 0 100.00% +info.c:decode_algorithms 12 0 100.00% 17 0 100.00% +info.c:decode_algorithm 9 0 100.00% 17 0 100.00% +info.c:decode_algorithm_entry 20 0 100.00% 27 0 100.00% +info.c:decode_certs 11 0 100.00% 15 0 100.00% +info.c:decode_cert 7 0 100.00% 15 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 232 0 100.00% 409 0 100.00% + +File '/libfido2/src/io.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_tx 14 0 100.00% 11 0 100.00% +fido_rx 13 1 92.31% 14 3 78.57% +fido_rx_cbor_status 16 0 100.00% 19 0 100.00% +io.c:transport_tx 7 0 100.00% 10 0 100.00% +io.c:tx_empty 9 0 100.00% 14 0 100.00% +io.c:tx_pkt 7 0 100.00% 10 0 100.00% +io.c:tx 13 0 100.00% 19 0 100.00% +io.c:tx_preamble 17 1 94.12% 20 1 95.00% +io.c:tx_frame 16 1 93.75% 18 1 94.44% +io.c:transport_rx 7 0 100.00% 10 0 100.00% +io.c:rx 40 2 95.00% 52 2 96.15% +io.c:rx_preamble 23 2 91.30% 22 5 77.27% +io.c:rx_frame 11 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 193 7 96.37% 230 12 94.78% + +File '/libfido2/src/iso7816.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +iso7816_new 4 0 100.00% 16 0 100.00% +iso7816_free 6 0 100.00% 7 0 100.00% +iso7816_add 6 1 83.33% 8 1 87.50% +iso7816_ptr 1 0 100.00% 3 0 100.00% +iso7816_len 1 0 100.00% 4 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 18 1 94.44% 38 1 97.37% + +File '/libfido2/src/largeblob.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_dev_largeblob_get 26 2 92.31% 38 4 89.47% +fido_dev_largeblob_set 27 0 100.00% 36 0 100.00% +fido_dev_largeblob_remove 12 0 100.00% 18 0 100.00% +fido_dev_largeblob_get_array 15 2 86.67% 27 4 85.19% +fido_dev_largeblob_set_array 14 0 100.00% 19 0 100.00% +largeblob.c:largeblob_get_array 32 0 100.00% 36 0 100.00% +largeblob.c:get_chunklen 10 1 90.00% 9 1 88.89% +largeblob.c:largeblob_get_tx 19 0 100.00% 24 0 100.00% +largeblob.c:largeblob_get_rx 26 0 100.00% 30 0 100.00% +largeblob.c:parse_largeblob_reply 8 0 100.00% 9 0 100.00% +largeblob.c:largeblob_array_check 7 0 100.00% 16 0 100.00% +largeblob.c:largeblob_array_digest 10 0 100.00% 9 0 100.00% +largeblob.c:largeblob_array_load 14 2 85.71% 19 7 63.16% +largeblob.c:largeblob_array_lookup 25 0 100.00% 33 0 100.00% +largeblob.c:largeblob_decode 16 2 87.50% 16 6 62.50% +largeblob.c:largeblob_do_decode 27 3 88.89% 30 7 76.67% +largeblob.c:largeblob_decrypt 15 0 100.00% 24 0 100.00% +largeblob.c:largeblob_aad 1 0 100.00% 10 0 100.00% +largeblob.c:largeblob_reset 1 0 100.00% 5 0 100.00% +largeblob.c:largeblob_encode 16 0 100.00% 21 0 100.00% +largeblob.c:largeblob_new 1 0 100.00% 3 0 100.00% +largeblob.c:largeblob_seal 20 0 100.00% 32 0 100.00% +largeblob.c:largeblob_get_nonce 8 0 100.00% 16 0 100.00% +largeblob.c:largeblob_free 6 0 100.00% 8 0 100.00% +largeblob.c:largeblob_add 27 2 92.59% 35 3 91.43% +largeblob.c:largeblob_drop 21 0 100.00% 27 0 100.00% +largeblob.c:largeblob_set_array 54 2 96.30% 61 4 93.44% +largeblob.c:largeblob_get_uv_token 19 0 100.00% 23 0 100.00% +largeblob.c:largeblob_set_tx 35 0 100.00% 36 0 100.00% +largeblob.c:prepare_hmac 13 2 84.62% 23 7 69.57% +------------------------------------------------------------------------------------------------------------------- +TOTAL 525 18 96.57% 693 43 93.80% + +File '/libfido2/src/log.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_log_init 1 0 100.00% 4 0 100.00% +fido_log_debug 6 1 83.33% 8 1 87.50% +fido_log_xxd 16 1 93.75% 24 1 95.83% +fido_log_error 8 2 75.00% 11 2 81.82% +fido_set_log_handler 3 0 100.00% 4 0 100.00% +log.c:log_on_stderr 1 1 0.00% 3 3 0.00% +log.c:do_log 4 0 100.00% 9 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 39 5 87.18% 63 7 88.89% + +File '/libfido2/src/netlink.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_nl_power_nfc 18 0 100.00% 24 0 100.00% +fido_nl_get_nfc_target 17 0 100.00% 31 0 100.00% +fido_nl_free 10 2 80.00% 9 2 77.78% +fido_nl_new 16 1 93.75% 26 3 88.46% +set_netlink_io_functions 1 0 100.00% 4 0 100.00% +netlink.c:nlmsg_new 8 0 100.00% 15 0 100.00% +netlink.c:nlmsg_set_genl 1 0 100.00% 7 0 100.00% +netlink.c:nlmsg_write 6 1 83.33% 7 1 85.71% +netlink.c:nlmsg_set_u32 1 0 100.00% 3 0 100.00% +netlink.c:nlmsg_setattr 15 1 93.33% 17 0 100.00% +netlink.c:nlmsg_tx 10 1 90.00% 13 3 76.92% +netlink.c:nlmsg_ptr 1 0 100.00% 3 0 100.00% +netlink.c:nlmsg_len 1 0 100.00% 3 0 100.00% +netlink.c:nlmsg_rx 11 2 81.82% 17 6 64.71% +netlink.c:nl_parse_reply 20 0 100.00% 28 0 100.00% +netlink.c:nlmsg_from_buf 15 0 100.00% 17 0 100.00% +netlink.c:nlmsg_type 1 0 100.00% 3 0 100.00% +netlink.c:nlmsg_get_status 8 0 100.00% 8 0 100.00% +netlink.c:nlmsg_read 6 0 100.00% 7 0 100.00% +netlink.c:nlmsg_get_genl 6 0 100.00% 7 0 100.00% +netlink.c:nlmsg_iter 6 0 100.00% 13 0 100.00% +netlink.c:nlmsg_getattr 1 0 100.00% 3 0 100.00% +netlink.c:nla_from_buf 17 0 100.00% 21 0 100.00% +netlink.c:nl_nfc_poll 18 0 100.00% 25 0 100.00% +netlink.c:parse_nfc_event 10 0 100.00% 17 0 100.00% +netlink.c:nla_type 1 0 100.00% 3 0 100.00% +netlink.c:nla_get_u32 1 0 100.00% 3 0 100.00% +netlink.c:nla_read 6 0 100.00% 7 0 100.00% +netlink.c:nl_dump_nfc_target 19 0 100.00% 31 0 100.00% +netlink.c:parse_target 9 0 100.00% 13 0 100.00% +netlink.c:nl_get_nfc_family 23 0 100.00% 33 0 100.00% +netlink.c:nlmsg_set_u16 1 0 100.00% 3 0 100.00% +netlink.c:nlmsg_set_str 1 0 100.00% 3 0 100.00% +netlink.c:parse_family 10 0 100.00% 17 0 100.00% +netlink.c:nla_get_u16 1 0 100.00% 3 0 100.00% +netlink.c:nla_iter 6 0 100.00% 13 0 100.00% +netlink.c:nla_getattr 1 0 100.00% 3 0 100.00% +netlink.c:parse_mcastgrps 1 0 100.00% 3 0 100.00% +netlink.c:parse_mcastgrp 15 0 100.00% 24 0 100.00% +netlink.c:nla_get_str 10 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 329 8 97.57% 498 15 96.99% + +File '/libfido2/src/nfc.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_nfc_tx 28 0 100.00% 43 0 100.00% +fido_nfc_rx 8 0 100.00% 13 0 100.00% +nfc_is_fido 13 1 92.31% 21 3 85.71% +fido_is_nfc 3 0 100.00% 3 0 100.00% +fido_dev_set_nfc 4 1 75.00% 18 3 83.33% +nfc.c:nfc_do_tx 20 0 100.00% 25 0 100.00% +nfc.c:tx_short_apdu 14 0 100.00% 32 0 100.00% +nfc.c:rx_init 25 0 100.00% 27 0 100.00% +nfc.c:rx_cbor 4 0 100.00% 6 0 100.00% +nfc.c:rx_msg 18 1 94.44% 23 3 86.96% +nfc.c:rx_apdu 14 0 100.00% 22 0 100.00% +nfc.c:tx_get_response 4 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 155 3 98.06% 244 9 96.31% + +File '/libfido2/src/nfc_linux.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_nfc_manifest 35 7 80.00% 45 15 66.67% +fido_nfc_open 20 2 90.00% 23 4 82.61% +fido_nfc_close 1 1 0.00% 4 4 0.00% +fido_nfc_set_sigmask 2 2 0.00% 6 6 0.00% +fido_nfc_read 14 14 0.00% 30 30 0.00% +fido_nfc_write 12 12 0.00% 18 18 0.00% +nfc_linux.c:copy_info 39 22 43.59% 44 16 63.64% +nfc_linux.c:get_usb_attr 1 1 0.00% 3 3 0.00% +nfc_linux.c:get_parent_attr 6 6 0.00% 9 9 0.00% +nfc_linux.c:sysnum_from_syspath 15 0 100.00% 17 0 100.00% +nfc_linux.c:nfc_new 6 0 100.00% 11 0 100.00% +nfc_linux.c:nfc_target_connect 9 6 33.33% 21 9 57.14% +nfc_linux.c:nfc_free 12 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 172 73 57.56% 242 114 52.89% + +File '/libfido2/src/pcsc.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_pcsc_manifest 51 0 100.00% 55 0 100.00% +fido_pcsc_open 32 0 100.00% 43 0 100.00% +fido_pcsc_close 6 0 100.00% 9 0 100.00% +fido_pcsc_read 8 0 100.00% 16 0 100.00% +fido_pcsc_write 8 0 100.00% 22 0 100.00% +fido_pcsc_tx 1 0 100.00% 3 0 100.00% +fido_pcsc_rx 1 0 100.00% 3 0 100.00% +fido_is_pcsc 3 0 100.00% 3 0 100.00% +fido_dev_set_pcsc 4 1 75.00% 18 3 83.33% +pcsc.c:list_readers 24 0 100.00% 24 0 100.00% +pcsc.c:copy_info 30 0 100.00% 41 0 100.00% +pcsc.c:get_reader 25 0 100.00% 28 0 100.00% +pcsc.c:prepare_io_request 11 0 100.00% 17 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 204 1 99.51% 282 3 98.94% + +File '/libfido2/src/pin.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_sha256 7 0 100.00% 10 0 100.00% +fido_dev_get_uv_token 1 0 100.00% 3 0 100.00% +fido_dev_set_pin 1 0 100.00% 4 0 100.00% +fido_dev_get_retry_count 1 0 100.00% 4 0 100.00% +fido_dev_get_uv_retry_count 1 0 100.00% 4 0 100.00% +cbor_add_uv_params 17 0 100.00% 23 0 100.00% +pin.c:uv_token_wait 14 2 85.71% 12 1 91.67% +pin.c:ctap21_uv_token_tx 49 0 100.00% 53 0 100.00% +pin.c:pin_sha256_enc 19 0 100.00% 24 0 100.00% +pin.c:encode_uv_permission 24 1 95.83% 21 3 85.71% +pin.c:ctap20_uv_token_tx 37 0 100.00% 45 0 100.00% +pin.c:uv_token_rx 27 0 100.00% 34 0 100.00% +pin.c:parse_uv_token 8 0 100.00% 10 0 100.00% +pin.c:fido_dev_set_pin_wait 21 0 100.00% 24 0 100.00% +pin.c:fido_dev_change_pin_tx 45 0 100.00% 56 0 100.00% +pin.c:pin_pad64_enc 15 0 100.00% 21 0 100.00% +pin.c:pad64 18 0 100.00% 20 0 100.00% +pin.c:fido_dev_set_pin_tx 33 0 100.00% 41 0 100.00% +pin.c:fido_dev_get_pin_retry_count_wait 10 0 100.00% 7 0 100.00% +pin.c:fido_dev_get_retry_count_tx 19 0 100.00% 23 0 100.00% +pin.c:fido_dev_get_pin_retry_count_rx 19 0 100.00% 24 0 100.00% +pin.c:parse_pin_retry_count 1 0 100.00% 3 0 100.00% +pin.c:parse_retry_count 13 0 100.00% 16 0 100.00% +pin.c:fido_dev_get_uv_retry_count_wait 10 0 100.00% 7 0 100.00% +pin.c:fido_dev_get_uv_retry_count_rx 19 0 100.00% 24 0 100.00% +pin.c:parse_uv_retry_count 1 0 100.00% 3 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 430 3 99.30% 516 4 99.22% + +File '/libfido2/src/random.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_get_random 6 0 100.00% 6 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 6 0 100.00% 6 0 100.00% + +File '/libfido2/src/reset.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_dev_reset 1 0 100.00% 4 0 100.00% +reset.c:fido_dev_reset_wait 15 0 100.00% 11 0 100.00% +reset.c:fido_dev_reset_tx 8 0 100.00% 8 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 24 0 100.00% 23 0 100.00% + +File '/libfido2/src/rs1.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +rs1_verify_sig 20 2 90.00% 30 6 80.00% +rs1.c:rs1_get_EVP_MD 1 0 100.00% 3 0 100.00% +rs1.c:rs1_free_EVP_MD 1 0 100.00% 3 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 22 2 90.91% 36 6 83.33% + +File '/libfido2/src/rs256.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +rs256_pk_decode 8 0 100.00% 9 0 100.00% +rs256_pk_new 1 0 100.00% 3 0 100.00% +rs256_pk_free 6 0 100.00% 7 0 100.00% +rs256_pk_from_ptr 10 0 100.00% 12 0 100.00% +rs256_pk_to_EVP_PKEY 35 0 100.00% 43 0 100.00% +rs256_pk_from_RSA 32 6 81.25% 26 9 65.38% +rs256_pk_from_EVP_PKEY 8 0 100.00% 7 0 100.00% +rs256_verify_sig 20 2 90.00% 30 5 83.33% +rs256_pk_verify_sig 7 1 85.71% 13 2 84.62% +rs256.c:decode_rsa_pubkey 9 0 100.00% 13 0 100.00% +rs256.c:decode_bignum 8 0 100.00% 10 0 100.00% +rs256.c:rs256_get_EVP_MD 1 0 100.00% 3 0 100.00% +rs256.c:rs256_free_EVP_MD 1 0 100.00% 3 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 146 9 93.84% 179 16 91.06% + +File '/libfido2/src/time.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_time_now 4 0 100.00% 7 0 100.00% +fido_time_delta 23 1 95.65% 23 0 100.00% +time.c:timespec_to_ms 16 2 87.50% 13 2 84.62% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 43 3 93.02% 43 2 95.35% + +File '/libfido2/src/touch.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_dev_get_touch_begin 50 0 100.00% 59 0 100.00% +fido_dev_get_touch_status 17 0 100.00% 20 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 67 0 100.00% 79 0 100.00% + +File '/libfido2/src/tpm.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_get_signed_hash_tpm 25 0 100.00% 39 0 100.00% +tpm.c:check_es256_pubarea 19 0 100.00% 30 0 100.00% +tpm.c:bswap_es256_pubarea 1 0 100.00% 12 0 100.00% +tpm.c:check_rs256_pubarea 17 0 100.00% 28 0 100.00% +tpm.c:bswap_rs256_pubarea 1 0 100.00% 10 0 100.00% +tpm.c:check_sha1_certinfo 15 0 100.00% 38 0 100.00% +tpm.c:get_signed_sha1 17 0 100.00% 19 0 100.00% +tpm.c:get_signed_name 7 0 100.00% 10 0 100.00% +tpm.c:bswap_sha1_certinfo 1 0 100.00% 8 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 103 0 100.00% 194 0 100.00% + +File '/libfido2/src/types.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_str_array_free 4 0 100.00% 7 0 100.00% +fido_opt_array_free 4 0 100.00% 9 0 100.00% +fido_byte_array_free 1 0 100.00% 5 0 100.00% +fido_algo_free 1 0 100.00% 5 0 100.00% +fido_algo_array_free 4 0 100.00% 7 0 100.00% +fido_cert_array_free 4 0 100.00% 9 0 100.00% +fido_str_array_pack 11 0 100.00% 14 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 29 0 100.00% 56 0 100.00% + +File '/libfido2/src/u2f.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +u2f_register 76 0 100.00% 81 0 100.00% +u2f_authenticate 33 0 100.00% 37 0 100.00% +u2f_get_touch_begin 37 0 100.00% 45 0 100.00% +u2f_get_touch_status 26 0 100.00% 36 0 100.00% +u2f.c:key_lookup 51 0 100.00% 65 0 100.00% +u2f.c:send_dummy_register 37 0 100.00% 45 0 100.00% +u2f.c:delay_ms 13 1 92.31% 15 3 80.00% +u2f.c:parse_register_reply 49 0 100.00% 62 0 100.00% +u2f.c:x5c_get 21 1 95.24% 26 3 88.46% +u2f.c:sig_get 6 0 100.00% 10 0 100.00% +u2f.c:encode_cred_attstmt 45 0 100.00% 52 0 100.00% +u2f.c:encode_cred_authdata 33 2 93.94% 61 6 90.16% +u2f.c:cbor_blob_from_ec_point 22 0 100.00% 31 0 100.00% +u2f.c:u2f_authenticate_single 32 0 100.00% 43 0 100.00% +u2f.c:do_auth 56 0 100.00% 67 0 100.00% +u2f.c:parse_auth_reply 23 0 100.00% 23 0 100.00% +u2f.c:authdata_fake 12 0 100.00% 27 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 572 4 99.30% 726 12 98.35% + +File '/libfido2/src/util.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_to_uint64 14 1 92.86% 14 1 92.86% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 14 1 92.86% 14 1 92.86% diff --git a/fuzz/fuzz_assert.c b/fuzz/fuzz_assert.c new file mode 100644 index 0000000..03cb51c --- /dev/null +++ b/fuzz/fuzz_assert.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2019-2023 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "wiredata_u2f.h" +#include "dummy.h" + +#include "../openbsd-compat/openbsd-compat.h" + +/* Parameter set defining a FIDO2 get assertion operation. */ +struct param { + char pin[MAXSTR]; + char rp_id[MAXSTR]; + int ext; + int seed; + struct blob cdh; + struct blob cred; + struct blob es256; + struct blob rs256; + struct blob eddsa; + struct blob wire_data; + uint8_t cred_count; + uint8_t type; + uint8_t opt; + uint8_t up; + uint8_t uv; +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * get assertion using the example parameters above. + */ +static const uint8_t dummy_wire_data_fido[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_ASSERT, +}; + +/* + * Collection of HID reports from an authenticator issued with a U2F + * authentication using the example parameters above. + */ +static const uint8_t dummy_wire_data_u2f[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_AUTH, +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 15 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_byte(v[0], &p->uv) < 0 || + unpack_byte(v[1], &p->up) < 0 || + unpack_byte(v[2], &p->opt) < 0 || + unpack_byte(v[3], &p->type) < 0 || + unpack_byte(v[4], &p->cred_count) < 0 || + unpack_int(v[5], &p->ext) < 0 || + unpack_int(v[6], &p->seed) < 0 || + unpack_string(v[7], p->rp_id) < 0 || + unpack_string(v[8], p->pin) < 0 || + unpack_blob(v[9], &p->wire_data) < 0 || + unpack_blob(v[10], &p->rs256) < 0 || + unpack_blob(v[11], &p->es256) < 0 || + unpack_blob(v[12], &p->eddsa) < 0 || + unpack_blob(v[13], &p->cred) < 0 || + unpack_blob(v[14], &p->cdh) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[15], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(15)) == NULL || + (argv[0] = pack_byte(p->uv)) == NULL || + (argv[1] = pack_byte(p->up)) == NULL || + (argv[2] = pack_byte(p->opt)) == NULL || + (argv[3] = pack_byte(p->type)) == NULL || + (argv[4] = pack_byte(p->cred_count)) == NULL || + (argv[5] = pack_int(p->ext)) == NULL || + (argv[6] = pack_int(p->seed)) == NULL || + (argv[7] = pack_string(p->rp_id)) == NULL || + (argv[8] = pack_string(p->pin)) == NULL || + (argv[9] = pack_blob(&p->wire_data)) == NULL || + (argv[10] = pack_blob(&p->rs256)) == NULL || + (argv[11] = pack_blob(&p->es256)) == NULL || + (argv[12] = pack_blob(&p->eddsa)) == NULL || + (argv[13] = pack_blob(&p->cred)) == NULL || + (argv[14] = pack_blob(&p->cdh)) == NULL) + goto fail; + + for (size_t i = 0; i < 15; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 15; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + dummy.type = 1; /* rsa */ + dummy.ext = FIDO_EXT_HMAC_SECRET; + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + + dummy.cred.len = sizeof(dummy_cdh); /* XXX */ + dummy.cdh.len = sizeof(dummy_cdh); + dummy.es256.len = sizeof(dummy_es256); + dummy.rs256.len = sizeof(dummy_rs256); + dummy.eddsa.len = sizeof(dummy_eddsa); + dummy.wire_data.len = sizeof(dummy_wire_data_fido); + + memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */ + memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); + memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, + dummy.wire_data.len); + memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); + memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); + memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static void +get_assert(fido_assert_t *assert, uint8_t opt, const struct blob *cdh, + const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, + uint8_t cred_count, const struct blob *cred) +{ + fido_dev_t *dev; + + if ((dev = open_dev(opt & 2)) == NULL) + return; + if (opt & 1) + fido_dev_force_u2f(dev); + if (ext & FIDO_EXT_HMAC_SECRET) + fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); + if (ext & FIDO_EXT_CRED_BLOB) + fido_assert_set_extensions(assert, FIDO_EXT_CRED_BLOB); + if (ext & FIDO_EXT_LARGEBLOB_KEY) + fido_assert_set_extensions(assert, FIDO_EXT_LARGEBLOB_KEY); + if (up & 1) + fido_assert_set_up(assert, FIDO_OPT_TRUE); + else if (opt & 1) + fido_assert_set_up(assert, FIDO_OPT_FALSE); + if (uv & 1) + fido_assert_set_uv(assert, FIDO_OPT_TRUE); + + for (uint8_t i = 0; i < cred_count; i++) + fido_assert_allow_cred(assert, cred->body, cred->len); + + fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); + fido_assert_set_rp(assert, rp_id); + /* XXX reuse cred as hmac salt */ + fido_assert_set_hmac_salt(assert, cred->body, cred->len); + + /* repeat memory operations to trigger reallocation paths */ + fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); + fido_assert_set_rp(assert, rp_id); + fido_assert_set_hmac_salt(assert, cred->body, cred->len); + + if (strlen(pin) == 0) + pin = NULL; + + fido_dev_get_assert(dev, assert, (opt & 1) ? NULL : pin); + + fido_dev_cancel(dev); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, + const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len, + const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, + int ext, void *pk) +{ + fido_assert_t *assert = NULL; + int r; + + if ((assert = fido_assert_new()) == NULL) + return; + + fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); + fido_assert_set_rp(assert, rp_id); + fido_assert_set_count(assert, 1); + + if (fido_assert_set_authdata(assert, 0, authdata_ptr, + authdata_len) != FIDO_OK) { + fido_assert_set_authdata_raw(assert, 0, authdata_ptr, + authdata_len); + } + + if (up & 1) + fido_assert_set_up(assert, FIDO_OPT_TRUE); + if (uv & 1) + fido_assert_set_uv(assert, FIDO_OPT_TRUE); + + fido_assert_set_extensions(assert, ext); + fido_assert_set_sig(assert, 0, sig_ptr, sig_len); + + /* repeat memory operations to trigger reallocation paths */ + if (fido_assert_set_authdata(assert, 0, authdata_ptr, + authdata_len) != FIDO_OK) { + fido_assert_set_authdata_raw(assert, 0, authdata_ptr, + authdata_len); + } + fido_assert_set_sig(assert, 0, sig_ptr, sig_len); + + r = fido_assert_verify(assert, 0, type, pk); + consume(&r, sizeof(r)); + + fido_assert_free(&assert); +} + +/* + * Do a dummy conversion to exercise es256_pk_from_EVP_PKEY(). + */ +static void +es256_convert(const es256_pk_t *k) +{ + EVP_PKEY *pkey = NULL; + es256_pk_t *pk = NULL; + int r; + + if ((pkey = es256_pk_to_EVP_PKEY(k)) == NULL || + (pk = es256_pk_new()) == NULL) + goto out; + + r = es256_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); +out: + es256_pk_free(&pk); + EVP_PKEY_free(pkey); +} + +/* + * Do a dummy conversion to exercise es384_pk_from_EVP_PKEY(). + */ +static void +es384_convert(const es384_pk_t *k) +{ + EVP_PKEY *pkey = NULL; + es384_pk_t *pk = NULL; + int r; + + if ((pkey = es384_pk_to_EVP_PKEY(k)) == NULL || + (pk = es384_pk_new()) == NULL) + goto out; + + r = es384_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); +out: + es384_pk_free(&pk); + EVP_PKEY_free(pkey); +} + +/* + * Do a dummy conversion to exercise rs256_pk_from_EVP_PKEY(). + */ +static void +rs256_convert(const rs256_pk_t *k) +{ + EVP_PKEY *pkey = NULL; + rs256_pk_t *pk = NULL; + int r; + + if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL || + (pk = rs256_pk_new()) == NULL) + goto out; + + r = rs256_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); +out: + rs256_pk_free(&pk); + EVP_PKEY_free(pkey); +} + +/* + * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY(). + */ +static void +eddsa_convert(const eddsa_pk_t *k) +{ + EVP_PKEY *pkey = NULL; + eddsa_pk_t *pk = NULL; + int r; + + if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL || + (pk = eddsa_pk_new()) == NULL) + goto out; + + r = eddsa_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); +out: + if (pk) + eddsa_pk_free(&pk); + if (pkey) + EVP_PKEY_free(pkey); +} + +void +test(const struct param *p) +{ + fido_assert_t *assert = NULL; + es256_pk_t *es256_pk = NULL; + es384_pk_t *es384_pk = NULL; + rs256_pk_t *rs256_pk = NULL; + eddsa_pk_t *eddsa_pk = NULL; + uint8_t flags; + uint32_t sigcount; + int cose_alg = 0; + void *pk; + + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + switch (p->type & 3) { + case 0: + cose_alg = COSE_ES256; + + if ((es256_pk = es256_pk_new()) == NULL) + return; + + es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len); + pk = es256_pk; + + es256_convert(pk); + + break; + case 1: + cose_alg = COSE_RS256; + + if ((rs256_pk = rs256_pk_new()) == NULL) + return; + + rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len); + pk = rs256_pk; + + rs256_convert(pk); + + break; + case 2: + cose_alg = COSE_ES384; + + if ((es384_pk = es384_pk_new()) == NULL) + return; + + /* XXX reuse p->es256 as es384 */ + es384_pk_from_ptr(es384_pk, p->es256.body, p->es256.len); + pk = es384_pk; + + es384_convert(pk); + + break; + default: + cose_alg = COSE_EDDSA; + + if ((eddsa_pk = eddsa_pk_new()) == NULL) + return; + + eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len); + pk = eddsa_pk; + + eddsa_convert(pk); + + break; + } + + if ((assert = fido_assert_new()) == NULL) + goto out; + + set_wire_data(p->wire_data.body, p->wire_data.len); + + get_assert(assert, p->opt, &p->cdh, p->rp_id, p->ext, p->up, p->uv, + p->pin, p->cred_count, &p->cred); + + /* XXX +1 on purpose */ + for (size_t i = 0; i <= fido_assert_count(assert); i++) { + verify_assert(cose_alg, + fido_assert_clientdata_hash_ptr(assert), + fido_assert_clientdata_hash_len(assert), + fido_assert_rp_id(assert), + fido_assert_authdata_ptr(assert, i), + fido_assert_authdata_len(assert, i), + fido_assert_sig_ptr(assert, i), + fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk); + consume(fido_assert_authdata_raw_ptr(assert, i), + fido_assert_authdata_raw_len(assert, i)); + consume(fido_assert_id_ptr(assert, i), + fido_assert_id_len(assert, i)); + consume(fido_assert_user_id_ptr(assert, i), + fido_assert_user_id_len(assert, i)); + consume(fido_assert_hmac_secret_ptr(assert, i), + fido_assert_hmac_secret_len(assert, i)); + consume_str(fido_assert_user_icon(assert, i)); + consume_str(fido_assert_user_name(assert, i)); + consume_str(fido_assert_user_display_name(assert, i)); + consume(fido_assert_blob_ptr(assert, i), + fido_assert_blob_len(assert, i)); + consume(fido_assert_largeblob_key_ptr(assert, i), + fido_assert_largeblob_key_len(assert, i)); + flags = fido_assert_flags(assert, i); + consume(&flags, sizeof(flags)); + sigcount = fido_assert_sigcount(assert, i); + consume(&sigcount, sizeof(sigcount)); + } + +out: + es256_pk_free(&es256_pk); + es384_pk_free(&es384_pk); + rs256_pk_free(&rs256_pk); + eddsa_pk_free(&eddsa_pk); + + fido_assert_free(&assert); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_byte(&p->uv); + mutate_byte(&p->up); + mutate_byte(&p->opt); + mutate_byte(&p->type); + mutate_byte(&p->cred_count); + mutate_int(&p->ext); + mutate_blob(&p->rs256); + mutate_blob(&p->es256); + mutate_blob(&p->eddsa); + mutate_blob(&p->cred); + mutate_blob(&p->cdh); + mutate_string(p->rp_id); + mutate_string(p->pin); + } + + if (flags & MUTATE_WIREDATA) { + if (p->opt & 1) { + p->wire_data.len = sizeof(dummy_wire_data_u2f); + memcpy(&p->wire_data.body, &dummy_wire_data_u2f, + p->wire_data.len); + } else { + p->wire_data.len = sizeof(dummy_wire_data_fido); + memcpy(&p->wire_data.body, &dummy_wire_data_fido, + p->wire_data.len); + } + mutate_blob(&p->wire_data); + } +} diff --git a/fuzz/fuzz_attobj.c b/fuzz/fuzz_attobj.c new file mode 100644 index 0000000..4fddc0f --- /dev/null +++ b/fuzz/fuzz_attobj.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2024 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "wiredata_u2f.h" +#include "dummy.h" + +#include "../openbsd-compat/openbsd-compat.h" + +struct param { + int seed; + char rp_id[MAXSTR]; + struct blob cdh; + struct blob attobj; + uint8_t type; +}; + +static const uint8_t dummy_attestation_object[] = { + 0xa3, 0x63, 0x66, 0x6d, 0x74, 0x66, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x64, 0x67, 0x61, 0x74, 0x74, + 0x53, 0x74, 0x6d, 0x74, 0xa3, 0x63, 0x61, 0x6c, + 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x58, 0x46, + 0x30, 0x44, 0x02, 0x20, 0x54, 0x92, 0x28, 0x3b, + 0x83, 0x33, 0x47, 0x56, 0x68, 0x79, 0xb2, 0x0c, + 0x84, 0x80, 0xcc, 0x67, 0x27, 0x8b, 0xfa, 0x48, + 0x43, 0x0d, 0x3c, 0xb4, 0x02, 0x36, 0x87, 0x97, + 0x3e, 0xdf, 0x2f, 0x65, 0x02, 0x20, 0x1b, 0x56, + 0x17, 0x06, 0xe2, 0x26, 0x0f, 0x6a, 0xe9, 0xa9, + 0x70, 0x99, 0x62, 0xeb, 0x3a, 0x04, 0x1a, 0xc4, + 0xa7, 0x03, 0x28, 0x56, 0x7c, 0xed, 0x47, 0x08, + 0x68, 0x73, 0x6a, 0xb6, 0x89, 0x0d, 0x63, 0x78, + 0x35, 0x63, 0x81, 0x59, 0x02, 0xe6, 0x30, 0x82, + 0x02, 0xe2, 0x30, 0x81, 0xcb, 0x02, 0x01, 0x01, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, 0x62, 0x69, + 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x54, + 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x31, 0x35, + 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a, 0x17, + 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x34, 0x31, + 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a, 0x30, 0x1d, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x12, 0x59, 0x75, 0x62, 0x69, 0x63, + 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x54, 0x65, + 0x73, 0x74, 0x20, 0x45, 0x45, 0x30, 0x59, 0x30, + 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, + 0xdb, 0x0a, 0xdb, 0xf5, 0x21, 0xc7, 0x5c, 0xce, + 0x63, 0xdc, 0xa6, 0xe1, 0xe8, 0x25, 0x06, 0x0d, + 0x94, 0xe6, 0x27, 0x54, 0x19, 0x4f, 0x9d, 0x24, + 0xaf, 0x26, 0x1a, 0xbe, 0xad, 0x99, 0x44, 0x1f, + 0x95, 0xa3, 0x71, 0x91, 0x0a, 0x3a, 0x20, 0xe7, + 0x3e, 0x91, 0x5e, 0x13, 0xe8, 0xbe, 0x38, 0x05, + 0x7a, 0xd5, 0x7a, 0xa3, 0x7e, 0x76, 0x90, 0x8f, + 0xaf, 0xe2, 0x8a, 0x94, 0xb6, 0x30, 0xeb, 0x9d, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x02, 0x01, 0x00, 0x95, 0x40, 0x6b, 0x50, + 0x61, 0x7d, 0xad, 0x84, 0xa3, 0xb4, 0xeb, 0x88, + 0x0f, 0xe3, 0x30, 0x0f, 0x2d, 0xa2, 0x0a, 0x00, + 0xd9, 0x25, 0x04, 0xee, 0x72, 0xfa, 0x67, 0xdf, + 0x58, 0x51, 0x0f, 0x0b, 0x47, 0x02, 0x9c, 0x3e, + 0x41, 0x29, 0x4a, 0x93, 0xac, 0x29, 0x85, 0x89, + 0x2d, 0xa4, 0x7a, 0x81, 0x32, 0x28, 0x57, 0x71, + 0x01, 0xef, 0xa8, 0x42, 0x88, 0x16, 0x96, 0x37, + 0x91, 0xd5, 0xdf, 0xe0, 0x8f, 0xc9, 0x3c, 0x8d, + 0xb0, 0xcd, 0x89, 0x70, 0x82, 0xec, 0x79, 0xd3, + 0xc6, 0x78, 0x73, 0x29, 0x32, 0xe5, 0xab, 0x6c, + 0xbd, 0x56, 0x9f, 0xd5, 0x45, 0x91, 0xce, 0xc1, + 0xdd, 0x8d, 0x64, 0xdc, 0xe9, 0x9c, 0x1f, 0x5e, + 0x3c, 0xd2, 0xaf, 0x51, 0xa5, 0x82, 0x18, 0xaf, + 0xe0, 0x37, 0xe7, 0x32, 0x9e, 0x76, 0x05, 0x77, + 0x02, 0x7b, 0xe6, 0x24, 0xa0, 0x31, 0x56, 0x1b, + 0xfd, 0x19, 0xc5, 0x71, 0xd3, 0xf0, 0x9e, 0xc0, + 0x73, 0x05, 0x4e, 0xbc, 0x85, 0xb8, 0x53, 0x9e, + 0xef, 0xc5, 0xbc, 0x9c, 0x56, 0xa3, 0xba, 0xd9, + 0x27, 0x6a, 0xbb, 0xa9, 0x7a, 0x40, 0xd7, 0x47, + 0x8b, 0x55, 0x72, 0x6b, 0xe3, 0xfe, 0x28, 0x49, + 0x71, 0x24, 0xf4, 0x8f, 0xf4, 0x20, 0x81, 0xea, + 0x38, 0xff, 0x7c, 0x0a, 0x4f, 0xdf, 0x02, 0x82, + 0x39, 0x81, 0x82, 0x3b, 0xca, 0x09, 0xdd, 0xca, + 0xaa, 0x0f, 0x27, 0xf5, 0xa4, 0x83, 0x55, 0x6c, + 0x9a, 0x39, 0x9b, 0x15, 0x3a, 0x16, 0x63, 0xdc, + 0x5b, 0xf9, 0xac, 0x5b, 0xbc, 0xf7, 0x9f, 0xbe, + 0x0f, 0x8a, 0xa2, 0x3c, 0x31, 0x13, 0xa3, 0x32, + 0x48, 0xca, 0x58, 0x87, 0xf8, 0x7b, 0xa0, 0xa1, + 0x0a, 0x6a, 0x60, 0x96, 0x93, 0x5f, 0x5d, 0x26, + 0x9e, 0x63, 0x1d, 0x09, 0xae, 0x9a, 0x41, 0xe5, + 0xbd, 0x08, 0x47, 0xfe, 0xe5, 0x09, 0x9b, 0x20, + 0xfd, 0x12, 0xe2, 0xe6, 0x40, 0x7f, 0xba, 0x4a, + 0x61, 0x33, 0x66, 0x0d, 0x0e, 0x73, 0xdb, 0xb0, + 0xd5, 0xa2, 0x9a, 0x9a, 0x17, 0x0d, 0x34, 0x30, + 0x85, 0x6a, 0x42, 0x46, 0x9e, 0xff, 0x34, 0x8f, + 0x5f, 0x87, 0x6c, 0x35, 0xe7, 0xa8, 0x4d, 0x35, + 0xeb, 0xc1, 0x41, 0xaa, 0x8a, 0xd2, 0xda, 0x19, + 0xaa, 0x79, 0xa2, 0x5f, 0x35, 0x2c, 0xa0, 0xfd, + 0x25, 0xd3, 0xf7, 0x9d, 0x25, 0x18, 0x2d, 0xfa, + 0xb4, 0xbc, 0xbb, 0x07, 0x34, 0x3c, 0x8d, 0x81, + 0xbd, 0xf4, 0xe9, 0x37, 0xdb, 0x39, 0xe9, 0xd1, + 0x45, 0x5b, 0x20, 0x41, 0x2f, 0x2d, 0x27, 0x22, + 0xdc, 0x92, 0x74, 0x8a, 0x92, 0xd5, 0x83, 0xfd, + 0x09, 0xfb, 0x13, 0x9b, 0xe3, 0x39, 0x7a, 0x6b, + 0x5c, 0xfa, 0xe6, 0x76, 0x9e, 0xe0, 0xe4, 0xe3, + 0xef, 0xad, 0xbc, 0xfd, 0x42, 0x45, 0x9a, 0xd4, + 0x94, 0xd1, 0x7e, 0x8d, 0xa7, 0xd8, 0x05, 0xd5, + 0xd3, 0x62, 0xcf, 0x15, 0xcf, 0x94, 0x7d, 0x1f, + 0x5b, 0x58, 0x20, 0x44, 0x20, 0x90, 0x71, 0xbe, + 0x66, 0xe9, 0x9a, 0xab, 0x74, 0x32, 0x70, 0x53, + 0x1d, 0x69, 0xed, 0x87, 0x66, 0xf4, 0x09, 0x4f, + 0xca, 0x25, 0x30, 0xc2, 0x63, 0x79, 0x00, 0x3c, + 0xb1, 0x9b, 0x39, 0x3f, 0x00, 0xe0, 0xa8, 0x88, + 0xef, 0x7a, 0x51, 0x5b, 0xe7, 0xbd, 0x49, 0x64, + 0xda, 0x41, 0x7b, 0x24, 0xc3, 0x71, 0x22, 0xfd, + 0xd1, 0xd1, 0x20, 0xb3, 0x3f, 0x97, 0xd3, 0x97, + 0xb2, 0xaa, 0x18, 0x1c, 0x9e, 0x03, 0x77, 0x7b, + 0x5b, 0x7e, 0xf9, 0xa3, 0xa0, 0xd6, 0x20, 0x81, + 0x2c, 0x38, 0x8f, 0x9d, 0x25, 0xde, 0xe9, 0xc8, + 0xf5, 0xdd, 0x6a, 0x47, 0x9c, 0x65, 0x04, 0x5a, + 0x56, 0xe6, 0xc2, 0xeb, 0xf2, 0x02, 0x97, 0xe1, + 0xb9, 0xd8, 0xe1, 0x24, 0x76, 0x9f, 0x23, 0x62, + 0x39, 0x03, 0x4b, 0xc8, 0xf7, 0x34, 0x07, 0x49, + 0xd6, 0xe7, 0x4d, 0x9a, 0x68, 0x61, 0x75, 0x74, + 0x68, 0x44, 0x61, 0x74, 0x61, 0x58, 0xc4, 0x49, + 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, + 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, + 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, + 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x41, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, + 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, + 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0x53, 0xfb, + 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, + 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, + 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, + 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, + 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, + 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, + 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, + 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 0xa5, 0x01, + 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, + 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, + 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, + 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, + 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, + 0x22, 0x58, 0x20, 0x87, 0x5f, 0x90, 0xe6, 0xfd, + 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, + 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, + 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, + 0x2b, 0x1e, 0xd2 +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 5 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->rp_id) < 0 || + unpack_blob(v[2], &p->cdh) < 0 || + unpack_blob(v[3], &p->attobj) < 0 || + unpack_byte(v[4], &p->type) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[5], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(17)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->rp_id)) == NULL || + (argv[2] = pack_blob(&p->cdh)) == NULL || + (argv[3] = pack_blob(&p->attobj)) == NULL || + (argv[4] = pack_byte(p->type)) == NULL) + goto fail; + + for (size_t i = 0; i < 5; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 5; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + dummy.type = 1; + + strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + + dummy.cdh.len = sizeof(dummy_cdh); + dummy.attobj.len = sizeof(dummy_attestation_object); + + memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); + memcpy(&dummy.attobj.body, dummy_attestation_object, dummy.attobj.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_byte(&p->type); + p->attobj.len = sizeof(dummy_attestation_object); + memcpy(&p->attobj.body, &dummy_attestation_object, + p->attobj.len); + mutate_blob(&p->attobj); + } +} + +void +test(const struct param *p) +{ + fido_cred_t *cred = NULL; + int r, cose_alg; + + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + if ((cred = fido_cred_new()) == NULL) + return; + + switch (p->type & 3) { + case 0: + cose_alg = COSE_ES256; + break; + case 1: + cose_alg = COSE_RS256; + break; + case 2: + cose_alg = COSE_ES384; + break; + default: + cose_alg = COSE_EDDSA; + break; + } + + r = fido_cred_set_type(cred, cose_alg); + consume(&r, sizeof(r)); + r = fido_cred_set_rp(cred, p->rp_id, NULL); + consume(&r, sizeof(r)); + r = fido_cred_set_clientdata_hash(cred, p->cdh.body, p->cdh.len); + consume(&r, sizeof(r)); + r = fido_cred_set_attobj(cred, p->attobj.body, p->attobj.len); + consume(&r, sizeof(r)); + + consume_str(fido_cred_fmt(cred)); + consume(fido_cred_attstmt_ptr(cred), fido_cred_attstmt_len(cred)); + consume(fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred)); + r = fido_cred_verify(cred); + consume(&r, sizeof(r)); + + fido_cred_free(&cred); +} diff --git a/fuzz/fuzz_bio.c b/fuzz/fuzz_bio.c new file mode 100644 index 0000000..0c6b12c --- /dev/null +++ b/fuzz/fuzz_bio.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2019 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "dummy.h" + +#include "../openbsd-compat/openbsd-compat.h" + +/* Parameter set defining a FIDO2 credential management operation. */ +struct param { + char pin[MAXSTR]; + char name[MAXSTR]; + int seed; + struct blob id; + struct blob info_wire_data; + struct blob enroll_wire_data; + struct blob list_wire_data; + struct blob set_name_wire_data; + struct blob remove_wire_data; +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'getFingerprintSensorInfo' bio enrollment command. + */ +static const uint8_t dummy_info_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_BIO_INFO, +}; + +/* + * Collection of HID reports from an authenticator issued with FIDO2 + * 'enrollBegin' + 'enrollCaptureNextSample' bio enrollment commands. + */ +static const uint8_t dummy_enroll_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_BIO_ENROLL, +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'enumerateEnrollments' bio enrollment command. + */ +static const uint8_t dummy_list_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_BIO_ENUM, +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'setFriendlyName' bio enrollment command. + */ +static const uint8_t dummy_set_name_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_STATUS, +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'removeEnrollment' bio enrollment command. + */ +static const uint8_t dummy_remove_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_STATUS, +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 9 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->pin) < 0 || + unpack_string(v[2], p->name) < 0 || + unpack_blob(v[3], &p->id) < 0 || + unpack_blob(v[4], &p->info_wire_data) < 0 || + unpack_blob(v[5], &p->enroll_wire_data) < 0 || + unpack_blob(v[6], &p->list_wire_data) < 0 || + unpack_blob(v[7], &p->set_name_wire_data) < 0 || + unpack_blob(v[8], &p->remove_wire_data) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[9], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(9)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->pin)) == NULL || + (argv[2] = pack_string(p->name)) == NULL || + (argv[3] = pack_blob(&p->id)) == NULL || + (argv[4] = pack_blob(&p->info_wire_data)) == NULL || + (argv[5] = pack_blob(&p->enroll_wire_data)) == NULL || + (argv[6] = pack_blob(&p->list_wire_data)) == NULL || + (argv[7] = pack_blob(&p->set_name_wire_data)) == NULL || + (argv[8] = pack_blob(&p->remove_wire_data)) == NULL) + goto fail; + + for (size_t i = 0; i < 9; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 9; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.name, dummy_name, sizeof(dummy.name)); + + dummy.info_wire_data.len = sizeof(dummy_info_wire_data); + dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data); + dummy.list_wire_data.len = sizeof(dummy_list_wire_data); + dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data); + dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data); + dummy.id.len = sizeof(dummy_id); + + memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, + dummy.info_wire_data.len); + memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data, + dummy.enroll_wire_data.len); + memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data, + dummy.list_wire_data.len); + memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data, + dummy.set_name_wire_data.len); + memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data, + dummy.remove_wire_data.len); + memcpy(&dummy.id.body, &dummy_id, dummy.id.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static fido_dev_t * +prepare_dev(void) +{ + fido_dev_t *dev; + bool x; + + if ((dev = open_dev(0)) == NULL) + return NULL; + + x = fido_dev_is_fido2(dev); + consume(&x, sizeof(x)); + x = fido_dev_supports_pin(dev); + consume(&x, sizeof(x)); + x = fido_dev_has_pin(dev); + consume(&x, sizeof(x)); + x = fido_dev_supports_uv(dev); + consume(&x, sizeof(x)); + x = fido_dev_has_uv(dev); + consume(&x, sizeof(x)); + + return dev; +} + +static void +get_info(const struct param *p) +{ + fido_dev_t *dev = NULL; + fido_bio_info_t *i = NULL; + uint8_t type; + uint8_t max_samples; + int r; + + set_wire_data(p->info_wire_data.body, p->info_wire_data.len); + + if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) + goto done; + + r = fido_bio_dev_get_info(dev, i); + consume_str(fido_strerr(r)); + + type = fido_bio_info_type(i); + max_samples = fido_bio_info_max_samples(i); + consume(&type, sizeof(type)); + consume(&max_samples, sizeof(max_samples)); + +done: + if (dev) + fido_dev_close(dev); + + fido_dev_free(&dev); + fido_bio_info_free(&i); +} + +static void +consume_template(const fido_bio_template_t *t) +{ + consume_str(fido_bio_template_name(t)); + consume(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t)); +} + +static void +consume_enroll(fido_bio_enroll_t *e) +{ + uint8_t last_status; + uint8_t remaining_samples; + + last_status = fido_bio_enroll_last_status(e); + remaining_samples = fido_bio_enroll_remaining_samples(e); + consume(&last_status, sizeof(last_status)); + consume(&remaining_samples, sizeof(remaining_samples)); +} + +static void +enroll(const struct param *p) +{ + fido_dev_t *dev = NULL; + fido_bio_template_t *t = NULL; + fido_bio_enroll_t *e = NULL; + size_t cnt = 0; + + set_wire_data(p->enroll_wire_data.body, p->enroll_wire_data.len); + + if ((dev = prepare_dev()) == NULL || + (t = fido_bio_template_new()) == NULL || + (e = fido_bio_enroll_new()) == NULL) + goto done; + + fido_bio_dev_enroll_begin(dev, t, e, (uint32_t)p->seed, p->pin); + + consume_template(t); + consume_enroll(e); + + while (fido_bio_enroll_remaining_samples(e) > 0 && cnt++ < 5) { + fido_bio_dev_enroll_continue(dev, t, e, p->seed); + consume_template(t); + consume_enroll(e); + } + +done: + if (dev) + fido_dev_close(dev); + + fido_dev_free(&dev); + fido_bio_template_free(&t); + fido_bio_enroll_free(&e); +} + +static void +list(const struct param *p) +{ + fido_dev_t *dev = NULL; + fido_bio_template_array_t *ta = NULL; + const fido_bio_template_t *t = NULL; + + set_wire_data(p->list_wire_data.body, p->list_wire_data.len); + + if ((dev = prepare_dev()) == NULL || + (ta = fido_bio_template_array_new()) == NULL) + goto done; + + fido_bio_dev_get_template_array(dev, ta, p->pin); + + /* +1 on purpose */ + for (size_t i = 0; i < fido_bio_template_array_count(ta) + 1; i++) + if ((t = fido_bio_template(ta, i)) != NULL) + consume_template(t); + +done: + if (dev) + fido_dev_close(dev); + + fido_dev_free(&dev); + fido_bio_template_array_free(&ta); +} + +static void +set_name(const struct param *p) +{ + fido_dev_t *dev = NULL; + fido_bio_template_t *t = NULL; + + set_wire_data(p->set_name_wire_data.body, p->set_name_wire_data.len); + + if ((dev = prepare_dev()) == NULL || + (t = fido_bio_template_new()) == NULL) + goto done; + + fido_bio_template_set_name(t, p->name); + fido_bio_template_set_id(t, p->id.body, p->id.len); + consume_template(t); + + fido_bio_dev_set_template_name(dev, t, p->pin); + +done: + if (dev) + fido_dev_close(dev); + + fido_dev_free(&dev); + fido_bio_template_free(&t); +} + +static void +del(const struct param *p) +{ + fido_dev_t *dev = NULL; + fido_bio_template_t *t = NULL; + int r; + + set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); + + if ((dev = prepare_dev()) == NULL || + (t = fido_bio_template_new()) == NULL) + goto done; + + r = fido_bio_template_set_id(t, p->id.body, p->id.len); + consume_template(t); + consume_str(fido_strerr(r)); + + fido_bio_dev_enroll_remove(dev, t, p->pin); + +done: + if (dev) + fido_dev_close(dev); + + fido_dev_free(&dev); + fido_bio_template_free(&t); +} + +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + get_info(p); + enroll(p); + list(p); + set_name(p); + del(p); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_blob(&p->id); + mutate_string(p->pin); + mutate_string(p->name); + } + + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->info_wire_data); + mutate_blob(&p->enroll_wire_data); + mutate_blob(&p->list_wire_data); + mutate_blob(&p->set_name_wire_data); + mutate_blob(&p->remove_wire_data); + } +} diff --git a/fuzz/fuzz_cred.c b/fuzz/fuzz_cred.c new file mode 100644 index 0000000..f1fc928 --- /dev/null +++ b/fuzz/fuzz_cred.c @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2019-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "wiredata_u2f.h" +#include "dummy.h" + +#include "../openbsd-compat/openbsd-compat.h" + +/* Parameter set defining a FIDO2 make credential operation. */ +struct param { + char pin[MAXSTR]; + char rp_id[MAXSTR]; + char rp_name[MAXSTR]; + char user_icon[MAXSTR]; + char user_name[MAXSTR]; + char user_nick[MAXSTR]; + int ext; + int seed; + struct blob cdh; + struct blob excl_cred; + struct blob user_id; + struct blob wire_data; + uint8_t excl_count; + uint8_t rk; + uint8_t type; + uint8_t opt; + uint8_t uv; +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * make credential using the example parameters above. + */ +static const uint8_t dummy_wire_data_fido[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_CBOR_CRED, +}; + +/* + * Collection of HID reports from an authenticator issued with a U2F + * registration using the example parameters above. + */ +static const uint8_t dummy_wire_data_u2f[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_6985, + WIREDATA_CTAP_U2F_REGISTER, +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 17 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_byte(v[0], &p->rk) < 0 || + unpack_byte(v[1], &p->type) < 0 || + unpack_byte(v[2], &p->opt) < 0 || + unpack_byte(v[3], &p->uv) < 0 || + unpack_byte(v[4], &p->excl_count) < 0 || + unpack_int(v[5], &p->ext) < 0 || + unpack_int(v[6], &p->seed) < 0 || + unpack_string(v[7], p->pin) < 0 || + unpack_string(v[8], p->rp_id) < 0 || + unpack_string(v[9], p->rp_name) < 0 || + unpack_string(v[10], p->user_icon) < 0 || + unpack_string(v[11], p->user_name) < 0 || + unpack_string(v[12], p->user_nick) < 0 || + unpack_blob(v[13], &p->cdh) < 0 || + unpack_blob(v[14], &p->user_id) < 0 || + unpack_blob(v[15], &p->wire_data) < 0 || + unpack_blob(v[16], &p->excl_cred) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[17], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(17)) == NULL || + (argv[0] = pack_byte(p->rk)) == NULL || + (argv[1] = pack_byte(p->type)) == NULL || + (argv[2] = pack_byte(p->opt)) == NULL || + (argv[3] = pack_byte(p->uv)) == NULL || + (argv[4] = pack_byte(p->excl_count)) == NULL || + (argv[5] = pack_int(p->ext)) == NULL || + (argv[6] = pack_int(p->seed)) == NULL || + (argv[7] = pack_string(p->pin)) == NULL || + (argv[8] = pack_string(p->rp_id)) == NULL || + (argv[9] = pack_string(p->rp_name)) == NULL || + (argv[10] = pack_string(p->user_icon)) == NULL || + (argv[11] = pack_string(p->user_name)) == NULL || + (argv[12] = pack_string(p->user_nick)) == NULL || + (argv[13] = pack_blob(&p->cdh)) == NULL || + (argv[14] = pack_blob(&p->user_id)) == NULL || + (argv[15] = pack_blob(&p->wire_data)) == NULL || + (argv[16] = pack_blob(&p->excl_cred)) == NULL) + goto fail; + + for (size_t i = 0; i < 17; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 17; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + dummy.type = 1; + dummy.ext = FIDO_EXT_HMAC_SECRET; + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); + strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); + strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); + strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); + + dummy.cdh.len = sizeof(dummy_cdh); + dummy.user_id.len = sizeof(dummy_user_id); + dummy.wire_data.len = sizeof(dummy_wire_data_fido); + + memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); + memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); + memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, + dummy.wire_data.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static void +make_cred(fido_cred_t *cred, uint8_t opt, int type, const struct blob *cdh, + const char *rp_id, const char *rp_name, const struct blob *user_id, + const char *user_name, const char *user_nick, const char *user_icon, + int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, + const struct blob *excl_cred) +{ + fido_dev_t *dev; + + if ((dev = open_dev(opt & 2)) == NULL) + return; + if (opt & 1) + fido_dev_force_u2f(dev); + + for (uint8_t i = 0; i < excl_count; i++) + fido_cred_exclude(cred, excl_cred->body, excl_cred->len); + + fido_cred_set_type(cred, type); + fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); + fido_cred_set_rp(cred, rp_id, rp_name); + fido_cred_set_user(cred, user_id->body, user_id->len, user_name, + user_nick, user_icon); + + if (ext & FIDO_EXT_HMAC_SECRET) + fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET); + if (ext & FIDO_EXT_CRED_BLOB) + fido_cred_set_blob(cred, user_id->body, user_id->len); + if (ext & FIDO_EXT_LARGEBLOB_KEY) + fido_cred_set_extensions(cred, FIDO_EXT_LARGEBLOB_KEY); + if (ext & FIDO_EXT_MINPINLEN) + fido_cred_set_pin_minlen(cred, strlen(pin)); + + if (rk & 1) + fido_cred_set_rk(cred, FIDO_OPT_TRUE); + if (uv & 1) + fido_cred_set_uv(cred, FIDO_OPT_TRUE); + if (user_id->len) + fido_cred_set_prot(cred, user_id->body[0] & 0x03); + + /* repeat memory operations to trigger reallocation paths */ + fido_cred_set_type(cred, type); + fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); + fido_cred_set_rp(cred, rp_id, rp_name); + fido_cred_set_user(cred, user_id->body, user_id->len, user_name, + user_nick, user_icon); + + if (strlen(pin) == 0) + pin = NULL; + + fido_dev_make_cred(dev, cred, (opt & 1) ? NULL : pin); + + fido_dev_cancel(dev); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, + const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr, + size_t authdata_len, const unsigned char *authdata_raw_ptr, + size_t authdata_raw_len, int ext, uint8_t rk, uint8_t uv, + const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, + size_t sig_len, const unsigned char *attstmt_ptr, size_t attstmt_len, + const char *fmt, int prot, size_t minpinlen) +{ + fido_cred_t *cred; + uint8_t flags; + uint32_t sigcount; + int r; + + if ((cred = fido_cred_new()) == NULL) + return; + + fido_cred_set_type(cred, type); + fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len); + fido_cred_set_rp(cred, rp_id, rp_name); + consume(authdata_ptr, authdata_len); + consume(authdata_raw_ptr, authdata_raw_len); + consume(x5c_ptr, x5c_len); + consume(sig_ptr, sig_len); + consume(attstmt_ptr, attstmt_len); + if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) + fido_cred_set_authdata_raw(cred, authdata_raw_ptr, + authdata_raw_len); + fido_cred_set_extensions(cred, ext); + if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) { + fido_cred_set_x509(cred, x5c_ptr, x5c_len); + fido_cred_set_sig(cred, sig_ptr, sig_len); + } + fido_cred_set_prot(cred, prot); + fido_cred_set_pin_minlen(cred, minpinlen); + + if (rk & 1) + fido_cred_set_rk(cred, FIDO_OPT_TRUE); + if (uv & 1) + fido_cred_set_uv(cred, FIDO_OPT_TRUE); + if (fmt) + fido_cred_set_fmt(cred, fmt); + + /* XXX +1 on purpose */ + for (size_t i = 0; i < fido_cred_x5c_list_count(cred) + 1; i++) + consume(fido_cred_x5c_list_ptr(cred, i), + fido_cred_x5c_list_len(cred, i)); + + /* repeat memory operations to trigger reallocation paths */ + if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) + fido_cred_set_authdata_raw(cred, authdata_raw_ptr, + authdata_raw_len); + if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) { + fido_cred_set_x509(cred, x5c_ptr, x5c_len); + fido_cred_set_sig(cred, sig_ptr, sig_len); + } + fido_cred_set_x509(cred, x5c_ptr, x5c_len); + fido_cred_set_sig(cred, sig_ptr, sig_len); + + r = fido_cred_verify(cred); + consume(&r, sizeof(r)); + r = fido_cred_verify_self(cred); + consume(&r, sizeof(r)); + + consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); + consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); + consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred)); + consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); + consume_str(fido_cred_user_name(cred)); + consume_str(fido_cred_display_name(cred)); + consume(fido_cred_largeblob_key_ptr(cred), + fido_cred_largeblob_key_len(cred)); + + flags = fido_cred_flags(cred); + consume(&flags, sizeof(flags)); + sigcount = fido_cred_sigcount(cred); + consume(&sigcount, sizeof(sigcount)); + type = fido_cred_type(cred); + consume(&type, sizeof(type)); + minpinlen = fido_cred_pin_minlen(cred); + consume(&minpinlen, sizeof(minpinlen)); + + fido_cred_free(&cred); +} + +static void +test_cred(const struct param *p) +{ + fido_cred_t *cred = NULL; + int cose_alg = 0; + + if ((cred = fido_cred_new()) == NULL) + return; + + switch (p->type & 3) { + case 0: + cose_alg = COSE_ES256; + break; + case 1: + cose_alg = COSE_RS256; + break; + case 2: + cose_alg = COSE_ES384; + break; + default: + cose_alg = COSE_EDDSA; + break; + } + + set_wire_data(p->wire_data.body, p->wire_data.len); + + make_cred(cred, p->opt, cose_alg, &p->cdh, p->rp_id, p->rp_name, + &p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext, + p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred); + + verify_cred(cose_alg, + fido_cred_clientdata_hash_ptr(cred), + fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), + fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), + fido_cred_authdata_len(cred), fido_cred_authdata_raw_ptr(cred), + fido_cred_authdata_raw_len(cred), p->ext, p->rk, p->uv, + fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), + fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), + fido_cred_attstmt_ptr(cred), fido_cred_attstmt_len(cred), + fido_cred_fmt(cred), fido_cred_prot(cred), + fido_cred_pin_minlen(cred)); + + fido_cred_free(&cred); +} + +static void +test_touch(const struct param *p) +{ + fido_dev_t *dev; + int r; + int touched; + + set_wire_data(p->wire_data.body, p->wire_data.len); + + if ((dev = open_dev(p->opt & 2)) == NULL) + return; + if (p->opt & 1) + fido_dev_force_u2f(dev); + + r = fido_dev_get_touch_begin(dev); + consume_str(fido_strerr(r)); + r = fido_dev_get_touch_status(dev, &touched, -1); + consume_str(fido_strerr(r)); + consume(&touched, sizeof(touched)); + + fido_dev_cancel(dev); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +test_misc(const struct param *p) +{ + fido_cred_t *cred = NULL; + + if ((cred = fido_cred_new()) == NULL) + return; + + /* reuse user id as credential id */ + fido_cred_set_id(cred, p->user_id.body, p->user_id.len); + consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); + fido_cred_free(&cred); +} + +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + test_cred(p); + test_touch(p); + test_misc(p); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_byte(&p->rk); + mutate_byte(&p->type); + mutate_byte(&p->opt); + mutate_byte(&p->uv); + mutate_byte(&p->excl_count); + mutate_int(&p->ext); + mutate_blob(&p->cdh); + mutate_blob(&p->user_id); + mutate_blob(&p->excl_cred); + mutate_string(p->pin); + mutate_string(p->user_icon); + mutate_string(p->user_name); + mutate_string(p->user_nick); + mutate_string(p->rp_id); + mutate_string(p->rp_name); + } + + if (flags & MUTATE_WIREDATA) { + if (p->opt & 1) { + p->wire_data.len = sizeof(dummy_wire_data_u2f); + memcpy(&p->wire_data.body, &dummy_wire_data_u2f, + p->wire_data.len); + } else { + p->wire_data.len = sizeof(dummy_wire_data_fido); + memcpy(&p->wire_data.body, &dummy_wire_data_fido, + p->wire_data.len); + } + mutate_blob(&p->wire_data); + } +} diff --git a/fuzz/fuzz_credman.c b/fuzz/fuzz_credman.c new file mode 100644 index 0000000..ef21475 --- /dev/null +++ b/fuzz/fuzz_credman.c @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "dummy.h" + +#include "../openbsd-compat/openbsd-compat.h" + +/* Parameter set defining a FIDO2 credential management operation. */ +struct param { + char pin[MAXSTR]; + char rp_id[MAXSTR]; + int seed; + struct blob cred_id; + struct blob del_wire_data; + struct blob meta_wire_data; + struct blob rk_wire_data; + struct blob rp_wire_data; +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'getCredsMetadata' credential management command. + */ +static const uint8_t dummy_meta_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_CREDMAN_META, +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'enumerateRPsBegin' credential management command. + */ +static const uint8_t dummy_rp_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_CREDMAN_RPLIST, +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'enumerateCredentialsBegin' credential management command. + */ +static const uint8_t dummy_rk_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_CREDMAN_RKLIST, +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'deleteCredential' credential management command. + */ +static const uint8_t dummy_del_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_STATUS, +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 8 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->pin) < 0 || + unpack_string(v[2], p->rp_id) < 0 || + unpack_blob(v[3], &p->cred_id) < 0 || + unpack_blob(v[4], &p->meta_wire_data) < 0 || + unpack_blob(v[5], &p->rp_wire_data) < 0 || + unpack_blob(v[6], &p->rk_wire_data) < 0 || + unpack_blob(v[7], &p->del_wire_data) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[8], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(8)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->pin)) == NULL || + (argv[2] = pack_string(p->rp_id)) == NULL || + (argv[3] = pack_blob(&p->cred_id)) == NULL || + (argv[4] = pack_blob(&p->meta_wire_data)) == NULL || + (argv[5] = pack_blob(&p->rp_wire_data)) == NULL || + (argv[6] = pack_blob(&p->rk_wire_data)) == NULL || + (argv[7] = pack_blob(&p->del_wire_data)) == NULL) + goto fail; + + for (size_t i = 0; i < 8; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 8; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + + dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); + dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); + dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); + dummy.del_wire_data.len = sizeof(dummy_del_wire_data); + dummy.cred_id.len = sizeof(dummy_cred_id); + + memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, + dummy.meta_wire_data.len); + memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, + dummy.rp_wire_data.len); + memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, + dummy.rk_wire_data.len); + memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, + dummy.del_wire_data.len); + memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static fido_dev_t * +prepare_dev(void) +{ + fido_dev_t *dev; + bool x; + + if ((dev = open_dev(0)) == NULL) + return NULL; + + x = fido_dev_is_fido2(dev); + consume(&x, sizeof(x)); + x = fido_dev_supports_cred_prot(dev); + consume(&x, sizeof(x)); + x = fido_dev_supports_credman(dev); + consume(&x, sizeof(x)); + + return dev; +} + +static void +get_metadata(const struct param *p) +{ + fido_dev_t *dev; + fido_credman_metadata_t *metadata; + uint64_t existing; + uint64_t remaining; + + set_wire_data(p->meta_wire_data.body, p->meta_wire_data.len); + + if ((dev = prepare_dev()) == NULL) + return; + + if ((metadata = fido_credman_metadata_new()) == NULL) { + fido_dev_close(dev); + fido_dev_free(&dev); + return; + } + + fido_credman_get_dev_metadata(dev, metadata, p->pin); + + existing = fido_credman_rk_existing(metadata); + remaining = fido_credman_rk_remaining(metadata); + consume(&existing, sizeof(existing)); + consume(&remaining, sizeof(remaining)); + + fido_credman_metadata_free(&metadata); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +get_rp_list(const struct param *p) +{ + fido_dev_t *dev; + fido_credman_rp_t *rp; + + set_wire_data(p->rp_wire_data.body, p->rp_wire_data.len); + + if ((dev = prepare_dev()) == NULL) + return; + + if ((rp = fido_credman_rp_new()) == NULL) { + fido_dev_close(dev); + fido_dev_free(&dev); + return; + } + + fido_credman_get_dev_rp(dev, rp, p->pin); + + /* +1 on purpose */ + for (size_t i = 0; i < fido_credman_rp_count(rp) + 1; i++) { + consume(fido_credman_rp_id_hash_ptr(rp, i), + fido_credman_rp_id_hash_len(rp, i)); + consume_str(fido_credman_rp_id(rp, i)); + consume_str(fido_credman_rp_name(rp, i)); + } + + fido_credman_rp_free(&rp); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +get_rk_list(const struct param *p) +{ + fido_dev_t *dev; + fido_credman_rk_t *rk; + const fido_cred_t *cred; + int val; + + set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); + + if ((dev = prepare_dev()) == NULL) + return; + + if ((rk = fido_credman_rk_new()) == NULL) { + fido_dev_close(dev); + fido_dev_free(&dev); + return; + } + + fido_credman_get_dev_rk(dev, p->rp_id, rk, p->pin); + + /* +1 on purpose */ + for (size_t i = 0; i < fido_credman_rk_count(rk) + 1; i++) { + if ((cred = fido_credman_rk(rk, i)) == NULL) { + assert(i >= fido_credman_rk_count(rk)); + continue; + } + val = fido_cred_type(cred); + consume(&val, sizeof(val)); + consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); + consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); + consume(fido_cred_user_id_ptr(cred), + fido_cred_user_id_len(cred)); + consume_str(fido_cred_user_name(cred)); + consume_str(fido_cred_display_name(cred)); + val = fido_cred_prot(cred); + consume(&val, sizeof(val)); + } + + fido_credman_rk_free(&rk); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +del_rk(const struct param *p) +{ + fido_dev_t *dev; + + set_wire_data(p->del_wire_data.body, p->del_wire_data.len); + + if ((dev = prepare_dev()) == NULL) + return; + + fido_credman_del_dev_rk(dev, p->cred_id.body, p->cred_id.len, p->pin); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +set_rk(const struct param *p) +{ + fido_dev_t *dev = NULL; + fido_cred_t *cred = NULL; + const char *pin = p->pin; + int r0, r1, r2; + + set_wire_data(p->del_wire_data.body, p->del_wire_data.len); + + if ((dev = prepare_dev()) == NULL) + return; + if ((cred = fido_cred_new()) == NULL) + goto out; + r0 = fido_cred_set_id(cred, p->cred_id.body, p->cred_id.len); + r1 = fido_cred_set_user(cred, p->cred_id.body, p->cred_id.len, p->rp_id, + NULL, NULL); + if (strlen(pin) == 0) + pin = NULL; + r2 = fido_credman_set_dev_rk(dev, cred, pin); + consume(&r0, sizeof(r0)); + consume(&r1, sizeof(r1)); + consume(&r2, sizeof(r2)); +out: + fido_dev_close(dev); + fido_dev_free(&dev); + fido_cred_free(&cred); +} + +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + get_metadata(p); + get_rp_list(p); + get_rk_list(p); + del_rk(p); + set_rk(p); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_blob(&p->cred_id); + mutate_string(p->pin); + mutate_string(p->rp_id); + } + + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->meta_wire_data); + mutate_blob(&p->rp_wire_data); + mutate_blob(&p->rk_wire_data); + mutate_blob(&p->del_wire_data); + } +} diff --git a/fuzz/fuzz_hid.c b/fuzz/fuzz_hid.c new file mode 100644 index 0000000..daaadad --- /dev/null +++ b/fuzz/fuzz_hid.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2020-2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" +#include "mutator_aux.h" +#include "dummy.h" + +extern int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *); +extern int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *); +extern void set_udev_parameters(const char *, const struct blob *); + +struct param { + int seed; + char uevent[MAXSTR]; + struct blob report_descriptor; + struct blob netlink_wiredata; +}; + +/* + * Sample HID report descriptor from the FIDO HID interface of a YubiKey 5. + */ +static const uint8_t dummy_report_descriptor[] = { + 0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, + 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, + 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, + 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x40, 0x91, + 0x02, 0xc0 +}; + +/* + * Sample uevent file from a Yubico Security Key. + */ +static const char dummy_uevent[] = + "DRIVER=hid-generic\n" + "HID_ID=0003:00001050:00000120\n" + "HID_NAME=Yubico Security Key by Yubico\n" + "HID_PHYS=usb-0000:00:14.0-3/input0\n" + "HID_UNIQ=\n" + "MODALIAS=hid:b0003g0001v00001050p00000120\n"; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 4 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->uevent) < 0 || + unpack_blob(v[2], &p->report_descriptor) < 0 || + unpack_blob(v[3], &p->netlink_wiredata) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[4], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(4)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->uevent)) == NULL || + (argv[2] = pack_blob(&p->report_descriptor)) == NULL || + (argv[3] = pack_blob(&p->netlink_wiredata)) == NULL) + goto fail; + + for (size_t i = 0; i < 4; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 4; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + dummy.report_descriptor.len = sizeof(dummy_report_descriptor); + strlcpy(dummy.uevent, dummy_uevent, sizeof(dummy.uevent)); + memcpy(&dummy.report_descriptor.body, &dummy_report_descriptor, + dummy.report_descriptor.len); + dummy.netlink_wiredata.len = sizeof(dummy_netlink_wiredata); + memcpy(&dummy.netlink_wiredata.body, &dummy_netlink_wiredata, + dummy.netlink_wiredata.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + if (blob_len > len) + blob_len = len; + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static void +get_usage(const struct param *p) +{ + uint32_t usage_page = 0; + + fido_hid_get_usage(p->report_descriptor.body, p->report_descriptor.len, + &usage_page); + consume(&usage_page, sizeof(usage_page)); +} + +static void +get_report_len(const struct param *p) +{ + size_t report_in_len = 0; + size_t report_out_len = 0; + + fido_hid_get_report_len(p->report_descriptor.body, + p->report_descriptor.len, &report_in_len, &report_out_len); + consume(&report_in_len, sizeof(report_in_len)); + consume(&report_out_len, sizeof(report_out_len)); +} + +static void +manifest(const struct param *p) +{ + size_t ndevs, nfound; + fido_dev_info_t *devlist = NULL, *devlist_set = NULL; + int16_t vendor_id, product_id; + fido_dev_io_t io; + fido_dev_transport_t t; + + memset(&io, 0, sizeof(io)); + memset(&t, 0, sizeof(t)); + set_netlink_io_functions(fd_read, fd_write); + set_wire_data(p->netlink_wiredata.body, p->netlink_wiredata.len); + set_udev_parameters(p->uevent, &p->report_descriptor); + + ndevs = uniform_random(64); + if ((devlist = fido_dev_info_new(ndevs)) == NULL || + (devlist_set = fido_dev_info_new(1)) == NULL || + fido_dev_info_manifest(devlist, ndevs, &nfound) != FIDO_OK) + goto out; + for (size_t i = 0; i < nfound; i++) { + const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); + consume_str(fido_dev_info_path(di)); + consume_str(fido_dev_info_manufacturer_string(di)); + consume_str(fido_dev_info_product_string(di)); + vendor_id = fido_dev_info_vendor(di); + product_id = fido_dev_info_product(di); + consume(&vendor_id, sizeof(vendor_id)); + consume(&product_id, sizeof(product_id)); + fido_dev_info_set(devlist_set, 0, fido_dev_info_path(di), + fido_dev_info_manufacturer_string(di), + fido_dev_info_product_string(di), &io, &t); + } +out: + fido_dev_info_free(&devlist, ndevs); + fido_dev_info_free(&devlist_set, 1); +} + +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + get_usage(p); + get_report_len(p); + manifest(p); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_blob(&p->report_descriptor); + mutate_string(p->uevent); + } + + if (flags & MUTATE_WIREDATA) + mutate_blob(&p->netlink_wiredata); +} diff --git a/fuzz/fuzz_largeblob.c b/fuzz/fuzz_largeblob.c new file mode 100644 index 0000000..6cdc0c0 --- /dev/null +++ b/fuzz/fuzz_largeblob.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2020 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "dummy.h" + +#include "../openbsd-compat/openbsd-compat.h" + +/* Parameter set defining a FIDO2 "large blob" operation. */ +struct param { + char pin[MAXSTR]; + int seed; + struct blob key; + struct blob get_wiredata; + struct blob set_wiredata; +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'authenticatorLargeBlobs' 'get' command. + */ +static const uint8_t dummy_get_wiredata[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY +}; + +/* + * Collection of HID reports from an authenticator issued with a FIDO2 + * 'authenticatorLargeBlobs' 'set' command. + */ +static const uint8_t dummy_set_wiredata[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_PINTOKEN, + WIREDATA_CTAP_CBOR_STATUS +}; + +/* + * XXX this needs to match the encrypted blob embedded in + * WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY. + */ +static const uint8_t dummy_key[] = { + 0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79, + 0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6, + 0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32, + 0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 5 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->pin) < 0 || + unpack_blob(v[2], &p->key) < 0 || + unpack_blob(v[3], &p->get_wiredata) < 0 || + unpack_blob(v[4], &p->set_wiredata) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[5], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(5)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->pin)) == NULL || + (argv[2] = pack_blob(&p->key)) == NULL || + (argv[3] = pack_blob(&p->get_wiredata)) == NULL || + (argv[4] = pack_blob(&p->set_wiredata)) == NULL) + goto fail; + + for (size_t i = 0; i < 5; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 5; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + + dummy.get_wiredata.len = sizeof(dummy_get_wiredata); + dummy.set_wiredata.len = sizeof(dummy_set_wiredata); + dummy.key.len = sizeof(dummy_key); + + memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata, + dummy.get_wiredata.len); + memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata, + dummy.set_wiredata.len); + memcpy(&dummy.key.body, &dummy_key, dummy.key.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static fido_dev_t * +prepare_dev(void) +{ + fido_dev_t *dev; + + if ((dev = open_dev(0)) == NULL) + return NULL; + + return dev; +} + +static void +get_blob(const struct param *p, int array) +{ + fido_dev_t *dev; + u_char *ptr = NULL; + size_t len = 0; + + set_wire_data(p->get_wiredata.body, p->get_wiredata.len); + + if ((dev = prepare_dev()) == NULL) + return; + + if (array) + fido_dev_largeblob_get_array(dev, &ptr, &len); + else + fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len); + consume(ptr, len); + free(ptr); + + fido_dev_close(dev); + fido_dev_free(&dev); +} + + +static void +set_blob(const struct param *p, int op) +{ + fido_dev_t *dev; + const char *pin; + + set_wire_data(p->set_wiredata.body, p->set_wiredata.len); + + if ((dev = prepare_dev()) == NULL) + return; + pin = p->pin; + if (strlen(pin) == 0) + pin = NULL; + + switch (op) { + case 0: + fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin); + break; + case 1: + /* XXX reuse p->get_wiredata as the blob to be set */ + fido_dev_largeblob_set(dev, p->key.body, p->key.len, + p->get_wiredata.body, p->get_wiredata.len, pin); + break; + case 2: + /* XXX reuse p->get_wiredata as the body of the cbor array */ + fido_dev_largeblob_set_array(dev, p->get_wiredata.body, + p->get_wiredata.len, pin); + } + + fido_dev_close(dev); + fido_dev_free(&dev); +} + +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + get_blob(p, 0); + get_blob(p, 1); + set_blob(p, 0); + set_blob(p, 1); + set_blob(p, 2); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_blob(&p->key); + mutate_string(p->pin); + } + + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->get_wiredata); + mutate_blob(&p->set_wiredata); + } +} diff --git a/fuzz/fuzz_mgmt.c b/fuzz/fuzz_mgmt.c new file mode 100644 index 0000000..cbc313d --- /dev/null +++ b/fuzz/fuzz_mgmt.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2019-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "dummy.h" + +#include "../openbsd-compat/openbsd-compat.h" + +#define MAXRPID 64 + +struct param { + char pin1[MAXSTR]; + char pin2[MAXSTR]; + struct blob reset_wire_data; + struct blob info_wire_data; + struct blob set_pin_wire_data; + struct blob change_pin_wire_data; + struct blob retry_wire_data; + struct blob config_wire_data; + int seed; +}; + +static const uint8_t dummy_reset_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_CBOR_STATUS, +}; + +static const uint8_t dummy_info_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_INFO, +}; + +static const uint8_t dummy_set_pin_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_STATUS, +}; + +static const uint8_t dummy_change_pin_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_AUTHKEY, + WIREDATA_CTAP_CBOR_STATUS, +}; + +static const uint8_t dummy_retry_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_RETRIES, +}; + +static const uint8_t dummy_config_wire_data[] = { + WIREDATA_CTAP_INIT, + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_CBOR_STATUS, +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 9 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->pin1) < 0 || + unpack_string(v[2], p->pin2) < 0 || + unpack_blob(v[3], &p->reset_wire_data) < 0 || + unpack_blob(v[4], &p->info_wire_data) < 0 || + unpack_blob(v[5], &p->set_pin_wire_data) < 0 || + unpack_blob(v[6], &p->change_pin_wire_data) < 0 || + unpack_blob(v[7], &p->retry_wire_data) < 0 || + unpack_blob(v[8], &p->config_wire_data) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[9], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(9)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->pin1)) == NULL || + (argv[2] = pack_string(p->pin2)) == NULL || + (argv[3] = pack_blob(&p->reset_wire_data)) == NULL || + (argv[4] = pack_blob(&p->info_wire_data)) == NULL || + (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL || + (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL || + (argv[7] = pack_blob(&p->retry_wire_data)) == NULL || + (argv[8] = pack_blob(&p->config_wire_data)) == NULL) + goto fail; + + for (size_t i = 0; i < 9; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 9; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); + strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); + + dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); + dummy.info_wire_data.len = sizeof(dummy_info_wire_data); + dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); + dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); + dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); + dummy.config_wire_data.len = sizeof(dummy_config_wire_data); + + memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, + dummy.reset_wire_data.len); + memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, + dummy.info_wire_data.len); + memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, + dummy.set_pin_wire_data.len); + memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, + dummy.change_pin_wire_data.len); + memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, + dummy.retry_wire_data.len); + memcpy(&dummy.config_wire_data.body, &dummy_config_wire_data, + dummy.config_wire_data.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static void +dev_reset(const struct param *p) +{ + fido_dev_t *dev; + + set_wire_data(p->reset_wire_data.body, p->reset_wire_data.len); + + if ((dev = open_dev(0)) == NULL) + return; + + fido_dev_reset(dev); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_get_cbor_info(const struct param *p) +{ + fido_dev_t *dev; + fido_cbor_info_t *ci; + uint64_t n; + uint8_t proto, major, minor, build, flags; + bool v; + + set_wire_data(p->info_wire_data.body, p->info_wire_data.len); + + if ((dev = open_dev(0)) == NULL) + return; + + proto = fido_dev_protocol(dev); + major = fido_dev_major(dev); + minor = fido_dev_minor(dev); + build = fido_dev_build(dev); + flags = fido_dev_flags(dev); + + consume(&proto, sizeof(proto)); + consume(&major, sizeof(major)); + consume(&minor, sizeof(minor)); + consume(&build, sizeof(build)); + consume(&flags, sizeof(flags)); + + if ((ci = fido_cbor_info_new()) == NULL) + goto out; + + fido_dev_get_cbor_info(dev, ci); + + for (size_t i = 0; i < fido_cbor_info_versions_len(ci); i++) { + char * const *sa = fido_cbor_info_versions_ptr(ci); + consume(sa[i], strlen(sa[i])); + } + + for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { + char * const *sa = fido_cbor_info_extensions_ptr(ci); + consume(sa[i], strlen(sa[i])); + } + + for (size_t i = 0; i < fido_cbor_info_transports_len(ci); i++) { + char * const *sa = fido_cbor_info_transports_ptr(ci); + consume(sa[i], strlen(sa[i])); + } + + for (size_t i = 0; i < fido_cbor_info_options_len(ci); i++) { + char * const *sa = fido_cbor_info_options_name_ptr(ci); + const bool *va = fido_cbor_info_options_value_ptr(ci); + consume(sa[i], strlen(sa[i])); + consume(&va[i], sizeof(va[i])); + } + + /* +1 on purpose */ + for (size_t i = 0; i <= fido_cbor_info_algorithm_count(ci); i++) { + const char *type = fido_cbor_info_algorithm_type(ci, i); + int cose = fido_cbor_info_algorithm_cose(ci, i); + consume_str(type); + consume(&cose, sizeof(cose)); + } + + for (size_t i = 0; i < fido_cbor_info_certs_len(ci); i++) { + char * const *na = fido_cbor_info_certs_name_ptr(ci); + const uint64_t *va = fido_cbor_info_certs_value_ptr(ci); + consume(na[i], strlen(na[i])); + consume(&va[i], sizeof(va[i])); + } + + n = fido_cbor_info_maxmsgsiz(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_maxcredbloblen(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_maxcredcntlst(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_maxcredidlen(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_maxlargeblob(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_fwversion(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_minpinlen(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_maxrpid_minpinlen(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_uv_attempts(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_uv_modality(ci); + consume(&n, sizeof(n)); + n = (uint64_t)fido_cbor_info_rk_remaining(ci); + consume(&n, sizeof(n)); + + consume(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); + consume(fido_cbor_info_protocols_ptr(ci), + fido_cbor_info_protocols_len(ci)); + + v = fido_cbor_info_new_pin_required(ci); + consume(&v, sizeof(v)); + +out: + fido_dev_close(dev); + fido_dev_free(&dev); + + fido_cbor_info_free(&ci); +} + +static void +dev_set_pin(const struct param *p) +{ + fido_dev_t *dev; + + set_wire_data(p->set_pin_wire_data.body, p->set_pin_wire_data.len); + + if ((dev = open_dev(0)) == NULL) + return; + + fido_dev_set_pin(dev, p->pin1, NULL); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_change_pin(const struct param *p) +{ + fido_dev_t *dev; + + set_wire_data(p->change_pin_wire_data.body, p->change_pin_wire_data.len); + + if ((dev = open_dev(0)) == NULL) + return; + + fido_dev_set_pin(dev, p->pin2, p->pin1); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_get_retry_count(const struct param *p) +{ + fido_dev_t *dev; + int n = 0; + + set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); + + if ((dev = open_dev(0)) == NULL) + return; + + fido_dev_get_retry_count(dev, &n); + consume(&n, sizeof(n)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_get_uv_retry_count(const struct param *p) +{ + fido_dev_t *dev; + int n = 0; + + set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); + + if ((dev = open_dev(0)) == NULL) + return; + + fido_dev_get_uv_retry_count(dev, &n); + consume(&n, sizeof(n)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_enable_entattest(const struct param *p) +{ + fido_dev_t *dev; + const char *pin; + int r; + + set_wire_data(p->config_wire_data.body, p->config_wire_data.len); + if ((dev = open_dev(0)) == NULL) + return; + pin = p->pin1; + if (strlen(pin) == 0) + pin = NULL; + r = fido_dev_enable_entattest(dev, pin); + consume_str(fido_strerr(r)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_toggle_always_uv(const struct param *p) +{ + fido_dev_t *dev; + const char *pin; + int r; + + set_wire_data(p->config_wire_data.body, p->config_wire_data.len); + if ((dev = open_dev(0)) == NULL) + return; + pin = p->pin1; + if (strlen(pin) == 0) + pin = NULL; + r = fido_dev_toggle_always_uv(dev, pin); + consume_str(fido_strerr(r)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_force_pin_change(const struct param *p) +{ + fido_dev_t *dev; + const char *pin; + int r; + + set_wire_data(p->config_wire_data.body, p->config_wire_data.len); + if ((dev = open_dev(0)) == NULL) + return; + pin = p->pin1; + if (strlen(pin) == 0) + pin = NULL; + r = fido_dev_force_pin_change(dev, pin); + consume_str(fido_strerr(r)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_set_pin_minlen(const struct param *p) +{ + fido_dev_t *dev; + const char *pin; + int r; + + set_wire_data(p->config_wire_data.body, p->config_wire_data.len); + if ((dev = open_dev(0)) == NULL) + return; + pin = p->pin1; + if (strlen(pin) == 0) + pin = NULL; + r = fido_dev_set_pin_minlen(dev, strlen(p->pin2), pin); + consume_str(fido_strerr(r)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +static void +dev_set_pin_minlen_rpid(const struct param *p) +{ + fido_dev_t *dev; + const char *rpid[MAXRPID]; + const char *pin; + size_t n; + int r; + + set_wire_data(p->config_wire_data.body, p->config_wire_data.len); + if ((dev = open_dev(0)) == NULL) + return; + n = uniform_random(MAXRPID); + for (size_t i = 0; i < n; i++) + rpid[i] = dummy_rp_id; + pin = p->pin1; + if (strlen(pin) == 0) + pin = NULL; + r = fido_dev_set_pin_minlen_rpid(dev, rpid, n, pin); + consume_str(fido_strerr(r)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + dev_reset(p); + dev_get_cbor_info(p); + dev_set_pin(p); + dev_change_pin(p); + dev_get_retry_count(p); + dev_get_uv_retry_count(p); + dev_enable_entattest(p); + dev_toggle_always_uv(p); + dev_force_pin_change(p); + dev_set_pin_minlen(p); + dev_set_pin_minlen_rpid(p); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_string(p->pin1); + mutate_string(p->pin2); + } + + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->reset_wire_data); + mutate_blob(&p->info_wire_data); + mutate_blob(&p->set_pin_wire_data); + mutate_blob(&p->change_pin_wire_data); + mutate_blob(&p->retry_wire_data); + } +} diff --git a/fuzz/fuzz_netlink.c b/fuzz/fuzz_netlink.c new file mode 100644 index 0000000..4d28129 --- /dev/null +++ b/fuzz/fuzz_netlink.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2020 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "../openbsd-compat/openbsd-compat.h" +#include "mutator_aux.h" +#include "dummy.h" + +struct param { + int seed; + int dev; + struct blob wiredata; +}; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 3 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_int(v[1], &p->dev) < 0 || + unpack_blob(v[2], &p->wiredata) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[3], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(3)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_int(p->dev)) == NULL || + (argv[2] = pack_blob(&p->wiredata)) == NULL) + goto fail; + + for (size_t i = 0; i < 3; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 3; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + dummy.wiredata.len = sizeof(dummy_netlink_wiredata); + memcpy(&dummy.wiredata.body, &dummy_netlink_wiredata, + dummy.wiredata.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +void +test(const struct param *p) +{ + fido_nl_t *nl; + uint32_t target; + + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + set_netlink_io_functions(fd_read, fd_write); + set_wire_data(p->wiredata.body, p->wiredata.len); + + if ((nl = fido_nl_new()) == NULL) + return; + + consume(&nl->fd, sizeof(nl->fd)); + consume(&nl->nfc_type, sizeof(nl->nfc_type)); + consume(&nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)); + consume(&nl->saddr, sizeof(nl->saddr)); + + fido_nl_power_nfc(nl, (uint32_t)p->dev); + + if (fido_nl_get_nfc_target(nl, (uint32_t)p->dev, &target) == 0) + consume(&target, sizeof(target)); + + fido_nl_free(&nl); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) + mutate_int(&p->dev); + + if (flags & MUTATE_WIREDATA) + mutate_blob(&p->wiredata); +} diff --git a/fuzz/fuzz_pcsc.c b/fuzz/fuzz_pcsc.c new file mode 100644 index 0000000..cf6210b --- /dev/null +++ b/fuzz/fuzz_pcsc.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#define _FIDO_INTERNAL + +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "dummy.h" + +#include "../src/extern.h" + +struct param { + int seed; + char path[MAXSTR]; + struct blob pcsc_list; + struct blob tx_apdu; + struct blob wiredata_init; + struct blob wiredata_msg; +}; + +static const uint8_t dummy_tx_apdu[] = { WIREDATA_CTAP_EXTENDED_APDU }; +static const uint8_t dummy_wiredata_init[] = { WIREDATA_CTAP_NFC_INIT }; +static const uint8_t dummy_wiredata_msg[] = { WIREDATA_CTAP_NFC_MSG }; + +struct param * +unpack(const uint8_t *ptr, size_t len) +{ + cbor_item_t *item = NULL, **v; + struct cbor_load_result cbor; + struct param *p; + int ok = -1; + + if ((p = calloc(1, sizeof(*p))) == NULL || + (item = cbor_load(ptr, len, &cbor)) == NULL || + cbor.read != len || + cbor_isa_array(item) == false || + cbor_array_is_definite(item) == false || + cbor_array_size(item) != 6 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->path) < 0 || + unpack_blob(v[2], &p->pcsc_list) < 0 || + unpack_blob(v[3], &p->tx_apdu) < 0 || + unpack_blob(v[4], &p->wiredata_init) < 0 || + unpack_blob(v[5], &p->wiredata_msg) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; +} + +size_t +pack(uint8_t *ptr, size_t len, const struct param *p) +{ + cbor_item_t *argv[6], *array = NULL; + size_t cbor_alloc_len, cbor_len = 0; + unsigned char *cbor = NULL; + + memset(argv, 0, sizeof(argv)); + + if ((array = cbor_new_definite_array(6)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->path)) == NULL || + (argv[2] = pack_blob(&p->pcsc_list)) == NULL || + (argv[3] = pack_blob(&p->tx_apdu)) == NULL || + (argv[4] = pack_blob(&p->wiredata_init)) == NULL || + (argv[5] = pack_blob(&p->wiredata_msg)) == NULL) + goto fail; + + for (size_t i = 0; i < 6; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 6; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; +} + +size_t +pack_dummy(uint8_t *ptr, size_t len) +{ + struct param dummy; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.path, dummy_pcsc_path, sizeof(dummy.path)); + + dummy.pcsc_list.len = sizeof(dummy_pcsc_list); + memcpy(&dummy.pcsc_list.body, &dummy_pcsc_list, dummy.pcsc_list.len); + + dummy.tx_apdu.len = sizeof(dummy_tx_apdu); + memcpy(&dummy.tx_apdu.body, &dummy_tx_apdu, dummy.tx_apdu.len); + + dummy.wiredata_init.len = sizeof(dummy_wiredata_init); + memcpy(&dummy.wiredata_init.body, &dummy_wiredata_init, + dummy.wiredata_init.len); + + dummy.wiredata_msg.len = sizeof(dummy_wiredata_msg); + memcpy(&dummy.wiredata_msg.body, &dummy_wiredata_msg, + dummy.wiredata_msg.len); + + assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); + + if (blob_len > len) { + memcpy(ptr, blob, len); + return len; + } + + memcpy(ptr, blob, blob_len); + + return blob_len; +} + +static void +test_manifest(void) +{ + size_t ndevs, nfound; + fido_dev_info_t *devlist = NULL; + int16_t vendor_id, product_id; + int r; + + r = fido_pcsc_manifest(NULL, 0, &nfound); + assert(r == FIDO_OK && nfound == 0); + r = fido_pcsc_manifest(NULL, 1, &nfound); + assert(r == FIDO_ERR_INVALID_ARGUMENT); + + ndevs = uniform_random(64); + if ((devlist = fido_dev_info_new(ndevs)) == NULL || + fido_pcsc_manifest(devlist, ndevs, &nfound) != FIDO_OK) + goto out; + + for (size_t i = 0; i < nfound; i++) { + const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); + consume_str(fido_dev_info_path(di)); + consume_str(fido_dev_info_manufacturer_string(di)); + consume_str(fido_dev_info_product_string(di)); + vendor_id = fido_dev_info_vendor(di); + product_id = fido_dev_info_product(di); + consume(&vendor_id, sizeof(vendor_id)); + consume(&product_id, sizeof(product_id)); + } + +out: + fido_dev_info_free(&devlist, ndevs); +} + +static void +test_tx(const char *path, const struct blob *apdu, uint8_t cmd, u_char *rx_buf, + size_t rx_len) +{ + fido_dev_t dev; + const u_char *tx_ptr = NULL; + size_t tx_len = 0; + int n; + + memset(&dev, 0, sizeof(dev)); + + if (fido_dev_set_pcsc(&dev) < 0) + return; + if ((dev.io_handle = fido_pcsc_open(path)) == NULL) + return; + + if (apdu) { + tx_ptr = apdu->body; + tx_len = apdu->len; + } + + fido_pcsc_tx(&dev, cmd, tx_ptr, tx_len); + + if ((n = fido_pcsc_rx(&dev, cmd, rx_buf, rx_len, -1)) >= 0) + consume(rx_buf, n); + + fido_pcsc_close(dev.io_handle); +} + +static void +test_misc(void) +{ + assert(fido_pcsc_open(NULL) == NULL); + assert(fido_pcsc_write(NULL, NULL, INT_MAX + 1LL) == -1); +} + +void +test(const struct param *p) +{ + u_char buf[512]; + + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + set_pcsc_parameters(&p->pcsc_list); + set_pcsc_io_functions(nfc_read, nfc_write, consume); + + set_wire_data(p->wiredata_init.body, p->wiredata_init.len); + test_manifest(); + + test_misc(); + + set_wire_data(p->wiredata_init.body, p->wiredata_init.len); + test_tx(p->path, NULL, CTAP_CMD_INIT, buf, uniform_random(20)); + + set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len); + test_tx(p->path, &p->tx_apdu, CTAP_CMD_MSG, buf, sizeof(buf)); + + set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len); + test_tx(p->path, &p->tx_apdu, CTAP_CMD_CBOR, buf, sizeof(buf)); + + set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len); + test_tx(p->path, &p->tx_apdu, CTAP_CMD_LOCK, buf, sizeof(buf)); +} + +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN +{ + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_string(p->path); + mutate_blob(&p->pcsc_list); + mutate_blob(&p->tx_apdu); + } + + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->wiredata_init); + mutate_blob(&p->wiredata_msg); + } +} diff --git a/fuzz/libfuzzer.c b/fuzz/libfuzzer.c new file mode 100644 index 0000000..d712aa6 --- /dev/null +++ b/fuzz/libfuzzer.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" + +extern int fuzz_save_corpus; + +static bool debug; +static unsigned int flags = MUTATE_ALL; +static unsigned long long test_fail; +static unsigned long long test_total; +static unsigned long long mutate_fail; +static unsigned long long mutate_total; + +int LLVMFuzzerInitialize(int *, char ***); +int LLVMFuzzerTestOneInput(const uint8_t *, size_t); +size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); + +static int +save_seed(const char *opt) +{ + const char *path; + int fd = -1, status = 1; + void *buf = NULL; + const size_t buflen = MAXCORPUS; + size_t n; + struct param *p = NULL; + + if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) { + warnx("usage: --fido-save-seed="); + goto fail; + } + + if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) { + warn("open %s", path); + goto fail; + } + + if ((buf = malloc(buflen)) == NULL) { + warn("malloc"); + goto fail; + } + + n = pack_dummy(buf, buflen); + + if ((p = unpack(buf, n)) == NULL) { + warnx("unpack"); + goto fail; + } + + if (write(fd, buf, n) != (ssize_t)n) { + warn("write %s", path); + goto fail; + } + + status = 0; +fail: + if (fd != -1) + close(fd); + free(buf); + free(p); + + return status; +} + +static int +save_corpus(const struct param *p) +{ + uint8_t blob[MAXCORPUS], dgst[SHA256_DIGEST_LENGTH]; + size_t blob_len; + char path[PATH_MAX]; + int r, fd; + + if ((blob_len = pack(blob, sizeof(blob), p)) == 0 || + blob_len > sizeof(blob)) { + warnx("pack"); + return -1; + } + + if (SHA256(blob, blob_len, dgst) != dgst) { + warnx("sha256"); + return -1; + } + + if ((r = snprintf(path, sizeof(path), "saved_corpus_%02x%02x%02x%02x" + "%02x%02x%02x%02x", dgst[0], dgst[1], dgst[2], dgst[3], dgst[4], + dgst[5], dgst[6], dgst[7])) < 0 || (size_t)r >= sizeof(path)) { + warnx("snprintf"); + return -1; + } + + if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) { + warn("open %s", path); + return -1; + } + + if (write(fd, blob, blob_len) != (ssize_t)blob_len) { + warn("write"); + r = -1; + } else { + warnx("wrote %s", path); + r = 0; + } + + close(fd); + + return r; +} + +static void +parse_mutate_flags(const char *opt, unsigned int *mutate_flags) +{ + const char *f; + + if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0) + errx(1, "usage: --fido-mutate="); + + if (strcmp(f, "seed") == 0) + *mutate_flags |= MUTATE_SEED; + else if (strcmp(f, "param") == 0) + *mutate_flags |= MUTATE_PARAM; + else if (strcmp(f, "wiredata") == 0) + *mutate_flags |= MUTATE_WIREDATA; + else + errx(1, "--fido-mutate: unknown flag '%s'", f); +} + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + unsigned int mutate_flags = 0; + + for (int i = 0; i < *argc; i++) + if (strcmp((*argv)[i], "--fido-debug") == 0) { + debug = 1; + } else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) { + exit(save_seed((*argv)[i])); + } else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) { + parse_mutate_flags((*argv)[i], &mutate_flags); + } + + if (mutate_flags) + flags = mutate_flags; + + return 0; +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + struct param *p; + + if (size > MAXCORPUS) + return 0; + + if (++test_total % 100000 == 0 && debug) { + double r = (double)test_fail/(double)test_total * 100.0; + fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, + test_fail, test_total, r); + } + + if ((p = unpack(data, size)) == NULL) + test_fail++; + else { + fuzz_save_corpus = 0; + test(p); + if (fuzz_save_corpus && save_corpus(p) < 0) + fprintf(stderr, "%s: failed to save corpus\n", + __func__); + free(p); + } + + return 0; +} + +size_t +LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, + unsigned int seed) NO_MSAN +{ + struct param *p; + uint8_t blob[MAXCORPUS]; + size_t blob_len; + + memset(&p, 0, sizeof(p)); + +#ifdef WITH_MSAN + __msan_unpoison(data, maxsize); +#endif + + if (++mutate_total % 100000 == 0 && debug) { + double r = (double)mutate_fail/(double)mutate_total * 100.0; + fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, + mutate_fail, mutate_total, r); + } + + if ((p = unpack(data, size)) == NULL) { + mutate_fail++; + return pack_dummy(data, maxsize); + } + + mutate(p, seed, flags); + + if ((blob_len = pack(blob, sizeof(blob), p)) == 0 || + blob_len > sizeof(blob) || blob_len > maxsize) { + mutate_fail++; + free(p); + return 0; + } + + free(p); + + memcpy(data, blob, blob_len); + + return blob_len; +} diff --git a/fuzz/mutator_aux.c b/fuzz/mutator_aux.c new file mode 100644 index 0000000..ebddf10 --- /dev/null +++ b/fuzz/mutator_aux.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2019-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" + +int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int); +int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t); +size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); + +extern int prng_up; +static const uint8_t *wire_data_ptr = NULL; +static size_t wire_data_len = 0; + +void +consume(const void *body, size_t len) +{ + const volatile uint8_t *ptr = body; + volatile uint8_t x = 0; + +#ifdef WITH_MSAN + __msan_check_mem_is_initialized(body, len); +#endif + + while (len--) + x ^= *ptr++; + + (void)x; +} + +void +consume_str(const char *str) +{ + if (str != NULL) + consume(str, strlen(str) + 1); +} + +int +unpack_int(cbor_item_t *item, int *v) +{ + if (cbor_is_int(item) == false || + cbor_int_get_width(item) != CBOR_INT_64) + return -1; + + if (cbor_isa_uint(item)) + *v = (int)cbor_get_uint64(item); + else + *v = (int)(-cbor_get_uint64(item) - 1); + + return 0; +} + +int +unpack_string(cbor_item_t *item, char *v) +{ + size_t len; + + if (cbor_isa_bytestring(item) == false || + (len = cbor_bytestring_length(item)) >= MAXSTR) + return -1; + + memcpy(v, cbor_bytestring_handle(item), len); + v[len] = '\0'; + + return 0; +} + +int +unpack_byte(cbor_item_t *item, uint8_t *v) +{ + if (cbor_isa_uint(item) == false || + cbor_int_get_width(item) != CBOR_INT_8) + return -1; + + *v = cbor_get_uint8(item); + + return 0; +} + +int +unpack_blob(cbor_item_t *item, struct blob *v) +{ + if (cbor_isa_bytestring(item) == false || + (v->len = cbor_bytestring_length(item)) > sizeof(v->body)) + return -1; + + memcpy(v->body, cbor_bytestring_handle(item), v->len); + + return 0; +} + +cbor_item_t * +pack_int(int v) NO_MSAN +{ + if (v < 0) + return cbor_build_negint64((uint64_t)(-(int64_t)v - 1)); + else + return cbor_build_uint64((uint64_t)v); +} + +cbor_item_t * +pack_string(const char *v) NO_MSAN +{ + if (strlen(v) >= MAXSTR) + return NULL; + + return cbor_build_bytestring((const unsigned char *)v, strlen(v)); +} + +cbor_item_t * +pack_byte(uint8_t v) NO_MSAN +{ + return cbor_build_uint8(v); +} + +cbor_item_t * +pack_blob(const struct blob *v) NO_MSAN +{ + return cbor_build_bytestring(v->body, v->len); +} + +void +mutate_byte(uint8_t *b) +{ + LLVMFuzzerMutate(b, sizeof(*b), sizeof(*b)); +#ifdef WITH_MSAN + __msan_unpoison(b, sizeof(*b)); +#endif +} + +void +mutate_int(int *i) +{ + LLVMFuzzerMutate((uint8_t *)i, sizeof(*i), sizeof(*i)); +#ifdef WITH_MSAN + __msan_unpoison(i, sizeof(*i)); +#endif +} + +void +mutate_blob(struct blob *blob) +{ + blob->len = LLVMFuzzerMutate((uint8_t *)blob->body, blob->len, + sizeof(blob->body)); +} + +void +mutate_string(char *s) +{ + size_t n; + + n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); + s[n] = '\0'; +} + +static int +buf_read(unsigned char *ptr, size_t len, int ms) +{ + size_t n; + + (void)ms; + + if (prng_up && uniform_random(400) < 1) { + errno = EIO; + return -1; + } + + if (wire_data_len < len) + n = wire_data_len; + else + n = len; + + memcpy(ptr, wire_data_ptr, n); + + wire_data_ptr += n; + wire_data_len -= n; + + return (int)n; +} + +static int +buf_write(const unsigned char *ptr, size_t len) +{ + consume(ptr, len); + + if (prng_up && uniform_random(400) < 1) { + errno = EIO; + return -1; + } + + return (int)len; +} + +static void * +hid_open(const char *path) +{ + (void)path; + + return (void *)HID_DEV_HANDLE; +} + +static void +hid_close(void *handle) +{ + assert(handle == (void *)HID_DEV_HANDLE); +} + +static int +hid_read(void *handle, unsigned char *ptr, size_t len, int ms) +{ + assert(handle == (void *)HID_DEV_HANDLE); + assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN); + + return buf_read(ptr, len, ms); +} + +static int +hid_write(void *handle, const unsigned char *ptr, size_t len) +{ + assert(handle == (void *)HID_DEV_HANDLE); + assert(len >= CTAP_MIN_REPORT_LEN + 1 && + len <= CTAP_MAX_REPORT_LEN + 1); + + return buf_write(ptr, len); +} + +static void * +nfc_open(const char *path) +{ + (void)path; + + return (void *)NFC_DEV_HANDLE; +} + +static void +nfc_close(void *handle) +{ + assert(handle == (void *)NFC_DEV_HANDLE); +} + +int +nfc_read(void *handle, unsigned char *ptr, size_t len, int ms) +{ + assert(handle == (void *)NFC_DEV_HANDLE); + assert(len > 0 && len <= 264); + + return buf_read(ptr, len, ms); +} + +int +nfc_write(void *handle, const unsigned char *ptr, size_t len) +{ + assert(handle == (void *)NFC_DEV_HANDLE); + assert(len > 0 && len <= 256 + 2); + + return buf_write(ptr, len); +} + +ssize_t +fd_read(int fd, void *ptr, size_t len) +{ + assert(fd != -1); + + return buf_read(ptr, len, -1); +} + +ssize_t +fd_write(int fd, const void *ptr, size_t len) +{ + assert(fd != -1); + + return buf_write(ptr, len); +} + +fido_dev_t * +open_dev(int nfc) +{ + fido_dev_t *dev; + fido_dev_io_t io; + fido_dev_transport_t t; + + memset(&io, 0, sizeof(io)); + memset(&t, 0, sizeof(t)); + + if ((dev = fido_dev_new()) == NULL) + return NULL; + + if (nfc) { + io.open = nfc_open; + io.close = nfc_close; + io.read = nfc_read; + io.write = nfc_write; + } else { + io.open = hid_open; + io.close = hid_close; + io.read = hid_read; + io.write = hid_write; + } + + if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) + goto fail; + + if (nfc) { + t.rx = fido_nfc_rx; + t.tx = fido_nfc_tx; + if (fido_dev_set_transport_functions(dev, &t) != FIDO_OK) + goto fail; + } + + if (fido_dev_set_timeout(dev, 300) != FIDO_OK || + fido_dev_open(dev, "nodev") != FIDO_OK) + goto fail; + + return dev; +fail: + fido_dev_free(&dev); + + return NULL; +} + +void +set_wire_data(const uint8_t *ptr, size_t len) +{ + wire_data_ptr = ptr; + wire_data_len = len; +} diff --git a/fuzz/mutator_aux.h b/fuzz/mutator_aux.h new file mode 100644 index 0000000..5ad5661 --- /dev/null +++ b/fuzz/mutator_aux.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _MUTATOR_AUX_H +#define _MUTATOR_AUX_H + +#include + +#include +#include +#include + +#include "../src/fido.h" +#include "../src/fido/bio.h" +#include "../src/fido/config.h" +#include "../src/fido/credman.h" +#include "../src/fido/eddsa.h" +#include "../src/fido/es256.h" +#include "../src/fido/es384.h" +#include "../src/fido/rs256.h" +#include "../src/netlink.h" + +/* + * As of LLVM 10.0.0, MSAN support in libFuzzer was still experimental. + * We therefore have to be careful when using our custom mutator, or + * MSAN will flag uninitialised reads on memory populated by libFuzzer. + * Since there is no way to suppress MSAN without regenerating object + * code (in which case you might as well rebuild libFuzzer with MSAN), + * we adjust our mutator to make it less accurate while allowing + * fuzzing to proceed. + */ + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# define NO_MSAN __attribute__((no_sanitize("memory"))) +# define WITH_MSAN 1 +# endif +#endif + +#if !defined(WITH_MSAN) +# define NO_MSAN +#endif + +#define MUTATE_SEED 0x01 +#define MUTATE_PARAM 0x02 +#define MUTATE_WIREDATA 0x04 +#define MUTATE_ALL (MUTATE_SEED | MUTATE_PARAM | MUTATE_WIREDATA) + +#define MAXSTR 1024 +#define MAXBLOB 3600 +#define MAXCORPUS 8192 + +#define HID_DEV_HANDLE 0x68696421 +#define NFC_DEV_HANDLE 0x6e666321 + +struct blob { + uint8_t body[MAXBLOB]; + size_t len; +}; + +struct param; + +struct param *unpack(const uint8_t *, size_t); +size_t pack(uint8_t *, size_t, const struct param *); +size_t pack_dummy(uint8_t *, size_t); +void mutate(struct param *, unsigned int, unsigned int); +void test(const struct param *); + +void consume(const void *, size_t); +void consume_str(const char *); + +int unpack_blob(cbor_item_t *, struct blob *); +int unpack_byte(cbor_item_t *, uint8_t *); +int unpack_int(cbor_item_t *, int *); +int unpack_string(cbor_item_t *, char *); + +cbor_item_t *pack_blob(const struct blob *); +cbor_item_t *pack_byte(uint8_t); +cbor_item_t *pack_int(int); +cbor_item_t *pack_string(const char *); + +void mutate_byte(uint8_t *); +void mutate_int(int *); +void mutate_blob(struct blob *); +void mutate_string(char *); + +ssize_t fd_read(int, void *, size_t); +ssize_t fd_write(int, const void *, size_t); + +int nfc_read(void *, unsigned char *, size_t, int); +int nfc_write(void *, const unsigned char *, size_t); + +fido_dev_t *open_dev(int); +void set_wire_data(const uint8_t *, size_t); + +void fuzz_clock_reset(void); +void prng_init(unsigned long); +unsigned long prng_uint32(void); + +uint32_t uniform_random(uint32_t); + +void set_pcsc_parameters(const struct blob *); +void set_pcsc_io_functions(int (*)(void *, u_char *, size_t, int), + int (*)(void *, const u_char *, size_t), void (*)(const void *, size_t)); + +#endif /* !_MUTATOR_AUX_H */ diff --git a/fuzz/pcsc.c b/fuzz/pcsc.c new file mode 100644 index 0000000..f6a3e9b --- /dev/null +++ b/fuzz/pcsc.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" + +static const struct blob *reader_list; +static int (*xread)(void *, u_char *, size_t, int); +static int (*xwrite)(void *, const u_char *, size_t); +static void (*xconsume)(const void *, size_t); + +LONG __wrap_SCardEstablishContext(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT); +LONG __wrap_SCardListReaders(SCARDCONTEXT, LPCSTR, LPSTR, LPDWORD); +LONG __wrap_SCardReleaseContext(SCARDCONTEXT); +LONG __wrap_SCardConnect(SCARDCONTEXT, LPCSTR, DWORD, DWORD, LPSCARDHANDLE, + LPDWORD); +LONG __wrap_SCardDisconnect(SCARDHANDLE, DWORD); +LONG __wrap_SCardTransmit(SCARDHANDLE, const SCARD_IO_REQUEST *, LPCBYTE, + DWORD, SCARD_IO_REQUEST *, LPBYTE, LPDWORD); + +LONG +__wrap_SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, + LPCVOID pvReserved2, LPSCARDCONTEXT phContext) +{ + assert(dwScope == SCARD_SCOPE_SYSTEM); + assert(pvReserved1 == NULL); + assert(pvReserved2 == NULL); + + *phContext = 1; + + if (uniform_random(400) < 1) + return SCARD_E_NO_SERVICE; + if (uniform_random(400) < 1) + return SCARD_E_NO_SMARTCARD; + if (uniform_random(400) < 1) + return SCARD_E_NO_MEMORY; + if (uniform_random(400) < 1) + *phContext = 0; + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, + LPSTR mszReaders, LPDWORD pcchReaders) +{ + assert(hContext == 1); + assert(mszGroups == NULL); + assert(mszReaders != NULL); + assert(pcchReaders != 0); + + if (reader_list == NULL || uniform_random(400) < 1) + return SCARD_E_NO_READERS_AVAILABLE; + if (uniform_random(400) < 1) + return SCARD_E_NO_MEMORY; + + memcpy(mszReaders, reader_list->body, reader_list->len > *pcchReaders ? + *pcchReaders : reader_list->len); + *pcchReaders = (DWORD)reader_list->len; /* on purpose */ + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardReleaseContext(SCARDCONTEXT hContext) +{ + assert(hContext == 1); + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, + DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) +{ + uint32_t r; + + assert(hContext == 1); + xconsume(szReader, strlen(szReader) + 1); + assert(dwShareMode == SCARD_SHARE_SHARED); + assert(dwPreferredProtocols == SCARD_PROTOCOL_ANY); + assert(phCard != NULL); + assert(pdwActiveProtocol != NULL); + + if ((r = uniform_random(400)) < 1) + return SCARD_E_UNEXPECTED; + + *phCard = 1; + *pdwActiveProtocol = (r & 1) ? SCARD_PROTOCOL_T0 : SCARD_PROTOCOL_T1; + + if (uniform_random(400) < 1) + *pdwActiveProtocol = SCARD_PROTOCOL_RAW; + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + assert(hCard == 1); + assert(dwDisposition == SCARD_LEAVE_CARD); + + return SCARD_S_SUCCESS; +} + +extern void consume(const void *body, size_t len); + +LONG +__wrap_SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, + LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, + LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) +{ + void *ioh = (void *)NFC_DEV_HANDLE; + int n; + + assert(hCard == 1); + xconsume(pioSendPci, sizeof(*pioSendPci)); + xwrite(ioh, pbSendBuffer, cbSendLength); + assert(pioRecvPci == NULL); + + if (uniform_random(400) < 1 || + (n = xread(ioh, pbRecvBuffer, *pcbRecvLength, -1)) == -1) + return SCARD_E_UNEXPECTED; + *pcbRecvLength = (DWORD)n; + + return SCARD_S_SUCCESS; +} + +void +set_pcsc_parameters(const struct blob *reader_list_ptr) +{ + reader_list = reader_list_ptr; +} + +void +set_pcsc_io_functions(int (*read_f)(void *, u_char *, size_t, int), + int (*write_f)(void *, const u_char *, size_t), + void (*consume_f)(const void *, size_t)) +{ + xread = read_f; + xwrite = write_f; + xconsume = consume_f; +} diff --git a/fuzz/preload-fuzz.c b/fuzz/preload-fuzz.c new file mode 100644 index 0000000..f18848d --- /dev/null +++ b/fuzz/preload-fuzz.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2019 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * cc -fPIC -D_GNU_SOURCE -shared -o preload-fuzz.so preload-fuzz.c + * LD_PRELOAD=$(realpath preload-fuzz.so) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUZZ_DEV_PREFIX "nodev" + +static int fd_fuzz = -1; +static int (*open_f)(const char *, int, mode_t); +static int (*close_f)(int); +static ssize_t (*write_f)(int, const void *, size_t); + +int +open(const char *path, int flags, ...) +{ + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + + if (open_f == NULL) { + open_f = dlsym(RTLD_NEXT, "open"); + if (open_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EACCES; + return (-1); + } + } + + if (strncmp(path, FUZZ_DEV_PREFIX, strlen(FUZZ_DEV_PREFIX)) != 0) + return (open_f(path, flags, mode)); + + if (fd_fuzz != -1) { + warnx("%s: fd_fuzz != -1", __func__); + errno = EACCES; + return (-1); + } + + if ((fd_fuzz = dup(STDIN_FILENO)) < 0) { + warn("%s: dup", __func__); + errno = EACCES; + return (-1); + } + + return (fd_fuzz); +} + +int +close(int fd) +{ + if (close_f == NULL) { + close_f = dlsym(RTLD_NEXT, "close"); + if (close_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EACCES; + return (-1); + } + } + + if (fd == fd_fuzz) + fd_fuzz = -1; + + return (close_f(fd)); +} + +ssize_t +write(int fd, const void *buf, size_t nbytes) +{ + if (write_f == NULL) { + write_f = dlsym(RTLD_NEXT, "write"); + if (write_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EBADF; + return (-1); + } + } + + if (fd != fd_fuzz) + return (write_f(fd, buf, nbytes)); + + return (nbytes); +} diff --git a/fuzz/preload-snoop.c b/fuzz/preload-snoop.c new file mode 100644 index 0000000..34d57ad --- /dev/null +++ b/fuzz/preload-snoop.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2019 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * cc -fPIC -D_GNU_SOURCE -shared -o preload-snoop.so preload-snoop.c + * LD_PRELOAD=$(realpath preload-snoop.so) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SNOOP_DEV_PREFIX "/dev/hidraw" + +struct fd_tuple { + int snoop_in; + int snoop_out; + int real_dev; +}; + +static struct fd_tuple *fd_tuple; +static int (*open_f)(const char *, int, mode_t); +static int (*close_f)(int); +static ssize_t (*read_f)(int, void *, size_t); +static ssize_t (*write_f)(int, const void *, size_t); + +static int +get_fd(const char *hid_path, const char *suffix) +{ + char *s = NULL; + char path[PATH_MAX]; + int fd; + int r; + + if ((s = strdup(hid_path)) == NULL) { + warnx("%s: strdup", __func__); + return (-1); + } + + for (size_t i = 0; i < strlen(s); i++) + if (s[i] == '/') + s[i] = '_'; + + if ((r = snprintf(path, sizeof(path), "%s-%s", s, suffix)) < 0 || + (size_t)r >= sizeof(path)) { + warnx("%s: snprintf", __func__); + free(s); + return (-1); + } + + free(s); + s = NULL; + + if ((fd = open_f(path, O_CREAT | O_WRONLY, 0644)) < 0) { + warn("%s: open", __func__); + return (-1); + } + + return (fd); +} + +int +open(const char *path, int flags, ...) +{ + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + + if (open_f == NULL) { + open_f = dlsym(RTLD_NEXT, "open"); + if (open_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EACCES; + return (-1); + } + } + + if (strncmp(path, SNOOP_DEV_PREFIX, strlen(SNOOP_DEV_PREFIX)) != 0) + return (open_f(path, flags, mode)); + + if (fd_tuple != NULL) { + warnx("%s: fd_tuple != NULL", __func__); + errno = EACCES; + return (-1); + } + + if ((fd_tuple = calloc(1, sizeof(*fd_tuple))) == NULL) { + warn("%s: calloc", __func__); + errno = ENOMEM; + return (-1); + } + + fd_tuple->snoop_in = -1; + fd_tuple->snoop_out = -1; + fd_tuple->real_dev = -1; + + if ((fd_tuple->snoop_in = get_fd(path, "in")) < 0 || + (fd_tuple->snoop_out = get_fd(path, "out")) < 0 || + (fd_tuple->real_dev = open_f(path, flags, mode)) < 0) { + warn("%s: get_fd/open", __func__); + goto fail; + } + + return (fd_tuple->real_dev); +fail: + if (fd_tuple->snoop_in != -1) + close(fd_tuple->snoop_in); + if (fd_tuple->snoop_out != -1) + close(fd_tuple->snoop_out); + if (fd_tuple->real_dev != -1) + close(fd_tuple->real_dev); + + free(fd_tuple); + fd_tuple = NULL; + + errno = EACCES; + + return (-1); +} + +int +close(int fd) +{ + if (close_f == NULL) { + close_f = dlsym(RTLD_NEXT, "close"); + if (close_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EBADF; + return (-1); + } + } + + if (fd_tuple == NULL || fd_tuple->real_dev != fd) + return (close_f(fd)); + + close_f(fd_tuple->snoop_in); + close_f(fd_tuple->snoop_out); + close_f(fd_tuple->real_dev); + + free(fd_tuple); + fd_tuple = NULL; + + return (0); +} + +ssize_t +read(int fd, void *buf, size_t nbytes) +{ + ssize_t n; + + if (read_f == NULL) { + read_f = dlsym(RTLD_NEXT, "read"); + if (read_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EBADF; + return (-1); + } + } + + if (write_f == NULL) { + write_f = dlsym(RTLD_NEXT, "write"); + if (write_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EBADF; + return (-1); + } + } + + if (fd_tuple == NULL || fd_tuple->real_dev != fd) + return (read_f(fd, buf, nbytes)); + + if ((n = read_f(fd, buf, nbytes)) < 0 || + write_f(fd_tuple->snoop_in, buf, n) != n) + return (-1); + + return (n); +} + +ssize_t +write(int fd, const void *buf, size_t nbytes) +{ + ssize_t n; + + if (write_f == NULL) { + write_f = dlsym(RTLD_NEXT, "write"); + if (write_f == NULL) { + warnx("%s: dlsym", __func__); + errno = EBADF; + return (-1); + } + } + + if (fd_tuple == NULL || fd_tuple->real_dev != fd) + return (write_f(fd, buf, nbytes)); + + if ((n = write_f(fd, buf, nbytes)) < 0 || + write_f(fd_tuple->snoop_out, buf, n) != n) + return (-1); + + return (n); +} diff --git a/fuzz/prng.c b/fuzz/prng.c new file mode 100644 index 0000000..61114ac --- /dev/null +++ b/fuzz/prng.c @@ -0,0 +1,113 @@ +/* + A C-program for MT19937, with initialization improved 2002/1/26. + Coded by Takuji Nishimura and Makoto Matsumoto. + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) +*/ + +#include +#include +#include +#include "mutator_aux.h" + +#define init_genrand prng_init +#define genrand_int32 prng_uint32 + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +int prng_up = 0; +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializes mt[N] with a seed */ +void init_genrand(unsigned long s) +{ + mt[0]= s & 0xffffffffUL; + for (mti=1; mti> 30)) + + (unsigned long)mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } + prng_up = 1; +} + +/* generates a random number on [0,0xffffffff]-interval */ +unsigned long genrand_int32(void) +{ + unsigned long y; + static unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + assert(mti != N+1); + + for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} diff --git a/fuzz/report.tgz b/fuzz/report.tgz new file mode 100644 index 0000000..221648f Binary files /dev/null and b/fuzz/report.tgz differ diff --git a/fuzz/summary.txt b/fuzz/summary.txt new file mode 100644 index 0000000..011ce02 --- /dev/null +++ b/fuzz/summary.txt @@ -0,0 +1,64 @@ +Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +fuzz/clock.c 24 1 95.83% 4 0 100.00% 35 1 97.14% +fuzz/pcsc.c 59 0 100.00% 8 0 100.00% 75 12 84.00% +fuzz/prng.c 31 0 100.00% 2 0 100.00% 35 1 97.14% +fuzz/udev.c 110 2 98.18% 17 0 100.00% 126 12 90.48% +fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 12 1 91.67% +fuzz/wrap.c 23 0 100.00% 3 0 100.00% 29 0 100.00% +openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 7 0 100.00% +openbsd-compat/freezero.c 4 0 100.00% 1 0 100.00% 6 0 100.00% +openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 36 7 80.56% +openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 7 0 100.00% +src/aes256.c 118 3 97.46% 8 0 100.00% 157 11 92.99% +src/assert.c 628 45 92.83% 63 4 93.65% 782 51 93.48% +src/authkey.c 52 0 100.00% 5 0 100.00% 66 0 100.00% +src/bio.c 458 20 95.63% 50 2 96.00% 592 24 95.95% +src/blob.c 53 2 96.23% 10 0 100.00% 83 4 95.18% +src/buf.c 8 0 100.00% 2 0 100.00% 16 0 100.00% +src/cbor.c 1070 12 98.88% 55 0 100.00% 1258 28 97.77% +src/compress.c 105 14 86.67% 5 0 100.00% 122 24 80.33% +src/config.c 112 0 100.00% 11 0 100.00% 154 0 100.00% +src/cred.c 653 36 94.49% 70 2 97.14% 853 39 95.43% +src/credman.c 428 10 97.66% 41 0 100.00% 562 20 96.44% +src/dev.c 344 65 81.10% 41 6 85.37% 383 80 79.11% +src/ecdh.c 117 2 98.29% 4 0 100.00% 146 5 96.58% +src/eddsa.c 88 5 94.32% 10 0 100.00% 114 9 92.11% +src/err.c 122 10 91.80% 1 0 100.00% 126 10 92.06% +src/es256.c 315 5 98.41% 19 0 100.00% 372 11 97.04% +src/es384.c 158 5 96.84% 11 0 100.00% 198 11 94.44% +src/hid.c 87 2 97.70% 14 0 100.00% 145 3 97.93% +src/hid_linux.c 202 73 63.86% 14 7 50.00% 277 115 58.48% +src/hid_unix.c 29 21 27.59% 2 0 100.00% 43 26 39.53% +src/info.c 232 0 100.00% 51 0 100.00% 409 0 100.00% +src/io.c 193 7 96.37% 13 0 100.00% 230 12 94.78% +src/iso7816.c 18 1 94.44% 5 0 100.00% 38 1 97.37% +src/largeblob.c 525 18 96.57% 30 0 100.00% 693 43 93.80% +src/log.c 39 5 87.18% 7 1 85.71% 63 7 88.89% +src/netlink.c 329 8 97.57% 40 0 100.00% 498 15 96.99% +src/nfc.c 155 3 98.06% 12 0 100.00% 244 9 96.31% +src/nfc_linux.c 172 73 57.56% 13 6 53.85% 242 114 52.89% +src/pcsc.c 204 1 99.51% 13 0 100.00% 282 3 98.94% +src/pin.c 430 3 99.30% 26 0 100.00% 516 4 99.22% +src/random.c 6 0 100.00% 1 0 100.00% 6 0 100.00% +src/reset.c 24 0 100.00% 3 0 100.00% 23 0 100.00% +src/rs1.c 22 2 90.91% 3 0 100.00% 36 6 83.33% +src/rs256.c 146 9 93.84% 13 0 100.00% 179 16 91.06% +src/time.c 43 3 93.02% 3 0 100.00% 43 2 95.35% +src/touch.c 67 0 100.00% 2 0 100.00% 79 0 100.00% +src/tpm.c 103 0 100.00% 9 0 100.00% 194 0 100.00% +src/types.c 29 0 100.00% 7 0 100.00% 56 0 100.00% +src/u2f.c 572 4 99.30% 17 0 100.00% 726 12 98.35% +src/util.c 14 1 92.86% 1 0 100.00% 14 1 92.86% + +Files which contain no functions: +fuzz/mutator_aux.h 0 0 - 0 0 - 0 0 - +openbsd-compat/openbsd-compat.h 0 0 - 0 0 - 0 0 - +openbsd-compat/time.h 0 0 - 0 0 - 0 0 - +src/extern.h 0 0 - 0 0 - 0 0 - +src/fallthrough.h 0 0 - 0 0 - 0 0 - +src/fido.h 0 0 - 0 0 - 0 0 - +src/fido/err.h 0 0 - 0 0 - 0 0 - +src/fido/param.h 0 0 - 0 0 - 0 0 - +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +TOTAL 8777 479 94.54% 744 28 96.24% 11388 750 93.41% diff --git a/fuzz/udev.c b/fuzz/udev.c new file mode 100644 index 0000000..3194012 --- /dev/null +++ b/fuzz/udev.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "mutator_aux.h" + +struct udev { + int magic; +}; + +struct udev_enumerate { + int magic; + struct udev_list_entry *list_entry; +}; + +struct udev_list_entry { + int magic; +}; + +struct udev_device { + int magic; + struct udev_device *parent; +}; + +#define UDEV_MAGIC 0x584492cc +#define UDEV_DEVICE_MAGIC 0x569180dd +#define UDEV_LIST_ENTRY_MAGIC 0x497422ee +#define UDEV_ENUM_MAGIC 0x583570ff + +#define ASSERT_TYPE(x, m) assert((x) != NULL && (x)->magic == (m)) +#define ASSERT_UDEV(x) ASSERT_TYPE((x), UDEV_MAGIC) +#define ASSERT_UDEV_ENUM(x) ASSERT_TYPE((x), UDEV_ENUM_MAGIC) +#define ASSERT_UDEV_LIST_ENTRY(x) ASSERT_TYPE((x), UDEV_LIST_ENTRY_MAGIC) +#define ASSERT_UDEV_DEVICE(x) ASSERT_TYPE((x), UDEV_DEVICE_MAGIC) + +static const char *uevent; +static const struct blob *report_descriptor; + +struct udev *__wrap_udev_new(void); +struct udev_device *__wrap_udev_device_get_parent_with_subsystem_devtype( + struct udev_device *, const char *, const char *); +struct udev_device *__wrap_udev_device_new_from_syspath(struct udev *, + const char *); +struct udev_enumerate *__wrap_udev_enumerate_new(struct udev *); +struct udev_list_entry *__wrap_udev_enumerate_get_list_entry( + struct udev_enumerate *); +struct udev_list_entry *__wrap_udev_list_entry_get_next( + struct udev_list_entry *); +const char *__wrap_udev_device_get_sysattr_value(struct udev_device *, + const char *); +const char *__wrap_udev_list_entry_get_name(struct udev_list_entry *); +const char *__wrap_udev_device_get_devnode(struct udev_device *); +const char *__wrap_udev_device_get_sysnum(struct udev_device *); +int __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *, + const char *); +int __wrap_udev_enumerate_scan_devices(struct udev_enumerate *); +int __wrap_ioctl(int, unsigned long , ...); +void __wrap_udev_device_unref(struct udev_device *); +void __wrap_udev_enumerate_unref(struct udev_enumerate *); +void __wrap_udev_unref(struct udev *); +void set_udev_parameters(const char *, const struct blob *); + +struct udev_device * +__wrap_udev_device_get_parent_with_subsystem_devtype(struct udev_device *child, + const char *subsystem, const char *devtype) +{ + ASSERT_UDEV_DEVICE(child); + fido_log_debug("%s", subsystem); /* XXX consume */ + fido_log_debug("%s", devtype); /* XXX consume */ + if (child->parent != NULL) + return child->parent; + if ((child->parent = calloc(1, sizeof(*child->parent))) == NULL) + return NULL; + child->parent->magic = UDEV_DEVICE_MAGIC; + + return child->parent; +} + +const char * +__wrap_udev_device_get_sysattr_value(struct udev_device *udev_device, + const char *sysattr) +{ + ASSERT_UDEV_DEVICE(udev_device); + if (uniform_random(400) < 1) + return NULL; + if (!strcmp(sysattr, "manufacturer") || !strcmp(sysattr, "product")) + return "product info"; /* XXX randomise? */ + else if (!strcmp(sysattr, "uevent")) + return uevent; + + return NULL; +} + +const char * +__wrap_udev_list_entry_get_name(struct udev_list_entry *entry) +{ + ASSERT_UDEV_LIST_ENTRY(entry); + return uniform_random(400) < 1 ? NULL : "name"; /* XXX randomise? */ +} + +struct udev_device * +__wrap_udev_device_new_from_syspath(struct udev *udev, const char *syspath) +{ + struct udev_device *udev_device; + + ASSERT_UDEV(udev); + fido_log_debug("%s", syspath); + if ((udev_device = calloc(1, sizeof(*udev_device))) == NULL) + return NULL; + udev_device->magic = UDEV_DEVICE_MAGIC; + + return udev_device; +} + +const char * +__wrap_udev_device_get_devnode(struct udev_device *udev_device) +{ + ASSERT_UDEV_DEVICE(udev_device); + return uniform_random(400) < 1 ? NULL : "/dev/zero"; +} + +const char * +__wrap_udev_device_get_sysnum(struct udev_device *udev_device) +{ + ASSERT_UDEV_DEVICE(udev_device); + return uniform_random(400) < 1 ? NULL : "101010"; /* XXX randomise? */ +} + +void +__wrap_udev_device_unref(struct udev_device *udev_device) +{ + ASSERT_UDEV_DEVICE(udev_device); + if (udev_device->parent) { + ASSERT_UDEV_DEVICE(udev_device->parent); + free(udev_device->parent); + } + free(udev_device); +} + +struct udev * +__wrap_udev_new(void) +{ + struct udev *udev; + + if ((udev = calloc(1, sizeof(*udev))) == NULL) + return NULL; + udev->magic = UDEV_MAGIC; + + return udev; +} + +struct udev_enumerate * +__wrap_udev_enumerate_new(struct udev *udev) +{ + struct udev_enumerate *udev_enum; + + ASSERT_UDEV(udev); + if ((udev_enum = calloc(1, sizeof(*udev_enum))) == NULL) + return NULL; + udev_enum->magic = UDEV_ENUM_MAGIC; + + return udev_enum; +} + +int +__wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum, + const char *subsystem) +{ + ASSERT_UDEV_ENUM(udev_enum); + fido_log_debug("%s:", subsystem); + return uniform_random(400) < 1 ? -EINVAL : 0; +} + +int +__wrap_udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) +{ + ASSERT_UDEV_ENUM(udev_enum); + return uniform_random(400) < 1 ? -EINVAL : 0; +} + +struct udev_list_entry * +__wrap_udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) +{ + ASSERT_UDEV_ENUM(udev_enum); + if ((udev_enum->list_entry = calloc(1, + sizeof(*udev_enum->list_entry))) == NULL) + return NULL; + udev_enum->list_entry->magic = UDEV_LIST_ENTRY_MAGIC; + + return udev_enum->list_entry; +} + +struct udev_list_entry * +__wrap_udev_list_entry_get_next(struct udev_list_entry *udev_list_entry) +{ + ASSERT_UDEV_LIST_ENTRY(udev_list_entry); + return uniform_random(400) < 1 ? NULL : udev_list_entry; +} + +void +__wrap_udev_enumerate_unref(struct udev_enumerate *udev_enum) +{ + ASSERT_UDEV_ENUM(udev_enum); + if (udev_enum->list_entry) + ASSERT_UDEV_LIST_ENTRY(udev_enum->list_entry); + free(udev_enum->list_entry); + free(udev_enum); +} + +void +__wrap_udev_unref(struct udev *udev) +{ + ASSERT_UDEV(udev); + free(udev); +} + +int +__wrap_ioctl(int fd, unsigned long request, ...) +{ + va_list ap; + struct hidraw_report_descriptor *hrd; + + (void)fd; + + if (uniform_random(400) < 1) { + errno = EINVAL; + return -1; + } + + va_start(ap, request); + + switch (IOCTL_REQ(request)) { + case IOCTL_REQ(HIDIOCGRDESCSIZE): + *va_arg(ap, int *) = (int)report_descriptor->len; + break; + case IOCTL_REQ(HIDIOCGRDESC): + hrd = va_arg(ap, struct hidraw_report_descriptor *); + assert(hrd->size == report_descriptor->len); + memcpy(hrd->value, report_descriptor->body, hrd->size); + break; + default: + warnx("%s: unknown request 0x%lx", __func__, request); + abort(); + } + + va_end(ap); + + return 0; +} + +void +set_udev_parameters(const char *uevent_ptr, + const struct blob *report_descriptor_ptr) +{ + uevent = uevent_ptr; + report_descriptor = report_descriptor_ptr; +} diff --git a/fuzz/uniform_random.c b/fuzz/uniform_random.c new file mode 100644 index 0000000..357091c --- /dev/null +++ b/fuzz/uniform_random.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008, Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +uint32_t uniform_random(uint32_t); +unsigned long prng_uint32(void); + +/* + * Calculate a uniformly distributed random number less than upper_bound + * avoiding "modulo bias". + * + * Uniformity is achieved by generating new random numbers until the one + * returned is outside the range [0, 2**32 % upper_bound). This + * guarantees the selected random number will be inside + * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) + * after reduction modulo upper_bound. + */ +uint32_t +uniform_random(uint32_t upper_bound) +{ + uint32_t r, min; + + if (upper_bound < 2) + return 0; + + /* 2**32 % x == (2**32 - x) % x */ + min = -upper_bound % upper_bound; + + /* + * This could theoretically loop forever but each retry has + * p > 0.5 (worst case, usually far better) of selecting a + * number inside the range we need, so it should rarely need + * to re-roll. + */ + for (;;) { + r = (uint32_t)prng_uint32(); + if (r >= min) + break; + } + + return r % upper_bound; +} diff --git a/fuzz/wiredata_fido2.h b/fuzz/wiredata_fido2.h new file mode 100644 index 0000000..6c66c54 --- /dev/null +++ b/fuzz/wiredata_fido2.h @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2020-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _WIREDATA_FIDO2_H +#define _WIREDATA_FIDO2_H + +#define WIREDATA_CTAP_INIT \ + 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x80, \ + 0x43, 0x56, 0x40, 0xb1, 0x4e, 0xd9, 0x2d, 0x00, \ + 0x22, 0x00, 0x02, 0x02, 0x05, 0x02, 0x01, 0x05, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_KEEPALIVE \ + 0x00, 0x22, 0x00, 0x02, 0xbb, 0x00, 0x01, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_INFO \ + 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0xb9, 0x00, \ + 0xa9, 0x01, 0x83, 0x66, 0x55, 0x32, 0x46, 0x5f, \ + 0x56, 0x32, 0x68, 0x46, 0x49, 0x44, 0x4f, 0x5f, \ + 0x32, 0x5f, 0x30, 0x6c, 0x46, 0x49, 0x44, 0x4f, \ + 0x5f, 0x32, 0x5f, 0x31, 0x5f, 0x50, 0x52, 0x45, \ + 0x02, 0x82, 0x6b, 0x63, 0x72, 0x65, 0x64, 0x50, \ + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x6b, 0x68, \ + 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, \ + 0x00, 0x22, 0x00, 0x02, 0x00, 0x65, 0x74, 0x03, \ + 0x50, 0x19, 0x56, 0xe5, 0xbd, 0xa3, 0x74, 0x45, \ + 0xf1, 0xa8, 0x14, 0x35, 0x64, 0x03, 0xfd, 0xbc, \ + 0x18, 0x04, 0xa5, 0x62, 0x72, 0x6b, 0xf5, 0x62, \ + 0x75, 0x70, 0xf5, 0x64, 0x70, 0x6c, 0x61, 0x74, \ + 0xf4, 0x69, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, \ + 0x50, 0x69, 0x6e, 0xf4, 0x75, 0x63, 0x72, 0x65, \ + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4d, \ + 0x00, 0x22, 0x00, 0x02, 0x01, 0x67, 0x6d, 0x74, \ + 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0xf5, \ + 0x05, 0x19, 0x04, 0xb0, 0x06, 0x81, 0x01, 0x07, \ + 0x08, 0x08, 0x18, 0x80, 0x0a, 0x82, 0xa2, 0x63, \ + 0x61, 0x6c, 0x67, 0x26, 0x64, 0x74, 0x79, 0x70, \ + 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, \ + 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, \ + 0x67, 0x27, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, \ + 0x00, 0x22, 0x00, 0x02, 0x02, 0x70, 0x75, 0x62, \ + 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_AUTHKEY \ + 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x51, 0x00, \ + 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, \ + 0x20, 0x01, 0x21, 0x58, 0x20, 0x2a, 0xb8, 0x2d, \ + 0x36, 0x69, 0xab, 0x30, 0x9d, 0xe3, 0x5e, 0x9b, \ + 0xfb, 0x94, 0xfc, 0x1d, 0x92, 0x95, 0xaf, 0x01, \ + 0x47, 0xfe, 0x4b, 0x87, 0xe5, 0xcf, 0x3f, 0x05, \ + 0x0b, 0x39, 0xda, 0x17, 0x49, 0x22, 0x58, 0x20, \ + 0x15, 0x1b, 0xbe, 0x08, 0x78, 0x60, 0x4d, 0x3c, \ + 0x00, 0x22, 0x00, 0x02, 0x00, 0x3f, 0xf1, 0x60, \ + 0xa6, 0xd8, 0xf8, 0xed, 0xce, 0x4a, 0x30, 0x5d, \ + 0x1a, 0xaf, 0x80, 0xc4, 0x0a, 0xd2, 0x6f, 0x77, \ + 0x38, 0x12, 0x97, 0xaa, 0xbd, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_PINTOKEN \ + 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x14, 0x00, \ + 0xa1, 0x02, 0x50, 0xee, 0x40, 0x4c, 0x85, 0xd7, \ + 0xa1, 0x2f, 0x56, 0xc4, 0x4e, 0xc5, 0x93, 0x41, \ + 0xd0, 0x3b, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_STATUS \ + 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x01, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_RETRIES \ + 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x04, 0x00, \ + 0xa1, 0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_ASSERT \ + 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0xcb, 0x00, \ + 0xa3, 0x01, 0xa2, 0x62, 0x69, 0x64, 0x58, 0x40, \ + 0x4a, 0x4c, 0x9e, 0xcc, 0x81, 0x7d, 0x42, 0x03, \ + 0x2b, 0x41, 0xd1, 0x38, 0xd3, 0x49, 0xb4, 0xfc, \ + 0xfb, 0xe4, 0x4e, 0xe4, 0xff, 0x76, 0x34, 0x16, \ + 0x68, 0x06, 0x9d, 0xa6, 0x01, 0x32, 0xb9, 0xff, \ + 0xc2, 0x35, 0x0d, 0x89, 0x43, 0x66, 0x12, 0xf8, \ + 0x8e, 0x5b, 0xde, 0xf4, 0xcc, 0xec, 0x9d, 0x03, \ + 0x00, 0x92, 0x00, 0x0e, 0x00, 0x85, 0xc2, 0xf5, \ + 0xe6, 0x8e, 0xeb, 0x3f, 0x3a, 0xec, 0xc3, 0x1d, \ + 0x04, 0x6e, 0xf3, 0x5b, 0x88, 0x64, 0x74, 0x79, \ + 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, \ + 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x02, 0x58, 0x25, \ + 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, \ + 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, \ + 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, \ + 0x00, 0x92, 0x00, 0x0e, 0x01, 0x99, 0x5c, 0xf3, \ + 0xba, 0x83, 0x1d, 0x97, 0x63, 0x04, 0x00, 0x00, \ + 0x00, 0x09, 0x03, 0x58, 0x47, 0x30, 0x45, 0x02, \ + 0x21, 0x00, 0xcf, 0x3f, 0x36, 0x0e, 0x1f, 0x6f, \ + 0xd6, 0xa0, 0x9d, 0x13, 0xcf, 0x55, 0xf7, 0x49, \ + 0x8f, 0xc8, 0xc9, 0x03, 0x12, 0x76, 0x41, 0x75, \ + 0x7b, 0xb5, 0x0a, 0x90, 0xa5, 0x82, 0x26, 0xf1, \ + 0x6b, 0x80, 0x02, 0x20, 0x34, 0x9b, 0x7a, 0x82, \ + 0x00, 0x92, 0x00, 0x0e, 0x02, 0xd3, 0xe1, 0x79, \ + 0x49, 0x55, 0x41, 0x9f, 0xa4, 0x06, 0x06, 0xbd, \ + 0xc8, 0xb9, 0x2b, 0x5f, 0xe1, 0xa7, 0x99, 0x1c, \ + 0xa1, 0xfc, 0x7e, 0x3e, 0xd5, 0x85, 0x2e, 0x11, \ + 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_CRED \ + 0x00, 0x91, 0x00, 0x03, 0x90, 0x03, 0xe1, 0x00, \ + 0xa3, 0x01, 0x66, 0x70, 0x61, 0x63, 0x6b, 0x65, \ + 0x64, 0x02, 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, \ + 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, \ + 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, \ + 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, \ + 0x83, 0x1d, 0x97, 0x63, 0x45, 0x00, 0x00, 0x00, \ + 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, \ + 0x00, 0x91, 0x00, 0x03, 0x00, 0x15, 0x80, 0x06, \ + 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, \ + 0xed, 0x88, 0x48, 0xa1, 0xdb, 0x56, 0x4d, 0x0f, \ + 0x0d, 0xc8, 0x8f, 0x0f, 0xe9, 0x16, 0xb1, 0x78, \ + 0xa9, 0x40, 0x98, 0x71, 0xa0, 0xb3, 0xf2, 0xcf, \ + 0x05, 0x73, 0x6c, 0x12, 0xbf, 0x00, 0x96, 0xf3, \ + 0x7b, 0x93, 0xba, 0x49, 0xee, 0x23, 0xb4, 0x78, \ + 0x2e, 0xfb, 0xce, 0x27, 0xa8, 0xc2, 0x26, 0x78, \ + 0x00, 0x91, 0x00, 0x03, 0x01, 0xcc, 0x95, 0x2d, \ + 0x40, 0xdb, 0xd1, 0x40, 0x3d, 0x2b, 0xa3, 0x31, \ + 0xa0, 0x75, 0x82, 0x63, 0xf0, 0xa5, 0x01, 0x02, \ + 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x9d, \ + 0x95, 0xa1, 0xb5, 0xd6, 0x11, 0xbf, 0xe2, 0x28, \ + 0xa0, 0x7f, 0xca, 0x1e, 0xd9, 0x09, 0x0f, 0x0d, \ + 0xe7, 0x8e, 0x29, 0xe8, 0x2e, 0x11, 0xdb, 0x55, \ + 0x62, 0x13, 0xd7, 0x26, 0xc2, 0x7e, 0x2b, 0x22, \ + 0x00, 0x91, 0x00, 0x03, 0x02, 0x58, 0x20, 0xbe, \ + 0x74, 0x2a, 0xac, 0xde, 0x11, 0x40, 0x76, 0x31, \ + 0x0b, 0xed, 0x55, 0xde, 0xf3, 0x03, 0xe4, 0x1c, \ + 0xac, 0x42, 0x63, 0x8f, 0xe8, 0x30, 0x63, 0xb7, \ + 0x07, 0x4e, 0x5d, 0xfb, 0x17, 0x5e, 0x9b, 0x03, \ + 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, \ + 0x69, 0x67, 0x58, 0x48, 0x30, 0x46, 0x02, 0x21, \ + 0x00, 0xfb, 0xd1, 0x26, 0x76, 0x34, 0x74, 0xac, \ + 0x00, 0x91, 0x00, 0x03, 0x03, 0xf6, 0xd8, 0x5c, \ + 0x5d, 0xbc, 0xda, 0xe0, 0x43, 0xe0, 0xa5, 0x42, \ + 0x9f, 0xc7, 0xe2, 0x18, 0x3e, 0xe2, 0x2c, 0x94, \ + 0x78, 0xbf, 0x9c, 0xeb, 0x3e, 0x9d, 0x02, 0x21, \ + 0x00, 0xab, 0x21, 0x1b, 0xc4, 0x30, 0x69, 0xee, \ + 0x7f, 0x09, 0xe6, 0x6b, 0x99, 0x98, 0x34, 0x07, \ + 0x7b, 0x9a, 0x58, 0xb2, 0xe8, 0x77, 0xe0, 0xba, \ + 0x7d, 0xab, 0x65, 0xf8, 0xba, 0x2a, 0xcb, 0x9a, \ + 0x00, 0x91, 0x00, 0x03, 0x04, 0x41, 0x63, 0x78, \ + 0x35, 0x63, 0x81, 0x59, 0x02, 0xb3, 0x30, 0x82, \ + 0x02, 0xaf, 0x30, 0x82, 0x01, 0x97, 0xa0, 0x03, \ + 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x5b, 0x3d, \ + 0xb6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, \ + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, \ + 0x30, 0x21, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, \ + 0x55, 0x04, 0x03, 0x0c, 0x16, 0x59, 0x75, 0x62, \ + 0x00, 0x91, 0x00, 0x03, 0x05, 0x69, 0x63, 0x6f, \ + 0x20, 0x46, 0x49, 0x44, 0x4f, 0x20, 0x50, 0x72, \ + 0x65, 0x76, 0x69, 0x65, 0x77, 0x20, 0x43, 0x41, \ + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, \ + 0x31, 0x32, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, \ + 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x32, 0x33, \ + 0x31, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, 0x5a, \ + 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ + 0x00, 0x91, 0x00, 0x03, 0x06, 0x55, 0x04, 0x06, \ + 0x13, 0x02, 0x53, 0x45, 0x31, 0x12, 0x30, 0x10, \ + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x59, \ + 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x41, 0x42, \ + 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, \ + 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, \ + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, \ + 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, \ + 0x00, 0x91, 0x00, 0x03, 0x07, 0x74, 0x69, 0x6f, \ + 0x6e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, \ + 0x04, 0x03, 0x0c, 0x1f, 0x59, 0x75, 0x62, 0x69, \ + 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, \ + 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, \ + 0x20, 0x31, 0x32, 0x31, 0x33, 0x39, 0x33, 0x39, \ + 0x31, 0x32, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, \ + 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, \ + 0x00, 0x91, 0x00, 0x03, 0x08, 0x06, 0x08, 0x2a, \ + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, \ + 0x42, 0x00, 0x04, 0xfb, 0x2c, 0xdd, 0x30, 0x43, \ + 0x28, 0xc5, 0x72, 0x4a, 0x50, 0xcc, 0xe6, 0xf6, \ + 0x0b, 0xad, 0x7d, 0x27, 0xa9, 0x1b, 0x59, 0xe1, \ + 0xe6, 0x6f, 0x29, 0x7b, 0x89, 0xc9, 0xd4, 0x3d, \ + 0xc2, 0xb2, 0xc7, 0x78, 0x89, 0xb4, 0xf0, 0xff, \ + 0x9d, 0x02, 0x28, 0xcb, 0x94, 0x6d, 0xfc, 0xe0, \ + 0x00, 0x91, 0x00, 0x03, 0x09, 0x1b, 0x19, 0x58, \ + 0x9b, 0x67, 0x80, 0x4a, 0xac, 0x97, 0x7f, 0x28, \ + 0x18, 0x9c, 0xcd, 0xb3, 0x25, 0x74, 0xca, 0x28, \ + 0xa3, 0x6c, 0x30, 0x6a, 0x30, 0x22, 0x06, 0x09, \ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, \ + 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, 0x2e, 0x36, \ + 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, \ + 0x31, 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x36, \ + 0x00, 0x91, 0x00, 0x03, 0x0a, 0x30, 0x13, 0x06, \ + 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, \ + 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, \ + 0x04, 0x30, 0x30, 0x21, 0x06, 0x0b, 0x2b, 0x06, \ + 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x01, 0x01, \ + 0x04, 0x04, 0x12, 0x04, 0x10, 0xf8, 0xa0, 0x11, \ + 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, \ + 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x30, 0x0c, 0x06, \ + 0x00, 0x91, 0x00, 0x03, 0x0b, 0x03, 0x55, 0x1d, \ + 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, \ + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \ + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, \ + 0x82, 0x01, 0x01, 0x00, 0x32, 0xf3, 0xe4, 0xbd, \ + 0x58, 0xd7, 0x42, 0x2b, 0xaf, 0x49, 0x99, 0x86, \ + 0x08, 0x1f, 0x0d, 0xa9, 0x3b, 0xc6, 0xaa, 0x1c, \ + 0x72, 0x11, 0xf9, 0x28, 0x53, 0xeb, 0xf3, 0xeb, \ + 0x00, 0x91, 0x00, 0x03, 0x0c, 0x73, 0xda, 0x69, \ + 0x3b, 0x06, 0xde, 0x31, 0x33, 0x8e, 0x5d, 0x02, \ + 0xec, 0xf6, 0x76, 0xe9, 0x5c, 0x42, 0xbe, 0xa5, \ + 0x8f, 0x25, 0xd3, 0x37, 0x3f, 0x77, 0xbb, 0x2a, \ + 0x9d, 0x7c, 0xb2, 0x3e, 0x11, 0x8c, 0x41, 0xd4, \ + 0x9a, 0x4c, 0x9a, 0xd8, 0xf3, 0xe2, 0xa4, 0xec, \ + 0x01, 0x77, 0x7a, 0x74, 0xa8, 0xc4, 0x12, 0x43, \ + 0xc3, 0x1e, 0xce, 0x20, 0x8f, 0x2d, 0x0f, 0x6e, \ + 0x00, 0x91, 0x00, 0x03, 0x0d, 0xbc, 0x61, 0x9b, \ + 0xe1, 0x84, 0xa1, 0x72, 0xf6, 0xa9, 0xac, 0xcb, \ + 0xf8, 0x73, 0x6d, 0x5b, 0xe2, 0x98, 0xb3, 0x6b, \ + 0xec, 0xe7, 0x1e, 0x77, 0x8d, 0x0a, 0x69, 0xaa, \ + 0xf9, 0x94, 0xb8, 0x63, 0x6d, 0xe8, 0xfa, 0xf6, \ + 0x2f, 0xd3, 0xce, 0x7f, 0x04, 0x4c, 0x32, 0x2c, \ + 0xf7, 0x26, 0x3e, 0x34, 0x99, 0xe6, 0xa5, 0xb2, \ + 0xb0, 0x2a, 0xbb, 0xad, 0x5b, 0xd9, 0xec, 0xe5, \ + 0x00, 0x91, 0x00, 0x03, 0x0e, 0xb0, 0x71, 0x4d, \ + 0x73, 0xbb, 0x94, 0x61, 0x49, 0x9c, 0x94, 0x2a, \ + 0x5f, 0x1d, 0xcc, 0xaf, 0x65, 0x03, 0x3b, 0x39, \ + 0x39, 0xd4, 0x47, 0xd9, 0xfc, 0xc4, 0x7b, 0x0b, \ + 0x16, 0xd8, 0xe9, 0x01, 0xfc, 0xec, 0x3f, 0x8c, \ + 0x1b, 0xc0, 0xc6, 0xac, 0x0b, 0x5d, 0x74, 0xc7, \ + 0xbb, 0x03, 0x05, 0x69, 0x17, 0xe9, 0x98, 0x1a, \ + 0x19, 0xb9, 0x09, 0x5c, 0xa1, 0xf4, 0xab, 0x9f, \ + 0x00, 0x91, 0x00, 0x03, 0x0f, 0x02, 0x7c, 0x28, \ + 0x0f, 0x8a, 0xf9, 0xed, 0x1d, 0x29, 0x3c, 0xf6, \ + 0xcc, 0x2f, 0x04, 0x6d, 0x9a, 0xd6, 0x62, 0xb4, \ + 0xa9, 0x6e, 0xb1, 0xca, 0xca, 0xac, 0x5e, 0x05, \ + 0x3e, 0x83, 0x91, 0x47, 0x7c, 0x1f, 0x8b, 0x60, \ + 0x01, 0xde, 0x65, 0x3a, 0xbf, 0xf2, 0xaa, 0xbb, \ + 0x55, 0x98, 0x86, 0x91, 0x7e, 0xad, 0x3b, 0x36, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_CREDMAN_META \ + 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x07, 0x00, \ + 0xa2, 0x01, 0x00, 0x02, 0x18, 0x19, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_CREDMAN_RPLIST \ + 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, \ + 0xa3, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6a, 0x79, \ + 0x75, 0x62, 0x69, 0x63, 0x6f, 0x2e, 0x63, 0x6f, \ + 0x6d, 0x04, 0x58, 0x20, 0x37, 0x82, 0x09, 0xb7, \ + 0x2d, 0xef, 0xcb, 0xa9, 0x1d, 0xcb, 0xf8, 0x54, \ + 0xed, 0xb4, 0xda, 0xa6, 0x48, 0x82, 0x8a, 0x2c, \ + 0xbd, 0x18, 0x0a, 0xfc, 0x77, 0xa7, 0x44, 0x34, \ + 0x65, 0x5a, 0x1c, 0x7d, 0x05, 0x03, 0x00, 0x00, \ + 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x36, 0x00, \ + 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6b, 0x79, \ + 0x75, 0x62, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x6f, \ + 0x72, 0x67, 0x04, 0x58, 0x20, 0x12, 0x6b, 0xba, \ + 0x6a, 0x2d, 0x7a, 0x81, 0x84, 0x25, 0x7b, 0x74, \ + 0xdd, 0x1d, 0xdd, 0x46, 0xb6, 0x2a, 0x8c, 0xa2, \ + 0xa7, 0x83, 0xfe, 0xdb, 0x5b, 0x19, 0x48, 0x73, \ + 0x55, 0xb7, 0xe3, 0x46, 0x09, 0x00, 0x00, 0x00, \ + 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, \ + 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6c, 0x77, \ + 0x65, 0x62, 0x61, 0x75, 0x74, 0x68, 0x6e, 0x2e, \ + 0x64, 0x65, 0x76, 0x04, 0x58, 0x20, 0xd6, 0x32, \ + 0x7d, 0x8c, 0x6a, 0x5d, 0xe6, 0xae, 0x0e, 0x33, \ + 0xd0, 0xa3, 0x31, 0xfb, 0x67, 0x77, 0xb9, 0x4e, \ + 0xf4, 0x73, 0x19, 0xfe, 0x7e, 0xfd, 0xfa, 0x82, \ + 0x70, 0x8e, 0x1f, 0xbb, 0xa2, 0x55, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_CREDMAN_RKLIST \ + 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc5, 0x00, \ + 0xa5, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ + 0xe4, 0xe1, 0x06, 0x31, 0xde, 0x00, 0x0f, 0x4f, \ + 0x12, 0x6e, 0xc9, 0x68, 0x2d, 0x43, 0x3f, 0xf1, \ + 0x02, 0x2c, 0x6e, 0xe6, 0x96, 0x10, 0xbf, 0x73, \ + 0x35, 0xc9, 0x20, 0x27, 0x06, 0xba, 0x39, 0x09, \ + 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ + 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ + 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ + 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ + 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x19, \ + 0xf7, 0x78, 0x0c, 0xa0, 0xbc, 0xb9, 0xa6, 0xd5, \ + 0x1e, 0xd7, 0x87, 0xfb, 0x6c, 0x80, 0x03, 0x64, \ + 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ + 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ + 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, \ + 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x81, \ + 0x6c, 0xdd, 0x8c, 0x8f, 0x8c, 0xc8, 0x43, 0xa7, \ + 0xbb, 0x79, 0x51, 0x09, 0xb1, 0xdf, 0xbe, 0xc4, \ + 0xa5, 0x54, 0x16, 0x9e, 0x58, 0x56, 0xb3, 0x0b, \ + 0x34, 0x4f, 0xa5, 0x6c, 0x05, 0xa2, 0x21, 0x22, \ + 0x58, 0x20, 0xcd, 0xc2, 0x0c, 0x99, 0x83, 0x5a, \ + 0x61, 0x73, 0xd8, 0xe0, 0x74, 0x23, 0x46, 0x64, \ + 0x00, 0x15, 0x00, 0x04, 0x02, 0x39, 0x4c, 0xb0, \ + 0xf4, 0x6c, 0x0a, 0x37, 0x72, 0xaa, 0xa8, 0xea, \ + 0x58, 0xd3, 0xd4, 0xe0, 0x51, 0xb2, 0x28, 0x09, \ + 0x05, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, \ + 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ + 0x56, 0xa1, 0x3c, 0x06, 0x2b, 0xad, 0xa2, 0x21, \ + 0x7d, 0xcd, 0x91, 0x08, 0x47, 0xa8, 0x8a, 0x06, \ + 0x06, 0xf6, 0x66, 0x91, 0xf6, 0xeb, 0x89, 0xe4, \ + 0xdf, 0x26, 0xbc, 0x46, 0x59, 0xc3, 0x7d, 0xc0, \ + 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ + 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ + 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ + 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ + 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xd8, \ + 0x27, 0x4b, 0x25, 0xed, 0x19, 0xef, 0x11, 0xaf, \ + 0xa6, 0x89, 0x7b, 0x84, 0x50, 0xe7, 0x62, 0x64, \ + 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ + 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ + 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, \ + 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x8d, \ + 0xfe, 0x45, 0xd5, 0x7d, 0xb6, 0x17, 0xab, 0x86, \ + 0x2d, 0x32, 0xf6, 0x85, 0xf0, 0x92, 0x76, 0xb7, \ + 0xce, 0x73, 0xca, 0x4e, 0x0e, 0xfd, 0xd5, 0xdb, \ + 0x2a, 0x1d, 0x55, 0x90, 0x96, 0x52, 0xc2, 0x0a, \ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, \ + 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ + 0x04, 0x0e, 0x0f, 0xa0, 0xcd, 0x60, 0x35, 0x9a, \ + 0xba, 0x47, 0x0c, 0x10, 0xb6, 0x82, 0x6e, 0x2f, \ + 0x66, 0xb9, 0xa7, 0xcf, 0xd8, 0x47, 0xb4, 0x3d, \ + 0xfd, 0x77, 0x1a, 0x38, 0x22, 0xa1, 0xda, 0xa5, \ + 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ + 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ + 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ + 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ + 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x00, \ + 0x5d, 0xdf, 0xef, 0xe2, 0xf3, 0x06, 0xb2, 0xa5, \ + 0x46, 0x4d, 0x98, 0xbc, 0x14, 0x65, 0xc1, 0x64, \ + 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ + 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ + 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, \ + 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x72, \ + 0x79, 0x14, 0x69, 0xdf, 0xcb, 0x64, 0x75, 0xee, \ + 0xd4, 0x45, 0x94, 0xbc, 0x48, 0x4d, 0x2a, 0x9f, \ + 0xc9, 0xf4, 0xb5, 0x1b, 0x05, 0xa6, 0x5b, 0x54, \ + 0x9a, 0xac, 0x6c, 0x2e, 0xc6, 0x90, 0x62, 0x0a, \ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, \ + 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ + 0xce, 0x32, 0xd8, 0x79, 0xdd, 0x86, 0xa2, 0x42, \ + 0x7c, 0xc3, 0xe1, 0x95, 0x12, 0x93, 0x1a, 0x03, \ + 0xe6, 0x70, 0xb8, 0xff, 0xcd, 0xa5, 0xdf, 0x15, \ + 0xfc, 0x88, 0x2a, 0xf5, 0x44, 0xf1, 0x33, 0x9c, \ + 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ + 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ + 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ + 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ + 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x0a, \ + 0x26, 0x5b, 0x7e, 0x1a, 0x2a, 0xba, 0x70, 0x5f, \ + 0x18, 0x26, 0x14, 0xb2, 0x71, 0xca, 0x98, 0x64, \ + 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ + 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ + 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, \ + 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x8b, \ + 0x48, 0xf0, 0x69, 0xfb, 0x22, 0xfb, 0xf3, 0x86, \ + 0x57, 0x7c, 0xdd, 0x82, 0x2c, 0x1c, 0x0c, 0xdc, \ + 0x27, 0xe2, 0x6a, 0x4c, 0x1a, 0x10, 0x04, 0x27, \ + 0x51, 0x3e, 0x2a, 0x9d, 0x3a, 0xb6, 0xb5, 0x22, \ + 0x58, 0x20, 0x70, 0xfe, 0x91, 0x67, 0x64, 0x53, \ + 0x63, 0x83, 0x72, 0x31, 0xe9, 0xe5, 0x20, 0xb7, \ + 0x00, 0x15, 0x00, 0x04, 0x02, 0xee, 0xc9, 0xfb, \ + 0x63, 0xd7, 0xe4, 0x76, 0x39, 0x80, 0x82, 0x74, \ + 0xb8, 0xfa, 0x67, 0xf5, 0x1b, 0x8f, 0xe0, 0x0a, \ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, \ + 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ + 0xf9, 0xa3, 0x67, 0xbf, 0x5e, 0x80, 0x95, 0xdb, \ + 0x4c, 0xc5, 0x8f, 0x65, 0x36, 0xc5, 0xaf, 0xdd, \ + 0x90, 0x2e, 0x62, 0x68, 0x67, 0x9c, 0xa2, 0x26, \ + 0x2f, 0x2a, 0xf9, 0x3a, 0xda, 0x15, 0xf2, 0x27, \ + 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ + 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ + 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ + 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ + 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xfb, \ + 0xa6, 0xbe, 0xc1, 0x01, 0xf6, 0x7a, 0x81, 0xf9, \ + 0xcd, 0x6d, 0x20, 0x41, 0x7a, 0x1c, 0x40, 0x64, \ + 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ + 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ + 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, \ + 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xda, \ + 0x2b, 0x53, 0xc3, 0xbe, 0x48, 0xf8, 0xab, 0xbd, \ + 0x06, 0x28, 0x46, 0xfa, 0x35, 0xab, 0xf9, 0xc5, \ + 0x2e, 0xfd, 0x3c, 0x38, 0x88, 0xb3, 0xe1, 0xa7, \ + 0xc5, 0xc6, 0xed, 0x72, 0x54, 0x37, 0x93, 0x22, \ + 0x58, 0x20, 0x12, 0x82, 0x32, 0x2d, 0xab, 0xbc, \ + 0x64, 0xb3, 0xed, 0xcc, 0xd5, 0x22, 0xec, 0x79, \ + 0x00, 0x15, 0x00, 0x04, 0x02, 0x4b, 0xe2, 0x4d, \ + 0x0c, 0x4b, 0x8d, 0x31, 0x4c, 0xb4, 0x0f, 0xd4, \ + 0xa9, 0xbe, 0x0c, 0xab, 0x9e, 0x0a, 0xc9, 0x0a, \ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_BIO_INFO \ + 0x00, 0x10, 0x00, 0x04, 0x90, 0x00, 0x06, 0x00, \ + 0xa2, 0x02, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_BIO_ENROLL \ + 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x0a, 0x00, \ + 0xa3, 0x04, 0x42, 0x68, 0x96, 0x05, 0x00, 0x06, \ + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, \ + 0xa2, 0x05, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, \ + 0xa2, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_BIO_ENUM \ + 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x2e, 0x00, \ + 0xa1, 0x07, 0x83, 0xa2, 0x01, 0x42, 0xce, 0xa3, \ + 0x02, 0x67, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, \ + 0x31, 0xa2, 0x01, 0x42, 0xbf, 0x5e, 0x02, 0x67, \ + 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x32, 0xa2, \ + 0x01, 0x42, 0x5e, 0xd2, 0x02, 0x67, 0x66, 0x69, \ + 0x6e, 0x67, 0x65, 0x72, 0x33, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY \ + 0x89, 0xc9, 0x8d, 0x28, 0x90, 0x01, 0xe6, 0x00, \ + 0xa1, 0x01, 0x59, 0x01, 0xe0, 0x81, 0xa3, 0x01, \ + 0x59, 0x01, 0xb8, 0xb3, 0x26, 0x24, 0x99, 0xde, \ + 0x06, 0x3f, 0xca, 0xde, 0x98, 0x8d, 0x9d, 0xc5, \ + 0x3f, 0x26, 0x6c, 0xc7, 0x40, 0x93, 0xc4, 0x88, \ + 0x06, 0x51, 0x4f, 0xb9, 0x61, 0xf2, 0xc9, 0x8d, \ + 0xbc, 0xce, 0x79, 0x08, 0xec, 0x90, 0xc5, 0x5b, \ + 0xe5, 0x0a, 0x72, 0x08, 0x7b, 0xe1, 0xf9, 0x16, \ + 0x89, 0xc9, 0x8d, 0x28, 0x00, 0x06, 0x8b, 0x76, \ + 0x32, 0xa0, 0xae, 0x55, 0xb2, 0x39, 0x71, 0xce, \ + 0x34, 0x4b, 0x6e, 0x6b, 0x89, 0xa6, 0x5e, 0x69, \ + 0x07, 0xac, 0xf6, 0x01, 0x3c, 0xba, 0x45, 0x7a, \ + 0x75, 0x25, 0x3a, 0xbd, 0x95, 0x22, 0x9d, 0xc3, \ + 0xe4, 0x42, 0x31, 0x5c, 0xb5, 0xf4, 0x64, 0x6a, \ + 0x56, 0x1d, 0xab, 0xc7, 0x6e, 0x96, 0x75, 0xe7, \ + 0xb3, 0x22, 0x0b, 0x82, 0xac, 0x57, 0x78, 0xdf, \ + 0x89, 0xc9, 0x8d, 0x28, 0x01, 0x57, 0x06, 0xc5, \ + 0x4b, 0x61, 0x0b, 0x4d, 0xa1, 0x66, 0xa0, 0x89, \ + 0xad, 0x19, 0x8f, 0xd8, 0x96, 0x55, 0x22, 0x5f, \ + 0xca, 0x2e, 0xc1, 0xd7, 0xbd, 0xa1, 0x83, 0x66, \ + 0x4d, 0x85, 0xcb, 0x01, 0x60, 0x3f, 0xf7, 0xf7, \ + 0xa3, 0x7a, 0xfa, 0x99, 0xa0, 0x1e, 0x25, 0x90, \ + 0xd0, 0xd0, 0x3b, 0x54, 0x90, 0x77, 0x94, 0xa6, \ + 0x88, 0xea, 0xc3, 0x6b, 0xa0, 0x59, 0x5e, 0x69, \ + 0x89, 0xc9, 0x8d, 0x28, 0x02, 0x78, 0x0b, 0x2b, \ + 0xab, 0x5b, 0x04, 0x2f, 0x78, 0x15, 0x86, 0x2b, \ + 0x0f, 0x63, 0xb2, 0xd7, 0xc9, 0xe9, 0xac, 0x0e, \ + 0xbc, 0x17, 0xe4, 0x19, 0x88, 0xe0, 0xe6, 0x13, \ + 0xf8, 0x15, 0x08, 0xa7, 0xe1, 0x6e, 0x71, 0x5c, \ + 0xef, 0x3e, 0xc1, 0x0f, 0x74, 0xdb, 0xdc, 0x52, \ + 0x9c, 0xfc, 0xe9, 0xa9, 0xf3, 0x0d, 0x52, 0xbc, \ + 0x0c, 0xe8, 0xba, 0xd1, 0x76, 0x46, 0x87, 0xb5, \ + 0x89, 0xc9, 0x8d, 0x28, 0x03, 0x30, 0xe6, 0x9d, \ + 0xa1, 0x2b, 0xa5, 0x9e, 0x3b, 0x86, 0xb3, 0x5f, \ + 0xe3, 0x81, 0xa6, 0x76, 0x32, 0x9d, 0xf9, 0xc5, \ + 0x07, 0x93, 0xb3, 0xdf, 0x64, 0xe2, 0x78, 0x9c, \ + 0x00, 0xc7, 0x86, 0x79, 0xd6, 0x67, 0xa2, 0xfb, \ + 0xf2, 0x8d, 0xea, 0xe9, 0xc8, 0xfc, 0x43, 0xd2, \ + 0x0f, 0x2f, 0x7d, 0x9d, 0xd3, 0x8f, 0x9c, 0xdd, \ + 0xa2, 0x9f, 0x42, 0x76, 0x40, 0xcc, 0x4a, 0xd0, \ + 0x89, 0xc9, 0x8d, 0x28, 0x04, 0xb4, 0x87, 0x18, \ + 0x06, 0xc3, 0xc7, 0x89, 0x98, 0x72, 0xcc, 0x1a, \ + 0xd1, 0xd8, 0x78, 0xb9, 0x75, 0x0b, 0x92, 0xe3, \ + 0xcc, 0xed, 0x38, 0x39, 0x4b, 0xa9, 0xcf, 0x30, \ + 0xd6, 0xb5, 0xa1, 0x3f, 0xfa, 0x4f, 0x29, 0x99, \ + 0xa9, 0x03, 0x77, 0xf6, 0x53, 0xfa, 0xd8, 0x32, \ + 0xce, 0xf4, 0xf6, 0x0a, 0x3c, 0xe8, 0x9c, 0x3d, \ + 0xaa, 0xe0, 0x7b, 0x2c, 0xa5, 0x28, 0xe1, 0xdd, \ + 0x89, 0xc9, 0x8d, 0x28, 0x05, 0x51, 0xbf, 0xe1, \ + 0xd4, 0xf5, 0x5e, 0x38, 0x2c, 0xec, 0xab, 0xdd, \ + 0xb8, 0x5c, 0x13, 0x43, 0x62, 0xc2, 0xb6, 0x02, \ + 0x18, 0xce, 0x9a, 0x62, 0x67, 0x6a, 0xeb, 0x99, \ + 0xf6, 0x2f, 0xf1, 0xf1, 0xec, 0x3e, 0x74, 0xfa, \ + 0xf8, 0x16, 0x43, 0xea, 0x1e, 0xef, 0x5d, 0x37, \ + 0x6c, 0x13, 0xf9, 0x7f, 0x65, 0x09, 0xab, 0x60, \ + 0x38, 0xda, 0x0f, 0xe7, 0xfa, 0x9e, 0x17, 0x10, \ + 0x89, 0xc9, 0x8d, 0x28, 0x06, 0xdc, 0x4c, 0x4d, \ + 0xae, 0x5c, 0xb4, 0x0d, 0x6b, 0x05, 0x6d, 0x25, \ + 0x3f, 0x78, 0x5d, 0xf3, 0x34, 0x33, 0xa4, 0x89, \ + 0x34, 0x0e, 0x88, 0x66, 0x40, 0x57, 0x6b, 0x34, \ + 0x83, 0xfd, 0x39, 0xe7, 0xfb, 0x84, 0x09, 0xb3, \ + 0x16, 0x8f, 0x80, 0xdf, 0x1b, 0xe0, 0x02, 0x4c, \ + 0xde, 0x31, 0x2a, 0x32, 0x58, 0x5b, 0xa3, 0x23, \ + 0x8e, 0x2a, 0xa6, 0xaf, 0x03, 0x19, 0x02, 0x7a, \ + 0x89, 0xc9, 0x8d, 0x28, 0x07, 0xf8, 0xbf, 0xa6, \ + 0xad, 0xf9, 0xd1, 0xdc, 0xbd, 0x6e, 0xb3, 0xc1, \ + 0xfb, 0x65, 0xd8, 0x5f, 0x2e, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_NFC_INIT \ + 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x90, 0x00 + +#define WIREDATA_CTAP_NFC_MSG \ + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00 + +#define WIREDATA_CTAP_EXTENDED_APDU \ + 0x00, 0xa4, 0x04, 0x00, 0x00, 0x02, 0x00, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, \ + 0x00 + +#endif /* _WIREDATA_FIDO2_H */ diff --git a/fuzz/wiredata_u2f.h b/fuzz/wiredata_u2f.h new file mode 100644 index 0000000..3be22d3 --- /dev/null +++ b/fuzz/wiredata_u2f.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _WIREDATA_U2F_H +#define _WIREDATA_U2F_H + +#define WIREDATA_CTAP_U2F_6985 \ + 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, \ + 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_U2F_AUTH \ + 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x4e, 0x01, \ + 0x00, 0x00, 0x00, 0x2c, 0x30, 0x45, 0x02, 0x20, \ + 0x1c, 0xf5, 0x7c, 0xf6, 0xde, 0xbe, 0xe9, 0x86, \ + 0xee, 0x97, 0xb7, 0x64, 0xa3, 0x4e, 0x7a, 0x70, \ + 0x85, 0xd0, 0x66, 0xf9, 0xf0, 0xcd, 0x04, 0x5d, \ + 0x97, 0xf2, 0x3c, 0x22, 0xe3, 0x0e, 0x61, 0xc8, \ + 0x02, 0x21, 0x00, 0x97, 0xef, 0xae, 0x36, 0xe6, \ + 0x17, 0x9f, 0x5e, 0x2d, 0xd7, 0x8c, 0x34, 0xa7, \ + 0x00, 0x00, 0x99, 0x01, 0x00, 0xa1, 0xe9, 0xfb, \ + 0x8f, 0x86, 0x8c, 0xe3, 0x1e, 0xde, 0x3f, 0x4e, \ + 0x1b, 0xe1, 0x2f, 0x8f, 0x2f, 0xca, 0x42, 0x26, \ + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define WIREDATA_CTAP_U2F_REGISTER \ + 0x00, 0x00, 0x99, 0x01, 0x83, 0x03, 0x1e, 0x05, \ + 0x04, 0x9f, 0xa0, 0xf9, 0x0d, 0x4c, 0xf4, 0xae, \ + 0x96, 0x3c, 0xb7, 0x46, 0xb7, 0x5c, 0x9d, 0x8b, \ + 0x48, 0x19, 0xdf, 0xc4, 0xad, 0xea, 0xb2, 0x70, \ + 0x58, 0x72, 0xd9, 0xce, 0x75, 0xf5, 0xe6, 0x8e, \ + 0x0f, 0x9c, 0x0e, 0x2e, 0x62, 0x3e, 0x91, 0xd3, \ + 0x7b, 0x97, 0x46, 0x60, 0xb9, 0x57, 0x13, 0x97, \ + 0x26, 0xae, 0x0f, 0xb3, 0x8f, 0x2e, 0x9b, 0x3f, \ + 0x00, 0x00, 0x99, 0x01, 0x00, 0xa5, 0x55, 0xec, \ + 0x8c, 0x25, 0x7c, 0x65, 0xb7, 0x09, 0x40, 0x48, \ + 0xae, 0xa8, 0xcb, 0xa1, 0x91, 0xac, 0x40, 0x24, \ + 0xf2, 0x34, 0x6e, 0x3a, 0x8f, 0xa5, 0xb7, 0x48, \ + 0x54, 0x6e, 0xfb, 0xf4, 0x37, 0x88, 0x69, 0x79, \ + 0x6f, 0x12, 0xc1, 0x32, 0xdf, 0x15, 0x5d, 0x6e, \ + 0x82, 0x54, 0xc0, 0x6e, 0x56, 0x4f, 0x3a, 0x9c, \ + 0xc3, 0x96, 0x7a, 0xde, 0xa5, 0xfe, 0xec, 0xd1, \ + 0x00, 0x00, 0x99, 0x01, 0x01, 0x5a, 0x21, 0x85, \ + 0x0e, 0x25, 0x7b, 0x8d, 0x6e, 0x1d, 0x32, 0x29, \ + 0xdb, 0x21, 0xb0, 0xa3, 0x30, 0x82, 0x02, 0x4f, \ + 0x30, 0x82, 0x01, 0x37, 0xa0, 0x03, 0x02, 0x01, \ + 0x02, 0x02, 0x04, 0x2a, 0xd9, 0x6a, 0xf3, 0x30, \ + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, \ + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, \ + 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, \ + 0x00, 0x00, 0x99, 0x01, 0x02, 0x03, 0x13, 0x23, \ + 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, \ + 0x32, 0x46, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, \ + 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, \ + 0x6c, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30, \ + 0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x31, \ + 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, \ + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, \ + 0x00, 0x00, 0x99, 0x01, 0x03, 0x35, 0x30, 0x30, \ + 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, \ + 0x30, 0x5a, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, \ + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x26, 0x59, \ + 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, \ + 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, \ + 0x69, 0x61, 0x6c, 0x20, 0x32, 0x33, 0x39, 0x32, \ + 0x35, 0x37, 0x33, 0x34, 0x35, 0x31, 0x36, 0x35, \ + 0x00, 0x00, 0x99, 0x01, 0x04, 0x35, 0x30, 0x33, \ + 0x38, 0x37, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, \ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, \ + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, \ + 0x07, 0x03, 0x42, 0x00, 0x04, 0x2f, 0xe1, 0xa2, \ + 0x3e, 0xbf, 0xa5, 0x5b, 0x3e, 0x46, 0x1d, 0x59, \ + 0xa4, 0x35, 0x22, 0xd7, 0x97, 0x48, 0x98, 0x1c, \ + 0xba, 0x6d, 0x28, 0x9a, 0x98, 0xf1, 0xbd, 0x7d, \ + 0x00, 0x00, 0x99, 0x01, 0x05, 0xff, 0x65, 0x66, \ + 0x80, 0xdb, 0xbb, 0xed, 0xbc, 0x2b, 0xae, 0x60, \ + 0x7e, 0x6e, 0xf7, 0x72, 0xf5, 0x76, 0xb0, 0x4d, \ + 0x54, 0xc4, 0xe5, 0xf3, 0x2f, 0x59, 0x6f, 0x26, \ + 0xe6, 0x11, 0x15, 0xc7, 0x27, 0x2c, 0xf6, 0xca, \ + 0x75, 0x94, 0xa3, 0x3b, 0x30, 0x39, 0x30, 0x22, \ + 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, \ + 0xc4, 0x0a, 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, \ + 0x00, 0x00, 0x99, 0x01, 0x06, 0x2e, 0x36, 0x2e, \ + 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x31, \ + 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x32, 0x30, \ + 0x13, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, \ + 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, \ + 0x03, 0x02, 0x04, 0x30, 0x30, 0x0d, 0x06, 0x09, \ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, \ + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, \ + 0x00, 0x00, 0x99, 0x01, 0x07, 0x85, 0x6a, 0xfa, \ + 0x8b, 0xcf, 0x4f, 0x3f, 0x62, 0x5f, 0x29, 0x1b, \ + 0xc1, 0x15, 0x8e, 0x3c, 0x7e, 0xbd, 0x25, 0x52, \ + 0xbc, 0xf7, 0x57, 0x07, 0x53, 0xf5, 0x12, 0x1d, \ + 0xa6, 0xa5, 0x4d, 0x24, 0xcc, 0xcf, 0xae, 0x27, \ + 0xce, 0xd6, 0xab, 0x31, 0x12, 0x8c, 0x29, 0x7e, \ + 0x5b, 0x5b, 0x89, 0x05, 0xdd, 0xa0, 0x20, 0x17, \ + 0x93, 0x1f, 0x1f, 0x5f, 0x59, 0x25, 0x93, 0x59, \ + 0x00, 0x00, 0x99, 0x01, 0x08, 0x51, 0xfc, 0x00, \ + 0x4b, 0xcb, 0xe2, 0x0a, 0xdd, 0x7d, 0x8d, 0x05, \ + 0x2f, 0x95, 0x43, 0xb3, 0x49, 0x6c, 0x15, 0xb8, \ + 0x31, 0x0e, 0x10, 0xcb, 0xd9, 0xbb, 0x05, 0x38, \ + 0x27, 0x4f, 0x58, 0x3e, 0xad, 0x1f, 0x45, 0x12, \ + 0x88, 0xc3, 0xea, 0x76, 0xd0, 0x70, 0xad, 0x44, \ + 0xe5, 0x3a, 0xfe, 0xa8, 0xf2, 0x2d, 0x1f, 0x73, \ + 0x62, 0x5f, 0xf2, 0xd5, 0x89, 0xfe, 0x30, 0xdf, \ + 0x00, 0x00, 0x99, 0x01, 0x09, 0x26, 0x62, 0xcb, \ + 0x7c, 0xbb, 0x7c, 0x99, 0x61, 0x80, 0xad, 0xcf, \ + 0xa9, 0x8a, 0x4d, 0x01, 0x2c, 0xf3, 0x13, 0x46, \ + 0xcd, 0x11, 0x74, 0x6a, 0x58, 0x48, 0xe8, 0xbe, \ + 0xed, 0xf3, 0xe3, 0x0c, 0xcb, 0xd9, 0xc1, 0xdd, \ + 0x22, 0x16, 0x71, 0xb2, 0x83, 0x88, 0x61, 0xf6, \ + 0x5a, 0x45, 0x36, 0x23, 0xb5, 0x18, 0xd5, 0x56, \ + 0x7f, 0xa8, 0xf0, 0xa3, 0xce, 0x10, 0x5d, 0xf4, \ + 0x00, 0x00, 0x99, 0x01, 0x0a, 0xf1, 0x39, 0x53, \ + 0xe1, 0x14, 0xea, 0x59, 0xe0, 0xa7, 0xf2, 0xfe, \ + 0x66, 0x88, 0x67, 0x43, 0x2e, 0x52, 0xfd, 0x6a, \ + 0x2f, 0x64, 0xf7, 0x3c, 0x48, 0xcd, 0x9b, 0x38, \ + 0xf2, 0xdf, 0xba, 0x2c, 0x7a, 0x4b, 0x3b, 0x11, \ + 0x28, 0xdf, 0x26, 0xd6, 0x6a, 0x24, 0xf8, 0x95, \ + 0xdd, 0xa0, 0xb6, 0x11, 0x80, 0xf4, 0x14, 0x4f, \ + 0x6b, 0x70, 0x75, 0xc3, 0x18, 0xa4, 0x9a, 0xe0, \ + 0x00, 0x00, 0x99, 0x01, 0x0b, 0x8b, 0x58, 0xd3, \ + 0x6a, 0xdb, 0x1e, 0x30, 0x53, 0x67, 0x2b, 0x17, \ + 0xc5, 0xa1, 0x9f, 0x7f, 0x0a, 0x22, 0xf1, 0x0e, \ + 0x94, 0x30, 0x44, 0x02, 0x20, 0x07, 0x5c, 0x4f, \ + 0xd2, 0x83, 0xb6, 0x9f, 0x0a, 0x4a, 0x4d, 0x4b, \ + 0x08, 0x35, 0xeb, 0xc0, 0x7e, 0x4a, 0x14, 0x2e, \ + 0xc7, 0x8c, 0xd6, 0x64, 0x2f, 0xd3, 0x1e, 0xcc, \ + 0xb5, 0xe8, 0x42, 0xea, 0xf6, 0x02, 0x20, 0x6b, \ + 0x00, 0x00, 0x99, 0x01, 0x0c, 0x5a, 0xba, 0x4a, \ + 0xc8, 0xd7, 0x89, 0xcc, 0x77, 0xe6, 0xb9, 0xa3, \ + 0x34, 0xea, 0x06, 0x85, 0x72, 0xc6, 0x28, 0xa8, \ + 0x7a, 0xaa, 0x19, 0x88, 0x34, 0xbb, 0xdc, 0x64, \ + 0x90, 0x0a, 0xdb, 0x39, 0x90, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#endif /* !_WIREDATA_U2F_H */ diff --git a/fuzz/wrap.c b/fuzz/wrap.c new file mode 100644 index 0000000..6f40ea1 --- /dev/null +++ b/fuzz/wrap.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2019-2022 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" + +extern int prng_up; + +int fuzz_save_corpus; + +/* + * Build wrappers around functions of interest, and have them fail + * in a pseudo-random manner. A uniform probability of 0.25% (1/400) + * allows for a depth of log(0.5)/log(399/400) > 276 operations + * before simulated errors become statistically more likely. + */ + +#define WRAP(type, name, args, retval, param, prob) \ +extern type __wrap_##name args; \ +extern type __real_##name args; \ +type __wrap_##name args { \ + if (prng_up && uniform_random(400) < (prob)) { \ + return (retval); \ + } \ + \ + return (__real_##name param); \ +} + +WRAP(void *, + malloc, + (size_t size), + NULL, + (size), + 1 +) + +WRAP(void *, + calloc, + (size_t nmemb, size_t size), + NULL, + (nmemb, size), + 1 +) + +WRAP(void *, + realloc, + (void *ptr, size_t size), + NULL, + (ptr, size), + 1 +) + +WRAP(char *, + strdup, + (const char *s), + NULL, + (s), + 1 +) + +WRAP(ssize_t, + getrandom, + (void *buf, size_t buflen, unsigned int flags), + -1, + (buf, buflen, flags), + 1 +) + +WRAP(int, + EVP_Cipher, + (EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, + unsigned int inl), + -1, + (ctx, out, in, inl), + 1 +) + +WRAP(int, + EVP_CIPHER_CTX_ctrl, + (EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr), + 0, + (ctx, type, arg, ptr), + 1 +) + +WRAP(EVP_CIPHER_CTX *, + EVP_CIPHER_CTX_new, + (void), + NULL, + (), + 1 +) + +WRAP(int, + EVP_CipherInit, + (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv, int enc), + 0, + (ctx, cipher, key, iv, enc), + 1 +) + +WRAP(RSA *, + EVP_PKEY_get0_RSA, + (EVP_PKEY *pkey), + NULL, + (pkey), + 1 +) + +WRAP(EC_KEY *, + EVP_PKEY_get0_EC_KEY, + (EVP_PKEY *pkey), + NULL, + (pkey), + 1 +) + +WRAP(int, + EVP_PKEY_get_raw_public_key, + (const EVP_PKEY *pkey, unsigned char *pub, size_t *len), + 0, + (pkey, pub, len), + 1 +) + +WRAP(EVP_MD_CTX *, + EVP_MD_CTX_new, + (void), + NULL, + (), + 1 +) + +WRAP(int, + EVP_DigestVerifyInit, + (EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey), + 0, + (ctx, pctx, type, e, pkey), + 1 +) + +WRAP(int, + EVP_DigestInit_ex, + (EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl), + 0, + (ctx, type, impl), + 1 +) + +WRAP(int, + EVP_DigestUpdate, + (EVP_MD_CTX *ctx, const void *data, size_t count), + 0, + (ctx, data, count), + 1 +) + +WRAP(int, + EVP_DigestFinal_ex, + (EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize), + 0, + (ctx, md, isize), + 1 +) + +WRAP(BIGNUM *, + BN_bin2bn, + (const unsigned char *s, int len, BIGNUM *ret), + NULL, + (s, len, ret), + 1 +) + +WRAP(int, + BN_bn2bin, + (const BIGNUM *a, unsigned char *to), + -1, + (a, to), + 1 +) + +WRAP(BIGNUM *, + BN_CTX_get, + (BN_CTX *ctx), + NULL, + (ctx), + 1 +) + +WRAP(BN_CTX *, + BN_CTX_new, + (void), + NULL, + (), + 1 +) + +WRAP(BIGNUM *, + BN_new, + (void), + NULL, + (), + 1 +) + +WRAP(RSA *, + RSA_new, + (void), + NULL, + (), + 1 +) + +WRAP(int, + RSA_set0_key, + (RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d), + 0, + (r, n, e, d), + 1 +) + +WRAP(int, + RSA_pkey_ctx_ctrl, + (EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2), + -1, + (ctx, optype, cmd, p1, p2), + 1 +) + +WRAP(EC_KEY *, + EC_KEY_new_by_curve_name, + (int nid), + NULL, + (nid), + 1 +) + +WRAP(const EC_GROUP *, + EC_KEY_get0_group, + (const EC_KEY *key), + NULL, + (key), + 1 +) + +WRAP(const BIGNUM *, + EC_KEY_get0_private_key, + (const EC_KEY *key), + NULL, + (key), + 1 +) + +WRAP(EC_POINT *, + EC_POINT_new, + (const EC_GROUP *group), + NULL, + (group), + 1 +) + +WRAP(int, + EC_POINT_get_affine_coordinates_GFp, + (const EC_GROUP *group, const EC_POINT *p, BIGNUM *x, BIGNUM *y, BN_CTX *ctx), + 0, + (group, p, x, y, ctx), + 1 +) + +WRAP(EVP_PKEY *, + EVP_PKEY_new, + (void), + NULL, + (), + 1 +) + +WRAP(int, + EVP_PKEY_assign, + (EVP_PKEY *pkey, int type, void *key), + 0, + (pkey, type, key), + 1 +) + +WRAP(int, + EVP_PKEY_keygen_init, + (EVP_PKEY_CTX *ctx), + 0, + (ctx), + 1 +) + +WRAP(int, + EVP_PKEY_keygen, + (EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey), + 0, + (ctx, ppkey), + 1 +) + +WRAP(int, + EVP_PKEY_paramgen_init, + (EVP_PKEY_CTX *ctx), + 0, + (ctx), + 1 +) + +WRAP(int, + EVP_PKEY_paramgen, + (EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey), + 0, + (ctx, ppkey), + 1 +) + +WRAP(EVP_PKEY *, + EVP_PKEY_new_raw_public_key, + (int type, ENGINE *e, const unsigned char *key, size_t keylen), + NULL, + (type, e, key, keylen), + 1 +) + +WRAP(EVP_PKEY_CTX *, + EVP_PKEY_CTX_new, + (EVP_PKEY *pkey, ENGINE *e), + NULL, + (pkey, e), + 1 +) + +WRAP(EVP_PKEY_CTX *, + EVP_PKEY_CTX_new_id, + (int id, ENGINE *e), + NULL, + (id, e), + 1 +) + +WRAP(int, + EVP_PKEY_derive, + (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen), + 0, + (ctx, key, pkeylen), + 1 +) + +WRAP(int, + EVP_PKEY_derive_init, + (EVP_PKEY_CTX *ctx), + 0, + (ctx), + 1 +) + +WRAP(int, + EVP_PKEY_derive_set_peer, + (EVP_PKEY_CTX *ctx, EVP_PKEY *peer), + 0, + (ctx, peer), + 1 +) + +WRAP(int, + EVP_PKEY_verify_init, + (EVP_PKEY_CTX *ctx), + 0, + (ctx), + 1 +) + +WRAP(int, + EVP_PKEY_CTX_ctrl, + (EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, int p1, void *p2), + -1, + (ctx, keytype, optype, cmd, p1, p2), + 1 +) + +WRAP(const EVP_MD *, + EVP_sha1, + (void), + NULL, + (), + 1 +) + +WRAP(const EVP_MD *, + EVP_sha256, + (void), + NULL, + (), + 1 +) + +WRAP(const EVP_CIPHER *, + EVP_aes_256_cbc, + (void), + NULL, + (), + 1 +) + +WRAP(const EVP_CIPHER *, + EVP_aes_256_gcm, + (void), + NULL, + (), + 1 +) + +WRAP(unsigned char *, + HMAC, + (const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *d, int n, unsigned char *md, + unsigned int *md_len), + NULL, + (evp_md, key, key_len, d, n, md, md_len), + 1 +) + +WRAP(HMAC_CTX *, + HMAC_CTX_new, + (void), + NULL, + (), + 1 +) + +WRAP(int, + HMAC_Init_ex, + (HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, + ENGINE *impl), + 0, + (ctx, key, key_len, md, impl), + 1 +) + +WRAP(int, + HMAC_Update, + (HMAC_CTX *ctx, const unsigned char *data, int len), + 0, + (ctx, data, len), + 1 +) + +WRAP(int, + HMAC_Final, + (HMAC_CTX *ctx, unsigned char *md, unsigned int *len), + 0, + (ctx, md, len), + 1 +) + +WRAP(unsigned char *, + SHA1, + (const unsigned char *d, size_t n, unsigned char *md), + NULL, + (d, n, md), + 1 +) + +WRAP(unsigned char *, + SHA256, + (const unsigned char *d, size_t n, unsigned char *md), + NULL, + (d, n, md), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_string, + (const char *val), + NULL, + (val), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_bytestring, + (cbor_data handle, size_t length), + NULL, + (handle, length), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_bool, + (bool value), + NULL, + (value), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_negint8, + (uint8_t value), + NULL, + (value), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_negint16, + (uint16_t value), + NULL, + (value), + 1 +) + +WRAP(cbor_item_t *, + cbor_load, + (cbor_data source, size_t source_size, struct cbor_load_result *result), + NULL, + (source, source_size, result), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_uint8, + (uint8_t value), + NULL, + (value), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_uint16, + (uint16_t value), + NULL, + (value), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_uint32, + (uint32_t value), + NULL, + (value), + 1 +) + +WRAP(cbor_item_t *, + cbor_build_uint64, + (uint64_t value), + NULL, + (value), + 1 +) + +WRAP(struct cbor_pair *, + cbor_map_handle, + (const cbor_item_t *item), + NULL, + (item), + 1 +) + +WRAP(cbor_item_t **, + cbor_array_handle, + (const cbor_item_t *item), + NULL, + (item), + 1 +) + +WRAP(bool, + cbor_array_push, + (cbor_item_t *array, cbor_item_t *pushee), + false, + (array, pushee), + 1 +) + +WRAP(bool, + cbor_map_add, + (cbor_item_t *item, struct cbor_pair pair), + false, + (item, pair), + 1 +) + +WRAP(cbor_item_t *, + cbor_new_definite_map, + (size_t size), + NULL, + (size), + 1 +) + +WRAP(cbor_item_t *, + cbor_new_definite_array, + (size_t size), + NULL, + (size), + 1 +) + +WRAP(cbor_item_t *, + cbor_new_definite_bytestring, + (void), + NULL, + (), + 1 +) + +WRAP(size_t, + cbor_serialize_alloc, + (const cbor_item_t *item, cbor_mutable_data *buffer, + size_t *buffer_size), + 0, + (item, buffer, buffer_size), + 1 +) + +WRAP(int, + fido_tx, + (fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms), + -1, + (d, cmd, buf, count, ms), + 1 +) + +WRAP(int, + bind, + (int sockfd, const struct sockaddr *addr, socklen_t addrlen), + -1, + (sockfd, addr, addrlen), + 1 +) + +WRAP(int, + deflateInit2_, + (z_streamp strm, int level, int method, int windowBits, int memLevel, + int strategy, const char *version, int stream_size), + Z_STREAM_ERROR, + (strm, level, method, windowBits, memLevel, strategy, version, + stream_size), + 1 +) + +int __wrap_deflate(z_streamp, int); +int __real_deflate(z_streamp, int); + +int +__wrap_deflate(z_streamp strm, int flush) +{ + if (prng_up && uniform_random(400) < 1) { + return Z_BUF_ERROR; + } + /* should never happen, but we check for it */ + if (prng_up && uniform_random(400) < 1) { + strm->avail_out = UINT_MAX; + return Z_STREAM_END; + } + + return __real_deflate(strm, flush); +} + +int __wrap_asprintf(char **, const char *, ...); + +int +__wrap_asprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + int r; + + if (prng_up && uniform_random(400) < 1) { + *strp = (void *)0xdeadbeef; + return -1; + } + + va_start(ap, fmt); + r = vasprintf(strp, fmt, ap); + va_end(ap); + + return r; +} diff --git a/fuzz/wrapped.sym b/fuzz/wrapped.sym new file mode 100644 index 0000000..219a0d8 --- /dev/null +++ b/fuzz/wrapped.sym @@ -0,0 +1,102 @@ +asprintf +bind +BN_bin2bn +BN_bn2bin +BN_CTX_get +BN_CTX_new +BN_new +calloc +cbor_array_handle +cbor_array_push +cbor_build_bool +cbor_build_bytestring +cbor_build_negint16 +cbor_build_negint8 +cbor_build_string +cbor_build_uint16 +cbor_build_uint32 +cbor_build_uint64 +cbor_build_uint8 +cbor_load +cbor_map_add +cbor_map_handle +cbor_new_definite_array +cbor_new_definite_bytestring +cbor_new_definite_map +cbor_serialize_alloc +clock_gettime +deflate +deflateInit2_ +EC_KEY_get0_group +EC_KEY_get0_private_key +EC_KEY_new_by_curve_name +EC_POINT_get_affine_coordinates_GFp +EC_POINT_new +EVP_aes_256_cbc +EVP_aes_256_gcm +EVP_Cipher +EVP_CIPHER_CTX_ctrl +EVP_CIPHER_CTX_new +EVP_CipherInit +EVP_DigestFinal_ex +EVP_DigestInit_ex +EVP_DigestUpdate +EVP_DigestVerifyInit +EVP_MD_CTX_new +EVP_PKEY_assign +EVP_PKEY_CTX_ctrl +EVP_PKEY_CTX_new +EVP_PKEY_CTX_new_id +EVP_PKEY_derive +EVP_PKEY_derive_init +EVP_PKEY_derive_set_peer +EVP_PKEY_get0_EC_KEY +EVP_PKEY_get0_RSA +EVP_PKEY_get_raw_public_key +EVP_PKEY_keygen +EVP_PKEY_keygen_init +EVP_PKEY_new +EVP_PKEY_new_raw_public_key +EVP_PKEY_paramgen +EVP_PKEY_paramgen_init +EVP_PKEY_verify_init +EVP_sha1 +EVP_sha256 +fido_tx +getrandom +HMAC +HMAC_CTX_new +HMAC_Final +HMAC_Init_ex +HMAC_Update +ioctl +malloc +realloc +RSA_new +RSA_pkey_ctx_ctrl +RSA_set0_key +SCardConnect +SCardDisconnect +SCardEstablishContext +SCardListReaders +SCardReleaseContext +SCardTransmit +SHA1 +SHA256 +strdup +udev_device_get_devnode +udev_device_get_parent_with_subsystem_devtype +udev_device_get_sysattr_value +udev_device_get_sysnum +udev_device_new_from_syspath +udev_device_unref +udev_enumerate_add_match_subsystem +udev_enumerate_get_list_entry +udev_enumerate_new +udev_enumerate_scan_devices +udev_enumerate_unref +udev_list_entry_get_name +udev_list_entry_get_next +udev_new +udev_unref +usleep