summaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'fuzz')
-rw-r--r--fuzz/CMakeLists.txt1
-rw-r--r--fuzz/Dockerfile9
-rw-r--r--fuzz/Makefile20
-rw-r--r--fuzz/README130
-rwxr-xr-xfuzz/build-coverage33
-rw-r--r--fuzz/dummy.h4
-rw-r--r--fuzz/export.gnu10
-rw-r--r--fuzz/functions.txt197
-rw-r--r--fuzz/fuzz_assert.c455
-rw-r--r--fuzz/fuzz_bio.c335
-rw-r--r--fuzz/fuzz_cred.c458
-rw-r--r--fuzz/fuzz_credman.c314
-rw-r--r--fuzz/fuzz_mgmt.c321
-rw-r--r--fuzz/libfuzzer.c174
-rw-r--r--fuzz/mutator_aux.c253
-rw-r--r--fuzz/mutator_aux.h49
-rw-r--r--[-rwxr-xr-x]fuzz/prng.c3
-rw-r--r--fuzz/report.tgzbin211709 -> 222723 bytes
-rw-r--r--fuzz/summary.txt31
19 files changed, 1437 insertions, 1360 deletions
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
8) 8)
9 9
10list(APPEND COMMON_SOURCES 10list(APPEND COMMON_SOURCES
11 libfuzzer.c
11 mutator_aux.c 12 mutator_aux.c
12) 13)
13 14
diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile
index 68afd99..f9152f8 100644
--- a/fuzz/Dockerfile
+++ b/fuzz/Dockerfile
@@ -2,9 +2,10 @@
2# Use of this source code is governed by a BSD-style 2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file. 3# license that can be found in the LICENSE file.
4 4
5FROM ubuntu:bionic 5FROM ubuntu:focal
6ENV DEBIAN_FRONTEND=noninteractive
6RUN apt-get update 7RUN apt-get update
7RUN apt-get install -y clang-9 cmake git libssl-dev libudev-dev make pkg-config 8RUN apt-get install -y clang-10 cmake git libssl-dev libudev-dev make pkg-config
8RUN git clone --branch v0.5.0 https://github.com/PJK/libcbor 9RUN git clone --branch v0.7.0 https://github.com/PJK/libcbor
9RUN git clone https://github.com/yubico/libfido2 10RUN git clone https://github.com/yubico/libfido2
10RUN CC=clang-9 /libfido2/fuzz/build-coverage /libcbor /libfido2 11RUN 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 @@
2# Use of this source code is governed by a BSD-style 2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file. 3# license that can be found in the LICENSE file.
4 4
5IMAGE := libfido2-coverage:1.3.0 5IMAGE := libfido2-coverage:1.5.0
6RUNNER := libfido2-runner 6RUNNER := libfido2-runner
7PROFDATA := llvm-profdata-9 7PROFDATA := llvm-profdata-10
8COV := llvm-cov-9 8COV := llvm-cov-10
9TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt 9TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt
10CORPORA := $(foreach f,${TARGETS},${f}/corpus) 10CORPORA := $(foreach f,${TARGETS},${f}/corpus)
11MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus) 11MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus)
@@ -26,16 +26,16 @@ sync: run
26 docker exec ${RUNNER} make -C libfido2/build 26 docker exec ${RUNNER} make -C libfido2/build
27 27
28corpus: sync 28corpus: sync
29 docker exec ${RUNNER} /bin/bash -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}' 29 docker exec ${RUNNER} /bin/sh -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}'
30 docker exec ${RUNNER} tar Czxf /libfido2/fuzz /libfido2/fuzz/corpus.tgz 30 docker exec ${RUNNER} tar Czxf /libfido2/fuzz /libfido2/fuzz/corpus.tgz
31 31
32${TARGETS}: corpus sync 32${TARGETS}: corpus sync
33 docker exec -e LLVM_PROFILE_FILE=/profraw/$@ ${RUNNER} \ 33 docker exec -e LLVM_PROFILE_FILE=/profraw/$@ ${RUNNER} \
34 /bin/bash -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ 34 /bin/sh -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \
35 -runs=1 /libfido2/fuzz/$@' 35 -runs=1 /libfido2/fuzz/$@'
36 36
37${MINIFY}: /minify/%/corpus: % 37${MINIFY}: /minify/%/corpus: %
38 docker exec ${RUNNER} /bin/bash -c 'rm -rf $@ && mkdir -p $@ && \ 38 docker exec ${RUNNER} /bin/sh -c 'rm -rf $@ && mkdir -p $@ && \
39 /libfido2/build/fuzz/$< -use_value_profile=1 -merge=1 $@ \ 39 /libfido2/build/fuzz/$< -use_value_profile=1 -merge=1 $@ \
40 /libfido2/fuzz/$</corpus' 40 /libfido2/fuzz/$</corpus'
41 41
@@ -43,11 +43,11 @@ corpus.tgz-: ${MINIFY}
43 docker exec -i ${RUNNER} tar Czcf /minify - ${TARGETS} > $@ 43 docker exec -i ${RUNNER} tar Czcf /minify - ${TARGETS} > $@
44 44
45profdata: run 45profdata: run
46 docker exec ${RUNNER} /bin/bash -c 'rm -f /$@ && ${PROFDATA} \ 46 docker exec ${RUNNER} /bin/sh -c 'rm -f /$@ && ${PROFDATA} \
47 merge -sparse profraw/* -o $@' 47 merge -sparse profraw/* -o $@'
48 48
49report.tgz: profdata 49report.tgz: profdata
50 docker exec ${RUNNER} /bin/bash -c 'rm -rf /report && mkdir /report && \ 50 docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \
51 ${COV} show -format=html -tab-size=8 -instr-profile=/$< \ 51 ${COV} show -format=html -tab-size=8 -instr-profile=/$< \
52 -output-dir=/report /libfido2/build/src/libfido2.so' 52 -output-dir=/report /libfido2/build/src/libfido2.so'
53 docker exec -i ${RUNNER} tar Czcf / - report > $@ 53 docker exec -i ${RUNNER} tar Czcf / - report > $@
@@ -57,12 +57,12 @@ summary.txt: profdata
57 /libfido2/build/src/libfido2.so -instr-profile=/$< > $@ 57 /libfido2/build/src/libfido2.so -instr-profile=/$< > $@
58 58
59functions.txt: profdata 59functions.txt: profdata
60 docker exec ${RUNNER} /bin/bash -c '${COV} report -use-color=false \ 60 docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \
61 -show-functions -instr-profile=/$< \ 61 -show-functions -instr-profile=/$< \
62 /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@ 62 /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@
63 63
64clean: run 64clean: run
65 docker exec ${RUNNER} /bin/bash -c 'rm -rf /profraw /profdata && \ 65 docker exec ${RUNNER} /bin/sh -c 'rm -rf /profraw /profdata && \
66 make -C /libfido2/build clean' 66 make -C /libfido2/build clean'
67 -docker stop ${RUNNER} 67 -docker stop ${RUNNER}
68 rm -rf ${TARGETS} 68 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.
3 3
4AFL is more convenient when fuzzing the path from the authenticator to 4AFL is more convenient when fuzzing the path from the authenticator to
5libfido2 in an existing application. To do so, use preload-snoop.c with a real 5libfido2 in an existing application. To do so, use preload-snoop.c with a real
6authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1 6authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1, and
7-DAFL=1, and use preload-fuzz.c to read device data from stdin. Examples of 7use preload-fuzz.c to read device data from stdin.
8this approach can be found in the harnesses under fuzz/harnesses/ that fuzz
9the standalone examples and tools bundled with libfido2.
10 8
11libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, 9libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c,
12fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses, 10fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses,
@@ -15,129 +13,7 @@ use -DFUZZ=1 -DLIBFUZZER=1.
15To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of 13To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of
16libcbor and OpenSSL built with the respective sanitiser. In order to keep 14libcbor and OpenSSL built with the respective sanitiser. In order to keep
17memory utilisation at a manageable level, you can either enforce limits at 15memory utilisation at a manageable level, you can either enforce limits at
18the OS level (e.g. cgroups on Linux) or, alternatively, patch libcbor with 16the OS level (e.g. cgroups on Linux), or patch libcbor with the diff below.
19the diff at the bottom of this file.
20
211. Using ASAN + UBSAN
22
23- Make sure you have libcbor built with -fsanitize=address;
24- Make sure you have OpenSSL built with -fsanitize=address;
25- Rebuild libfido2 with -DASAN=1 -DUBSAN=1.
26
271.1 Decide where your workspace will live
28
29$ export FAKEROOT=/home/pedro/fakeroot
30$ mkdir -p ${FAKEROOT}/src
31
321.2 Building libcbor with ASAN
33
34$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor
35$ cd ${FAKEROOT}/src/libcbor
36
37Assuming libfido2 is under ${FAKEROOT}/src/libfido2:
38
39$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README
40$ mkdir build
41$ cd build
42$ cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \
43 -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \
44 -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \
45 -DCMAKE_INSTALL_LIBDIR=lib ..
46$ make
47$ make install
48
491.3 Building OpenSSL with ASAN
50
51$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl
52$ cd ${FAKEROOT}/src/openssl
53$ ./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \
54 --openssldir=${FAKEROOT}/openssl
55$ make clean
56$ make
57$ make install_sw
58
591.4 Building libfido2 with libFuzzer and ASAN + UBSAN
60
61$ cd ${FAKEROOT}/src/libfido2
62$ mkdir build
63$ cd build
64$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \
65 -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \
66 -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \
67 -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \
68 -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \
69 -DCMAKE_BUILD_TYPE=Debug ..
70$ make
71
722. Using MSAN + UBSAN
73
74- Make sure you have libcbor built with -fsanitize=memory;
75- Make sure you have OpenSSL built with -fsanitize=memory;
76- Rebuild libfido2 with -DMSAN=1 -DUBSAN=1.
77
782.1 Decide where your workspace will live
79
80$ export FAKEROOT=/home/pedro/fakeroot
81$ mkdir -p ${FAKEROOT}/src
82
832.2 Building libcbor with MSAN
84
85$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor
86$ cd ${FAKEROOT}/src/libcbor
87
88Assuming libfido2 is under ${FAKEROOT}/src/libfido2:
89
90$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README
91$ mkdir build
92$ cd build
93$ cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \
94 -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \
95 -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \
96 -DCMAKE_INSTALL_LIBDIR=lib ..
97$ make
98$ make install
99
1002.2 Building OpenSSL with MSAN
101
102$ mkdir -p ${FAKEROOT}/src
103$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl
104$ cd ${FAKEROOT}/src/openssl
105$ ./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \
106 --openssldir=${FAKEROOT}/openssl
107$ make clean
108$ make
109$ make install_sw
110
1112.3 Building libfido2 with libFuzzer and MSAN + UBSAN
112
113$ cd ${FAKEROOT}/src/libfido2
114$ mkdir build
115$ cd build
116$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \
117 -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \
118 -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \
119 -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \
120 -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \
121 -DCMAKE_BUILD_TYPE=Debug ..
122$ make
123
1243. Running the libFuzzer harnesses
125
126When running under ASAN, you may want to set ASAN_OPTIONS to
127'allocator_may_return_null=1:detect_stack_use_after_return=1'.
128
129The recommended way to run the harnesses is:
130
131$ fuzz_{assert,cred,credman,mgmt} -use_value_profile=1 -reload=30 \
132 -print_pcs=1 -print_funcs=30 -timeout=10 CORPUS_DIR
133
134You may want to use -jobs or -workers depending on the number of logical
135cores available for fuzzing.
136
1374. Auxiliary scripts
138
139A set of harnesses and auxiliary scripts can be found under harnesses/. To
140compile coverage reports, adjust the harnesses to your setup and run 'report'.
141 17
142diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c 18diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c
143index aa049a2..e294b38 100644 19index 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 @@
1#!/bin/bash -eux 1#!/bin/sh -eux
2# 2
3# Copyright (c) 2019 Yubico AB. All rights reserved. 3# Copyright (c) 2019 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style 4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file. 5# license that can be found in the LICENSE file.
6 6
7LIBCBOR=$1 7LIBCBOR="$1"
8LIBFIDO2=$2 8LIBFIDO2="$2"
9 9
10CC=${CC:-clang} 10CC="${CC:-clang}"
11PKG_CONFIG_PATH=${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig} 11CXX="${CXX:-clang++}"
12PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig}"
12export CC PKG_CONFIG_PATH 13export CC PKG_CONFIG_PATH
13 14
14# Clean up. 15# Clean up.
15rm -rf ${LIBCBOR}/build ${LIBCBOR}/install ${LIBFIDO2}/build 16rm -rf "${LIBCBOR}/build" "${LIBCBOR}/install" "${LIBFIDO2}/build"
16 17
17# Patch, build, and install libcbor. 18# Patch, build, and install libcbor.
18(cd ${LIBCBOR} && patch -N -l -s -p0 < ${LIBFIDO2}/fuzz/README) || true 19(cd "${LIBCBOR}" && patch -N -l -s -p0 < "${LIBFIDO2}/fuzz/README") || true
19mkdir ${LIBCBOR}/build ${LIBCBOR}/install 20mkdir "${LIBCBOR}/build" "${LIBCBOR}/install"
20(cd ${LIBCBOR}/build && cmake -DCMAKE_INSTALL_PREFIX=${LIBCBOR}/install ..) 21(cd "${LIBCBOR}/build" && cmake -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..)
21make -C ${LIBCBOR}/build all install 22make -C "${LIBCBOR}/build" all install
22 23
23# Build libfido2. 24# Build libfido2.
24mkdir -p ${LIBFIDO2}/build 25mkdir -p "${LIBFIDO2}/build"
25(cd ${LIBFIDO2}/build && cmake -DFUZZ=1 -DLIBFUZZER=1 -DCOVERAGE=1 \ 26export CFLAGS="-fprofile-instr-generate -fcoverage-mapping"
26 -DCMAKE_BUILD_TYPE=Debug ..) 27export LDFLAGS="${CFLAGS}"
27make -C ${LIBFIDO2}/build 28(cd "${LIBFIDO2}/build" && cmake -DFUZZ=1 -DLIBFUZZER=1 \
29 -DCMAKE_BUILD_TYPE=Debug ..)
30make -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 @@
10#include <stdint.h> 10#include <stdint.h>
11 11
12const char dummy_name[] = "finger1"; 12const char dummy_name[] = "finger1";
13const char dummy_pin1[] = "skepp cg0u3;Y..";
14const char dummy_pin2[] = "bastilha 6rJrfQZI.";
13const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; 15const char dummy_pin[] = "9}4gT:8d=A37Dh}U";
14const char dummy_rp_id[] = "localhost"; 16const char dummy_rp_id[] = "localhost";
15const char dummy_rp_name[] = "sweet home localhost"; 17const char dummy_rp_name[] = "sweet home localhost";
@@ -17,8 +19,6 @@ const char dummy_user_icon[] = "an icon";
17const char dummy_user_name[] = "john smith"; 19const char dummy_user_name[] = "john smith";
18const char dummy_user_nick[] = "jsmith"; 20const char dummy_user_nick[] = "jsmith";
19const uint8_t dummy_id[] = { 0x5e, 0xd2 }; 21const uint8_t dummy_id[] = { 0x5e, 0xd2 };
20const char dummy_pin1[] = "skepp cg0u3;Y..";
21const char dummy_pin2[] = "bastilha 6rJrfQZI.";
22 22
23const uint8_t dummy_user_id[] = { 23const uint8_t dummy_user_id[] = {
24 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, 24 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 @@
76 fido_cbor_info_extensions_ptr; 76 fido_cbor_info_extensions_ptr;
77 fido_cbor_info_free; 77 fido_cbor_info_free;
78 fido_cbor_info_maxmsgsiz; 78 fido_cbor_info_maxmsgsiz;
79 fido_cbor_info_maxcredcntlst;
80 fido_cbor_info_maxcredidlen;
79 fido_cbor_info_fwversion; 81 fido_cbor_info_fwversion;
80 fido_cbor_info_new; 82 fido_cbor_info_new;
81 fido_cbor_info_options_len; 83 fido_cbor_info_options_len;
@@ -96,6 +98,8 @@
96 fido_cred_free; 98 fido_cred_free;
97 fido_cred_id_len; 99 fido_cred_id_len;
98 fido_cred_id_ptr; 100 fido_cred_id_ptr;
101 fido_cred_aaguid_len;
102 fido_cred_aaguid_ptr;
99 fido_credman_del_dev_rk; 103 fido_credman_del_dev_rk;
100 fido_credman_get_dev_metadata; 104 fido_credman_get_dev_metadata;
101 fido_credman_get_dev_rk; 105 fido_credman_get_dev_rk;
@@ -155,6 +159,9 @@
155 fido_dev_get_assert; 159 fido_dev_get_assert;
156 fido_dev_get_cbor_info; 160 fido_dev_get_cbor_info;
157 fido_dev_get_retry_count; 161 fido_dev_get_retry_count;
162 fido_dev_get_touch_begin;
163 fido_dev_get_touch_status;
164 fido_dev_has_pin;
158 fido_dev_info_free; 165 fido_dev_info_free;
159 fido_dev_info_manifest; 166 fido_dev_info_manifest;
160 fido_dev_info_manufacturer_string; 167 fido_dev_info_manufacturer_string;
@@ -174,6 +181,9 @@
174 fido_dev_reset; 181 fido_dev_reset;
175 fido_dev_set_io_functions; 182 fido_dev_set_io_functions;
176 fido_dev_set_pin; 183 fido_dev_set_pin;
184 fido_dev_set_transport_functions;
185 fido_dev_supports_cred_prot;
186 fido_dev_supports_pin;
177 fido_init; 187 fido_init;
178 fido_set_log_handler; 188 fido_set_log_handler;
179 fido_strerr; 189 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%
9File '/libfido2/src/assert.c': 9File '/libfido2/src/assert.c':
10Name Regions Miss Cover Lines Miss Cover 10Name Regions Miss Cover Lines Miss Cover
11--------------------------------------------------------------------------------------- 11---------------------------------------------------------------------------------------
12fido_dev_get_assert 35 3 91.43% 38 4 89.47% 12fido_dev_get_assert 35 0 100.00% 38 0 100.00%
13fido_check_flags 13 0 100.00% 18 0 100.00% 13fido_check_flags 13 0 100.00% 18 0 100.00%
14fido_get_signed_hash 32 0 100.00% 46 0 100.00% 14fido_get_signed_hash 32 0 100.00% 46 0 100.00%
15fido_verify_sig_es256 17 2 88.24% 31 7 77.42% 15fido_verify_sig_es256 17 2 88.24% 31 7 77.42%
16fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% 16fido_verify_sig_rs256 17 2 88.24% 31 7 77.42%
17fido_verify_sig_eddsa 23 4 82.61% 43 13 69.77% 17fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72%
18fido_assert_verify 48 4 91.67% 79 4 94.94% 18fido_assert_verify 48 4 91.67% 79 5 93.67%
19fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% 19fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00%
20fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% 20fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00%
21fido_assert_set_rp 12 1 91.67% 14 3 78.57% 21fido_assert_set_rp 12 0 100.00% 14 0 100.00%
22fido_assert_allow_cred 13 2 84.62% 29 3 89.66% 22fido_assert_allow_cred 13 2 84.62% 29 3 89.66%
23fido_assert_set_extensions 9 0 100.00% 8 0 100.00% 23fido_assert_set_extensions 9 0 100.00% 8 0 100.00%
24fido_assert_set_options 6 6 0.00% 6 6 0.00% 24fido_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
28fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% 28fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00%
29fido_assert_new 1 0 100.00% 3 0 100.00% 29fido_assert_new 1 0 100.00% 3 0 100.00%
30fido_assert_reset_tx 1 0 100.00% 15 0 100.00% 30fido_assert_reset_tx 1 0 100.00% 15 0 100.00%
31fido_assert_reset_rx 6 1 83.33% 24 3 87.50% 31fido_assert_reset_rx 6 0 100.00% 24 0 100.00%
32fido_assert_free 6 0 100.00% 13 0 100.00% 32fido_assert_free 6 0 100.00% 13 0 100.00%
33fido_assert_count 1 0 100.00% 3 0 100.00% 33fido_assert_count 1 0 100.00% 3 0 100.00%
34fido_assert_rp_id 1 0 100.00% 3 0 100.00% 34fido_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
48fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% 48fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00%
49fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% 49fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00%
50fido_assert_set_authdata 24 0 100.00% 35 0 100.00% 50fido_assert_set_authdata 24 0 100.00% 35 0 100.00%
51fido_assert_set_authdata_raw 24 4 83.33% 34 7 79.41% 51fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00%
52fido_assert_set_sig 14 0 100.00% 17 0 100.00% 52fido_assert_set_sig 14 0 100.00% 17 0 100.00%
53fido_assert_set_count 10 0 100.00% 21 0 100.00% 53fido_assert_set_count 10 0 100.00% 21 0 100.00%
54assert.c:fido_dev_get_assert_wait 21 1 95.24% 16 2 87.50% 54assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00%
55assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% 55assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90%
56assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00% 56assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00%
57assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% 57assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00%
58assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% 58assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00%
59assert.c:fido_get_next_assert_tx 8 2 75.00% 10 3 70.00% 59assert.c:fido_get_next_assert_tx 8 0 100.00% 10 0 100.00%
60assert.c:fido_get_next_assert_rx 15 4 73.33% 26 7 73.08% 60assert.c:fido_get_next_assert_rx 15 2 86.67% 26 4 84.62%
61assert.c:decrypt_hmac_secrets 9 3 66.67% 15 7 53.33% 61assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00%
62assert.c:check_extensions 4 0 100.00% 9 0 100.00% 62assert.c:check_extensions 4 0 100.00% 9 0 100.00%
63assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% 63assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00%
64assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% 64assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00%
65--------------------------------------------------------------------------------------- 65---------------------------------------------------------------------------------------
66TOTAL 566 43 92.40% 900 87 90.33% 66TOTAL 566 24 95.76% 900 50 94.44%
67 67
68File '/libfido2/src/authkey.c': 68File '/libfido2/src/authkey.c':
69Name Regions Miss Cover Lines Miss Cover 69Name Regions Miss Cover Lines Miss Cover
@@ -135,14 +135,14 @@ File '/libfido2/src/blob.c':
135Name Regions Miss Cover Lines Miss Cover 135Name Regions Miss Cover Lines Miss Cover
136--------------------------------------------------------------------------------------- 136---------------------------------------------------------------------------------------
137fido_blob_new 1 0 100.00% 3 0 100.00% 137fido_blob_new 1 0 100.00% 3 0 100.00%
138fido_blob_set 11 1 90.91% 25 4 84.00% 138fido_blob_set 11 0 100.00% 25 0 100.00%
139fido_blob_free 8 0 100.00% 16 0 100.00% 139fido_blob_free 8 0 100.00% 16 0 100.00%
140fido_free_blob_array 9 0 100.00% 17 0 100.00% 140fido_free_blob_array 9 0 100.00% 17 0 100.00%
141fido_blob_encode 6 0 100.00% 6 0 100.00% 141fido_blob_encode 6 0 100.00% 6 0 100.00%
142fido_blob_decode 1 0 100.00% 3 0 100.00% 142fido_blob_decode 1 0 100.00% 3 0 100.00%
143fido_blob_is_empty 3 0 100.00% 3 0 100.00% 143fido_blob_is_empty 3 0 100.00% 3 0 100.00%
144--------------------------------------------------------------------------------------- 144---------------------------------------------------------------------------------------
145TOTAL 39 1 97.44% 73 4 94.52% 145TOTAL 39 0 100.00% 73 0 100.00%
146 146
147File '/libfido2/src/buf.c': 147File '/libfido2/src/buf.c':
148Name Regions Miss Cover Lines Miss Cover 148Name Regions Miss Cover Lines Miss Cover
@@ -155,7 +155,7 @@ TOTAL 8 1 87.50% 20 1
155File '/libfido2/src/cbor.c': 155File '/libfido2/src/cbor.c':
156Name Regions Miss Cover Lines Miss Cover 156Name Regions Miss Cover Lines Miss Cover
157--------------------------------------------------------------------------------------- 157---------------------------------------------------------------------------------------
158cbor_map_iter 20 0 100.00% 30 0 100.00% 158cbor_map_iter 20 1 95.00% 30 4 86.67%
159cbor_array_iter 12 0 100.00% 20 0 100.00% 159cbor_array_iter 12 0 100.00% 20 0 100.00%
160cbor_parse_reply 27 0 100.00% 43 0 100.00% 160cbor_parse_reply 27 0 100.00% 43 0 100.00%
161cbor_vector_free 6 0 100.00% 5 0 100.00% 161cbor_vector_free 6 0 100.00% 5 0 100.00%
@@ -168,23 +168,23 @@ cbor_flatten_vector 14 1 92.86% 21 1
168cbor_build_frame 15 0 100.00% 32 0 100.00% 168cbor_build_frame 15 0 100.00% 32 0 100.00%
169cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% 169cbor_encode_rp_entity 13 0 100.00% 14 0 100.00%
170cbor_encode_user_entity 21 0 100.00% 18 0 100.00% 170cbor_encode_user_entity 21 0 100.00% 18 0 100.00%
171cbor_encode_pubkey_param 36 1 97.22% 48 0 100.00% 171cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00%
172cbor_encode_pubkey 10 0 100.00% 13 0 100.00% 172cbor_encode_pubkey 10 0 100.00% 13 0 100.00%
173cbor_encode_pubkey_list 18 1 94.44% 23 0 100.00% 173cbor_encode_pubkey_list 18 0 100.00% 23 0 100.00%
174cbor_encode_extensions 24 2 91.67% 26 3 88.46% 174cbor_encode_extensions 28 0 100.00% 28 0 100.00%
175cbor_encode_options 13 0 100.00% 14 0 100.00% 175cbor_encode_options 13 0 100.00% 14 0 100.00%
176cbor_encode_assert_options 13 0 100.00% 14 0 100.00% 176cbor_encode_assert_options 13 0 100.00% 14 0 100.00%
177cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% 177cbor_encode_pin_auth 8 0 100.00% 12 0 100.00%
178cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% 178cbor_encode_pin_opt 1 0 100.00% 3 0 100.00%
179cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% 179cbor_encode_pin_enc 4 0 100.00% 12 0 100.00%
180cbor_encode_change_pin_auth 44 1 97.73% 69 3 95.65% 180cbor_encode_change_pin_auth 39 0 100.00% 60 0 100.00%
181cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% 181cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00%
182cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% 182cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00%
183cbor_encode_hmac_secret_param 41 2 95.12% 66 9 86.36% 183cbor_encode_hmac_secret_param 41 1 97.56% 66 4 93.94%
184cbor_decode_fmt 9 0 100.00% 18 0 100.00% 184cbor_decode_fmt 9 0 100.00% 18 0 100.00%
185cbor_decode_pubkey 21 6 71.43% 32 7 78.12% 185cbor_decode_pubkey 21 1 95.24% 32 2 93.75%
186cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00% 186cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00%
187cbor_decode_assert_authdata 23 2 91.30% 44 2 95.45% 187cbor_decode_assert_authdata 23 0 100.00% 44 0 100.00%
188cbor_decode_attstmt 8 0 100.00% 10 0 100.00% 188cbor_decode_attstmt 8 0 100.00% 10 0 100.00%
189cbor_decode_uint64 4 0 100.00% 10 0 100.00% 189cbor_decode_uint64 4 0 100.00% 10 0 100.00%
190cbor_decode_cred_id 8 0 100.00% 10 0 100.00% 190cbor_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
193cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% 193cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00%
194cbor.c:check_key_type 8 0 100.00% 9 0 100.00% 194cbor.c:check_key_type 8 0 100.00% 9 0 100.00%
195cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% 195cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00%
196cbor.c:cbor_add_uint8 14 1 92.86% 26 3 88.46% 196cbor.c:cbor_add_uint8 14 0 100.00% 26 0 100.00%
197cbor.c:sha256 7 0 100.00% 15 0 100.00% 197cbor.c:sha256 7 0 100.00% 15 0 100.00%
198cbor.c:get_cose_alg 36 6 83.33% 48 6 87.50% 198cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00%
199cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% 199cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00%
200cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% 200cbor.c:decode_attcred 25 0 100.00% 58 0 100.00%
201cbor.c:decode_extensions 14 9 35.71% 34 13 61.76% 201cbor.c:decode_extensions 14 0 100.00% 34 0 100.00%
202cbor.c:decode_extension 27 27 0.00% 36 36 0.00% 202cbor.c:decode_extension 27 2 92.59% 36 6 83.33%
203cbor.c:decode_hmac_secret 16 4 75.00% 32 6 81.25% 203cbor.c:decode_hmac_secret 16 0 100.00% 32 0 100.00%
204cbor.c:decode_hmac_secret_aux 7 7 0.00% 17 17 0.00% 204cbor.c:decode_hmac_secret_aux 7 0 100.00% 17 0 100.00%
205cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00% 205cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00%
206cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% 206cbor.c:decode_x5c 4 0 100.00% 8 0 100.00%
207cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% 207cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00%
208cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% 208cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00%
209cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% 209cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00%
210--------------------------------------------------------------------------------------- 210---------------------------------------------------------------------------------------
211TOTAL 884 70 92.08% 1371 106 92.27% 211TOTAL 883 6 99.32% 1364 17 98.75%
212 212
213File '/libfido2/src/cred.c': 213File '/libfido2/src/cred.c':
214Name Regions Miss Cover Lines Miss Cover 214Name Regions Miss Cover Lines Miss Cover
215--------------------------------------------------------------------------------------- 215---------------------------------------------------------------------------------------
216fido_dev_make_cred 12 0 100.00% 10 0 100.00% 216fido_dev_make_cred 12 0 100.00% 10 0 100.00%
217fido_check_rp_id 4 0 100.00% 14 0 100.00% 217fido_check_rp_id 4 0 100.00% 14 0 100.00%
218fido_cred_verify 46 6 86.96% 71 11 84.51% 218fido_cred_verify 46 2 95.65% 71 3 95.77%
219fido_cred_verify_self 54 14 74.07% 90 22 75.56% 219fido_cred_verify_self 54 4 92.59% 90 5 94.44%
220fido_cred_new 1 0 100.00% 3 0 100.00% 220fido_cred_new 1 0 100.00% 3 0 100.00%
221fido_cred_reset_tx 1 0 100.00% 20 0 100.00% 221fido_cred_reset_tx 1 0 100.00% 20 0 100.00%
222fido_cred_reset_rx 1 0 100.00% 8 0 100.00% 222fido_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
227fido_cred_set_sig 12 0 100.00% 16 0 100.00% 227fido_cred_set_sig 12 0 100.00% 16 0 100.00%
228fido_cred_exclude 14 2 85.71% 25 3 88.00% 228fido_cred_exclude 14 2 85.71% 25 3 88.00%
229fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% 229fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00%
230fido_cred_set_rp 18 2 88.89% 26 6 76.92% 230fido_cred_set_rp 18 0 100.00% 26 0 100.00%
231fido_cred_set_user 33 4 87.88% 50 13 74.00% 231fido_cred_set_user 33 0 100.00% 50 0 100.00%
232fido_cred_set_extensions 15 0 100.00% 12 0 100.00% 232fido_cred_set_extensions 15 0 100.00% 12 0 100.00%
233fido_cred_set_options 6 6 0.00% 6 6 0.00% 233fido_cred_set_options 6 6 0.00% 6 6 0.00%
234fido_cred_set_rk 2 0 100.00% 5 0 100.00% 234fido_cred_set_rk 2 0 100.00% 5 0 100.00%
235fido_cred_set_uv 2 0 100.00% 5 0 100.00% 235fido_cred_set_uv 2 0 100.00% 5 0 100.00%
236fido_cred_set_prot 21 2 90.48% 16 0 100.00% 236fido_cred_set_prot 21 0 100.00% 16 0 100.00%
237fido_cred_set_fmt 16 4 75.00% 15 1 93.33% 237fido_cred_set_fmt 16 4 75.00% 15 1 93.33%
238fido_cred_set_type 17 2 88.24% 9 1 88.89% 238fido_cred_set_type 17 0 100.00% 9 0 100.00%
239fido_cred_type 1 0 100.00% 3 0 100.00% 239fido_cred_type 1 0 100.00% 3 0 100.00%
240fido_cred_flags 1 0 100.00% 3 0 100.00% 240fido_cred_flags 1 0 100.00% 3 0 100.00%
241fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% 241fido_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
246fido_cred_sig_len 1 0 100.00% 3 0 100.00% 246fido_cred_sig_len 1 0 100.00% 3 0 100.00%
247fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% 247fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00%
248fido_cred_authdata_len 1 0 100.00% 3 0 100.00% 248fido_cred_authdata_len 1 0 100.00% 3 0 100.00%
249fido_cred_pubkey_ptr 9 2 77.78% 20 2 90.00% 249fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00%
250fido_cred_pubkey_len 9 2 77.78% 20 2 90.00% 250fido_cred_pubkey_len 9 0 100.00% 20 0 100.00%
251fido_cred_id_ptr 1 0 100.00% 3 0 100.00% 251fido_cred_id_ptr 1 0 100.00% 3 0 100.00%
252fido_cred_id_len 1 0 100.00% 3 0 100.00% 252fido_cred_id_len 1 0 100.00% 3 0 100.00%
253fido_cred_aaguid_ptr 1 0 100.00% 3 0 100.00%
254fido_cred_aaguid_len 1 0 100.00% 3 0 100.00%
253fido_cred_prot 1 0 100.00% 3 0 100.00% 255fido_cred_prot 1 0 100.00% 3 0 100.00%
254fido_cred_fmt 1 0 100.00% 3 0 100.00% 256fido_cred_fmt 1 0 100.00% 3 0 100.00%
255fido_cred_rp_id 1 0 100.00% 3 0 100.00% 257fido_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
269cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% 271cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00%
270cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% 272cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00%
271--------------------------------------------------------------------------------------- 273---------------------------------------------------------------------------------------
272TOTAL 534 51 90.45% 830 78 90.60% 274TOTAL 536 23 95.71% 836 29 96.53%
273 275
274File '/libfido2/src/credman.c': 276File '/libfido2/src/credman.c':
275Name Regions Miss Cover Lines Miss Cover 277Name Regions Miss Cover Lines Miss Cover
@@ -295,14 +297,14 @@ fido_credman_rp_id_hash_len 4 0 100.00% 6 0
295fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% 297fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00%
296credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% 298credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00%
297credman.c:credman_tx 30 0 100.00% 53 0 100.00% 299credman.c:credman_tx 30 0 100.00% 53 0 100.00%
298credman.c:credman_prepare_hmac 21 1 95.24% 43 2 95.35% 300credman.c:credman_prepare_hmac 21 1 95.24% 43 3 93.02%
299credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00% 301credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00%
300credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% 302credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00%
301credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% 303credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00%
302credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00% 304credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00%
303credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% 305credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00%
304credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% 306credman.c:credman_grow_array 17 2 88.24% 28 5 82.14%
305credman.c:credman_parse_rk 13 0 100.00% 25 0 100.00% 307credman.c:credman_parse_rk 22 0 100.00% 31 0 100.00%
306credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62% 308credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62%
307credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% 309credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00%
308credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% 310credman.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
313credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% 315credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00%
314credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% 316credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00%
315--------------------------------------------------------------------------------------- 317---------------------------------------------------------------------------------------
316TOTAL 376 18 95.21% 589 15 97.45% 318TOTAL 385 18 95.32% 595 16 97.31%
317 319
318File '/libfido2/src/dev.c': 320File '/libfido2/src/dev.c':
319Name Regions Miss Cover Lines Miss Cover 321Name Regions Miss Cover Lines Miss Cover
@@ -324,9 +326,11 @@ fido_dev_info_manifest 17 17 0.00% 24 24
324fido_dev_open_with_info 5 5 0.00% 6 6 0.00% 326fido_dev_open_with_info 5 5 0.00% 6 6 0.00%
325fido_dev_open 1 0 100.00% 3 0 100.00% 327fido_dev_open 1 0 100.00% 3 0 100.00%
326fido_dev_close 8 2 75.00% 9 0 100.00% 328fido_dev_close 8 2 75.00% 9 0 100.00%
327fido_dev_cancel 7 0 100.00% 6 0 100.00% 329fido_dev_cancel 11 0 100.00% 9 0 100.00%
328fido_dev_set_io_functions 18 4 77.78% 16 6 62.50% 330fido_dev_get_touch_begin 50 0 100.00% 68 0 100.00%
329fido_dev_set_transport_functions 6 6 0.00% 10 10 0.00% 331fido_dev_get_touch_status 17 0 100.00% 25 0 100.00%
332fido_dev_set_io_functions 18 4 77.78% 17 6 64.71%
333fido_dev_set_transport_functions 6 6 0.00% 11 11 0.00%
330fido_init 7 1 85.71% 4 0 100.00% 334fido_init 7 1 85.71% 4 0 100.00%
331fido_dev_new 5 0 100.00% 16 0 100.00% 335fido_dev_new 5 0 100.00% 16 0 100.00%
332fido_dev_new_with_info 17 17 0.00% 26 26 0.00% 336fido_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
337fido_dev_build 1 0 100.00% 3 0 100.00% 341fido_dev_build 1 0 100.00% 3 0 100.00%
338fido_dev_flags 1 0 100.00% 3 0 100.00% 342fido_dev_flags 1 0 100.00% 3 0 100.00%
339fido_dev_is_fido2 2 0 100.00% 3 0 100.00% 343fido_dev_is_fido2 2 0 100.00% 3 0 100.00%
340fido_dev_force_u2f 2 0 100.00% 3 0 100.00% 344fido_dev_supports_pin 3 0 100.00% 3 0 100.00%
345fido_dev_has_pin 2 0 100.00% 3 0 100.00%
346fido_dev_supports_cred_prot 2 0 100.00% 3 0 100.00%
347fido_dev_force_u2f 2 0 100.00% 4 0 100.00%
341fido_dev_force_fido2 2 2 0.00% 3 3 0.00% 348fido_dev_force_fido2 2 2 0.00% 3 3 0.00%
342dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00% 349dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00%
343dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% 350dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00%
344dev.c:fido_dev_open_tx 25 8 68.00% 32 12 62.50% 351dev.c:fido_dev_open_tx 51 13 74.51% 63 23 63.49%
345dev.c:obtain_nonce 4 1 75.00% 5 1 80.00% 352dev.c:obtain_nonce 4 1 75.00% 5 1 80.00%
346dev.c:fido_dev_open_rx 32 0 100.00% 53 0 100.00% 353dev.c:set_random_report_len 11 0 100.00% 6 0 100.00%
354dev.c:fido_dev_open_rx 33 0 100.00% 56 0 100.00%
355dev.c:fido_dev_set_flags 17 0 100.00% 24 0 100.00%
347--------------------------------------------------------------------------------------- 356---------------------------------------------------------------------------------------
348TOTAL 201 85 57.71% 294 128 56.46% 357TOTAL 334 90 73.05% 466 140 69.96%
349 358
350File '/libfido2/src/ecdh.c': 359File '/libfido2/src/ecdh.c':
351Name Regions Miss Cover Lines Miss Cover 360Name Regions Miss Cover Lines Miss Cover
@@ -372,9 +381,9 @@ TOTAL 54 0 100.00% 79 0
372File '/libfido2/src/err.c': 381File '/libfido2/src/err.c':
373Name Regions Miss Cover Lines Miss Cover 382Name Regions Miss Cover Lines Miss Cover
374--------------------------------------------------------------------------------------- 383---------------------------------------------------------------------------------------
375fido_strerr 108 108 0.00% 112 112 0.00% 384fido_strerr 112 8 92.86% 116 8 93.10%
376--------------------------------------------------------------------------------------- 385---------------------------------------------------------------------------------------
377TOTAL 108 108 0.00% 112 112 0.00% 386TOTAL 112 8 92.86% 116 8 93.10%
378 387
379File '/libfido2/src/es256.c': 388File '/libfido2/src/es256.c':
380Name Regions Miss Cover Lines Miss Cover 389Name Regions Miss Cover Lines Miss Cover
@@ -389,14 +398,14 @@ es256_pk_from_ptr 11 0 100.00% 13 0
389es256_pk_set_x 1 0 100.00% 5 0 100.00% 398es256_pk_set_x 1 0 100.00% 5 0 100.00%
390es256_pk_set_y 1 0 100.00% 5 0 100.00% 399es256_pk_set_y 1 0 100.00% 5 0 100.00%
391es256_sk_create 39 0 100.00% 46 0 100.00% 400es256_sk_create 39 0 100.00% 46 0 100.00%
392es256_pk_to_EVP_PKEY 41 0 100.00% 58 0 100.00% 401es256_pk_to_EVP_PKEY 42 0 100.00% 66 0 100.00%
393es256_pk_from_EC_KEY 38 0 100.00% 39 0 100.00% 402es256_pk_from_EC_KEY 38 0 100.00% 43 0 100.00%
394es256_sk_to_EVP_PKEY 27 0 100.00% 41 0 100.00% 403es256_sk_to_EVP_PKEY 28 0 100.00% 50 0 100.00%
395es256_derive_pk 25 0 100.00% 34 0 100.00% 404es256_derive_pk 25 0 100.00% 34 0 100.00%
396es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% 405es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00%
397es256.c:decode_coord 8 0 100.00% 12 0 100.00% 406es256.c:decode_coord 8 0 100.00% 12 0 100.00%
398--------------------------------------------------------------------------------------- 407---------------------------------------------------------------------------------------
399TOTAL 278 0 100.00% 377 0 100.00% 408TOTAL 280 0 100.00% 398 0 100.00%
400 409
401File '/libfido2/src/extern.h': 410File '/libfido2/src/extern.h':
402Name Regions Miss Cover Lines Miss Cover 411Name Regions Miss Cover Lines Miss Cover
@@ -423,20 +432,27 @@ TOTAL 16 16 0.00% 38 38
423File '/libfido2/src/hid_linux.c': 432File '/libfido2/src/hid_linux.c':
424Name Regions Miss Cover Lines Miss Cover 433Name Regions Miss Cover Lines Miss Cover
425--------------------------------------------------------------------------------------- 434---------------------------------------------------------------------------------------
426fido_hid_manifest 33 33 0.00% 46 46 0.00% 435fido_hid_manifest 35 35 0.00% 50 50 0.00%
427fido_hid_open 6 6 0.00% 11 11 0.00% 436fido_hid_open 17 17 0.00% 22 22 0.00%
428fido_hid_close 1 1 0.00% 6 6 0.00% 437fido_hid_close 1 1 0.00% 6 6 0.00%
429fido_hid_read 12 12 0.00% 16 16 0.00% 438fido_hid_read 12 12 0.00% 21 21 0.00%
430fido_hid_write 12 12 0.00% 16 16 0.00% 439fido_hid_write 9 9 0.00% 16 16 0.00%
431hid_linux.c:copy_info 35 35 0.00% 56 56 0.00% 440fido_hid_report_in_len 1 1 0.00% 5 5 0.00%
432hid_linux.c:is_fido 6 6 0.00% 14 14 0.00% 441fido_hid_report_out_len 1 1 0.00% 5 5 0.00%
433hid_linux.c:get_report_descriptor 17 17 0.00% 30 30 0.00% 442hid_linux.c:copy_info 30 30 0.00% 52 52 0.00%
434hid_linux.c:get_usage_info 16 16 0.00% 33 33 0.00% 443hid_linux.c:is_fido 9 9 0.00% 23 23 0.00%
444hid_linux.c:get_usage_info 16 16 0.00% 30 30 0.00%
435hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% 445hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00%
436hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% 446hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00%
437hid_linux.c:parse_uevent 16 16 0.00% 30 30 0.00% 447hid_linux.c:get_parent_attr 6 6 0.00% 11 11 0.00%
438--------------------------------------------------------------------------------------- 448hid_linux.c:parse_uevent 12 12 0.00% 28 28 0.00%
439TOTAL 166 166 0.00% 292 292 0.00% 449hid_linux.c:get_usb_attr 1 1 0.00% 3 3 0.00%
450hid_linux.c:get_report_descriptor 11 11 0.00% 18 18 0.00%
451hid_linux.c:get_report_sizes 19 19 0.00% 33 33 0.00%
452hid_linux.c:waitfd 28 28 0.00% 43 43 0.00%
453hid_linux.c:timespec_to_ms 15 15 0.00% 16 16 0.00%
454---------------------------------------------------------------------------------------
455TOTAL 235 235 0.00% 416 416 0.00%
440 456
441File '/libfido2/src/info.c': 457File '/libfido2/src/info.c':
442Name Regions Miss Cover Lines Miss Cover 458Name Regions Miss Cover Lines Miss Cover
@@ -455,11 +471,14 @@ fido_cbor_info_options_name_ptr 1 0 100.00% 3 0
455fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% 471fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00%
456fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% 472fido_cbor_info_options_len 1 0 100.00% 3 0 100.00%
457fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% 473fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00%
474fido_cbor_info_maxcredcntlst 1 0 100.00% 3 0 100.00%
475fido_cbor_info_maxcredidlen 1 0 100.00% 3 0 100.00%
476fido_cbor_info_fwversion 1 0 100.00% 3 0 100.00%
458fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% 477fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00%
459fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% 478fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00%
460info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00% 479info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00%
461info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00% 480info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00%
462info.c:parse_reply_element 13 0 100.00% 27 0 100.00% 481info.c:parse_reply_element 16 0 100.00% 33 0 100.00%
463info.c:decode_versions 12 0 100.00% 21 0 100.00% 482info.c:decode_versions 12 0 100.00% 21 0 100.00%
464info.c:decode_version 4 0 100.00% 14 0 100.00% 483info.c:decode_version 4 0 100.00% 14 0 100.00%
465info.c:decode_extensions 12 0 100.00% 21 0 100.00% 484info.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
473info.c:free_opt_array 4 0 100.00% 9 0 100.00% 492info.c:free_opt_array 4 0 100.00% 9 0 100.00%
474info.c:free_byte_array 1 0 100.00% 6 0 100.00% 493info.c:free_byte_array 1 0 100.00% 6 0 100.00%
475--------------------------------------------------------------------------------------- 494---------------------------------------------------------------------------------------
476TOTAL 146 0 100.00% 304 0 100.00% 495TOTAL 152 0 100.00% 319 0 100.00%
477 496
478File '/libfido2/src/io.c': 497File '/libfido2/src/io.c':
479Name Regions Miss Cover Lines Miss Cover 498Name Regions Miss Cover Lines Miss Cover
480--------------------------------------------------------------------------------------- 499---------------------------------------------------------------------------------------
481fido_tx 14 1 92.86% 18 0 100.00% 500fido_tx 13 1 92.31% 14 0 100.00%
482fido_rx 13 2 84.62% 21 3 85.71% 501fido_rx 13 2 84.62% 19 3 84.21%
483fido_rx_cbor_status 8 0 100.00% 12 0 100.00% 502fido_rx_cbor_status 8 0 100.00% 12 0 100.00%
484io.c:tx_empty 7 0 100.00% 16 0 100.00% 503io.c:tx_empty 9 0 100.00% 17 0 100.00%
485io.c:tx 13 0 100.00% 21 0 100.00% 504io.c:tx 13 0 100.00% 21 0 100.00%
486io.c:tx_preamble 10 0 100.00% 20 0 100.00% 505io.c:tx_preamble 16 1 93.75% 24 1 95.83%
487io.c:tx_frame 9 0 100.00% 18 0 100.00% 506io.c:tx_frame 15 1 93.33% 22 1 95.45%
488io.c:rx 25 1 96.00% 58 4 93.10% 507io.c:rx 40 2 95.00% 68 1 98.53%
489io.c:rx_preamble 18 1 94.44% 25 4 84.00% 508io.c:rx_preamble 21 2 90.48% 28 5 82.14%
490io.c:rx_frame 6 0 100.00% 9 0 100.00% 509io.c:rx_frame 8 0 100.00% 11 0 100.00%
491--------------------------------------------------------------------------------------- 510---------------------------------------------------------------------------------------
492TOTAL 123 5 95.93% 218 11 94.95% 511TOTAL 156 9 94.23% 236 11 95.34%
493 512
494File '/libfido2/src/iso7816.c': 513File '/libfido2/src/iso7816.c':
495Name Regions Miss Cover Lines Miss Cover 514Name Regions Miss Cover Lines Miss Cover
@@ -547,32 +566,34 @@ TOTAL 19 0 100.00% 22 0
547File '/libfido2/src/rs256.c': 566File '/libfido2/src/rs256.c':
548Name Regions Miss Cover Lines Miss Cover 567Name Regions Miss Cover Lines Miss Cover
549--------------------------------------------------------------------------------------- 568---------------------------------------------------------------------------------------
550rs256_pk_decode 8 8 0.00% 10 10 0.00% 569rs256_pk_decode 8 0 100.00% 10 0 100.00%
551rs256_pk_new 1 0 100.00% 3 0 100.00% 570rs256_pk_new 1 0 100.00% 3 0 100.00%
552rs256_pk_free 6 0 100.00% 11 0 100.00% 571rs256_pk_free 6 0 100.00% 11 0 100.00%
553rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% 572rs256_pk_from_ptr 6 0 100.00% 8 0 100.00%
554rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% 573rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00%
555rs256_pk_from_RSA 32 4 87.50% 32 6 81.25% 574rs256_pk_from_RSA 32 4 87.50% 32 6 81.25%
556rs256.c:decode_rsa_pubkey 9 9 0.00% 16 16 0.00% 575rs256.c:decode_rsa_pubkey 9 1 88.89% 16 4 75.00%
557rs256.c:decode_bignum 8 8 0.00% 12 12 0.00% 576rs256.c:decode_bignum 8 1 87.50% 12 3 75.00%
558--------------------------------------------------------------------------------------- 577---------------------------------------------------------------------------------------
559TOTAL 102 29 71.57% 140 44 68.57% 578TOTAL 102 6 94.12% 140 13 90.71%
560 579
561File '/libfido2/src/u2f.c': 580File '/libfido2/src/u2f.c':
562Name Regions Miss Cover Lines Miss Cover 581Name Regions Miss Cover Lines Miss Cover
563--------------------------------------------------------------------------------------- 582---------------------------------------------------------------------------------------
564u2f_register 70 5 92.86% 88 7 92.05% 583u2f_register 70 1 98.57% 88 0 100.00%
565u2f_authenticate 32 4 87.50% 44 2 95.45% 584u2f_authenticate 32 0 100.00% 44 0 100.00%
585u2f_get_touch_begin 30 0 100.00% 46 0 100.00%
586u2f_get_touch_status 18 0 100.00% 29 0 100.00%
566u2f.c:key_lookup 44 0 100.00% 69 0 100.00% 587u2f.c:key_lookup 44 0 100.00% 69 0 100.00%
567u2f.c:send_dummy_register 31 5 83.87% 49 8 83.67% 588u2f.c:send_dummy_register 31 1 96.77% 49 0 100.00%
568u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% 589u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00%
569u2f.c:x5c_get 21 2 90.48% 37 6 83.78% 590u2f.c:x5c_get 21 1 95.24% 37 3 91.89%
570u2f.c:sig_get 8 1 87.50% 16 6 62.50% 591u2f.c:sig_get 8 1 87.50% 16 6 62.50%
571u2f.c:encode_cred_authdata 37 3 91.89% 82 9 89.02% 592u2f.c:encode_cred_authdata 37 2 94.59% 82 6 92.68%
572u2f.c:cbor_blob_from_ec_point 22 1 95.45% 39 3 92.31% 593u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00%
573u2f.c:u2f_authenticate_single 36 2 94.44% 58 4 93.10% 594u2f.c:u2f_authenticate_single 36 0 100.00% 58 0 100.00%
574u2f.c:do_auth 50 3 94.00% 71 4 94.37% 595u2f.c:do_auth 50 1 98.00% 71 0 100.00%
575u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% 596u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66%
576u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% 597u2f.c:authdata_fake 12 0 100.00% 34 0 100.00%
577--------------------------------------------------------------------------------------- 598---------------------------------------------------------------------------------------
578TOTAL 443 28 93.68% 699 52 92.56% 599TOTAL 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 @@
23 23
24#include "../openbsd-compat/openbsd-compat.h" 24#include "../openbsd-compat/openbsd-compat.h"
25 25
26#define TAG_U2F 0x01
27#define TAG_TYPE 0x02
28#define TAG_CDH 0x03
29#define TAG_RP_ID 0x04
30#define TAG_EXT 0x05
31#define TAG_SEED 0x06
32#define TAG_UP 0x07
33#define TAG_UV 0x08
34#define TAG_WIRE_DATA 0x09
35#define TAG_CRED_COUNT 0x0a
36#define TAG_CRED 0x0b
37#define TAG_ES256 0x0c
38#define TAG_RS256 0x0d
39#define TAG_PIN 0x0e
40#define TAG_EDDSA 0x0f
41
42/* Parameter set defining a FIDO2 get assertion operation. */ 26/* Parameter set defining a FIDO2 get assertion operation. */
43struct param { 27struct param {
44 char pin[MAXSTR]; 28 char pin[MAXSTR];
45 char rp_id[MAXSTR]; 29 char rp_id[MAXSTR];
46 int ext; 30 int ext;
47 int seed; 31 int seed;
48 struct blob cdh; 32 struct blob cdh;
49 struct blob cred; 33 struct blob cred;
50 struct blob es256; 34 struct blob es256;
51 struct blob rs256; 35 struct blob rs256;
52 struct blob eddsa; 36 struct blob eddsa;
53 struct blob wire_data; 37 struct blob wire_data;
54 uint8_t cred_count; 38 uint8_t cred_count;
55 uint8_t type; 39 uint8_t type;
56 uint8_t u2f; 40 uint8_t u2f;
57 uint8_t up; 41 uint8_t up;
58 uint8_t uv; 42 uint8_t uv;
59}; 43};
60 44
61/* 45/*
@@ -83,73 +67,153 @@ static const uint8_t dummy_wire_data_u2f[] = {
83 WIREDATA_CTAP_U2F_AUTH, 67 WIREDATA_CTAP_U2F_AUTH,
84}; 68};
85 69
86int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 70struct param *
87size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 71unpack(const uint8_t *ptr, size_t len)
88
89static int
90unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
91{ 72{
92 uint8_t **pp = (void *)&ptr; 73 cbor_item_t *item = NULL, **v;
93 74 struct cbor_load_result cbor;
94 if (unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || 75 struct param *p;
95 unpack_byte(TAG_UP, pp, &len, &p->up) < 0 || 76 int ok = -1;
96 unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || 77
97 unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || 78 if ((p = calloc(1, sizeof(*p))) == NULL ||
98 unpack_byte(TAG_CRED_COUNT, pp, &len, &p->cred_count) < 0 || 79 (item = cbor_load(ptr, len, &cbor)) == NULL ||
99 unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || 80 cbor.read != len ||
100 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 81 cbor_isa_array(item) == false ||
101 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 82 cbor_array_is_definite(item) == false ||
102 unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 83 cbor_array_size(item) != 15 ||
103 unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || 84 (v = cbor_array_handle(item)) == NULL)
104 unpack_blob(TAG_RS256, pp, &len, &p->rs256) < 0 || 85 goto fail;
105 unpack_blob(TAG_ES256, pp, &len, &p->es256) < 0 || 86
106 unpack_blob(TAG_EDDSA, pp, &len, &p->eddsa) < 0 || 87 if (unpack_byte(v[0], &p->uv) < 0 ||
107 unpack_blob(TAG_CRED, pp, &len, &p->cred) < 0 || 88 unpack_byte(v[1], &p->up) < 0 ||
108 unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0) 89 unpack_byte(v[2], &p->u2f) < 0 ||
109 return (-1); 90 unpack_byte(v[3], &p->type) < 0 ||
110 91 unpack_byte(v[4], &p->cred_count) < 0 ||
111 return (0); 92 unpack_int(v[5], &p->ext) < 0 ||
93 unpack_int(v[6], &p->seed) < 0 ||
94 unpack_string(v[7], p->rp_id) < 0 ||
95 unpack_string(v[8], p->pin) < 0 ||
96 unpack_blob(v[9], &p->wire_data) < 0 ||
97 unpack_blob(v[10], &p->rs256) < 0 ||
98 unpack_blob(v[11], &p->es256) < 0 ||
99 unpack_blob(v[12], &p->eddsa) < 0 ||
100 unpack_blob(v[13], &p->cred) < 0 ||
101 unpack_blob(v[14], &p->cdh) < 0)
102 goto fail;
103
104 ok = 0;
105fail:
106 if (ok < 0) {
107 free(p);
108 p = NULL;
109 }
110
111 if (item)
112 cbor_decref(&item);
113
114 return p;
112} 115}
113 116
114static size_t 117size_t
115pack(uint8_t *ptr, size_t len, const struct param *p) 118pack(uint8_t *ptr, size_t len, const struct param *p)
116{ 119{
117 const size_t max = len; 120 cbor_item_t *argv[15], *array = NULL;
118 121 size_t cbor_alloc_len, cbor_len = 0;
119 if (pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || 122 unsigned char *cbor = NULL;
120 pack_byte(TAG_UP, &ptr, &len, p->up) < 0 || 123
121 pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || 124 memset(argv, 0, sizeof(argv));
122 pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || 125
123 pack_byte(TAG_CRED_COUNT, &ptr, &len, p->cred_count) < 0 || 126 if ((array = cbor_new_definite_array(15)) == NULL ||
124 pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || 127 (argv[0] = pack_byte(p->uv)) == NULL ||
125 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 128 (argv[1] = pack_byte(p->up)) == NULL ||
126 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 129 (argv[2] = pack_byte(p->u2f)) == NULL ||
127 pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 130 (argv[3] = pack_byte(p->type)) == NULL ||
128 pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || 131 (argv[4] = pack_byte(p->cred_count)) == NULL ||
129 pack_blob(TAG_RS256, &ptr, &len, &p->rs256) < 0 || 132 (argv[5] = pack_int(p->ext)) == NULL ||
130 pack_blob(TAG_ES256, &ptr, &len, &p->es256) < 0 || 133 (argv[6] = pack_int(p->seed)) == NULL ||
131 pack_blob(TAG_EDDSA, &ptr, &len, &p->eddsa) < 0 || 134 (argv[7] = pack_string(p->rp_id)) == NULL ||
132 pack_blob(TAG_CRED, &ptr, &len, &p->cred) < 0 || 135 (argv[8] = pack_string(p->pin)) == NULL ||
133 pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0) 136 (argv[9] = pack_blob(&p->wire_data)) == NULL ||
134 return (0); 137 (argv[10] = pack_blob(&p->rs256)) == NULL ||
135 138 (argv[11] = pack_blob(&p->es256)) == NULL ||
136 return (max - len); 139 (argv[12] = pack_blob(&p->eddsa)) == NULL ||
140 (argv[13] = pack_blob(&p->cred)) == NULL ||
141 (argv[14] = pack_blob(&p->cdh)) == NULL)
142 goto fail;
143
144 for (size_t i = 0; i < 15; i++)
145 if (cbor_array_push(array, argv[i]) == false)
146 goto fail;
147
148 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
149 &cbor_alloc_len)) > len) {
150 cbor_len = 0;
151 goto fail;
152 }
153
154 memcpy(ptr, cbor, cbor_len);
155fail:
156 for (size_t i = 0; i < 15; i++)
157 if (argv[i])
158 cbor_decref(&argv[i]);
159
160 if (array)
161 cbor_decref(&array);
162
163 free(cbor);
164
165 return cbor_len;
137} 166}
138 167
139static size_t 168size_t
140input_len(int max) 169pack_dummy(uint8_t *ptr, size_t len)
141{ 170{
142 return (5 * len_byte() + 2 * len_int() + 2 * len_string(max) + 171 struct param dummy;
143 6 * len_blob(max)); 172 uint8_t blob[4096];
173 size_t blob_len;
174
175 memset(&dummy, 0, sizeof(dummy));
176
177 dummy.type = 1; /* rsa */
178 dummy.ext = FIDO_EXT_HMAC_SECRET;
179
180 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
181 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
182
183 dummy.cred.len = sizeof(dummy_cdh); /* XXX */
184 dummy.cdh.len = sizeof(dummy_cdh);
185 dummy.es256.len = sizeof(dummy_es256);
186 dummy.rs256.len = sizeof(dummy_rs256);
187 dummy.eddsa.len = sizeof(dummy_eddsa);
188 dummy.wire_data.len = sizeof(dummy_wire_data_fido);
189
190 memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */
191 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
192 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
193 dummy.wire_data.len);
194 memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len);
195 memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len);
196 memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len);
197
198 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
199
200 if (blob_len > len) {
201 memcpy(ptr, blob, len);
202 return len;
203 }
204
205 memcpy(ptr, blob, blob_len);
206
207 return blob_len;
144} 208}
145 209
146static void 210static void
147get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, 211get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh,
148 const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, 212 const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin,
149 uint8_t cred_count, struct blob *cred) 213 uint8_t cred_count, const struct blob *cred)
150{ 214{
151 fido_dev_t *dev; 215 fido_dev_t *dev;
152 fido_dev_io_t io; 216 fido_dev_io_t io;
153 217
154 memset(&io, 0, sizeof(io)); 218 memset(&io, 0, sizeof(io));
155 219
@@ -166,21 +230,31 @@ get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh,
166 230
167 if (u2f & 1) 231 if (u2f & 1)
168 fido_dev_force_u2f(dev); 232 fido_dev_force_u2f(dev);
169
170 for (uint8_t i = 0; i < cred_count; i++)
171 fido_assert_allow_cred(assert, cred->body, cred->len);
172
173 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
174 fido_assert_set_rp(assert, rp_id);
175 if (ext & 1) 233 if (ext & 1)
176 fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); 234 fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET);
177 if (up & 1) 235 if (up & 1)
178 fido_assert_set_up(assert, FIDO_OPT_TRUE); 236 fido_assert_set_up(assert, FIDO_OPT_TRUE);
237 else if (u2f &1)
238 fido_assert_set_up(assert, FIDO_OPT_FALSE);
179 if (uv & 1) 239 if (uv & 1)
180 fido_assert_set_uv(assert, FIDO_OPT_TRUE); 240 fido_assert_set_uv(assert, FIDO_OPT_TRUE);
181 /* XXX reuse cred as hmac salt to keep struct param small */ 241
242 for (uint8_t i = 0; i < cred_count; i++)
243 fido_assert_allow_cred(assert, cred->body, cred->len);
244
245 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
246 fido_assert_set_rp(assert, rp_id);
247 /* XXX reuse cred as hmac salt */
182 fido_assert_set_hmac_salt(assert, cred->body, cred->len); 248 fido_assert_set_hmac_salt(assert, cred->body, cred->len);
183 249
250 /* repeat memory operations to trigger reallocation paths */
251 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
252 fido_assert_set_rp(assert, rp_id);
253 fido_assert_set_hmac_salt(assert, cred->body, cred->len);
254
255 if (strlen(pin) == 0)
256 pin = NULL;
257
184 fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin); 258 fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin);
185 259
186 fido_dev_cancel(dev); 260 fido_dev_cancel(dev);
@@ -194,7 +268,7 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
194 const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, 268 const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv,
195 int ext, void *pk) 269 int ext, void *pk)
196{ 270{
197 fido_assert_t *assert = NULL; 271 fido_assert_t *assert = NULL;
198 272
199 if ((assert = fido_assert_new()) == NULL) 273 if ((assert = fido_assert_new()) == NULL)
200 return; 274 return;
@@ -202,16 +276,30 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
202 fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); 276 fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len);
203 fido_assert_set_rp(assert, rp_id); 277 fido_assert_set_rp(assert, rp_id);
204 fido_assert_set_count(assert, 1); 278 fido_assert_set_count(assert, 1);
279
205 if (fido_assert_set_authdata(assert, 0, authdata_ptr, 280 if (fido_assert_set_authdata(assert, 0, authdata_ptr,
206 authdata_len) != FIDO_OK) { 281 authdata_len) != FIDO_OK) {
207 fido_assert_set_authdata_raw(assert, 0, authdata_ptr, 282 fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
208 authdata_len); 283 authdata_len);
209 } 284 }
285
286 if (up & 1)
287 fido_assert_set_up(assert, FIDO_OPT_TRUE);
288 if (uv & 1)
289 fido_assert_set_uv(assert, FIDO_OPT_TRUE);
290
210 fido_assert_set_extensions(assert, ext); 291 fido_assert_set_extensions(assert, ext);
211 if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE);
212 if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE);
213 fido_assert_set_sig(assert, 0, sig_ptr, sig_len); 292 fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
214 fido_assert_verify(assert, 0, type, pk); 293
294 /* repeat memory operations to trigger reallocation paths */
295 if (fido_assert_set_authdata(assert, 0, authdata_ptr,
296 authdata_len) != FIDO_OK) {
297 fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
298 authdata_len);
299 }
300 fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
301
302 assert(fido_assert_verify(assert, 0, type, pk) != FIDO_OK);
215 303
216 fido_assert_free(&assert); 304 fido_assert_free(&assert);
217} 305}
@@ -262,38 +350,30 @@ out:
262 EVP_PKEY_free(pkey); 350 EVP_PKEY_free(pkey);
263} 351}
264 352
265int 353void
266LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 354test(const struct param *p)
267{ 355{
268 struct param p; 356 fido_assert_t *assert = NULL;
269 fido_assert_t *assert = NULL; 357 es256_pk_t *es256_pk = NULL;
270 es256_pk_t *es256_pk = NULL; 358 rs256_pk_t *rs256_pk = NULL;
271 rs256_pk_t *rs256_pk = NULL; 359 eddsa_pk_t *eddsa_pk = NULL;
272 eddsa_pk_t *eddsa_pk = NULL; 360 uint8_t flags;
273 uint8_t flags; 361 uint32_t sigcount;
274 uint32_t sigcount; 362 int cose_alg = 0;
275 int cose_alg = 0; 363 void *pk;
276 void *pk; 364
277 365 prng_init((unsigned int)p->seed);
278 memset(&p, 0, sizeof(p));
279
280 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
281 unpack(data, size, &p) < 0)
282 return (0);
283
284 prng_init((unsigned int)p.seed);
285
286 fido_init(FIDO_DEBUG); 366 fido_init(FIDO_DEBUG);
287 fido_set_log_handler(consume_str); 367 fido_set_log_handler(consume_str);
288 368
289 switch (p.type & 3) { 369 switch (p->type & 3) {
290 case 0: 370 case 0:
291 cose_alg = COSE_ES256; 371 cose_alg = COSE_ES256;
292 372
293 if ((es256_pk = es256_pk_new()) == NULL) 373 if ((es256_pk = es256_pk_new()) == NULL)
294 return (0); 374 return;
295 375
296 es256_pk_from_ptr(es256_pk, p.es256.body, p.es256.len); 376 es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len);
297 pk = es256_pk; 377 pk = es256_pk;
298 378
299 break; 379 break;
@@ -301,9 +381,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
301 cose_alg = COSE_RS256; 381 cose_alg = COSE_RS256;
302 382
303 if ((rs256_pk = rs256_pk_new()) == NULL) 383 if ((rs256_pk = rs256_pk_new()) == NULL)
304 return (0); 384 return;
305 385
306 rs256_pk_from_ptr(rs256_pk, p.rs256.body, p.rs256.len); 386 rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len);
307 pk = rs256_pk; 387 pk = rs256_pk;
308 388
309 rs256_convert(pk); 389 rs256_convert(pk);
@@ -313,9 +393,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
313 cose_alg = COSE_EDDSA; 393 cose_alg = COSE_EDDSA;
314 394
315 if ((eddsa_pk = eddsa_pk_new()) == NULL) 395 if ((eddsa_pk = eddsa_pk_new()) == NULL)
316 return (0); 396 return;
317 397
318 eddsa_pk_from_ptr(eddsa_pk, p.eddsa.body, p.eddsa.len); 398 eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len);
319 pk = eddsa_pk; 399 pk = eddsa_pk;
320 400
321 eddsa_convert(pk); 401 eddsa_convert(pk);
@@ -326,10 +406,10 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
326 if ((assert = fido_assert_new()) == NULL) 406 if ((assert = fido_assert_new()) == NULL)
327 goto out; 407 goto out;
328 408
329 set_wire_data(p.wire_data.body, p.wire_data.len); 409 set_wire_data(p->wire_data.body, p->wire_data.len);
330 410
331 get_assert(assert, p.u2f, &p.cdh, p.rp_id, p.ext, p.up, p.uv, p.pin, 411 get_assert(assert, p->u2f, &p->cdh, p->rp_id, p->ext, p->up, p->uv,
332 p.cred_count, &p.cred); 412 p->pin, p->cred_count, &p->cred);
333 413
334 /* XXX +1 on purpose */ 414 /* XXX +1 on purpose */
335 for (size_t i = 0; i <= fido_assert_count(assert); i++) { 415 for (size_t i = 0; i <= fido_assert_count(assert); i++) {
@@ -340,7 +420,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
340 fido_assert_authdata_ptr(assert, i), 420 fido_assert_authdata_ptr(assert, i),
341 fido_assert_authdata_len(assert, i), 421 fido_assert_authdata_len(assert, i),
342 fido_assert_sig_ptr(assert, i), 422 fido_assert_sig_ptr(assert, i),
343 fido_assert_sig_len(assert, i), p.up, p.uv, p.ext, pk); 423 fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk);
344 consume(fido_assert_id_ptr(assert, i), 424 consume(fido_assert_id_ptr(assert, i),
345 fido_assert_id_len(assert, i)); 425 fido_assert_id_len(assert, i));
346 consume(fido_assert_user_id_ptr(assert, i), 426 consume(fido_assert_user_id_ptr(assert, i),
@@ -365,103 +445,40 @@ out:
365 eddsa_pk_free(&eddsa_pk); 445 eddsa_pk_free(&eddsa_pk);
366 446
367 fido_assert_free(&assert); 447 fido_assert_free(&assert);
368
369 return (0);
370} 448}
371 449
372static size_t 450void
373pack_dummy(uint8_t *ptr, size_t len) 451mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
374{ 452{
375 struct param dummy; 453 if (flags & MUTATE_SEED)
376 uint8_t blob[16384]; 454 p->seed = (int)seed;
377 size_t blob_len; 455
378 456 if (flags & MUTATE_PARAM) {
379 memset(&dummy, 0, sizeof(dummy)); 457 mutate_byte(&p->uv);
380 458 mutate_byte(&p->up);
381 dummy.type = 1; /* rsa */ 459 mutate_byte(&p->u2f);
382 dummy.ext = FIDO_EXT_HMAC_SECRET; 460 mutate_byte(&p->type);
383 461 mutate_byte(&p->cred_count);
384 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 462 mutate_int(&p->ext);
385 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); 463 mutate_blob(&p->rs256);
386 464 mutate_blob(&p->es256);
387 dummy.cred.len = sizeof(dummy_cdh); /* XXX */ 465 mutate_blob(&p->eddsa);
388 dummy.cdh.len = sizeof(dummy_cdh); 466 mutate_blob(&p->cred);
389 dummy.es256.len = sizeof(dummy_es256); 467 mutate_blob(&p->cdh);
390 dummy.rs256.len = sizeof(dummy_rs256); 468 mutate_string(p->rp_id);
391 dummy.eddsa.len = sizeof(dummy_eddsa); 469 mutate_string(p->pin);
392 dummy.wire_data.len = sizeof(dummy_wire_data_fido);
393
394 memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */
395 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
396 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
397 dummy.wire_data.len);
398 memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len);
399 memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len);
400 memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len);
401
402 blob_len = pack(blob, sizeof(blob), &dummy);
403 assert(blob_len != 0);
404
405 if (blob_len > len) {
406 memcpy(ptr, blob, len);
407 return (len);
408 } 470 }
409 471
410 memcpy(ptr, blob, blob_len); 472 if (flags & MUTATE_WIREDATA) {
411 473 if (p->u2f & 1) {
412 return (blob_len); 474 p->wire_data.len = sizeof(dummy_wire_data_u2f);
413} 475 memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
414 476 p->wire_data.len);
415size_t 477 } else {
416LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 478 p->wire_data.len = sizeof(dummy_wire_data_fido);
417 unsigned int seed) NO_MSAN 479 memcpy(&p->wire_data.body, &dummy_wire_data_fido,
418{ 480 p->wire_data.len);
419 struct param p; 481 }
420 uint8_t blob[16384]; 482 mutate_blob(&p->wire_data);
421 size_t blob_len;
422
423 (void)seed;
424
425 memset(&p, 0, sizeof(p));
426
427 if (unpack(data, size, &p) < 0)
428 return (pack_dummy(data, maxsize));
429
430 mutate_byte(&p.uv);
431 mutate_byte(&p.up);
432 mutate_byte(&p.u2f);
433 mutate_byte(&p.type);
434 mutate_byte(&p.cred_count);
435
436 mutate_int(&p.ext);
437 p.seed = (int)seed;
438
439 if (p.u2f & 1) {
440 p.wire_data.len = sizeof(dummy_wire_data_u2f);
441 memcpy(&p.wire_data.body, &dummy_wire_data_u2f,
442 p.wire_data.len);
443 } else {
444 p.wire_data.len = sizeof(dummy_wire_data_fido);
445 memcpy(&p.wire_data.body, &dummy_wire_data_fido,
446 p.wire_data.len);
447 } 483 }
448
449 mutate_blob(&p.wire_data);
450 mutate_blob(&p.rs256);
451 mutate_blob(&p.es256);
452 mutate_blob(&p.eddsa);
453 mutate_blob(&p.cred);
454 mutate_blob(&p.cdh);
455
456 mutate_string(p.rp_id);
457 mutate_string(p.pin);
458
459 blob_len = pack(blob, sizeof(blob), &p);
460
461 if (blob_len == 0 || blob_len > maxsize)
462 return (0);
463
464 memcpy(data, blob, blob_len);
465
466 return (blob_len);
467} 484}
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 @@
19 19
20#include "../openbsd-compat/openbsd-compat.h" 20#include "../openbsd-compat/openbsd-compat.h"
21 21
22#define TAG_PIN 0x01
23#define TAG_NAME 0x02
24#define TAG_SEED 0x03
25#define TAG_ID 0x04
26#define TAG_INFO_WIRE_DATA 0x05
27#define TAG_ENROLL_WIRE_DATA 0x06
28#define TAG_LIST_WIRE_DATA 0x07
29#define TAG_SET_NAME_WIRE_DATA 0x08
30#define TAG_REMOVE_WIRE_DATA 0x09
31
32/* Parameter set defining a FIDO2 credential management operation. */ 22/* Parameter set defining a FIDO2 credential management operation. */
33struct param { 23struct param {
34 char pin[MAXSTR]; 24 char pin[MAXSTR];
35 char name[MAXSTR]; 25 char name[MAXSTR];
36 int seed; 26 int seed;
37 struct blob id; 27 struct blob id;
38 struct blob info_wire_data; 28 struct blob info_wire_data;
39 struct blob enroll_wire_data; 29 struct blob enroll_wire_data;
40 struct blob list_wire_data; 30 struct blob list_wire_data;
41 struct blob set_name_wire_data; 31 struct blob set_name_wire_data;
42 struct blob remove_wire_data; 32 struct blob remove_wire_data;
43}; 33};
44 34
45/* 35/*
@@ -100,58 +90,141 @@ static const uint8_t dummy_remove_wire_data[] = {
100 WIREDATA_CTAP_CBOR_STATUS, 90 WIREDATA_CTAP_CBOR_STATUS,
101}; 91};
102 92
103int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 93struct param *
104size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 94unpack(const uint8_t *ptr, size_t len)
105
106static int
107unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
108{ 95{
109 uint8_t **pp = (void *)&ptr; 96 cbor_item_t *item = NULL, **v;
110 97 struct cbor_load_result cbor;
111 if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 98 struct param *p;
112 unpack_string(TAG_NAME, pp, &len, p->name) < 0 || 99 int ok = -1;
113 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 100
114 unpack_blob(TAG_ID, pp, &len, &p->id) < 0 || 101 if ((p = calloc(1, sizeof(*p))) == NULL ||
115 unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || 102 (item = cbor_load(ptr, len, &cbor)) == NULL ||
116 unpack_blob(TAG_ENROLL_WIRE_DATA, pp, &len, &p->enroll_wire_data) < 0 || 103 cbor.read != len ||
117 unpack_blob(TAG_LIST_WIRE_DATA, pp, &len, &p->list_wire_data) < 0 || 104 cbor_isa_array(item) == false ||
118 unpack_blob(TAG_SET_NAME_WIRE_DATA, pp, &len, &p->set_name_wire_data) < 0 || 105 cbor_array_is_definite(item) == false ||
119 unpack_blob(TAG_REMOVE_WIRE_DATA, pp, &len, &p->remove_wire_data) < 0) 106 cbor_array_size(item) != 9 ||
120 return (-1); 107 (v = cbor_array_handle(item)) == NULL)
121 108 goto fail;
122 return (0); 109
110 if (unpack_int(v[0], &p->seed) < 0 ||
111 unpack_string(v[1], p->pin) < 0 ||
112 unpack_string(v[2], p->name) < 0 ||
113 unpack_blob(v[3], &p->id) < 0 ||
114 unpack_blob(v[4], &p->info_wire_data) < 0 ||
115 unpack_blob(v[5], &p->enroll_wire_data) < 0 ||
116 unpack_blob(v[6], &p->list_wire_data) < 0 ||
117 unpack_blob(v[7], &p->set_name_wire_data) < 0 ||
118 unpack_blob(v[8], &p->remove_wire_data) < 0)
119 goto fail;
120
121 ok = 0;
122fail:
123 if (ok < 0) {
124 free(p);
125 p = NULL;
126 }
127
128 if (item)
129 cbor_decref(&item);
130
131 return p;
123} 132}
124 133
125static size_t 134size_t
126pack(uint8_t *ptr, size_t len, const struct param *p) 135pack(uint8_t *ptr, size_t len, const struct param *p)
127{ 136{
128 const size_t max = len; 137 cbor_item_t *argv[9], *array = NULL;
129 138 size_t cbor_alloc_len, cbor_len = 0;
130 if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 139 unsigned char *cbor = NULL;
131 pack_string(TAG_NAME, &ptr, &len, p->name) < 0 || 140
132 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 141 memset(argv, 0, sizeof(argv));
133 pack_blob(TAG_ID, &ptr, &len, &p->id) < 0 || 142
134 pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || 143 if ((array = cbor_new_definite_array(9)) == NULL ||
135 pack_blob(TAG_ENROLL_WIRE_DATA, &ptr, &len, &p->enroll_wire_data) < 0 || 144 (argv[0] = pack_int(p->seed)) == NULL ||
136 pack_blob(TAG_LIST_WIRE_DATA, &ptr, &len, &p->list_wire_data) < 0 || 145 (argv[1] = pack_string(p->pin)) == NULL ||
137 pack_blob(TAG_SET_NAME_WIRE_DATA, &ptr, &len, &p->set_name_wire_data) < 0 || 146 (argv[2] = pack_string(p->name)) == NULL ||
138 pack_blob(TAG_REMOVE_WIRE_DATA, &ptr, &len, &p->remove_wire_data) < 0) 147 (argv[3] = pack_blob(&p->id)) == NULL ||
139 return (0); 148 (argv[4] = pack_blob(&p->info_wire_data)) == NULL ||
140 149 (argv[5] = pack_blob(&p->enroll_wire_data)) == NULL ||
141 return (max - len); 150 (argv[6] = pack_blob(&p->list_wire_data)) == NULL ||
151 (argv[7] = pack_blob(&p->set_name_wire_data)) == NULL ||
152 (argv[8] = pack_blob(&p->remove_wire_data)) == NULL)
153 goto fail;
154
155 for (size_t i = 0; i < 9; i++)
156 if (cbor_array_push(array, argv[i]) == false)
157 goto fail;
158
159 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
160 &cbor_alloc_len)) > len) {
161 cbor_len = 0;
162 goto fail;
163 }
164
165 memcpy(ptr, cbor, cbor_len);
166fail:
167 for (size_t i = 0; i < 9; i++)
168 if (argv[i])
169 cbor_decref(&argv[i]);
170
171 if (array)
172 cbor_decref(&array);
173
174 free(cbor);
175
176 return cbor_len;
142} 177}
143 178
144static size_t 179size_t
145input_len(int max) 180pack_dummy(uint8_t *ptr, size_t len)
146{ 181{
147 return (2 * len_string(max) + len_int() + 6 * len_blob(max)); 182 struct param dummy;
183 uint8_t blob[4096];
184 size_t blob_len;
185
186 memset(&dummy, 0, sizeof(dummy));
187
188 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
189 strlcpy(dummy.name, dummy_name, sizeof(dummy.name));
190
191 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
192 dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data);
193 dummy.list_wire_data.len = sizeof(dummy_list_wire_data);
194 dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data);
195 dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data);
196 dummy.id.len = sizeof(dummy_id);
197
198 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
199 dummy.info_wire_data.len);
200 memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data,
201 dummy.enroll_wire_data.len);
202 memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data,
203 dummy.list_wire_data.len);
204 memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data,
205 dummy.set_name_wire_data.len);
206 memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data,
207 dummy.remove_wire_data.len);
208 memcpy(&dummy.id.body, &dummy_id, dummy.id.len);
209
210 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
211
212 if (blob_len > len) {
213 memcpy(ptr, blob, len);
214 return len;
215 }
216
217 memcpy(ptr, blob, blob_len);
218
219 return blob_len;
148} 220}
149 221
150static fido_dev_t * 222static fido_dev_t *
151prepare_dev() 223prepare_dev(void)
152{ 224{
153 fido_dev_t *dev; 225 fido_dev_t *dev;
154 fido_dev_io_t io; 226 fido_dev_io_t io;
227 bool x;
155 228
156 memset(&io, 0, sizeof(io)); 229 memset(&io, 0, sizeof(io));
157 230
@@ -163,26 +236,35 @@ prepare_dev()
163 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 236 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
164 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 237 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
165 fido_dev_free(&dev); 238 fido_dev_free(&dev);
166 return (NULL); 239 return NULL;
167 } 240 }
168 241
169 return (dev); 242 x = fido_dev_is_fido2(dev);
243 consume(&x, sizeof(x));
244 x = fido_dev_supports_pin(dev);
245 consume(&x, sizeof(x));
246 x = fido_dev_has_pin(dev);
247 consume(&x, sizeof(x));
248
249 return dev;
170} 250}
171 251
172static void 252static void
173get_info(struct param *p) 253get_info(const struct param *p)
174{ 254{
175 fido_dev_t *dev = NULL; 255 fido_dev_t *dev = NULL;
176 fido_bio_info_t *i = NULL; 256 fido_bio_info_t *i = NULL;
177 uint8_t type; 257 uint8_t type;
178 uint8_t max_samples; 258 uint8_t max_samples;
259 int r;
179 260
180 set_wire_data(p->info_wire_data.body, p->info_wire_data.len); 261 set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
181 262
182 if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) 263 if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL)
183 goto done; 264 goto done;
184 265
185 fido_bio_dev_get_info(dev, i); 266 r = fido_bio_dev_get_info(dev, i);
267 consume_str(fido_strerr(r));
186 268
187 type = fido_bio_info_type(i); 269 type = fido_bio_info_type(i);
188 max_samples = fido_bio_info_max_samples(i); 270 max_samples = fido_bio_info_max_samples(i);
@@ -217,7 +299,7 @@ consume_enroll(fido_bio_enroll_t *e)
217} 299}
218 300
219static void 301static void
220enroll(struct param *p) 302enroll(const struct param *p)
221{ 303{
222 fido_dev_t *dev = NULL; 304 fido_dev_t *dev = NULL;
223 fido_bio_template_t *t = NULL; 305 fido_bio_template_t *t = NULL;
@@ -252,7 +334,7 @@ done:
252} 334}
253 335
254static void 336static void
255list(struct param *p) 337list(const struct param *p)
256{ 338{
257 fido_dev_t *dev = NULL; 339 fido_dev_t *dev = NULL;
258 fido_bio_template_array_t *ta = NULL; 340 fido_bio_template_array_t *ta = NULL;
@@ -280,7 +362,7 @@ done:
280} 362}
281 363
282static void 364static void
283set_name(struct param *p) 365set_name(const struct param *p)
284{ 366{
285 fido_dev_t *dev = NULL; 367 fido_dev_t *dev = NULL;
286 fido_bio_template_t *t = NULL; 368 fido_bio_template_t *t = NULL;
@@ -306,10 +388,11 @@ done:
306} 388}
307 389
308static void 390static void
309del(struct param *p) 391del(const struct param *p)
310{ 392{
311 fido_dev_t *dev = NULL; 393 fido_dev_t *dev = NULL;
312 fido_bio_template_t *t = NULL; 394 fido_bio_template_t *t = NULL;
395 int r;
313 396
314 set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); 397 set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len);
315 398
@@ -317,8 +400,9 @@ del(struct param *p)
317 (t = fido_bio_template_new()) == NULL) 400 (t = fido_bio_template_new()) == NULL)
318 goto done; 401 goto done;
319 402
320 fido_bio_template_set_id(t, p->id.body, p->id.len); 403 r = fido_bio_template_set_id(t, p->id.body, p->id.len);
321 consume_template(t); 404 consume_template(t);
405 consume_str(fido_strerr(r));
322 406
323 fido_bio_dev_enroll_remove(dev, t, p->pin); 407 fido_bio_dev_enroll_remove(dev, t, p->pin);
324 408
@@ -330,106 +414,37 @@ done:
330 fido_bio_template_free(&t); 414 fido_bio_template_free(&t);
331} 415}
332 416
333int 417void
334LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 418test(const struct param *p)
335{ 419{
336 struct param p; 420 prng_init((unsigned int)p->seed);
337
338 memset(&p, 0, sizeof(p));
339
340 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
341 unpack(data, size, &p) < 0)
342 return (0);
343
344 prng_init((unsigned int)p.seed);
345
346 fido_init(FIDO_DEBUG); 421 fido_init(FIDO_DEBUG);
347 fido_set_log_handler(consume_str); 422 fido_set_log_handler(consume_str);
348 423
349 get_info(&p); 424 get_info(p);
350 enroll(&p); 425 enroll(p);
351 list(&p); 426 list(p);
352 set_name(&p); 427 set_name(p);
353 del(&p); 428 del(p);
354
355 return (0);
356} 429}
357 430
358static size_t 431void
359pack_dummy(uint8_t *ptr, size_t len) 432mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
360{ 433{
361 struct param dummy; 434 if (flags & MUTATE_SEED)
362 uint8_t blob[32768]; 435 p->seed = (int)seed;
363 size_t blob_len;
364
365 memset(&dummy, 0, sizeof(dummy));
366
367 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
368 strlcpy(dummy.name, dummy_name, sizeof(dummy.name));
369
370 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
371 dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data);
372 dummy.list_wire_data.len = sizeof(dummy_list_wire_data);
373 dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data);
374 dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data);
375 dummy.id.len = sizeof(dummy_id);
376
377 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
378 dummy.info_wire_data.len);
379 memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data,
380 dummy.enroll_wire_data.len);
381 memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data,
382 dummy.list_wire_data.len);
383 memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data,
384 dummy.set_name_wire_data.len);
385 memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data,
386 dummy.remove_wire_data.len);
387 memcpy(&dummy.id.body, &dummy_id, dummy.id.len);
388
389 blob_len = pack(blob, sizeof(blob), &dummy);
390 assert(blob_len != 0);
391 436
392 if (blob_len > len) { 437 if (flags & MUTATE_PARAM) {
393 memcpy(ptr, blob, len); 438 mutate_blob(&p->id);
394 return (len); 439 mutate_string(p->pin);
440 mutate_string(p->name);
395 } 441 }
396 442
397 memcpy(ptr, blob, blob_len); 443 if (flags & MUTATE_WIREDATA) {
398 444 mutate_blob(&p->info_wire_data);
399 return (blob_len); 445 mutate_blob(&p->enroll_wire_data);
400} 446 mutate_blob(&p->list_wire_data);
401 447 mutate_blob(&p->set_name_wire_data);
402size_t 448 mutate_blob(&p->remove_wire_data);
403LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 449 }
404 unsigned int seed) NO_MSAN
405{
406 struct param p;
407 uint8_t blob[16384];
408 size_t blob_len;
409
410 memset(&p, 0, sizeof(p));
411
412 if (unpack(data, size, &p) < 0)
413 return (pack_dummy(data, maxsize));
414
415 p.seed = (int)seed;
416
417 mutate_blob(&p.id);
418 mutate_blob(&p.info_wire_data);
419 mutate_blob(&p.enroll_wire_data);
420 mutate_blob(&p.list_wire_data);
421 mutate_blob(&p.set_name_wire_data);
422 mutate_blob(&p.remove_wire_data);
423
424 mutate_string(p.pin);
425 mutate_string(p.name);
426
427 blob_len = pack(blob, sizeof(blob), &p);
428
429 if (blob_len == 0 || blob_len > maxsize)
430 return (0);
431
432 memcpy(data, blob, blob_len);
433
434 return (blob_len);
435} 450}
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 @@
18 18
19#include "../openbsd-compat/openbsd-compat.h" 19#include "../openbsd-compat/openbsd-compat.h"
20 20
21#define TAG_U2F 0x01
22#define TAG_TYPE 0x02
23#define TAG_CDH 0x03
24#define TAG_RP_ID 0x04
25#define TAG_RP_NAME 0x05
26#define TAG_USER_ID 0x06
27#define TAG_USER_NAME 0x07
28#define TAG_USER_NICK 0x08
29#define TAG_USER_ICON 0x09
30#define TAG_EXT 0x0a
31#define TAG_SEED 0x0b
32#define TAG_RK 0x0c
33#define TAG_UV 0x0d
34#define TAG_PIN 0x0e
35#define TAG_WIRE_DATA 0x0f
36#define TAG_EXCL_COUNT 0x10
37#define TAG_EXCL_CRED 0x11
38
39/* Parameter set defining a FIDO2 make credential operation. */ 21/* Parameter set defining a FIDO2 make credential operation. */
40struct param { 22struct param {
41 char pin[MAXSTR]; 23 char pin[MAXSTR];
42 char rp_id[MAXSTR]; 24 char rp_id[MAXSTR];
43 char rp_name[MAXSTR]; 25 char rp_name[MAXSTR];
44 char user_icon[MAXSTR]; 26 char user_icon[MAXSTR];
45 char user_name[MAXSTR]; 27 char user_name[MAXSTR];
46 char user_nick[MAXSTR]; 28 char user_nick[MAXSTR];
47 int ext; 29 int ext;
48 int seed; 30 int seed;
49 struct blob cdh; 31 struct blob cdh;
50 struct blob excl_cred; 32 struct blob excl_cred;
51 struct blob user_id; 33 struct blob user_id;
52 struct blob wire_data; 34 struct blob wire_data;
53 uint8_t excl_count; 35 uint8_t excl_count;
54 uint8_t rk; 36 uint8_t rk;
55 uint8_t type; 37 uint8_t type;
56 uint8_t u2f; 38 uint8_t u2f;
57 uint8_t uv; 39 uint8_t uv;
58}; 40};
59 41
60/* 42/*
@@ -86,79 +68,157 @@ static const uint8_t dummy_wire_data_u2f[] = {
86 WIREDATA_CTAP_U2F_REGISTER, 68 WIREDATA_CTAP_U2F_REGISTER,
87}; 69};
88 70
89int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 71struct param *
90size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 72unpack(const uint8_t *ptr, size_t len)
91
92static int
93unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
94{ 73{
95 uint8_t **pp = (void *)&ptr; 74 cbor_item_t *item = NULL, **v;
96 75 struct cbor_load_result cbor;
97 if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || 76 struct param *p;
98 unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || 77 int ok = -1;
99 unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || 78
100 unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || 79 if ((p = calloc(1, sizeof(*p))) == NULL ||
101 unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || 80 (item = cbor_load(ptr, len, &cbor)) == NULL ||
102 unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 81 cbor.read != len ||
103 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 82 cbor_isa_array(item) == false ||
104 unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || 83 cbor_array_is_definite(item) == false ||
105 unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || 84 cbor_array_size(item) != 17 ||
106 unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || 85 (v = cbor_array_handle(item)) == NULL)
107 unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || 86 goto fail;
108 unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || 87
109 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 88 if (unpack_byte(v[0], &p->rk) < 0 ||
110 unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || 89 unpack_byte(v[1], &p->type) < 0 ||
111 unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || 90 unpack_byte(v[2], &p->u2f) < 0 ||
112 unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || 91 unpack_byte(v[3], &p->uv) < 0 ||
113 unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) 92 unpack_byte(v[4], &p->excl_count) < 0 ||
114 return (-1); 93 unpack_int(v[5], &p->ext) < 0 ||
115 94 unpack_int(v[6], &p->seed) < 0 ||
116 return (0); 95 unpack_string(v[7], p->pin) < 0 ||
96 unpack_string(v[8], p->rp_id) < 0 ||
97 unpack_string(v[9], p->rp_name) < 0 ||
98 unpack_string(v[10], p->user_icon) < 0 ||
99 unpack_string(v[11], p->user_name) < 0 ||
100 unpack_string(v[12], p->user_nick) < 0 ||
101 unpack_blob(v[13], &p->cdh) < 0 ||
102 unpack_blob(v[14], &p->user_id) < 0 ||
103 unpack_blob(v[15], &p->wire_data) < 0 ||
104 unpack_blob(v[16], &p->excl_cred) < 0)
105 goto fail;
106
107 ok = 0;
108fail:
109 if (ok < 0) {
110 free(p);
111 p = NULL;
112 }
113
114 if (item)
115 cbor_decref(&item);
116
117 return p;
117} 118}
118 119
119static size_t 120size_t
120pack(uint8_t *ptr, size_t len, const struct param *p) 121pack(uint8_t *ptr, size_t len, const struct param *p)
121{ 122{
122 const size_t max = len; 123 cbor_item_t *argv[17], *array = NULL;
123 124 size_t cbor_alloc_len, cbor_len = 0;
124 if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || 125 unsigned char *cbor = NULL;
125 pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || 126
126 pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || 127 memset(argv, 0, sizeof(argv));
127 pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || 128
128 pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || 129 if ((array = cbor_new_definite_array(17)) == NULL ||
129 pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 130 (argv[0] = pack_byte(p->rk)) == NULL ||
130 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 131 (argv[1] = pack_byte(p->type)) == NULL ||
131 pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || 132 (argv[2] = pack_byte(p->u2f)) == NULL ||
132 pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || 133 (argv[3] = pack_byte(p->uv)) == NULL ||
133 pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || 134 (argv[4] = pack_byte(p->excl_count)) == NULL ||
134 pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || 135 (argv[5] = pack_int(p->ext)) == NULL ||
135 pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || 136 (argv[6] = pack_int(p->seed)) == NULL ||
136 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 137 (argv[7] = pack_string(p->pin)) == NULL ||
137 pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || 138 (argv[8] = pack_string(p->rp_id)) == NULL ||
138 pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || 139 (argv[9] = pack_string(p->rp_name)) == NULL ||
139 pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || 140 (argv[10] = pack_string(p->user_icon)) == NULL ||
140 pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) 141 (argv[11] = pack_string(p->user_name)) == NULL ||
141 return (0); 142 (argv[12] = pack_string(p->user_nick)) == NULL ||
142 143 (argv[13] = pack_blob(&p->cdh)) == NULL ||
143 return (max - len); 144 (argv[14] = pack_blob(&p->user_id)) == NULL ||
145 (argv[15] = pack_blob(&p->wire_data)) == NULL ||
146 (argv[16] = pack_blob(&p->excl_cred)) == NULL)
147 goto fail;
148
149 for (size_t i = 0; i < 17; i++)
150 if (cbor_array_push(array, argv[i]) == false)
151 goto fail;
152
153 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
154 &cbor_alloc_len)) > len) {
155 cbor_len = 0;
156 goto fail;
157 }
158
159 memcpy(ptr, cbor, cbor_len);
160fail:
161 for (size_t i = 0; i < 17; i++)
162 if (argv[i])
163 cbor_decref(&argv[i]);
164
165 if (array)
166 cbor_decref(&array);
167
168 free(cbor);
169
170 return cbor_len;
144} 171}
145 172
146static size_t 173size_t
147input_len(int max) 174pack_dummy(uint8_t *ptr, size_t len)
148{ 175{
149 return (5 * len_byte() + 6 * len_string(max) + 2 * len_int() + 176 struct param dummy;
150 4 * len_blob(max)); 177 uint8_t blob[4096];
178 size_t blob_len;
179
180 memset(&dummy, 0, sizeof(dummy));
181
182 dummy.type = 1;
183 dummy.ext = FIDO_EXT_HMAC_SECRET;
184
185 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
186 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
187 strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));
188 strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));
189 strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));
190 strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));
191
192 dummy.cdh.len = sizeof(dummy_cdh);
193 dummy.user_id.len = sizeof(dummy_user_id);
194 dummy.wire_data.len = sizeof(dummy_wire_data_fido);
195
196 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
197 memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len);
198 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
199 dummy.wire_data.len);
200
201 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
202
203 if (blob_len > len) {
204 memcpy(ptr, blob, len);
205 return len;
206 }
207
208 memcpy(ptr, blob, blob_len);
209
210 return blob_len;
151} 211}
152 212
153static void 213static void
154make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, 214make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
155 const char *rp_id, const char *rp_name, struct blob *user_id, 215 const char *rp_id, const char *rp_name, const struct blob *user_id,
156 const char *user_name, const char *user_nick, const char *user_icon, 216 const char *user_name, const char *user_nick, const char *user_icon,
157 int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, 217 int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count,
158 struct blob *excl_cred) 218 const struct blob *excl_cred)
159{ 219{
160 fido_dev_t *dev; 220 fido_dev_t *dev;
161 fido_dev_io_t io; 221 fido_dev_io_t io;
162 222
163 memset(&io, 0, sizeof(io)); 223 memset(&io, 0, sizeof(io));
164 224
@@ -185,6 +245,7 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
185 fido_cred_set_user(cred, user_id->body, user_id->len, user_name, 245 fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
186 user_nick, user_icon); 246 user_nick, user_icon);
187 fido_cred_set_extensions(cred, ext); 247 fido_cred_set_extensions(cred, ext);
248
188 if (rk & 1) 249 if (rk & 1)
189 fido_cred_set_rk(cred, FIDO_OPT_TRUE); 250 fido_cred_set_rk(cred, FIDO_OPT_TRUE);
190 if (uv & 1) 251 if (uv & 1)
@@ -192,6 +253,16 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
192 if (user_id->len) 253 if (user_id->len)
193 fido_cred_set_prot(cred, user_id->body[0] & 0x03); 254 fido_cred_set_prot(cred, user_id->body[0] & 0x03);
194 255
256 /* repeat memory operations to trigger reallocation paths */
257 fido_cred_set_type(cred, type);
258 fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);
259 fido_cred_set_rp(cred, rp_id, rp_name);
260 fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
261 user_nick, user_icon);
262
263 if (strlen(pin) == 0)
264 pin = NULL;
265
195 fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); 266 fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin);
196 267
197 fido_dev_cancel(dev); 268 fido_dev_cancel(dev);
@@ -206,8 +277,8 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
206 const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, 277 const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,
207 size_t sig_len, const char *fmt, int prot) 278 size_t sig_len, const char *fmt, int prot)
208{ 279{
209 fido_cred_t *cred; 280 fido_cred_t *cred;
210 uint8_t flags; 281 uint8_t flags;
211 282
212 if ((cred = fido_cred_new()) == NULL) 283 if ((cred = fido_cred_new()) == NULL)
213 return; 284 return;
@@ -229,11 +300,18 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
229 if (fmt) 300 if (fmt)
230 fido_cred_set_fmt(cred, fmt); 301 fido_cred_set_fmt(cred, fmt);
231 302
232 fido_cred_verify(cred); 303 /* repeat memory operations to trigger reallocation paths */
233 fido_cred_verify_self(cred); 304 if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
305 fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len);
306 fido_cred_set_x509(cred, x5c_ptr, x5c_len);
307 fido_cred_set_sig(cred, sig_ptr, sig_len);
308
309 assert(fido_cred_verify(cred) != FIDO_OK);
310 assert(fido_cred_verify_self(cred) != FIDO_OK);
234 311
235 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); 312 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
236 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 313 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
314 consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred));
237 consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); 315 consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred));
238 consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); 316 consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred)));
239 consume(fido_cred_display_name(cred), 317 consume(fido_cred_display_name(cred),
@@ -247,30 +325,16 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
247 fido_cred_free(&cred); 325 fido_cred_free(&cred);
248} 326}
249 327
250int 328static void
251LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 329test_cred(const struct param *p)
252{ 330{
253 struct param p; 331 fido_cred_t *cred = NULL;
254 fido_cred_t *cred = NULL; 332 int cose_alg = 0;
255 int cose_alg = 0;
256
257 memset(&p, 0, sizeof(p));
258
259 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
260 unpack(data, size, &p) < 0)
261 return (0);
262
263 prng_init((unsigned int)p.seed);
264
265 fido_init(FIDO_DEBUG);
266 fido_set_log_handler(consume_str);
267 333
268 if ((cred = fido_cred_new()) == NULL) 334 if ((cred = fido_cred_new()) == NULL)
269 return (0); 335 return;
270
271 set_wire_data(p.wire_data.body, p.wire_data.len);
272 336
273 switch (p.type & 3) { 337 switch (p->type & 3) {
274 case 0: 338 case 0:
275 cose_alg = COSE_ES256; 339 cose_alg = COSE_ES256;
276 break; 340 break;
@@ -282,116 +346,106 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
282 break; 346 break;
283 } 347 }
284 348
285 make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name, 349 set_wire_data(p->wire_data.body, p->wire_data.len);
286 &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk, 350
287 p.uv, p.pin, p.excl_count, &p.excl_cred); 351 make_cred(cred, p->u2f, cose_alg, &p->cdh, p->rp_id, p->rp_name,
352 &p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext,
353 p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred);
288 354
289 verify_cred(cose_alg, 355 verify_cred(cose_alg,
290 fido_cred_clientdata_hash_ptr(cred), 356 fido_cred_clientdata_hash_ptr(cred),
291 fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), 357 fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred),
292 fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), 358 fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred),
293 fido_cred_authdata_len(cred), p.ext, p.rk, p.uv, 359 fido_cred_authdata_len(cred), p->ext, p->rk, p->uv,
294 fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), 360 fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),
295 fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), 361 fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
296 fido_cred_fmt(cred), fido_cred_prot(cred)); 362 fido_cred_fmt(cred), fido_cred_prot(cred));
297 363
298 fido_cred_free(&cred); 364 fido_cred_free(&cred);
299
300 return (0);
301} 365}
302 366
303static size_t 367static void
304pack_dummy(uint8_t *ptr, size_t len) 368test_touch(const struct param *p)
305{ 369{
306 struct param dummy; 370 fido_dev_t *dev;
307 uint8_t blob[16384]; 371 fido_dev_io_t io;
308 size_t blob_len; 372 int r;
373 int touched;
309 374
310 memset(&dummy, 0, sizeof(dummy)); 375 memset(&io, 0, sizeof(io));
311 376
312 dummy.type = 1; 377 io.open = dev_open;
313 dummy.ext = FIDO_EXT_HMAC_SECRET; 378 io.close = dev_close;
379 io.read = dev_read;
380 io.write = dev_write;
314 381
315 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 382 set_wire_data(p->wire_data.body, p->wire_data.len);
316 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
317 strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));
318 strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));
319 strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));
320 strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));
321 383
322 dummy.cdh.len = sizeof(dummy_cdh); 384 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
323 dummy.user_id.len = sizeof(dummy_user_id); 385 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
324 dummy.wire_data.len = sizeof(dummy_wire_data_fido); 386 fido_dev_free(&dev);
387 return;
388 }
325 389
326 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); 390 if (p->u2f & 1)
327 memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); 391 fido_dev_force_u2f(dev);
328 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
329 dummy.wire_data.len);
330 392
331 blob_len = pack(blob, sizeof(blob), &dummy); 393 r = fido_dev_get_touch_begin(dev);
332 assert(blob_len != 0); 394 consume_str(fido_strerr(r));
395 r = fido_dev_get_touch_status(dev, &touched, -1);
396 consume_str(fido_strerr(r));
397 consume(&touched, sizeof(touched));
333 398
334 if (blob_len > len) { 399 fido_dev_cancel(dev);
335 memcpy(ptr, blob, len); 400 fido_dev_close(dev);
336 return (len); 401 fido_dev_free(&dev);
337 } 402}
338 403
339 memcpy(ptr, blob, blob_len); 404void
405test(const struct param *p)
406{
407 prng_init((unsigned int)p->seed);
408 fido_init(FIDO_DEBUG);
409 fido_set_log_handler(consume_str);
340 410
341 return (blob_len); 411 test_cred(p);
412 test_touch(p);
342} 413}
343 414
344size_t 415void
345LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 416mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
346 unsigned int seed) NO_MSAN
347{ 417{
348 struct param p; 418 if (flags & MUTATE_SEED)
349 uint8_t blob[16384]; 419 p->seed = (int)seed;
350 size_t blob_len; 420
351 421 if (flags & MUTATE_PARAM) {
352 memset(&p, 0, sizeof(p)); 422 mutate_byte(&p->rk);
353 423 mutate_byte(&p->type);
354 if (unpack(data, size, &p) < 0) 424 mutate_byte(&p->u2f);
355 return (pack_dummy(data, maxsize)); 425 mutate_byte(&p->uv);
356 426 mutate_byte(&p->excl_count);
357 mutate_byte(&p.rk); 427 mutate_int(&p->ext);
358 mutate_byte(&p.type); 428 mutate_blob(&p->cdh);
359 mutate_byte(&p.u2f); 429 mutate_blob(&p->user_id);
360 mutate_byte(&p.uv); 430 mutate_blob(&p->excl_cred);
361 mutate_byte(&p.excl_count); 431 mutate_string(p->pin);
362 432 mutate_string(p->user_icon);
363 mutate_int(&p.ext); 433 mutate_string(p->user_name);
364 p.seed = (int)seed; 434 mutate_string(p->user_nick);
365 435 mutate_string(p->rp_id);
366 mutate_blob(&p.cdh); 436 mutate_string(p->rp_name);
367 mutate_blob(&p.user_id);
368
369 if (p.u2f & 1) {
370 p.wire_data.len = sizeof(dummy_wire_data_u2f);
371 memcpy(&p.wire_data.body, &dummy_wire_data_u2f,
372 p.wire_data.len);
373 } else {
374 p.wire_data.len = sizeof(dummy_wire_data_fido);
375 memcpy(&p.wire_data.body, &dummy_wire_data_fido,
376 p.wire_data.len);
377 } 437 }
378 438
379 mutate_blob(&p.wire_data); 439 if (flags & MUTATE_WIREDATA) {
380 mutate_blob(&p.excl_cred); 440 if (p->u2f & 1) {
381 441 p->wire_data.len = sizeof(dummy_wire_data_u2f);
382 mutate_string(p.pin); 442 memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
383 mutate_string(p.user_icon); 443 p->wire_data.len);
384 mutate_string(p.user_name); 444 } else {
385 mutate_string(p.user_nick); 445 p->wire_data.len = sizeof(dummy_wire_data_fido);
386 mutate_string(p.rp_id); 446 memcpy(&p->wire_data.body, &dummy_wire_data_fido,
387 mutate_string(p.rp_name); 447 p->wire_data.len);
388 448 }
389 blob_len = pack(blob, sizeof(blob), &p); 449 mutate_blob(&p->wire_data);
390 450 }
391 if (blob_len == 0 || blob_len > maxsize)
392 return (0);
393
394 memcpy(data, blob, blob_len);
395
396 return (blob_len);
397} 451}
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 @@
19 19
20#include "../openbsd-compat/openbsd-compat.h" 20#include "../openbsd-compat/openbsd-compat.h"
21 21
22#define TAG_META_WIRE_DATA 0x01
23#define TAG_RP_WIRE_DATA 0x02
24#define TAG_RK_WIRE_DATA 0x03
25#define TAG_DEL_WIRE_DATA 0x04
26#define TAG_CRED_ID 0x05
27#define TAG_PIN 0x06
28#define TAG_RP_ID 0x07
29#define TAG_SEED 0x08
30
31/* Parameter set defining a FIDO2 credential management operation. */ 22/* Parameter set defining a FIDO2 credential management operation. */
32struct param { 23struct param {
33 char pin[MAXSTR]; 24 char pin[MAXSTR];
34 char rp_id[MAXSTR]; 25 char rp_id[MAXSTR];
35 int seed; 26 int seed;
36 struct blob cred_id; 27 struct blob cred_id;
37 struct blob del_wire_data; 28 struct blob del_wire_data;
38 struct blob meta_wire_data; 29 struct blob meta_wire_data;
39 struct blob rk_wire_data; 30 struct blob rk_wire_data;
40 struct blob rp_wire_data; 31 struct blob rp_wire_data;
41}; 32};
42 33
43/* 34/*
@@ -88,56 +79,136 @@ static const uint8_t dummy_del_wire_data[] = {
88 WIREDATA_CTAP_CBOR_STATUS, 79 WIREDATA_CTAP_CBOR_STATUS,
89}; 80};
90 81
91int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 82struct param *
92size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 83unpack(const uint8_t *ptr, size_t len)
93
94static int
95unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
96{ 84{
97 uint8_t **pp = (void *)&ptr; 85 cbor_item_t *item = NULL, **v;
98 86 struct cbor_load_result cbor;
99 if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 87 struct param *p;
100 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 88 int ok = -1;
101 unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || 89
102 unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || 90 if ((p = calloc(1, sizeof(*p))) == NULL ||
103 unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || 91 (item = cbor_load(ptr, len, &cbor)) == NULL ||
104 unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || 92 cbor.read != len ||
105 unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || 93 cbor_isa_array(item) == false ||
106 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) 94 cbor_array_is_definite(item) == false ||
107 return (-1); 95 cbor_array_size(item) != 8 ||
108 96 (v = cbor_array_handle(item)) == NULL)
109 return (0); 97 goto fail;
98
99 if (unpack_int(v[0], &p->seed) < 0 ||
100 unpack_string(v[1], p->pin) < 0 ||
101 unpack_string(v[2], p->rp_id) < 0 ||
102 unpack_blob(v[3], &p->cred_id) < 0 ||
103 unpack_blob(v[4], &p->meta_wire_data) < 0 ||
104 unpack_blob(v[5], &p->rp_wire_data) < 0 ||
105 unpack_blob(v[6], &p->rk_wire_data) < 0 ||
106 unpack_blob(v[7], &p->del_wire_data) < 0)
107 goto fail;
108
109 ok = 0;
110fail:
111 if (ok < 0) {
112 free(p);
113 p = NULL;
114 }
115
116 if (item)
117 cbor_decref(&item);
118
119 return p;
110} 120}
111 121
112static size_t 122size_t
113pack(uint8_t *ptr, size_t len, const struct param *p) 123pack(uint8_t *ptr, size_t len, const struct param *p)
114{ 124{
115 const size_t max = len; 125 cbor_item_t *argv[8], *array = NULL;
116 126 size_t cbor_alloc_len, cbor_len = 0;
117 if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 127 unsigned char *cbor = NULL;
118 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 128
119 pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || 129 memset(argv, 0, sizeof(argv));
120 pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || 130
121 pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || 131 if ((array = cbor_new_definite_array(8)) == NULL ||
122 pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || 132 (argv[0] = pack_int(p->seed)) == NULL ||
123 pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || 133 (argv[1] = pack_string(p->pin)) == NULL ||
124 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) 134 (argv[2] = pack_string(p->rp_id)) == NULL ||
125 return (0); 135 (argv[3] = pack_blob(&p->cred_id)) == NULL ||
126 136 (argv[4] = pack_blob(&p->meta_wire_data)) == NULL ||
127 return (max - len); 137 (argv[5] = pack_blob(&p->rp_wire_data)) == NULL ||
138 (argv[6] = pack_blob(&p->rk_wire_data)) == NULL ||
139 (argv[7] = pack_blob(&p->del_wire_data)) == NULL)
140 goto fail;
141
142 for (size_t i = 0; i < 8; i++)
143 if (cbor_array_push(array, argv[i]) == false)
144 goto fail;
145
146 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
147 &cbor_alloc_len)) > len) {
148 cbor_len = 0;
149 goto fail;
150 }
151
152 memcpy(ptr, cbor, cbor_len);
153fail:
154 for (size_t i = 0; i < 8; i++)
155 if (argv[i])
156 cbor_decref(&argv[i]);
157
158 if (array)
159 cbor_decref(&array);
160
161 free(cbor);
162
163 return cbor_len;
128} 164}
129 165
130static size_t 166size_t
131input_len(int max) 167pack_dummy(uint8_t *ptr, size_t len)
132{ 168{
133 return (2 * len_string(max) + 5 * len_blob(max) + len_int()); 169 struct param dummy;
170 uint8_t blob[4096];
171 size_t blob_len;
172
173 memset(&dummy, 0, sizeof(dummy));
174
175 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
176 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
177
178 dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data);
179 dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data);
180 dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data);
181 dummy.del_wire_data.len = sizeof(dummy_del_wire_data);
182 dummy.cred_id.len = sizeof(dummy_cred_id);
183
184 memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data,
185 dummy.meta_wire_data.len);
186 memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data,
187 dummy.rp_wire_data.len);
188 memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data,
189 dummy.rk_wire_data.len);
190 memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data,
191 dummy.del_wire_data.len);
192 memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len);
193
194 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
195
196 if (blob_len > len) {
197 memcpy(ptr, blob, len);
198 return len;
199 }
200
201 memcpy(ptr, blob, blob_len);
202
203 return blob_len;
134} 204}
135 205
136static fido_dev_t * 206static fido_dev_t *
137prepare_dev() 207prepare_dev(void)
138{ 208{
139 fido_dev_t *dev; 209 fido_dev_t *dev;
140 fido_dev_io_t io; 210 fido_dev_io_t io;
211 bool x;
141 212
142 memset(&io, 0, sizeof(io)); 213 memset(&io, 0, sizeof(io));
143 214
@@ -149,14 +220,19 @@ prepare_dev()
149 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 220 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
150 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 221 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
151 fido_dev_free(&dev); 222 fido_dev_free(&dev);
152 return (NULL); 223 return NULL;
153 } 224 }
154 225
155 return (dev); 226 x = fido_dev_is_fido2(dev);
227 consume(&x, sizeof(x));
228 x = fido_dev_supports_cred_prot(dev);
229 consume(&x, sizeof(x));
230
231 return dev;
156} 232}
157 233
158static void 234static void
159get_metadata(struct param *p) 235get_metadata(const struct param *p)
160{ 236{
161 fido_dev_t *dev; 237 fido_dev_t *dev;
162 fido_credman_metadata_t *metadata; 238 fido_credman_metadata_t *metadata;
@@ -187,7 +263,7 @@ get_metadata(struct param *p)
187} 263}
188 264
189static void 265static void
190get_rp_list(struct param *p) 266get_rp_list(const struct param *p)
191{ 267{
192 fido_dev_t *dev; 268 fido_dev_t *dev;
193 fido_credman_rp_t *rp; 269 fido_credman_rp_t *rp;
@@ -221,12 +297,12 @@ get_rp_list(struct param *p)
221} 297}
222 298
223static void 299static void
224get_rk_list(struct param *p) 300get_rk_list(const struct param *p)
225{ 301{
226 fido_dev_t *dev; 302 fido_dev_t *dev;
227 fido_credman_rk_t *rk; 303 fido_credman_rk_t *rk;
228 const fido_cred_t *cred; 304 const fido_cred_t *cred;
229 int type; 305 int val;
230 306
231 set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); 307 set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len);
232 308
@@ -247,8 +323,8 @@ get_rk_list(struct param *p)
247 assert(i >= fido_credman_rk_count(rk)); 323 assert(i >= fido_credman_rk_count(rk));
248 continue; 324 continue;
249 } 325 }
250 type = fido_cred_type(cred); 326 val = fido_cred_type(cred);
251 consume(&type, sizeof(type)); 327 consume(&val, sizeof(val));
252 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 328 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
253 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); 329 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
254 consume(fido_cred_user_id_ptr(cred), 330 consume(fido_cred_user_id_ptr(cred),
@@ -257,6 +333,8 @@ get_rk_list(struct param *p)
257 xstrlen(fido_cred_user_name(cred))); 333 xstrlen(fido_cred_user_name(cred)));
258 consume(fido_cred_display_name(cred), 334 consume(fido_cred_display_name(cred),
259 xstrlen(fido_cred_display_name(cred))); 335 xstrlen(fido_cred_display_name(cred)));
336 val = fido_cred_prot(cred);
337 consume(&val, sizeof(val));
260 } 338 }
261 339
262 fido_credman_rk_free(&rk); 340 fido_credman_rk_free(&rk);
@@ -265,7 +343,7 @@ get_rk_list(struct param *p)
265} 343}
266 344
267static void 345static void
268del_rk(struct param *p) 346del_rk(const struct param *p)
269{ 347{
270 fido_dev_t *dev; 348 fido_dev_t *dev;
271 349
@@ -279,101 +357,35 @@ del_rk(struct param *p)
279 fido_dev_free(&dev); 357 fido_dev_free(&dev);
280} 358}
281 359
282int 360void
283LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 361test(const struct param *p)
284{ 362{
285 struct param p; 363 prng_init((unsigned int)p->seed);
286
287 memset(&p, 0, sizeof(p));
288
289 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
290 unpack(data, size, &p) < 0)
291 return (0);
292
293 prng_init((unsigned int)p.seed);
294
295 fido_init(FIDO_DEBUG); 364 fido_init(FIDO_DEBUG);
296 fido_set_log_handler(consume_str); 365 fido_set_log_handler(consume_str);
297 366
298 get_metadata(&p); 367 get_metadata(p);
299 get_rp_list(&p); 368 get_rp_list(p);
300 get_rk_list(&p); 369 get_rk_list(p);
301 del_rk(&p); 370 del_rk(p);
302
303 return (0);
304} 371}
305 372
306static size_t 373void
307pack_dummy(uint8_t *ptr, size_t len) 374mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
308{ 375{
309 struct param dummy; 376 if (flags & MUTATE_SEED)
310 uint8_t blob[32768]; 377 p->seed = (int)seed;
311 size_t blob_len;
312
313 memset(&dummy, 0, sizeof(dummy));
314
315 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
316 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
317 378
318 dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); 379 if (flags & MUTATE_PARAM) {
319 dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); 380 mutate_blob(&p->cred_id);
320 dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); 381 mutate_string(p->pin);
321 dummy.del_wire_data.len = sizeof(dummy_del_wire_data); 382 mutate_string(p->rp_id);
322 dummy.cred_id.len = sizeof(dummy_cred_id);
323
324 memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data,
325 dummy.meta_wire_data.len);
326 memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data,
327 dummy.rp_wire_data.len);
328 memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data,
329 dummy.rk_wire_data.len);
330 memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data,
331 dummy.del_wire_data.len);
332 memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len);
333
334 blob_len = pack(blob, sizeof(blob), &dummy);
335 assert(blob_len != 0);
336
337 if (blob_len > len) {
338 memcpy(ptr, blob, len);
339 return (len);
340 } 383 }
341 384
342 memcpy(ptr, blob, blob_len); 385 if (flags & MUTATE_WIREDATA) {
343 386 mutate_blob(&p->meta_wire_data);
344 return (blob_len); 387 mutate_blob(&p->rp_wire_data);
345} 388 mutate_blob(&p->rk_wire_data);
346 389 mutate_blob(&p->del_wire_data);
347size_t 390 }
348LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
349 unsigned int seed) NO_MSAN
350{
351 struct param p;
352 uint8_t blob[16384];
353 size_t blob_len;
354
355 memset(&p, 0, sizeof(p));
356
357 if (unpack(data, size, &p) < 0)
358 return (pack_dummy(data, maxsize));
359
360 p.seed = (int)seed;
361
362 mutate_blob(&p.cred_id);
363 mutate_blob(&p.meta_wire_data);
364 mutate_blob(&p.rp_wire_data);
365 mutate_blob(&p.rk_wire_data);
366 mutate_blob(&p.del_wire_data);
367
368 mutate_string(p.pin);
369 mutate_string(p.rp_id);
370
371 blob_len = pack(blob, sizeof(blob), &p);
372
373 if (blob_len == 0 || blob_len > maxsize)
374 return (0);
375
376 memcpy(data, blob, blob_len);
377
378 return (blob_len);
379} 391}
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 @@
17 17
18#include "../openbsd-compat/openbsd-compat.h" 18#include "../openbsd-compat/openbsd-compat.h"
19 19
20#define TAG_PIN1 0x01
21#define TAG_PIN2 0x02
22#define TAG_RESET_WIRE_DATA 0x03
23#define TAG_INFO_WIRE_DATA 0x04
24#define TAG_SET_PIN_WIRE_DATA 0x05
25#define TAG_CHANGE_PIN_WIRE_DATA 0x06
26#define TAG_RETRY_WIRE_DATA 0x07
27#define TAG_SEED 0x08
28
29struct param { 20struct param {
30 char pin1[MAXSTR]; 21 char pin1[MAXSTR];
31 char pin2[MAXSTR]; 22 char pin2[MAXSTR];
32 struct blob reset_wire_data; 23 struct blob reset_wire_data;
33 struct blob info_wire_data; 24 struct blob info_wire_data;
34 struct blob set_pin_wire_data; 25 struct blob set_pin_wire_data;
35 struct blob change_pin_wire_data; 26 struct blob change_pin_wire_data;
36 struct blob retry_wire_data; 27 struct blob retry_wire_data;
37 int seed; 28 int seed;
38}; 29};
39 30
40static const uint8_t dummy_reset_wire_data[] = { 31static const uint8_t dummy_reset_wire_data[] = {
@@ -72,56 +63,136 @@ static const uint8_t dummy_retry_wire_data[] = {
72 WIREDATA_CTAP_CBOR_RETRIES, 63 WIREDATA_CTAP_CBOR_RETRIES,
73}; 64};
74 65
75int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 66struct param *
76size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 67unpack(const uint8_t *ptr, size_t len)
77
78static int
79unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
80{ 68{
81 uint8_t **pp = (void *)&ptr; 69 cbor_item_t *item = NULL, **v;
82 70 struct cbor_load_result cbor;
83 if (unpack_string(TAG_PIN1, pp, &len, p->pin1) < 0 || 71 struct param *p;
84 unpack_string(TAG_PIN2, pp, &len, p->pin2) < 0 || 72 int ok = -1;
85 unpack_blob(TAG_RESET_WIRE_DATA, pp, &len, &p->reset_wire_data) < 0 || 73
86 unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || 74 if ((p = calloc(1, sizeof(*p))) == NULL ||
87 unpack_blob(TAG_SET_PIN_WIRE_DATA, pp, &len, &p->set_pin_wire_data) < 0 || 75 (item = cbor_load(ptr, len, &cbor)) == NULL ||
88 unpack_blob(TAG_CHANGE_PIN_WIRE_DATA, pp, &len, &p->change_pin_wire_data) < 0 || 76 cbor.read != len ||
89 unpack_blob(TAG_RETRY_WIRE_DATA, pp, &len, &p->retry_wire_data) < 0 || 77 cbor_isa_array(item) == false ||
90 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) 78 cbor_array_is_definite(item) == false ||
91 return (-1); 79 cbor_array_size(item) != 8 ||
92 80 (v = cbor_array_handle(item)) == NULL)
93 return (0); 81 goto fail;
82
83 if (unpack_int(v[0], &p->seed) < 0 ||
84 unpack_string(v[1], p->pin1) < 0 ||
85 unpack_string(v[2], p->pin2) < 0 ||
86 unpack_blob(v[3], &p->reset_wire_data) < 0 ||
87 unpack_blob(v[4], &p->info_wire_data) < 0 ||
88 unpack_blob(v[5], &p->set_pin_wire_data) < 0 ||
89 unpack_blob(v[6], &p->change_pin_wire_data) < 0 ||
90 unpack_blob(v[7], &p->retry_wire_data) < 0)
91 goto fail;
92
93 ok = 0;
94fail:
95 if (ok < 0) {
96 free(p);
97 p = NULL;
98 }
99
100 if (item)
101 cbor_decref(&item);
102
103 return p;
94} 104}
95 105
96static size_t 106size_t
97pack(uint8_t *ptr, size_t len, const struct param *p) 107pack(uint8_t *ptr, size_t len, const struct param *p)
98{ 108{
99 const size_t max = len; 109 cbor_item_t *argv[8], *array = NULL;
100 110 size_t cbor_alloc_len, cbor_len = 0;
101 if (pack_string(TAG_PIN1, &ptr, &len, p->pin1) < 0 || 111 unsigned char *cbor = NULL;
102 pack_string(TAG_PIN2, &ptr, &len, p->pin2) < 0 || 112
103 pack_blob(TAG_RESET_WIRE_DATA, &ptr, &len, &p->reset_wire_data) < 0 || 113 memset(argv, 0, sizeof(argv));
104 pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || 114
105 pack_blob(TAG_SET_PIN_WIRE_DATA, &ptr, &len, &p->set_pin_wire_data) < 0 || 115 if ((array = cbor_new_definite_array(8)) == NULL ||
106 pack_blob(TAG_CHANGE_PIN_WIRE_DATA, &ptr, &len, &p->change_pin_wire_data) < 0 || 116 (argv[0] = pack_int(p->seed)) == NULL ||
107 pack_blob(TAG_RETRY_WIRE_DATA, &ptr, &len, &p->retry_wire_data) < 0 || 117 (argv[1] = pack_string(p->pin1)) == NULL ||
108 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) 118 (argv[2] = pack_string(p->pin2)) == NULL ||
109 return (0); 119 (argv[3] = pack_blob(&p->reset_wire_data)) == NULL ||
110 120 (argv[4] = pack_blob(&p->info_wire_data)) == NULL ||
111 return (max - len); 121 (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL ||
122 (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL ||
123 (argv[7] = pack_blob(&p->retry_wire_data)) == NULL)
124 goto fail;
125
126 for (size_t i = 0; i < 8; i++)
127 if (cbor_array_push(array, argv[i]) == false)
128 goto fail;
129
130 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
131 &cbor_alloc_len)) > len) {
132 cbor_len = 0;
133 goto fail;
134 }
135
136 memcpy(ptr, cbor, cbor_len);
137fail:
138 for (size_t i = 0; i < 8; i++)
139 if (argv[i])
140 cbor_decref(&argv[i]);
141
142 if (array)
143 cbor_decref(&array);
144
145 free(cbor);
146
147 return cbor_len;
112} 148}
113 149
114static size_t 150size_t
115input_len(int max) 151pack_dummy(uint8_t *ptr, size_t len)
116{ 152{
117 return (2 * len_string(max) + 5 * len_blob(max) + len_int()); 153 struct param dummy;
154 uint8_t blob[4096];
155 size_t blob_len;
156
157 memset(&dummy, 0, sizeof(dummy));
158
159 strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1));
160 strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2));
161
162 dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data);
163 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
164 dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data);
165 dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data);
166 dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data);
167
168 memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data,
169 dummy.reset_wire_data.len);
170 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
171 dummy.info_wire_data.len);
172 memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data,
173 dummy.set_pin_wire_data.len);
174 memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data,
175 dummy.change_pin_wire_data.len);
176 memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data,
177 dummy.retry_wire_data.len);
178
179 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
180
181 if (blob_len > len) {
182 memcpy(ptr, blob, len);
183 return len;
184 }
185
186 memcpy(ptr, blob, blob_len);
187
188 return blob_len;
118} 189}
119 190
120static fido_dev_t * 191static fido_dev_t *
121prepare_dev() 192prepare_dev(void)
122{ 193{
123 fido_dev_t *dev; 194 fido_dev_t *dev;
124 fido_dev_io_t io; 195 fido_dev_io_t io;
125 196
126 memset(&io, 0, sizeof(io)); 197 memset(&io, 0, sizeof(io));
127 198
@@ -133,14 +204,14 @@ prepare_dev()
133 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 204 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
134 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 205 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
135 fido_dev_free(&dev); 206 fido_dev_free(&dev);
136 return (NULL); 207 return NULL;
137 } 208 }
138 209
139 return (dev); 210 return dev;
140} 211}
141 212
142static void 213static void
143dev_reset(struct param *p) 214dev_reset(const struct param *p)
144{ 215{
145 fido_dev_t *dev; 216 fido_dev_t *dev;
146 217
@@ -155,16 +226,12 @@ dev_reset(struct param *p)
155} 226}
156 227
157static void 228static void
158dev_get_cbor_info(struct param *p) 229dev_get_cbor_info(const struct param *p)
159{ 230{
160 fido_dev_t *dev; 231 fido_dev_t *dev;
161 fido_cbor_info_t *ci; 232 fido_cbor_info_t *ci;
162 uint64_t n; 233 uint64_t n;
163 uint8_t proto; 234 uint8_t proto, major, minor, build, flags;
164 uint8_t major;
165 uint8_t minor;
166 uint8_t build;
167 uint8_t flags;
168 235
169 set_wire_data(p->info_wire_data.body, p->info_wire_data.len); 236 set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
170 237
@@ -192,6 +259,7 @@ dev_get_cbor_info(struct param *p)
192 char * const *sa = fido_cbor_info_versions_ptr(ci); 259 char * const *sa = fido_cbor_info_versions_ptr(ci);
193 consume(sa[i], strlen(sa[i])); 260 consume(sa[i], strlen(sa[i]));
194 } 261 }
262
195 for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { 263 for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) {
196 char * const *sa = fido_cbor_info_extensions_ptr(ci); 264 char * const *sa = fido_cbor_info_extensions_ptr(ci);
197 consume(sa[i], strlen(sa[i])); 265 consume(sa[i], strlen(sa[i]));
@@ -207,6 +275,12 @@ dev_get_cbor_info(struct param *p)
207 n = fido_cbor_info_maxmsgsiz(ci); 275 n = fido_cbor_info_maxmsgsiz(ci);
208 consume(&n, sizeof(n)); 276 consume(&n, sizeof(n));
209 277
278 n = fido_cbor_info_maxcredcntlst(ci);
279 consume(&n, sizeof(n));
280
281 n = fido_cbor_info_maxcredidlen(ci);
282 consume(&n, sizeof(n));
283
210 n = fido_cbor_info_fwversion(ci); 284 n = fido_cbor_info_fwversion(ci);
211 consume(&n, sizeof(n)); 285 consume(&n, sizeof(n));
212 286
@@ -222,7 +296,7 @@ out:
222} 296}
223 297
224static void 298static void
225dev_set_pin(struct param *p) 299dev_set_pin(const struct param *p)
226{ 300{
227 fido_dev_t *dev; 301 fido_dev_t *dev;
228 302
@@ -237,7 +311,7 @@ dev_set_pin(struct param *p)
237} 311}
238 312
239static void 313static void
240dev_change_pin(struct param *p) 314dev_change_pin(const struct param *p)
241{ 315{
242 fido_dev_t *dev; 316 fido_dev_t *dev;
243 317
@@ -252,10 +326,10 @@ dev_change_pin(struct param *p)
252} 326}
253 327
254static void 328static void
255dev_get_retry_count(struct param *p) 329dev_get_retry_count(const struct param *p)
256{ 330{
257 fido_dev_t *dev; 331 fido_dev_t *dev;
258 int n; 332 int n = 0;
259 333
260 set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); 334 set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len);
261 335
@@ -268,103 +342,36 @@ dev_get_retry_count(struct param *p)
268 fido_dev_free(&dev); 342 fido_dev_free(&dev);
269} 343}
270 344
271int 345void
272LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 346test(const struct param *p)
273{ 347{
274 struct param p; 348 prng_init((unsigned int)p->seed);
275
276 memset(&p, 0, sizeof(p));
277
278 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
279 unpack(data, size, &p) < 0)
280 return (0);
281
282 prng_init((unsigned int)p.seed);
283
284 fido_init(FIDO_DEBUG); 349 fido_init(FIDO_DEBUG);
285 fido_set_log_handler(consume_str); 350 fido_set_log_handler(consume_str);
286 351
287 dev_reset(&p); 352 dev_reset(p);
288 dev_get_cbor_info(&p); 353 dev_get_cbor_info(p);
289 dev_set_pin(&p); 354 dev_set_pin(p);
290 dev_change_pin(&p); 355 dev_change_pin(p);
291 dev_get_retry_count(&p); 356 dev_get_retry_count(p);
292
293 return (0);
294} 357}
295 358
296static size_t 359void
297pack_dummy(uint8_t *ptr, size_t len) 360mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
298{ 361{
299 struct param dummy; 362 if (flags & MUTATE_SEED)
300 uint8_t blob[16384]; 363 p->seed = (int)seed;
301 size_t blob_len;
302
303 memset(&dummy, 0, sizeof(dummy));
304
305 strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1));
306 strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2));
307
308 dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data);
309 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
310 dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data);
311 dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data);
312 dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data);
313
314 memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data,
315 dummy.reset_wire_data.len);
316 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
317 dummy.info_wire_data.len);
318 memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data,
319 dummy.set_pin_wire_data.len);
320 memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data,
321 dummy.change_pin_wire_data.len);
322 memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data,
323 dummy.retry_wire_data.len);
324
325 blob_len = pack(blob, sizeof(blob), &dummy);
326 assert(blob_len != 0);
327 364
328 if (blob_len > len) { 365 if (flags & MUTATE_PARAM) {
329 memcpy(ptr, blob, len); 366 mutate_string(p->pin1);
330 return (len); 367 mutate_string(p->pin2);
331 } 368 }
332 369
333 memcpy(ptr, blob, blob_len); 370 if (flags & MUTATE_WIREDATA) {
334 371 mutate_blob(&p->reset_wire_data);
335 return (blob_len); 372 mutate_blob(&p->info_wire_data);
336} 373 mutate_blob(&p->set_pin_wire_data);
337 374 mutate_blob(&p->change_pin_wire_data);
338size_t 375 mutate_blob(&p->retry_wire_data);
339LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 376 }
340 unsigned int seed)
341{
342 struct param p;
343 uint8_t blob[16384];
344 size_t blob_len;
345
346 memset(&p, 0, sizeof(p));
347
348 if (unpack(data, size, &p) < 0)
349 return (pack_dummy(data, maxsize));
350
351 p.seed = (int)seed;
352
353 mutate_string(p.pin1);
354 mutate_string(p.pin2);
355
356 mutate_blob(&p.reset_wire_data);
357 mutate_blob(&p.info_wire_data);
358 mutate_blob(&p.set_pin_wire_data);
359 mutate_blob(&p.change_pin_wire_data);
360 mutate_blob(&p.retry_wire_data);
361
362 blob_len = pack(blob, sizeof(blob), &p);
363
364 if (blob_len == 0 || blob_len > maxsize)
365 return (0);
366
367 memcpy(data, blob, blob_len);
368
369 return (blob_len);
370} 377}
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 @@
1/*
2 * Copyright (c) 2019 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 */
6
7#include <err.h>
8#include <fcntl.h>
9#include <stdbool.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15
16#include "mutator_aux.h"
17
18static bool debug;
19static unsigned int flags = MUTATE_ALL;
20static unsigned long long test_fail;
21static unsigned long long test_total;
22static unsigned long long mutate_fail;
23static unsigned long long mutate_total;
24
25int LLVMFuzzerInitialize(int *, char ***);
26int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
27size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
28
29static int
30save_seed(const char *opt)
31{
32 const char *path;
33 int fd = -1, status = 1;
34 void *buf = NULL;
35 const size_t buflen = 4096;
36 size_t n;
37 struct param *p = NULL;
38
39 if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) {
40 warnx("usage: --fido-save-seed=<path>");
41 goto fail;
42 }
43
44 if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
45 warn("open %s", path);
46 goto fail;
47 }
48
49 if ((buf = malloc(buflen)) == NULL) {
50 warn("malloc");
51 goto fail;
52 }
53
54 n = pack_dummy(buf, buflen);
55
56 if ((p = unpack(buf, n)) == NULL) {
57 warnx("unpack");
58 goto fail;
59 }
60
61 if (write(fd, buf, n) != (ssize_t)n) {
62 warn("write %s", path);
63 goto fail;
64 }
65
66 status = 0;
67fail:
68 if (fd != -1)
69 close(fd);
70 free(buf);
71 free(p);
72
73 return status;
74}
75
76static void
77parse_mutate_flags(const char *opt, unsigned int *mutate_flags)
78{
79 const char *f;
80
81 if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0)
82 errx(1, "usage: --fido-mutate=<flag>");
83
84 if (strcmp(f, "seed") == 0)
85 *mutate_flags |= MUTATE_SEED;
86 else if (strcmp(f, "param") == 0)
87 *mutate_flags |= MUTATE_PARAM;
88 else if (strcmp(f, "wiredata") == 0)
89 *mutate_flags |= MUTATE_WIREDATA;
90 else
91 errx(1, "--fido-mutate: unknown flag '%s'", f);
92}
93
94int
95LLVMFuzzerInitialize(int *argc, char ***argv)
96{
97 unsigned int mutate_flags = 0;
98
99 for (int i = 0; i < *argc; i++)
100 if (strcmp((*argv)[i], "--fido-debug") == 0) {
101 debug = 1;
102 } else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) {
103 exit(save_seed((*argv)[i]));
104 } else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) {
105 parse_mutate_flags((*argv)[i], &mutate_flags);
106 }
107
108 if (mutate_flags)
109 flags = mutate_flags;
110
111 return 0;
112}
113
114int
115LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
116{
117 struct param *p;
118
119 if (++test_total % 100000 == 0 && debug) {
120 double r = (double)test_fail/(double)test_total * 100.0;
121 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
122 test_fail, test_total, r);
123 }
124
125 if (size > 4096 || (p = unpack(data, size)) == NULL)
126 test_fail++;
127 else {
128 test(p);
129 free(p);
130 }
131
132 return 0;
133}
134
135size_t
136LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
137 unsigned int seed) NO_MSAN
138{
139 struct param *p;
140 uint8_t blob[4096];
141 size_t blob_len;
142
143 memset(&p, 0, sizeof(p));
144
145#ifdef WITH_MSAN
146 __msan_unpoison(data, maxsize);
147#endif
148
149 if (++mutate_total % 100000 == 0 && debug) {
150 double r = (double)mutate_fail/(double)mutate_total * 100.0;
151 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
152 mutate_fail, mutate_total, r);
153 }
154
155 if ((p = unpack(data, size)) == NULL) {
156 mutate_fail++;
157 return pack_dummy(data, maxsize);
158 }
159
160 mutate(p, seed, flags);
161
162 if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
163 blob_len > sizeof(blob) || blob_len > maxsize) {
164 mutate_fail++;
165 free(p);
166 return 0;
167 }
168
169 free(p);
170
171 memcpy(data, blob, blob_len);
172
173 return blob_len;
174}
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 @@
5 */ 5 */
6 6
7#include <assert.h> 7#include <assert.h>
8#include <cbor.h>
8#include <stddef.h> 9#include <stddef.h>
9#include <stdint.h> 10#include <stdint.h>
10#include <stdio.h> 11#include <stdio.h>
11#include <stdlib.h> 12#include <stdlib.h>
12#include <string.h> 13#include <string.h>
13 14
15#include "fido.h"
14#include "mutator_aux.h" 16#include "mutator_aux.h"
15 17
16size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); 18size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t);
17 19
18static uint8_t *wire_data_ptr = NULL; 20static const uint8_t *wire_data_ptr = NULL;
19static size_t wire_data_len = 0; 21static size_t wire_data_len = 0;
20 22
21size_t 23size_t
22xstrlen(const char *s) 24xstrlen(const char *s)
23{ 25{
24 if (s == NULL) 26 if (s == NULL)
25 return (0); 27 return 0;
26 28
27 return (strlen(s)); 29 return strlen(s);
28} 30}
29 31
30void 32void
@@ -33,6 +35,10 @@ consume(const void *body, size_t len)
33 const volatile uint8_t *ptr = body; 35 const volatile uint8_t *ptr = body;
34 volatile uint8_t x = 0; 36 volatile uint8_t x = 0;
35 37
38#ifdef WITH_MSAN
39 __msan_check_mem_is_initialized(body, len);
40#endif
41
36 while (len--) 42 while (len--)
37 x ^= *ptr++; 43 x ^= *ptr++;
38} 44}
@@ -44,217 +50,87 @@ consume_str(const char *str)
44} 50}
45 51
46int 52int
47unpack_int(uint8_t t, uint8_t **ptr, size_t *len, int *v) NO_MSAN 53unpack_int(cbor_item_t *item, int *v)
48{
49 size_t l;
50
51 if (*len < sizeof(t) || **ptr != t)
52 return (-1);
53
54 *ptr += sizeof(t);
55 *len -= sizeof(t);
56
57 if (*len < sizeof(l))
58 return (-1);
59
60 memcpy(&l, *ptr, sizeof(l));
61 *ptr += sizeof(l);
62 *len -= sizeof(l);
63
64 if (l != sizeof(*v) || *len < l)
65 return (-1);
66
67 memcpy(v, *ptr, sizeof(*v));
68 *ptr += sizeof(*v);
69 *len -= sizeof(*v);
70
71 return (0);
72}
73
74int
75unpack_string(uint8_t t, uint8_t **ptr, size_t *len, char *v) NO_MSAN
76{ 54{
77 size_t l; 55 if (cbor_is_int(item) == false ||
78 56 cbor_int_get_width(item) != CBOR_INT_64)
79 if (*len < sizeof(t) || **ptr != t) 57 return -1;
80 return (-1);
81
82 *ptr += sizeof(t);
83 *len -= sizeof(t);
84
85 if (*len < sizeof(l))
86 return (-1);
87
88 memcpy(&l, *ptr, sizeof(l));
89 *ptr += sizeof(l);
90 *len -= sizeof(l);
91 58
92 if (*len < l || l >= MAXSTR) 59 if (cbor_isa_uint(item))
93 return (-1); 60 *v = (int)cbor_get_uint64(item);
94 61 else
95 memcpy(v, *ptr, l); 62 *v = (int)(-cbor_get_uint64(item) - 1);
96 v[l] = '\0';
97
98 *ptr += l;
99 *len -= l;
100
101 return (0);
102}
103
104int
105unpack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t *v) NO_MSAN
106{
107 size_t l;
108
109 if (*len < sizeof(t) || **ptr != t)
110 return (-1);
111
112 *ptr += sizeof(t);
113 *len -= sizeof(t);
114
115 if (*len < sizeof(l))
116 return (-1);
117
118 memcpy(&l, *ptr, sizeof(l));
119 *ptr += sizeof(l);
120 *len -= sizeof(l);
121
122 if (l != sizeof(*v) || *len < l)
123 return (-1);
124
125 memcpy(v, *ptr, sizeof(*v));
126 *ptr += sizeof(*v);
127 *len -= sizeof(*v);
128
129 return (0);
130}
131
132int
133unpack_blob(uint8_t t, uint8_t **ptr, size_t *len, struct blob *v) NO_MSAN
134{
135 size_t l;
136
137 v->len = 0;
138
139 if (*len < sizeof(t) || **ptr != t)
140 return (-1);
141
142 *ptr += sizeof(t);
143 *len -= sizeof(t);
144
145 if (*len < sizeof(l))
146 return (-1);
147
148 memcpy(&l, *ptr, sizeof(l));
149 *ptr += sizeof(l);
150 *len -= sizeof(l);
151
152 if (*len < l || l > sizeof(v->body))
153 return (-1);
154
155 memcpy(v->body, *ptr, l);
156 *ptr += l;
157 *len -= l;
158
159 v->len = l;
160 63
161 return (0); 64 return 0;
162} 65}
163 66
164int 67int
165pack_int(uint8_t t, uint8_t **ptr, size_t *len, int v) NO_MSAN 68unpack_string(cbor_item_t *item, char *v)
166{ 69{
167 const size_t l = sizeof(v); 70 size_t len;
168 71
169 if (*len < sizeof(t) + sizeof(l) + l) 72 if (cbor_isa_bytestring(item) == false ||
170 return (-1); 73 (len = cbor_bytestring_length(item)) >= MAXSTR)
74 return -1;
171 75
172 (*ptr)[0] = t; 76 memcpy(v, cbor_bytestring_handle(item), len);
173 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); 77 v[len] = '\0';
174 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l);
175 78
176 *ptr += sizeof(t) + sizeof(l) + l; 79 return 0;
177 *len -= sizeof(t) + sizeof(l) + l;
178
179 return (0);
180} 80}
181 81
182int 82int
183pack_string(uint8_t t, uint8_t **ptr, size_t *len, const char *v) NO_MSAN 83unpack_byte(cbor_item_t *item, uint8_t *v)
184{ 84{
185 const size_t l = strlen(v); 85 if (cbor_isa_uint(item) == false ||
186 86 cbor_int_get_width(item) != CBOR_INT_8)
187 if (*len < sizeof(t) + sizeof(l) + l) 87 return -1;
188 return (-1);
189
190 (*ptr)[0] = t;
191 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l));
192 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v, l);
193 88
194 *ptr += sizeof(t) + sizeof(l) + l; 89 *v = cbor_get_uint8(item);
195 *len -= sizeof(t) + sizeof(l) + l;
196 90
197 return (0); 91 return 0;
198} 92}
199 93
200int 94int
201pack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t v) NO_MSAN 95unpack_blob(cbor_item_t *item, struct blob *v)
202{ 96{
203 const size_t l = sizeof(v); 97 if (cbor_isa_bytestring(item) == false ||
98 (v->len = cbor_bytestring_length(item)) > sizeof(v->body))
99 return -1;
204 100
205 if (*len < sizeof(t) + sizeof(l) + l) 101 memcpy(v->body, cbor_bytestring_handle(item), v->len);
206 return (-1);
207 102
208 (*ptr)[0] = t; 103 return 0;
209 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l));
210 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l);
211
212 *ptr += sizeof(t) + sizeof(l) + l;
213 *len -= sizeof(t) + sizeof(l) + l;
214
215 return (0);
216} 104}
217 105
218int 106cbor_item_t *
219pack_blob(uint8_t t, uint8_t **ptr, size_t *len, const struct blob *v) NO_MSAN 107pack_int(int v) NO_MSAN
220{ 108{
221 const size_t l = v->len; 109 if (v < 0)
222 110 return cbor_build_negint64((uint64_t)(-(int64_t)v - 1));
223 if (*len < sizeof(t) + sizeof(l) + l) 111 else
224 return (-1); 112 return cbor_build_uint64((uint64_t)v);
225
226 (*ptr)[0] = t;
227 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l));
228 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v->body, l);
229
230 *ptr += sizeof(t) + sizeof(l) + l;
231 *len -= sizeof(t) + sizeof(l) + l;
232
233 return (0);
234} 113}
235 114
236size_t 115cbor_item_t *
237len_int(void) 116pack_string(const char *v) NO_MSAN
238{ 117{
239 return (sizeof(uint8_t) + sizeof(size_t) + sizeof(int)); 118 if (strlen(v) >= MAXSTR)
240} 119 return NULL;
241 120
242size_t 121 return cbor_build_bytestring((const unsigned char *)v, strlen(v));
243len_string(int max)
244{
245 return ((sizeof(uint8_t) + sizeof(size_t)) + (max ? MAXSTR - 1 : 0));
246} 122}
247 123
248size_t 124cbor_item_t *
249len_byte(void) 125pack_byte(uint8_t v) NO_MSAN
250{ 126{
251 return (sizeof(uint8_t) + sizeof(size_t) + sizeof(uint8_t)); 127 return cbor_build_uint8(v);
252} 128}
253 129
254size_t 130cbor_item_t *
255len_blob(int max) 131pack_blob(const struct blob *v) NO_MSAN
256{ 132{
257 return (sizeof(uint8_t) + sizeof(size_t) + (max ? MAXBLOB : 0)); 133 return cbor_build_bytestring(v->body, v->len);
258} 134}
259 135
260void 136void
@@ -284,13 +160,13 @@ mutate_string(char *s)
284 n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); 160 n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1);
285 s[n] = '\0'; 161 s[n] = '\0';
286} 162}
287 163
288void * 164void *
289dev_open(const char *path) 165dev_open(const char *path)
290{ 166{
291 (void)path; 167 (void)path;
292 168
293 return ((void *)0xdeadbeef); 169 return (void *)0xdeadbeef;
294} 170}
295 171
296void 172void
@@ -307,7 +183,7 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms)
307 (void)ms; 183 (void)ms;
308 184
309 assert(handle == (void *)0xdeadbeef); 185 assert(handle == (void *)0xdeadbeef);
310 assert(len == 64); 186 assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN);
311 187
312 if (wire_data_len < len) 188 if (wire_data_len < len)
313 n = wire_data_len; 189 n = wire_data_len;
@@ -319,25 +195,26 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms)
319 wire_data_ptr += n; 195 wire_data_ptr += n;
320 wire_data_len -= n; 196 wire_data_len -= n;
321 197
322 return ((int)n); 198 return (int)n;
323} 199}
324 200
325int 201int
326dev_write(void *handle, const unsigned char *ptr, size_t len) 202dev_write(void *handle, const unsigned char *ptr, size_t len)
327{ 203{
328 assert(handle == (void *)0xdeadbeef); 204 assert(handle == (void *)0xdeadbeef);
329 assert(len == 64 + 1); 205 assert(len >= CTAP_MIN_REPORT_LEN + 1 &&
206 len <= CTAP_MAX_REPORT_LEN + 1);
330 207
331 consume(ptr, len); 208 consume(ptr, len);
332 209
333 if (uniform_random(400) < 1) 210 if (uniform_random(400) < 1)
334 return (-1); 211 return -1;
335 212
336 return ((int)len); 213 return (int)len;
337} 214}
338 215
339void 216void
340set_wire_data(uint8_t *ptr, size_t len) 217set_wire_data(const uint8_t *ptr, size_t len)
341{ 218{
342 wire_data_ptr = ptr; 219 wire_data_ptr = ptr;
343 wire_data_len = len; 220 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 @@
9 9
10#include <stddef.h> 10#include <stddef.h>
11#include <stdint.h> 11#include <stdint.h>
12#include <cbor.h>
12 13
13/* 14/*
14 * As of LLVM 7.0.1, MSAN support in libFuzzer was still experimental. 15 * As of LLVM 10.0.0, MSAN support in libFuzzer was still experimental.
15 * We therefore have to be careful when using our custom mutator, or 16 * We therefore have to be careful when using our custom mutator, or
16 * MSAN will flag uninitialised reads on memory populated by libFuzzer. 17 * MSAN will flag uninitialised reads on memory populated by libFuzzer.
17 * Since there is no way to suppress MSAN without regenerating object 18 * Since there is no way to suppress MSAN without regenerating object
@@ -22,6 +23,7 @@
22 23
23#if defined(__has_feature) 24#if defined(__has_feature)
24# if __has_feature(memory_sanitizer) 25# if __has_feature(memory_sanitizer)
26# include <sanitizer/msan_interface.h>
25# define NO_MSAN __attribute__((no_sanitize("memory"))) 27# define NO_MSAN __attribute__((no_sanitize("memory")))
26# define WITH_MSAN 1 28# define WITH_MSAN 1
27# endif 29# endif
@@ -31,44 +33,49 @@
31# define NO_MSAN 33# define NO_MSAN
32#endif 34#endif
33 35
36#define MUTATE_SEED 0x01
37#define MUTATE_PARAM 0x02
38#define MUTATE_WIREDATA 0x04
39#define MUTATE_ALL (MUTATE_SEED | MUTATE_PARAM | MUTATE_WIREDATA)
40
34#define MAXSTR 1024 41#define MAXSTR 1024
35#define MAXBLOB 3072 42#define MAXBLOB 3072
36 43
37#define GETLEN_MIN 0
38#define GETLEN_MAX 1
39
40struct blob { 44struct blob {
41 uint8_t body[MAXBLOB]; 45 uint8_t body[MAXBLOB];
42 size_t len; 46 size_t len;
43}; 47};
44 48
49struct param;
50
51struct param *unpack(const uint8_t *, size_t);
52size_t pack(uint8_t *, size_t, const struct param *);
53size_t pack_dummy(uint8_t *, size_t);
54void mutate(struct param *, unsigned int, unsigned int);
55void test(const struct param *);
56
45size_t xstrlen(const char *); 57size_t xstrlen(const char *);
46void consume(const void *, size_t); 58void consume(const void *, size_t);
47void consume_str(const char *); 59void consume_str(const char *);
48 60
49int unpack_blob(uint8_t, uint8_t **, size_t *, struct blob *); 61int unpack_blob(cbor_item_t *, struct blob *);
50int unpack_byte(uint8_t, uint8_t **, size_t *, uint8_t *); 62int unpack_byte(cbor_item_t *, uint8_t *);
51int unpack_int(uint8_t, uint8_t **, size_t *, int *); 63int unpack_int(cbor_item_t *, int *);
52int unpack_string(uint8_t, uint8_t **, size_t *, char *); 64int unpack_string(cbor_item_t *, char *);
53
54int pack_blob(uint8_t, uint8_t **, size_t *, const struct blob *);
55int pack_byte(uint8_t, uint8_t **, size_t *, uint8_t);
56int pack_int(uint8_t, uint8_t **, size_t *, int);
57int pack_string(uint8_t, uint8_t **, size_t *, const char *);
58 65
59size_t len_int(void); 66cbor_item_t *pack_blob(const struct blob *);
60size_t len_string(int); 67cbor_item_t *pack_byte(uint8_t);
61size_t len_byte(void); 68cbor_item_t *pack_int(int);
62size_t len_blob(int); 69cbor_item_t *pack_string(const char *);
63 70
64void mutate_byte(uint8_t *); 71void mutate_byte(uint8_t *);
65void mutate_int(int *); 72void mutate_int(int *);
66void mutate_blob(struct blob *); 73void mutate_blob(struct blob *);
67void mutate_string(char *); 74void mutate_string(char *);
68 75
69void * dev_open(const char *); 76void *dev_open(const char *);
70void dev_close(void *); 77void dev_close(void *);
71void set_wire_data(uint8_t *, size_t); 78void set_wire_data(const uint8_t *, size_t);
72int dev_read(void *, unsigned char *, size_t, int); 79int dev_read(void *, unsigned char *, size_t, int);
73int dev_write(void *, const unsigned char *, size_t); 80int dev_write(void *, const unsigned char *, size_t);
74 81
diff --git a/fuzz/prng.c b/fuzz/prng.c
index fa6d4e4..61114ac 100755..100644
--- a/fuzz/prng.c
+++ b/fuzz/prng.c
@@ -63,7 +63,8 @@ void init_genrand(unsigned long s)
63 mt[0]= s & 0xffffffffUL; 63 mt[0]= s & 0xffffffffUL;
64 for (mti=1; mti<N; mti++) { 64 for (mti=1; mti<N; mti++) {
65 mt[mti] = 65 mt[mti] =
66 (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 66 (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) +
67 (unsigned long)mti);
67 /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ 68 /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
68 /* In the previous versions, MSBs of the seed affect */ 69 /* In the previous versions, MSBs of the seed affect */
69 /* only MSBs of the array mt[]. */ 70 /* only MSBs of the array mt[]. */
diff --git a/fuzz/report.tgz b/fuzz/report.tgz
index 8a002f0..6f02fc5 100644
--- a/fuzz/report.tgz
+++ b/fuzz/report.tgz
Binary files 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 @@
1Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover 1Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover
2-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 2--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3fuzz/prng.c 31 0 100.00% 2 0 100.00% 48 0 100.00% 3fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00%
4fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% 4fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65%
5fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00% 5fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00%
6openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% 6openbsd-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%
8openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00% 8openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00%
9openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% 9openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00%
10src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% 10src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00%
11src/assert.c 566 43 92.40% 53 1 98.11% 900 87 90.33% 11src/assert.c 566 24 95.76% 53 1 98.11% 900 50 94.44%
12src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00% 12src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00%
13src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67% 13src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67%
14src/blob.c 39 1 97.44% 7 0 100.00% 73 4 94.52% 14src/blob.c 39 0 100.00% 7 0 100.00% 73 0 100.00%
15src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% 15src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00%
16src/cbor.c 884 70 92.08% 52 2 96.15% 1371 106 92.27% 16src/cbor.c 883 6 99.32% 52 0 100.00% 1364 17 98.75%
17src/cred.c 534 51 90.45% 55 1 98.18% 830 78 90.60% 17src/cred.c 536 23 95.71% 57 1 98.25% 836 29 96.53%
18src/credman.c 376 18 95.21% 38 0 100.00% 589 15 97.45% 18src/credman.c 385 18 95.32% 38 0 100.00% 595 16 97.31%
19src/dev.c 201 85 57.71% 26 8 69.23% 294 128 56.46% 19src/dev.c 334 90 73.05% 33 8 75.76% 466 140 69.96%
20src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% 20src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00%
21src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00% 21src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00%
22src/err.c 108 108 0.00% 1 1 0.00% 112 112 0.00% 22src/err.c 112 8 92.86% 1 0 100.00% 116 8 93.10%
23src/es256.c 278 0 100.00% 16 0 100.00% 377 0 100.00% 23src/es256.c 280 0 100.00% 16 0 100.00% 398 0 100.00%
24src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% 24src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00%
25src/hid_linux.c 166 166 0.00% 12 12 0.00% 292 292 0.00% 25src/hid_linux.c 235 235 0.00% 19 19 0.00% 416 416 0.00%
26src/info.c 146 0 100.00% 31 0 100.00% 304 0 100.00% 26src/info.c 152 0 100.00% 34 0 100.00% 319 0 100.00%
27src/io.c 123 5 95.93% 10 0 100.00% 218 11 94.95% 27src/io.c 156 9 94.23% 10 0 100.00% 236 11 95.34%
28src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% 28src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00%
29src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00% 29src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00%
30src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00% 30src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00%
31src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00% 31src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00%
32src/rs256.c 102 29 71.57% 8 3 62.50% 140 44 68.57% 32src/rs256.c 102 6 94.12% 8 0 100.00% 140 13 90.71%
33src/u2f.c 443 28 93.68% 13 0 100.00% 699 52 92.56% 33src/u2f.c 491 9 98.17% 15 0 100.00% 774 18 97.67%
34 34
35Files which contain no functions: 35Files which contain no functions:
36openbsd-compat/time.h 0 0 - 0 0 - 0 0 -
36src/extern.h 0 0 - 0 0 - 0 0 - 37src/extern.h 0 0 - 0 0 - 0 0 -
37src/fido.h 0 0 - 0 0 - 0 0 - 38src/fido.h 0 0 - 0 0 - 0 0 -
38src/fido/err.h 0 0 - 0 0 - 0 0 - 39src/fido/err.h 0 0 - 0 0 - 0 0 -
39src/fido/param.h 0 0 - 0 0 - 0 0 - 40src/fido/param.h 0 0 - 0 0 - 0 0 -
40-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 41--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
41TOTAL 5054 653 87.08% 435 39 91.03% 7914 1002 87.34% 42TOTAL 5359 477 91.10% 456 40 91.23% 8349 791 90.53%