From 173bfbf7886608a4a7abbfac6a42ac4bf4a3432d Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Sun, 20 Sep 2020 16:14:20 +0100 Subject: New upstream version 1.5.0 --- fuzz/fuzz_cred.c | 458 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 256 insertions(+), 202 deletions(-) (limited to 'fuzz/fuzz_cred.c') diff --git a/fuzz/fuzz_cred.c b/fuzz/fuzz_cred.c index cc37903..87a877a 100644 --- a/fuzz/fuzz_cred.c +++ b/fuzz/fuzz_cred.c @@ -18,43 +18,25 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_U2F 0x01 -#define TAG_TYPE 0x02 -#define TAG_CDH 0x03 -#define TAG_RP_ID 0x04 -#define TAG_RP_NAME 0x05 -#define TAG_USER_ID 0x06 -#define TAG_USER_NAME 0x07 -#define TAG_USER_NICK 0x08 -#define TAG_USER_ICON 0x09 -#define TAG_EXT 0x0a -#define TAG_SEED 0x0b -#define TAG_RK 0x0c -#define TAG_UV 0x0d -#define TAG_PIN 0x0e -#define TAG_WIRE_DATA 0x0f -#define TAG_EXCL_COUNT 0x10 -#define TAG_EXCL_CRED 0x11 - /* 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 u2f; - uint8_t uv; + 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 u2f; + uint8_t uv; }; /* @@ -86,79 +68,157 @@ static const uint8_t dummy_wire_data_u2f[] = { WIREDATA_CTAP_U2F_REGISTER, }; -int LLVMFuzzerTestOneInput(const uint8_t *, size_t); -size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); - -static int -unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN +struct param * +unpack(const uint8_t *ptr, size_t len) { - uint8_t **pp = (void *)&ptr; - - if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || - unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || - unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || - unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || - unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || - unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || - unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || - unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || - unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || - unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || - unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || - unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || - unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || - unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || - unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) - return (-1); - - return (0); + 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->u2f) < 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; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || - pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || - pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || - pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || - pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || - pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || - pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || - pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || - pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || - pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || - pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || - pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || - pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || - pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || - pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) - return (0); - - return (max - len); + 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->u2f)) == 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)) > 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; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (5 * len_byte() + 6 * len_string(max) + 2 * len_int() + - 4 * len_blob(max)); + struct param dummy; + uint8_t blob[4096]; + 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 u2f, int type, const struct blob *cdh, - const char *rp_id, const char *rp_name, struct blob *user_id, + 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, - struct blob *excl_cred) + const struct blob *excl_cred) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; memset(&io, 0, sizeof(io)); @@ -185,6 +245,7 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, fido_cred_set_user(cred, user_id->body, user_id->len, user_name, user_nick, user_icon); fido_cred_set_extensions(cred, ext); + if (rk & 1) fido_cred_set_rk(cred, FIDO_OPT_TRUE); if (uv & 1) @@ -192,6 +253,16 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, 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, u2f & 1 ? NULL : pin); fido_dev_cancel(dev); @@ -206,8 +277,8 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, size_t sig_len, const char *fmt, int prot) { - fido_cred_t *cred; - uint8_t flags; + fido_cred_t *cred; + uint8_t flags; if ((cred = fido_cred_new()) == NULL) return; @@ -229,11 +300,18 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, if (fmt) fido_cred_set_fmt(cred, fmt); - fido_cred_verify(cred); - fido_cred_verify_self(cred); + /* 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_ptr, authdata_len); + fido_cred_set_x509(cred, x5c_ptr, x5c_len); + fido_cred_set_sig(cred, sig_ptr, sig_len); + + assert(fido_cred_verify(cred) != FIDO_OK); + assert(fido_cred_verify_self(cred) != FIDO_OK); 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(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); consume(fido_cred_display_name(cred), @@ -247,30 +325,16 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, fido_cred_free(&cred); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +static void +test_cred(const struct param *p) { - struct param p; - fido_cred_t *cred = NULL; - int cose_alg = 0; - - memset(&p, 0, sizeof(p)); - - if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || - unpack(data, size, &p) < 0) - return (0); - - prng_init((unsigned int)p.seed); - - fido_init(FIDO_DEBUG); - fido_set_log_handler(consume_str); + fido_cred_t *cred = NULL; + int cose_alg = 0; if ((cred = fido_cred_new()) == NULL) - return (0); - - set_wire_data(p.wire_data.body, p.wire_data.len); + return; - switch (p.type & 3) { + switch (p->type & 3) { case 0: cose_alg = COSE_ES256; break; @@ -282,116 +346,106 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) break; } - make_cred(cred, p.u2f, 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); + set_wire_data(p->wire_data.body, p->wire_data.len); + + make_cred(cred, p->u2f, 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), p.ext, p.rk, p.uv, + fido_cred_authdata_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_fmt(cred), fido_cred_prot(cred)); fido_cred_free(&cred); - - return (0); } -static size_t -pack_dummy(uint8_t *ptr, size_t len) +static void +test_touch(const struct param *p) { - struct param dummy; - uint8_t blob[16384]; - size_t blob_len; + fido_dev_t *dev; + fido_dev_io_t io; + int r; + int touched; - memset(&dummy, 0, sizeof(dummy)); + memset(&io, 0, sizeof(io)); - dummy.type = 1; - dummy.ext = FIDO_EXT_HMAC_SECRET; + io.open = dev_open; + io.close = dev_close; + io.read = dev_read; + io.write = dev_write; - 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)); + set_wire_data(p->wire_data.body, p->wire_data.len); - dummy.cdh.len = sizeof(dummy_cdh); - dummy.user_id.len = sizeof(dummy_user_id); - dummy.wire_data.len = sizeof(dummy_wire_data_fido); + if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, + &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { + fido_dev_free(&dev); + return; + } - 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); + if (p->u2f & 1) + fido_dev_force_u2f(dev); - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); + 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)); - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); - } + fido_dev_cancel(dev); + fido_dev_close(dev); + fido_dev_free(&dev); +} - memcpy(ptr, blob, blob_len); +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); - return (blob_len); + test_cred(p); + test_touch(p); } -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) NO_MSAN +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { - struct param p; - uint8_t blob[16384]; - size_t blob_len; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - mutate_byte(&p.rk); - mutate_byte(&p.type); - mutate_byte(&p.u2f); - mutate_byte(&p.uv); - mutate_byte(&p.excl_count); - - mutate_int(&p.ext); - p.seed = (int)seed; - - mutate_blob(&p.cdh); - mutate_blob(&p.user_id); - - if (p.u2f & 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); + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_byte(&p->rk); + mutate_byte(&p->type); + mutate_byte(&p->u2f); + 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); } - mutate_blob(&p.wire_data); - 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); - - blob_len = pack(blob, sizeof(blob), &p); - - if (blob_len == 0 || blob_len > maxsize) - return (0); - - memcpy(data, blob, blob_len); - - return (blob_len); + if (flags & MUTATE_WIREDATA) { + if (p->u2f & 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); + } } -- cgit v1.2.3