diff options
Diffstat (limited to 'fuzz')
-rw-r--r-- | fuzz/CMakeLists.txt | 1 | ||||
-rw-r--r-- | fuzz/Dockerfile | 9 | ||||
-rw-r--r-- | fuzz/Makefile | 20 | ||||
-rw-r--r-- | fuzz/README | 130 | ||||
-rwxr-xr-x | fuzz/build-coverage | 33 | ||||
-rw-r--r-- | fuzz/dummy.h | 4 | ||||
-rw-r--r-- | fuzz/export.gnu | 10 | ||||
-rw-r--r-- | fuzz/functions.txt | 197 | ||||
-rw-r--r-- | fuzz/fuzz_assert.c | 455 | ||||
-rw-r--r-- | fuzz/fuzz_bio.c | 335 | ||||
-rw-r--r-- | fuzz/fuzz_cred.c | 458 | ||||
-rw-r--r-- | fuzz/fuzz_credman.c | 314 | ||||
-rw-r--r-- | fuzz/fuzz_mgmt.c | 321 | ||||
-rw-r--r-- | fuzz/libfuzzer.c | 174 | ||||
-rw-r--r-- | fuzz/mutator_aux.c | 253 | ||||
-rw-r--r-- | fuzz/mutator_aux.h | 49 | ||||
-rw-r--r--[-rwxr-xr-x] | fuzz/prng.c | 3 | ||||
-rw-r--r-- | fuzz/report.tgz | bin | 211709 -> 222723 bytes | |||
-rw-r--r-- | fuzz/summary.txt | 31 |
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 | ||
10 | list(APPEND COMMON_SOURCES | 10 | list(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 | ||
5 | FROM ubuntu:bionic | 5 | FROM ubuntu:focal |
6 | ENV DEBIAN_FRONTEND=noninteractive | ||
6 | RUN apt-get update | 7 | RUN apt-get update |
7 | RUN apt-get install -y clang-9 cmake git libssl-dev libudev-dev make pkg-config | 8 | RUN apt-get install -y clang-10 cmake git libssl-dev libudev-dev make pkg-config |
8 | RUN git clone --branch v0.5.0 https://github.com/PJK/libcbor | 9 | RUN git clone --branch v0.7.0 https://github.com/PJK/libcbor |
9 | RUN git clone https://github.com/yubico/libfido2 | 10 | RUN git clone https://github.com/yubico/libfido2 |
10 | RUN CC=clang-9 /libfido2/fuzz/build-coverage /libcbor /libfido2 | 11 | RUN CC=clang-10 CXX=clang++-10 /libfido2/fuzz/build-coverage /libcbor /libfido2 |
diff --git a/fuzz/Makefile b/fuzz/Makefile index c8fe0b8..77699ac 100644 --- a/fuzz/Makefile +++ b/fuzz/Makefile | |||
@@ -2,10 +2,10 @@ | |||
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 | ||
5 | IMAGE := libfido2-coverage:1.3.0 | 5 | IMAGE := libfido2-coverage:1.5.0 |
6 | RUNNER := libfido2-runner | 6 | RUNNER := libfido2-runner |
7 | PROFDATA := llvm-profdata-9 | 7 | PROFDATA := llvm-profdata-10 |
8 | COV := llvm-cov-9 | 8 | COV := llvm-cov-10 |
9 | TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt | 9 | TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt |
10 | CORPORA := $(foreach f,${TARGETS},${f}/corpus) | 10 | CORPORA := $(foreach f,${TARGETS},${f}/corpus) |
11 | MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus) | 11 | MINIFY := $(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 | ||
28 | corpus: sync | 28 | corpus: 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 | ||
45 | profdata: run | 45 | profdata: 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 | ||
49 | report.tgz: profdata | 49 | report.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 | ||
59 | functions.txt: profdata | 59 | functions.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 | ||
64 | clean: run | 64 | clean: 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 | ||
4 | AFL is more convenient when fuzzing the path from the authenticator to | 4 | AFL is more convenient when fuzzing the path from the authenticator to |
5 | libfido2 in an existing application. To do so, use preload-snoop.c with a real | 5 | libfido2 in an existing application. To do so, use preload-snoop.c with a real |
6 | authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1 | 6 | authenticator 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 | 7 | use preload-fuzz.c to read device data from stdin. |
8 | this approach can be found in the harnesses under fuzz/harnesses/ that fuzz | ||
9 | the standalone examples and tools bundled with libfido2. | ||
10 | 8 | ||
11 | libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, | 9 | libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, |
12 | fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses, | 10 | fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses, |
@@ -15,129 +13,7 @@ use -DFUZZ=1 -DLIBFUZZER=1. | |||
15 | To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of | 13 | To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of |
16 | libcbor and OpenSSL built with the respective sanitiser. In order to keep | 14 | libcbor and OpenSSL built with the respective sanitiser. In order to keep |
17 | memory utilisation at a manageable level, you can either enforce limits at | 15 | memory utilisation at a manageable level, you can either enforce limits at |
18 | the OS level (e.g. cgroups on Linux) or, alternatively, patch libcbor with | 16 | the OS level (e.g. cgroups on Linux), or patch libcbor with the diff below. |
19 | the diff at the bottom of this file. | ||
20 | |||
21 | 1. 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 | |||
27 | 1.1 Decide where your workspace will live | ||
28 | |||
29 | $ export FAKEROOT=/home/pedro/fakeroot | ||
30 | $ mkdir -p ${FAKEROOT}/src | ||
31 | |||
32 | 1.2 Building libcbor with ASAN | ||
33 | |||
34 | $ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor | ||
35 | $ cd ${FAKEROOT}/src/libcbor | ||
36 | |||
37 | Assuming 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 | |||
49 | 1.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 | |||
59 | 1.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 | |||
72 | 2. 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 | |||
78 | 2.1 Decide where your workspace will live | ||
79 | |||
80 | $ export FAKEROOT=/home/pedro/fakeroot | ||
81 | $ mkdir -p ${FAKEROOT}/src | ||
82 | |||
83 | 2.2 Building libcbor with MSAN | ||
84 | |||
85 | $ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor | ||
86 | $ cd ${FAKEROOT}/src/libcbor | ||
87 | |||
88 | Assuming 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 | |||
100 | 2.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 | |||
111 | 2.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 | |||
124 | 3. Running the libFuzzer harnesses | ||
125 | |||
126 | When running under ASAN, you may want to set ASAN_OPTIONS to | ||
127 | 'allocator_may_return_null=1:detect_stack_use_after_return=1'. | ||
128 | |||
129 | The 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 | |||
134 | You may want to use -jobs or -workers depending on the number of logical | ||
135 | cores available for fuzzing. | ||
136 | |||
137 | 4. Auxiliary scripts | ||
138 | |||
139 | A set of harnesses and auxiliary scripts can be found under harnesses/. To | ||
140 | compile coverage reports, adjust the harnesses to your setup and run 'report'. | ||
141 | 17 | ||
142 | diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c | 18 | diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c |
143 | index aa049a2..e294b38 100644 | 19 | index aa049a2..e294b38 100644 |
diff --git a/fuzz/build-coverage b/fuzz/build-coverage index af9f8df..0f8310d 100755 --- a/fuzz/build-coverage +++ b/fuzz/build-coverage | |||
@@ -1,27 +1,30 @@ | |||
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 | ||
7 | LIBCBOR=$1 | 7 | LIBCBOR="$1" |
8 | LIBFIDO2=$2 | 8 | LIBFIDO2="$2" |
9 | 9 | ||
10 | CC=${CC:-clang} | 10 | CC="${CC:-clang}" |
11 | PKG_CONFIG_PATH=${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig} | 11 | CXX="${CXX:-clang++}" |
12 | PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig}" | ||
12 | export CC PKG_CONFIG_PATH | 13 | export CC PKG_CONFIG_PATH |
13 | 14 | ||
14 | # Clean up. | 15 | # Clean up. |
15 | rm -rf ${LIBCBOR}/build ${LIBCBOR}/install ${LIBFIDO2}/build | 16 | rm -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 |
19 | mkdir ${LIBCBOR}/build ${LIBCBOR}/install | 20 | mkdir "${LIBCBOR}/build" "${LIBCBOR}/install" |
20 | (cd ${LIBCBOR}/build && cmake -DCMAKE_INSTALL_PREFIX=${LIBCBOR}/install ..) | 21 | (cd "${LIBCBOR}/build" && cmake -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..) |
21 | make -C ${LIBCBOR}/build all install | 22 | make -C "${LIBCBOR}/build" all install |
22 | 23 | ||
23 | # Build libfido2. | 24 | # Build libfido2. |
24 | mkdir -p ${LIBFIDO2}/build | 25 | mkdir -p "${LIBFIDO2}/build" |
25 | (cd ${LIBFIDO2}/build && cmake -DFUZZ=1 -DLIBFUZZER=1 -DCOVERAGE=1 \ | 26 | export CFLAGS="-fprofile-instr-generate -fcoverage-mapping" |
26 | -DCMAKE_BUILD_TYPE=Debug ..) | 27 | export LDFLAGS="${CFLAGS}" |
27 | make -C ${LIBFIDO2}/build | 28 | (cd "${LIBFIDO2}/build" && cmake -DFUZZ=1 -DLIBFUZZER=1 \ |
29 | -DCMAKE_BUILD_TYPE=Debug ..) | ||
30 | make -C "${LIBFIDO2}/build" | ||
diff --git a/fuzz/dummy.h b/fuzz/dummy.h index a899e4a..981ccee 100644 --- a/fuzz/dummy.h +++ b/fuzz/dummy.h | |||
@@ -10,6 +10,8 @@ | |||
10 | #include <stdint.h> | 10 | #include <stdint.h> |
11 | 11 | ||
12 | const char dummy_name[] = "finger1"; | 12 | const char dummy_name[] = "finger1"; |
13 | const char dummy_pin1[] = "skepp cg0u3;Y.."; | ||
14 | const char dummy_pin2[] = "bastilha 6rJrfQZI."; | ||
13 | const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; | 15 | const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; |
14 | const char dummy_rp_id[] = "localhost"; | 16 | const char dummy_rp_id[] = "localhost"; |
15 | const char dummy_rp_name[] = "sweet home localhost"; | 17 | const char dummy_rp_name[] = "sweet home localhost"; |
@@ -17,8 +19,6 @@ const char dummy_user_icon[] = "an icon"; | |||
17 | const char dummy_user_name[] = "john smith"; | 19 | const char dummy_user_name[] = "john smith"; |
18 | const char dummy_user_nick[] = "jsmith"; | 20 | const char dummy_user_nick[] = "jsmith"; |
19 | const uint8_t dummy_id[] = { 0x5e, 0xd2 }; | 21 | const uint8_t dummy_id[] = { 0x5e, 0xd2 }; |
20 | const char dummy_pin1[] = "skepp cg0u3;Y.."; | ||
21 | const char dummy_pin2[] = "bastilha 6rJrfQZI."; | ||
22 | 22 | ||
23 | const uint8_t dummy_user_id[] = { | 23 | const 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% | |||
9 | File '/libfido2/src/assert.c': | 9 | File '/libfido2/src/assert.c': |
10 | Name Regions Miss Cover Lines Miss Cover | 10 | Name Regions Miss Cover Lines Miss Cover |
11 | --------------------------------------------------------------------------------------- | 11 | --------------------------------------------------------------------------------------- |
12 | fido_dev_get_assert 35 3 91.43% 38 4 89.47% | 12 | fido_dev_get_assert 35 0 100.00% 38 0 100.00% |
13 | fido_check_flags 13 0 100.00% 18 0 100.00% | 13 | fido_check_flags 13 0 100.00% 18 0 100.00% |
14 | fido_get_signed_hash 32 0 100.00% 46 0 100.00% | 14 | fido_get_signed_hash 32 0 100.00% 46 0 100.00% |
15 | fido_verify_sig_es256 17 2 88.24% 31 7 77.42% | 15 | fido_verify_sig_es256 17 2 88.24% 31 7 77.42% |
16 | fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% | 16 | fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% |
17 | fido_verify_sig_eddsa 23 4 82.61% 43 13 69.77% | 17 | fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72% |
18 | fido_assert_verify 48 4 91.67% 79 4 94.94% | 18 | fido_assert_verify 48 4 91.67% 79 5 93.67% |
19 | fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% | 19 | fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% |
20 | fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% | 20 | fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% |
21 | fido_assert_set_rp 12 1 91.67% 14 3 78.57% | 21 | fido_assert_set_rp 12 0 100.00% 14 0 100.00% |
22 | fido_assert_allow_cred 13 2 84.62% 29 3 89.66% | 22 | fido_assert_allow_cred 13 2 84.62% 29 3 89.66% |
23 | fido_assert_set_extensions 9 0 100.00% 8 0 100.00% | 23 | fido_assert_set_extensions 9 0 100.00% 8 0 100.00% |
24 | fido_assert_set_options 6 6 0.00% 6 6 0.00% | 24 | fido_assert_set_options 6 6 0.00% 6 6 0.00% |
@@ -28,7 +28,7 @@ fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 | |||
28 | fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% | 28 | fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% |
29 | fido_assert_new 1 0 100.00% 3 0 100.00% | 29 | fido_assert_new 1 0 100.00% 3 0 100.00% |
30 | fido_assert_reset_tx 1 0 100.00% 15 0 100.00% | 30 | fido_assert_reset_tx 1 0 100.00% 15 0 100.00% |
31 | fido_assert_reset_rx 6 1 83.33% 24 3 87.50% | 31 | fido_assert_reset_rx 6 0 100.00% 24 0 100.00% |
32 | fido_assert_free 6 0 100.00% 13 0 100.00% | 32 | fido_assert_free 6 0 100.00% 13 0 100.00% |
33 | fido_assert_count 1 0 100.00% 3 0 100.00% | 33 | fido_assert_count 1 0 100.00% 3 0 100.00% |
34 | fido_assert_rp_id 1 0 100.00% 3 0 100.00% | 34 | fido_assert_rp_id 1 0 100.00% 3 0 100.00% |
@@ -48,22 +48,22 @@ fido_assert_user_display_name 4 0 100.00% 6 0 | |||
48 | fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% | 48 | fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% |
49 | fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% | 49 | fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% |
50 | fido_assert_set_authdata 24 0 100.00% 35 0 100.00% | 50 | fido_assert_set_authdata 24 0 100.00% 35 0 100.00% |
51 | fido_assert_set_authdata_raw 24 4 83.33% 34 7 79.41% | 51 | fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00% |
52 | fido_assert_set_sig 14 0 100.00% 17 0 100.00% | 52 | fido_assert_set_sig 14 0 100.00% 17 0 100.00% |
53 | fido_assert_set_count 10 0 100.00% 21 0 100.00% | 53 | fido_assert_set_count 10 0 100.00% 21 0 100.00% |
54 | assert.c:fido_dev_get_assert_wait 21 1 95.24% 16 2 87.50% | 54 | assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00% |
55 | assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% | 55 | assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% |
56 | assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00% | 56 | assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00% |
57 | assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% | 57 | assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% |
58 | assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% | 58 | assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% |
59 | assert.c:fido_get_next_assert_tx 8 2 75.00% 10 3 70.00% | 59 | assert.c:fido_get_next_assert_tx 8 0 100.00% 10 0 100.00% |
60 | assert.c:fido_get_next_assert_rx 15 4 73.33% 26 7 73.08% | 60 | assert.c:fido_get_next_assert_rx 15 2 86.67% 26 4 84.62% |
61 | assert.c:decrypt_hmac_secrets 9 3 66.67% 15 7 53.33% | 61 | assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00% |
62 | assert.c:check_extensions 4 0 100.00% 9 0 100.00% | 62 | assert.c:check_extensions 4 0 100.00% 9 0 100.00% |
63 | assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% | 63 | assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% |
64 | assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% | 64 | assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% |
65 | --------------------------------------------------------------------------------------- | 65 | --------------------------------------------------------------------------------------- |
66 | TOTAL 566 43 92.40% 900 87 90.33% | 66 | TOTAL 566 24 95.76% 900 50 94.44% |
67 | 67 | ||
68 | File '/libfido2/src/authkey.c': | 68 | File '/libfido2/src/authkey.c': |
69 | Name Regions Miss Cover Lines Miss Cover | 69 | Name Regions Miss Cover Lines Miss Cover |
@@ -135,14 +135,14 @@ File '/libfido2/src/blob.c': | |||
135 | Name Regions Miss Cover Lines Miss Cover | 135 | Name Regions Miss Cover Lines Miss Cover |
136 | --------------------------------------------------------------------------------------- | 136 | --------------------------------------------------------------------------------------- |
137 | fido_blob_new 1 0 100.00% 3 0 100.00% | 137 | fido_blob_new 1 0 100.00% 3 0 100.00% |
138 | fido_blob_set 11 1 90.91% 25 4 84.00% | 138 | fido_blob_set 11 0 100.00% 25 0 100.00% |
139 | fido_blob_free 8 0 100.00% 16 0 100.00% | 139 | fido_blob_free 8 0 100.00% 16 0 100.00% |
140 | fido_free_blob_array 9 0 100.00% 17 0 100.00% | 140 | fido_free_blob_array 9 0 100.00% 17 0 100.00% |
141 | fido_blob_encode 6 0 100.00% 6 0 100.00% | 141 | fido_blob_encode 6 0 100.00% 6 0 100.00% |
142 | fido_blob_decode 1 0 100.00% 3 0 100.00% | 142 | fido_blob_decode 1 0 100.00% 3 0 100.00% |
143 | fido_blob_is_empty 3 0 100.00% 3 0 100.00% | 143 | fido_blob_is_empty 3 0 100.00% 3 0 100.00% |
144 | --------------------------------------------------------------------------------------- | 144 | --------------------------------------------------------------------------------------- |
145 | TOTAL 39 1 97.44% 73 4 94.52% | 145 | TOTAL 39 0 100.00% 73 0 100.00% |
146 | 146 | ||
147 | File '/libfido2/src/buf.c': | 147 | File '/libfido2/src/buf.c': |
148 | Name Regions Miss Cover Lines Miss Cover | 148 | Name Regions Miss Cover Lines Miss Cover |
@@ -155,7 +155,7 @@ TOTAL 8 1 87.50% 20 1 | |||
155 | File '/libfido2/src/cbor.c': | 155 | File '/libfido2/src/cbor.c': |
156 | Name Regions Miss Cover Lines Miss Cover | 156 | Name Regions Miss Cover Lines Miss Cover |
157 | --------------------------------------------------------------------------------------- | 157 | --------------------------------------------------------------------------------------- |
158 | cbor_map_iter 20 0 100.00% 30 0 100.00% | 158 | cbor_map_iter 20 1 95.00% 30 4 86.67% |
159 | cbor_array_iter 12 0 100.00% 20 0 100.00% | 159 | cbor_array_iter 12 0 100.00% 20 0 100.00% |
160 | cbor_parse_reply 27 0 100.00% 43 0 100.00% | 160 | cbor_parse_reply 27 0 100.00% 43 0 100.00% |
161 | cbor_vector_free 6 0 100.00% 5 0 100.00% | 161 | cbor_vector_free 6 0 100.00% 5 0 100.00% |
@@ -168,23 +168,23 @@ cbor_flatten_vector 14 1 92.86% 21 1 | |||
168 | cbor_build_frame 15 0 100.00% 32 0 100.00% | 168 | cbor_build_frame 15 0 100.00% 32 0 100.00% |
169 | cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% | 169 | cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% |
170 | cbor_encode_user_entity 21 0 100.00% 18 0 100.00% | 170 | cbor_encode_user_entity 21 0 100.00% 18 0 100.00% |
171 | cbor_encode_pubkey_param 36 1 97.22% 48 0 100.00% | 171 | cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00% |
172 | cbor_encode_pubkey 10 0 100.00% 13 0 100.00% | 172 | cbor_encode_pubkey 10 0 100.00% 13 0 100.00% |
173 | cbor_encode_pubkey_list 18 1 94.44% 23 0 100.00% | 173 | cbor_encode_pubkey_list 18 0 100.00% 23 0 100.00% |
174 | cbor_encode_extensions 24 2 91.67% 26 3 88.46% | 174 | cbor_encode_extensions 28 0 100.00% 28 0 100.00% |
175 | cbor_encode_options 13 0 100.00% 14 0 100.00% | 175 | cbor_encode_options 13 0 100.00% 14 0 100.00% |
176 | cbor_encode_assert_options 13 0 100.00% 14 0 100.00% | 176 | cbor_encode_assert_options 13 0 100.00% 14 0 100.00% |
177 | cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% | 177 | cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% |
178 | cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% | 178 | cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% |
179 | cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% | 179 | cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% |
180 | cbor_encode_change_pin_auth 44 1 97.73% 69 3 95.65% | 180 | cbor_encode_change_pin_auth 39 0 100.00% 60 0 100.00% |
181 | cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% | 181 | cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% |
182 | cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% | 182 | cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% |
183 | cbor_encode_hmac_secret_param 41 2 95.12% 66 9 86.36% | 183 | cbor_encode_hmac_secret_param 41 1 97.56% 66 4 93.94% |
184 | cbor_decode_fmt 9 0 100.00% 18 0 100.00% | 184 | cbor_decode_fmt 9 0 100.00% 18 0 100.00% |
185 | cbor_decode_pubkey 21 6 71.43% 32 7 78.12% | 185 | cbor_decode_pubkey 21 1 95.24% 32 2 93.75% |
186 | cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00% | 186 | cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00% |
187 | cbor_decode_assert_authdata 23 2 91.30% 44 2 95.45% | 187 | cbor_decode_assert_authdata 23 0 100.00% 44 0 100.00% |
188 | cbor_decode_attstmt 8 0 100.00% 10 0 100.00% | 188 | cbor_decode_attstmt 8 0 100.00% 10 0 100.00% |
189 | cbor_decode_uint64 4 0 100.00% 10 0 100.00% | 189 | cbor_decode_uint64 4 0 100.00% 10 0 100.00% |
190 | cbor_decode_cred_id 8 0 100.00% 10 0 100.00% | 190 | cbor_decode_cred_id 8 0 100.00% 10 0 100.00% |
@@ -193,30 +193,30 @@ cbor_decode_rp_entity 8 0 100.00% 10 0 | |||
193 | cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% | 193 | cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% |
194 | cbor.c:check_key_type 8 0 100.00% 9 0 100.00% | 194 | cbor.c:check_key_type 8 0 100.00% 9 0 100.00% |
195 | cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% | 195 | cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% |
196 | cbor.c:cbor_add_uint8 14 1 92.86% 26 3 88.46% | 196 | cbor.c:cbor_add_uint8 14 0 100.00% 26 0 100.00% |
197 | cbor.c:sha256 7 0 100.00% 15 0 100.00% | 197 | cbor.c:sha256 7 0 100.00% 15 0 100.00% |
198 | cbor.c:get_cose_alg 36 6 83.33% 48 6 87.50% | 198 | cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00% |
199 | cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% | 199 | cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% |
200 | cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% | 200 | cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% |
201 | cbor.c:decode_extensions 14 9 35.71% 34 13 61.76% | 201 | cbor.c:decode_extensions 14 0 100.00% 34 0 100.00% |
202 | cbor.c:decode_extension 27 27 0.00% 36 36 0.00% | 202 | cbor.c:decode_extension 27 2 92.59% 36 6 83.33% |
203 | cbor.c:decode_hmac_secret 16 4 75.00% 32 6 81.25% | 203 | cbor.c:decode_hmac_secret 16 0 100.00% 32 0 100.00% |
204 | cbor.c:decode_hmac_secret_aux 7 7 0.00% 17 17 0.00% | 204 | cbor.c:decode_hmac_secret_aux 7 0 100.00% 17 0 100.00% |
205 | cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00% | 205 | cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00% |
206 | cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% | 206 | cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% |
207 | cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% | 207 | cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% |
208 | cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% | 208 | cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% |
209 | cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% | 209 | cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% |
210 | --------------------------------------------------------------------------------------- | 210 | --------------------------------------------------------------------------------------- |
211 | TOTAL 884 70 92.08% 1371 106 92.27% | 211 | TOTAL 883 6 99.32% 1364 17 98.75% |
212 | 212 | ||
213 | File '/libfido2/src/cred.c': | 213 | File '/libfido2/src/cred.c': |
214 | Name Regions Miss Cover Lines Miss Cover | 214 | Name Regions Miss Cover Lines Miss Cover |
215 | --------------------------------------------------------------------------------------- | 215 | --------------------------------------------------------------------------------------- |
216 | fido_dev_make_cred 12 0 100.00% 10 0 100.00% | 216 | fido_dev_make_cred 12 0 100.00% 10 0 100.00% |
217 | fido_check_rp_id 4 0 100.00% 14 0 100.00% | 217 | fido_check_rp_id 4 0 100.00% 14 0 100.00% |
218 | fido_cred_verify 46 6 86.96% 71 11 84.51% | 218 | fido_cred_verify 46 2 95.65% 71 3 95.77% |
219 | fido_cred_verify_self 54 14 74.07% 90 22 75.56% | 219 | fido_cred_verify_self 54 4 92.59% 90 5 94.44% |
220 | fido_cred_new 1 0 100.00% 3 0 100.00% | 220 | fido_cred_new 1 0 100.00% 3 0 100.00% |
221 | fido_cred_reset_tx 1 0 100.00% 20 0 100.00% | 221 | fido_cred_reset_tx 1 0 100.00% 20 0 100.00% |
222 | fido_cred_reset_rx 1 0 100.00% 8 0 100.00% | 222 | fido_cred_reset_rx 1 0 100.00% 8 0 100.00% |
@@ -227,15 +227,15 @@ fido_cred_set_x509 12 0 100.00% 16 0 | |||
227 | fido_cred_set_sig 12 0 100.00% 16 0 100.00% | 227 | fido_cred_set_sig 12 0 100.00% 16 0 100.00% |
228 | fido_cred_exclude 14 2 85.71% 25 3 88.00% | 228 | fido_cred_exclude 14 2 85.71% 25 3 88.00% |
229 | fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% | 229 | fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% |
230 | fido_cred_set_rp 18 2 88.89% 26 6 76.92% | 230 | fido_cred_set_rp 18 0 100.00% 26 0 100.00% |
231 | fido_cred_set_user 33 4 87.88% 50 13 74.00% | 231 | fido_cred_set_user 33 0 100.00% 50 0 100.00% |
232 | fido_cred_set_extensions 15 0 100.00% 12 0 100.00% | 232 | fido_cred_set_extensions 15 0 100.00% 12 0 100.00% |
233 | fido_cred_set_options 6 6 0.00% 6 6 0.00% | 233 | fido_cred_set_options 6 6 0.00% 6 6 0.00% |
234 | fido_cred_set_rk 2 0 100.00% 5 0 100.00% | 234 | fido_cred_set_rk 2 0 100.00% 5 0 100.00% |
235 | fido_cred_set_uv 2 0 100.00% 5 0 100.00% | 235 | fido_cred_set_uv 2 0 100.00% 5 0 100.00% |
236 | fido_cred_set_prot 21 2 90.48% 16 0 100.00% | 236 | fido_cred_set_prot 21 0 100.00% 16 0 100.00% |
237 | fido_cred_set_fmt 16 4 75.00% 15 1 93.33% | 237 | fido_cred_set_fmt 16 4 75.00% 15 1 93.33% |
238 | fido_cred_set_type 17 2 88.24% 9 1 88.89% | 238 | fido_cred_set_type 17 0 100.00% 9 0 100.00% |
239 | fido_cred_type 1 0 100.00% 3 0 100.00% | 239 | fido_cred_type 1 0 100.00% 3 0 100.00% |
240 | fido_cred_flags 1 0 100.00% 3 0 100.00% | 240 | fido_cred_flags 1 0 100.00% 3 0 100.00% |
241 | fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% | 241 | fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% |
@@ -246,10 +246,12 @@ fido_cred_sig_ptr 1 0 100.00% 3 0 | |||
246 | fido_cred_sig_len 1 0 100.00% 3 0 100.00% | 246 | fido_cred_sig_len 1 0 100.00% 3 0 100.00% |
247 | fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% | 247 | fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% |
248 | fido_cred_authdata_len 1 0 100.00% 3 0 100.00% | 248 | fido_cred_authdata_len 1 0 100.00% 3 0 100.00% |
249 | fido_cred_pubkey_ptr 9 2 77.78% 20 2 90.00% | 249 | fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00% |
250 | fido_cred_pubkey_len 9 2 77.78% 20 2 90.00% | 250 | fido_cred_pubkey_len 9 0 100.00% 20 0 100.00% |
251 | fido_cred_id_ptr 1 0 100.00% 3 0 100.00% | 251 | fido_cred_id_ptr 1 0 100.00% 3 0 100.00% |
252 | fido_cred_id_len 1 0 100.00% 3 0 100.00% | 252 | fido_cred_id_len 1 0 100.00% 3 0 100.00% |
253 | fido_cred_aaguid_ptr 1 0 100.00% 3 0 100.00% | ||
254 | fido_cred_aaguid_len 1 0 100.00% 3 0 100.00% | ||
253 | fido_cred_prot 1 0 100.00% 3 0 100.00% | 255 | fido_cred_prot 1 0 100.00% 3 0 100.00% |
254 | fido_cred_fmt 1 0 100.00% 3 0 100.00% | 256 | fido_cred_fmt 1 0 100.00% 3 0 100.00% |
255 | fido_cred_rp_id 1 0 100.00% 3 0 100.00% | 257 | fido_cred_rp_id 1 0 100.00% 3 0 100.00% |
@@ -269,7 +271,7 @@ cred.c:fido_cred_clean_authdata 1 0 100.00% 9 0 | |||
269 | cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% | 271 | cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% |
270 | cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% | 272 | cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% |
271 | --------------------------------------------------------------------------------------- | 273 | --------------------------------------------------------------------------------------- |
272 | TOTAL 534 51 90.45% 830 78 90.60% | 274 | TOTAL 536 23 95.71% 836 29 96.53% |
273 | 275 | ||
274 | File '/libfido2/src/credman.c': | 276 | File '/libfido2/src/credman.c': |
275 | Name Regions Miss Cover Lines Miss Cover | 277 | Name Regions Miss Cover Lines Miss Cover |
@@ -295,14 +297,14 @@ fido_credman_rp_id_hash_len 4 0 100.00% 6 0 | |||
295 | fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% | 297 | fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% |
296 | credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% | 298 | credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% |
297 | credman.c:credman_tx 30 0 100.00% 53 0 100.00% | 299 | credman.c:credman_tx 30 0 100.00% 53 0 100.00% |
298 | credman.c:credman_prepare_hmac 21 1 95.24% 43 2 95.35% | 300 | credman.c:credman_prepare_hmac 21 1 95.24% 43 3 93.02% |
299 | credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00% | 301 | credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00% |
300 | credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% | 302 | credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% |
301 | credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% | 303 | credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% |
302 | credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00% | 304 | credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00% |
303 | credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% | 305 | credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% |
304 | credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% | 306 | credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% |
305 | credman.c:credman_parse_rk 13 0 100.00% 25 0 100.00% | 307 | credman.c:credman_parse_rk 22 0 100.00% 31 0 100.00% |
306 | credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62% | 308 | credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62% |
307 | credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% | 309 | credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% |
308 | credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% | 310 | credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% |
@@ -313,7 +315,7 @@ credman.c:credman_rx_next_rp 15 2 86.67% 26 4 | |||
313 | credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% | 315 | credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% |
314 | credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% | 316 | credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% |
315 | --------------------------------------------------------------------------------------- | 317 | --------------------------------------------------------------------------------------- |
316 | TOTAL 376 18 95.21% 589 15 97.45% | 318 | TOTAL 385 18 95.32% 595 16 97.31% |
317 | 319 | ||
318 | File '/libfido2/src/dev.c': | 320 | File '/libfido2/src/dev.c': |
319 | Name Regions Miss Cover Lines Miss Cover | 321 | Name Regions Miss Cover Lines Miss Cover |
@@ -324,9 +326,11 @@ fido_dev_info_manifest 17 17 0.00% 24 24 | |||
324 | fido_dev_open_with_info 5 5 0.00% 6 6 0.00% | 326 | fido_dev_open_with_info 5 5 0.00% 6 6 0.00% |
325 | fido_dev_open 1 0 100.00% 3 0 100.00% | 327 | fido_dev_open 1 0 100.00% 3 0 100.00% |
326 | fido_dev_close 8 2 75.00% 9 0 100.00% | 328 | fido_dev_close 8 2 75.00% 9 0 100.00% |
327 | fido_dev_cancel 7 0 100.00% 6 0 100.00% | 329 | fido_dev_cancel 11 0 100.00% 9 0 100.00% |
328 | fido_dev_set_io_functions 18 4 77.78% 16 6 62.50% | 330 | fido_dev_get_touch_begin 50 0 100.00% 68 0 100.00% |
329 | fido_dev_set_transport_functions 6 6 0.00% 10 10 0.00% | 331 | fido_dev_get_touch_status 17 0 100.00% 25 0 100.00% |
332 | fido_dev_set_io_functions 18 4 77.78% 17 6 64.71% | ||
333 | fido_dev_set_transport_functions 6 6 0.00% 11 11 0.00% | ||
330 | fido_init 7 1 85.71% 4 0 100.00% | 334 | fido_init 7 1 85.71% 4 0 100.00% |
331 | fido_dev_new 5 0 100.00% 16 0 100.00% | 335 | fido_dev_new 5 0 100.00% 16 0 100.00% |
332 | fido_dev_new_with_info 17 17 0.00% 26 26 0.00% | 336 | fido_dev_new_with_info 17 17 0.00% 26 26 0.00% |
@@ -337,15 +341,20 @@ fido_dev_minor 1 0 100.00% 3 0 | |||
337 | fido_dev_build 1 0 100.00% 3 0 100.00% | 341 | fido_dev_build 1 0 100.00% 3 0 100.00% |
338 | fido_dev_flags 1 0 100.00% 3 0 100.00% | 342 | fido_dev_flags 1 0 100.00% 3 0 100.00% |
339 | fido_dev_is_fido2 2 0 100.00% 3 0 100.00% | 343 | fido_dev_is_fido2 2 0 100.00% 3 0 100.00% |
340 | fido_dev_force_u2f 2 0 100.00% 3 0 100.00% | 344 | fido_dev_supports_pin 3 0 100.00% 3 0 100.00% |
345 | fido_dev_has_pin 2 0 100.00% 3 0 100.00% | ||
346 | fido_dev_supports_cred_prot 2 0 100.00% 3 0 100.00% | ||
347 | fido_dev_force_u2f 2 0 100.00% 4 0 100.00% | ||
341 | fido_dev_force_fido2 2 2 0.00% 3 3 0.00% | 348 | fido_dev_force_fido2 2 2 0.00% 3 3 0.00% |
342 | dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00% | 349 | dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00% |
343 | dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% | 350 | dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% |
344 | dev.c:fido_dev_open_tx 25 8 68.00% 32 12 62.50% | 351 | dev.c:fido_dev_open_tx 51 13 74.51% 63 23 63.49% |
345 | dev.c:obtain_nonce 4 1 75.00% 5 1 80.00% | 352 | dev.c:obtain_nonce 4 1 75.00% 5 1 80.00% |
346 | dev.c:fido_dev_open_rx 32 0 100.00% 53 0 100.00% | 353 | dev.c:set_random_report_len 11 0 100.00% 6 0 100.00% |
354 | dev.c:fido_dev_open_rx 33 0 100.00% 56 0 100.00% | ||
355 | dev.c:fido_dev_set_flags 17 0 100.00% 24 0 100.00% | ||
347 | --------------------------------------------------------------------------------------- | 356 | --------------------------------------------------------------------------------------- |
348 | TOTAL 201 85 57.71% 294 128 56.46% | 357 | TOTAL 334 90 73.05% 466 140 69.96% |
349 | 358 | ||
350 | File '/libfido2/src/ecdh.c': | 359 | File '/libfido2/src/ecdh.c': |
351 | Name Regions Miss Cover Lines Miss Cover | 360 | Name Regions Miss Cover Lines Miss Cover |
@@ -372,9 +381,9 @@ TOTAL 54 0 100.00% 79 0 | |||
372 | File '/libfido2/src/err.c': | 381 | File '/libfido2/src/err.c': |
373 | Name Regions Miss Cover Lines Miss Cover | 382 | Name Regions Miss Cover Lines Miss Cover |
374 | --------------------------------------------------------------------------------------- | 383 | --------------------------------------------------------------------------------------- |
375 | fido_strerr 108 108 0.00% 112 112 0.00% | 384 | fido_strerr 112 8 92.86% 116 8 93.10% |
376 | --------------------------------------------------------------------------------------- | 385 | --------------------------------------------------------------------------------------- |
377 | TOTAL 108 108 0.00% 112 112 0.00% | 386 | TOTAL 112 8 92.86% 116 8 93.10% |
378 | 387 | ||
379 | File '/libfido2/src/es256.c': | 388 | File '/libfido2/src/es256.c': |
380 | Name Regions Miss Cover Lines Miss Cover | 389 | Name Regions Miss Cover Lines Miss Cover |
@@ -389,14 +398,14 @@ es256_pk_from_ptr 11 0 100.00% 13 0 | |||
389 | es256_pk_set_x 1 0 100.00% 5 0 100.00% | 398 | es256_pk_set_x 1 0 100.00% 5 0 100.00% |
390 | es256_pk_set_y 1 0 100.00% 5 0 100.00% | 399 | es256_pk_set_y 1 0 100.00% 5 0 100.00% |
391 | es256_sk_create 39 0 100.00% 46 0 100.00% | 400 | es256_sk_create 39 0 100.00% 46 0 100.00% |
392 | es256_pk_to_EVP_PKEY 41 0 100.00% 58 0 100.00% | 401 | es256_pk_to_EVP_PKEY 42 0 100.00% 66 0 100.00% |
393 | es256_pk_from_EC_KEY 38 0 100.00% 39 0 100.00% | 402 | es256_pk_from_EC_KEY 38 0 100.00% 43 0 100.00% |
394 | es256_sk_to_EVP_PKEY 27 0 100.00% 41 0 100.00% | 403 | es256_sk_to_EVP_PKEY 28 0 100.00% 50 0 100.00% |
395 | es256_derive_pk 25 0 100.00% 34 0 100.00% | 404 | es256_derive_pk 25 0 100.00% 34 0 100.00% |
396 | es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% | 405 | es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% |
397 | es256.c:decode_coord 8 0 100.00% 12 0 100.00% | 406 | es256.c:decode_coord 8 0 100.00% 12 0 100.00% |
398 | --------------------------------------------------------------------------------------- | 407 | --------------------------------------------------------------------------------------- |
399 | TOTAL 278 0 100.00% 377 0 100.00% | 408 | TOTAL 280 0 100.00% 398 0 100.00% |
400 | 409 | ||
401 | File '/libfido2/src/extern.h': | 410 | File '/libfido2/src/extern.h': |
402 | Name Regions Miss Cover Lines Miss Cover | 411 | Name Regions Miss Cover Lines Miss Cover |
@@ -423,20 +432,27 @@ TOTAL 16 16 0.00% 38 38 | |||
423 | File '/libfido2/src/hid_linux.c': | 432 | File '/libfido2/src/hid_linux.c': |
424 | Name Regions Miss Cover Lines Miss Cover | 433 | Name Regions Miss Cover Lines Miss Cover |
425 | --------------------------------------------------------------------------------------- | 434 | --------------------------------------------------------------------------------------- |
426 | fido_hid_manifest 33 33 0.00% 46 46 0.00% | 435 | fido_hid_manifest 35 35 0.00% 50 50 0.00% |
427 | fido_hid_open 6 6 0.00% 11 11 0.00% | 436 | fido_hid_open 17 17 0.00% 22 22 0.00% |
428 | fido_hid_close 1 1 0.00% 6 6 0.00% | 437 | fido_hid_close 1 1 0.00% 6 6 0.00% |
429 | fido_hid_read 12 12 0.00% 16 16 0.00% | 438 | fido_hid_read 12 12 0.00% 21 21 0.00% |
430 | fido_hid_write 12 12 0.00% 16 16 0.00% | 439 | fido_hid_write 9 9 0.00% 16 16 0.00% |
431 | hid_linux.c:copy_info 35 35 0.00% 56 56 0.00% | 440 | fido_hid_report_in_len 1 1 0.00% 5 5 0.00% |
432 | hid_linux.c:is_fido 6 6 0.00% 14 14 0.00% | 441 | fido_hid_report_out_len 1 1 0.00% 5 5 0.00% |
433 | hid_linux.c:get_report_descriptor 17 17 0.00% 30 30 0.00% | 442 | hid_linux.c:copy_info 30 30 0.00% 52 52 0.00% |
434 | hid_linux.c:get_usage_info 16 16 0.00% 33 33 0.00% | 443 | hid_linux.c:is_fido 9 9 0.00% 23 23 0.00% |
444 | hid_linux.c:get_usage_info 16 16 0.00% 30 30 0.00% | ||
435 | hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% | 445 | hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% |
436 | hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% | 446 | hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% |
437 | hid_linux.c:parse_uevent 16 16 0.00% 30 30 0.00% | 447 | hid_linux.c:get_parent_attr 6 6 0.00% 11 11 0.00% |
438 | --------------------------------------------------------------------------------------- | 448 | hid_linux.c:parse_uevent 12 12 0.00% 28 28 0.00% |
439 | TOTAL 166 166 0.00% 292 292 0.00% | 449 | hid_linux.c:get_usb_attr 1 1 0.00% 3 3 0.00% |
450 | hid_linux.c:get_report_descriptor 11 11 0.00% 18 18 0.00% | ||
451 | hid_linux.c:get_report_sizes 19 19 0.00% 33 33 0.00% | ||
452 | hid_linux.c:waitfd 28 28 0.00% 43 43 0.00% | ||
453 | hid_linux.c:timespec_to_ms 15 15 0.00% 16 16 0.00% | ||
454 | --------------------------------------------------------------------------------------- | ||
455 | TOTAL 235 235 0.00% 416 416 0.00% | ||
440 | 456 | ||
441 | File '/libfido2/src/info.c': | 457 | File '/libfido2/src/info.c': |
442 | Name Regions Miss Cover Lines Miss Cover | 458 | Name Regions Miss Cover Lines Miss Cover |
@@ -455,11 +471,14 @@ fido_cbor_info_options_name_ptr 1 0 100.00% 3 0 | |||
455 | fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% | 471 | fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% |
456 | fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% | 472 | fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% |
457 | fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% | 473 | fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% |
474 | fido_cbor_info_maxcredcntlst 1 0 100.00% 3 0 100.00% | ||
475 | fido_cbor_info_maxcredidlen 1 0 100.00% 3 0 100.00% | ||
476 | fido_cbor_info_fwversion 1 0 100.00% 3 0 100.00% | ||
458 | fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% | 477 | fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% |
459 | fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% | 478 | fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% |
460 | info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00% | 479 | info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00% |
461 | info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00% | 480 | info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00% |
462 | info.c:parse_reply_element 13 0 100.00% 27 0 100.00% | 481 | info.c:parse_reply_element 16 0 100.00% 33 0 100.00% |
463 | info.c:decode_versions 12 0 100.00% 21 0 100.00% | 482 | info.c:decode_versions 12 0 100.00% 21 0 100.00% |
464 | info.c:decode_version 4 0 100.00% 14 0 100.00% | 483 | info.c:decode_version 4 0 100.00% 14 0 100.00% |
465 | info.c:decode_extensions 12 0 100.00% 21 0 100.00% | 484 | info.c:decode_extensions 12 0 100.00% 21 0 100.00% |
@@ -473,23 +492,23 @@ info.c:free_str_array 4 0 100.00% 8 0 | |||
473 | info.c:free_opt_array 4 0 100.00% 9 0 100.00% | 492 | info.c:free_opt_array 4 0 100.00% 9 0 100.00% |
474 | info.c:free_byte_array 1 0 100.00% 6 0 100.00% | 493 | info.c:free_byte_array 1 0 100.00% 6 0 100.00% |
475 | --------------------------------------------------------------------------------------- | 494 | --------------------------------------------------------------------------------------- |
476 | TOTAL 146 0 100.00% 304 0 100.00% | 495 | TOTAL 152 0 100.00% 319 0 100.00% |
477 | 496 | ||
478 | File '/libfido2/src/io.c': | 497 | File '/libfido2/src/io.c': |
479 | Name Regions Miss Cover Lines Miss Cover | 498 | Name Regions Miss Cover Lines Miss Cover |
480 | --------------------------------------------------------------------------------------- | 499 | --------------------------------------------------------------------------------------- |
481 | fido_tx 14 1 92.86% 18 0 100.00% | 500 | fido_tx 13 1 92.31% 14 0 100.00% |
482 | fido_rx 13 2 84.62% 21 3 85.71% | 501 | fido_rx 13 2 84.62% 19 3 84.21% |
483 | fido_rx_cbor_status 8 0 100.00% 12 0 100.00% | 502 | fido_rx_cbor_status 8 0 100.00% 12 0 100.00% |
484 | io.c:tx_empty 7 0 100.00% 16 0 100.00% | 503 | io.c:tx_empty 9 0 100.00% 17 0 100.00% |
485 | io.c:tx 13 0 100.00% 21 0 100.00% | 504 | io.c:tx 13 0 100.00% 21 0 100.00% |
486 | io.c:tx_preamble 10 0 100.00% 20 0 100.00% | 505 | io.c:tx_preamble 16 1 93.75% 24 1 95.83% |
487 | io.c:tx_frame 9 0 100.00% 18 0 100.00% | 506 | io.c:tx_frame 15 1 93.33% 22 1 95.45% |
488 | io.c:rx 25 1 96.00% 58 4 93.10% | 507 | io.c:rx 40 2 95.00% 68 1 98.53% |
489 | io.c:rx_preamble 18 1 94.44% 25 4 84.00% | 508 | io.c:rx_preamble 21 2 90.48% 28 5 82.14% |
490 | io.c:rx_frame 6 0 100.00% 9 0 100.00% | 509 | io.c:rx_frame 8 0 100.00% 11 0 100.00% |
491 | --------------------------------------------------------------------------------------- | 510 | --------------------------------------------------------------------------------------- |
492 | TOTAL 123 5 95.93% 218 11 94.95% | 511 | TOTAL 156 9 94.23% 236 11 95.34% |
493 | 512 | ||
494 | File '/libfido2/src/iso7816.c': | 513 | File '/libfido2/src/iso7816.c': |
495 | Name Regions Miss Cover Lines Miss Cover | 514 | Name Regions Miss Cover Lines Miss Cover |
@@ -547,32 +566,34 @@ TOTAL 19 0 100.00% 22 0 | |||
547 | File '/libfido2/src/rs256.c': | 566 | File '/libfido2/src/rs256.c': |
548 | Name Regions Miss Cover Lines Miss Cover | 567 | Name Regions Miss Cover Lines Miss Cover |
549 | --------------------------------------------------------------------------------------- | 568 | --------------------------------------------------------------------------------------- |
550 | rs256_pk_decode 8 8 0.00% 10 10 0.00% | 569 | rs256_pk_decode 8 0 100.00% 10 0 100.00% |
551 | rs256_pk_new 1 0 100.00% 3 0 100.00% | 570 | rs256_pk_new 1 0 100.00% 3 0 100.00% |
552 | rs256_pk_free 6 0 100.00% 11 0 100.00% | 571 | rs256_pk_free 6 0 100.00% 11 0 100.00% |
553 | rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% | 572 | rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% |
554 | rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% | 573 | rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% |
555 | rs256_pk_from_RSA 32 4 87.50% 32 6 81.25% | 574 | rs256_pk_from_RSA 32 4 87.50% 32 6 81.25% |
556 | rs256.c:decode_rsa_pubkey 9 9 0.00% 16 16 0.00% | 575 | rs256.c:decode_rsa_pubkey 9 1 88.89% 16 4 75.00% |
557 | rs256.c:decode_bignum 8 8 0.00% 12 12 0.00% | 576 | rs256.c:decode_bignum 8 1 87.50% 12 3 75.00% |
558 | --------------------------------------------------------------------------------------- | 577 | --------------------------------------------------------------------------------------- |
559 | TOTAL 102 29 71.57% 140 44 68.57% | 578 | TOTAL 102 6 94.12% 140 13 90.71% |
560 | 579 | ||
561 | File '/libfido2/src/u2f.c': | 580 | File '/libfido2/src/u2f.c': |
562 | Name Regions Miss Cover Lines Miss Cover | 581 | Name Regions Miss Cover Lines Miss Cover |
563 | --------------------------------------------------------------------------------------- | 582 | --------------------------------------------------------------------------------------- |
564 | u2f_register 70 5 92.86% 88 7 92.05% | 583 | u2f_register 70 1 98.57% 88 0 100.00% |
565 | u2f_authenticate 32 4 87.50% 44 2 95.45% | 584 | u2f_authenticate 32 0 100.00% 44 0 100.00% |
585 | u2f_get_touch_begin 30 0 100.00% 46 0 100.00% | ||
586 | u2f_get_touch_status 18 0 100.00% 29 0 100.00% | ||
566 | u2f.c:key_lookup 44 0 100.00% 69 0 100.00% | 587 | u2f.c:key_lookup 44 0 100.00% 69 0 100.00% |
567 | u2f.c:send_dummy_register 31 5 83.87% 49 8 83.67% | 588 | u2f.c:send_dummy_register 31 1 96.77% 49 0 100.00% |
568 | u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% | 589 | u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% |
569 | u2f.c:x5c_get 21 2 90.48% 37 6 83.78% | 590 | u2f.c:x5c_get 21 1 95.24% 37 3 91.89% |
570 | u2f.c:sig_get 8 1 87.50% 16 6 62.50% | 591 | u2f.c:sig_get 8 1 87.50% 16 6 62.50% |
571 | u2f.c:encode_cred_authdata 37 3 91.89% 82 9 89.02% | 592 | u2f.c:encode_cred_authdata 37 2 94.59% 82 6 92.68% |
572 | u2f.c:cbor_blob_from_ec_point 22 1 95.45% 39 3 92.31% | 593 | u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00% |
573 | u2f.c:u2f_authenticate_single 36 2 94.44% 58 4 93.10% | 594 | u2f.c:u2f_authenticate_single 36 0 100.00% 58 0 100.00% |
574 | u2f.c:do_auth 50 3 94.00% 71 4 94.37% | 595 | u2f.c:do_auth 50 1 98.00% 71 0 100.00% |
575 | u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% | 596 | u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% |
576 | u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% | 597 | u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% |
577 | --------------------------------------------------------------------------------------- | 598 | --------------------------------------------------------------------------------------- |
578 | TOTAL 443 28 93.68% 699 52 92.56% | 599 | TOTAL 491 9 98.17% 774 18 97.67% |
diff --git a/fuzz/fuzz_assert.c b/fuzz/fuzz_assert.c index 5b72658..3ae54eb 100644 --- a/fuzz/fuzz_assert.c +++ b/fuzz/fuzz_assert.c | |||
@@ -23,39 +23,23 @@ | |||
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. */ |
43 | struct param { | 27 | struct 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 | ||
86 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 70 | struct param * |
87 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 71 | unpack(const uint8_t *ptr, size_t len) |
88 | |||
89 | static int | ||
90 | unpack(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; | ||
105 | fail: | ||
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 | ||
114 | static size_t | 117 | size_t |
115 | pack(uint8_t *ptr, size_t len, const struct param *p) | 118 | pack(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); | ||
155 | fail: | ||
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 | ||
139 | static size_t | 168 | size_t |
140 | input_len(int max) | 169 | pack_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 | ||
146 | static void | 210 | static void |
147 | get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, | 211 | get_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 | ||
265 | int | 353 | void |
266 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 354 | test(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 | ||
372 | static size_t | 450 | void |
373 | pack_dummy(uint8_t *ptr, size_t len) | 451 | mutate(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); | |
415 | size_t | 477 | } else { |
416 | LLVMFuzzerCustomMutator(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. */ |
33 | struct param { | 23 | struct 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 | ||
103 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 93 | struct param * |
104 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 94 | unpack(const uint8_t *ptr, size_t len) |
105 | |||
106 | static int | ||
107 | unpack(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; | ||
122 | fail: | ||
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 | ||
125 | static size_t | 134 | size_t |
126 | pack(uint8_t *ptr, size_t len, const struct param *p) | 135 | pack(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); | ||
166 | fail: | ||
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 | ||
144 | static size_t | 179 | size_t |
145 | input_len(int max) | 180 | pack_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 | ||
150 | static fido_dev_t * | 222 | static fido_dev_t * |
151 | prepare_dev() | 223 | prepare_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 | ||
172 | static void | 252 | static void |
173 | get_info(struct param *p) | 253 | get_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 | ||
219 | static void | 301 | static void |
220 | enroll(struct param *p) | 302 | enroll(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 | ||
254 | static void | 336 | static void |
255 | list(struct param *p) | 337 | list(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 | ||
282 | static void | 364 | static void |
283 | set_name(struct param *p) | 365 | set_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 | ||
308 | static void | 390 | static void |
309 | del(struct param *p) | 391 | del(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 | ||
333 | int | 417 | void |
334 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 418 | test(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 | ||
358 | static size_t | 431 | void |
359 | pack_dummy(uint8_t *ptr, size_t len) | 432 | mutate(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); | |
402 | size_t | 448 | mutate_blob(&p->remove_wire_data); |
403 | LLVMFuzzerCustomMutator(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. */ |
40 | struct param { | 22 | struct 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 | ||
89 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 71 | struct param * |
90 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 72 | unpack(const uint8_t *ptr, size_t len) |
91 | |||
92 | static int | ||
93 | unpack(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; | ||
108 | fail: | ||
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 | ||
119 | static size_t | 120 | size_t |
120 | pack(uint8_t *ptr, size_t len, const struct param *p) | 121 | pack(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); | ||
160 | fail: | ||
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 | ||
146 | static size_t | 173 | size_t |
147 | input_len(int max) | 174 | pack_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 | ||
153 | static void | 213 | static void |
154 | make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, | 214 | make_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 | ||
250 | int | 328 | static void |
251 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 329 | test_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 | ||
303 | static size_t | 367 | static void |
304 | pack_dummy(uint8_t *ptr, size_t len) | 368 | test_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); | 404 | void |
405 | test(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 | ||
344 | size_t | 415 | void |
345 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | 416 | mutate(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. */ |
32 | struct param { | 23 | struct 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 | ||
91 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 82 | struct param * |
92 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 83 | unpack(const uint8_t *ptr, size_t len) |
93 | |||
94 | static int | ||
95 | unpack(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; | ||
110 | fail: | ||
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 | ||
112 | static size_t | 122 | size_t |
113 | pack(uint8_t *ptr, size_t len, const struct param *p) | 123 | pack(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); | ||
153 | fail: | ||
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 | ||
130 | static size_t | 166 | size_t |
131 | input_len(int max) | 167 | pack_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 | ||
136 | static fido_dev_t * | 206 | static fido_dev_t * |
137 | prepare_dev() | 207 | prepare_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 | ||
158 | static void | 234 | static void |
159 | get_metadata(struct param *p) | 235 | get_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 | ||
189 | static void | 265 | static void |
190 | get_rp_list(struct param *p) | 266 | get_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 | ||
223 | static void | 299 | static void |
224 | get_rk_list(struct param *p) | 300 | get_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 | ||
267 | static void | 345 | static void |
268 | del_rk(struct param *p) | 346 | del_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 | ||
282 | int | 360 | void |
283 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 361 | test(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 | ||
306 | static size_t | 373 | void |
307 | pack_dummy(uint8_t *ptr, size_t len) | 374 | mutate(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); | |
347 | size_t | 390 | } |
348 | LLVMFuzzerCustomMutator(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 | |||
29 | struct param { | 20 | struct 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 | ||
40 | static const uint8_t dummy_reset_wire_data[] = { | 31 | static 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 | ||
75 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 66 | struct param * |
76 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 67 | unpack(const uint8_t *ptr, size_t len) |
77 | |||
78 | static int | ||
79 | unpack(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; | ||
94 | fail: | ||
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 | ||
96 | static size_t | 106 | size_t |
97 | pack(uint8_t *ptr, size_t len, const struct param *p) | 107 | pack(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); | ||
137 | fail: | ||
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 | ||
114 | static size_t | 150 | size_t |
115 | input_len(int max) | 151 | pack_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 | ||
120 | static fido_dev_t * | 191 | static fido_dev_t * |
121 | prepare_dev() | 192 | prepare_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 | ||
142 | static void | 213 | static void |
143 | dev_reset(struct param *p) | 214 | dev_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 | ||
157 | static void | 228 | static void |
158 | dev_get_cbor_info(struct param *p) | 229 | dev_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 | ||
224 | static void | 298 | static void |
225 | dev_set_pin(struct param *p) | 299 | dev_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 | ||
239 | static void | 313 | static void |
240 | dev_change_pin(struct param *p) | 314 | dev_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 | ||
254 | static void | 328 | static void |
255 | dev_get_retry_count(struct param *p) | 329 | dev_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 | ||
271 | int | 345 | void |
272 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 346 | test(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 | ||
296 | static size_t | 359 | void |
297 | pack_dummy(uint8_t *ptr, size_t len) | 360 | mutate(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); | |
338 | size_t | 375 | mutate_blob(&p->retry_wire_data); |
339 | LLVMFuzzerCustomMutator(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 | |||
18 | static bool debug; | ||
19 | static unsigned int flags = MUTATE_ALL; | ||
20 | static unsigned long long test_fail; | ||
21 | static unsigned long long test_total; | ||
22 | static unsigned long long mutate_fail; | ||
23 | static unsigned long long mutate_total; | ||
24 | |||
25 | int LLVMFuzzerInitialize(int *, char ***); | ||
26 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | ||
27 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | ||
28 | |||
29 | static int | ||
30 | save_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; | ||
67 | fail: | ||
68 | if (fd != -1) | ||
69 | close(fd); | ||
70 | free(buf); | ||
71 | free(p); | ||
72 | |||
73 | return status; | ||
74 | } | ||
75 | |||
76 | static void | ||
77 | parse_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 | |||
94 | int | ||
95 | LLVMFuzzerInitialize(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 | |||
114 | int | ||
115 | LLVMFuzzerTestOneInput(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 | |||
135 | size_t | ||
136 | LLVMFuzzerCustomMutator(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 | ||
16 | size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); | 18 | size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); |
17 | 19 | ||
18 | static uint8_t *wire_data_ptr = NULL; | 20 | static const uint8_t *wire_data_ptr = NULL; |
19 | static size_t wire_data_len = 0; | 21 | static size_t wire_data_len = 0; |
20 | 22 | ||
21 | size_t | 23 | size_t |
22 | xstrlen(const char *s) | 24 | xstrlen(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 | ||
30 | void | 32 | void |
@@ -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 | ||
46 | int | 52 | int |
47 | unpack_int(uint8_t t, uint8_t **ptr, size_t *len, int *v) NO_MSAN | 53 | unpack_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 | |||
74 | int | ||
75 | unpack_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 | |||
104 | int | ||
105 | unpack_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 | |||
132 | int | ||
133 | unpack_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 | ||
164 | int | 67 | int |
165 | pack_int(uint8_t t, uint8_t **ptr, size_t *len, int v) NO_MSAN | 68 | unpack_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 | ||
182 | int | 82 | int |
183 | pack_string(uint8_t t, uint8_t **ptr, size_t *len, const char *v) NO_MSAN | 83 | unpack_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 | ||
200 | int | 94 | int |
201 | pack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t v) NO_MSAN | 95 | unpack_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 | ||
218 | int | 106 | cbor_item_t * |
219 | pack_blob(uint8_t t, uint8_t **ptr, size_t *len, const struct blob *v) NO_MSAN | 107 | pack_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 | ||
236 | size_t | 115 | cbor_item_t * |
237 | len_int(void) | 116 | pack_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 | ||
242 | size_t | 121 | return cbor_build_bytestring((const unsigned char *)v, strlen(v)); |
243 | len_string(int max) | ||
244 | { | ||
245 | return ((sizeof(uint8_t) + sizeof(size_t)) + (max ? MAXSTR - 1 : 0)); | ||
246 | } | 122 | } |
247 | 123 | ||
248 | size_t | 124 | cbor_item_t * |
249 | len_byte(void) | 125 | pack_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 | ||
254 | size_t | 130 | cbor_item_t * |
255 | len_blob(int max) | 131 | pack_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 | ||
260 | void | 136 | void |
@@ -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 | ||
288 | void * | 164 | void * |
289 | dev_open(const char *path) | 165 | dev_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 | ||
296 | void | 172 | void |
@@ -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 | ||
325 | int | 201 | int |
326 | dev_write(void *handle, const unsigned char *ptr, size_t len) | 202 | dev_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 | ||
339 | void | 216 | void |
340 | set_wire_data(uint8_t *ptr, size_t len) | 217 | set_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 | |||
40 | struct blob { | 44 | struct blob { |
41 | uint8_t body[MAXBLOB]; | 45 | uint8_t body[MAXBLOB]; |
42 | size_t len; | 46 | size_t len; |
43 | }; | 47 | }; |
44 | 48 | ||
49 | struct param; | ||
50 | |||
51 | struct param *unpack(const uint8_t *, size_t); | ||
52 | size_t pack(uint8_t *, size_t, const struct param *); | ||
53 | size_t pack_dummy(uint8_t *, size_t); | ||
54 | void mutate(struct param *, unsigned int, unsigned int); | ||
55 | void test(const struct param *); | ||
56 | |||
45 | size_t xstrlen(const char *); | 57 | size_t xstrlen(const char *); |
46 | void consume(const void *, size_t); | 58 | void consume(const void *, size_t); |
47 | void consume_str(const char *); | 59 | void consume_str(const char *); |
48 | 60 | ||
49 | int unpack_blob(uint8_t, uint8_t **, size_t *, struct blob *); | 61 | int unpack_blob(cbor_item_t *, struct blob *); |
50 | int unpack_byte(uint8_t, uint8_t **, size_t *, uint8_t *); | 62 | int unpack_byte(cbor_item_t *, uint8_t *); |
51 | int unpack_int(uint8_t, uint8_t **, size_t *, int *); | 63 | int unpack_int(cbor_item_t *, int *); |
52 | int unpack_string(uint8_t, uint8_t **, size_t *, char *); | 64 | int unpack_string(cbor_item_t *, char *); |
53 | |||
54 | int pack_blob(uint8_t, uint8_t **, size_t *, const struct blob *); | ||
55 | int pack_byte(uint8_t, uint8_t **, size_t *, uint8_t); | ||
56 | int pack_int(uint8_t, uint8_t **, size_t *, int); | ||
57 | int pack_string(uint8_t, uint8_t **, size_t *, const char *); | ||
58 | 65 | ||
59 | size_t len_int(void); | 66 | cbor_item_t *pack_blob(const struct blob *); |
60 | size_t len_string(int); | 67 | cbor_item_t *pack_byte(uint8_t); |
61 | size_t len_byte(void); | 68 | cbor_item_t *pack_int(int); |
62 | size_t len_blob(int); | 69 | cbor_item_t *pack_string(const char *); |
63 | 70 | ||
64 | void mutate_byte(uint8_t *); | 71 | void mutate_byte(uint8_t *); |
65 | void mutate_int(int *); | 72 | void mutate_int(int *); |
66 | void mutate_blob(struct blob *); | 73 | void mutate_blob(struct blob *); |
67 | void mutate_string(char *); | 74 | void mutate_string(char *); |
68 | 75 | ||
69 | void * dev_open(const char *); | 76 | void *dev_open(const char *); |
70 | void dev_close(void *); | 77 | void dev_close(void *); |
71 | void set_wire_data(uint8_t *, size_t); | 78 | void set_wire_data(const uint8_t *, size_t); |
72 | int dev_read(void *, unsigned char *, size_t, int); | 79 | int dev_read(void *, unsigned char *, size_t, int); |
73 | int dev_write(void *, const unsigned char *, size_t); | 80 | int 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 @@ | |||
1 | Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover | 1 | Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover |
2 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 2 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3 | fuzz/prng.c 31 0 100.00% 2 0 100.00% 48 0 100.00% | 3 | fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00% |
4 | fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% | 4 | fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% |
5 | fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00% | 5 | fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00% |
6 | openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% | 6 | openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% |
@@ -8,34 +8,35 @@ openbsd-compat/recallocarray.c 41 7 82.93% | |||
8 | openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00% | 8 | openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00% |
9 | openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% | 9 | openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% |
10 | src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% | 10 | src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% |
11 | src/assert.c 566 43 92.40% 53 1 98.11% 900 87 90.33% | 11 | src/assert.c 566 24 95.76% 53 1 98.11% 900 50 94.44% |
12 | src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00% | 12 | src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00% |
13 | src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67% | 13 | src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67% |
14 | src/blob.c 39 1 97.44% 7 0 100.00% 73 4 94.52% | 14 | src/blob.c 39 0 100.00% 7 0 100.00% 73 0 100.00% |
15 | src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% | 15 | src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% |
16 | src/cbor.c 884 70 92.08% 52 2 96.15% 1371 106 92.27% | 16 | src/cbor.c 883 6 99.32% 52 0 100.00% 1364 17 98.75% |
17 | src/cred.c 534 51 90.45% 55 1 98.18% 830 78 90.60% | 17 | src/cred.c 536 23 95.71% 57 1 98.25% 836 29 96.53% |
18 | src/credman.c 376 18 95.21% 38 0 100.00% 589 15 97.45% | 18 | src/credman.c 385 18 95.32% 38 0 100.00% 595 16 97.31% |
19 | src/dev.c 201 85 57.71% 26 8 69.23% 294 128 56.46% | 19 | src/dev.c 334 90 73.05% 33 8 75.76% 466 140 69.96% |
20 | src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% | 20 | src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% |
21 | src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00% | 21 | src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00% |
22 | src/err.c 108 108 0.00% 1 1 0.00% 112 112 0.00% | 22 | src/err.c 112 8 92.86% 1 0 100.00% 116 8 93.10% |
23 | src/es256.c 278 0 100.00% 16 0 100.00% 377 0 100.00% | 23 | src/es256.c 280 0 100.00% 16 0 100.00% 398 0 100.00% |
24 | src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% | 24 | src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% |
25 | src/hid_linux.c 166 166 0.00% 12 12 0.00% 292 292 0.00% | 25 | src/hid_linux.c 235 235 0.00% 19 19 0.00% 416 416 0.00% |
26 | src/info.c 146 0 100.00% 31 0 100.00% 304 0 100.00% | 26 | src/info.c 152 0 100.00% 34 0 100.00% 319 0 100.00% |
27 | src/io.c 123 5 95.93% 10 0 100.00% 218 11 94.95% | 27 | src/io.c 156 9 94.23% 10 0 100.00% 236 11 95.34% |
28 | src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% | 28 | src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% |
29 | src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00% | 29 | src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00% |
30 | src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00% | 30 | src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00% |
31 | src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00% | 31 | src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00% |
32 | src/rs256.c 102 29 71.57% 8 3 62.50% 140 44 68.57% | 32 | src/rs256.c 102 6 94.12% 8 0 100.00% 140 13 90.71% |
33 | src/u2f.c 443 28 93.68% 13 0 100.00% 699 52 92.56% | 33 | src/u2f.c 491 9 98.17% 15 0 100.00% 774 18 97.67% |
34 | 34 | ||
35 | Files which contain no functions: | 35 | Files which contain no functions: |
36 | openbsd-compat/time.h 0 0 - 0 0 - 0 0 - | ||
36 | src/extern.h 0 0 - 0 0 - 0 0 - | 37 | src/extern.h 0 0 - 0 0 - 0 0 - |
37 | src/fido.h 0 0 - 0 0 - 0 0 - | 38 | src/fido.h 0 0 - 0 0 - 0 0 - |
38 | src/fido/err.h 0 0 - 0 0 - 0 0 - | 39 | src/fido/err.h 0 0 - 0 0 - 0 0 - |
39 | src/fido/param.h 0 0 - 0 0 - 0 0 - | 40 | src/fido/param.h 0 0 - 0 0 - 0 0 - |
40 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 41 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
41 | TOTAL 5054 653 87.08% 435 39 91.03% 7914 1002 87.34% | 42 | TOTAL 5359 477 91.10% 456 40 91.23% 8349 791 90.53% |