Fuzzing of Mbed TLS

This document describes public resources about fuzzing of Mbed TLS.

Cryptofuzz

Cryptofuzz is a program by Guido Vranken that performs the same cryptographic operation in many crypto libraries and compares the results.

The Cryptofuzz project does not run instances of Cryptofuzz. OSS-Fuzz does.

Cryptofuzz integration

Each cryptographic library is integrated as a module: a file modules/NAME/module.cpp has code to dispatch operations to the library. Mbed TLS is integrated through two modules:

The Mbed TLS module was originally written and is primarily maintained by Guido Vranken. The TF-PSA-Crypto module is currently being written by Arm with much help from Guido.

Building cryptofuzz

Cryptofuzz treats OpenSSL (or one of its forks) as the reference implementation that it compares the other libraries against. To work on Mbed TLS support in Cryptofuzz, you’ll need:

  • A reasonably recent Clang;

  • A build of a reasonably recent OpenSSL, with some non-default options (so distro builds might not work);

  • A recent Mbed TLS source.

Assuming you have the Cryptofuzz source in a directory cryptofuzz, the OpenSSL source in cryptofuzz/openssl and the Mbed TLS source in cryptofuzz/mbedtls, you can use the following build script.

#!/bin/sh

cat >/dev/null <<'EOF'
Prerequisites:
apt-get install clang libboost-dev
apt-get install libfuzzer-$(clang --version | grep -Eo '[0-9]+' | head -n 1)-dev

Ubuntu 22.04: clang fails to compile C++ programs out of the box.
Reported bug: https://bugs.launchpad.net/ubuntu/+source/llvm-toolchain-14/+bug/2038340
Workaround:
```
apt-get install libstdc++-12-dev
```

Ubuntu 22.04:
```
clang++ -fsanitize=address,undefined,fuzzer-no-link -D_GLIBCXX_DEBUG -O2 -g -DCRYPTOFUZZ_OPENSSL_110 -I/home/gilpes01/_/crypto/cryptofuzz/openssl/include -Wall -Wextra -std=c++17 -I include/ -I . -I fuzzing-headers/include -DFUZZING_HEADERS_NO_IMPL driver.o executor.o util.o entry.o tests.o operation.o datasource.o repository.o options.o components.o wycheproof.o crypto.o expmod.o mutator.o z3.o numbers.o mutatorpool.o ecc_diff_fuzzer_importer.o ecc_diff_fuzzer_exporter.o botan_importer.o openssl_importer.o builtin_tests_importer.o bignum_fuzzer_importer.o  -fsanitize=fuzzer third_party/cpu_features/build/libcpu_features.a  -o cryptofuzz
/usr/bin/ld: /usr/bin/ld: DWARF error: invalid or unhandled FORM value: 0x23
```
Seems to be a known bug with binutils 2.38, fixed in 2.39 (so Ubuntu 22.10+ should work):
https://github.com/llvm/llvm-project/issues/56994

EOF

set -e

export CC=clang CFLAGS="-fsanitize=address,undefined,fuzzer-no-link -O2 -g"
export CXX=clang++ CXXFLAGS="-fsanitize=address,undefined,fuzzer-no-link -O2 -g -I$PWD/openssl/include -DCRYPTOFUZZ_MBEDTLS -DCRYPTOFUZZ_TF_PSA_CRYPTO"

# Since e34981e902495bf8d18f50eedb5bc69587f67893, this is still necessary to
# build modules before calling the toplevel makefile.
[ -e repository_tbl.h ] || ./gen_repository.py

# Create a worktree with openssl and build it.
# Note that you need OpenSSL 3.x, not 1.1.1.
[ -d openssl ] || git clone https://github.com/openssl/openssl
# Enable "enable-md2" and "enable-rc5" because cryptofuzz needs them.
# Enable "no-makedepend" because otherwise openssl wants to regenerate its
# build dependencies each time you run `make`, which takes time, requires
# more perl modules, and uses absolute paths which make it impossible to
# mix working inside and outside Docker.
[ -e openssl/Makefile ] || ( cd openssl && ./config enable-md2 enable-rc5 no-makedepend )
make -C openssl
make -C modules/openssl OPENSSL_INCLUDE_PATH=$PWD/openssl/include OPENSSL_LIBCRYPTO_A_PATH=$PWD/openssl/libcrypto.a

# Create a worktree with mbedtls and build it.
[ -d mbedtls ] || git clone https://github.com/Mbed-TLS/mbedtls
grep -q '^#define MBEDTLS_PLATFORM_MEMORY' mbedtls/include/mbedtls/mbedtls_config.h || {
  mbedtls/scripts/config.py full
  mbedtls/scripts/config.py unset MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS
}
make -C mbedtls/library libmbedcrypto.a
make -C modules/mbedtls MBEDTLS_INCLUDE_PATH=$PWD/mbedtls/include MBEDTLS_LIBMBEDCRYPTO_A_PATH=$PWD/mbedtls/library/libmbedcrypto.a
make -C modules/tf-psa-crypto MBEDTLS_INCLUDE_PATH=$PWD/mbedtls/include MBEDTLS_LIBMBEDCRYPTO_A_PATH=$PWD/mbedtls/library/libmbedcrypto.a

if [ -e cryptofuzz ] && {
     [ -e modules/mbedtls/module.a -a modules/mbedtls/module.a -nt cryptofuzz ] ||
     [ -e modules/tf-psa-crypto/module.a -a modules/tf-psa-crypto/module.a -nt cryptofuzz ]
   }
then
  rm cryptofuzz
fi
make LIBFUZZER_LINK="-fsanitize=fuzzer"

See also Generic building documentation.

Running Cryptofuzz

  • To run cryptofuzz for some randomized testing, just run ./cryptofuzz.

  • To run a specific set of operations, pass the --operations option with a comma-separated list of operation names. The operation names match class names in cryptofuzz/operations.h.

  • To restrict the set of algorithms, you can pass --digests, --ciphers, --curves (all with a comma-separated list of names). For the list of available names, see repository_tbl.h (generated during the build) or gen_repository.py (search for Add( Digest("...") ), Add( Cipher("...") ), Add( ECC_Curve("...", ...) )).

Example:

./cryptofuzz --operations=SymmetricEncrypt,SymmetricDecrypt --ciphers=AES_128_ECB,AES_128_CBC

See also Generic running documentation.

Reproducing Cryptofuzz crashes

If Cryptofuzz finds a (potential) bug, it aborts and leaves a crash-* file. Common causes of bugs are a sanitizer-triggered abort, an assertion failure in a module or a discrepancy between a library’s result and the OpenSSL result.

To run Cryptofuzz on a crash file:

./cryptofuzz --debug crash-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

OSS-Fuzz

OSS-Fuzz is a software project that combines fuzzing-related tools with scripts to run those fuzzers on a large set of security-critical programs, including Mbed TLS. OSS-Fuzz also runs these programs on a regular basis.

OSS-Fuzz reports

When the OSS-Fuzz infrastructure notices a fuzzer crash, the maintainers of the offending module are notified. For fuzzers where Mbed TLS is integrated, this includes the Mbed TLS security team.

Fuzzing crash reports become public after 90 days or when the crash is noticed as fixed.

OSS-Fuzz integration

Mbed TLS is integrated in four Cryptofuzz projects:

Mbed TLS fuzz programs

The program/fuzz directory contains several programs to fuzz key parsing in the PK module, X.509 certificate/CRL/CRT parsing, and TLS/DTLS handshakes and communication.

These programs, as well as a corpuse, were contributed by Philippe Antoine (catenacyber) and are now mostly maintained by Arm.

To reproduce a crash, just run programs/fuzz/xxx_fuzz crash-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, preferably in a debug build to understand what’s going on.