From 3baa546d70bcd078b23be07069d755a5f130fb0f Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Mon, 31 Jul 2017 15:13:15 -0400 Subject: Create new fuzzer build mode --- .travis.yml | 12 +- configure.py | 109 ++++++++++----- src/build-data/buildh.in | 1 + src/build-data/makefile/gmake.in | 2 + src/build-data/makefile/gmake_fuzzers.in | 18 +++ src/extra_tests/fuzzers/.gitignore | 10 -- src/extra_tests/fuzzers/GNUmakefile | 88 ------------- src/extra_tests/fuzzers/jigs/ber_decode.cpp | 27 ---- src/extra_tests/fuzzers/jigs/bn_sqr.cpp | 24 ---- src/extra_tests/fuzzers/jigs/cert.cpp | 21 --- src/extra_tests/fuzzers/jigs/crl.cpp | 21 --- src/extra_tests/fuzzers/jigs/divide.cpp | 29 ---- src/extra_tests/fuzzers/jigs/driver.h | 115 ---------------- src/extra_tests/fuzzers/jigs/ecc_bp256.cpp | 16 --- src/extra_tests/fuzzers/jigs/ecc_helper.h | 69 ---------- src/extra_tests/fuzzers/jigs/ecc_p256.cpp | 15 --- src/extra_tests/fuzzers/jigs/ecc_p384.cpp | 15 --- src/extra_tests/fuzzers/jigs/ecc_p521.cpp | 15 --- src/extra_tests/fuzzers/jigs/invert.cpp | 84 ------------ src/extra_tests/fuzzers/jigs/ocsp.cpp | 17 --- src/extra_tests/fuzzers/jigs/os2ecp.cpp | 40 ------ src/extra_tests/fuzzers/jigs/pkcs1.cpp | 77 ----------- src/extra_tests/fuzzers/jigs/pkcs8.cpp | 18 --- src/extra_tests/fuzzers/jigs/pow_mod.cpp | 63 --------- src/extra_tests/fuzzers/jigs/redc_p192.cpp | 26 ---- src/extra_tests/fuzzers/jigs/redc_p224.cpp | 23 ---- src/extra_tests/fuzzers/jigs/redc_p256.cpp | 26 ---- src/extra_tests/fuzzers/jigs/redc_p384.cpp | 26 ---- src/extra_tests/fuzzers/jigs/redc_p521.cpp | 26 ---- src/extra_tests/fuzzers/jigs/ressol.cpp | 45 ------- src/extra_tests/fuzzers/jigs/tls_client.cpp | 57 -------- src/extra_tests/fuzzers/jigs/tls_client_hello.cpp | 17 --- src/extra_tests/fuzzers/jigs/tls_server.cpp | 153 ---------------------- src/extra_tests/fuzzers/readme.txt | 49 ------- src/fuzzer/asn1.cpp | 24 ++++ src/fuzzer/bn_sqr.cpp | 24 ++++ src/fuzzer/cert.cpp | 21 +++ src/fuzzer/crl.cpp | 18 +++ src/fuzzer/divide.cpp | 29 ++++ src/fuzzer/ecc_bp256.cpp | 16 +++ src/fuzzer/ecc_helper.h | 58 ++++++++ src/fuzzer/ecc_p256.cpp | 15 +++ src/fuzzer/ecc_p384.cpp | 15 +++ src/fuzzer/ecc_p521.cpp | 15 +++ src/fuzzer/fuzzers.h | 95 ++++++++++++++ src/fuzzer/invert.cpp | 87 ++++++++++++ src/fuzzer/ocsp.cpp | 17 +++ src/fuzzer/os2ecp.cpp | 44 +++++++ src/fuzzer/pkcs1.cpp | 82 ++++++++++++ src/fuzzer/pkcs8.cpp | 19 +++ src/fuzzer/pow_mod.cpp | 70 ++++++++++ src/fuzzer/redc_helper.h | 33 +++++ src/fuzzer/redc_p192.cpp | 26 ++++ src/fuzzer/redc_p224.cpp | 23 ++++ src/fuzzer/redc_p256.cpp | 26 ++++ src/fuzzer/redc_p384.cpp | 26 ++++ src/fuzzer/redc_p521.cpp | 26 ++++ src/fuzzer/ressol.cpp | 45 +++++++ src/fuzzer/tls_client.cpp | 57 ++++++++ src/fuzzer/tls_client_hello.cpp | 18 +++ src/fuzzer/tls_server.cpp | 153 ++++++++++++++++++++++ src/scripts/ci/travis/build.sh | 13 +- src/scripts/create_corpus_zip.py | 48 +++++++ src/scripts/test_fuzzers.py | 78 +++++++++++ 64 files changed, 1326 insertions(+), 1249 deletions(-) create mode 100644 src/build-data/makefile/gmake_fuzzers.in delete mode 100644 src/extra_tests/fuzzers/.gitignore delete mode 100644 src/extra_tests/fuzzers/GNUmakefile delete mode 100644 src/extra_tests/fuzzers/jigs/ber_decode.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/bn_sqr.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/cert.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/crl.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/divide.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/driver.h delete mode 100644 src/extra_tests/fuzzers/jigs/ecc_bp256.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/ecc_helper.h delete mode 100644 src/extra_tests/fuzzers/jigs/ecc_p256.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/ecc_p384.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/ecc_p521.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/invert.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/ocsp.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/os2ecp.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/pkcs1.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/pkcs8.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/pow_mod.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/redc_p192.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/redc_p224.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/redc_p256.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/redc_p384.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/redc_p521.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/ressol.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/tls_client.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/tls_client_hello.cpp delete mode 100644 src/extra_tests/fuzzers/jigs/tls_server.cpp delete mode 100644 src/extra_tests/fuzzers/readme.txt create mode 100644 src/fuzzer/asn1.cpp create mode 100644 src/fuzzer/bn_sqr.cpp create mode 100644 src/fuzzer/cert.cpp create mode 100644 src/fuzzer/crl.cpp create mode 100644 src/fuzzer/divide.cpp create mode 100644 src/fuzzer/ecc_bp256.cpp create mode 100644 src/fuzzer/ecc_helper.h create mode 100644 src/fuzzer/ecc_p256.cpp create mode 100644 src/fuzzer/ecc_p384.cpp create mode 100644 src/fuzzer/ecc_p521.cpp create mode 100644 src/fuzzer/fuzzers.h create mode 100644 src/fuzzer/invert.cpp create mode 100644 src/fuzzer/ocsp.cpp create mode 100644 src/fuzzer/os2ecp.cpp create mode 100644 src/fuzzer/pkcs1.cpp create mode 100644 src/fuzzer/pkcs8.cpp create mode 100644 src/fuzzer/pow_mod.cpp create mode 100644 src/fuzzer/redc_helper.h create mode 100644 src/fuzzer/redc_p192.cpp create mode 100644 src/fuzzer/redc_p224.cpp create mode 100644 src/fuzzer/redc_p256.cpp create mode 100644 src/fuzzer/redc_p384.cpp create mode 100644 src/fuzzer/redc_p521.cpp create mode 100644 src/fuzzer/ressol.cpp create mode 100644 src/fuzzer/tls_client.cpp create mode 100644 src/fuzzer/tls_client_hello.cpp create mode 100644 src/fuzzer/tls_server.cpp create mode 100755 src/scripts/create_corpus_zip.py create mode 100755 src/scripts/test_fuzzers.py diff --git a/.travis.yml b/.travis.yml index d7092f01a..8431729b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ env: - BUILD_MODE="static" - BUILD_MODE="bsi" - BUILD_MODE="nist" + - BUILD_MODE="fuzzers" - BUILD_MODE="sanitizer" - BUILD_MODE="coverage" - BUILD_MODE="cross-arm32" @@ -52,10 +53,11 @@ matrix: - os: osx compiler: gcc - # Run docs, lint, bsi, nist, coverage, valgrind, sonarqube, sanitizer, - # minimized and non-ARM cross builds on Linux/gcc only. The - # sanitizer builds under Clang run the tests very slowly and cause - # CI timeouts. + # Run docs, lint, bsi, nist, fuzzers, coverage, valgrind, sonarqube, sanitizer, + # minimized and non-ARM cross builds on Linux/gcc only. + + # The sanitizer builds under Clang run the tests very slowly and + # cause CI timeouts. - compiler: clang env: BUILD_MODE="bsi" @@ -71,6 +73,8 @@ matrix: env: BUILD_MODE="sonarqube" - compiler: clang env: BUILD_MODE="sanitizer" + - compiler: clang + env: BUILD_MODE="fuzzers" - compiler: clang env: BUILD_MODE="valgrind" - compiler: clang diff --git a/configure.py b/configure.py index 58a4f19d2..f9bf90fc9 100755 --- a/configure.py +++ b/configure.py @@ -183,6 +183,13 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes self.cli_headers = list(find_headers_in(source_paths.src_dir, 'cli')) self.test_sources = list(find_sources_in(source_paths.src_dir, 'tests')) + if options.build_fuzzers: + self.fuzzer_sources = list(find_sources_in(source_paths.src_dir, 'fuzzer')) + self.fuzzer_output_dir = os.path.join(self.build_dir, 'fuzzer') + else: + self.fuzzer_sources = None + self.fuzzer_output_dir = None + def build_dirs(self): out = [ self.libobj_dir, @@ -195,6 +202,8 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes ] if self.doc_output_dir_doxygen: out += [self.doc_output_dir_doxygen] + if self.fuzzer_output_dir: + out += [self.fuzzer_output_dir] return out def src_info(self, typ): @@ -204,6 +213,10 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes return (self.cli_sources, self.cliobj_dir) elif typ == 'test': return (self.test_sources, self.testobj_dir) + elif typ == 'fuzzer': + return (self.fuzzer_sources, self.fuzzer_output_dir) + else: + raise InternalError("Unknown src info type '%s'" % (typ)) PKG_CONFIG_FILENAME = 'botan-%d.pc' % (Version.major) @@ -409,7 +422,14 @@ def process_command_line(args): # pylint: disable=too-many-locals help='Generate CMakeLists.txt which can be used to create many IDEs project files') build_group.add_option('--unsafe-fuzzer-mode', action='store_true', default=False, - help='disable essential checks for testing') + help='Disable essential checks for testing') + + build_group.add_option('--build-fuzzers=', dest='build_fuzzers', + metavar='TYPE', default=None, + help='Build fuzzers (afl, libfuzzer, test)') + + build_group.add_option('--with-fuzzer-lib=', metavar='LIB', default=None, dest='fuzzer_lib', + help='additionally link in LIB') mods_group = optparse.OptionGroup(parser, 'Module selection') @@ -1711,13 +1731,14 @@ class MakefileListsGenerator(object): for src in sources: (directory, filename) = os.path.split(os.path.normpath(src)) + obj_suffix = '.' + self._osinfo.obj_suffix + parts = directory.split(os.sep) + if 'fuzzer' in parts: + obj_suffix = '' + if 'src' in parts: parts = parts[parts.index('src')+2:] - elif 'tests' in parts: - parts = parts[parts.index('tests')+2:] - elif 'cli' in parts: - parts = parts[parts.index('cli'):] elif filename.find('botan_all') != -1: parts = [] else: @@ -1744,8 +1765,7 @@ class MakefileListsGenerator(object): else: name = filename - for src_suffix in ['.cpp', '.S']: - name = name.replace(src_suffix, '.' + self._osinfo.obj_suffix) + name = name.replace('.cpp', obj_suffix) yield os.path.join(obj_dir, name) @@ -1760,21 +1780,29 @@ class MakefileListsGenerator(object): if self._options.with_external_includedir: includes += ' ' + self._cc.add_include_dir_option + self._options.with_external_includedir - for (obj_file, src) in zip(self._objectfile_list(sources, obj_dir), sources): - isa_specific_flags_str = "".join([" %s" % flagset for flagset in sorted(self._isa_specific_flags(src))]) - yield '%s: %s\n\t$(CXX)%s $(%s_FLAGS) %s %s %s %s$@\n' % ( - obj_file, - src, - isa_specific_flags_str, - flags, - includes, - self._cc.compile_flags, - src, - self._cc.output_to_option) + is_fuzzer = obj_dir.find('fuzzer') != -1 + + if is_fuzzer: + for (obj_file, src) in zip(self._objectfile_list(sources, obj_dir), sources): + + yield '%s: %s\n\t$(CXX) %s $(%s_FLAGS) %s -L. -lbotan-2 $(FUZZER_LINKS_TO) %s$@\n' % ( + obj_file, src, includes, flags, src, self._cc.output_to_option) + else: + for (obj_file, src) in zip(self._objectfile_list(sources, obj_dir), sources): + isa_specific_flags_str = "".join([" %s" % flagset for flagset in sorted(self._isa_specific_flags(src))]) + + yield '%s: %s\n\t$(CXX)%s $(%s_FLAGS) %s %s %s %s$@\n' % ( + obj_file, src, isa_specific_flags_str, flags, + includes, self._cc.compile_flags, src, self._cc.output_to_option) def generate(self): out = {} - for t in ['lib', 'cli', 'test']: + + targets = ['lib', 'cli', 'test'] + if self._options.build_fuzzers: + targets += ['fuzzer'] + + for t in targets: obj_key = '%s_objs' % (t) src_list, src_dir = self._build_paths.src_info(t) src_list.sort() @@ -1817,7 +1845,7 @@ class HouseEccCurve(object): return "\\\n" + ' \\\n'.join(lines) -def create_template_vars(source_paths, build_config, options, modules, cc, arch, osinfo): +def create_template_vars(source_paths, build_config, options, modules, cc, arch, osinfo): #pylint: disable=too-many-locals,too-many-branches """ Create the template variables needed to process the makefile, build.h, etc """ @@ -1846,6 +1874,7 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, exceptions = match.group(1).split(',') if osinfo.basename not in exceptions: libs |= set(module_link_to) + return sorted(libs) def choose_mp_bits(): @@ -1909,6 +1938,7 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, 'libobj_dir': build_config.libobj_dir, 'cliobj_dir': build_config.cliobj_dir, 'testobj_dir': build_config.testobj_dir, + 'fuzzobj_dir': build_config.fuzzer_output_dir if build_config.fuzzer_output_dir else '', 'doc_output_dir': build_config.doc_output_dir, @@ -1938,6 +1968,7 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, 'lib_link_cmd': cc.so_link_command_for(osinfo.basename, options) + external_link_cmd(), 'cli_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + external_link_cmd(), 'test_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + external_link_cmd(), + 'fuzzer_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + external_link_cmd(), 'link_to': ' '.join( [cc.add_lib_option + lib for lib in link_to('libs')] + @@ -1956,7 +1987,9 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, 'include_files': makefile_list(build_config.public_headers), - 'unsafe_fuzzer_mode_define': '' if not options.unsafe_fuzzer_mode else '#define BOTAN_UNSAFE_FUZZER_MODE', + 'unsafe_fuzzer_mode_define': '#define BOTAN_UNSAFE_FUZZER_MODE' if options.unsafe_fuzzer_mode else '', + 'fuzzer_type': '#define BOTAN_FUZZER_IS_%s' % (options.build_fuzzers.upper()) if options.build_fuzzers else '', + 'fuzzer_libs': '' if options.fuzzer_lib is None else '%s%s' % (cc.add_lib_option, options.fuzzer_lib), 'ar_command': cc.ar_command or osinfo.ar_command, 'ranlib_command': osinfo.ranlib_command(), @@ -2026,17 +2059,22 @@ def create_template_vars(source_paths, build_config, options, modules, cc, arch, variables["header_in"] = process_template(os.path.join(source_paths.makefile_dir, 'header.in'), variables) if variables["makefile_style"] == "gmake": - variables["gmake_commands_in"] = process_template( - os.path.join(source_paths.makefile_dir, 'gmake_commands.in'), - variables) - variables["gmake_dso_in"] = process_template( - os.path.join(source_paths.makefile_dir, 'gmake_dso.in'), - variables - ) if options.build_shared_lib else '' - variables["gmake_coverage_in"] = process_template( - os.path.join(source_paths.makefile_dir, 'gmake_coverage.in'), - variables - ) if options.with_coverage_info else '' + templates = [ + ('gmake_commands.in', True), + ('gmake_dso.in', options.build_shared_lib), + ('gmake_coverage.in', options.with_coverage_info), + ('gmake_fuzzers.in', options.build_fuzzers) + ] + + for (template, build_it) in templates: + template_file = os.path.join(source_paths.makefile_dir, template) + + var_name = template.replace('.', '_') + + if build_it: + variables[var_name] = process_template(template_file, variables) + else: + variables[var_name] = '' return variables @@ -3006,6 +3044,13 @@ def main(argv): source_paths = SourcePaths(os.path.dirname(argv[0])) + if options.build_fuzzers != None: + if options.build_fuzzers not in ['libfuzzer', 'afl', 'test']: + raise UserError('Bad value to --build-fuzzers') + + if options.build_fuzzers == 'libfuzzer' and options.fuzzer_lib is None: + options.fuzzer_lib = 'Fuzzer' + info_modules = load_info_files(source_paths.lib_dir, 'Modules', "info.txt", ModuleInfo) info_arch = load_build_data_info_files(source_paths, 'CPU info', 'arch', ArchInfo) info_os = load_build_data_info_files(source_paths, 'OS info', 'os', OsInfo) diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index 2376b056e..6e60718ee 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -25,6 +25,7 @@ /* How many bits per limb in a BigInt */ #define BOTAN_MP_WORD_BITS %{mp_bits} %{unsafe_fuzzer_mode_define} +%{fuzzer_type} #define BOTAN_INSTALL_PREFIX R"(%{prefix})" #define BOTAN_INSTALL_HEADER_DIR "%{includedir}/botan-%{version_major}" diff --git a/src/build-data/makefile/gmake.in b/src/build-data/makefile/gmake.in index 22e4ef778..c77c1908c 100644 --- a/src/build-data/makefile/gmake.in +++ b/src/build-data/makefile/gmake.in @@ -53,6 +53,8 @@ $(STATIC_LIB): $(LIBOBJS) %{gmake_coverage_in} +%{gmake_fuzzers_in} + SPHINX_CONFIG = %{sphinx_config_dir} SPHINX_OPTS = -b html diff --git a/src/build-data/makefile/gmake_fuzzers.in b/src/build-data/makefile/gmake_fuzzers.in new file mode 100644 index 000000000..82fa8b256 --- /dev/null +++ b/src/build-data/makefile/gmake_fuzzers.in @@ -0,0 +1,18 @@ + +# Fuzzer build commands + +FUZZER_LINK_CMD = %{fuzzer_link_cmd} +FUZZER_LINKS_TO = $(LIB_LINKS_TO) %{fuzzer_libs} +FUZZER_FLAGS = $(CXXFLAGS) $(WARN_FLAGS) + +%{fuzzer_build_cmds} + +FUZZERS=%{fuzzer_objs} + +fuzzers: libs $(FUZZERS) + +fuzzer_corpus: + git clone --depth=1 https://github.com/randombit/crypto-corpus.git fuzzer_corpus + +fuzzer_corpus_zip: fuzzer_corpus + ./src/scripts/create_corpus_zip.py fuzzer_corpus %{fuzzobj_dir} diff --git a/src/extra_tests/fuzzers/.gitignore b/src/extra_tests/fuzzers/.gitignore deleted file mode 100644 index f7ce206a2..000000000 --- a/src/extra_tests/fuzzers/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*.log - -/libFuzzer -libFuzzer.a - -/output -/botan -/bin -callgrind.out.* -/corpus/ diff --git a/src/extra_tests/fuzzers/GNUmakefile b/src/extra_tests/fuzzers/GNUmakefile deleted file mode 100644 index 32b353d17..000000000 --- a/src/extra_tests/fuzzers/GNUmakefile +++ /dev/null @@ -1,88 +0,0 @@ - -FUZZERS=$(patsubst jigs/%.cpp,%,$(wildcard jigs/*.cpp)) - -AFL_SAN_FLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -CLANG_SAN_FLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -#CLANG_SAN_FLAGS=-fsanitize=address - -CLANG_COV_FLAGS=-fsanitize-coverage=edge,indirect-calls,8bit-counters -SHARED_FLAGS=-O3 -g -std=c++11 -pthread -CFG_FLAGS=--with-debug-info --unsafe-fuzzer-mode - -LIBFUZZER_FLAGS=-Illvm-build/build/include $(SHARED_FLAGS) $(CLANG_COV_FLAGS) $(CLANG_SAN_FLAGS) -AFL_FLAGS=-Iafl-build/build/include $(SHARED_FLAGS) -DINCLUDE_AFL_MAIN - -LIBFUZZER_LIBS=llvm-build/libbotan-2.a libFuzzer.a -AFL_LIBS=afl-build/libbotan-2.a - -#AFL_CXX=AFL_USE_ASAN=1 afl-g++ -m32 -AFL_CXX=afl-g++ -AFL_CXX_TYPE=gcc -CLANG_CXX=clang++ - -LIBFUZZER_PROGS=$(patsubst %,bin/llvm_fuzz_%,$(FUZZERS)) -AFL_PROGS=$(patsubst %,bin/afl_fuzz_%,$(FUZZERS)) - -all: - @echo "make afl for AFL, llvm for libFuzzer" - -afl: dirs afl-build $(AFL_PROGS) - -llvm: dirs llvm-build $(LIBFUZZER_PROGS) - -bin/llvm_fuzz_%: jigs/%.cpp $(LIBFUZZER_LIBS) - $(CLANG_CXX) $(LIBFUZZER_FLAGS) $< $(LIBFUZZER_LIBS) -o $@ - -bin/afl_fuzz_%: jigs/%.cpp $(AFL_LIBS) - $(AFL_CXX) $(AFL_FLAGS) $< $(AFL_LIBS) -o $@ - - -dirs: - mkdir -p bin - mkdir -p output - mkdir -p corpus - -afl-build: - ../../../configure.py $(CFG_FLAGS) --with-build-dir=afl-build --cc=$(AFL_CXX_TYPE) --cc-bin=$(AFL_CXX) - make -j2 -f afl-build/Makefile afl-build/libbotan-2.a - -llvm-build: - ../../../configure.py $(CFG_FLAGS) --with-build-dir=llvm-build --cc=clang --cc-bin=$(CLANG_CXX) --cc-abi-flags="$(CLANG_COV_FLAGS) $(CLANG_SAN_FLAGS)" - make -j2 -f llvm-build/Makefile llvm-build/libbotan-2.a - -# libFuzzer default is max_len 64 this sets 140 but allows override via args= -run_llvm_%: bin/llvm_fuzz_% - $(eval FUZZER = $(subst bin/llvm_fuzz_,,$<)) - mkdir -p output/$(FUZZER)/llvm/queue - mkdir -p output/$(FUZZER)/llvm/outputs - $< -max_len=140 -artifact_prefix=output/$(FUZZER)/llvm/outputs/ output/$(FUZZER)/llvm/queue corpus/$(FUZZER) $(args) - -run_afl_%: bin/afl_fuzz_% - $(eval FUZZER = $(subst bin/afl_fuzz_,,$<)) - mkdir -p output/$(FUZZER)/afl - afl-fuzz $(args) -o output/$(FUZZER)/afl -i corpus/$(FUZZER) $< - -cmin_%: bin/afl_fuzz_% - $(eval FUZZER = $(subst bin/afl_fuzz_,,$<)) - rm -rf cmin-dir - mv corpus/$(FUZZER) cmin-dir - -cp -n output/$(FUZZER)/afl/queue/* cmin-dir - -cp -n output/$(FUZZER)/llvm/queue/* cmin-dir - afl-cmin -i cmin-dir -o corpus/$(FUZZER) $< - rm -rf cmin-dir - -clean: - rm -f $(LIBFUZZER_PROGS) $(AFL_PROGS) - -clean_builds: clean - rm -rf afl-build llvm-build - -libFuzzer: - svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libFuzzer - -libFuzzer.a: libFuzzer - cd libFuzzer && clang -c -g -O2 -std=c++11 *.cpp - ar cr libFuzzer.a libFuzzer/*.o - -update: - svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libFuzzer diff --git a/src/extra_tests/fuzzers/jigs/ber_decode.cpp b/src/extra_tests/fuzzers/jigs/ber_decode.cpp deleted file mode 100644 index 6ec9cadba..000000000 --- a/src/extra_tests/fuzzers/jigs/ber_decode.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* -* (C) 2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" - -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 4096) - return; - - try - { - DataSource_Memory input(in, len); - BER_Decoder dec(input); - - while(dec.more_items()) - { - BER_Object obj; - dec.get_next(obj); - } - } - catch(Botan::Exception& e) { } - } diff --git a/src/extra_tests/fuzzers/jigs/bn_sqr.cpp b/src/extra_tests/fuzzers/jigs/bn_sqr.cpp deleted file mode 100644 index aa76067f7..000000000 --- a/src/extra_tests/fuzzers/jigs/bn_sqr.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" - -#include -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 8192/8) - return; - - Botan::BigInt x = Botan::BigInt::decode(in, len); - - Botan::BigInt x_sqr = square(x); - Botan::BigInt x_mul = x * x; - - FUZZER_ASSERT_EQUAL(x_sqr, x_mul); - } - diff --git a/src/extra_tests/fuzzers/jigs/cert.cpp b/src/extra_tests/fuzzers/jigs/cert.cpp deleted file mode 100644 index 5620a4700..000000000 --- a/src/extra_tests/fuzzers/jigs/cert.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" - -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 8192) - return; - - try - { - DataSource_Memory input(in, len); - X509_Certificate cert(input); - } - catch(Botan::Exception& e) { } - } diff --git a/src/extra_tests/fuzzers/jigs/crl.cpp b/src/extra_tests/fuzzers/jigs/crl.cpp deleted file mode 100644 index b3157e5fe..000000000 --- a/src/extra_tests/fuzzers/jigs/crl.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" - -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 4096) - return; - - try - { - DataSource_Memory input(in, len); - X509_CRL crl(input); - } - catch(Botan::Exception& e) { } - } diff --git a/src/extra_tests/fuzzers/jigs/divide.cpp b/src/extra_tests/fuzzers/jigs/divide.cpp deleted file mode 100644 index 4ff50a680..000000000 --- a/src/extra_tests/fuzzers/jigs/divide.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len % 2 == 1 || len > 2*4096/8) - return; - - const BigInt x = BigInt::decode(in, len / 2); - const BigInt y = BigInt::decode(in + len / 2, len / 2); - - if(y == 0) - return; - - BigInt q, r; - Botan::divide(x, y, q, r); - - FUZZER_ASSERT_TRUE(r < y); - - BigInt z = q*y + r; - - FUZZER_ASSERT_EQUAL(z, x); - } - diff --git a/src/extra_tests/fuzzers/jigs/driver.h b/src/extra_tests/fuzzers/jigs/driver.h deleted file mode 100644 index 08fffd0c1..000000000 --- a/src/extra_tests/fuzzers/jigs/driver.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef FUZZER_DRIVER_H_ -#define FUZZER_DRIVER_H_ - -#include -#include -#include -#include // for setenv -#include -#include -#include - -using namespace Botan; - -extern void fuzz(const uint8_t in[], size_t len); - -extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) - { - /* - * This disables the mlock pool, as overwrites within the pool are - * opaque to ASan or other instrumentation. - */ - ::setenv("BOTAN_MLOCK_POOL_SIZE", "0", 1); - return 0; - } - -// Called by main() in libFuzzer or in main for AFL below -extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len) - { - fuzz(in, len); - return 0; - } - -#if defined(INCLUDE_AFL_MAIN) - -// Read stdin for AFL - -int main(int argc, char* argv[]) - { - const size_t max_read = 4096; - - LLVMFuzzerInitialize(&argc, &argv); - -#if defined(__AFL_LOOP) - while(__AFL_LOOP(1000)) -#endif - { - std::vector buf(max_read); - std::cin.read((char*)buf.data(), buf.size()); - size_t got = std::cin.gcount(); - - buf.resize(got); - buf.shrink_to_fit(); - - fuzz(buf.data(), got); - } - } - -#endif - -// Some helpers for the fuzzer jigs - -inline Botan::RandomNumberGenerator& fuzzer_rng() - { - class ChaCha20_RNG : public Botan::RandomNumberGenerator - { - public: - std::string name() const override { return "ChaCha20_RNG"; } - void clear() override { /* ignored */ } - - void randomize(uint8_t out[], size_t len) override - { - Botan::clear_mem(out, len); - m_chacha.cipher1(out, len); - } - - bool is_seeded() const override { return true; } - - void add_entropy(const uint8_t[], size_t) override { /* ignored */ } - - ChaCha20_RNG() - { - std::vector seed(32, 0x82); - m_chacha.set_key(seed); - } - - private: - Botan::ChaCha m_chacha; - }; - - static ChaCha20_RNG rng; - return rng; - } - -#define FUZZER_ASSERT_EQUAL(x, y) do { \ - if(x != y) { \ - std::cerr << #x << " = " << x << " !=\n" << #y << " = " << y \ - << " at " << __LINE__ << ":" << __FILE__ << std::endl; \ - abort(); \ -} } while(0) - -#define FUZZER_ASSERT_TRUE(e) \ - do { \ - if(!(e)) { \ - std::cerr << "Expression " << #e << " was false at " \ - << __LINE__ << ":" << __FILE__ << std::endl; \ - abort(); \ - } } while(0) - -#endif diff --git a/src/extra_tests/fuzzers/jigs/ecc_bp256.cpp b/src/extra_tests/fuzzers/jigs/ecc_bp256.cpp deleted file mode 100644 index 07833c639..000000000 --- a/src/extra_tests/fuzzers/jigs/ecc_bp256.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include "ecc_helper.h" - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*256/8) - return; - - static EC_Group bp256("brainpool256r1"); - return check_ecc_math(bp256, in, len); - } diff --git a/src/extra_tests/fuzzers/jigs/ecc_helper.h b/src/extra_tests/fuzzers/jigs/ecc_helper.h deleted file mode 100644 index fb502452a..000000000 --- a/src/extra_tests/fuzzers/jigs/ecc_helper.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#ifndef ECC_HELPERS_H__ -#define ECC_HELPERS_H__ - -#include "driver.h" -#include -#include -#include - -void check_redc(std::function&)> redc_fn, - const Modular_Reducer& redc, - const BigInt& prime, - const BigInt& x) - { - const Botan::BigInt v1 = x % prime; - const Botan::BigInt v2 = redc.reduce(x); - - Botan::secure_vector ws; - Botan::BigInt v3 = x; - redc_fn(v3, ws); - - FUZZER_ASSERT_EQUAL(v1, v2); - FUZZER_ASSERT_EQUAL(v2, v3); - } - -inline std::ostream& operator<<(std::ostream& o, const PointGFp& point) - { - o << point.get_affine_x() << "," << point.get_affine_y(); - return o; - } - -void check_ecc_math(const EC_Group& group, - const uint8_t in[], size_t len) - { - // These depend only on the group, which is also static - static const Botan::PointGFp base_point = group.get_base_point(); - static Botan::Blinded_Point_Multiply blind(base_point, group.get_order(), 4); - - const size_t hlen = len / 2; - const BigInt a = BigInt::decode(in, hlen); - const BigInt b = BigInt::decode(in + hlen, len - hlen); - - const Botan::BigInt c = a + b; - - const Botan::PointGFp P = base_point * a; - const Botan::PointGFp Q = base_point * b; - const Botan::PointGFp R = base_point * c; - - const Botan::PointGFp A1 = P + Q; - const Botan::PointGFp A2 = Q + P; - - FUZZER_ASSERT_EQUAL(A1, A2); - - const Botan::PointGFp P1 = blind.blinded_multiply(a, fuzzer_rng()); - const Botan::PointGFp Q1 = blind.blinded_multiply(b, fuzzer_rng()); - const Botan::PointGFp R1 = blind.blinded_multiply(c, fuzzer_rng()); - - const Botan::PointGFp S1 = P1 + Q1; - const Botan::PointGFp S2 = Q1 + P1; - - FUZZER_ASSERT_EQUAL(S1, S2); - FUZZER_ASSERT_EQUAL(S1, A1); - } - -#endif diff --git a/src/extra_tests/fuzzers/jigs/ecc_p256.cpp b/src/extra_tests/fuzzers/jigs/ecc_p256.cpp deleted file mode 100644 index f13104fda..000000000 --- a/src/extra_tests/fuzzers/jigs/ecc_p256.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include "ecc_helper.h" - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*256/8) - return; - static EC_Group p256("secp256r1"); - return check_ecc_math(p256, in, len); - } diff --git a/src/extra_tests/fuzzers/jigs/ecc_p384.cpp b/src/extra_tests/fuzzers/jigs/ecc_p384.cpp deleted file mode 100644 index 47826e1d6..000000000 --- a/src/extra_tests/fuzzers/jigs/ecc_p384.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include "ecc_helper.h" - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*384/8) - return; - static EC_Group p384("secp384r1"); - return check_ecc_math(p384, in, len); - } diff --git a/src/extra_tests/fuzzers/jigs/ecc_p521.cpp b/src/extra_tests/fuzzers/jigs/ecc_p521.cpp deleted file mode 100644 index c2d1e36bb..000000000 --- a/src/extra_tests/fuzzers/jigs/ecc_p521.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include "ecc_helper.h" - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*(521+7)/8) - return; - static EC_Group p521("secp521r1"); - return check_ecc_math(p521, in, len); - } diff --git a/src/extra_tests/fuzzers/jigs/invert.cpp b/src/extra_tests/fuzzers/jigs/invert.cpp deleted file mode 100644 index 63c140139..000000000 --- a/src/extra_tests/fuzzers/jigs/invert.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include - -BigInt inverse_mod_ref(const BigInt& n, const BigInt& mod) - { - if(n == 0) - return 0; - - BigInt u = mod, v = n; - BigInt B = 0, D = 1; - - while(u.is_nonzero()) - { - const size_t u_zero_bits = low_zero_bits(u); - u >>= u_zero_bits; - for(size_t i = 0; i != u_zero_bits; ++i) - { - //B.cond_sub(B.is_odd(), mod); - if(B.is_odd()) - { B -= mod; } - B >>= 1; - } - - const size_t v_zero_bits = low_zero_bits(v); - v >>= v_zero_bits; - for(size_t i = 0; i != v_zero_bits; ++i) - { - if(D.is_odd()) - { D -= mod; } - D >>= 1; - } - - if(u >= v) { u -= v; B -= D; } - else { v -= u; D -= B; } - } - - if(v != 1) - return 0; // no modular inverse - - while(D.is_negative()) D += mod; - while(D >= mod) D -= mod; - - return D; - } - - -void fuzz(const uint8_t in[], size_t len) - { - if(len % 2 == 1 || len > 2*4096/8) - return; - - const BigInt x = BigInt::decode(in, len / 2); - BigInt mod = BigInt::decode(in + len / 2, len / 2); - - mod.set_bit(0); - - if(mod < 3 || x >= mod) - return; - - BigInt ref = inverse_mod_ref(x, mod); - BigInt ct = ct_inverse_mod_odd_modulus(x, mod); - //BigInt mon = normalized_montgomery_inverse(x, mod); - - if(ref != ct) - { - std::cout << "X = " << x << "\n"; - std::cout << "P = " << mod << "\n"; - std::cout << "GCD = " << gcd(x, mod) << "\n"; - std::cout << "Ref = " << ref << "\n"; - std::cout << "CT = " << ct << "\n"; - //std::cout << "Mon = " << mon << "\n"; - - std::cout << "RefCheck = " << (ref*ref)%mod << "\n"; - std::cout << "CTCheck = " << (ct*ct)%mod << "\n"; - //std::cout << "MonCheck = " << (mon*mon)%mod << "\n"; - abort(); - } - } - diff --git a/src/extra_tests/fuzzers/jigs/ocsp.cpp b/src/extra_tests/fuzzers/jigs/ocsp.cpp deleted file mode 100644 index 7cf2d91b0..000000000 --- a/src/extra_tests/fuzzers/jigs/ocsp.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" - -#include - -void fuzz(const uint8_t in[], size_t len) - { - try - { - OCSP::Response response(in, len); - } - catch(Botan::Exception& e) { } - } diff --git a/src/extra_tests/fuzzers/jigs/os2ecp.cpp b/src/extra_tests/fuzzers/jigs/os2ecp.cpp deleted file mode 100644 index 61ce1bd7b..000000000 --- a/src/extra_tests/fuzzers/jigs/os2ecp.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include -#include - -void check_os2ecp(const EC_Group& group, const uint8_t in[], size_t len) - { - try - { - PointGFp point = OS2ECP(in, len, group.get_curve()); - } - catch(Botan::Exception& e) {} - } - -void fuzz(const uint8_t in[], size_t len) - { - if(len >= 256) - return; - - static EC_Group p192("secp192r1"); - static EC_Group p224("secp224r1"); - static EC_Group p256("secp256r1"); - static EC_Group p384("secp384r1"); - static EC_Group p521("secp521r1"); - static EC_Group bp256("brainpool256r1"); - static EC_Group bp512("brainpool512r1"); - - check_os2ecp(p192, in, len); - check_os2ecp(p224, in, len); - check_os2ecp(p256, in, len); - check_os2ecp(p384, in, len); - check_os2ecp(p521, in, len); - check_os2ecp(p521, in, len); - check_os2ecp(bp256, in, len); - check_os2ecp(bp512, in, len); - } diff --git a/src/extra_tests/fuzzers/jigs/pkcs1.cpp b/src/extra_tests/fuzzers/jigs/pkcs1.cpp deleted file mode 100644 index 8a16d17e5..000000000 --- a/src/extra_tests/fuzzers/jigs/pkcs1.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" - -#include -#include - -secure_vector simple_pkcs1_unpad(const byte in[], size_t len) - { - if(len < 10) - throw Botan::Decoding_Error("bad len"); - - if(in[0] != 0 || in[1] != 2) - throw Botan::Decoding_Error("bad header field"); - - for(size_t i = 2; i < len; ++i) - { - if(in[i] == 0) - { - if(i < 10) // at least 8 padding bytes required - throw Botan::Decoding_Error("insufficient padding bytes"); - return secure_vector(in + i + 1, in + len); - } - } - - throw Botan::Decoding_Error("delim not found"); - } - -void fuzz(const uint8_t in[], size_t len) - { - static EME_PKCS1v15 pkcs1; - - secure_vector lib_result, ref_result; - bool lib_rejected = false, ref_rejected = false; - - try - { - byte valid_mask = 0; - secure_vector decoded = ((EME*)&pkcs1)->unpad(valid_mask, in, len); - - if(valid_mask == 0) - lib_rejected = true; - else if(valid_mask == 0xFF) - lib_rejected = false; - else - abort(); - } - catch(Botan::Decoding_Error&) { lib_rejected = true; } - - try - { - ref_result = simple_pkcs1_unpad(in, len); - } - catch(Botan::Decoding_Error& e) { ref_rejected = true; /*printf("%s\n", e.what());*/ } - - if(lib_rejected == ref_rejected) - { - return; // ok, they agree - } - - // otherwise: incorrect result, log info and crash - if(lib_rejected == true && ref_rejected == false) - { - std::cerr << "Library rejected input accepted by ref\n"; - std::cerr << "Ref decoded " << hex_encode(ref_result) << "\n"; - } - else if(ref_rejected == true && lib_rejected == false) - { - std::cerr << "Library accepted input reject by ref\n"; - std::cerr << "Lib decoded " << hex_encode(lib_result) << "\n"; - } - - abort(); - } diff --git a/src/extra_tests/fuzzers/jigs/pkcs8.cpp b/src/extra_tests/fuzzers/jigs/pkcs8.cpp deleted file mode 100644 index 47c0068ad..000000000 --- a/src/extra_tests/fuzzers/jigs/pkcs8.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" - -#include - -void fuzz(const uint8_t in[], size_t len) - { - try - { - DataSource_Memory input(in, len); - std::unique_ptr key(PKCS8::load_key(input, fuzzer_rng())); - } - catch(Botan::Exception& e) { } - } diff --git a/src/extra_tests/fuzzers/jigs/pow_mod.cpp b/src/extra_tests/fuzzers/jigs/pow_mod.cpp deleted file mode 100644 index c97dd78cd..000000000 --- a/src/extra_tests/fuzzers/jigs/pow_mod.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* -* (C) 2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include -#include -#include - -BigInt simple_power_mod(BigInt x, BigInt n, const BigInt& p, const Modular_Reducer& mod_p) - { - if(n == 0) - { - if(p == 1) - return 0; - return 1; - } - - BigInt y = 1; - - while(n > 1) - { - if(n.is_odd()) - { - y = mod_p.multiply(x, y); - } - x = mod_p.square(x); - n >>= 1; - } - return mod_p.multiply(x, y); - } - -void fuzz(const uint8_t in[], size_t len) - { - static const size_t p_bits = 1024; - static const BigInt p = random_prime(fuzzer_rng(), p_bits); - static Modular_Reducer mod_p(p); - - if(len == 0 || len > p_bits/8) - return; - - try - { - const BigInt g = BigInt::decode(in, len / 2); - const BigInt x = BigInt::decode(in + len / 2, len / 2); - - const BigInt ref = simple_power_mod(g, x, p, mod_p); - const BigInt z = Botan::power_mod(g, x, p); - - if(ref != z) - { - std::cout << "G = " << g << "\n" - << "X = " << x << "\n" - << "P = " << p << "\n" - << "Z = " << z << "\n" - << "R = " << ref << "\n"; - abort(); - } - } - catch(Botan::Exception& e) {} - } diff --git a/src/extra_tests/fuzzers/jigs/redc_p192.cpp b/src/extra_tests/fuzzers/jigs/redc_p192.cpp deleted file mode 100644 index 9bece4595..000000000 --- a/src/extra_tests/fuzzers/jigs/redc_p192.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include "ecc_helper.h" -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*192/8) - return; - - static const BigInt& prime = Botan::prime_p192(); - static const BigInt prime_2 = prime * prime; - static Botan::Modular_Reducer prime_redc(prime); - - Botan::BigInt x = Botan::BigInt::decode(in, len); - - if(x < prime_2) - { - check_redc(Botan::redc_p192, prime_redc, prime, x); - } - } diff --git a/src/extra_tests/fuzzers/jigs/redc_p224.cpp b/src/extra_tests/fuzzers/jigs/redc_p224.cpp deleted file mode 100644 index 637d9e6fd..000000000 --- a/src/extra_tests/fuzzers/jigs/redc_p224.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include "ecc_helper.h" -#include - -void fuzz(const uint8_t in[], size_t len) - { - static const BigInt& prime = Botan::prime_p224(); - static const BigInt prime_2 = prime * prime; - static Botan::Modular_Reducer prime_redc(prime); - - Botan::BigInt x = Botan::BigInt::decode(in, len); - - if(x < prime_2) - { - check_redc(Botan::redc_p224, prime_redc, prime, x); - } - } diff --git a/src/extra_tests/fuzzers/jigs/redc_p256.cpp b/src/extra_tests/fuzzers/jigs/redc_p256.cpp deleted file mode 100644 index cbb7f4fef..000000000 --- a/src/extra_tests/fuzzers/jigs/redc_p256.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include "ecc_helper.h" -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*256/8) - return; - - static const BigInt& prime = Botan::prime_p256(); - static const BigInt prime_2 = prime * prime; - static Botan::Modular_Reducer prime_redc(prime); - - Botan::BigInt x = Botan::BigInt::decode(in, len); - - if(x < prime_2) - { - check_redc(Botan::redc_p256, prime_redc, prime, x); - } - } diff --git a/src/extra_tests/fuzzers/jigs/redc_p384.cpp b/src/extra_tests/fuzzers/jigs/redc_p384.cpp deleted file mode 100644 index 3b990fb63..000000000 --- a/src/extra_tests/fuzzers/jigs/redc_p384.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include "ecc_helper.h" -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*384/8) - return; - - static const BigInt& prime = Botan::prime_p384(); - static const BigInt prime_2 = prime * prime; - static Botan::Modular_Reducer prime_redc(prime); - - Botan::BigInt x = Botan::BigInt::decode(in, len); - - if(x < prime_2) - { - check_redc(Botan::redc_p384, prime_redc, prime, x); - } - } diff --git a/src/extra_tests/fuzzers/jigs/redc_p521.cpp b/src/extra_tests/fuzzers/jigs/redc_p521.cpp deleted file mode 100644 index 5142a44c2..000000000 --- a/src/extra_tests/fuzzers/jigs/redc_p521.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include "ecc_helper.h" -#include - -void fuzz(const uint8_t in[], size_t len) - { - if(len > 2*(521+7)/8) - return; - - static const BigInt& prime = Botan::prime_p521(); - static const BigInt prime_2 = prime * prime; - static Botan::Modular_Reducer prime_redc(prime); - - Botan::BigInt x = Botan::BigInt::decode(in, len); - - if(x < prime_2) - { - check_redc(Botan::redc_p521, prime_redc, prime, x); - } - } diff --git a/src/extra_tests/fuzzers/jigs/ressol.cpp b/src/extra_tests/fuzzers/jigs/ressol.cpp deleted file mode 100644 index 6fbb85690..000000000 --- a/src/extra_tests/fuzzers/jigs/ressol.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include -#include - -void fuzz(const uint8_t in[], size_t len) - { - // Ressol is mostly used for ECC point decompression so best to test smaller sizes - static const size_t p_bits = 256; - static const BigInt p = random_prime(fuzzer_rng(), p_bits); - static const Modular_Reducer mod_p(p); - - if(len > p_bits / 8) - return; - - try - { - const BigInt a = BigInt::decode(in, len); - BigInt a_sqrt = Botan::ressol(a, p); - - if(a_sqrt > 0) - { - const BigInt a_redc = mod_p.reduce(a); - const BigInt z = mod_p.square(a_sqrt); - - if(z != a_redc) - { - std::cout << "A = " << a << "\n"; - std::cout << "P = " << p << "\n"; - std::cout << "R = " << a_sqrt << "\n"; - std::cout << "Z = " << z << "\n"; - abort(); - } - } - } - catch(Botan::Exception& e) {} - - return; - } - diff --git a/src/extra_tests/fuzzers/jigs/tls_client.cpp b/src/extra_tests/fuzzers/jigs/tls_client.cpp deleted file mode 100644 index d3fbd069c..000000000 --- a/src/extra_tests/fuzzers/jigs/tls_client.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include - -class Fuzzer_TLS_Client_Creds : public Credentials_Manager - { - public: - std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } - std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } - SymmetricKey psk(const std::string&, const std::string&, const std::string&) override - { - return SymmetricKey("AABBCCDDEEFF00112233445566778899"); - } - }; - -void fuzz(const uint8_t in[], size_t len) - { - if(len == 0) - return; - - auto dev_null = [](const byte[], size_t) {}; - - auto ignore_alerts = [](TLS::Alert, const byte[], size_t) {}; - auto ignore_hs = [](const TLS::Session&) { abort(); return true; }; - - TLS::Session_Manager_Noop session_manager; - TLS::Policy policy; - TLS::Protocol_Version client_offer = TLS::Protocol_Version::TLS_V12; - TLS::Server_Information info("server.name", 443); - Fuzzer_TLS_Client_Creds creds; - - TLS::Client client(dev_null, - dev_null, - ignore_alerts, - ignore_hs, - session_manager, - creds, - policy, - fuzzer_rng(), - info, - client_offer); - - try - { - client.received_data(in, len); - } - catch(std::exception& e) - { - } - - } - diff --git a/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp b/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp deleted file mode 100644 index 7c95c7db3..000000000 --- a/src/extra_tests/fuzzers/jigs/tls_client_hello.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ -#include "driver.h" -#include - -void fuzz(const uint8_t in[], size_t len) - { - try - { - std::vector v(in, in + len); - Botan::TLS::Client_Hello ch(v); - } - catch(Botan::Exception& e) {} - } diff --git a/src/extra_tests/fuzzers/jigs/tls_server.cpp b/src/extra_tests/fuzzers/jigs/tls_server.cpp deleted file mode 100644 index a4e0d5f00..000000000 --- a/src/extra_tests/fuzzers/jigs/tls_server.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* -* (C) 2015,2016 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include "driver.h" -#include - -const char* fixed_rsa_key = - "-----BEGIN PRIVATE KEY-----\n" - "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCe6qqpMQVJ7zCJ\n" - "oSnpxia0yO6M7Ie3FGqPcd0DzueC+kWPvuHQ+PpP5vfO6qqRaDVII37PFX5NUZQm\n" - "GK/rAm7spjIHTCMgqSZ8pN13LU8m1gDwIdu9al16LXN9zZjB67uLlFn2trtLi234\n" - "i0cnyeF8IC0cz7tgCOzMSVEBcqJjkdgGrZ3WUgOXecVm2lXVrYlEiaSxFp4VOE9k\n" - "RFeVrELCjmNtc4hRd1yJsF+vObCtvyqGYQE1Qcb0MVSQDBHMkiUVmO6zuW7td5ef\n" - "O/1OyntQJGyVa+SnWbkSLCybta2J7MreHENrF5GA0K1KL140SNRHeWifRMuNQua7\n" - "qmKXMBTFAgMBAAECggEAIk3fxyQI0zvpy1vZ01ft1QqmzA7nAPNMSWi33/GS8iga\n" - "SfxXfKeySPs/tQ/dAARxs//NiOBH4mLgyxR7LQzaawU5OXALCSraXv+ruuUx990s\n" - "WKnGaG4EfbJAAwEVn47Gbkv425P4fEc91vAhzQn8PbIoatbAyOtESpjs/pYDTeC/\n" - "mnJId8gqO90cqyRECEMjk9sQ8iEjWPlik4ayGlUVbeeMu6/pJ9F8IZEgkLZiNDAB\n" - "4anmOFaT7EmqUjI4IlcaqfbbXyDXlvWUYukidEss+CNvPuqbQHBDnpFVvBxdDR2N\n" - "Uj2D5Xd5blcIe2/+1IVRnznjoQ5zvutzb7ThBmMehQKBgQDOITKG0ht2kXLxjVoR\n" - "r/pVpx+f3hs3H7wE0+vrLHoQgkVjpMWXQ47YuZTT9rCOOYNI2cMoH2D27t1j78/B\n" - "9kGYABUVpvQQ+6amqJDI1eYI6e68TPueEDjeALfSCdmPNiI3lZZrCIK9XLpkoy8K\n" - "tGYBRRJ+JJxjj1zPXj9SGshPgwKBgQDFXUtoxY3mCStH3+0b1qxGG9r1L5goHEmd\n" - "Am8WBYDheNpL0VqPNzouhuM/ZWMGyyAs/py6aLATe+qhR1uX5vn7LVZwjCSONZ4j\n" - "7ieEEUh1BHetPI1oI5PxgokRYfVuckotqVseanI/536Er3Yf2FXNQ1/ceVp9WykX\n" - "3mYTKMhQFwKBgQDKakcXpZNaZ5IcKdZcsBZ/rdGcR5sqEnursf9lvRNQytwg8Vkn\n" - "JSxNHlBLpV/TCh8lltHRwJ6TXhUBYij+KzhWbx5FWOErHDOWTMmArqtp7W6GcoJT\n" - "wVJWjxXzp8CApYQMWVSQXpckJL7UvHohZO0WKiHyxTjde5aD++TqV2qEyQKBgBbD\n" - "jvoTpy08K4DLxCZs2Uvw1I1pIuylbpwsdrGciuP2s38BM6fHH+/T4Qwj3osfDKQD\n" - "7gHWJ1Dn/wUBHQBlRLoC3bB3iZPZfVb5lhc2gxv0GvWhQVIcoGi/vJ2DpfJKPmIL\n" - "4ZWdg3X5dm9JaZ98rVDSj5D3ckd5J0E4hp95GbmbAoGBAJJHM4O9lx60tIjw9Sf/\n" - "QmKWyUk0NLnt8DcgRMW7fVxtzPNDy9DBKGIkDdWZ2s+ForICA3C9WSxBC1EOEHGG\n" - "xkg2xKt66CeutGroP6M191mHQrRClt1VbEYzQFX21BCk5kig9i/BURyoTHtFiV+t\n" - "kbf4VLg8Vk9u/R3RU1HsYWhe\n" - "-----END PRIVATE KEY-----\n"; - -const char* fixed_rsa_cert = - "-----BEGIN CERTIFICATE-----\n" - "MIIDUDCCAjgCCQD7pIb1ZsoafjANBgkqhkiG9w0BAQsFADBqMQswCQYDVQQGEwJW\n" - "VDEQMA4GA1UECAwHVmVybW9udDEWMBQGA1UEBwwNVGhlIEludGVybmV0czEUMBIG\n" - "A1UECgwLTWFuZ29zIFIgVXMxGzAZBgNVBAMMEnNlcnZlci5leGFtcGxlLmNvbTAe\n" - "Fw0xNjAxMDYxNzQ3MjNaFw0yNjAxMDMxNzQ3MjNaMGoxCzAJBgNVBAYTAlZUMRAw\n" - "DgYDVQQIDAdWZXJtb250MRYwFAYDVQQHDA1UaGUgSW50ZXJuZXRzMRQwEgYDVQQK\n" - "DAtNYW5nb3MgUiBVczEbMBkGA1UEAwwSc2VydmVyLmV4YW1wbGUuY29tMIIBIjAN\n" - "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnuqqqTEFSe8wiaEp6cYmtMjujOyH\n" - "txRqj3HdA87ngvpFj77h0Pj6T+b3zuqqkWg1SCN+zxV+TVGUJhiv6wJu7KYyB0wj\n" - "IKkmfKTddy1PJtYA8CHbvWpdei1zfc2Yweu7i5RZ9ra7S4tt+ItHJ8nhfCAtHM+7\n" - "YAjszElRAXKiY5HYBq2d1lIDl3nFZtpV1a2JRImksRaeFThPZERXlaxCwo5jbXOI\n" - "UXdcibBfrzmwrb8qhmEBNUHG9DFUkAwRzJIlFZjus7lu7XeXnzv9Tsp7UCRslWvk\n" - "p1m5Eiwsm7WtiezK3hxDaxeRgNCtSi9eNEjUR3lon0TLjULmu6pilzAUxQIDAQAB\n" - "MA0GCSqGSIb3DQEBCwUAA4IBAQA1eZGc/4V7z/E/6eG0hVkzoAZeuTcSP7WqBSx+\n" - "OP2yh0163UYjoa6nehmkKYQQ9PbYPZGzIcl+dBFyYzy6jcp0NdtzpWnTFrjl4rMq\n" - "akcQ1D0LTYjJXVP9G/vF/SvatOFeVTnQmLlLt/a8ZtRUINqejeZZPzH8ifzFW6tu\n" - "mlhTVIEKyPHpxClh5Y3ubw/mZYygekFTqMkTx3FwJxKU8J6rYGZxanWAODUIvCUo\n" - "Fxer1qC5Love3uWl3vXPLEZWZdORnExSRByzz2immBP2vX4zYZoeZRhTQ9ae1TIV\n" - "Dk02a/1AOJZdZReDbgXhlqaUx5pk/rzo4mDzvu5HSCeXmClz\n" - "-----END CERTIFICATE-----\n"; - -class Fuzzer_TLS_Server_Creds : public Credentials_Manager - { - public: - Fuzzer_TLS_Server_Creds() - { - DataSource_Memory cert_in(fixed_rsa_cert); - DataSource_Memory key_in(fixed_rsa_key); - - m_rsa_cert.reset(new Botan::X509_Certificate(cert_in)); - //m_rsa_key.reset(Botan::PKCS8::load_key(key_in, fuzzer_rng()); - } - - std::vector cert_chain( - const std::vector& algos, - const std::string& type, - const std::string& hostname) override - { - std::vector v; - - for(auto algo : algos) - { - if(algo == "RSA") - { - v.push_back(*m_rsa_cert); - break; - } - } - - return v; - } - - Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, - const std::string& /*type*/, - const std::string& /*context*/) override - { - return m_rsa_key.get(); - } - - std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } - std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } - SymmetricKey psk(const std::string&, const std::string&, const std::string&) override - { - return SymmetricKey("AABBCCDDEEFF00112233445566778899"); - } - private: - std::unique_ptr m_rsa_cert; - std::unique_ptr m_rsa_key; - }; - -void fuzz(const uint8_t in[], size_t len) - { - if(len == 0) - return; - - auto dev_null = [](const byte[], size_t) {}; - - auto ignore_alerts = [](TLS::Alert, const byte[], size_t) {}; - auto ignore_hs = [](const TLS::Session&) { return true; }; - - TLS::Session_Manager_Noop session_manager; - TLS::Policy policy; - TLS::Server_Information info("server.name", 443); - Fuzzer_TLS_Server_Creds creds; - - auto next_proto_fn = [](const std::vector& protos) -> std::string { - if(protos.size() > 1) - return protos[0]; - else - return "fuzzed"; - }; - - const bool is_datagram = (len % 2 == 0); - - TLS::Server server(dev_null, - dev_null, - ignore_alerts, - ignore_hs, - session_manager, - creds, - policy, - fuzzer_rng(), - next_proto_fn, - is_datagram); - - try - { - server.received_data(in, len); - } - catch(std::exception& e) - { - } - } diff --git a/src/extra_tests/fuzzers/readme.txt b/src/extra_tests/fuzzers/readme.txt deleted file mode 100644 index 1bee1a785..000000000 --- a/src/extra_tests/fuzzers/readme.txt +++ /dev/null @@ -1,49 +0,0 @@ - -The code in this directory is for testing various message decoders and -math functions using the fuzzers AFL (http://lcamtuf.coredump.cx/afl/) -and libFuzzer (http://llvm.org/docs/LibFuzzer.html). - -To build for AFL, run - - make afl - -For libFuzzer - - make llvm - -To add a new fuzzer, create a new file in jigs/, include "driver.h", -and implement the function with the signature - -void fuzz(const uint8_t buf[], size_t len); - -This function should abort/crash if something is incorrect. - -Run it with - -make run_{llvm,afl}_{what} - -like in - -make run_llvm_crl -make run_afl_tls_client - -You can pass args to the fuzzer process using args= - -make args=-max_len=4000 run_llvm_tls_client - -The fuzzer entry point assumes no more than 4K of input. The base -libFuzzer default max len is 64 bytes, the makefile sets it to 140 as -default. - -Use - -make cmin_redc_p384 - -to run afl-cmin to minimize and merge the LLVM and AFL outputs back to -the corpus directory. - -TODO: - -- KLEE (https://klee.github.io) -- DFSan (http://clang.llvm.org/docs/DataFlowSanitizer.html) -- More jigs diff --git a/src/fuzzer/asn1.cpp b/src/fuzzer/asn1.cpp new file mode 100644 index 000000000..b0ea553e5 --- /dev/null +++ b/src/fuzzer/asn1.cpp @@ -0,0 +1,24 @@ +/* +* (C) 2016,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + Botan::DataSource_Memory input(in, len); + Botan::BER_Decoder dec(input); + + while(dec.more_items()) + { + Botan::BER_Object obj; + dec.get_next(obj); + } + } + catch(Botan::Exception& e) { } + } diff --git a/src/fuzzer/bn_sqr.cpp b/src/fuzzer/bn_sqr.cpp new file mode 100644 index 000000000..f507c4a79 --- /dev/null +++ b/src/fuzzer/bn_sqr.cpp @@ -0,0 +1,24 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" + +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 8192/8) + return; + + Botan::BigInt x = Botan::BigInt::decode(in, len); + + Botan::BigInt x_sqr = square(x); + Botan::BigInt x_mul = x * x; + + FUZZER_ASSERT_EQUAL(x_sqr, x_mul); + } + diff --git a/src/fuzzer/cert.cpp b/src/fuzzer/cert.cpp new file mode 100644 index 000000000..3b40020df --- /dev/null +++ b/src/fuzzer/cert.cpp @@ -0,0 +1,21 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > max_fuzzer_input_size) + return; + + try + { + Botan::DataSource_Memory input(in, len); + Botan::X509_Certificate cert(input); + } + catch(Botan::Exception& e) { } + } diff --git a/src/fuzzer/crl.cpp b/src/fuzzer/crl.cpp new file mode 100644 index 000000000..63699b9b3 --- /dev/null +++ b/src/fuzzer/crl.cpp @@ -0,0 +1,18 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + Botan::DataSource_Memory input(in, len); + Botan::X509_CRL crl(input); + } + catch(Botan::Exception& e) {} + } diff --git a/src/fuzzer/divide.cpp b/src/fuzzer/divide.cpp new file mode 100644 index 000000000..01ec14e28 --- /dev/null +++ b/src/fuzzer/divide.cpp @@ -0,0 +1,29 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len % 2 == 1 || len > 2*4096/8) + return; + + const Botan::BigInt x = Botan::BigInt::decode(in, len / 2); + const Botan::BigInt y = Botan::BigInt::decode(in + len / 2, len / 2); + + if(y == 0) + return; + + Botan::BigInt q, r; + Botan::divide(x, y, q, r); + + FUZZER_ASSERT_TRUE(r < y); + + Botan::BigInt z = q*y + r; + + FUZZER_ASSERT_EQUAL(z, x); + } + diff --git a/src/fuzzer/ecc_bp256.cpp b/src/fuzzer/ecc_bp256.cpp new file mode 100644 index 000000000..4c1186f06 --- /dev/null +++ b/src/fuzzer/ecc_bp256.cpp @@ -0,0 +1,16 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*256/8) + return; + + static Botan::EC_Group bp256("brainpool256r1"); + return check_ecc_math(bp256, in, len); + } diff --git a/src/fuzzer/ecc_helper.h b/src/fuzzer/ecc_helper.h new file mode 100644 index 000000000..c9b3a6604 --- /dev/null +++ b/src/fuzzer/ecc_helper.h @@ -0,0 +1,58 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef ECC_HELPERS_H__ +#define ECC_HELPERS_H__ + +#include "fuzzers.h" +#include +#include +#include + +namespace { + +inline std::ostream& operator<<(std::ostream& o, const Botan::PointGFp& point) + { + o << point.get_affine_x() << "," << point.get_affine_y(); + return o; + } + +void check_ecc_math(const Botan::EC_Group& group, + const uint8_t in[], size_t len) + { + // These depend only on the group, which is also static + static const Botan::PointGFp base_point = group.get_base_point(); + static Botan::Blinded_Point_Multiply blind(base_point, group.get_order(), 4); + + const size_t hlen = len / 2; + const Botan::BigInt a = Botan::BigInt::decode(in, hlen); + const Botan::BigInt b = Botan::BigInt::decode(in + hlen, len - hlen); + + const Botan::BigInt c = a + b; + + const Botan::PointGFp P = base_point * a; + const Botan::PointGFp Q = base_point * b; + const Botan::PointGFp R = base_point * c; + + const Botan::PointGFp A1 = P + Q; + const Botan::PointGFp A2 = Q + P; + + FUZZER_ASSERT_EQUAL(A1, A2); + + const Botan::PointGFp P1 = blind.blinded_multiply(a, fuzzer_rng()); + const Botan::PointGFp Q1 = blind.blinded_multiply(b, fuzzer_rng()); + const Botan::PointGFp R1 = blind.blinded_multiply(c, fuzzer_rng()); + + const Botan::PointGFp S1 = P1 + Q1; + const Botan::PointGFp S2 = Q1 + P1; + + FUZZER_ASSERT_EQUAL(S1, S2); + FUZZER_ASSERT_EQUAL(S1, A1); + } + +} + +#endif diff --git a/src/fuzzer/ecc_p256.cpp b/src/fuzzer/ecc_p256.cpp new file mode 100644 index 000000000..c00be71b6 --- /dev/null +++ b/src/fuzzer/ecc_p256.cpp @@ -0,0 +1,15 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*256/8) + return; + static Botan::EC_Group p256("secp256r1"); + return check_ecc_math(p256, in, len); + } diff --git a/src/fuzzer/ecc_p384.cpp b/src/fuzzer/ecc_p384.cpp new file mode 100644 index 000000000..1b58da958 --- /dev/null +++ b/src/fuzzer/ecc_p384.cpp @@ -0,0 +1,15 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*384/8) + return; + static Botan::EC_Group p384("secp384r1"); + return check_ecc_math(p384, in, len); + } diff --git a/src/fuzzer/ecc_p521.cpp b/src/fuzzer/ecc_p521.cpp new file mode 100644 index 000000000..3b9ed2d5c --- /dev/null +++ b/src/fuzzer/ecc_p521.cpp @@ -0,0 +1,15 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*(521+7)/8) + return; + static Botan::EC_Group p521("secp521r1"); + return check_ecc_math(p521, in, len); + } diff --git a/src/fuzzer/fuzzers.h b/src/fuzzer/fuzzers.h new file mode 100644 index 000000000..2f1b1346d --- /dev/null +++ b/src/fuzzer/fuzzers.h @@ -0,0 +1,95 @@ +/* +* (C) 2015,2016,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FUZZER_DRIVER_H__ +#define BOTAN_FUZZER_DRIVER_H__ + +#include +#include // for setenv +#include +#include +#include +#include + +#if defined(BOTAN_FUZZER_IS_AFL) && !defined(__AFL_COMPILER) + #error "Build configured for AFL but not being compiled by AFL compiler" +#endif + +static const size_t max_fuzzer_input_size = 8192; + +extern void fuzz(const uint8_t in[], size_t len); +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len); + +extern "C" int LLVMFuzzerInitialize(int *, char ***) + { + /* + * This disables the mlock pool, as overwrites within the pool are + * opaque to ASan or other instrumentation. + */ + ::setenv("BOTAN_MLOCK_POOL_SIZE", "0", 1); + return 0; + } + +// Called by main() in libFuzzer or in main for AFL below +extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len) + { + if(len <= max_fuzzer_input_size) + { + fuzz(in, len); + } + return 0; + } + +// Some helpers for the fuzzer jigs + +inline Botan::RandomNumberGenerator& fuzzer_rng() + { + static Botan::ChaCha_RNG rng(Botan::secure_vector(32)); + return rng; + } + +#define FUZZER_ASSERT_EQUAL(x, y) do { \ + if(x != y) { \ + std::cerr << #x << " = " << x << " !=\n" << #y << " = " << y \ + << " at " << __LINE__ << ":" << __FILE__ << std::endl; \ + abort(); \ +} } while(0) + +#define FUZZER_ASSERT_TRUE(e) \ + do { \ + if(!(e)) { \ + std::cerr << "Expression " << #e << " was false at " \ + << __LINE__ << ":" << __FILE__ << std::endl; \ + abort(); \ + } } while(0) + +#if defined(BOTAN_FUZZER_IS_AFL) || defined(BOTAN_FUZZER_IS_TEST) + +/* Stub for AFL */ + +int main(int argc, char* argv[]) + { + LLVMFuzzerInitialize(&argc, &argv); + +#if defined(__AFL_LOOP) + while(__AFL_LOOP(1000)) +#endif + { + std::vector buf(max_fuzzer_input_size); + std::cin.read((char*)buf.data(), buf.size()); + const size_t got = std::cin.gcount(); + + buf.resize(got); + buf.shrink_to_fit(); + + LLVMFuzzerTestOneInput(buf.data(), got); + } + } + +#endif + +#endif diff --git a/src/fuzzer/invert.cpp b/src/fuzzer/invert.cpp new file mode 100644 index 000000000..08e8229b8 --- /dev/null +++ b/src/fuzzer/invert.cpp @@ -0,0 +1,87 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include + +namespace { + +Botan::BigInt inverse_mod_ref(const Botan::BigInt& n, const Botan::BigInt& mod) + { + if(n == 0) + return 0; + + Botan::BigInt u = mod, v = n; + Botan::BigInt B = 0, D = 1; + + while(u.is_nonzero()) + { + const size_t u_zero_bits = low_zero_bits(u); + u >>= u_zero_bits; + for(size_t i = 0; i != u_zero_bits; ++i) + { + //B.cond_sub(B.is_odd(), mod); + if(B.is_odd()) + { B -= mod; } + B >>= 1; + } + + const size_t v_zero_bits = low_zero_bits(v); + v >>= v_zero_bits; + for(size_t i = 0; i != v_zero_bits; ++i) + { + if(D.is_odd()) + { D -= mod; } + D >>= 1; + } + + if(u >= v) { u -= v; B -= D; } + else { v -= u; D -= B; } + } + + if(v != 1) + return 0; // no modular inverse + + while(D.is_negative()) D += mod; + while(D >= mod) D -= mod; + + return D; + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + if(len % 2 == 1 || len > 2*4096/8) + return; + + const Botan::BigInt x = Botan::BigInt::decode(in, len / 2); + Botan::BigInt mod = Botan::BigInt::decode(in + len / 2, len / 2); + + mod.set_bit(0); + + if(mod < 3 || x >= mod) + return; + + Botan::BigInt ref = inverse_mod_ref(x, mod); + Botan::BigInt ct = Botan::ct_inverse_mod_odd_modulus(x, mod); + //Botan::BigInt mon = Botan::normalized_montgomery_inverse(x, mod); + + if(ref != ct) + { + std::cout << "X = " << x << "\n"; + std::cout << "P = " << mod << "\n"; + std::cout << "GCD = " << gcd(x, mod) << "\n"; + std::cout << "Ref = " << ref << "\n"; + std::cout << "CT = " << ct << "\n"; + //std::cout << "Mon = " << mon << "\n"; + + std::cout << "RefCheck = " << (ref*ref)%mod << "\n"; + std::cout << "CTCheck = " << (ct*ct)%mod << "\n"; + //std::cout << "MonCheck = " << (mon*mon)%mod << "\n"; + abort(); + } + } + diff --git a/src/fuzzer/ocsp.cpp b/src/fuzzer/ocsp.cpp new file mode 100644 index 000000000..0db265b8d --- /dev/null +++ b/src/fuzzer/ocsp.cpp @@ -0,0 +1,17 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + Botan::OCSP::Response response(in, len); + } + catch(Botan::Exception& e) { } + } diff --git a/src/fuzzer/os2ecp.cpp b/src/fuzzer/os2ecp.cpp new file mode 100644 index 000000000..dba6dbdfe --- /dev/null +++ b/src/fuzzer/os2ecp.cpp @@ -0,0 +1,44 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include +#include + +namespace { + +void check_os2ecp(const Botan::EC_Group& group, const uint8_t in[], size_t len) + { + try + { + Botan::PointGFp point = Botan::OS2ECP(in, len, group.get_curve()); + } + catch(Botan::Exception& e) {} + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + if(len >= 256) + return; + + static Botan::EC_Group p192("secp192r1"); + static Botan::EC_Group p224("secp224r1"); + static Botan::EC_Group p256("secp256r1"); + static Botan::EC_Group p384("secp384r1"); + static Botan::EC_Group p521("secp521r1"); + static Botan::EC_Group bp256("brainpool256r1"); + static Botan::EC_Group bp512("brainpool512r1"); + + check_os2ecp(p192, in, len); + check_os2ecp(p224, in, len); + check_os2ecp(p256, in, len); + check_os2ecp(p384, in, len); + check_os2ecp(p521, in, len); + check_os2ecp(p521, in, len); + check_os2ecp(bp256, in, len); + check_os2ecp(bp512, in, len); + } diff --git a/src/fuzzer/pkcs1.cpp b/src/fuzzer/pkcs1.cpp new file mode 100644 index 000000000..a0323d2b2 --- /dev/null +++ b/src/fuzzer/pkcs1.cpp @@ -0,0 +1,82 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" + +#include +#include + +namespace { + +std::vector simple_pkcs1_unpad(const uint8_t in[], size_t len) + { + if(len < 10) + throw Botan::Decoding_Error("bad len"); + + if(in[0] != 0 || in[1] != 2) + throw Botan::Decoding_Error("bad header field"); + + for(size_t i = 2; i < len; ++i) + { + if(in[i] == 0) + { + if(i < 10) // at least 8 padding bytes required + throw Botan::Decoding_Error("insufficient padding bytes"); + return std::vector(in + i + 1, in + len); + } + } + + throw Botan::Decoding_Error("delim not found"); + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + static Botan::EME_PKCS1v15 pkcs1; + + Botan::secure_vector lib_result; + std::vector ref_result; + bool lib_rejected = false, ref_rejected = false; + + try + { + uint8_t valid_mask = 0; + Botan::secure_vector decoded = (static_cast(&pkcs1))->unpad(valid_mask, in, len); + + if(valid_mask == 0) + lib_rejected = true; + else if(valid_mask == 0xFF) + lib_rejected = false; + else + abort(); + } + catch(Botan::Decoding_Error&) { lib_rejected = true; } + + try + { + ref_result = simple_pkcs1_unpad(in, len); + } + catch(Botan::Decoding_Error& e) { ref_rejected = true; } + + if(lib_rejected == ref_rejected) + { + return; // ok, they agree + } + + // otherwise: incorrect result, log info and crash + if(lib_rejected == true && ref_rejected == false) + { + std::cerr << "Library rejected input accepted by ref\n"; + std::cerr << "Ref decoded " << Botan::hex_encode(ref_result) << "\n"; + } + else if(ref_rejected == true && lib_rejected == false) + { + std::cerr << "Library accepted input reject by ref\n"; + std::cerr << "Lib decoded " << Botan::hex_encode(lib_result) << "\n"; + } + + abort(); + } diff --git a/src/fuzzer/pkcs8.cpp b/src/fuzzer/pkcs8.cpp new file mode 100644 index 000000000..ad43d6f3e --- /dev/null +++ b/src/fuzzer/pkcs8.cpp @@ -0,0 +1,19 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" + +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + Botan::DataSource_Memory input(in, len); + Botan::Null_RNG null_rng; + std::unique_ptr key(Botan::PKCS8::load_key(input, null_rng)); + } + catch(Botan::Exception& e) { } + } diff --git a/src/fuzzer/pow_mod.cpp b/src/fuzzer/pow_mod.cpp new file mode 100644 index 000000000..2244c2004 --- /dev/null +++ b/src/fuzzer/pow_mod.cpp @@ -0,0 +1,70 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include +#include + +namespace { + +Botan::BigInt simple_power_mod(Botan::BigInt x, + Botan::BigInt n, + const Botan::BigInt& p, + const Botan::Modular_Reducer& mod_p) + { + if(n == 0) + { + if(p == 1) + return 0; + return 1; + } + + Botan::BigInt y = 1; + + while(n > 1) + { + if(n.is_odd()) + { + y = mod_p.multiply(x, y); + } + x = mod_p.square(x); + n >>= 1; + } + return mod_p.multiply(x, y); + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + static const size_t p_bits = 1024; + static const Botan::BigInt p = random_prime(fuzzer_rng(), p_bits); + static Botan::Modular_Reducer mod_p(p); + + if(len == 0 || len > p_bits/8) + return; + + try + { + const Botan::BigInt g = Botan::BigInt::decode(in, len / 2); + const Botan::BigInt x = Botan::BigInt::decode(in + len / 2, len / 2); + + const Botan::BigInt ref = simple_power_mod(g, x, p, mod_p); + const Botan::BigInt z = Botan::power_mod(g, x, p); + + if(ref != z) + { + std::cout << "G = " << g << "\n" + << "X = " << x << "\n" + << "P = " << p << "\n" + << "Z = " << z << "\n" + << "R = " << ref << "\n"; + abort(); + } + } + catch(Botan::Exception& e) {} + } diff --git a/src/fuzzer/redc_helper.h b/src/fuzzer/redc_helper.h new file mode 100644 index 000000000..4fc33894a --- /dev/null +++ b/src/fuzzer/redc_helper.h @@ -0,0 +1,33 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FUZZ_REDC_HELPERS_H__ +#define BOTAN_FUZZ_REDC_HELPERS_H__ + +#include "fuzzers.h" +#include + +namespace { + +void check_redc(std::function&)> redc_fn, + const Botan::Modular_Reducer& redc, + const Botan::BigInt& prime, + const Botan::BigInt& x) + { + const Botan::BigInt v1 = x % prime; + const Botan::BigInt v2 = redc.reduce(x); + + Botan::secure_vector ws; + Botan::BigInt v3 = x; + redc_fn(v3, ws); + + FUZZER_ASSERT_EQUAL(v1, v2); + FUZZER_ASSERT_EQUAL(v2, v3); + } + +} + +#endif diff --git a/src/fuzzer/redc_p192.cpp b/src/fuzzer/redc_p192.cpp new file mode 100644 index 000000000..e1f7c753f --- /dev/null +++ b/src/fuzzer/redc_p192.cpp @@ -0,0 +1,26 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include "redc_helper.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*192/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p192(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt x = Botan::BigInt::decode(in, len); + + if(x < prime_2) + { + check_redc(Botan::redc_p192, prime_redc, prime, x); + } + } diff --git a/src/fuzzer/redc_p224.cpp b/src/fuzzer/redc_p224.cpp new file mode 100644 index 000000000..a8a4d5d72 --- /dev/null +++ b/src/fuzzer/redc_p224.cpp @@ -0,0 +1,23 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include "redc_helper.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + static const Botan::BigInt& prime = Botan::prime_p224(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt x = Botan::BigInt::decode(in, len); + + if(x < prime_2) + { + check_redc(Botan::redc_p224, prime_redc, prime, x); + } + } diff --git a/src/fuzzer/redc_p256.cpp b/src/fuzzer/redc_p256.cpp new file mode 100644 index 000000000..b8d78e7bb --- /dev/null +++ b/src/fuzzer/redc_p256.cpp @@ -0,0 +1,26 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include "redc_helper.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*256/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p256(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt x = Botan::BigInt::decode(in, len); + + if(x < prime_2) + { + check_redc(Botan::redc_p256, prime_redc, prime, x); + } + } diff --git a/src/fuzzer/redc_p384.cpp b/src/fuzzer/redc_p384.cpp new file mode 100644 index 000000000..35e3ccfee --- /dev/null +++ b/src/fuzzer/redc_p384.cpp @@ -0,0 +1,26 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include "redc_helper.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*384/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p384(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt x = Botan::BigInt::decode(in, len); + + if(x < prime_2) + { + check_redc(Botan::redc_p384, prime_redc, prime, x); + } + } diff --git a/src/fuzzer/redc_p521.cpp b/src/fuzzer/redc_p521.cpp new file mode 100644 index 000000000..c6c5d262b --- /dev/null +++ b/src/fuzzer/redc_p521.cpp @@ -0,0 +1,26 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include "redc_helper.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*(521+7)/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p521(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt x = Botan::BigInt::decode(in, len); + + if(x < prime_2) + { + check_redc(Botan::redc_p521, prime_redc, prime, x); + } + } diff --git a/src/fuzzer/ressol.cpp b/src/fuzzer/ressol.cpp new file mode 100644 index 000000000..17ba88b8b --- /dev/null +++ b/src/fuzzer/ressol.cpp @@ -0,0 +1,45 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + // Ressol is mostly used for ECC point decompression so best to test smaller sizes + static const size_t p_bits = 256; + static const Botan::BigInt p = random_prime(fuzzer_rng(), p_bits); + static const Botan::Modular_Reducer mod_p(p); + + if(len > p_bits / 8) + return; + + try + { + const Botan::BigInt a = Botan::BigInt::decode(in, len); + Botan::BigInt a_sqrt = Botan::ressol(a, p); + + if(a_sqrt > 0) + { + const Botan::BigInt a_redc = mod_p.reduce(a); + const Botan::BigInt z = mod_p.square(a_sqrt); + + if(z != a_redc) + { + std::cout << "A = " << a << "\n"; + std::cout << "P = " << p << "\n"; + std::cout << "R = " << a_sqrt << "\n"; + std::cout << "Z = " << z << "\n"; + abort(); + } + } + } + catch(Botan::Exception& e) {} + + return; + } + diff --git a/src/fuzzer/tls_client.cpp b/src/fuzzer/tls_client.cpp new file mode 100644 index 000000000..197e97928 --- /dev/null +++ b/src/fuzzer/tls_client.cpp @@ -0,0 +1,57 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +class Fuzzer_TLS_Client_Creds : public Botan::Credentials_Manager + { + public: + std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } + std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } + Botan::SymmetricKey psk(const std::string&, const std::string&, const std::string&) override + { + return Botan::SymmetricKey("AABBCCDDEEFF00112233445566778899"); + } + }; + +void fuzz(const uint8_t in[], size_t len) + { + if(len == 0) + return; + + auto dev_null = [](const uint8_t[], size_t) {}; + + auto ignore_alerts = [](Botan::TLS::Alert, const uint8_t[], size_t) {}; + auto ignore_hs = [](const Botan::TLS::Session&) { abort(); return true; }; + + Botan::TLS::Session_Manager_Noop session_manager; + Botan::TLS::Policy policy; + Botan::TLS::Protocol_Version client_offer = Botan::TLS::Protocol_Version::TLS_V12; + Botan::TLS::Server_Information info("server.name", 443); + Fuzzer_TLS_Client_Creds creds; + + Botan::TLS::Client client(dev_null, + dev_null, + ignore_alerts, + ignore_hs, + session_manager, + creds, + policy, + fuzzer_rng(), + info, + client_offer); + + try + { + client.received_data(in, len); + } + catch(std::exception& e) + { + } + + } + diff --git a/src/fuzzer/tls_client_hello.cpp b/src/fuzzer/tls_client_hello.cpp new file mode 100644 index 000000000..28c77c9b6 --- /dev/null +++ b/src/fuzzer/tls_client_hello.cpp @@ -0,0 +1,18 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + std::vector v(in, in + len); + Botan::TLS::Client_Hello ch(v); + } + catch(Botan::Exception& e) {} + } diff --git a/src/fuzzer/tls_server.cpp b/src/fuzzer/tls_server.cpp new file mode 100644 index 000000000..54586595f --- /dev/null +++ b/src/fuzzer/tls_server.cpp @@ -0,0 +1,153 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +const char* fixed_rsa_key = + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCe6qqpMQVJ7zCJ\n" + "oSnpxia0yO6M7Ie3FGqPcd0DzueC+kWPvuHQ+PpP5vfO6qqRaDVII37PFX5NUZQm\n" + "GK/rAm7spjIHTCMgqSZ8pN13LU8m1gDwIdu9al16LXN9zZjB67uLlFn2trtLi234\n" + "i0cnyeF8IC0cz7tgCOzMSVEBcqJjkdgGrZ3WUgOXecVm2lXVrYlEiaSxFp4VOE9k\n" + "RFeVrELCjmNtc4hRd1yJsF+vObCtvyqGYQE1Qcb0MVSQDBHMkiUVmO6zuW7td5ef\n" + "O/1OyntQJGyVa+SnWbkSLCybta2J7MreHENrF5GA0K1KL140SNRHeWifRMuNQua7\n" + "qmKXMBTFAgMBAAECggEAIk3fxyQI0zvpy1vZ01ft1QqmzA7nAPNMSWi33/GS8iga\n" + "SfxXfKeySPs/tQ/dAARxs//NiOBH4mLgyxR7LQzaawU5OXALCSraXv+ruuUx990s\n" + "WKnGaG4EfbJAAwEVn47Gbkv425P4fEc91vAhzQn8PbIoatbAyOtESpjs/pYDTeC/\n" + "mnJId8gqO90cqyRECEMjk9sQ8iEjWPlik4ayGlUVbeeMu6/pJ9F8IZEgkLZiNDAB\n" + "4anmOFaT7EmqUjI4IlcaqfbbXyDXlvWUYukidEss+CNvPuqbQHBDnpFVvBxdDR2N\n" + "Uj2D5Xd5blcIe2/+1IVRnznjoQ5zvutzb7ThBmMehQKBgQDOITKG0ht2kXLxjVoR\n" + "r/pVpx+f3hs3H7wE0+vrLHoQgkVjpMWXQ47YuZTT9rCOOYNI2cMoH2D27t1j78/B\n" + "9kGYABUVpvQQ+6amqJDI1eYI6e68TPueEDjeALfSCdmPNiI3lZZrCIK9XLpkoy8K\n" + "tGYBRRJ+JJxjj1zPXj9SGshPgwKBgQDFXUtoxY3mCStH3+0b1qxGG9r1L5goHEmd\n" + "Am8WBYDheNpL0VqPNzouhuM/ZWMGyyAs/py6aLATe+qhR1uX5vn7LVZwjCSONZ4j\n" + "7ieEEUh1BHetPI1oI5PxgokRYfVuckotqVseanI/536Er3Yf2FXNQ1/ceVp9WykX\n" + "3mYTKMhQFwKBgQDKakcXpZNaZ5IcKdZcsBZ/rdGcR5sqEnursf9lvRNQytwg8Vkn\n" + "JSxNHlBLpV/TCh8lltHRwJ6TXhUBYij+KzhWbx5FWOErHDOWTMmArqtp7W6GcoJT\n" + "wVJWjxXzp8CApYQMWVSQXpckJL7UvHohZO0WKiHyxTjde5aD++TqV2qEyQKBgBbD\n" + "jvoTpy08K4DLxCZs2Uvw1I1pIuylbpwsdrGciuP2s38BM6fHH+/T4Qwj3osfDKQD\n" + "7gHWJ1Dn/wUBHQBlRLoC3bB3iZPZfVb5lhc2gxv0GvWhQVIcoGi/vJ2DpfJKPmIL\n" + "4ZWdg3X5dm9JaZ98rVDSj5D3ckd5J0E4hp95GbmbAoGBAJJHM4O9lx60tIjw9Sf/\n" + "QmKWyUk0NLnt8DcgRMW7fVxtzPNDy9DBKGIkDdWZ2s+ForICA3C9WSxBC1EOEHGG\n" + "xkg2xKt66CeutGroP6M191mHQrRClt1VbEYzQFX21BCk5kig9i/BURyoTHtFiV+t\n" + "kbf4VLg8Vk9u/R3RU1HsYWhe\n" + "-----END PRIVATE KEY-----\n"; + +const char* fixed_rsa_cert = + "-----BEGIN CERTIFICATE-----\n" + "MIIDUDCCAjgCCQD7pIb1ZsoafjANBgkqhkiG9w0BAQsFADBqMQswCQYDVQQGEwJW\n" + "VDEQMA4GA1UECAwHVmVybW9udDEWMBQGA1UEBwwNVGhlIEludGVybmV0czEUMBIG\n" + "A1UECgwLTWFuZ29zIFIgVXMxGzAZBgNVBAMMEnNlcnZlci5leGFtcGxlLmNvbTAe\n" + "Fw0xNjAxMDYxNzQ3MjNaFw0yNjAxMDMxNzQ3MjNaMGoxCzAJBgNVBAYTAlZUMRAw\n" + "DgYDVQQIDAdWZXJtb250MRYwFAYDVQQHDA1UaGUgSW50ZXJuZXRzMRQwEgYDVQQK\n" + "DAtNYW5nb3MgUiBVczEbMBkGA1UEAwwSc2VydmVyLmV4YW1wbGUuY29tMIIBIjAN\n" + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnuqqqTEFSe8wiaEp6cYmtMjujOyH\n" + "txRqj3HdA87ngvpFj77h0Pj6T+b3zuqqkWg1SCN+zxV+TVGUJhiv6wJu7KYyB0wj\n" + "IKkmfKTddy1PJtYA8CHbvWpdei1zfc2Yweu7i5RZ9ra7S4tt+ItHJ8nhfCAtHM+7\n" + "YAjszElRAXKiY5HYBq2d1lIDl3nFZtpV1a2JRImksRaeFThPZERXlaxCwo5jbXOI\n" + "UXdcibBfrzmwrb8qhmEBNUHG9DFUkAwRzJIlFZjus7lu7XeXnzv9Tsp7UCRslWvk\n" + "p1m5Eiwsm7WtiezK3hxDaxeRgNCtSi9eNEjUR3lon0TLjULmu6pilzAUxQIDAQAB\n" + "MA0GCSqGSIb3DQEBCwUAA4IBAQA1eZGc/4V7z/E/6eG0hVkzoAZeuTcSP7WqBSx+\n" + "OP2yh0163UYjoa6nehmkKYQQ9PbYPZGzIcl+dBFyYzy6jcp0NdtzpWnTFrjl4rMq\n" + "akcQ1D0LTYjJXVP9G/vF/SvatOFeVTnQmLlLt/a8ZtRUINqejeZZPzH8ifzFW6tu\n" + "mlhTVIEKyPHpxClh5Y3ubw/mZYygekFTqMkTx3FwJxKU8J6rYGZxanWAODUIvCUo\n" + "Fxer1qC5Love3uWl3vXPLEZWZdORnExSRByzz2immBP2vX4zYZoeZRhTQ9ae1TIV\n" + "Dk02a/1AOJZdZReDbgXhlqaUx5pk/rzo4mDzvu5HSCeXmClz\n" + "-----END CERTIFICATE-----\n"; + +class Fuzzer_TLS_Server_Creds : public Botan::Credentials_Manager + { + public: + Fuzzer_TLS_Server_Creds() + { + Botan::DataSource_Memory cert_in(fixed_rsa_cert); + Botan::DataSource_Memory key_in(fixed_rsa_key); + + m_rsa_cert.reset(new Botan::X509_Certificate(cert_in)); + //m_rsa_key.reset(Botan::PKCS8::load_key(key_in, fuzzer_rng()); + } + + std::vector cert_chain( + const std::vector& algos, + const std::string& /*type*/, + const std::string& /*hostname*/) override + { + std::vector v; + + for(auto algo : algos) + { + if(algo == "RSA") + { + v.push_back(*m_rsa_cert); + break; + } + } + + return v; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& /*cert*/, + const std::string& /*type*/, + const std::string& /*context*/) override + { + return m_rsa_key.get(); + } + + std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } + std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } + Botan::SymmetricKey psk(const std::string&, const std::string&, const std::string&) override + { + return Botan::SymmetricKey("AABBCCDDEEFF00112233445566778899"); + } + private: + std::unique_ptr m_rsa_cert; + std::unique_ptr m_rsa_key; + }; + +void fuzz(const uint8_t in[], size_t len) + { + if(len == 0) + return; + + auto dev_null = [](const uint8_t[], size_t) {}; + + auto ignore_alerts = [](Botan::TLS::Alert, const uint8_t[], size_t) {}; + auto ignore_hs = [](const Botan::TLS::Session&) { return true; }; + + Botan::TLS::Session_Manager_Noop session_manager; + Botan::TLS::Policy policy; + Botan::TLS::Server_Information info("server.name", 443); + Fuzzer_TLS_Server_Creds creds; + + auto next_proto_fn = [](const std::vector& protos) -> std::string { + if(protos.size() > 1) + return protos[0]; + else + return "fuzzed"; + }; + + const bool is_datagram = (len % 2 == 0); + + Botan::TLS::Server server(dev_null, + dev_null, + ignore_alerts, + ignore_hs, + session_manager, + creds, + policy, + fuzzer_rng(), + next_proto_fn, + is_datagram); + + try + { + server.received_data(in, len); + } + catch(std::exception& e) + { + } + } diff --git a/src/scripts/ci/travis/build.sh b/src/scripts/ci/travis/build.sh index 36517738b..d2e35112e 100755 --- a/src/scripts/ci/travis/build.sh +++ b/src/scripts/ci/travis/build.sh @@ -23,6 +23,8 @@ elif [ "$BUILD_MODE" = "nist" ]; then elif [ "$BUILD_MODE" = "sonarqube" ]; then # No special flags required CFG_FLAGS+=() +elif [ "$BUILD_MODE" = "fuzzers" ]; then + CFG_FLAGS+=(--build-fuzzers=test --with-sanitizers --with-debug-info --disable-shared) elif [ "$BUILD_MODE" = "parallel" ]; then if [ "$CC" = "gcc" ]; then @@ -137,6 +139,11 @@ else time "${MAKE_CMD[@]}" fi +if [ "$BUILD_MODE" = "fuzzers" ]; then + make fuzzers + make fuzzer_corpus_zip +fi + # post-build ccache stats ccache --show-stats @@ -171,9 +178,13 @@ if [ "$BUILD_MODE" = "sonarqube" ]; then # When neither on master branch nor on a non-external pull request => nothing to do fi -if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || \ +if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || ( [ "${BUILD_MODE:0:5}" = "cross" ] && [ "$TRAVIS_OS_NAME" = "osx" ] ); then echo "Running tests disabled on this build type" + +elif [ "$BUILD_MODE" = "fuzzers" ]; then + # Test each fuzzer against its corpus + ./src/scripts/test_fuzzers.py fuzzer_corpus build/fuzzer else TEST_CMD=("${TEST_PREFIX[@]}" $TEST_EXE "${TEST_FLAGS[@]}") echo "Running" "${TEST_CMD[@]}" diff --git a/src/scripts/create_corpus_zip.py b/src/scripts/create_corpus_zip.py new file mode 100755 index 000000000..5faee3b52 --- /dev/null +++ b/src/scripts/create_corpus_zip.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# These is used to create fuzzer corpus zip files + +# This is primarily used by OSS-Fuzz but might be useful if you were +# deploying the binaries in a custom fuzzer deployment system. + +import sys +import os +import zipfile +import stat + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) != 2 and len(args) != 3: + print("Usage: %s corpus_dir " % (args[0])) + return 1 + + root_dir = args[1] + + if len(args) == 3: + output_dir = args[2] + else: + output_dir = '' + + if not os.access(root_dir, os.R_OK): + print("Error could not access directory '%s'" % (root_dir)) + return 1 + + for corpus_dir in os.listdir(root_dir): + if corpus_dir == '.git': + continue + subdir = os.path.join(root_dir, corpus_dir) + if not stat.S_ISDIR(os.stat(subdir).st_mode): + continue + + zipfile_path = os.path.join(output_dir, '%s.zip' % (corpus_dir)) + zf = zipfile.ZipFile(zipfile_path, 'w', zipfile.ZIP_DEFLATED) + for f in os.listdir(subdir): + zf.write(os.path.join(subdir, f), f) + zf.close() + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/scripts/test_fuzzers.py b/src/scripts/test_fuzzers.py new file mode 100755 index 000000000..0d473e00c --- /dev/null +++ b/src/scripts/test_fuzzers.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +import sys +import os +import subprocess + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) != 3: + print("Usage: %s " % (args[0])) + return 1 + + corpus_dir = args[1] + fuzzer_dir = args[2] + + if not os.access(corpus_dir, os.R_OK): + print("Error could not access corpus directory '%s'" % (corpus_dir)) + return 1 + + if not os.access(fuzzer_dir, os.R_OK): + print("Error could not access fuzzers directory '%s'" % (fuzzer_dir)) + return 1 + + fuzzers = set([]) + for fuzzer in os.listdir(fuzzer_dir): + if fuzzer.endswith('.zip'): + continue + fuzzers.add(fuzzer) + + corpii = set([]) + for corpus in os.listdir(corpus_dir): + if corpus in ['.git', 'readme.txt']: + continue + corpii.add(corpus) + + fuzzers_without_corpus = fuzzers - corpii + corpus_without_fuzzers = corpii - fuzzers + + for f in sorted(list(fuzzers_without_corpus)): + print("Warning: Fuzzer %s has no corpus" % (f)) + for c in sorted(list(corpus_without_fuzzers)): + print("Warning: Corpus %s has no fuzzer" % (c)) + + fuzzers_with_corpus = fuzzers & corpii + + any_crashes = False + + for f in sorted(list(fuzzers_with_corpus)): + fuzzer_bin = os.path.join(fuzzer_dir, f) + corpus_files = os.path.join(corpus_dir, f) + for corpus_file in sorted(list(os.listdir(corpus_files))): + corpus_fd = open(os.path.join(corpus_files, corpus_file), 'r') + fuzzer_proc = subprocess.Popen([fuzzer_bin], stdin=corpus_fd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + (stdout, stderr) = fuzzer_proc.communicate() + corpus_fd.close() + + if fuzzer_proc.returncode != 0: + print("Fuzzer %s crashed with input %s returncode %d" % (f, corpus_file, fuzzer_proc.returncode)) + any_crashes = True + + if len(stdout) != 0: + stdout = stdout.decode('ascii') + print("Fuzzer %s produced stdout on input %s:\n%s" % (f, corpus_file, stdout)) + + if len(stderr) != 0: + stderr = stderr.decode('ascii') + print("Fuzzer %s produced stderr on input %s:\n%s" % (f, corpus_file, stderr)) + + if any_crashes: + return 2 + return 0 + + +if __name__ == '__main__': + sys.exit(main()) -- cgit v1.2.3