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_assert.c | 455 +++++++++++++++++++++++++++-------------------------- 1 file changed, 236 insertions(+), 219 deletions(-) (limited to 'fuzz/fuzz_assert.c') diff --git a/fuzz/fuzz_assert.c b/fuzz/fuzz_assert.c index 5b72658..3ae54eb 100644 --- a/fuzz/fuzz_assert.c +++ b/fuzz/fuzz_assert.c @@ -23,39 +23,23 @@ #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_EXT 0x05 -#define TAG_SEED 0x06 -#define TAG_UP 0x07 -#define TAG_UV 0x08 -#define TAG_WIRE_DATA 0x09 -#define TAG_CRED_COUNT 0x0a -#define TAG_CRED 0x0b -#define TAG_ES256 0x0c -#define TAG_RS256 0x0d -#define TAG_PIN 0x0e -#define TAG_EDDSA 0x0f - /* 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 u2f; - uint8_t up; - uint8_t uv; + 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 u2f; + uint8_t up; + uint8_t uv; }; /* @@ -83,73 +67,153 @@ static const uint8_t dummy_wire_data_u2f[] = { WIREDATA_CTAP_U2F_AUTH, }; -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_UV, pp, &len, &p->uv) < 0 || - unpack_byte(TAG_UP, pp, &len, &p->up) < 0 || - unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || - unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || - unpack_byte(TAG_CRED_COUNT, pp, &len, &p->cred_count) < 0 || - unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || - unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || - unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || - unpack_blob(TAG_RS256, pp, &len, &p->rs256) < 0 || - unpack_blob(TAG_ES256, pp, &len, &p->es256) < 0 || - unpack_blob(TAG_EDDSA, pp, &len, &p->eddsa) < 0 || - unpack_blob(TAG_CRED, pp, &len, &p->cred) < 0 || - unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 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) != 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->u2f) < 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; } -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_UV, &ptr, &len, p->uv) < 0 || - pack_byte(TAG_UP, &ptr, &len, p->up) < 0 || - pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || - pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || - pack_byte(TAG_CRED_COUNT, &ptr, &len, p->cred_count) < 0 || - pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || - pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || - pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || - pack_blob(TAG_RS256, &ptr, &len, &p->rs256) < 0 || - pack_blob(TAG_ES256, &ptr, &len, &p->es256) < 0 || - pack_blob(TAG_EDDSA, &ptr, &len, &p->eddsa) < 0 || - pack_blob(TAG_CRED, &ptr, &len, &p->cred) < 0 || - pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0) - return (0); - - return (max - len); + 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->u2f)) == 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)) > 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; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (5 * len_byte() + 2 * len_int() + 2 * len_string(max) + - 6 * len_blob(max)); + struct param dummy; + uint8_t blob[4096]; + 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 u2f, const struct blob *cdh, const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, - uint8_t cred_count, struct blob *cred) + uint8_t cred_count, const struct blob *cred) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; memset(&io, 0, sizeof(io)); @@ -166,21 +230,31 @@ get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, if (u2f & 1) fido_dev_force_u2f(dev); - - 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); if (ext & 1) fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); + else if (u2f &1) + fido_assert_set_up(assert, FIDO_OPT_FALSE); if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); - /* XXX reuse cred as hmac salt to keep struct param small */ + + 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, u2f & 1 ? NULL : pin); fido_dev_cancel(dev); @@ -194,7 +268,7 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_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; + fido_assert_t *assert = NULL; if ((assert = fido_assert_new()) == NULL) return; @@ -202,16 +276,30 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, 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); - 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_sig(assert, 0, sig_ptr, sig_len); - fido_assert_verify(assert, 0, type, pk); + + /* 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); + + assert(fido_assert_verify(assert, 0, type, pk) != FIDO_OK); fido_assert_free(&assert); } @@ -262,38 +350,30 @@ out: EVP_PKEY_free(pkey); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - fido_assert_t *assert = NULL; - es256_pk_t *es256_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; - - 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_assert_t *assert = NULL; + es256_pk_t *es256_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); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); - switch (p.type & 3) { + switch (p->type & 3) { case 0: cose_alg = COSE_ES256; if ((es256_pk = es256_pk_new()) == NULL) - return (0); + return; - es256_pk_from_ptr(es256_pk, p.es256.body, p.es256.len); + es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len); pk = es256_pk; break; @@ -301,9 +381,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) cose_alg = COSE_RS256; if ((rs256_pk = rs256_pk_new()) == NULL) - return (0); + return; - rs256_pk_from_ptr(rs256_pk, p.rs256.body, p.rs256.len); + rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len); pk = rs256_pk; rs256_convert(pk); @@ -313,9 +393,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) cose_alg = COSE_EDDSA; if ((eddsa_pk = eddsa_pk_new()) == NULL) - return (0); + return; - eddsa_pk_from_ptr(eddsa_pk, p.eddsa.body, p.eddsa.len); + eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len); pk = eddsa_pk; eddsa_convert(pk); @@ -326,10 +406,10 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if ((assert = fido_assert_new()) == NULL) goto out; - set_wire_data(p.wire_data.body, p.wire_data.len); + set_wire_data(p->wire_data.body, p->wire_data.len); - get_assert(assert, p.u2f, &p.cdh, p.rp_id, p.ext, p.up, p.uv, p.pin, - p.cred_count, &p.cred); + get_assert(assert, p->u2f, &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++) { @@ -340,7 +420,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 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); + fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk); consume(fido_assert_id_ptr(assert, i), fido_assert_id_len(assert, i)); consume(fido_assert_user_id_ptr(assert, i), @@ -365,103 +445,40 @@ out: eddsa_pk_free(&eddsa_pk); fido_assert_free(&assert); - - return (0); } -static size_t -pack_dummy(uint8_t *ptr, size_t len) +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { - struct param dummy; - uint8_t blob[16384]; - 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); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); - - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_byte(&p->uv); + mutate_byte(&p->up); + mutate_byte(&p->u2f); + 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); } - memcpy(ptr, blob, blob_len); - - return (blob_len); -} - -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) NO_MSAN -{ - struct param p; - uint8_t blob[16384]; - size_t blob_len; - - (void)seed; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - mutate_byte(&p.uv); - mutate_byte(&p.up); - mutate_byte(&p.u2f); - mutate_byte(&p.type); - mutate_byte(&p.cred_count); - - mutate_int(&p.ext); - p.seed = (int)seed; - - 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_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); } - - mutate_blob(&p.wire_data); - 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); - - blob_len = pack(blob, sizeof(blob), &p); - - if (blob_len == 0 || blob_len > maxsize) - return (0); - - memcpy(data, blob, blob_len); - - return (blob_len); } -- cgit v1.2.3