|
1 | 1 | # Fuzzing |
2 | 2 |
|
3 | | -Fuzz testing is an automated software testing method that injects invalid, |
4 | | -malformed, or unexpected inputs to reveal defects and vulnerabilities. A fuzzing |
5 | | -tool monitors the system for exceptions like crashes, information leakage, or |
6 | | -errors, helping developers identify and fix bugs and security loopholes. |
7 | | - |
8 | | -## Current state of fuzzing in liboqs |
9 | | -- [ ] kem |
10 | | - - [ ] bike |
11 | | - - [ ] classic_mceliece |
12 | | - - [ ] frodokem |
13 | | - - [ ] hqc |
14 | | - - [ ] kyber |
15 | | - - [ ] ml_kem |
16 | | - - [ ] ntruprime |
17 | | -- [ ] sig |
18 | | - - [x] falcon |
19 | | - - [x] mayo |
20 | | - - [x] ml_dsa |
21 | | -- [ ] sig_stfl |
22 | | - - [ ] lms |
23 | | - - [ ] sig_stfl |
24 | | - - [ ] xmss |
25 | | - |
26 | | -## Building and running fuzz tests |
27 | | - |
28 | | -Building fuzz tests is very similar to building normally with some optional |
29 | | -steps to target different types of bugs. The most basic ways to build the |
30 | | -fuzz tests is as follows; |
| 3 | +liboqs fuzz targets focus on public inputs that can reach scheme-specific |
| 4 | +decoders or deserializers before authentication succeeds. The targets start |
| 5 | +from a valid cached baseline for each enabled algorithm and then mutate the |
| 6 | +attacker-controlled fields, which keeps the fuzzer in deep parsing and |
| 7 | +verification paths instead of spending most iterations on early rejects. |
31 | 8 |
|
32 | | -```bash |
33 | | -mkdir build && cd build |
34 | | -cmake -GNinja -DOQS_BUILD_FUZZ_TESTS=ON .. |
35 | | -ninja |
36 | | -``` |
| 9 | +## Targets |
37 | 10 |
|
38 | | -`OQS_BUILD_FUZZ_TESTS` will build two test binaries: `tests/fuzz_test_sig` and `tests/fuzz_test_kem`. |
| 11 | +| Target | Public API surface | Mutated attacker input | |
| 12 | +| --- | --- | --- | |
| 13 | +| `fuzz_test_kem_encaps` | `OQS_KEM_encaps`, `OQS_KEM_encaps_derand` | KEM public keys | |
| 14 | +| `fuzz_test_kem_decaps` | `OQS_KEM_decaps` | KEM ciphertexts | |
| 15 | +| `fuzz_test_sig_verify` | `OQS_SIG_verify`, `OQS_SIG_verify_with_ctx_str` | Public keys, signatures, messages, contexts | |
| 16 | +| `fuzz_test_sig_stfl_verify` | `OQS_SIG_STFL_verify` | Stateful public keys, signatures, messages | |
| 17 | +| `fuzz_test_sig_stfl_deserialize` | `OQS_SIG_STFL_SECRET_KEY_deserialize` and round-trip serialization | Serialized stateful secret keys | |
39 | 18 |
|
40 | | -The fuzzer will run indefinitely or; |
41 | | -- until it finds a bug and crashes, |
42 | | -- you manually stop the fuzzer i.e. CTRL-C |
43 | | -- you set a timeout using the command line. |
| 19 | +`fuzz_test_sig_stfl_deserialize` is only built when |
| 20 | +`OQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON`, because the |
| 21 | +target relies on the full stateful object layout and persistence callback path |
| 22 | +available in key/sign builds. |
44 | 23 |
|
45 | | -For more details on the available command line args please consult the [libfuzzer docs](https://llvm.org/docs/LibFuzzer.html). |
| 24 | +## Building |
46 | 25 |
|
47 | | -## Sanitizers |
48 | | -It is a common pattern to combine fuzzing with various sanitizers to catch different bugs. |
49 | | -One of the simpler sanitizers is the fuzzing sanitizer, which will instrument the code |
50 | | -for coverage driven fuzzing. To enable this simply add this to your environment variables |
51 | | -before configuring cmake; |
| 26 | +Use Clang and sanitizer instrumentation for local runs: |
52 | 27 |
|
53 | | -``` |
54 | | -export CFLAGS=-fsanitize=fuzzer-no-link |
| 28 | +```bash |
| 29 | +export CC=clang |
| 30 | +export CXX=clang++ |
| 31 | +export CFLAGS=-fsanitize=fuzzer-no-link,address |
| 32 | +export LDFLAGS=-fsanitize=address |
| 33 | + |
| 34 | +cmake -S . -B build/fuzz -GNinja \ |
| 35 | + -DCMAKE_BUILD_TYPE=Debug \ |
| 36 | + -DOQS_BUILD_FUZZ_TESTS=ON \ |
| 37 | + -DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON \ |
| 38 | + -DOQS_ENABLE_SIG_STFL_XMSS=ON \ |
| 39 | + -DOQS_ENABLE_SIG_STFL_LMS=ON |
| 40 | +ninja -C build/fuzz \ |
| 41 | + fuzz_test_kem_encaps \ |
| 42 | + fuzz_test_kem_decaps \ |
| 43 | + fuzz_test_sig_verify \ |
| 44 | + fuzz_test_sig_stfl_verify \ |
| 45 | + fuzz_test_sig_stfl_deserialize |
55 | 46 | ``` |
56 | 47 |
|
57 | | -It is common to combine the fuzzer sanitizer with either the [address](https://clang.llvm.org/docs/AddressSanitizer.html) |
58 | | -or the [undefined behaviour sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html). To |
59 | | -add these simply add the relevant flags to BOTH the CFLAGS and LDFLAGS e.g. |
| 48 | +For focused local work, prefer a minimal build: |
60 | 49 |
|
| 50 | +```bash |
| 51 | +cmake -S . -B build/fuzz-minimal -GNinja \ |
| 52 | + -DCMAKE_BUILD_TYPE=Debug \ |
| 53 | + -DOQS_BUILD_FUZZ_TESTS=ON \ |
| 54 | + -DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON \ |
| 55 | + -DOQS_ENABLE_SIG_STFL_XMSS=ON \ |
| 56 | + -DOQS_ENABLE_SIG_STFL_LMS=ON \ |
| 57 | + '-DOQS_MINIMAL_BUILD=KEM_ml_kem_768;KEM_bike_l1;SIG_ml_dsa_44;SIG_falcon_512;SIG_STFL_xmss_shake128_h10;SIG_STFL_lms_sha256_h5_w2' |
61 | 58 | ``` |
62 | | -export CFLAGS=-fsanitize=fuzzer-no-link,address |
63 | | -export LDFLAGS=-fsanitize=address |
| 59 | + |
| 60 | +## Corpus |
| 61 | + |
| 62 | +The committed seed corpus is generated from the algorithm registries in |
| 63 | +`src/kem/kem.c`, `src/sig/sig.c`, and `src/sig_stfl/sig_stfl.c`. Each seed is a |
| 64 | +small binary header selecting one algorithm and API mode; the target then |
| 65 | +reconstructs a valid baseline in memory. |
| 66 | + |
| 67 | +Regenerate or validate the corpus after algorithm registry changes: |
| 68 | + |
| 69 | +```bash |
| 70 | +python3 tests/fuzz/generate_corpus.py --write |
| 71 | +python3 tests/fuzz/generate_corpus.py --check |
64 | 72 | ``` |
65 | 73 |
|
66 | | -Then rerun cmake as normal i.e. |
| 74 | +## Running |
| 75 | + |
| 76 | +Pass the matching corpus directory to libFuzzer and use an artifact prefix so a |
| 77 | +crashing input is preserved: |
| 78 | + |
67 | 79 | ```bash |
68 | | -mkdir build && cd build |
69 | | -cmake -GNinja .. -DOQS_BUILD_FUZZ_TESTS=ON |
70 | | -ninja -j$(nproc) |
| 80 | +mkdir -p fuzz-artifacts |
| 81 | +build/fuzz/tests/fuzz_test_sig_verify \ |
| 82 | + tests/fuzz/corpus/fuzz_test_sig_verify \ |
| 83 | + -max_total_time=300 \ |
| 84 | + -timeout=10 \ |
| 85 | + -max_len=65536 \ |
| 86 | + -keep_seed=1 \ |
| 87 | + -verbosity=0 \ |
| 88 | + -print_final_stats=1 \ |
| 89 | + -artifact_prefix=fuzz-artifacts/fuzz_test_sig_verify- |
71 | 90 | ``` |
| 91 | + |
| 92 | +The PR workflow runs a short sanitizer smoke profile over representative KEM, |
| 93 | +signature, XMSS, and LMS algorithms. The weekly workflow enables all default |
| 94 | +algorithms plus both stateful families and runs every target for longer. |
0 commit comments