# Fuzz testing

Modern fuzz testers are very effective and we wish to use them to ensure that no silly bugs creep into BoringSSL.

We use Clang's [libFuzzer](http://llvm.org/docs/LibFuzzer.html) for fuzz testing and there are a number of fuzz testing functions in `fuzz/`. They are not built by default because they require that the rest of BoringSSL be built with some changes that make fuzzing much more effective, but are completely unsafe for real use.

In order to build the fuzz tests you will need at least Clang 6.0. Pass `-DFUZZ=1` on the CMake command line to enable building BoringSSL with coverage and AddressSanitizer, and to build the fuzz test binaries. You'll probably need to set the `CC` and `CXX` environment variables too, like this:

```
CC=clang CXX=clang++ cmake -GNinja -DFUZZ=1 -B build
ninja -C build
```


From the `build/` directory, you can then run the fuzzers. For example:

```
./fuzz/cert -max_len=10000 -jobs=32 -workers=32 ../fuzz/cert_corpus/
```

The arguments to `jobs` and `workers` should be the number of cores that you wish to dedicate to fuzzing. By default, libFuzzer uses the largest test in the corpus (or 64 if empty) as the maximum test case length. The `max_len` argument overrides this.

The recommended values of `max_len` for each test are:

| Test          | `max_len` value |
|---------------|-----------------|
| `bn_div`      | 384             |
| `bn_mod_exp`  | 4096            |
| `cert`        | 10000           |
| `client`      | 20000           |
| `pkcs8`       | 2048            |
| `privkey`     | 2048            |
| `server`      | 4096            |
| `session`     | 8192            |
| `spki`        | 1024            |
| `read_pem`    | 512             |
| `ssl_ctx_api` | 256             |

These were determined by rounding up the length of the largest case in the corpus.

There are directories in `fuzz/` for each of the fuzzing tests which contain seed files for fuzzing. Some of the seed files were generated manually but many of them are “interesting” results generated by the fuzzing itself. (Where “interesting” means that it triggered a previously unknown path in the code.)

## Minimising the corpora

When a large number of new seeds are available, it's a good idea to minimise the corpus so that different seeds that trigger the same code paths can be deduplicated.

In order to minimise all the corpora, build for fuzzing and run `./fuzz/minimise_corpora.sh`. Note that minimisation is, oddly, often not idempotent for unknown reasons.

## Fuzzer mode

When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` defined. BoringSSL will then:

* Replace `RAND_bytes` with a deterministic PRNG. Call `RAND_reset_for_fuzzing()` at the start of fuzzers which use `RAND_bytes` to reset the PRNG state.

Additionally, if `CRYPTO_set_fuzzer_mode()` is called to enable fuzzer mode, BoringSSL will:

* Ignore the result of the PKCS#12 MAC check.

* Ignore the result of TLS signature checks (CertificateVerify and ServerKeyExchange), Finished checks, and PSK binder checks.

* Treat every TLS cipher as the NULL cipher.

* Skip encrypting TLS EncryptedClientHello payloads.

* Skip TLS ticket encryption and ignore the result of the MAC check.

* Ignore the result of the TLS `renegotiation\_info` check.

This is to prevent the fuzzer from getting stuck on cryptographic invariants.

## TLS transcripts

The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. The `run_tests` target will pass appropriate command-line flags.

There are separate fuzzers, `client_no_fuzzer_mode` and `server_no_fuzzer_mode`, with fuzzer mode disabled. This configuration is run in the same way but without `-fuzzer` and `-shim-config` flags.

If both sets of tests pass, refresh the fuzzer corpora with `refresh_ssl_corpora.sh`:

```
cd fuzz
./refresh_ssl_corpora.sh /path/to/fuzzer/mode/build /path/to/non/fuzzer/mode/build
```
