Path: blob/main/contrib/libfido2/fuzz/fuzz_cred.c
101160 views
/*1* Copyright (c) 2019-2022 Yubico AB. All rights reserved.2* Use of this source code is governed by a BSD-style3* license that can be found in the LICENSE file.4* SPDX-License-Identifier: BSD-2-Clause5*/67#include <assert.h>8#include <stdint.h>9#include <stdio.h>10#include <stdlib.h>11#include <string.h>1213#include "mutator_aux.h"14#include "wiredata_fido2.h"15#include "wiredata_u2f.h"16#include "dummy.h"1718#include "../openbsd-compat/openbsd-compat.h"1920/* Parameter set defining a FIDO2 make credential operation. */21struct param {22char pin[MAXSTR];23char rp_id[MAXSTR];24char rp_name[MAXSTR];25char user_icon[MAXSTR];26char user_name[MAXSTR];27char user_nick[MAXSTR];28int ext;29int seed;30struct blob cdh;31struct blob excl_cred;32struct blob user_id;33struct blob wire_data;34uint8_t excl_count;35uint8_t rk;36uint8_t type;37uint8_t opt;38uint8_t uv;39};4041/*42* Collection of HID reports from an authenticator issued with a FIDO243* make credential using the example parameters above.44*/45static const uint8_t dummy_wire_data_fido[] = {46WIREDATA_CTAP_INIT,47WIREDATA_CTAP_CBOR_INFO,48WIREDATA_CTAP_CBOR_AUTHKEY,49WIREDATA_CTAP_CBOR_PINTOKEN,50WIREDATA_CTAP_KEEPALIVE,51WIREDATA_CTAP_KEEPALIVE,52WIREDATA_CTAP_KEEPALIVE,53WIREDATA_CTAP_CBOR_CRED,54};5556/*57* Collection of HID reports from an authenticator issued with a U2F58* registration using the example parameters above.59*/60static const uint8_t dummy_wire_data_u2f[] = {61WIREDATA_CTAP_INIT,62WIREDATA_CTAP_U2F_6985,63WIREDATA_CTAP_U2F_6985,64WIREDATA_CTAP_U2F_6985,65WIREDATA_CTAP_U2F_6985,66WIREDATA_CTAP_U2F_6985,67WIREDATA_CTAP_U2F_REGISTER,68};6970struct param *71unpack(const uint8_t *ptr, size_t len)72{73cbor_item_t *item = NULL, **v;74struct cbor_load_result cbor;75struct param *p;76int ok = -1;7778if ((p = calloc(1, sizeof(*p))) == NULL ||79(item = cbor_load(ptr, len, &cbor)) == NULL ||80cbor.read != len ||81cbor_isa_array(item) == false ||82cbor_array_is_definite(item) == false ||83cbor_array_size(item) != 17 ||84(v = cbor_array_handle(item)) == NULL)85goto fail;8687if (unpack_byte(v[0], &p->rk) < 0 ||88unpack_byte(v[1], &p->type) < 0 ||89unpack_byte(v[2], &p->opt) < 0 ||90unpack_byte(v[3], &p->uv) < 0 ||91unpack_byte(v[4], &p->excl_count) < 0 ||92unpack_int(v[5], &p->ext) < 0 ||93unpack_int(v[6], &p->seed) < 0 ||94unpack_string(v[7], p->pin) < 0 ||95unpack_string(v[8], p->rp_id) < 0 ||96unpack_string(v[9], p->rp_name) < 0 ||97unpack_string(v[10], p->user_icon) < 0 ||98unpack_string(v[11], p->user_name) < 0 ||99unpack_string(v[12], p->user_nick) < 0 ||100unpack_blob(v[13], &p->cdh) < 0 ||101unpack_blob(v[14], &p->user_id) < 0 ||102unpack_blob(v[15], &p->wire_data) < 0 ||103unpack_blob(v[16], &p->excl_cred) < 0)104goto fail;105106ok = 0;107fail:108if (ok < 0) {109free(p);110p = NULL;111}112113if (item)114cbor_decref(&item);115116return p;117}118119size_t120pack(uint8_t *ptr, size_t len, const struct param *p)121{122cbor_item_t *argv[17], *array = NULL;123size_t cbor_alloc_len, cbor_len = 0;124unsigned char *cbor = NULL;125126memset(argv, 0, sizeof(argv));127128if ((array = cbor_new_definite_array(17)) == NULL ||129(argv[0] = pack_byte(p->rk)) == NULL ||130(argv[1] = pack_byte(p->type)) == NULL ||131(argv[2] = pack_byte(p->opt)) == NULL ||132(argv[3] = pack_byte(p->uv)) == NULL ||133(argv[4] = pack_byte(p->excl_count)) == NULL ||134(argv[5] = pack_int(p->ext)) == NULL ||135(argv[6] = pack_int(p->seed)) == NULL ||136(argv[7] = pack_string(p->pin)) == NULL ||137(argv[8] = pack_string(p->rp_id)) == NULL ||138(argv[9] = pack_string(p->rp_name)) == NULL ||139(argv[10] = pack_string(p->user_icon)) == NULL ||140(argv[11] = pack_string(p->user_name)) == NULL ||141(argv[12] = pack_string(p->user_nick)) == NULL ||142(argv[13] = pack_blob(&p->cdh)) == NULL ||143(argv[14] = pack_blob(&p->user_id)) == NULL ||144(argv[15] = pack_blob(&p->wire_data)) == NULL ||145(argv[16] = pack_blob(&p->excl_cred)) == NULL)146goto fail;147148for (size_t i = 0; i < 17; i++)149if (cbor_array_push(array, argv[i]) == false)150goto fail;151152if ((cbor_len = cbor_serialize_alloc(array, &cbor,153&cbor_alloc_len)) == 0 || cbor_len > len) {154cbor_len = 0;155goto fail;156}157158memcpy(ptr, cbor, cbor_len);159fail:160for (size_t i = 0; i < 17; i++)161if (argv[i])162cbor_decref(&argv[i]);163164if (array)165cbor_decref(&array);166167free(cbor);168169return cbor_len;170}171172size_t173pack_dummy(uint8_t *ptr, size_t len)174{175struct param dummy;176uint8_t blob[MAXCORPUS];177size_t blob_len;178179memset(&dummy, 0, sizeof(dummy));180181dummy.type = 1;182dummy.ext = FIDO_EXT_HMAC_SECRET;183184strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));185strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));186strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));187strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));188strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));189strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));190191dummy.cdh.len = sizeof(dummy_cdh);192dummy.user_id.len = sizeof(dummy_user_id);193dummy.wire_data.len = sizeof(dummy_wire_data_fido);194195memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);196memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len);197memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,198dummy.wire_data.len);199200assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);201202if (blob_len > len) {203memcpy(ptr, blob, len);204return len;205}206207memcpy(ptr, blob, blob_len);208209return blob_len;210}211212static void213make_cred(fido_cred_t *cred, uint8_t opt, int type, const struct blob *cdh,214const char *rp_id, const char *rp_name, const struct blob *user_id,215const char *user_name, const char *user_nick, const char *user_icon,216int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count,217const struct blob *excl_cred)218{219fido_dev_t *dev;220221if ((dev = open_dev(opt & 2)) == NULL)222return;223if (opt & 1)224fido_dev_force_u2f(dev);225226for (uint8_t i = 0; i < excl_count; i++)227fido_cred_exclude(cred, excl_cred->body, excl_cred->len);228229fido_cred_set_type(cred, type);230fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);231fido_cred_set_rp(cred, rp_id, rp_name);232fido_cred_set_user(cred, user_id->body, user_id->len, user_name,233user_nick, user_icon);234235if (ext & FIDO_EXT_HMAC_SECRET)236fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET);237if (ext & FIDO_EXT_CRED_BLOB)238fido_cred_set_blob(cred, user_id->body, user_id->len);239if (ext & FIDO_EXT_LARGEBLOB_KEY)240fido_cred_set_extensions(cred, FIDO_EXT_LARGEBLOB_KEY);241if (ext & FIDO_EXT_MINPINLEN)242fido_cred_set_pin_minlen(cred, strlen(pin));243244if (rk & 1)245fido_cred_set_rk(cred, FIDO_OPT_TRUE);246if (uv & 1)247fido_cred_set_uv(cred, FIDO_OPT_TRUE);248if (user_id->len)249fido_cred_set_prot(cred, user_id->body[0] & 0x03);250251/* repeat memory operations to trigger reallocation paths */252fido_cred_set_type(cred, type);253fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);254fido_cred_set_rp(cred, rp_id, rp_name);255fido_cred_set_user(cred, user_id->body, user_id->len, user_name,256user_nick, user_icon);257258if (strlen(pin) == 0)259pin = NULL;260261fido_dev_make_cred(dev, cred, (opt & 1) ? NULL : pin);262263fido_dev_cancel(dev);264fido_dev_close(dev);265fido_dev_free(&dev);266}267268static void269verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,270const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr,271size_t authdata_len, const unsigned char *authdata_raw_ptr,272size_t authdata_raw_len, int ext, uint8_t rk, uint8_t uv,273const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,274size_t sig_len, const unsigned char *attstmt_ptr, size_t attstmt_len,275const char *fmt, int prot, size_t minpinlen)276{277fido_cred_t *cred;278uint8_t flags;279uint32_t sigcount;280int r;281282if ((cred = fido_cred_new()) == NULL)283return;284285fido_cred_set_type(cred, type);286fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len);287fido_cred_set_rp(cred, rp_id, rp_name);288consume(authdata_ptr, authdata_len);289consume(authdata_raw_ptr, authdata_raw_len);290consume(x5c_ptr, x5c_len);291consume(sig_ptr, sig_len);292consume(attstmt_ptr, attstmt_len);293if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)294fido_cred_set_authdata_raw(cred, authdata_raw_ptr,295authdata_raw_len);296fido_cred_set_extensions(cred, ext);297if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) {298fido_cred_set_x509(cred, x5c_ptr, x5c_len);299fido_cred_set_sig(cred, sig_ptr, sig_len);300}301fido_cred_set_prot(cred, prot);302fido_cred_set_pin_minlen(cred, minpinlen);303304if (rk & 1)305fido_cred_set_rk(cred, FIDO_OPT_TRUE);306if (uv & 1)307fido_cred_set_uv(cred, FIDO_OPT_TRUE);308if (fmt)309fido_cred_set_fmt(cred, fmt);310311/* repeat memory operations to trigger reallocation paths */312if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)313fido_cred_set_authdata_raw(cred, authdata_raw_ptr,314authdata_raw_len);315if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) {316fido_cred_set_x509(cred, x5c_ptr, x5c_len);317fido_cred_set_sig(cred, sig_ptr, sig_len);318}319fido_cred_set_x509(cred, x5c_ptr, x5c_len);320fido_cred_set_sig(cred, sig_ptr, sig_len);321322r = fido_cred_verify(cred);323consume(&r, sizeof(r));324r = fido_cred_verify_self(cred);325consume(&r, sizeof(r));326327consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));328consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));329consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred));330consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred));331consume_str(fido_cred_user_name(cred));332consume_str(fido_cred_display_name(cred));333consume(fido_cred_largeblob_key_ptr(cred),334fido_cred_largeblob_key_len(cred));335336flags = fido_cred_flags(cred);337consume(&flags, sizeof(flags));338sigcount = fido_cred_sigcount(cred);339consume(&sigcount, sizeof(sigcount));340type = fido_cred_type(cred);341consume(&type, sizeof(type));342minpinlen = fido_cred_pin_minlen(cred);343consume(&minpinlen, sizeof(minpinlen));344345fido_cred_free(&cred);346}347348static void349test_cred(const struct param *p)350{351fido_cred_t *cred = NULL;352int cose_alg = 0;353354if ((cred = fido_cred_new()) == NULL)355return;356357switch (p->type & 3) {358case 0:359cose_alg = COSE_ES256;360break;361case 1:362cose_alg = COSE_RS256;363break;364case 2:365cose_alg = COSE_ES384;366break;367default:368cose_alg = COSE_EDDSA;369break;370}371372set_wire_data(p->wire_data.body, p->wire_data.len);373374make_cred(cred, p->opt, cose_alg, &p->cdh, p->rp_id, p->rp_name,375&p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext,376p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred);377378verify_cred(cose_alg,379fido_cred_clientdata_hash_ptr(cred),380fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred),381fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred),382fido_cred_authdata_len(cred), fido_cred_authdata_raw_ptr(cred),383fido_cred_authdata_raw_len(cred), p->ext, p->rk, p->uv,384fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),385fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),386fido_cred_attstmt_ptr(cred), fido_cred_attstmt_len(cred),387fido_cred_fmt(cred), fido_cred_prot(cred),388fido_cred_pin_minlen(cred));389390fido_cred_free(&cred);391}392393static void394test_touch(const struct param *p)395{396fido_dev_t *dev;397int r;398int touched;399400set_wire_data(p->wire_data.body, p->wire_data.len);401402if ((dev = open_dev(p->opt & 2)) == NULL)403return;404if (p->opt & 1)405fido_dev_force_u2f(dev);406407r = fido_dev_get_touch_begin(dev);408consume_str(fido_strerr(r));409r = fido_dev_get_touch_status(dev, &touched, -1);410consume_str(fido_strerr(r));411consume(&touched, sizeof(touched));412413fido_dev_cancel(dev);414fido_dev_close(dev);415fido_dev_free(&dev);416}417418static void419test_misc(const struct param *p)420{421fido_cred_t *cred = NULL;422423if ((cred = fido_cred_new()) == NULL)424return;425426/* reuse user id as credential id */427fido_cred_set_id(cred, p->user_id.body, p->user_id.len);428consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));429fido_cred_free(&cred);430}431432void433test(const struct param *p)434{435prng_init((unsigned int)p->seed);436fuzz_clock_reset();437fido_init(FIDO_DEBUG);438fido_set_log_handler(consume_str);439440test_cred(p);441test_touch(p);442test_misc(p);443}444445void446mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN447{448if (flags & MUTATE_SEED)449p->seed = (int)seed;450451if (flags & MUTATE_PARAM) {452mutate_byte(&p->rk);453mutate_byte(&p->type);454mutate_byte(&p->opt);455mutate_byte(&p->uv);456mutate_byte(&p->excl_count);457mutate_int(&p->ext);458mutate_blob(&p->cdh);459mutate_blob(&p->user_id);460mutate_blob(&p->excl_cred);461mutate_string(p->pin);462mutate_string(p->user_icon);463mutate_string(p->user_name);464mutate_string(p->user_nick);465mutate_string(p->rp_id);466mutate_string(p->rp_name);467}468469if (flags & MUTATE_WIREDATA) {470if (p->opt & 1) {471p->wire_data.len = sizeof(dummy_wire_data_u2f);472memcpy(&p->wire_data.body, &dummy_wire_data_u2f,473p->wire_data.len);474} else {475p->wire_data.len = sizeof(dummy_wire_data_fido);476memcpy(&p->wire_data.body, &dummy_wire_data_fido,477p->wire_data.len);478}479mutate_blob(&p->wire_data);480}481}482483484