Cryptofuzz (differential crypto fuzzing) (#2273)

* Add cryptofuzz

* [cryptofuzz] Specify sanitizers

* [cryptofuzz] Actually disable assembly in second OpenSSL build

* [cryptofuzz] Add BoringSSL

* [cryptofuzz] Enable MemorySanitizer builds

* [cryptofuzz] Fix OpenSSL build

* [cryptofuzz] Add LibreSSL target

* [cryptofuzz] Don't build LibreSSL if MemorySanitizer is enabled

* [cryptofuzz] Adapt build script to latest cryptofuzz code

* [cryptofuzz] Force rebuild of OpenSSL

* [cryptofuzz] Comment and move to Dockerfile OpenSSL's commit lock

* [cryptofuzz] BoringSSL, LibreSSL: only build libcrypto.a for faster builds

* [cryptofuzz] Replace -lFuzzingEngine -> $LIB_FUZZING_ENGINE for compatibility with OSS-Fuzz' new build setup

* [cryptofuzz] Add README.md
This commit is contained in:
Guido Vranken 2019-04-18 05:33:50 +02:00 committed by Kostya Serebryany
parent 7b8971290d
commit 7bdfb2b7d8
4 changed files with 249 additions and 0 deletions

View File

@ -0,0 +1,39 @@
# Copyright 2019 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
FROM gcr.io/oss-fuzz-base/base-builder
MAINTAINER guidovranken@gmail.com
RUN apt-get update && apt-get install -y software-properties-common python-software-properties make autoconf automake libtool build-essential cmake
# BoringSSL needs Go to build
RUN add-apt-repository -y ppa:gophers/archive && apt-get update && apt-get install -y golang-1.9-go
RUN ln -s /usr/lib/go-1.9/bin/go /usr/bin/go
RUN git clone --depth 1 https://github.com/guidovranken/cryptofuzz
RUN git clone --depth 1 https://github.com/guidovranken/cryptofuzz-corpora
RUN git clone https://github.com/openssl/openssl
# The OpenSSL build system is currently broken, see also: https://github.com/google/oss-fuzz/issues/2314
# Lock OpenSSL to an older commit that does not cause build problems.
# This should be removed as soon as OpenSSL's build system is repaired.
RUN cd openssl && git checkout 9efa0ae0b602c1c0e356009a58410a2e8b80201a
RUN git clone --depth 1 https://boringssl.googlesource.com/boringssl
RUN git clone --depth 1 https://github.com/libressl-portable/portable libressl
RUN cd $SRC/libressl && ./update.sh
COPY build.sh $SRC/

View File

@ -0,0 +1,30 @@
This OSS-Fuzz project is a composite of multiple cryptographic libraries. It invokes a large amount of implementations for cryptographic primitives across multiple popular libraries, coordinated from a single fuzzing harness.
Its objectives are:
1. To assert programmatic soundness: find memory bugs, crashes and time-outs with the help of sanitizers.
2. To assert semantic soundness: detect invalid output occurring under legal use of the library's API.
One method to detect invalid results (point 2) is to assert equivalence between two or more outputs generated by a single library with the same input (but where each output allowed to be computed differently), aka "self-differential" testing. See [here](https://github.com/openssl/openssl/issues/8675) for a bug found with self-differential testing.
Another method is to compare a result against the result of different library, where both results are expected to be the same. If they are not the same, this indicates a bug in at least one library. This second method is what merits the composite setup of the project; adherence to the normative specification of a cryptographic primitive is implicitly asserted under the assumption that at least one implementation gets it right. Because determining which one of libraries gets it wrong cannot be reliably automated, all library maintainers are notified in this event, so that the cause of discrepancy can be resolved collaboratively.
Library builds embedding optimized assembly language code and those using pure C implementations have been assigned seperate fuzzer targets (binaries), because either implementation can have distinct bugs that will not transpire if only the other one is tested.
OpenSSL, BoringSSL and LibreSSL are assigned separate fuzzing targets because their exported symbols largely overlap and can therefore not be bundled into a single binary.
At this time of writing, no differential testing is performed, because support for additional libraries is not ready yet, but I intend to support mbed TLS and libsodium shortly, and support for popular or built-in cryptography implementations for Go, Rust, Java and Javascript is planned.
To further clear things up, at some point in the future, the matrix of support libraries versus fuzzing binaries could look like this:
A binary embedding OpenSSL, mbed TLS, libsodium, Go, Rust, Java, Javascript, ..., ...
A binary embedding BoringSSL, mbed TLS, libsodium, Go, Rust, Java, Javascript, ..., ...
A binary embedding LibreSSL, mbed TLS, libsodium, Go, Rust, Java, Javascript, ..., ...
and another 3 binaries for all of the pure C versions (no assembly language optimizations) of these libraries.
As more libraries are added, I will add a throttle mechanism to Cryptofuzz to ensure that no more than, say, 4 libraries will be called during a single iteration, so that no amount of supported libraries will impact the overall speed of the fuzzing process.
More information can be found at [Cryptofuzz](https://github.com/guidovranken/cryptofuzz).

164
projects/cryptofuzz/build.sh Executable file
View File

@ -0,0 +1,164 @@
#!/bin/bash -eu
# Copyright 2019 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
# Generate lookup tables. This only needs to be done once.
cd $SRC/cryptofuzz
python gen_repository.py
cd $SRC/openssl
export CXXFLAGS="$CXXFLAGS -I $SRC/cryptofuzz/fuzzing-headers/include"
if [[ $CFLAGS = *sanitize=memory* ]]
then
export CXXFLAGS="$CXXFLAGS -DMSAN"
fi
##############################################################################
if [[ $CFLAGS != *sanitize=memory* ]]
then
# Compile LibreSSL (with assembly)
cd $SRC/libressl
rm -rf build ; mkdir build
cd build
cmake -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_CXX_FLAGS="$CXXFLAGS" -DCMAKE_C_FLAGS="$CFLAGS" ..
make -j$(nproc) crypto
# Compile Cryptofuzz LibreSSL (with assembly) module
cd $SRC/cryptofuzz/modules/openssl
OPENSSL_INCLUDE_PATH="$SRC/libressl/include" OPENSSL_LIBCRYPTO_A_PATH="$SRC/libressl/build/crypto/libcrypto.a" CXXFLAGS="$CXXFLAGS -DCRYPTOFUZZ_LIBRESSL" make -B
# Compile Cryptofuzz
cd $SRC/cryptofuzz
LIBFUZZER_LINK="$LIB_FUZZING_ENGINE" CXXFLAGS="$CXXFLAGS -I $SRC/libressl/include -DCRYPTOFUZZ_LIBRESSL" make -B -j$(nproc)
# Generate dictionary
./generate_dict
# Copy fuzzer
cp $SRC/cryptofuzz/cryptofuzz $OUT/cryptofuzz-libressl
# Copy dictionary
cp $SRC/cryptofuzz/cryptofuzz-dict.txt $OUT/cryptofuzz-libressl.dict
# Copy seed corpus
cp $SRC/cryptofuzz-corpora/libressl_latest.zip $OUT/cryptofuzz-libressl_seed_corpus.zip
fi
##############################################################################
if [[ $CFLAGS != *sanitize=memory* ]]
then
# Compile Openssl (with assembly)
cd $SRC/openssl
./config --debug enable-md2 enable-rc5
make -j$(nproc)
# Compile Cryptofuzz OpenSSL (with assembly) module
cd $SRC/cryptofuzz/modules/openssl
OPENSSL_INCLUDE_PATH="$SRC/openssl/include" OPENSSL_LIBCRYPTO_A_PATH="$SRC/openssl/libcrypto.a" make -B
# Compile Cryptofuzz
cd $SRC/cryptofuzz
LIBFUZZER_LINK="$LIB_FUZZING_ENGINE" CXXFLAGS="$CXXFLAGS -I $SRC/openssl/include" make -B -j$(nproc)
# Generate dictionary
./generate_dict
# Copy fuzzer
cp $SRC/cryptofuzz/cryptofuzz $OUT/cryptofuzz-openssl
# Copy dictionary
cp $SRC/cryptofuzz/cryptofuzz-dict.txt $OUT/cryptofuzz-openssl.dict
# Copy seed corpus
cp $SRC/cryptofuzz-corpora/openssl_latest.zip $OUT/cryptofuzz-openssl_seed_corpus.zip
fi
##############################################################################
# Compile Openssl (without assembly)
cd $SRC/openssl
./config --debug no-asm enable-md2 enable-rc5
make clean
make -j$(nproc)
# Compile Cryptofuzz OpenSSL (without assembly) module
cd $SRC/cryptofuzz/modules/openssl
OPENSSL_INCLUDE_PATH="$SRC/openssl/include" OPENSSL_LIBCRYPTO_A_PATH="$SRC/openssl/libcrypto.a" make -B
# Compile Cryptofuzz
cd $SRC/cryptofuzz
LIBFUZZER_LINK="$LIB_FUZZING_ENGINE" CXXFLAGS="$CXXFLAGS -I $SRC/openssl/include" make -B -j$(nproc)
# Generate dictionary
./generate_dict
# Copy fuzzer
cp $SRC/cryptofuzz/cryptofuzz $OUT/cryptofuzz-openssl-noasm
# Copy dictionary
cp $SRC/cryptofuzz/cryptofuzz-dict.txt $OUT/cryptofuzz-openssl-noasm.dict
# Copy seed corpus
cp $SRC/cryptofuzz-corpora/openssl_latest.zip $OUT/cryptofuzz-openssl-noasm_seed_corpus.zip
##############################################################################
if [[ $CFLAGS != *sanitize=memory* ]]
then
# Compile BoringSSL (with assembly)
cd $SRC/boringssl
rm -rf build ; mkdir build
cd build
cmake -DCMAKE_CXX_FLAGS="$CXXFLAGS" -DCMAKE_C_FLAGS="$CFLAGS" -DBORINGSSL_ALLOW_CXX_RUNTIME=1 ..
make -j$(nproc) crypto
# Compile Cryptofuzz BoringSSL (with assembly) module
cd $SRC/cryptofuzz/modules/openssl
OPENSSL_INCLUDE_PATH="$SRC/boringssl/include" OPENSSL_LIBCRYPTO_A_PATH="$SRC/boringssl/build/crypto/libcrypto.a" CXXFLAGS="$CXXFLAGS -DCRYPTOFUZZ_BORINGSSL" make -B
# Compile Cryptofuzz
cd $SRC/cryptofuzz
LIBFUZZER_LINK="$LIB_FUZZING_ENGINE" CXXFLAGS="$CXXFLAGS -I $SRC/openssl/include" make -B -j$(nproc)
# Generate dictionary
./generate_dict
# Copy fuzzer
cp $SRC/cryptofuzz/cryptofuzz $OUT/cryptofuzz-boringssl
# Copy dictionary
cp $SRC/cryptofuzz/cryptofuzz-dict.txt $OUT/cryptofuzz-boringssl.dict
# Copy seed corpus
cp $SRC/cryptofuzz-corpora/boringssl_latest.zip $OUT/cryptofuzz-boringssl_seed_corpus.zip
fi
##############################################################################
# Compile BoringSSL (with assembly)
cd $SRC/boringssl
rm -rf build ; mkdir build
cd build
cmake -DCMAKE_CXX_FLAGS="$CXXFLAGS" -DCMAKE_C_FLAGS="$CFLAGS" -DBORINGSSL_ALLOW_CXX_RUNTIME=1 -DOPENSSL_NO_ASM=1 ..
make -j$(nproc) crypto
# Compile Cryptofuzz BoringSSL (with assembly) module
cd $SRC/cryptofuzz/modules/openssl
OPENSSL_INCLUDE_PATH="$SRC/boringssl/include" OPENSSL_LIBCRYPTO_A_PATH="$SRC/boringssl/build/crypto/libcrypto.a" CXXFLAGS="$CXXFLAGS -DCRYPTOFUZZ_BORINGSSL" make -B
# Compile Cryptofuzz
cd $SRC/cryptofuzz
LIBFUZZER_LINK="$LIB_FUZZING_ENGINE" CXXFLAGS="$CXXFLAGS -I $SRC/openssl/include" make -B -j$(nproc)
# Generate dictionary
./generate_dict
# Copy fuzzer
cp $SRC/cryptofuzz/cryptofuzz $OUT/cryptofuzz-boringssl-noasm
# Copy dictionary
cp $SRC/cryptofuzz/cryptofuzz-dict.txt $OUT/cryptofuzz-boringssl-noasm.dict
# Copy seed corpus
cp $SRC/cryptofuzz-corpora/boringssl_latest.zip $OUT/cryptofuzz-boringssl-noasm_seed_corpus.zip

View File

@ -0,0 +1,16 @@
homepage: "https://github.com/guidovranken/cryptofuzz"
primary_contact: "guidovranken@gmail.com"
auto_ccs:
- "openssl-security@openssl.org"
- "kurt@roeckx.be"
- "caswell.matt@googlemail.com"
- "agl@google.com"
- "davidben@google.com"
- "svaldez@google.com"
- "beck@obtuse.com"
- "joel.sing@gmail.com"
- "kinichiro.inoguchi@gmail.com"
sanitizers:
- address
- undefined
- memory