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/CMakeLists.txt | 1 + fuzz/Dockerfile | 9 +- fuzz/Makefile | 20 +-- fuzz/README | 130 +-------------- fuzz/build-coverage | 33 ++-- fuzz/dummy.h | 4 +- fuzz/export.gnu | 10 ++ fuzz/functions.txt | 197 ++++++++++++---------- fuzz/fuzz_assert.c | 455 ++++++++++++++++++++++++++------------------------- fuzz/fuzz_bio.c | 335 ++++++++++++++++++++------------------ fuzz/fuzz_cred.c | 458 +++++++++++++++++++++++++++++----------------------- fuzz/fuzz_credman.c | 314 ++++++++++++++++++----------------- fuzz/fuzz_mgmt.c | 321 ++++++++++++++++++------------------ fuzz/libfuzzer.c | 174 ++++++++++++++++++++ fuzz/mutator_aux.c | 253 ++++++++--------------------- fuzz/mutator_aux.h | 49 +++--- fuzz/prng.c | 3 +- fuzz/report.tgz | Bin 211709 -> 222723 bytes fuzz/summary.txt | 31 ++-- 19 files changed, 1437 insertions(+), 1360 deletions(-) create mode 100644 fuzz/libfuzzer.c mode change 100755 => 100644 fuzz/prng.c (limited to 'fuzz') diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 241cdc7..70c5eec 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -8,6 +8,7 @@ list(APPEND COMPAT_SOURCES ) list(APPEND COMMON_SOURCES + libfuzzer.c mutator_aux.c ) diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile index 68afd99..f9152f8 100644 --- a/fuzz/Dockerfile +++ b/fuzz/Dockerfile @@ -2,9 +2,10 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -FROM ubuntu:bionic +FROM ubuntu:focal +ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update -RUN apt-get install -y clang-9 cmake git libssl-dev libudev-dev make pkg-config -RUN git clone --branch v0.5.0 https://github.com/PJK/libcbor +RUN apt-get install -y clang-10 cmake git libssl-dev libudev-dev make pkg-config +RUN git clone --branch v0.7.0 https://github.com/PJK/libcbor RUN git clone https://github.com/yubico/libfido2 -RUN CC=clang-9 /libfido2/fuzz/build-coverage /libcbor /libfido2 +RUN CC=clang-10 CXX=clang++-10 /libfido2/fuzz/build-coverage /libcbor /libfido2 diff --git a/fuzz/Makefile b/fuzz/Makefile index c8fe0b8..77699ac 100644 --- a/fuzz/Makefile +++ b/fuzz/Makefile @@ -2,10 +2,10 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -IMAGE := libfido2-coverage:1.3.0 +IMAGE := libfido2-coverage:1.5.0 RUNNER := libfido2-runner -PROFDATA := llvm-profdata-9 -COV := llvm-cov-9 +PROFDATA := llvm-profdata-10 +COV := llvm-cov-10 TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt CORPORA := $(foreach f,${TARGETS},${f}/corpus) MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus) @@ -26,16 +26,16 @@ sync: run docker exec ${RUNNER} make -C libfido2/build corpus: sync - docker exec ${RUNNER} /bin/bash -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}' + 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/bash -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ + /bin/sh -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ -runs=1 /libfido2/fuzz/$@' ${MINIFY}: /minify/%/corpus: % - docker exec ${RUNNER} /bin/bash -c 'rm -rf $@ && mkdir -p $@ && \ + 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/bash -c 'rm -f /$@ && ${PROFDATA} \ + docker exec ${RUNNER} /bin/sh -c 'rm -f /$@ && ${PROFDATA} \ merge -sparse profraw/* -o $@' report.tgz: profdata - docker exec ${RUNNER} /bin/bash -c 'rm -rf /report && mkdir /report && \ + docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \ ${COV} show -format=html -tab-size=8 -instr-profile=/$< \ -output-dir=/report /libfido2/build/src/libfido2.so' docker exec -i ${RUNNER} tar Czcf / - report > $@ @@ -57,12 +57,12 @@ summary.txt: profdata /libfido2/build/src/libfido2.so -instr-profile=/$< > $@ functions.txt: profdata - docker exec ${RUNNER} /bin/bash -c '${COV} report -use-color=false \ + docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \ -show-functions -instr-profile=/$< \ /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@ clean: run - docker exec ${RUNNER} /bin/bash -c 'rm -rf /profraw /profdata && \ + docker exec ${RUNNER} /bin/sh -c 'rm -rf /profraw /profdata && \ make -C /libfido2/build clean' -docker stop ${RUNNER} rm -rf ${TARGETS} diff --git a/fuzz/README b/fuzz/README index 42646e4..03de9d0 100644 --- a/fuzz/README +++ b/fuzz/README @@ -3,10 +3,8 @@ 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=1 --DAFL=1, and use preload-fuzz.c to read device data from stdin. Examples of -this approach can be found in the harnesses under fuzz/harnesses/ that fuzz -the standalone examples and tools bundled with libfido2. +authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1, 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, and fuzz_mgmt.c for examples. To build these harnesses, @@ -15,129 +13,7 @@ use -DFUZZ=1 -DLIBFUZZER=1. 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, alternatively, patch libcbor with -the diff at the bottom of this file. - -1. Using ASAN + UBSAN - -- Make sure you have libcbor built with -fsanitize=address; -- Make sure you have OpenSSL built with -fsanitize=address; -- Rebuild libfido2 with -DASAN=1 -DUBSAN=1. - -1.1 Decide where your workspace will live - -$ export FAKEROOT=/home/pedro/fakeroot -$ mkdir -p ${FAKEROOT}/src - -1.2 Building libcbor with ASAN - -$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor -$ cd ${FAKEROOT}/src/libcbor - -Assuming libfido2 is under ${FAKEROOT}/src/libfido2: - -$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README -$ mkdir build -$ cd build -$ cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \ - -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \ - -DCMAKE_INSTALL_LIBDIR=lib .. -$ make -$ make install - -1.3 Building OpenSSL with ASAN - -$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl -$ cd ${FAKEROOT}/src/openssl -$ ./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \ - --openssldir=${FAKEROOT}/openssl -$ make clean -$ make -$ make install_sw - -1.4 Building libfido2 with libFuzzer and ASAN + UBSAN - -$ cd ${FAKEROOT}/src/libfido2 -$ mkdir build -$ cd build -$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ - -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCMAKE_BUILD_TYPE=Debug .. -$ make - -2. Using MSAN + UBSAN - -- Make sure you have libcbor built with -fsanitize=memory; -- Make sure you have OpenSSL built with -fsanitize=memory; -- Rebuild libfido2 with -DMSAN=1 -DUBSAN=1. - -2.1 Decide where your workspace will live - -$ export FAKEROOT=/home/pedro/fakeroot -$ mkdir -p ${FAKEROOT}/src - -2.2 Building libcbor with MSAN - -$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor -$ cd ${FAKEROOT}/src/libcbor - -Assuming libfido2 is under ${FAKEROOT}/src/libfido2: - -$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README -$ mkdir build -$ cd build -$ cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \ - -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \ - -DCMAKE_INSTALL_LIBDIR=lib .. -$ make -$ make install - -2.2 Building OpenSSL with MSAN - -$ mkdir -p ${FAKEROOT}/src -$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl -$ cd ${FAKEROOT}/src/openssl -$ ./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \ - --openssldir=${FAKEROOT}/openssl -$ make clean -$ make -$ make install_sw - -2.3 Building libfido2 with libFuzzer and MSAN + UBSAN - -$ cd ${FAKEROOT}/src/libfido2 -$ mkdir build -$ cd build -$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ - -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCMAKE_BUILD_TYPE=Debug .. -$ make - -3. Running the libFuzzer harnesses - -When running under ASAN, you may want to set ASAN_OPTIONS to -'allocator_may_return_null=1:detect_stack_use_after_return=1'. - -The recommended way to run the harnesses is: - -$ fuzz_{assert,cred,credman,mgmt} -use_value_profile=1 -reload=30 \ - -print_pcs=1 -print_funcs=30 -timeout=10 CORPUS_DIR - -You may want to use -jobs or -workers depending on the number of logical -cores available for fuzzing. - -4. Auxiliary scripts - -A set of harnesses and auxiliary scripts can be found under harnesses/. To -compile coverage reports, adjust the harnesses to your setup and run 'report'. +the OS level (e.g. cgroups on Linux), or patch libcbor with the diff below. diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c index aa049a2..e294b38 100644 diff --git a/fuzz/build-coverage b/fuzz/build-coverage index af9f8df..0f8310d 100755 --- a/fuzz/build-coverage +++ b/fuzz/build-coverage @@ -1,27 +1,30 @@ -#!/bin/bash -eux -# +#!/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. -LIBCBOR=$1 -LIBFIDO2=$2 +LIBCBOR="$1" +LIBFIDO2="$2" -CC=${CC:-clang} -PKG_CONFIG_PATH=${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig} +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 +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 -DCMAKE_INSTALL_PREFIX=${LIBCBOR}/install ..) -make -C ${LIBCBOR}/build all install +(cd "${LIBCBOR}" && patch -N -l -s -p0 < "${LIBFIDO2}/fuzz/README") || true +mkdir "${LIBCBOR}/build" "${LIBCBOR}/install" +(cd "${LIBCBOR}/build" && cmake -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..) +make -C "${LIBCBOR}/build" all install # Build libfido2. -mkdir -p ${LIBFIDO2}/build -(cd ${LIBFIDO2}/build && cmake -DFUZZ=1 -DLIBFUZZER=1 -DCOVERAGE=1 \ - -DCMAKE_BUILD_TYPE=Debug ..) -make -C ${LIBFIDO2}/build +mkdir -p "${LIBFIDO2}/build" +export CFLAGS="-fprofile-instr-generate -fcoverage-mapping" +export LDFLAGS="${CFLAGS}" +(cd "${LIBFIDO2}/build" && cmake -DFUZZ=1 -DLIBFUZZER=1 \ + -DCMAKE_BUILD_TYPE=Debug ..) +make -C "${LIBFIDO2}/build" diff --git a/fuzz/dummy.h b/fuzz/dummy.h index a899e4a..981ccee 100644 --- a/fuzz/dummy.h +++ b/fuzz/dummy.h @@ -10,6 +10,8 @@ #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"; @@ -17,8 +19,6 @@ const char dummy_user_icon[] = "an icon"; const char dummy_user_name[] = "john smith"; const char dummy_user_nick[] = "jsmith"; const uint8_t dummy_id[] = { 0x5e, 0xd2 }; -const char dummy_pin1[] = "skepp cg0u3;Y.."; -const char dummy_pin2[] = "bastilha 6rJrfQZI."; const uint8_t dummy_user_id[] = { 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, diff --git a/fuzz/export.gnu b/fuzz/export.gnu index 68463ff..80941e4 100644 --- a/fuzz/export.gnu +++ b/fuzz/export.gnu @@ -76,6 +76,8 @@ fido_cbor_info_extensions_ptr; fido_cbor_info_free; fido_cbor_info_maxmsgsiz; + fido_cbor_info_maxcredcntlst; + fido_cbor_info_maxcredidlen; fido_cbor_info_fwversion; fido_cbor_info_new; fido_cbor_info_options_len; @@ -96,6 +98,8 @@ 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; @@ -155,6 +159,9 @@ fido_dev_get_assert; fido_dev_get_cbor_info; fido_dev_get_retry_count; + fido_dev_get_touch_begin; + fido_dev_get_touch_status; + fido_dev_has_pin; fido_dev_info_free; fido_dev_info_manifest; fido_dev_info_manufacturer_string; @@ -174,6 +181,9 @@ fido_dev_reset; fido_dev_set_io_functions; fido_dev_set_pin; + fido_dev_set_transport_functions; + fido_dev_supports_cred_prot; + fido_dev_supports_pin; fido_init; fido_set_log_handler; fido_strerr; diff --git a/fuzz/functions.txt b/fuzz/functions.txt index 27a9608..90284dd 100644 --- a/fuzz/functions.txt +++ b/fuzz/functions.txt @@ -9,16 +9,16 @@ TOTAL 56 0 100.00% 82 0 100.00% File '/libfido2/src/assert.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_dev_get_assert 35 3 91.43% 38 4 89.47% +fido_dev_get_assert 35 0 100.00% 38 0 100.00% fido_check_flags 13 0 100.00% 18 0 100.00% fido_get_signed_hash 32 0 100.00% 46 0 100.00% fido_verify_sig_es256 17 2 88.24% 31 7 77.42% fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% -fido_verify_sig_eddsa 23 4 82.61% 43 13 69.77% -fido_assert_verify 48 4 91.67% 79 4 94.94% +fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72% +fido_assert_verify 48 4 91.67% 79 5 93.67% fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% -fido_assert_set_rp 12 1 91.67% 14 3 78.57% +fido_assert_set_rp 12 0 100.00% 14 0 100.00% fido_assert_allow_cred 13 2 84.62% 29 3 89.66% fido_assert_set_extensions 9 0 100.00% 8 0 100.00% fido_assert_set_options 6 6 0.00% 6 6 0.00% @@ -28,7 +28,7 @@ fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 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% 15 0 100.00% -fido_assert_reset_rx 6 1 83.33% 24 3 87.50% +fido_assert_reset_rx 6 0 100.00% 24 0 100.00% fido_assert_free 6 0 100.00% 13 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% @@ -48,22 +48,22 @@ fido_assert_user_display_name 4 0 100.00% 6 0 fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% fido_assert_set_authdata 24 0 100.00% 35 0 100.00% -fido_assert_set_authdata_raw 24 4 83.33% 34 7 79.41% +fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00% fido_assert_set_sig 14 0 100.00% 17 0 100.00% fido_assert_set_count 10 0 100.00% 21 0 100.00% -assert.c:fido_dev_get_assert_wait 21 1 95.24% 16 2 87.50% +assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00% assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00% assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% -assert.c:fido_get_next_assert_tx 8 2 75.00% 10 3 70.00% -assert.c:fido_get_next_assert_rx 15 4 73.33% 26 7 73.08% -assert.c:decrypt_hmac_secrets 9 3 66.67% 15 7 53.33% +assert.c:fido_get_next_assert_tx 8 0 100.00% 10 0 100.00% +assert.c:fido_get_next_assert_rx 15 2 86.67% 26 4 84.62% +assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00% assert.c:check_extensions 4 0 100.00% 9 0 100.00% assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 566 43 92.40% 900 87 90.33% +TOTAL 566 24 95.76% 900 50 94.44% File '/libfido2/src/authkey.c': Name Regions Miss Cover Lines Miss Cover @@ -135,14 +135,14 @@ 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_set 11 1 90.91% 25 4 84.00% +fido_blob_set 11 0 100.00% 25 0 100.00% fido_blob_free 8 0 100.00% 16 0 100.00% fido_free_blob_array 9 0 100.00% 17 0 100.00% fido_blob_encode 6 0 100.00% 6 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% --------------------------------------------------------------------------------------- -TOTAL 39 1 97.44% 73 4 94.52% +TOTAL 39 0 100.00% 73 0 100.00% File '/libfido2/src/buf.c': Name Regions Miss Cover Lines Miss Cover @@ -155,7 +155,7 @@ TOTAL 8 1 87.50% 20 1 File '/libfido2/src/cbor.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -cbor_map_iter 20 0 100.00% 30 0 100.00% +cbor_map_iter 20 1 95.00% 30 4 86.67% cbor_array_iter 12 0 100.00% 20 0 100.00% cbor_parse_reply 27 0 100.00% 43 0 100.00% cbor_vector_free 6 0 100.00% 5 0 100.00% @@ -168,23 +168,23 @@ cbor_flatten_vector 14 1 92.86% 21 1 cbor_build_frame 15 0 100.00% 32 0 100.00% cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% cbor_encode_user_entity 21 0 100.00% 18 0 100.00% -cbor_encode_pubkey_param 36 1 97.22% 48 0 100.00% +cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00% cbor_encode_pubkey 10 0 100.00% 13 0 100.00% -cbor_encode_pubkey_list 18 1 94.44% 23 0 100.00% -cbor_encode_extensions 24 2 91.67% 26 3 88.46% +cbor_encode_pubkey_list 18 0 100.00% 23 0 100.00% +cbor_encode_extensions 28 0 100.00% 28 0 100.00% cbor_encode_options 13 0 100.00% 14 0 100.00% cbor_encode_assert_options 13 0 100.00% 14 0 100.00% cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% -cbor_encode_change_pin_auth 44 1 97.73% 69 3 95.65% +cbor_encode_change_pin_auth 39 0 100.00% 60 0 100.00% cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% -cbor_encode_hmac_secret_param 41 2 95.12% 66 9 86.36% +cbor_encode_hmac_secret_param 41 1 97.56% 66 4 93.94% cbor_decode_fmt 9 0 100.00% 18 0 100.00% -cbor_decode_pubkey 21 6 71.43% 32 7 78.12% +cbor_decode_pubkey 21 1 95.24% 32 2 93.75% cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00% -cbor_decode_assert_authdata 23 2 91.30% 44 2 95.45% +cbor_decode_assert_authdata 23 0 100.00% 44 0 100.00% cbor_decode_attstmt 8 0 100.00% 10 0 100.00% cbor_decode_uint64 4 0 100.00% 10 0 100.00% cbor_decode_cred_id 8 0 100.00% 10 0 100.00% @@ -193,30 +193,30 @@ cbor_decode_rp_entity 8 0 100.00% 10 0 cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% cbor.c:check_key_type 8 0 100.00% 9 0 100.00% cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% -cbor.c:cbor_add_uint8 14 1 92.86% 26 3 88.46% +cbor.c:cbor_add_uint8 14 0 100.00% 26 0 100.00% cbor.c:sha256 7 0 100.00% 15 0 100.00% -cbor.c:get_cose_alg 36 6 83.33% 48 6 87.50% +cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00% cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% -cbor.c:decode_extensions 14 9 35.71% 34 13 61.76% -cbor.c:decode_extension 27 27 0.00% 36 36 0.00% -cbor.c:decode_hmac_secret 16 4 75.00% 32 6 81.25% -cbor.c:decode_hmac_secret_aux 7 7 0.00% 17 17 0.00% +cbor.c:decode_extensions 14 0 100.00% 34 0 100.00% +cbor.c:decode_extension 27 2 92.59% 36 6 83.33% +cbor.c:decode_hmac_secret 16 0 100.00% 32 0 100.00% +cbor.c:decode_hmac_secret_aux 7 0 100.00% 17 0 100.00% cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00% cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 884 70 92.08% 1371 106 92.27% +TOTAL 883 6 99.32% 1364 17 98.75% 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% 14 0 100.00% -fido_cred_verify 46 6 86.96% 71 11 84.51% -fido_cred_verify_self 54 14 74.07% 90 22 75.56% +fido_cred_verify 46 2 95.65% 71 3 95.77% +fido_cred_verify_self 54 4 92.59% 90 5 94.44% fido_cred_new 1 0 100.00% 3 0 100.00% fido_cred_reset_tx 1 0 100.00% 20 0 100.00% fido_cred_reset_rx 1 0 100.00% 8 0 100.00% @@ -227,15 +227,15 @@ fido_cred_set_x509 12 0 100.00% 16 0 fido_cred_set_sig 12 0 100.00% 16 0 100.00% fido_cred_exclude 14 2 85.71% 25 3 88.00% fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% -fido_cred_set_rp 18 2 88.89% 26 6 76.92% -fido_cred_set_user 33 4 87.88% 50 13 74.00% +fido_cred_set_rp 18 0 100.00% 26 0 100.00% +fido_cred_set_user 33 0 100.00% 50 0 100.00% fido_cred_set_extensions 15 0 100.00% 12 0 100.00% fido_cred_set_options 6 6 0.00% 6 6 0.00% fido_cred_set_rk 2 0 100.00% 5 0 100.00% fido_cred_set_uv 2 0 100.00% 5 0 100.00% -fido_cred_set_prot 21 2 90.48% 16 0 100.00% +fido_cred_set_prot 21 0 100.00% 16 0 100.00% fido_cred_set_fmt 16 4 75.00% 15 1 93.33% -fido_cred_set_type 17 2 88.24% 9 1 88.89% +fido_cred_set_type 17 0 100.00% 9 0 100.00% fido_cred_type 1 0 100.00% 3 0 100.00% fido_cred_flags 1 0 100.00% 3 0 100.00% fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% @@ -246,10 +246,12 @@ fido_cred_sig_ptr 1 0 100.00% 3 0 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_pubkey_ptr 9 2 77.78% 20 2 90.00% -fido_cred_pubkey_len 9 2 77.78% 20 2 90.00% +fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00% +fido_cred_pubkey_len 9 0 100.00% 20 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_fmt 1 0 100.00% 3 0 100.00% fido_cred_rp_id 1 0 100.00% 3 0 100.00% @@ -269,7 +271,7 @@ cred.c:fido_cred_clean_authdata 1 0 100.00% 9 0 cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 534 51 90.45% 830 78 90.60% +TOTAL 536 23 95.71% 836 29 96.53% File '/libfido2/src/credman.c': Name Regions Miss Cover Lines Miss Cover @@ -295,14 +297,14 @@ fido_credman_rp_id_hash_len 4 0 100.00% 6 0 fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% credman.c:credman_tx 30 0 100.00% 53 0 100.00% -credman.c:credman_prepare_hmac 21 1 95.24% 43 2 95.35% +credman.c:credman_prepare_hmac 21 1 95.24% 43 3 93.02% credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00% credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00% credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% -credman.c:credman_parse_rk 13 0 100.00% 25 0 100.00% +credman.c:credman_parse_rk 22 0 100.00% 31 0 100.00% credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62% credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% @@ -313,7 +315,7 @@ credman.c:credman_rx_next_rp 15 2 86.67% 26 4 credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 376 18 95.21% 589 15 97.45% +TOTAL 385 18 95.32% 595 16 97.31% File '/libfido2/src/dev.c': Name Regions Miss Cover Lines Miss Cover @@ -324,9 +326,11 @@ fido_dev_info_manifest 17 17 0.00% 24 24 fido_dev_open_with_info 5 5 0.00% 6 6 0.00% fido_dev_open 1 0 100.00% 3 0 100.00% fido_dev_close 8 2 75.00% 9 0 100.00% -fido_dev_cancel 7 0 100.00% 6 0 100.00% -fido_dev_set_io_functions 18 4 77.78% 16 6 62.50% -fido_dev_set_transport_functions 6 6 0.00% 10 10 0.00% +fido_dev_cancel 11 0 100.00% 9 0 100.00% +fido_dev_get_touch_begin 50 0 100.00% 68 0 100.00% +fido_dev_get_touch_status 17 0 100.00% 25 0 100.00% +fido_dev_set_io_functions 18 4 77.78% 17 6 64.71% +fido_dev_set_transport_functions 6 6 0.00% 11 11 0.00% fido_init 7 1 85.71% 4 0 100.00% fido_dev_new 5 0 100.00% 16 0 100.00% fido_dev_new_with_info 17 17 0.00% 26 26 0.00% @@ -337,15 +341,20 @@ fido_dev_minor 1 0 100.00% 3 0 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_force_u2f 2 0 100.00% 3 0 100.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_force_u2f 2 0 100.00% 4 0 100.00% fido_dev_force_fido2 2 2 0.00% 3 3 0.00% dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00% dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% -dev.c:fido_dev_open_tx 25 8 68.00% 32 12 62.50% +dev.c:fido_dev_open_tx 51 13 74.51% 63 23 63.49% dev.c:obtain_nonce 4 1 75.00% 5 1 80.00% -dev.c:fido_dev_open_rx 32 0 100.00% 53 0 100.00% +dev.c:set_random_report_len 11 0 100.00% 6 0 100.00% +dev.c:fido_dev_open_rx 33 0 100.00% 56 0 100.00% +dev.c:fido_dev_set_flags 17 0 100.00% 24 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 201 85 57.71% 294 128 56.46% +TOTAL 334 90 73.05% 466 140 69.96% File '/libfido2/src/ecdh.c': Name Regions Miss Cover Lines Miss Cover @@ -372,9 +381,9 @@ TOTAL 54 0 100.00% 79 0 File '/libfido2/src/err.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_strerr 108 108 0.00% 112 112 0.00% +fido_strerr 112 8 92.86% 116 8 93.10% --------------------------------------------------------------------------------------- -TOTAL 108 108 0.00% 112 112 0.00% +TOTAL 112 8 92.86% 116 8 93.10% File '/libfido2/src/es256.c': Name Regions Miss Cover Lines Miss Cover @@ -389,14 +398,14 @@ es256_pk_from_ptr 11 0 100.00% 13 0 es256_pk_set_x 1 0 100.00% 5 0 100.00% es256_pk_set_y 1 0 100.00% 5 0 100.00% es256_sk_create 39 0 100.00% 46 0 100.00% -es256_pk_to_EVP_PKEY 41 0 100.00% 58 0 100.00% -es256_pk_from_EC_KEY 38 0 100.00% 39 0 100.00% -es256_sk_to_EVP_PKEY 27 0 100.00% 41 0 100.00% +es256_pk_to_EVP_PKEY 42 0 100.00% 66 0 100.00% +es256_pk_from_EC_KEY 38 0 100.00% 43 0 100.00% +es256_sk_to_EVP_PKEY 28 0 100.00% 50 0 100.00% es256_derive_pk 25 0 100.00% 34 0 100.00% es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% es256.c:decode_coord 8 0 100.00% 12 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 278 0 100.00% 377 0 100.00% +TOTAL 280 0 100.00% 398 0 100.00% File '/libfido2/src/extern.h': Name Regions Miss Cover Lines Miss Cover @@ -423,20 +432,27 @@ TOTAL 16 16 0.00% 38 38 File '/libfido2/src/hid_linux.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_hid_manifest 33 33 0.00% 46 46 0.00% -fido_hid_open 6 6 0.00% 11 11 0.00% +fido_hid_manifest 35 35 0.00% 50 50 0.00% +fido_hid_open 17 17 0.00% 22 22 0.00% fido_hid_close 1 1 0.00% 6 6 0.00% -fido_hid_read 12 12 0.00% 16 16 0.00% -fido_hid_write 12 12 0.00% 16 16 0.00% -hid_linux.c:copy_info 35 35 0.00% 56 56 0.00% -hid_linux.c:is_fido 6 6 0.00% 14 14 0.00% -hid_linux.c:get_report_descriptor 17 17 0.00% 30 30 0.00% -hid_linux.c:get_usage_info 16 16 0.00% 33 33 0.00% +fido_hid_read 12 12 0.00% 21 21 0.00% +fido_hid_write 9 9 0.00% 16 16 0.00% +fido_hid_report_in_len 1 1 0.00% 5 5 0.00% +fido_hid_report_out_len 1 1 0.00% 5 5 0.00% +hid_linux.c:copy_info 30 30 0.00% 52 52 0.00% +hid_linux.c:is_fido 9 9 0.00% 23 23 0.00% +hid_linux.c:get_usage_info 16 16 0.00% 30 30 0.00% hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% -hid_linux.c:parse_uevent 16 16 0.00% 30 30 0.00% ---------------------------------------------------------------------------------------- -TOTAL 166 166 0.00% 292 292 0.00% +hid_linux.c:get_parent_attr 6 6 0.00% 11 11 0.00% +hid_linux.c:parse_uevent 12 12 0.00% 28 28 0.00% +hid_linux.c:get_usb_attr 1 1 0.00% 3 3 0.00% +hid_linux.c:get_report_descriptor 11 11 0.00% 18 18 0.00% +hid_linux.c:get_report_sizes 19 19 0.00% 33 33 0.00% +hid_linux.c:waitfd 28 28 0.00% 43 43 0.00% +hid_linux.c:timespec_to_ms 15 15 0.00% 16 16 0.00% +--------------------------------------------------------------------------------------- +TOTAL 235 235 0.00% 416 416 0.00% File '/libfido2/src/info.c': Name Regions Miss Cover Lines Miss Cover @@ -455,11 +471,14 @@ fido_cbor_info_options_name_ptr 1 0 100.00% 3 0 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_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_fwversion 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% info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00% info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00% -info.c:parse_reply_element 13 0 100.00% 27 0 100.00% +info.c:parse_reply_element 16 0 100.00% 33 0 100.00% info.c:decode_versions 12 0 100.00% 21 0 100.00% info.c:decode_version 4 0 100.00% 14 0 100.00% info.c:decode_extensions 12 0 100.00% 21 0 100.00% @@ -473,23 +492,23 @@ info.c:free_str_array 4 0 100.00% 8 0 info.c:free_opt_array 4 0 100.00% 9 0 100.00% info.c:free_byte_array 1 0 100.00% 6 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 146 0 100.00% 304 0 100.00% +TOTAL 152 0 100.00% 319 0 100.00% File '/libfido2/src/io.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_tx 14 1 92.86% 18 0 100.00% -fido_rx 13 2 84.62% 21 3 85.71% +fido_tx 13 1 92.31% 14 0 100.00% +fido_rx 13 2 84.62% 19 3 84.21% fido_rx_cbor_status 8 0 100.00% 12 0 100.00% -io.c:tx_empty 7 0 100.00% 16 0 100.00% +io.c:tx_empty 9 0 100.00% 17 0 100.00% io.c:tx 13 0 100.00% 21 0 100.00% -io.c:tx_preamble 10 0 100.00% 20 0 100.00% -io.c:tx_frame 9 0 100.00% 18 0 100.00% -io.c:rx 25 1 96.00% 58 4 93.10% -io.c:rx_preamble 18 1 94.44% 25 4 84.00% -io.c:rx_frame 6 0 100.00% 9 0 100.00% +io.c:tx_preamble 16 1 93.75% 24 1 95.83% +io.c:tx_frame 15 1 93.33% 22 1 95.45% +io.c:rx 40 2 95.00% 68 1 98.53% +io.c:rx_preamble 21 2 90.48% 28 5 82.14% +io.c:rx_frame 8 0 100.00% 11 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 123 5 95.93% 218 11 94.95% +TOTAL 156 9 94.23% 236 11 95.34% File '/libfido2/src/iso7816.c': Name Regions Miss Cover Lines Miss Cover @@ -547,32 +566,34 @@ TOTAL 19 0 100.00% 22 0 File '/libfido2/src/rs256.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -rs256_pk_decode 8 8 0.00% 10 10 0.00% +rs256_pk_decode 8 0 100.00% 10 0 100.00% rs256_pk_new 1 0 100.00% 3 0 100.00% rs256_pk_free 6 0 100.00% 11 0 100.00% rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% rs256_pk_from_RSA 32 4 87.50% 32 6 81.25% -rs256.c:decode_rsa_pubkey 9 9 0.00% 16 16 0.00% -rs256.c:decode_bignum 8 8 0.00% 12 12 0.00% +rs256.c:decode_rsa_pubkey 9 1 88.89% 16 4 75.00% +rs256.c:decode_bignum 8 1 87.50% 12 3 75.00% --------------------------------------------------------------------------------------- -TOTAL 102 29 71.57% 140 44 68.57% +TOTAL 102 6 94.12% 140 13 90.71% File '/libfido2/src/u2f.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -u2f_register 70 5 92.86% 88 7 92.05% -u2f_authenticate 32 4 87.50% 44 2 95.45% +u2f_register 70 1 98.57% 88 0 100.00% +u2f_authenticate 32 0 100.00% 44 0 100.00% +u2f_get_touch_begin 30 0 100.00% 46 0 100.00% +u2f_get_touch_status 18 0 100.00% 29 0 100.00% u2f.c:key_lookup 44 0 100.00% 69 0 100.00% -u2f.c:send_dummy_register 31 5 83.87% 49 8 83.67% +u2f.c:send_dummy_register 31 1 96.77% 49 0 100.00% u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% -u2f.c:x5c_get 21 2 90.48% 37 6 83.78% +u2f.c:x5c_get 21 1 95.24% 37 3 91.89% u2f.c:sig_get 8 1 87.50% 16 6 62.50% -u2f.c:encode_cred_authdata 37 3 91.89% 82 9 89.02% -u2f.c:cbor_blob_from_ec_point 22 1 95.45% 39 3 92.31% -u2f.c:u2f_authenticate_single 36 2 94.44% 58 4 93.10% -u2f.c:do_auth 50 3 94.00% 71 4 94.37% +u2f.c:encode_cred_authdata 37 2 94.59% 82 6 92.68% +u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00% +u2f.c:u2f_authenticate_single 36 0 100.00% 58 0 100.00% +u2f.c:do_auth 50 1 98.00% 71 0 100.00% u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 443 28 93.68% 699 52 92.56% +TOTAL 491 9 98.17% 774 18 97.67% 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); } diff --git a/fuzz/fuzz_bio.c b/fuzz/fuzz_bio.c index 05f6ce3..5051a34 100644 --- a/fuzz/fuzz_bio.c +++ b/fuzz/fuzz_bio.c @@ -19,27 +19,17 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_PIN 0x01 -#define TAG_NAME 0x02 -#define TAG_SEED 0x03 -#define TAG_ID 0x04 -#define TAG_INFO_WIRE_DATA 0x05 -#define TAG_ENROLL_WIRE_DATA 0x06 -#define TAG_LIST_WIRE_DATA 0x07 -#define TAG_SET_NAME_WIRE_DATA 0x08 -#define TAG_REMOVE_WIRE_DATA 0x09 - /* 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; + 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; }; /* @@ -100,58 +90,141 @@ static const uint8_t dummy_remove_wire_data[] = { WIREDATA_CTAP_CBOR_STATUS, }; -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_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_string(TAG_NAME, pp, &len, p->name) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || - unpack_blob(TAG_ID, pp, &len, &p->id) < 0 || - unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || - unpack_blob(TAG_ENROLL_WIRE_DATA, pp, &len, &p->enroll_wire_data) < 0 || - unpack_blob(TAG_LIST_WIRE_DATA, pp, &len, &p->list_wire_data) < 0 || - unpack_blob(TAG_SET_NAME_WIRE_DATA, pp, &len, &p->set_name_wire_data) < 0 || - unpack_blob(TAG_REMOVE_WIRE_DATA, pp, &len, &p->remove_wire_data) < 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) != 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; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_string(TAG_NAME, &ptr, &len, p->name) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || - pack_blob(TAG_ID, &ptr, &len, &p->id) < 0 || - pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || - pack_blob(TAG_ENROLL_WIRE_DATA, &ptr, &len, &p->enroll_wire_data) < 0 || - pack_blob(TAG_LIST_WIRE_DATA, &ptr, &len, &p->list_wire_data) < 0 || - pack_blob(TAG_SET_NAME_WIRE_DATA, &ptr, &len, &p->set_name_wire_data) < 0 || - pack_blob(TAG_REMOVE_WIRE_DATA, &ptr, &len, &p->remove_wire_data) < 0) - return (0); - - return (max - len); + 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)) > 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; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (2 * len_string(max) + len_int() + 6 * len_blob(max)); + struct param dummy; + uint8_t blob[4096]; + 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() +prepare_dev(void) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; + bool x; memset(&io, 0, sizeof(io)); @@ -163,26 +236,35 @@ prepare_dev() 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 (NULL); + return NULL; } - return (dev); + 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)); + + return dev; } static void -get_info(struct param *p) +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; - fido_bio_dev_get_info(dev, i); + 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); @@ -217,7 +299,7 @@ consume_enroll(fido_bio_enroll_t *e) } static void -enroll(struct param *p) +enroll(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; @@ -252,7 +334,7 @@ done: } static void -list(struct param *p) +list(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_array_t *ta = NULL; @@ -280,7 +362,7 @@ done: } static void -set_name(struct param *p) +set_name(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; @@ -306,10 +388,11 @@ done: } static void -del(struct param *p) +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); @@ -317,8 +400,9 @@ del(struct param *p) (t = fido_bio_template_new()) == NULL) goto done; - fido_bio_template_set_id(t, p->id.body, p->id.len); + 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); @@ -330,106 +414,37 @@ done: fido_bio_template_free(&t); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - - 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); - + prng_init((unsigned int)p->seed); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); - get_info(&p); - enroll(&p); - list(&p); - set_name(&p); - del(&p); - - return (0); + get_info(p); + enroll(p); + list(p); + set_name(p); + del(p); } -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[32768]; - 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); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); + if (flags & MUTATE_SEED) + p->seed = (int)seed; - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_PARAM) { + mutate_blob(&p->id); + mutate_string(p->pin); + mutate_string(p->name); } - 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; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - p.seed = (int)seed; - - mutate_blob(&p.id); - 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); - - mutate_string(p.pin); - mutate_string(p.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) { + 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 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); + } } diff --git a/fuzz/fuzz_credman.c b/fuzz/fuzz_credman.c index 323d0a9..db0dfb8 100644 --- a/fuzz/fuzz_credman.c +++ b/fuzz/fuzz_credman.c @@ -19,25 +19,16 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_META_WIRE_DATA 0x01 -#define TAG_RP_WIRE_DATA 0x02 -#define TAG_RK_WIRE_DATA 0x03 -#define TAG_DEL_WIRE_DATA 0x04 -#define TAG_CRED_ID 0x05 -#define TAG_PIN 0x06 -#define TAG_RP_ID 0x07 -#define TAG_SEED 0x08 - /* 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; + 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; }; /* @@ -88,56 +79,136 @@ static const uint8_t dummy_del_wire_data[] = { WIREDATA_CTAP_CBOR_STATUS, }; -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_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || - unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || - unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || - unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || - unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || - unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 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) != 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; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || - pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || - pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || - pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || - pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || - pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) - return (0); - - return (max - len); + 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)) > 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; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (2 * len_string(max) + 5 * len_blob(max) + len_int()); + struct param dummy; + uint8_t blob[4096]; + 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() +prepare_dev(void) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; + bool x; memset(&io, 0, sizeof(io)); @@ -149,14 +220,19 @@ prepare_dev() 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 (NULL); + return NULL; } - return (dev); + x = fido_dev_is_fido2(dev); + consume(&x, sizeof(x)); + x = fido_dev_supports_cred_prot(dev); + consume(&x, sizeof(x)); + + return dev; } static void -get_metadata(struct param *p) +get_metadata(const struct param *p) { fido_dev_t *dev; fido_credman_metadata_t *metadata; @@ -187,7 +263,7 @@ get_metadata(struct param *p) } static void -get_rp_list(struct param *p) +get_rp_list(const struct param *p) { fido_dev_t *dev; fido_credman_rp_t *rp; @@ -221,12 +297,12 @@ get_rp_list(struct param *p) } static void -get_rk_list(struct param *p) +get_rk_list(const struct param *p) { fido_dev_t *dev; fido_credman_rk_t *rk; const fido_cred_t *cred; - int type; + int val; set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); @@ -247,8 +323,8 @@ get_rk_list(struct param *p) assert(i >= fido_credman_rk_count(rk)); continue; } - type = fido_cred_type(cred); - consume(&type, sizeof(type)); + 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), @@ -257,6 +333,8 @@ get_rk_list(struct param *p) xstrlen(fido_cred_user_name(cred))); consume(fido_cred_display_name(cred), xstrlen(fido_cred_display_name(cred))); + val = fido_cred_prot(cred); + consume(&val, sizeof(val)); } fido_credman_rk_free(&rk); @@ -265,7 +343,7 @@ get_rk_list(struct param *p) } static void -del_rk(struct param *p) +del_rk(const struct param *p) { fido_dev_t *dev; @@ -279,101 +357,35 @@ del_rk(struct param *p) fido_dev_free(&dev); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - - 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); - + prng_init((unsigned int)p->seed); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); - get_metadata(&p); - get_rp_list(&p); - get_rk_list(&p); - del_rk(&p); - - return (0); + get_metadata(p); + get_rp_list(p); + get_rk_list(p); + del_rk(p); } -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[32768]; - 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)); + if (flags & MUTATE_SEED) + p->seed = (int)seed; - 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); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); - - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_PARAM) { + mutate_blob(&p->cred_id); + mutate_string(p->pin); + mutate_string(p->rp_id); } - 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; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - p.seed = (int)seed; - - mutate_blob(&p.cred_id); - mutate_blob(&p.meta_wire_data); - mutate_blob(&p.rp_wire_data); - mutate_blob(&p.rk_wire_data); - mutate_blob(&p.del_wire_data); - - mutate_string(p.pin); - mutate_string(p.rp_id); - - 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) { + 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_mgmt.c b/fuzz/fuzz_mgmt.c index d46daf6..0b6cf19 100644 --- a/fuzz/fuzz_mgmt.c +++ b/fuzz/fuzz_mgmt.c @@ -17,24 +17,15 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_PIN1 0x01 -#define TAG_PIN2 0x02 -#define TAG_RESET_WIRE_DATA 0x03 -#define TAG_INFO_WIRE_DATA 0x04 -#define TAG_SET_PIN_WIRE_DATA 0x05 -#define TAG_CHANGE_PIN_WIRE_DATA 0x06 -#define TAG_RETRY_WIRE_DATA 0x07 -#define TAG_SEED 0x08 - 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; - int seed; + 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; + int seed; }; static const uint8_t dummy_reset_wire_data[] = { @@ -72,56 +63,136 @@ static const uint8_t dummy_retry_wire_data[] = { WIREDATA_CTAP_CBOR_RETRIES, }; -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_string(TAG_PIN1, pp, &len, p->pin1) < 0 || - unpack_string(TAG_PIN2, pp, &len, p->pin2) < 0 || - unpack_blob(TAG_RESET_WIRE_DATA, pp, &len, &p->reset_wire_data) < 0 || - unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || - unpack_blob(TAG_SET_PIN_WIRE_DATA, pp, &len, &p->set_pin_wire_data) < 0 || - unpack_blob(TAG_CHANGE_PIN_WIRE_DATA, pp, &len, &p->change_pin_wire_data) < 0 || - unpack_blob(TAG_RETRY_WIRE_DATA, pp, &len, &p->retry_wire_data) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 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) != 8 || + (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) + 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_string(TAG_PIN1, &ptr, &len, p->pin1) < 0 || - pack_string(TAG_PIN2, &ptr, &len, p->pin2) < 0 || - pack_blob(TAG_RESET_WIRE_DATA, &ptr, &len, &p->reset_wire_data) < 0 || - pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || - pack_blob(TAG_SET_PIN_WIRE_DATA, &ptr, &len, &p->set_pin_wire_data) < 0 || - pack_blob(TAG_CHANGE_PIN_WIRE_DATA, &ptr, &len, &p->change_pin_wire_data) < 0 || - pack_blob(TAG_RETRY_WIRE_DATA, &ptr, &len, &p->retry_wire_data) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) - return (0); - - return (max - len); + 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->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) + 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)) > 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; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (2 * len_string(max) + 5 * len_blob(max) + len_int()); + struct param dummy; + uint8_t blob[4096]; + 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); + + 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); + + 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() +prepare_dev(void) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; memset(&io, 0, sizeof(io)); @@ -133,14 +204,14 @@ prepare_dev() 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 (NULL); + return NULL; } - return (dev); + return dev; } static void -dev_reset(struct param *p) +dev_reset(const struct param *p) { fido_dev_t *dev; @@ -155,16 +226,12 @@ dev_reset(struct param *p) } static void -dev_get_cbor_info(struct param *p) +dev_get_cbor_info(const struct param *p) { fido_dev_t *dev; fido_cbor_info_t *ci; uint64_t n; - uint8_t proto; - uint8_t major; - uint8_t minor; - uint8_t build; - uint8_t flags; + uint8_t proto, major, minor, build, flags; set_wire_data(p->info_wire_data.body, p->info_wire_data.len); @@ -192,6 +259,7 @@ dev_get_cbor_info(struct param *p) 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])); @@ -207,6 +275,12 @@ dev_get_cbor_info(struct param *p) n = fido_cbor_info_maxmsgsiz(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_fwversion(ci); consume(&n, sizeof(n)); @@ -222,7 +296,7 @@ out: } static void -dev_set_pin(struct param *p) +dev_set_pin(const struct param *p) { fido_dev_t *dev; @@ -237,7 +311,7 @@ dev_set_pin(struct param *p) } static void -dev_change_pin(struct param *p) +dev_change_pin(const struct param *p) { fido_dev_t *dev; @@ -252,10 +326,10 @@ dev_change_pin(struct param *p) } static void -dev_get_retry_count(struct param *p) +dev_get_retry_count(const struct param *p) { fido_dev_t *dev; - int n; + int n = 0; set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); @@ -268,103 +342,36 @@ dev_get_retry_count(struct param *p) fido_dev_free(&dev); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - - 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); - + prng_init((unsigned int)p->seed); 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); - - return (0); + dev_reset(p); + dev_get_cbor_info(p); + dev_set_pin(p); + dev_change_pin(p); + dev_get_retry_count(p); } -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)); - - 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); - - 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); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); + if (flags & MUTATE_SEED) + p->seed = (int)seed; - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_PARAM) { + mutate_string(p->pin1); + mutate_string(p->pin2); } - memcpy(ptr, blob, blob_len); - - return (blob_len); -} - -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) -{ - 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)); - - p.seed = (int)seed; - - mutate_string(p.pin1); - mutate_string(p.pin2); - - 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); - - 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) { + 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/libfuzzer.c b/fuzz/libfuzzer.c new file mode 100644 index 0000000..ac9c798 --- /dev/null +++ b/fuzz/libfuzzer.c @@ -0,0 +1,174 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" + +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 = 4096; + 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 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 (++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 (size > 4096 || (p = unpack(data, size)) == NULL) + test_fail++; + else { + test(p); + 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[4096]; + 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 index fe09438..98815e8 100644 --- a/fuzz/mutator_aux.c +++ b/fuzz/mutator_aux.c @@ -5,26 +5,28 @@ */ #include +#include #include #include #include #include #include +#include "fido.h" #include "mutator_aux.h" size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); -static uint8_t *wire_data_ptr = NULL; -static size_t wire_data_len = 0; +static const uint8_t *wire_data_ptr = NULL; +static size_t wire_data_len = 0; size_t xstrlen(const char *s) { if (s == NULL) - return (0); + return 0; - return (strlen(s)); + return strlen(s); } void @@ -33,6 +35,10 @@ 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++; } @@ -44,217 +50,87 @@ consume_str(const char *str) } int -unpack_int(uint8_t t, uint8_t **ptr, size_t *len, int *v) NO_MSAN -{ - size_t l; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); - - if (l != sizeof(*v) || *len < l) - return (-1); - - memcpy(v, *ptr, sizeof(*v)); - *ptr += sizeof(*v); - *len -= sizeof(*v); - - return (0); -} - -int -unpack_string(uint8_t t, uint8_t **ptr, size_t *len, char *v) NO_MSAN +unpack_int(cbor_item_t *item, int *v) { - size_t l; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); + if (cbor_is_int(item) == false || + cbor_int_get_width(item) != CBOR_INT_64) + return -1; - if (*len < l || l >= MAXSTR) - return (-1); - - memcpy(v, *ptr, l); - v[l] = '\0'; - - *ptr += l; - *len -= l; - - return (0); -} - -int -unpack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t *v) NO_MSAN -{ - size_t l; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); - - if (l != sizeof(*v) || *len < l) - return (-1); - - memcpy(v, *ptr, sizeof(*v)); - *ptr += sizeof(*v); - *len -= sizeof(*v); - - return (0); -} - -int -unpack_blob(uint8_t t, uint8_t **ptr, size_t *len, struct blob *v) NO_MSAN -{ - size_t l; - - v->len = 0; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); - - if (*len < l || l > sizeof(v->body)) - return (-1); - - memcpy(v->body, *ptr, l); - *ptr += l; - *len -= l; - - v->len = l; + if (cbor_isa_uint(item)) + *v = (int)cbor_get_uint64(item); + else + *v = (int)(-cbor_get_uint64(item) - 1); - return (0); + return 0; } int -pack_int(uint8_t t, uint8_t **ptr, size_t *len, int v) NO_MSAN +unpack_string(cbor_item_t *item, char *v) { - const size_t l = sizeof(v); + size_t len; - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); + if (cbor_isa_bytestring(item) == false || + (len = cbor_bytestring_length(item)) >= MAXSTR) + return -1; - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); + memcpy(v, cbor_bytestring_handle(item), len); + v[len] = '\0'; - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; - - return (0); + return 0; } int -pack_string(uint8_t t, uint8_t **ptr, size_t *len, const char *v) NO_MSAN +unpack_byte(cbor_item_t *item, uint8_t *v) { - const size_t l = strlen(v); - - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); - - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v, l); + if (cbor_isa_uint(item) == false || + cbor_int_get_width(item) != CBOR_INT_8) + return -1; - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; + *v = cbor_get_uint8(item); - return (0); + return 0; } int -pack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t v) NO_MSAN +unpack_blob(cbor_item_t *item, struct blob *v) { - const size_t l = sizeof(v); + if (cbor_isa_bytestring(item) == false || + (v->len = cbor_bytestring_length(item)) > sizeof(v->body)) + return -1; - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); + memcpy(v->body, cbor_bytestring_handle(item), v->len); - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); - - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; - - return (0); + return 0; } -int -pack_blob(uint8_t t, uint8_t **ptr, size_t *len, const struct blob *v) NO_MSAN +cbor_item_t * +pack_int(int v) NO_MSAN { - const size_t l = v->len; - - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); - - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v->body, l); - - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; - - return (0); + if (v < 0) + return cbor_build_negint64((uint64_t)(-(int64_t)v - 1)); + else + return cbor_build_uint64((uint64_t)v); } -size_t -len_int(void) +cbor_item_t * +pack_string(const char *v) NO_MSAN { - return (sizeof(uint8_t) + sizeof(size_t) + sizeof(int)); -} + if (strlen(v) >= MAXSTR) + return NULL; -size_t -len_string(int max) -{ - return ((sizeof(uint8_t) + sizeof(size_t)) + (max ? MAXSTR - 1 : 0)); + return cbor_build_bytestring((const unsigned char *)v, strlen(v)); } -size_t -len_byte(void) +cbor_item_t * +pack_byte(uint8_t v) NO_MSAN { - return (sizeof(uint8_t) + sizeof(size_t) + sizeof(uint8_t)); + return cbor_build_uint8(v); } -size_t -len_blob(int max) +cbor_item_t * +pack_blob(const struct blob *v) NO_MSAN { - return (sizeof(uint8_t) + sizeof(size_t) + (max ? MAXBLOB : 0)); + return cbor_build_bytestring(v->body, v->len); } void @@ -284,13 +160,13 @@ mutate_string(char *s) n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); s[n] = '\0'; } - + void * dev_open(const char *path) { (void)path; - return ((void *)0xdeadbeef); + return (void *)0xdeadbeef; } void @@ -307,7 +183,7 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms) (void)ms; assert(handle == (void *)0xdeadbeef); - assert(len == 64); + assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN); if (wire_data_len < len) n = wire_data_len; @@ -319,25 +195,26 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms) wire_data_ptr += n; wire_data_len -= n; - return ((int)n); + return (int)n; } int dev_write(void *handle, const unsigned char *ptr, size_t len) { assert(handle == (void *)0xdeadbeef); - assert(len == 64 + 1); + assert(len >= CTAP_MIN_REPORT_LEN + 1 && + len <= CTAP_MAX_REPORT_LEN + 1); consume(ptr, len); if (uniform_random(400) < 1) - return (-1); + return -1; - return ((int)len); + return (int)len; } void -set_wire_data(uint8_t *ptr, size_t len) +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 index d14e177..4a7e647 100644 --- a/fuzz/mutator_aux.h +++ b/fuzz/mutator_aux.h @@ -9,9 +9,10 @@ #include #include +#include /* - * As of LLVM 7.0.1, MSAN support in libFuzzer was still experimental. + * 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 @@ -22,6 +23,7 @@ #if defined(__has_feature) # if __has_feature(memory_sanitizer) +# include # define NO_MSAN __attribute__((no_sanitize("memory"))) # define WITH_MSAN 1 # endif @@ -31,44 +33,49 @@ # 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 3072 -#define GETLEN_MIN 0 -#define GETLEN_MAX 1 - struct blob { - uint8_t body[MAXBLOB]; - size_t len; + 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 *); + size_t xstrlen(const char *); void consume(const void *, size_t); void consume_str(const char *); -int unpack_blob(uint8_t, uint8_t **, size_t *, struct blob *); -int unpack_byte(uint8_t, uint8_t **, size_t *, uint8_t *); -int unpack_int(uint8_t, uint8_t **, size_t *, int *); -int unpack_string(uint8_t, uint8_t **, size_t *, char *); - -int pack_blob(uint8_t, uint8_t **, size_t *, const struct blob *); -int pack_byte(uint8_t, uint8_t **, size_t *, uint8_t); -int pack_int(uint8_t, uint8_t **, size_t *, int); -int pack_string(uint8_t, uint8_t **, size_t *, 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 *); -size_t len_int(void); -size_t len_string(int); -size_t len_byte(void); -size_t len_blob(int); +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 *); -void * dev_open(const char *); +void *dev_open(const char *); void dev_close(void *); -void set_wire_data(uint8_t *, size_t); +void set_wire_data(const uint8_t *, size_t); int dev_read(void *, unsigned char *, size_t, int); int dev_write(void *, const unsigned char *, size_t); diff --git a/fuzz/prng.c b/fuzz/prng.c old mode 100755 new mode 100644 index fa6d4e4..61114ac --- a/fuzz/prng.c +++ b/fuzz/prng.c @@ -63,7 +63,8 @@ void init_genrand(unsigned long s) mt[0]= s & 0xffffffffUL; for (mti=1; mti> 30)) + mti); + (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 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[]. */ diff --git a/fuzz/report.tgz b/fuzz/report.tgz index 8a002f0..6f02fc5 100644 Binary files a/fuzz/report.tgz and b/fuzz/report.tgz differ diff --git a/fuzz/summary.txt b/fuzz/summary.txt index da9d165..3a1ac21 100644 --- a/fuzz/summary.txt +++ b/fuzz/summary.txt @@ -1,6 +1,6 @@ Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -fuzz/prng.c 31 0 100.00% 2 0 100.00% 48 0 100.00% +fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00% fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00% openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% @@ -8,34 +8,35 @@ openbsd-compat/recallocarray.c 41 7 82.93% openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00% openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% -src/assert.c 566 43 92.40% 53 1 98.11% 900 87 90.33% +src/assert.c 566 24 95.76% 53 1 98.11% 900 50 94.44% src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00% src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67% -src/blob.c 39 1 97.44% 7 0 100.00% 73 4 94.52% +src/blob.c 39 0 100.00% 7 0 100.00% 73 0 100.00% src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% -src/cbor.c 884 70 92.08% 52 2 96.15% 1371 106 92.27% -src/cred.c 534 51 90.45% 55 1 98.18% 830 78 90.60% -src/credman.c 376 18 95.21% 38 0 100.00% 589 15 97.45% -src/dev.c 201 85 57.71% 26 8 69.23% 294 128 56.46% +src/cbor.c 883 6 99.32% 52 0 100.00% 1364 17 98.75% +src/cred.c 536 23 95.71% 57 1 98.25% 836 29 96.53% +src/credman.c 385 18 95.32% 38 0 100.00% 595 16 97.31% +src/dev.c 334 90 73.05% 33 8 75.76% 466 140 69.96% src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00% -src/err.c 108 108 0.00% 1 1 0.00% 112 112 0.00% -src/es256.c 278 0 100.00% 16 0 100.00% 377 0 100.00% +src/err.c 112 8 92.86% 1 0 100.00% 116 8 93.10% +src/es256.c 280 0 100.00% 16 0 100.00% 398 0 100.00% src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% -src/hid_linux.c 166 166 0.00% 12 12 0.00% 292 292 0.00% -src/info.c 146 0 100.00% 31 0 100.00% 304 0 100.00% -src/io.c 123 5 95.93% 10 0 100.00% 218 11 94.95% +src/hid_linux.c 235 235 0.00% 19 19 0.00% 416 416 0.00% +src/info.c 152 0 100.00% 34 0 100.00% 319 0 100.00% +src/io.c 156 9 94.23% 10 0 100.00% 236 11 95.34% src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00% src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00% src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00% -src/rs256.c 102 29 71.57% 8 3 62.50% 140 44 68.57% -src/u2f.c 443 28 93.68% 13 0 100.00% 699 52 92.56% +src/rs256.c 102 6 94.12% 8 0 100.00% 140 13 90.71% +src/u2f.c 491 9 98.17% 15 0 100.00% 774 18 97.67% Files which contain no functions: +openbsd-compat/time.h 0 0 - 0 0 - 0 0 - src/extern.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 5054 653 87.08% 435 39 91.03% 7914 1002 87.34% +TOTAL 5359 477 91.10% 456 40 91.23% 8349 791 90.53% -- cgit v1.2.3