summaryrefslogtreecommitdiff
path: root/nss/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'nss/fuzz')
-rw-r--r--nss/fuzz/asn1_mutators.cc122
-rw-r--r--nss/fuzz/asn1_mutators.h16
-rw-r--r--nss/fuzz/certDN_target.cc45
-rwxr-xr-xnss/fuzz/clone_corpus.sh4
-rwxr-xr-xnss/fuzz/clone_libfuzzer.sh4
-rwxr-xr-xnss/fuzz/config/clone_corpus.sh4
-rwxr-xr-xnss/fuzz/config/clone_libfuzzer.sh6
-rwxr-xr-xnss/fuzz/config/git-copy.sh (renamed from nss/fuzz/git-copy.sh)0
-rw-r--r--nss/fuzz/fuzz.gyp393
-rw-r--r--nss/fuzz/mpi_add_target.cc42
-rw-r--r--nss/fuzz/mpi_addmod_target.cc27
-rw-r--r--nss/fuzz/mpi_div_target.cc36
-rw-r--r--nss/fuzz/mpi_expmod_target.cc27
-rw-r--r--nss/fuzz/mpi_helper.cc100
-rw-r--r--nss/fuzz/mpi_helper.h86
-rw-r--r--nss/fuzz/mpi_invmod_target.cc69
-rw-r--r--nss/fuzz/mpi_mod_target.cc36
-rw-r--r--nss/fuzz/mpi_mulmod_target.cc27
-rw-r--r--nss/fuzz/mpi_sqr_target.cc40
-rw-r--r--nss/fuzz/mpi_sqrmod_target.cc36
-rw-r--r--nss/fuzz/mpi_sub_target.cc42
-rw-r--r--nss/fuzz/mpi_submod_target.cc27
-rw-r--r--nss/fuzz/nssfuzz.cc148
-rw-r--r--nss/fuzz/options/certDN.options3
-rw-r--r--nss/fuzz/options/dtls-client-no_fuzzer_mode.options3
-rw-r--r--nss/fuzz/options/dtls-client.options3
-rw-r--r--nss/fuzz/options/dtls-server-no_fuzzer_mode.options3
-rw-r--r--nss/fuzz/options/dtls-server.options3
-rw-r--r--nss/fuzz/options/mpi-add.options3
-rw-r--r--nss/fuzz/options/mpi-addmod.options3
-rw-r--r--nss/fuzz/options/mpi-div.options3
-rw-r--r--nss/fuzz/options/mpi-expmod.options3
-rw-r--r--nss/fuzz/options/mpi-invmod.options2
-rw-r--r--nss/fuzz/options/mpi-mod.options3
-rw-r--r--nss/fuzz/options/mpi-mulmod.options3
-rw-r--r--nss/fuzz/options/mpi-sqr.options3
-rw-r--r--nss/fuzz/options/mpi-sqrmod.options3
-rw-r--r--nss/fuzz/options/mpi-sub.options3
-rw-r--r--nss/fuzz/options/mpi-submod.options3
-rw-r--r--nss/fuzz/options/quickder.options3
-rw-r--r--nss/fuzz/options/tls-client-no_fuzzer_mode.options3
-rw-r--r--nss/fuzz/options/tls-client.options3
-rw-r--r--nss/fuzz/options/tls-server-no_fuzzer_mode.options3
-rw-r--r--nss/fuzz/options/tls-server.options3
-rw-r--r--nss/fuzz/pkcs8_target.cc16
-rw-r--r--nss/fuzz/quickder_target.cc85
-rw-r--r--nss/fuzz/quickder_targets.cc36
-rw-r--r--nss/fuzz/registry.h71
-rw-r--r--nss/fuzz/shared.cc18
-rw-r--r--nss/fuzz/shared.h16
-rw-r--r--nss/fuzz/tls_client_config.cc51
-rw-r--r--nss/fuzz/tls_client_config.h28
-rw-r--r--nss/fuzz/tls_client_target.cc134
-rw-r--r--nss/fuzz/tls_common.cc48
-rw-r--r--nss/fuzz/tls_common.h14
-rw-r--r--nss/fuzz/tls_mutators.cc289
-rw-r--r--nss/fuzz/tls_mutators.h29
-rw-r--r--nss/fuzz/tls_server_certs.cc295
-rw-r--r--nss/fuzz/tls_server_certs.h12
-rw-r--r--nss/fuzz/tls_server_config.cc46
-rw-r--r--nss/fuzz/tls_server_config.h27
-rw-r--r--nss/fuzz/tls_server_target.cc141
-rw-r--r--nss/fuzz/tls_socket.cc34
-rw-r--r--nss/fuzz/tls_socket.h24
-rw-r--r--nss/fuzz/warning.txt27
65 files changed, 2514 insertions, 326 deletions
diff --git a/nss/fuzz/asn1_mutators.cc b/nss/fuzz/asn1_mutators.cc
new file mode 100644
index 0000000..12d8c37
--- /dev/null
+++ b/nss/fuzz/asn1_mutators.cc
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <assert.h>
+#include <string.h>
+#include <random>
+#include <tuple>
+
+#include "asn1_mutators.h"
+
+using namespace std;
+
+static tuple<uint8_t *, size_t> ParseItem(uint8_t *Data, size_t MaxLength) {
+ // Short form. Bit 8 has value "0" and bits 7-1 give the length.
+ if ((Data[1] & 0x80) == 0) {
+ size_t length = min(static_cast<size_t>(Data[1]), MaxLength - 2);
+ return make_tuple(&Data[2], length);
+ }
+
+ // Constructed, indefinite length. Read until {0x00, 0x00}.
+ if (Data[1] == 0x80) {
+ void *offset = memmem(&Data[2], MaxLength - 2, "\0", 2);
+ size_t length = offset ? (static_cast<uint8_t *>(offset) - &Data[2]) + 2
+ : MaxLength - 2;
+ return make_tuple(&Data[2], length);
+ }
+
+ // Long form. Two to 127 octets. Bit 8 of first octet has value "1"
+ // and bits 7-1 give the number of additional length octets.
+ size_t octets = min(static_cast<size_t>(Data[1] & 0x7f), MaxLength - 2);
+
+ // Handle lengths bigger than 32 bits.
+ if (octets > 4) {
+ // Ignore any further children, assign remaining length.
+ return make_tuple(&Data[2] + octets, MaxLength - 2 - octets);
+ }
+
+ // Parse the length.
+ size_t length = 0;
+ for (size_t j = 0; j < octets; j++) {
+ length = (length << 8) | Data[2 + j];
+ }
+
+ length = min(length, MaxLength - 2 - octets);
+ return make_tuple(&Data[2] + octets, length);
+}
+
+static vector<uint8_t *> ParseItems(uint8_t *Data, size_t Size) {
+ vector<uint8_t *> items;
+ vector<size_t> lengths;
+
+ // The first item is always the whole corpus.
+ items.push_back(Data);
+ lengths.push_back(Size);
+
+ // Can't use iterators here because the `items` vector is modified inside the
+ // loop. That's safe as long as we always check `items.size()` before every
+ // iteration, and only call `.push_back()` to append new items we found.
+ // Items are accessed through `items.at()`, we hold no references.
+ for (size_t i = 0; i < items.size(); i++) {
+ uint8_t *item = items.at(i);
+ size_t remaining = lengths.at(i);
+
+ // Empty or primitive items have no children.
+ if (remaining == 0 || (0x20 & item[0]) == 0) {
+ continue;
+ }
+
+ while (remaining > 2) {
+ uint8_t *content;
+ size_t length;
+
+ tie(content, length) = ParseItem(item, remaining);
+
+ if (length > 0) {
+ // Record the item.
+ items.push_back(content);
+
+ // Record the length for further parsing.
+ lengths.push_back(length);
+ }
+
+ // Reduce number of bytes left in current item.
+ remaining -= length + (content - item);
+
+ // Skip the item we just parsed.
+ item = content + length;
+ }
+ }
+
+ return items;
+}
+
+size_t ASN1MutatorFlipConstructed(uint8_t *Data, size_t Size, size_t MaxSize,
+ unsigned int Seed) {
+ auto items = ParseItems(Data, Size);
+
+ std::mt19937 rng(Seed);
+ std::uniform_int_distribution<size_t> dist(0, items.size() - 1);
+ uint8_t *item = items.at(dist(rng));
+
+ // Flip "constructed" type bit.
+ item[0] ^= 0x20;
+
+ return Size;
+}
+
+size_t ASN1MutatorChangeType(uint8_t *Data, size_t Size, size_t MaxSize,
+ unsigned int Seed) {
+ auto items = ParseItems(Data, Size);
+
+ std::mt19937 rng(Seed);
+ std::uniform_int_distribution<size_t> dist(0, items.size() - 1);
+ uint8_t *item = items.at(dist(rng));
+
+ // Change type to a random int [0, 30].
+ static std::uniform_int_distribution<size_t> tdist(0, 30);
+ item[0] = tdist(rng);
+
+ return Size;
+}
diff --git a/nss/fuzz/asn1_mutators.h b/nss/fuzz/asn1_mutators.h
new file mode 100644
index 0000000..8bf02d4
--- /dev/null
+++ b/nss/fuzz/asn1_mutators.h
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef asn1_mutators_h__
+#define asn1_mutators_h__
+
+#include <stdint.h>
+#include <cstddef>
+
+size_t ASN1MutatorFlipConstructed(uint8_t *Data, size_t Size, size_t MaxSize,
+ unsigned int Seed);
+size_t ASN1MutatorChangeType(uint8_t *Data, size_t Size, size_t MaxSize,
+ unsigned int Seed);
+
+#endif // asn1_mutators_h__
diff --git a/nss/fuzz/certDN_target.cc b/nss/fuzz/certDN_target.cc
new file mode 100644
index 0000000..264880a
--- /dev/null
+++ b/nss/fuzz/certDN_target.cc
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <string>
+
+#include "shared.h"
+
+#define TEST_FUNCTION(f) \
+ out = f(certName); \
+ free(out);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ std::string name(data, data + size);
+
+ assert(SECOID_Init() == SECSuccess);
+
+ CERTName* certName = CERT_AsciiToName(name.c_str());
+ if (certName) {
+ char* out;
+ TEST_FUNCTION(CERT_NameToAscii)
+ TEST_FUNCTION(CERT_GetCertEmailAddress)
+
+ // These functions call CERT_GetNameElement with different OIDs.
+ // Unfotunately CERT_GetNameElement is not accesible from here.
+ TEST_FUNCTION(CERT_GetCertUid)
+ TEST_FUNCTION(CERT_GetCommonName)
+ TEST_FUNCTION(CERT_GetCountryName)
+ TEST_FUNCTION(CERT_GetDomainComponentName)
+ TEST_FUNCTION(CERT_GetLocalityName)
+ TEST_FUNCTION(CERT_GetOrgName)
+ TEST_FUNCTION(CERT_GetOrgUnitName)
+ TEST_FUNCTION(CERT_GetStateName)
+
+ out = CERT_NameToAsciiInvertible(certName, CERT_N2A_READABLE);
+ free(out);
+ out = CERT_NameToAsciiInvertible(certName, CERT_N2A_STRICT);
+ free(out);
+ out = CERT_NameToAsciiInvertible(certName, CERT_N2A_INVERTIBLE);
+ free(out);
+ }
+ CERT_DestroyName(certName);
+
+ return 0;
+}
diff --git a/nss/fuzz/clone_corpus.sh b/nss/fuzz/clone_corpus.sh
deleted file mode 100755
index a41cbc0..0000000
--- a/nss/fuzz/clone_corpus.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-d=$(dirname $0)
-exec $d/git-copy.sh https://github.com/mozilla/nss-fuzzing-corpus master $d/corpus
diff --git a/nss/fuzz/clone_libfuzzer.sh b/nss/fuzz/clone_libfuzzer.sh
deleted file mode 100755
index 91c93de..0000000
--- a/nss/fuzz/clone_libfuzzer.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-d=$(dirname $0)
-exec $d/git-copy.sh https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer 1b543d6e5073b56be214394890c9193979a3d7e1 $d/libFuzzer
diff --git a/nss/fuzz/config/clone_corpus.sh b/nss/fuzz/config/clone_corpus.sh
new file mode 100755
index 0000000..856f63d
--- /dev/null
+++ b/nss/fuzz/config/clone_corpus.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+d=$(dirname $0)
+$d/git-copy.sh https://github.com/mozilla/nss-fuzzing-corpus master $d/../corpus
diff --git a/nss/fuzz/config/clone_libfuzzer.sh b/nss/fuzz/config/clone_libfuzzer.sh
new file mode 100755
index 0000000..f1dc2e1
--- /dev/null
+++ b/nss/fuzz/config/clone_libfuzzer.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+LIBFUZZER_REVISION=56bd1d43451cca4b6a11d3be316bb77ab159b09d
+
+d=$(dirname $0)
+$d/git-copy.sh https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer $LIBFUZZER_REVISION $d/../libFuzzer
diff --git a/nss/fuzz/git-copy.sh b/nss/fuzz/config/git-copy.sh
index 1389dda..1389dda 100755
--- a/nss/fuzz/git-copy.sh
+++ b/nss/fuzz/config/git-copy.sh
diff --git a/nss/fuzz/fuzz.gyp b/nss/fuzz/fuzz.gyp
index 4321c5c..ed1f53d 100644
--- a/nss/fuzz/fuzz.gyp
+++ b/nss/fuzz/fuzz.gyp
@@ -4,62 +4,373 @@
{
'includes': [
'../coreconf/config.gypi',
- '../cmd/platlibs.gypi'
],
+ 'target_defaults': {
+ 'variables': {
+ 'debug_optimization_level': '2',
+ },
+ 'target_conditions': [
+ [ '_type=="executable"', {
+ 'libraries!': [
+ '<@(nspr_libs)',
+ ],
+ 'libraries': [
+ '<(nss_dist_obj_dir)/lib/libplds4.a',
+ '<(nss_dist_obj_dir)/lib/libnspr4.a',
+ '<(nss_dist_obj_dir)/lib/libplc4.a',
+ ],
+ }],
+ ],
+ },
'targets': [
{
- 'target_name': 'libFuzzer',
+ 'target_name': 'fuzz_base',
'type': 'static_library',
'sources': [
- 'libFuzzer/FuzzerCrossOver.cpp',
- 'libFuzzer/FuzzerDriver.cpp',
- 'libFuzzer/FuzzerExtFunctionsDlsym.cpp',
- 'libFuzzer/FuzzerExtFunctionsWeak.cpp',
- 'libFuzzer/FuzzerIO.cpp',
- 'libFuzzer/FuzzerLoop.cpp',
- 'libFuzzer/FuzzerMutate.cpp',
- 'libFuzzer/FuzzerSHA1.cpp',
- 'libFuzzer/FuzzerTracePC.cpp',
- 'libFuzzer/FuzzerTraceState.cpp',
- 'libFuzzer/FuzzerUtil.cpp',
- 'libFuzzer/FuzzerUtilDarwin.cpp',
- 'libFuzzer/FuzzerUtilLinux.cpp',
- ],
- 'cflags': [
- '-O2',
- ],
- 'cflags/': [
- ['exclude', '-fsanitize='],
- ['exclude', '-fsanitize-'],
- ],
- 'xcode_settings': {
- 'GCC_OPTIMIZATION_LEVEL': '2', # -O2
- 'OTHER_CFLAGS/': [
- ['exclude', '-fsanitize='],
- ['exclude', '-fsanitize-'],
+ 'shared.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ '<(DEPTH)/lib/certdb/certdb.gyp:certdb',
+ '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
+ '<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
+ '<(DEPTH)/lib/ssl/ssl.gyp:ssl',
+ '<(DEPTH)/lib/base/base.gyp:nssb',
+ '<(DEPTH)/lib/dev/dev.gyp:nssdev',
+ '<(DEPTH)/lib/pki/pki.gyp:nsspki',
+ '<(DEPTH)/lib/util/util.gyp:nssutil',
+ '<(DEPTH)/lib/nss/nss.gyp:nss_static',
+ '<(DEPTH)/lib/pkcs7/pkcs7.gyp:pkcs7',
+ # This is a static build of pk11wrap, softoken, and freebl.
+ '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
+ ],
+ 'conditions': [
+ ['fuzz_oss==0', {
+ 'sources': [
+ '<!@(ls <(DEPTH)/fuzz/libFuzzer/*.cpp)',
+ ],
+ 'cflags/': [
+ ['exclude', '-fsanitize-coverage'],
+ ],
+ 'xcode_settings': {
+ 'OTHER_CFLAGS/': [
+ ['exclude', '-fsanitize-coverage'],
+ ],
+ },
+ }, {
+ 'all_dependent_settings': {
+ 'libraries': ['-lFuzzingEngine'],
+ }
+ }]
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-base',
+ 'type': 'none',
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'fuzz_base',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(DEPTH)/lib/freebl/mpi',
+ ],
+ 'sources': [
+ 'mpi_helper.cc',
+ ],
+ 'conditions': [
+ [ 'fuzz_oss==1', {
+ 'libraries': [
+ '/usr/lib/x86_64-linux-gnu/libcrypto.a',
+ ],
+ }, {
+ 'libraries': [
+ '-lcrypto',
+ ],
+ }],
+ # For test builds we have to set MPI defines.
+ [ 'target_arch=="ia32"', {
+ 'defines': [
+ 'MP_USE_UINT_DIGIT',
+ 'MP_ASSEMBLY_MULTIPLY',
+ 'MP_ASSEMBLY_SQUARE',
+ 'MP_ASSEMBLY_DIV_2DX1D',
+ ],
+ }],
],
},
},
{
- 'target_name': 'nssfuzz',
+ 'target_name': 'nssfuzz-pkcs8',
'type': 'executable',
'sources': [
- 'nssfuzz.cc',
+ 'asn1_mutators.cc',
'pkcs8_target.cc',
- 'quickder_targets.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
- 'libFuzzer',
- ]
+ 'fuzz_base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-quickder',
+ 'type': 'executable',
+ 'sources': [
+ 'asn1_mutators.cc',
+ 'quickder_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'fuzz_base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-certDN',
+ 'type': 'executable',
+ 'sources': [
+ 'certDN_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'fuzz_base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-add',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_add_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-sub',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_sub_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-sqr',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_sqr_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-div',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_div_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-mod',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_mod_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-sqrmod',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_sqrmod_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-addmod',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_addmod_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-submod',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_submod_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-mulmod',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_mulmod_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-expmod',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_expmod_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-mpi-invmod',
+ 'type': 'executable',
+ 'sources': [
+ 'mpi_invmod_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'nssfuzz-mpi-base',
+ ],
+ 'include_dirs': [
+ '<(DEPTH)/lib/freebl',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-tls-base',
+ 'type': 'static_library',
+ 'sources': [
+ 'tls_common.cc',
+ 'tls_mutators.cc',
+ 'tls_socket.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/cpputil/cpputil.gyp:cpputil',
+ '<(DEPTH)/exports.gyp:nss_exports',
+ 'fuzz_base',
+ ],
+ 'include_dirs': [
+ '<(DEPTH)/lib/ssl',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(DEPTH)/lib/freebl',
+ '<(DEPTH)/lib/ssl',
+ ],
+ },
+ },
+ {
+ 'target_name': 'nssfuzz-tls-client',
+ 'type': 'executable',
+ 'sources': [
+ 'tls_client_config.cc',
+ 'tls_client_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ '<(DEPTH)/cpputil/cpputil.gyp:cpputil',
+ 'nssfuzz-tls-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-tls-server',
+ 'type': 'executable',
+ 'sources': [
+ 'tls_server_certs.cc',
+ 'tls_server_config.cc',
+ 'tls_server_target.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ '<(DEPTH)/cpputil/cpputil.gyp:cpputil',
+ 'nssfuzz-tls-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-dtls-client',
+ 'type': 'executable',
+ 'sources': [
+ 'tls_client_config.cc',
+ 'tls_client_target.cc',
+ ],
+ 'defines': [
+ 'IS_DTLS'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ '<(DEPTH)/cpputil/cpputil.gyp:cpputil',
+ 'nssfuzz-tls-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz-dtls-server',
+ 'type': 'executable',
+ 'sources': [
+ 'tls_server_certs.cc',
+ 'tls_server_config.cc',
+ 'tls_server_target.cc',
+ ],
+ 'defines': [
+ 'IS_DTLS'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ '<(DEPTH)/cpputil/cpputil.gyp:cpputil',
+ 'nssfuzz-tls-base',
+ ],
+ },
+ {
+ 'target_name': 'nssfuzz',
+ 'type': 'none',
+ 'dependencies': [
+ 'nssfuzz-certDN',
+ 'nssfuzz-dtls-client',
+ 'nssfuzz-dtls-server',
+ 'nssfuzz-pkcs8',
+ 'nssfuzz-quickder',
+ 'nssfuzz-tls-client',
+ 'nssfuzz-tls-server',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'dependencies': [
+ 'nssfuzz-mpi-add',
+ 'nssfuzz-mpi-addmod',
+ 'nssfuzz-mpi-div',
+ 'nssfuzz-mpi-expmod',
+ 'nssfuzz-mpi-invmod',
+ 'nssfuzz-mpi-mod',
+ 'nssfuzz-mpi-mulmod',
+ 'nssfuzz-mpi-sqr',
+ 'nssfuzz-mpi-sqrmod',
+ 'nssfuzz-mpi-sub',
+ 'nssfuzz-mpi-submod',
+ ],
+ }],
+ ],
}
],
- 'target_defaults': {
- 'include_dirs': [
- 'libFuzzer',
- ],
- },
- 'variables': {
- 'module': 'nss',
- }
}
diff --git a/nss/fuzz/mpi_add_target.cc b/nss/fuzz/mpi_add_target.cc
new file mode 100644
index 0000000..3ebad37
--- /dev/null
+++ b/nss/fuzz/mpi_add_target.cc
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ // Compare with OpenSSL addition
+ assert(mp_add(&a, &b, &c) == MP_OKAY);
+ (void)BN_add(C, A, B);
+ check_equal(C, &c, max_size);
+
+ // Check a + b == a - -b
+ mp_neg(&b, &b);
+ assert(mp_sub(&a, &b, &r) == MP_OKAY);
+ bool eq = mp_cmp(&r, &c) == 0;
+ if (!eq) {
+ char rC[max_size], cC[max_size], aC[max_size], bC[max_size];
+ mp_tohex(&r, rC);
+ mp_tohex(&c, cC);
+ mp_tohex(&a, aC);
+ mp_tohex(&b, bC);
+ std::cout << "a = " << std::hex << aC << std::endl;
+ std::cout << "-b = " << std::hex << bC << std::endl;
+ std::cout << "a + b = " << std::hex << cC << std::endl;
+ std::cout << "a - -b = " << std::hex << rC << std::endl;
+ }
+ assert(eq);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/mpi_addmod_target.cc b/nss/fuzz/mpi_addmod_target.cc
new file mode 100644
index 0000000..a7802b6
--- /dev/null
+++ b/nss/fuzz/mpi_addmod_target.cc
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ auto modulus = get_modulus(data, size, ctx);
+ // Compare with OpenSSL add mod
+ m1 = &std::get<1>(modulus);
+ assert(mp_addmod(&a, &b, m1, &c) == MP_OKAY);
+ (void)BN_mod_add(C, A, B, std::get<0>(modulus), ctx);
+ check_equal(C, &c, max_size);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/mpi_div_target.cc b/nss/fuzz/mpi_div_target.cc
new file mode 100644
index 0000000..08c714e
--- /dev/null
+++ b/nss/fuzz/mpi_div_target.cc
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ // We can't divide by 0.
+ if (mp_cmp_z(&b) == 0) {
+ CLEANUP_AND_RETURN
+ }
+
+ // Compare with OpenSSL division
+ assert(mp_div(&a, &b, &c, &r) == MP_OKAY);
+ BN_div(C, R, A, B, ctx);
+ check_equal(C, &c, max_size);
+ check_equal(R, &r, max_size);
+
+ // Check c * b + r == a
+ assert(mp_mul(&c, &b, &c) == MP_OKAY);
+ assert(mp_add(&c, &r, &c) == MP_OKAY);
+ assert(mp_cmp(&c, &a) == 0);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/mpi_expmod_target.cc b/nss/fuzz/mpi_expmod_target.cc
new file mode 100644
index 0000000..ed31da3
--- /dev/null
+++ b/nss/fuzz/mpi_expmod_target.cc
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ auto modulus = get_modulus(data, size, ctx);
+ // Compare with OpenSSL exp mod
+ m1 = &std::get<1>(modulus);
+ assert(mp_exptmod(&a, &b, m1, &c) == MP_OKAY);
+ (void)BN_mod_exp(C, A, B, std::get<0>(modulus), ctx);
+ check_equal(C, &c, 2 * max_size);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/mpi_helper.cc b/nss/fuzz/mpi_helper.cc
new file mode 100644
index 0000000..65cf4b9
--- /dev/null
+++ b/nss/fuzz/mpi_helper.cc
@@ -0,0 +1,100 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Helper functions for MPI fuzzing targets. */
+
+#include "mpi_helper.h"
+#include <cstdlib>
+#include <random>
+
+char *to_char(const uint8_t *x) {
+ return reinterpret_cast<char *>(const_cast<unsigned char *>(x));
+}
+
+// Check that the two numbers are equal.
+void check_equal(BIGNUM *b, mp_int *m, size_t max_size) {
+ char *bnBc = BN_bn2hex(b);
+ char mpiMc[max_size];
+ mp_tohex(m, mpiMc);
+ std::string bnA(bnBc);
+ std::string mpiA(mpiMc);
+ OPENSSL_free(bnBc);
+ // We have to strip leading zeros from bignums, ignoring the sign.
+ if (bnA.at(0) != '-') {
+ bnA.erase(0, std::min(bnA.find_first_not_of('0'), bnA.size() - 1));
+ } else if (bnA.at(1) == '0') {
+ bnA.erase(1, std::min(bnA.find_first_not_of('0', 1) - 1, bnA.size() - 1));
+ }
+
+ if (mpiA != bnA) {
+ std::cout << "openssl: " << std::hex << bnA << std::endl;
+ std::cout << "nss: " << std::hex << mpiA << std::endl;
+ }
+
+ assert(mpiA == bnA);
+}
+
+// Parse data into two numbers for MPI and OpenSSL Bignum.
+void parse_input(const uint8_t *data, size_t size, BIGNUM *A, BIGNUM *B,
+ mp_int *a, mp_int *b) {
+ // Note that b might overlap a.
+ size_t len = (size_t)size / 2;
+ assert(mp_read_raw(a, to_char(data), len) == MP_OKAY);
+ assert(mp_read_raw(b, to_char(data) + len, len) == MP_OKAY);
+ // Force a positive sign.
+ // TODO: add tests for negatives.
+ MP_SIGN(a) = MP_ZPOS;
+ MP_SIGN(b) = MP_ZPOS;
+
+ // Skip the first byte as it's interpreted as sign by NSS.
+ assert(BN_bin2bn(data + 1, len - 1, A) != nullptr);
+ assert(BN_bin2bn(data + len + 1, len - 1, B) != nullptr);
+
+ check_equal(A, a, 2 * size + 1);
+ check_equal(B, b, 2 * size + 1);
+}
+
+// Parse data into a number for MPI and OpenSSL Bignum.
+void parse_input(const uint8_t *data, size_t size, BIGNUM *A, mp_int *a) {
+ assert(mp_read_raw(a, to_char(data), size) == MP_OKAY);
+
+ // Force a positive sign.
+ // TODO: add tests for negatives.
+ MP_SIGN(a) = MP_ZPOS;
+
+ // Skip the first byte as it's interpreted as sign by NSS.
+ assert(BN_bin2bn(data + 1, size - 1, A) != nullptr);
+
+ check_equal(A, a, 4 * size + 1);
+}
+
+// Take a chunk in the middle of data and use it as modulus.
+std::tuple<BIGNUM *, mp_int> get_modulus(const uint8_t *data, size_t size,
+ BN_CTX *ctx) {
+ BIGNUM *r1 = BN_CTX_get(ctx);
+ mp_int r2;
+ assert(mp_init(&r2) == MP_OKAY);
+
+ size_t len = static_cast<size_t>(size / 4);
+ if (len != 0) {
+ assert(mp_read_raw(&r2, to_char(data + len), len) == MP_OKAY);
+ MP_SIGN(&r2) = MP_ZPOS;
+
+ assert(BN_bin2bn(data + len + 1, len - 1, r1) != nullptr);
+ check_equal(r1, &r2, 2 * len + 1);
+ }
+
+ // If we happen to get 0 for the modulus, take a random number.
+ if (mp_cmp_z(&r2) == 0 || len == 0) {
+ mp_zero(&r2);
+ BN_zero(r1);
+ std::mt19937 rng(data[0]);
+ std::uniform_int_distribution<mp_digit> dist(1, MP_DIGIT_MAX);
+ mp_digit x = dist(rng);
+ mp_add_d(&r2, x, &r2);
+ BN_add_word(r1, x);
+ }
+
+ return std::make_tuple(r1, r2);
+}
diff --git a/nss/fuzz/mpi_helper.h b/nss/fuzz/mpi_helper.h
new file mode 100644
index 0000000..1738374
--- /dev/null
+++ b/nss/fuzz/mpi_helper.h
@@ -0,0 +1,86 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Helper functions for MPI fuzzing targets. */
+
+#ifndef mpi_helper_h__
+#define mpi_helper_h__
+
+#include <iostream>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "hasht.h"
+#include "mpi.h"
+
+#include <openssl/bn.h>
+
+void check_equal(BIGNUM *b, mp_int *m, size_t max_size);
+void parse_input(const uint8_t *data, size_t size, BIGNUM *A, BIGNUM *B,
+ mp_int *a, mp_int *b);
+void parse_input(const uint8_t *data, size_t size, BIGNUM *A, mp_int *a);
+std::tuple<BIGNUM *, mp_int> get_modulus(const uint8_t *data, size_t size,
+ BN_CTX *ctx);
+
+// Initialise MPI and BN variables
+// XXX: Also silence unused variable warnings for R.
+#define INIT_FOUR_NUMBERS \
+ mp_int a, b, c, r; \
+ mp_int *m1 = nullptr; \
+ BN_CTX *ctx = BN_CTX_new(); \
+ BN_CTX_start(ctx); \
+ BIGNUM *A = BN_CTX_get(ctx); \
+ BIGNUM *B = BN_CTX_get(ctx); \
+ BIGNUM *C = BN_CTX_get(ctx); \
+ BIGNUM *R = BN_CTX_get(ctx); \
+ assert(mp_init(&a) == MP_OKAY); \
+ assert(mp_init(&b) == MP_OKAY); \
+ assert(mp_init(&c) == MP_OKAY); \
+ assert(mp_init(&r) == MP_OKAY); \
+ size_t max_size = 2 * size + 1; \
+ parse_input(data, size, A, B, &a, &b); \
+ do { \
+ (void)(R); \
+ } while (0);
+
+// Initialise MPI and BN variables
+// XXX: Also silence unused variable warnings for B.
+#define INIT_THREE_NUMBERS \
+ mp_int a, b, c; \
+ BN_CTX *ctx = BN_CTX_new(); \
+ BN_CTX_start(ctx); \
+ BIGNUM *A = BN_CTX_get(ctx); \
+ BIGNUM *B = BN_CTX_get(ctx); \
+ BIGNUM *C = BN_CTX_get(ctx); \
+ assert(mp_init(&a) == MP_OKAY); \
+ assert(mp_init(&b) == MP_OKAY); \
+ assert(mp_init(&c) == MP_OKAY); \
+ size_t max_size = 4 * size + 1; \
+ parse_input(data, size, A, &a); \
+ do { \
+ (void)(B); \
+ } while (0);
+
+#define CLEANUP_AND_RETURN \
+ mp_clear(&a); \
+ mp_clear(&b); \
+ mp_clear(&c); \
+ mp_clear(&r); \
+ if (m1) { \
+ mp_clear(m1); \
+ } \
+ BN_CTX_end(ctx); \
+ BN_CTX_free(ctx); \
+ return 0;
+
+#define CLEANUP_AND_RETURN_THREE \
+ mp_clear(&a); \
+ mp_clear(&b); \
+ mp_clear(&c); \
+ BN_CTX_end(ctx); \
+ BN_CTX_free(ctx); \
+ return 0;
+
+#endif // mpi_helper_h__
diff --git a/nss/fuzz/mpi_invmod_target.cc b/nss/fuzz/mpi_invmod_target.cc
new file mode 100644
index 0000000..6480d54
--- /dev/null
+++ b/nss/fuzz/mpi_invmod_target.cc
@@ -0,0 +1,69 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+#include "mpprime.h"
+
+#include <algorithm>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 4 to get everything we need from data.
+ if (size < 4) {
+ return 0;
+ }
+
+ INIT_THREE_NUMBERS
+
+ // Make a prime of length size.
+ int count = 0;
+ mp_err res = MP_NO;
+ // mpp_make_prime is so slow :( use something smaller than size.
+ int primeLen = std::max(static_cast<int>(size / 4), 3);
+ uint8_t bp[primeLen];
+ memcpy(bp, data, primeLen);
+ do {
+ bp[0] |= 0x80; /* set high-order bit */
+ bp[primeLen - 1] |= 0x01; /* set low-order bit */
+ ++count;
+ assert(mp_read_unsigned_octets(&b, bp, primeLen) == MP_OKAY);
+ } while ((res = mpp_make_prime(&b, primeLen * 8, PR_FALSE)) != MP_YES &&
+ count < 10);
+ if (res != MP_YES) {
+ return 0;
+ }
+
+ // Use the same prime in OpenSSL B
+ char tmp[max_size];
+ mp_toradix(&b, tmp, 16);
+ int tmpLen;
+ assert((tmpLen = BN_hex2bn(&B, tmp)) != 0);
+
+ // Compare with OpenSSL invmod
+ res = mp_invmod(&a, &b, &c);
+ BIGNUM *X = BN_mod_inverse(C, A, B, ctx);
+ if (res != MP_OKAY) {
+ // In case we couldn't compute the inverse, OpenSSL shouldn't be able to
+ // either.
+ assert(X == nullptr);
+ } else {
+ check_equal(C, &c, max_size);
+
+ // Check a * c mod b == 1
+ assert(mp_mulmod(&a, &c, &b, &c) == MP_OKAY);
+ bool eq = mp_cmp_d(&c, 1) == 0;
+ if (!eq) {
+ char cC[max_size];
+ mp_tohex(&c, cC);
+ std::cout << "c = " << std::hex << cC << std::endl;
+ }
+ assert(eq);
+ }
+
+ CLEANUP_AND_RETURN_THREE
+}
diff --git a/nss/fuzz/mpi_mod_target.cc b/nss/fuzz/mpi_mod_target.cc
new file mode 100644
index 0000000..85c883f
--- /dev/null
+++ b/nss/fuzz/mpi_mod_target.cc
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ // We can't divide by 0.
+ if (mp_cmp_z(&b) == 0) {
+ CLEANUP_AND_RETURN
+ }
+
+ // Compare with OpenSSL mod
+ assert(mp_mod(&a, &b, &c) == MP_OKAY);
+ (void)BN_mod(C, A, B, ctx);
+ check_equal(C, &c, max_size);
+
+ // Check a mod b = a - floor(a / b) * b
+ assert(mp_div(&a, &b, &r, nullptr) == MP_OKAY);
+ assert(mp_mul(&r, &b, &r) == MP_OKAY);
+ assert(mp_sub(&a, &r, &r) == MP_OKAY);
+ assert(mp_cmp(&c, &r) == 0);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/mpi_mulmod_target.cc b/nss/fuzz/mpi_mulmod_target.cc
new file mode 100644
index 0000000..75585e2
--- /dev/null
+++ b/nss/fuzz/mpi_mulmod_target.cc
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ auto modulus = get_modulus(data, size, ctx);
+ // Compare with OpenSSL mul mod
+ m1 = &std::get<1>(modulus);
+ assert(mp_mulmod(&a, &b, m1, &c) == MP_OKAY);
+ (void)BN_mod_mul(C, A, B, std::get<0>(modulus), ctx);
+ check_equal(C, &c, max_size);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/mpi_sqr_target.cc b/nss/fuzz/mpi_sqr_target.cc
new file mode 100644
index 0000000..b404d62
--- /dev/null
+++ b/nss/fuzz/mpi_sqr_target.cc
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 2 to get an integers from Data.
+ if (size < 2) {
+ return 0;
+ }
+
+ INIT_THREE_NUMBERS
+
+ // Compare with OpenSSL sqr
+ assert(mp_sqr(&a, &c) == MP_OKAY);
+ (void)BN_sqr(C, A, ctx);
+ check_equal(C, &c, max_size);
+
+ // Check a * a == a**2
+ assert(mp_mul(&a, &a, &b) == MP_OKAY);
+ bool eq = mp_cmp(&b, &c) == 0;
+ if (!eq) {
+ char rC[max_size], cC[max_size], aC[max_size];
+ mp_tohex(&b, rC);
+ mp_tohex(&c, cC);
+ mp_tohex(&a, aC);
+ std::cout << "a = " << std::hex << aC << std::endl;
+ std::cout << "a * a = " << std::hex << cC << std::endl;
+ std::cout << "a ** 2 = " << std::hex << rC << std::endl;
+ }
+ assert(eq);
+
+ CLEANUP_AND_RETURN_THREE
+}
diff --git a/nss/fuzz/mpi_sqrmod_target.cc b/nss/fuzz/mpi_sqrmod_target.cc
new file mode 100644
index 0000000..ca403b5
--- /dev/null
+++ b/nss/fuzz/mpi_sqrmod_target.cc
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+
+ INIT_THREE_NUMBERS
+
+ // We can't divide by 0.
+ if (mp_cmp_z(&b) == 0) {
+ mp_clear(&a);
+ mp_clear(&b);
+ mp_clear(&c);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return 0;
+ }
+
+ // Compare with OpenSSL square mod
+ assert(mp_sqrmod(&a, &b, &c) == MP_OKAY);
+ (void)BN_mod_sqr(C, A, B, ctx);
+ check_equal(C, &c, max_size);
+
+ CLEANUP_AND_RETURN_THREE
+}
diff --git a/nss/fuzz/mpi_sub_target.cc b/nss/fuzz/mpi_sub_target.cc
new file mode 100644
index 0000000..da20d74
--- /dev/null
+++ b/nss/fuzz/mpi_sub_target.cc
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ // Compare with OpenSSL subtraction
+ assert(mp_sub(&a, &b, &c) == MP_OKAY);
+ (void)BN_sub(C, A, B);
+ check_equal(C, &c, max_size);
+
+ // Check a - b == a + -b
+ mp_neg(&b, &b);
+ assert(mp_add(&a, &b, &r) == MP_OKAY);
+ bool eq = mp_cmp(&r, &c) == 0;
+ if (!eq) {
+ char rC[max_size], cC[max_size], aC[max_size], bC[max_size];
+ mp_tohex(&r, rC);
+ mp_tohex(&c, cC);
+ mp_tohex(&a, aC);
+ mp_tohex(&b, bC);
+ std::cout << "a = " << std::hex << aC << std::endl;
+ std::cout << "-b = " << std::hex << bC << std::endl;
+ std::cout << "a - b = " << std::hex << cC << std::endl;
+ std::cout << "a + -b = " << std::hex << rC << std::endl;
+ }
+ assert(eq);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/mpi_submod_target.cc b/nss/fuzz/mpi_submod_target.cc
new file mode 100644
index 0000000..26b2c53
--- /dev/null
+++ b/nss/fuzz/mpi_submod_target.cc
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This target fuzzes NSS mpi against openssl bignum.
+ * It therefore requires openssl to be installed.
+ */
+
+#include "mpi_helper.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // We require at least size 3 to get two integers from Data.
+ if (size < 3) {
+ return 0;
+ }
+ INIT_FOUR_NUMBERS
+
+ auto modulus = get_modulus(data, size, ctx);
+ // Compare with OpenSSL sub mod
+ m1 = &std::get<1>(modulus);
+ assert(mp_submod(&a, &b, m1, &c) == MP_OKAY);
+ (void)BN_mod_sub(C, A, B, std::get<0>(modulus), ctx);
+ check_equal(C, &c, 2 * max_size);
+
+ CLEANUP_AND_RETURN
+}
diff --git a/nss/fuzz/nssfuzz.cc b/nss/fuzz/nssfuzz.cc
deleted file mode 100644
index d976930..0000000
--- a/nss/fuzz/nssfuzz.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <iomanip>
-#include <iostream>
-#include <memory>
-
-#include "keyhi.h"
-#include "pk11pub.h"
-
-#include "FuzzerInternal.h"
-#include "registry.h"
-#include "shared.h"
-
-using namespace std;
-
-class Args {
- public:
- Args(int argc, char **argv) : args_(argv, argv + argc) {}
-
- string &operator[](const int idx) { return args_[idx]; }
-
- bool Has(const string &arg) {
- return any_of(args_.begin(), args_.end(),
- [&arg](string &a) { return a.find(arg) == 0; });
- }
-
- void Append(const string &arg) { args_.push_back(arg); }
-
- void Remove(const int index) {
- assert(index < count());
- args_.erase(args_.begin() + index);
- }
-
- vector<char *> argv() {
- vector<char *> out;
- out.resize(count());
-
- transform(args_.begin(), args_.end(), out.begin(),
- [](string &a) { return const_cast<char *>(a.c_str()); });
-
- return out;
- }
-
- size_t count() { return args_.size(); }
-
- private:
- vector<string> args_;
-};
-
-void printUsage(Args &args) {
- size_t sep = args[0].rfind("/") + 1;
- string progName = args[0].substr(sep);
-
- cerr << progName << " - Various libFuzzer targets for NSS" << endl << endl;
- cerr << "Usage: " << progName << " <target> <libFuzzer options>" << endl
- << endl;
- cerr << "Valid targets:" << endl;
-
- vector<string> names = Registry::Names();
-
- // Find length of the longest name.
- size_t name_w =
- max_element(names.begin(), names.end(), [](string &a, string &b) {
- return a.size() < b.size();
- })->size();
-
- // Find length of the longest description.
- auto max = max_element(names.begin(), names.end(), [](string &a, string &b) {
- return Registry::Desc(a).size() < Registry::Desc(b).size();
- });
- size_t desc_w = Registry::Desc(*max).size();
-
- // Print list of targets.
- for (string name : names) {
- cerr << " " << left << setw(name_w) << name << " - " << setw(desc_w)
- << Registry::Desc(name)
- << " [default max_len=" << Registry::MaxLen(name) << "]" << endl;
- }
-
- // Some usage examples.
- cerr << endl << "Run fuzzer with a given corpus directory:" << endl;
- cerr << " " << progName << " <target> /path/to/corpus" << endl;
-
- cerr << endl << "Run fuzzer with a single test input:" << endl;
- cerr << " " << progName
- << " <target> ./crash-14d4355b971092e39572bc306a135ddf9f923e19" << endl;
-
- cerr << endl
- << "Specify the number of cores you wish to dedicate to fuzzing:"
- << endl;
- cerr << " " << progName << " <target> -jobs=8 -workers=8 /path/to/corpus"
- << endl;
-
- cerr << endl << "Override the maximum length of a test input:" << endl;
- cerr << " " << progName << " <target> -max_len=2048 /path/to/corpus" << endl;
-
- cerr << endl
- << "Minimize a given corpus and put the result into 'new_corpus':"
- << endl;
- cerr << " " << progName
- << " <target> -merge=1 -max_len=50000 ./new_corpus /path/to/corpus"
- << endl;
-
- cerr << endl << "Merge new test inputs into a corpus:" << endl;
- cerr
- << " " << progName
- << " <target> -merge=1 -max_len=50000 /path/to/corpus ./inputs1 ./inputs2"
- << endl;
-
- cerr << endl << "Print libFuzzer usage information:" << endl;
- cerr << " " << progName << " <target> -help=1" << endl << endl;
-
- cerr << "Check out the docs at http://llvm.org/docs/LibFuzzer.html" << endl;
-}
-
-int main(int argc, char **argv) {
- Args args(argc, argv);
-
- if (args.count() < 2 || !Registry::Has(args[1])) {
- printUsage(args);
- return 1;
- }
-
- string targetName(args[1]);
-
- // Remove the target argument when -workers=x or -jobs=y is NOT given.
- // If both are given, libFuzzer will spawn multiple processes for the target.
- if (!args.Has("-workers=") || !args.Has("-jobs=")) {
- args.Remove(1);
- }
-
- // Set default max_len arg, if none given and we're not merging.
- if (!args.Has("-max_len=") && !args.Has("-merge=1")) {
- uint16_t maxLen = Registry::MaxLen(targetName);
- args.Append("-max_len=" + to_string(maxLen));
- }
-
- // Hand control to the libFuzzer driver.
- vector<char *> args_new(args.argv());
- argc = args_new.size();
- argv = args_new.data();
-
- return fuzzer::FuzzerDriver(&argc, &argv, Registry::Func(targetName));
-}
diff --git a/nss/fuzz/options/certDN.options b/nss/fuzz/options/certDN.options
new file mode 100644
index 0000000..635be52
--- /dev/null
+++ b/nss/fuzz/options/certDN.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 4096
+
diff --git a/nss/fuzz/options/dtls-client-no_fuzzer_mode.options b/nss/fuzz/options/dtls-client-no_fuzzer_mode.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/dtls-client-no_fuzzer_mode.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/options/dtls-client.options b/nss/fuzz/options/dtls-client.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/dtls-client.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/options/dtls-server-no_fuzzer_mode.options b/nss/fuzz/options/dtls-server-no_fuzzer_mode.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/dtls-server-no_fuzzer_mode.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/options/dtls-server.options b/nss/fuzz/options/dtls-server.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/dtls-server.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/options/mpi-add.options b/nss/fuzz/options/mpi-add.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-add.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-addmod.options b/nss/fuzz/options/mpi-addmod.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-addmod.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-div.options b/nss/fuzz/options/mpi-div.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-div.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-expmod.options b/nss/fuzz/options/mpi-expmod.options
new file mode 100644
index 0000000..98fcc34
--- /dev/null
+++ b/nss/fuzz/options/mpi-expmod.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 1024
+
diff --git a/nss/fuzz/options/mpi-invmod.options b/nss/fuzz/options/mpi-invmod.options
new file mode 100644
index 0000000..a38c2fe
--- /dev/null
+++ b/nss/fuzz/options/mpi-invmod.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 256
diff --git a/nss/fuzz/options/mpi-mod.options b/nss/fuzz/options/mpi-mod.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-mod.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-mulmod.options b/nss/fuzz/options/mpi-mulmod.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-mulmod.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-sqr.options b/nss/fuzz/options/mpi-sqr.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-sqr.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-sqrmod.options b/nss/fuzz/options/mpi-sqrmod.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-sqrmod.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-sub.options b/nss/fuzz/options/mpi-sub.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-sub.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/mpi-submod.options b/nss/fuzz/options/mpi-submod.options
new file mode 100644
index 0000000..fd32ac1
--- /dev/null
+++ b/nss/fuzz/options/mpi-submod.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 2048
+
diff --git a/nss/fuzz/options/quickder.options b/nss/fuzz/options/quickder.options
new file mode 100644
index 0000000..369977d
--- /dev/null
+++ b/nss/fuzz/options/quickder.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 10000
+
diff --git a/nss/fuzz/options/tls-client-no_fuzzer_mode.options b/nss/fuzz/options/tls-client-no_fuzzer_mode.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/tls-client-no_fuzzer_mode.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/options/tls-client.options b/nss/fuzz/options/tls-client.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/tls-client.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/options/tls-server-no_fuzzer_mode.options b/nss/fuzz/options/tls-server-no_fuzzer_mode.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/tls-server-no_fuzzer_mode.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/options/tls-server.options b/nss/fuzz/options/tls-server.options
new file mode 100644
index 0000000..8b017d2
--- /dev/null
+++ b/nss/fuzz/options/tls-server.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/nss/fuzz/pkcs8_target.cc b/nss/fuzz/pkcs8_target.cc
index 8b6ed7b..6ce6f6d 100644
--- a/nss/fuzz/pkcs8_target.cc
+++ b/nss/fuzz/pkcs8_target.cc
@@ -1,20 +1,17 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include <assert.h>
-#include <stdint.h>
#include <memory>
+#include <vector>
#include "keyhi.h"
#include "pk11pub.h"
-#include "registry.h"
+#include "asn1_mutators.h"
#include "shared.h"
-extern "C" int pkcs8_fuzzing_target(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
SECItem data = {siBuffer, (unsigned char *)Data, (unsigned int)Size};
static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
@@ -34,4 +31,9 @@ extern "C" int pkcs8_fuzzing_target(const uint8_t *Data, size_t Size) {
return 0;
}
-REGISTER_FUZZING_TARGET("pkcs8", pkcs8_fuzzing_target, 2048, "PKCS#8 Import")
+extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size,
+ size_t max_size, unsigned int seed) {
+ return CustomMutate(
+ Mutators({ASN1MutatorFlipConstructed, ASN1MutatorChangeType}), data, size,
+ max_size, seed);
+}
diff --git a/nss/fuzz/quickder_target.cc b/nss/fuzz/quickder_target.cc
new file mode 100644
index 0000000..e246275
--- /dev/null
+++ b/nss/fuzz/quickder_target.cc
@@ -0,0 +1,85 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "asn1_mutators.h"
+#include "shared.h"
+
+const std::vector<const SEC_ASN1Template *> templates = {
+ CERT_AttributeTemplate,
+ CERT_CertExtensionTemplate,
+ CERT_CertificateRequestTemplate,
+ CERT_CertificateTemplate,
+ CERT_CrlTemplate,
+ CERT_IssuerAndSNTemplate,
+ CERT_NameTemplate,
+ CERT_PublicKeyAndChallengeTemplate,
+ CERT_RDNTemplate,
+ CERT_SequenceOfCertExtensionTemplate,
+ CERT_SetOfAttributeTemplate,
+ CERT_SetOfSignedCrlTemplate,
+ CERT_SignedCrlTemplate,
+ CERT_SignedDataTemplate,
+ CERT_SubjectPublicKeyInfoTemplate,
+ CERT_TimeChoiceTemplate,
+ CERT_ValidityTemplate,
+ SEC_AnyTemplate,
+ SEC_BitStringTemplate,
+ SEC_BMPStringTemplate,
+ SEC_BooleanTemplate,
+ SEC_CertSequenceTemplate,
+ SEC_EnumeratedTemplate,
+ SEC_GeneralizedTimeTemplate,
+ SEC_IA5StringTemplate,
+ SEC_IntegerTemplate,
+ SEC_NullTemplate,
+ SEC_ObjectIDTemplate,
+ SEC_OctetStringTemplate,
+ SEC_PointerToAnyTemplate,
+ SEC_PointerToEnumeratedTemplate,
+ SEC_PointerToGeneralizedTimeTemplate,
+ SEC_PointerToOctetStringTemplate,
+ SEC_PrintableStringTemplate,
+ SEC_SetOfAnyTemplate,
+ SEC_SetOfEnumeratedTemplate,
+ SEC_SequenceOfAnyTemplate,
+ SEC_SequenceOfObjectIDTemplate,
+ SEC_SignedCertificateTemplate,
+ SEC_SkipTemplate,
+ SEC_T61StringTemplate,
+ SEC_UniversalStringTemplate,
+ SEC_UTCTimeTemplate,
+ SEC_UTF8StringTemplate,
+ SEC_VisibleStringTemplate,
+ SECKEY_DHParamKeyTemplate,
+ SECKEY_DHPublicKeyTemplate,
+ SECKEY_DSAPrivateKeyExportTemplate,
+ SECKEY_DSAPublicKeyTemplate,
+ SECKEY_PQGParamsTemplate,
+ SECKEY_PrivateKeyInfoTemplate,
+ SECKEY_RSAPSSParamsTemplate,
+ SECKEY_RSAPublicKeyTemplate,
+ SECOID_AlgorithmIDTemplate};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ char *dest[2048];
+
+ for (auto tpl : templates) {
+ PORTCheapArenaPool pool;
+ SECItem buf = {siBuffer, const_cast<unsigned char *>(Data),
+ static_cast<unsigned int>(Size)};
+
+ PORT_InitCheapArena(&pool, DER_DEFAULT_CHUNKSIZE);
+ (void)SEC_QuickDERDecodeItem(&pool.arena, dest, tpl, &buf);
+ PORT_DestroyCheapArena(&pool);
+ }
+
+ return 0;
+}
+
+extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size,
+ size_t max_size, unsigned int seed) {
+ return CustomMutate(
+ Mutators({ASN1MutatorFlipConstructed, ASN1MutatorChangeType}), data, size,
+ max_size, seed);
+}
diff --git a/nss/fuzz/quickder_targets.cc b/nss/fuzz/quickder_targets.cc
deleted file mode 100644
index 2517721..0000000
--- a/nss/fuzz/quickder_targets.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <stdint.h>
-
-#include "cert.h"
-
-#include "registry.h"
-
-void QuickDERDecode(void *dst, const SEC_ASN1Template *tpl, const uint8_t *buf,
- size_t len) {
- PORTCheapArenaPool pool;
- SECItem data = {siBuffer, const_cast<unsigned char *>(buf),
- static_cast<unsigned int>(len)};
-
- PORT_InitCheapArena(&pool, DER_DEFAULT_CHUNKSIZE);
- (void)SEC_QuickDERDecodeItem(&pool.arena, dst, tpl, &data);
- PORT_DestroyCheapArena(&pool);
-}
-
-extern "C" int cert_fuzzing_target(const uint8_t *Data, size_t Size) {
- CERTCertificate cert;
- QuickDERDecode(&cert, SEC_SignedCertificateTemplate, Data, Size);
- return 0;
-}
-
-REGISTER_FUZZING_TARGET("cert", cert_fuzzing_target, 3072, "Certificate Import")
-
-extern "C" int spki_fuzzing_target(const uint8_t *Data, size_t Size) {
- CERTSubjectPublicKeyInfo spki;
- QuickDERDecode(&spki, CERT_SubjectPublicKeyInfoTemplate, Data, Size);
- return 0;
-}
-
-REGISTER_FUZZING_TARGET("spki", spki_fuzzing_target, 1024, "SPKI Import")
diff --git a/nss/fuzz/registry.h b/nss/fuzz/registry.h
deleted file mode 100644
index 760118d..0000000
--- a/nss/fuzz/registry.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef registry_h__
-#define registry_h__
-
-#include <map>
-#include "FuzzerInternal.h"
-#include "nss.h"
-
-class Registry {
- public:
- static void Add(std::string name, fuzzer::UserCallback func, uint16_t max_len,
- std::string desc) {
- assert(!Has(name));
- GetInstance().targets_[name] = TargetData(func, max_len, desc);
- }
-
- static bool Has(std::string name) {
- return GetInstance().targets_.count(name) > 0;
- }
-
- static fuzzer::UserCallback Func(std::string name) {
- assert(Has(name));
- return std::get<0>(Get(name));
- }
-
- static uint16_t MaxLen(std::string name) {
- assert(Has(name));
- return std::get<1>(Get(name));
- }
-
- static std::string& Desc(std::string name) {
- assert(Has(name));
- return std::get<2>(Get(name));
- }
-
- static std::vector<std::string> Names() {
- std::vector<std::string> names;
- for (auto& it : GetInstance().targets_) {
- names.push_back(it.first);
- }
- return names;
- }
-
- private:
- typedef std::tuple<fuzzer::UserCallback, uint16_t, std::string> TargetData;
-
- static Registry& GetInstance() {
- static Registry registry;
- return registry;
- }
-
- static TargetData& Get(std::string name) {
- return GetInstance().targets_[name];
- }
-
- Registry() {}
-
- std::map<std::string, TargetData> targets_;
-};
-
-#define REGISTER_FUZZING_TARGET(name, func, max_len, desc) \
- static void __attribute__((constructor)) Register_##func() { \
- Registry::Add(name, func, max_len, desc); \
- }
-
-#endif // registry_h__
diff --git a/nss/fuzz/shared.cc b/nss/fuzz/shared.cc
new file mode 100644
index 0000000..47fb216
--- /dev/null
+++ b/nss/fuzz/shared.cc
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "shared.h"
+
+size_t CustomMutate(Mutators mutators, uint8_t *data, size_t size,
+ size_t max_size, unsigned int seed) {
+ std::mt19937 rng(seed);
+ static std::bernoulli_distribution bdist;
+
+ if (bdist(rng)) {
+ std::uniform_int_distribution<size_t> idist(0, mutators.size() - 1);
+ return mutators.at(idist(rng))(data, size, max_size, seed);
+ }
+
+ return LLVMFuzzerMutate(data, size, max_size);
+}
diff --git a/nss/fuzz/shared.h b/nss/fuzz/shared.h
index 09d805e..35621eb 100644
--- a/nss/fuzz/shared.h
+++ b/nss/fuzz/shared.h
@@ -7,12 +7,24 @@
#ifndef shared_h__
#define shared_h__
+#include <assert.h>
+#include <random>
+#include "cert.h"
#include "nss.h"
+extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
+ size_t MaxSize, unsigned int Seed);
+
class NSSDatabase {
public:
- NSSDatabase() { NSS_NoDB_Init(nullptr); }
- ~NSSDatabase() { NSS_Shutdown(); }
+ NSSDatabase() { assert(NSS_NoDB_Init(nullptr) == SECSuccess); }
+ ~NSSDatabase() { assert(NSS_Shutdown() == SECSuccess); }
};
+typedef std::vector<decltype(LLVMFuzzerCustomMutator) *> Mutators;
+
+size_t CustomMutate(Mutators mutators, uint8_t *data, size_t size,
+ size_t max_size, unsigned int seed);
+
#endif // shared_h__
diff --git a/nss/fuzz/tls_client_config.cc b/nss/fuzz/tls_client_config.cc
new file mode 100644
index 0000000..81f3f57
--- /dev/null
+++ b/nss/fuzz/tls_client_config.cc
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "tls_client_config.h"
+
+const uint64_t CONFIG_FAIL_CERT_AUTH = 0x01;
+const uint64_t CONFIG_ENABLE_EXTENDED_MS = 0x02;
+const uint64_t CONFIG_REQUIRE_DH_NAMED_GROUPS = 0x04;
+const uint64_t CONFIG_ENABLE_FALSE_START = 0x08;
+const uint64_t CONFIG_ENABLE_DEFLATE = 0x10;
+const uint64_t CONFIG_ENABLE_CBC_RANDOM_IV = 0x20;
+const uint64_t CONFIG_REQUIRE_SAFE_NEGOTIATION = 0x40;
+const uint64_t CONFIG_ENABLE_CACHE = 0x80;
+
+// XOR 64-bit chunks of data to build a bitmap of config options derived from
+// the fuzzing input. This seems the only way to fuzz various options while
+// still maintaining compatibility with BoringSSL or OpenSSL fuzzers.
+ClientConfig::ClientConfig(const uint8_t* data, size_t len) {
+ for (size_t i = 0; i < len; i++) {
+ config_ ^= static_cast<uint64_t>(data[i]) << (8 * (i % 8));
+ }
+}
+
+bool ClientConfig::FailCertificateAuthentication() {
+ return config_ & CONFIG_FAIL_CERT_AUTH;
+}
+
+bool ClientConfig::EnableExtendedMasterSecret() {
+ return config_ & CONFIG_ENABLE_EXTENDED_MS;
+}
+
+bool ClientConfig::RequireDhNamedGroups() {
+ return config_ & CONFIG_REQUIRE_DH_NAMED_GROUPS;
+}
+
+bool ClientConfig::EnableFalseStart() {
+ return config_ & CONFIG_ENABLE_FALSE_START;
+}
+
+bool ClientConfig::EnableDeflate() { return config_ & CONFIG_ENABLE_DEFLATE; }
+
+bool ClientConfig::EnableCbcRandomIv() {
+ return config_ & CONFIG_ENABLE_CBC_RANDOM_IV;
+}
+
+bool ClientConfig::RequireSafeNegotiation() {
+ return config_ & CONFIG_REQUIRE_SAFE_NEGOTIATION;
+}
+
+bool ClientConfig::EnableCache() { return config_ & CONFIG_ENABLE_CACHE; }
diff --git a/nss/fuzz/tls_client_config.h b/nss/fuzz/tls_client_config.h
new file mode 100644
index 0000000..4abdc3e
--- /dev/null
+++ b/nss/fuzz/tls_client_config.h
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef tls_client_config_h__
+#define tls_client_config_h__
+
+#include <stdint.h>
+#include <cstddef>
+
+class ClientConfig {
+ public:
+ ClientConfig(const uint8_t* data, size_t len);
+
+ bool FailCertificateAuthentication();
+ bool EnableExtendedMasterSecret();
+ bool RequireDhNamedGroups();
+ bool EnableFalseStart();
+ bool EnableDeflate();
+ bool EnableCbcRandomIv();
+ bool RequireSafeNegotiation();
+ bool EnableCache();
+
+ private:
+ uint64_t config_;
+};
+
+#endif // tls_client_config_h__
diff --git a/nss/fuzz/tls_client_target.cc b/nss/fuzz/tls_client_target.cc
new file mode 100644
index 0000000..e595509
--- /dev/null
+++ b/nss/fuzz/tls_client_target.cc
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <assert.h>
+#include <stdint.h>
+#include <memory>
+
+#include "blapi.h"
+#include "prinit.h"
+#include "ssl.h"
+
+#include "shared.h"
+#include "tls_client_config.h"
+#include "tls_common.h"
+#include "tls_mutators.h"
+#include "tls_socket.h"
+
+#ifdef IS_DTLS
+__attribute__((constructor)) static void set_is_dtls() {
+ TlsMutators::SetIsDTLS();
+}
+#endif
+
+PRFileDesc* ImportFD(PRFileDesc* model, PRFileDesc* fd) {
+#ifdef IS_DTLS
+ return DTLS_ImportFD(model, fd);
+#else
+ return SSL_ImportFD(model, fd);
+#endif
+}
+
+static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checksig,
+ PRBool isServer) {
+ assert(!isServer);
+ auto config = reinterpret_cast<ClientConfig*>(arg);
+ return config->FailCertificateAuthentication() ? SECFailure : SECSuccess;
+}
+
+static void SetSocketOptions(PRFileDesc* fd,
+ std::unique_ptr<ClientConfig>& config) {
+ SECStatus rv = SSL_OptionSet(fd, SSL_NO_CACHE, config->EnableCache());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_ENABLE_EXTENDED_MASTER_SECRET,
+ config->EnableExtendedMasterSecret());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_REQUIRE_DH_NAMED_GROUPS,
+ config->RequireDhNamedGroups());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_ENABLE_FALSE_START, config->EnableFalseStart());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_ENABLE_DEFLATE, config->EnableDeflate());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_CBC_RANDOM_IV, config->EnableCbcRandomIv());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION,
+ config->RequireSafeNegotiation());
+ assert(rv == SECSuccess);
+
+#ifndef IS_DTLS
+ rv =
+ SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED);
+ assert(rv == SECSuccess);
+#endif
+}
+
+// This is only called when we set SSL_ENABLE_FALSE_START=1,
+// so we can always just set *canFalseStart=true.
+static SECStatus CanFalseStartCallback(PRFileDesc* fd, void* arg,
+ PRBool* canFalseStart) {
+ *canFalseStart = true;
+ return SECSuccess;
+}
+
+static void SetupCallbacks(PRFileDesc* fd, ClientConfig* config) {
+ SECStatus rv = SSL_AuthCertificateHook(fd, AuthCertificateHook, config);
+ assert(rv == SECSuccess);
+
+ rv = SSL_SetCanFalseStartCallback(fd, CanFalseStartCallback, nullptr);
+ assert(rv == SECSuccess);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
+ static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
+ assert(db != nullptr);
+
+ EnableAllProtocolVersions();
+ std::unique_ptr<ClientConfig> config(new ClientConfig(data, len));
+
+ // Clear the cache. We never want to resume as we couldn't reproduce that.
+ SSL_ClearSessionCache();
+
+ // Reset the RNG state.
+ assert(RNG_RandomUpdate(NULL, 0) == SECSuccess);
+
+ // Create and import dummy socket.
+ std::unique_ptr<DummyPrSocket> socket(new DummyPrSocket(data, len));
+ static PRDescIdentity id = PR_GetUniqueIdentity("fuzz-client");
+ ScopedPRFileDesc fd(DummyIOLayerMethods::CreateFD(id, socket.get()));
+ PRFileDesc* ssl_fd = ImportFD(nullptr, fd.get());
+ assert(ssl_fd == fd.get());
+
+ // Probably not too important for clients.
+ SSL_SetURL(ssl_fd, "server");
+
+ SetSocketOptions(ssl_fd, config);
+ EnableAllCipherSuites(ssl_fd);
+ SetupCallbacks(ssl_fd, config.get());
+ DoHandshake(ssl_fd, false);
+
+ return 0;
+}
+
+extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
+ size_t max_size, unsigned int seed) {
+ using namespace TlsMutators;
+ return CustomMutate({DropRecord, ShuffleRecords, DuplicateRecord,
+ TruncateRecord, FragmentRecord},
+ data, size, max_size, seed);
+}
+
+extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t* data1, size_t size1,
+ const uint8_t* data2, size_t size2,
+ uint8_t* out, size_t max_out_size,
+ unsigned int seed) {
+ return TlsMutators::CrossOver(data1, size1, data2, size2, out, max_out_size,
+ seed);
+}
diff --git a/nss/fuzz/tls_common.cc b/nss/fuzz/tls_common.cc
new file mode 100644
index 0000000..1e66684
--- /dev/null
+++ b/nss/fuzz/tls_common.cc
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <assert.h>
+
+#include "ssl.h"
+
+#include "tls_common.h"
+
+PRStatus EnableAllProtocolVersions() {
+ SSLVersionRange supported;
+
+ SECStatus rv = SSL_VersionRangeGetSupported(ssl_variant_stream, &supported);
+ assert(rv == SECSuccess);
+
+ rv = SSL_VersionRangeSetDefault(ssl_variant_stream, &supported);
+ assert(rv == SECSuccess);
+
+ return PR_SUCCESS;
+}
+
+void EnableAllCipherSuites(PRFileDesc* fd) {
+ for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
+ SECStatus rv = SSL_CipherPrefSet(fd, SSL_ImplementedCiphers[i], true);
+ assert(rv == SECSuccess);
+ }
+}
+
+void DoHandshake(PRFileDesc* fd, bool isServer) {
+ SECStatus rv = SSL_ResetHandshake(fd, isServer);
+ assert(rv == SECSuccess);
+
+ do {
+ rv = SSL_ForceHandshake(fd);
+ } while (rv != SECSuccess && PR_GetError() == PR_WOULD_BLOCK_ERROR);
+
+ // If the handshake succeeds, let's read some data from the server, if any.
+ if (rv == SECSuccess) {
+ uint8_t block[1024];
+ int32_t nb;
+
+ // Read application data and echo it back.
+ while ((nb = PR_Read(fd, block, sizeof(block))) > 0) {
+ PR_Write(fd, block, nb);
+ }
+ }
+}
diff --git a/nss/fuzz/tls_common.h b/nss/fuzz/tls_common.h
new file mode 100644
index 0000000..8843347
--- /dev/null
+++ b/nss/fuzz/tls_common.h
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef tls_common_h__
+#define tls_common_h__
+
+#include "prinit.h"
+
+PRStatus EnableAllProtocolVersions();
+void EnableAllCipherSuites(PRFileDesc* fd);
+void DoHandshake(PRFileDesc* fd, bool isServer);
+
+#endif // tls_common_h__
diff --git a/nss/fuzz/tls_mutators.cc b/nss/fuzz/tls_mutators.cc
new file mode 100644
index 0000000..e9770cb
--- /dev/null
+++ b/nss/fuzz/tls_mutators.cc
@@ -0,0 +1,289 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "shared.h"
+#include "tls_parser.h"
+
+#include "ssl.h"
+#include "sslimpl.h"
+
+using namespace nss_test;
+
+// Number of additional bytes in the TLS header.
+// Used to properly skip DTLS seqnums.
+static size_t gExtraHeaderBytes = 0;
+
+// Helper class to simplify TLS record manipulation.
+class Record {
+ public:
+ static std::unique_ptr<Record> Create(const uint8_t *data, size_t size,
+ size_t remaining) {
+ return std::unique_ptr<Record>(new Record(data, size, remaining));
+ }
+
+ void insert_before(const std::unique_ptr<Record> &other) {
+ assert(data_ && size_ > 0);
+
+ // Copy data in case other == this.
+ uint8_t buf[size_];
+ memcpy(buf, data_, size_);
+
+ uint8_t *dest = const_cast<uint8_t *>(other->data());
+ // Make room for the record we want to insert.
+ memmove(dest + size_, other->data(), other->size() + other->remaining());
+ // Insert the record.
+ memcpy(dest, buf, size_);
+ }
+
+ void truncate(size_t length) {
+ assert(length >= 5 + gExtraHeaderBytes);
+ uint8_t *dest = const_cast<uint8_t *>(data_);
+ (void)ssl_EncodeUintX(length - 5 - gExtraHeaderBytes, 2, &dest[3]);
+ memmove(dest + length, data_ + size_, remaining_);
+ }
+
+ void drop() {
+ uint8_t *dest = const_cast<uint8_t *>(data_);
+ memmove(dest, data_ + size_, remaining_);
+ }
+
+ const uint8_t *data() { return data_; }
+ size_t remaining() { return remaining_; }
+ size_t size() { return size_; }
+
+ private:
+ Record(const uint8_t *data, size_t size, size_t remaining)
+ : data_(data), remaining_(remaining), size_(size) {}
+
+ const uint8_t *data_;
+ size_t remaining_;
+ size_t size_;
+};
+
+// Parse records contained in a given TLS transcript.
+std::vector<std::unique_ptr<Record>> ParseRecords(const uint8_t *data,
+ size_t size) {
+ std::vector<std::unique_ptr<Record>> records;
+ TlsParser parser(data, size);
+
+ while (parser.remaining()) {
+ size_t offset = parser.consumed();
+
+ // Skip type, version, and DTLS seqnums.
+ if (!parser.Skip(3 + gExtraHeaderBytes)) {
+ break;
+ }
+
+ DataBuffer fragment;
+ if (!parser.ReadVariable(&fragment, 2)) {
+ break;
+ }
+
+ records.push_back(Record::Create(data + offset,
+ fragment.len() + 5 + gExtraHeaderBytes,
+ parser.remaining()));
+ }
+
+ return records;
+}
+
+namespace TlsMutators {
+
+// Handle seqnums in DTLS transcripts.
+void SetIsDTLS() { gExtraHeaderBytes = 8; }
+
+// Mutator that drops whole TLS records.
+size_t DropRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed) {
+ std::mt19937 rng(seed);
+
+ // Find TLS records in the corpus.
+ auto records = ParseRecords(data, size);
+ if (records.empty()) {
+ return 0;
+ }
+
+ // Pick a record to drop at random.
+ std::uniform_int_distribution<size_t> dist(0, records.size() - 1);
+ auto &rec = records.at(dist(rng));
+
+ // Drop the record.
+ rec->drop();
+
+ // Return the new final size.
+ return size - rec->size();
+}
+
+// Mutator that shuffles TLS records in a transcript.
+size_t ShuffleRecords(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed) {
+ std::mt19937 rng(seed);
+
+ // Store the original corpus.
+ uint8_t buf[size];
+ memcpy(buf, data, size);
+
+ // Find TLS records in the corpus.
+ auto records = ParseRecords(buf, sizeof(buf));
+ if (records.empty()) {
+ return 0;
+ }
+
+ // Find offset of first record in target buffer.
+ uint8_t *dest = const_cast<uint8_t *>(ParseRecords(data, size).at(0)->data());
+
+ // Shuffle record order.
+ std::shuffle(records.begin(), records.end(), rng);
+
+ // Write records to their new positions.
+ for (auto &rec : records) {
+ memcpy(dest, rec->data(), rec->size());
+ dest += rec->size();
+ }
+
+ // Final size hasn't changed.
+ return size;
+}
+
+// Mutator that duplicates a single TLS record and randomly inserts it.
+size_t DuplicateRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed) {
+ std::mt19937 rng(seed);
+
+ // Find TLS records in the corpus.
+ const auto records = ParseRecords(data, size);
+ if (records.empty()) {
+ return 0;
+ }
+
+ // Pick a record to duplicate at random.
+ std::uniform_int_distribution<size_t> dist(0, records.size() - 1);
+ auto &rec = records.at(dist(rng));
+ if (size + rec->size() > max_size) {
+ return 0;
+ }
+
+ // Insert before random record.
+ rec->insert_before(records.at(dist(rng)));
+
+ // Return the new final size.
+ return size + rec->size();
+}
+
+// Mutator that truncates a TLS record.
+size_t TruncateRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed) {
+ std::mt19937 rng(seed);
+
+ // Find TLS records in the corpus.
+ const auto records = ParseRecords(data, size);
+ if (records.empty()) {
+ return 0;
+ }
+
+ // Pick a record to truncate at random.
+ std::uniform_int_distribution<size_t> dist(0, records.size() - 1);
+ auto &rec = records.at(dist(rng));
+
+ // Need a record with data.
+ if (rec->size() <= 5 + gExtraHeaderBytes) {
+ return 0;
+ }
+
+ // Truncate.
+ std::uniform_int_distribution<size_t> dist2(5 + gExtraHeaderBytes,
+ rec->size() - 1);
+ size_t new_length = dist2(rng);
+ rec->truncate(new_length);
+
+ // Return the new final size.
+ return size + new_length - rec->size();
+}
+
+// Mutator that splits a TLS record in two.
+size_t FragmentRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed) {
+ std::mt19937 rng(seed);
+
+ // We can't deal with DTLS yet.
+ if (gExtraHeaderBytes > 0) {
+ return 0;
+ }
+
+ if (size + 5 > max_size) {
+ return 0;
+ }
+
+ // Find TLS records in the corpus.
+ const auto records = ParseRecords(data, size);
+ if (records.empty()) {
+ return 0;
+ }
+
+ // Pick a record to fragment at random.
+ std::uniform_int_distribution<size_t> dist(0, records.size() - 1);
+ auto &rec = records.at(dist(rng));
+ uint8_t *rdata = const_cast<uint8_t *>(rec->data());
+ size_t length = rec->size();
+ size_t content_length = length - 5;
+
+ if (content_length < 2) {
+ return 0;
+ }
+
+ // Assign a new length to the first fragment.
+ size_t new_length = content_length / 2;
+ uint8_t *content = ssl_EncodeUintX(new_length, 2, &rdata[3]);
+
+ // Make room for one more header.
+ memmove(content + new_length + 5, content + new_length,
+ rec->remaining() + content_length - new_length);
+
+ // Write second header.
+ memcpy(content + new_length, rdata, 3);
+ (void)ssl_EncodeUintX(content_length - new_length, 2,
+ &content[new_length + 3]);
+
+ return size + 5;
+}
+
+// Cross-over function that merges and shuffles two transcripts.
+size_t CrossOver(const uint8_t *data1, size_t size1, const uint8_t *data2,
+ size_t size2, uint8_t *out, size_t max_out_size,
+ unsigned int seed) {
+ std::mt19937 rng(seed);
+
+ // Find TLS records in the corpus.
+ auto records1 = ParseRecords(data1, size1);
+ if (records1.empty()) {
+ return 0;
+ }
+
+ { // Merge the two vectors.
+ auto records2 = ParseRecords(data2, size2);
+ if (records2.empty()) {
+ return 0;
+ }
+ std::move(records2.begin(), records2.end(), std::back_inserter(records1));
+ }
+
+ // Shuffle record order.
+ std::shuffle(records1.begin(), records1.end(), rng);
+
+ size_t total = 0;
+ for (auto &rec : records1) {
+ size_t length = rec->size();
+ if (total + length > max_out_size) {
+ break;
+ }
+
+ // Write record to its new position.
+ memcpy(out + total, rec->data(), length);
+ total += length;
+ }
+
+ return total;
+}
+
+} // namespace TlsMutators
diff --git a/nss/fuzz/tls_mutators.h b/nss/fuzz/tls_mutators.h
new file mode 100644
index 0000000..03a2147
--- /dev/null
+++ b/nss/fuzz/tls_mutators.h
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef tls_mutators_h__
+#define tls_mutators_h__
+
+namespace TlsMutators {
+
+void SetIsDTLS();
+
+size_t DropRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed);
+size_t ShuffleRecords(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed);
+size_t DuplicateRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed);
+size_t TruncateRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed);
+size_t FragmentRecord(uint8_t *data, size_t size, size_t max_size,
+ unsigned int seed);
+
+size_t CrossOver(const uint8_t *data1, size_t size1, const uint8_t *data2,
+ size_t size2, uint8_t *out, size_t max_out_size,
+ unsigned int seed);
+
+} // namespace TlsMutators
+
+#endif // tls_mutators_h__
diff --git a/nss/fuzz/tls_server_certs.cc b/nss/fuzz/tls_server_certs.cc
new file mode 100644
index 0000000..705b6aa
--- /dev/null
+++ b/nss/fuzz/tls_server_certs.cc
@@ -0,0 +1,295 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "ssl.h"
+
+#include "cpputil.h"
+#include "scoped_ptrs.h"
+#include "tls_server_certs.h"
+
+const uint8_t kP256ServerCert[] = {
+ 0x30, 0x82, 0x01, 0xcf, 0x30, 0x82, 0x01, 0x76, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0xd9, 0x4c, 0x04, 0xda, 0x49, 0x7d, 0xbf, 0xeb,
+ 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+ 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
+ 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
+ 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
+ 0x17, 0x0d, 0x31, 0x34, 0x30, 0x34, 0x32, 0x33, 0x32, 0x33, 0x32, 0x31,
+ 0x35, 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x32, 0x33, 0x32,
+ 0x33, 0x32, 0x31, 0x35, 0x37, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
+ 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
+ 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
+ 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
+ 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
+ 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
+ 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2,
+ 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5,
+ 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e,
+ 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9,
+ 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a,
+ 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
+ 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0xab, 0x84, 0xd2, 0xac, 0xab, 0x95, 0xf0, 0x82, 0x4e,
+ 0x16, 0x78, 0x07, 0x55, 0x57, 0x5f, 0xe4, 0x26, 0x8d, 0x82, 0xd1, 0x30,
+ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+ 0xab, 0x84, 0xd2, 0xac, 0xab, 0x95, 0xf0, 0x82, 0x4e, 0x16, 0x78, 0x07,
+ 0x55, 0x57, 0x5f, 0xe4, 0x26, 0x8d, 0x82, 0xd1, 0x30, 0x0c, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x09,
+ 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x03, 0x48, 0x00,
+ 0x30, 0x45, 0x02, 0x21, 0x00, 0xf2, 0xa0, 0x35, 0x5e, 0x51, 0x3a, 0x36,
+ 0xc3, 0x82, 0x79, 0x9b, 0xee, 0x27, 0x50, 0x85, 0x8e, 0x70, 0x06, 0x74,
+ 0x95, 0x57, 0xd2, 0x29, 0x74, 0x00, 0xf4, 0xbe, 0x15, 0x87, 0x5d, 0xc4,
+ 0x07, 0x02, 0x20, 0x7c, 0x1e, 0x79, 0x14, 0x6a, 0x21, 0x83, 0xf0, 0x7a,
+ 0x74, 0x68, 0x79, 0x5f, 0x14, 0x99, 0x9a, 0x68, 0xb4, 0xf1, 0xcb, 0x9e,
+ 0x15, 0x5e, 0xe6, 0x1f, 0x32, 0x52, 0x61, 0x5e, 0x75, 0xc9, 0x14};
+
+const uint8_t kP256ServerKey[] = {
+ 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+ 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
+ 0x07, 0x0f, 0x08, 0x72, 0x7a, 0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9,
+ 0x4d, 0x89, 0x68, 0x77, 0x08, 0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e,
+ 0xe8, 0xd1, 0xc9, 0xce, 0x0a, 0x8b, 0xb4, 0x6a, 0xa1, 0x44, 0x03, 0x42,
+ 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f,
+ 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d,
+ 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7,
+ 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2,
+ 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94,
+ 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1};
+
+const uint8_t kRsaServerCert[] = {
+ 0x30, 0x82, 0x03, 0xb5, 0x30, 0x82, 0x02, 0x9d, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0xb5, 0xb6, 0x22, 0xb9, 0x5a, 0x04, 0xa5, 0x21,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x0b, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+ 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
+ 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, 0x30, 0x39,
+ 0x30, 0x34, 0x33, 0x38, 0x30, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x30,
+ 0x38, 0x30, 0x38, 0x30, 0x34, 0x33, 0x38, 0x30, 0x39, 0x5a, 0x30, 0x45,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
+ 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
+ 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
+ 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
+ 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
+ 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x82, 0x01,
+ 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+ 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xba, 0x0b, 0xda, 0x84, 0x19, 0x12,
+ 0x01, 0x41, 0x75, 0x7c, 0x2e, 0x3d, 0xbd, 0xbd, 0x5b, 0xbe, 0x53, 0xeb,
+ 0x72, 0x5f, 0x34, 0x92, 0x8a, 0x75, 0x88, 0xba, 0x62, 0xb9, 0x8a, 0x33,
+ 0xe1, 0x0a, 0x6d, 0xc3, 0x2e, 0x7b, 0xf8, 0x45, 0xac, 0xb1, 0x90, 0x5c,
+ 0x1e, 0x9a, 0xd9, 0xe4, 0x19, 0x16, 0x7f, 0xa3, 0xde, 0x19, 0x9e, 0xc5,
+ 0xe4, 0x05, 0xf5, 0x3f, 0x22, 0x5b, 0x18, 0x76, 0x4b, 0xaa, 0xf3, 0x02,
+ 0xbd, 0x58, 0x8f, 0xea, 0x97, 0x78, 0x30, 0x5a, 0x31, 0xfe, 0x28, 0x04,
+ 0x48, 0x84, 0x84, 0x1c, 0x48, 0xb1, 0xa2, 0x25, 0xc2, 0xcd, 0xea, 0x41,
+ 0xae, 0x1b, 0x69, 0xe5, 0x44, 0x12, 0x8c, 0x70, 0xf8, 0x0f, 0x88, 0x4a,
+ 0xb6, 0x07, 0x4c, 0x81, 0x5c, 0x57, 0xf8, 0xb4, 0x6d, 0xc2, 0x05, 0xb7,
+ 0x9a, 0x7b, 0xbf, 0xbc, 0x1b, 0xbb, 0xaf, 0x3a, 0x6b, 0xfc, 0x34, 0xbc,
+ 0x8a, 0x8f, 0x7d, 0xa7, 0x79, 0x6a, 0x67, 0x50, 0x24, 0xcb, 0xe6, 0x8d,
+ 0x95, 0xc3, 0x23, 0xe8, 0xc6, 0x32, 0xf1, 0x4f, 0x98, 0x14, 0x47, 0xaf,
+ 0x6f, 0xf5, 0x74, 0x95, 0x16, 0x3d, 0xa2, 0xac, 0x26, 0x5b, 0xb0, 0x47,
+ 0x9d, 0x78, 0xa4, 0x9b, 0xfb, 0xe2, 0xea, 0xc8, 0xc8, 0x4b, 0x7e, 0x74,
+ 0x53, 0xcc, 0xdb, 0xfe, 0x64, 0x73, 0x61, 0xe2, 0x2c, 0xd9, 0x1e, 0xb9,
+ 0x2d, 0x47, 0x6e, 0x4c, 0xbe, 0x74, 0xf9, 0x43, 0x20, 0x6a, 0xdf, 0x68,
+ 0x71, 0xec, 0x08, 0xd9, 0xdb, 0xfc, 0x68, 0xef, 0x43, 0xa6, 0x1f, 0xbc,
+ 0x35, 0xd1, 0xad, 0x83, 0xc2, 0xc5, 0x63, 0x24, 0xd3, 0x1d, 0xc5, 0x31,
+ 0x26, 0x83, 0x2b, 0xd4, 0xf4, 0xce, 0x82, 0x79, 0x84, 0x4f, 0x5f, 0x56,
+ 0x24, 0x7e, 0x0f, 0xac, 0x5c, 0x24, 0xed, 0x91, 0x35, 0x40, 0x94, 0x10,
+ 0xd4, 0xbe, 0x22, 0x2a, 0x63, 0xde, 0x42, 0x2b, 0x2d, 0xb9, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06,
+ 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf9, 0x9b, 0xa5, 0x6f,
+ 0xcd, 0x88, 0xd5, 0x60, 0x71, 0xb7, 0xd2, 0x20, 0x44, 0xfa, 0x3d, 0x97,
+ 0x0e, 0x15, 0x04, 0xf2, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+ 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xf9, 0x9b, 0xa5, 0x6f, 0xcd, 0x88, 0xd5,
+ 0x60, 0x71, 0xb7, 0xd2, 0x20, 0x44, 0xfa, 0x3d, 0x97, 0x0e, 0x15, 0x04,
+ 0xf2, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
+ 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
+ 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb5, 0xb6, 0x22, 0xb9, 0x5a,
+ 0x04, 0xa5, 0x21, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
+ 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+ 0x00, 0x3e, 0xc9, 0x83, 0xaf, 0x12, 0x02, 0xb6, 0x16, 0x95, 0xca, 0x07,
+ 0x7d, 0x90, 0x01, 0xf7, 0x43, 0xe6, 0xca, 0xbb, 0x79, 0x1f, 0xa0, 0xfc,
+ 0x2d, 0x18, 0xbe, 0x5b, 0x64, 0x62, 0xd5, 0xf0, 0x4d, 0xc5, 0x11, 0x04,
+ 0x2e, 0x77, 0xb3, 0x58, 0x9d, 0xac, 0x72, 0x39, 0x78, 0x50, 0xc7, 0x2c,
+ 0x29, 0x8a, 0x78, 0x3e, 0x2f, 0x79, 0xd2, 0x05, 0x4d, 0xfb, 0xad, 0x88,
+ 0x82, 0xb2, 0x26, 0x70, 0x23, 0x6f, 0xb5, 0xbe, 0x48, 0xd4, 0x27, 0xf2,
+ 0xfc, 0xc3, 0x4d, 0xba, 0xbf, 0x5f, 0x7d, 0xab, 0x3a, 0x5f, 0x7d, 0xf8,
+ 0x0f, 0x48, 0x58, 0x54, 0x84, 0x13, 0x78, 0xfc, 0x85, 0x93, 0x7b, 0xa6,
+ 0x23, 0xed, 0xa6, 0x25, 0x0a, 0xed, 0x65, 0x9c, 0x8c, 0x3c, 0x82, 0x92,
+ 0x63, 0xfb, 0x18, 0x19, 0x01, 0xe1, 0x18, 0x65, 0xfa, 0xc0, 0x62, 0xbe,
+ 0x18, 0xef, 0xe8, 0x83, 0x43, 0xd0, 0x93, 0xf5, 0x6e, 0xe8, 0x3f, 0x86,
+ 0x53, 0x65, 0xd1, 0x9c, 0x35, 0x74, 0x61, 0x98, 0x35, 0x96, 0xc0, 0x2c,
+ 0x1d, 0xdd, 0xb5, 0x5e, 0xbc, 0x8a, 0xe9, 0xf0, 0xe6, 0x36, 0x41, 0x0c,
+ 0xc1, 0xb2, 0x16, 0xae, 0xdb, 0x38, 0xc5, 0xce, 0xec, 0x71, 0x1a, 0xc6,
+ 0x1d, 0x6c, 0xbe, 0x88, 0xc7, 0xfa, 0xff, 0xba, 0x7f, 0x02, 0x4f, 0xd2,
+ 0x22, 0x27, 0x0c, 0xe1, 0x74, 0xb0, 0x9a, 0x54, 0x3c, 0xa4, 0xfc, 0x40,
+ 0x64, 0xfa, 0xfe, 0x13, 0x62, 0xe8, 0x55, 0xdf, 0x69, 0x32, 0x95, 0x94,
+ 0xc2, 0x95, 0xb6, 0x51, 0xbb, 0x4e, 0xe7, 0x0b, 0x06, 0x4e, 0xb6, 0x39,
+ 0xb0, 0xee, 0x39, 0xb4, 0x53, 0x4d, 0xff, 0x2f, 0xa3, 0xb5, 0x48, 0x5e,
+ 0x07, 0x50, 0xb6, 0x8a, 0x33, 0x9b, 0x1b, 0xfb, 0x57, 0x10, 0xb6, 0xa2,
+ 0xc8, 0x27, 0x4c, 0xf9, 0x2f, 0xf0, 0x69, 0xeb, 0xaf, 0xd0, 0xc5, 0xed,
+ 0x23, 0x8c, 0x67, 0x9f, 0x50};
+
+const uint8_t kRsaServerKey[] = {
+ 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+ 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
+ 0x01, 0x00, 0xba, 0x0b, 0xda, 0x84, 0x19, 0x12, 0x01, 0x41, 0x75, 0x7c,
+ 0x2e, 0x3d, 0xbd, 0xbd, 0x5b, 0xbe, 0x53, 0xeb, 0x72, 0x5f, 0x34, 0x92,
+ 0x8a, 0x75, 0x88, 0xba, 0x62, 0xb9, 0x8a, 0x33, 0xe1, 0x0a, 0x6d, 0xc3,
+ 0x2e, 0x7b, 0xf8, 0x45, 0xac, 0xb1, 0x90, 0x5c, 0x1e, 0x9a, 0xd9, 0xe4,
+ 0x19, 0x16, 0x7f, 0xa3, 0xde, 0x19, 0x9e, 0xc5, 0xe4, 0x05, 0xf5, 0x3f,
+ 0x22, 0x5b, 0x18, 0x76, 0x4b, 0xaa, 0xf3, 0x02, 0xbd, 0x58, 0x8f, 0xea,
+ 0x97, 0x78, 0x30, 0x5a, 0x31, 0xfe, 0x28, 0x04, 0x48, 0x84, 0x84, 0x1c,
+ 0x48, 0xb1, 0xa2, 0x25, 0xc2, 0xcd, 0xea, 0x41, 0xae, 0x1b, 0x69, 0xe5,
+ 0x44, 0x12, 0x8c, 0x70, 0xf8, 0x0f, 0x88, 0x4a, 0xb6, 0x07, 0x4c, 0x81,
+ 0x5c, 0x57, 0xf8, 0xb4, 0x6d, 0xc2, 0x05, 0xb7, 0x9a, 0x7b, 0xbf, 0xbc,
+ 0x1b, 0xbb, 0xaf, 0x3a, 0x6b, 0xfc, 0x34, 0xbc, 0x8a, 0x8f, 0x7d, 0xa7,
+ 0x79, 0x6a, 0x67, 0x50, 0x24, 0xcb, 0xe6, 0x8d, 0x95, 0xc3, 0x23, 0xe8,
+ 0xc6, 0x32, 0xf1, 0x4f, 0x98, 0x14, 0x47, 0xaf, 0x6f, 0xf5, 0x74, 0x95,
+ 0x16, 0x3d, 0xa2, 0xac, 0x26, 0x5b, 0xb0, 0x47, 0x9d, 0x78, 0xa4, 0x9b,
+ 0xfb, 0xe2, 0xea, 0xc8, 0xc8, 0x4b, 0x7e, 0x74, 0x53, 0xcc, 0xdb, 0xfe,
+ 0x64, 0x73, 0x61, 0xe2, 0x2c, 0xd9, 0x1e, 0xb9, 0x2d, 0x47, 0x6e, 0x4c,
+ 0xbe, 0x74, 0xf9, 0x43, 0x20, 0x6a, 0xdf, 0x68, 0x71, 0xec, 0x08, 0xd9,
+ 0xdb, 0xfc, 0x68, 0xef, 0x43, 0xa6, 0x1f, 0xbc, 0x35, 0xd1, 0xad, 0x83,
+ 0xc2, 0xc5, 0x63, 0x24, 0xd3, 0x1d, 0xc5, 0x31, 0x26, 0x83, 0x2b, 0xd4,
+ 0xf4, 0xce, 0x82, 0x79, 0x84, 0x4f, 0x5f, 0x56, 0x24, 0x7e, 0x0f, 0xac,
+ 0x5c, 0x24, 0xed, 0x91, 0x35, 0x40, 0x94, 0x10, 0xd4, 0xbe, 0x22, 0x2a,
+ 0x63, 0xde, 0x42, 0x2b, 0x2d, 0xb9, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+ 0x82, 0x01, 0x00, 0x1c, 0xfb, 0xef, 0xc5, 0x18, 0xaa, 0xc7, 0x6b, 0x4d,
+ 0x44, 0x55, 0x67, 0xe5, 0x01, 0x75, 0x23, 0x87, 0xab, 0x6c, 0x9c, 0x0c,
+ 0x72, 0xb0, 0x03, 0x73, 0x93, 0xa6, 0x01, 0xc5, 0xd8, 0x23, 0x3d, 0x1e,
+ 0xb0, 0x83, 0xb3, 0x68, 0x90, 0x62, 0x41, 0x1f, 0x7e, 0x5a, 0x7e, 0x41,
+ 0x67, 0xd9, 0xc8, 0xb9, 0x85, 0xeb, 0xfa, 0x0d, 0xd4, 0x42, 0x9b, 0xf3,
+ 0x03, 0x2c, 0xf5, 0x08, 0x30, 0x95, 0xc5, 0x42, 0x2a, 0xb1, 0x18, 0xf5,
+ 0x02, 0xd5, 0x2a, 0x32, 0x4e, 0x3a, 0xef, 0x9f, 0x88, 0x5b, 0x4b, 0xd9,
+ 0xd1, 0x16, 0x3a, 0x26, 0x4a, 0xbf, 0xb8, 0x98, 0xc0, 0x36, 0xc1, 0xaa,
+ 0x93, 0xbf, 0x31, 0x2c, 0x94, 0x04, 0xf1, 0x56, 0x88, 0x5d, 0x27, 0x71,
+ 0xf1, 0xcd, 0x53, 0x1f, 0x39, 0xec, 0xc7, 0x87, 0x60, 0x7d, 0x3e, 0xbe,
+ 0x36, 0x2e, 0x13, 0xe5, 0x4e, 0xb2, 0xb8, 0x0d, 0xf7, 0x39, 0x96, 0xb0,
+ 0xe0, 0xd7, 0x58, 0x65, 0x8b, 0x44, 0x92, 0xa3, 0x62, 0xa8, 0xae, 0x95,
+ 0x61, 0xee, 0x26, 0x03, 0x1c, 0x55, 0x87, 0x9a, 0xac, 0x72, 0x28, 0x55,
+ 0x54, 0xc1, 0xa4, 0x05, 0x5a, 0x89, 0x36, 0x28, 0x84, 0xa2, 0xd7, 0x2d,
+ 0x9b, 0x59, 0x69, 0x87, 0xca, 0x30, 0xfb, 0xba, 0x3c, 0x82, 0x05, 0xce,
+ 0x5b, 0xdc, 0x66, 0xf9, 0x11, 0xc7, 0x3d, 0xc1, 0xfb, 0x12, 0x9c, 0x7b,
+ 0x86, 0x39, 0x1b, 0xfe, 0x17, 0xa5, 0x00, 0xd7, 0x18, 0x38, 0xaf, 0x79,
+ 0xd1, 0x6e, 0x7f, 0x47, 0xed, 0xb3, 0x59, 0x5f, 0x51, 0xea, 0x4c, 0x68,
+ 0xe9, 0x1f, 0xbf, 0x85, 0xf1, 0x85, 0x16, 0x60, 0xaf, 0x97, 0x89, 0x39,
+ 0xfa, 0x2f, 0x18, 0xd0, 0x89, 0x44, 0xbf, 0x77, 0xf3, 0x7b, 0x51, 0x34,
+ 0x2f, 0x0c, 0x9f, 0xdf, 0xbf, 0x62, 0xdc, 0x2f, 0xdc, 0x29, 0xcb, 0x9a,
+ 0x13, 0x98, 0x30, 0x47, 0x9e, 0x01, 0x01, 0x02, 0x81, 0x81, 0x00, 0xf1,
+ 0x96, 0xc3, 0x72, 0xf4, 0xcd, 0xfb, 0x1e, 0x08, 0x2e, 0x82, 0x51, 0xed,
+ 0xf1, 0x6f, 0x9c, 0xb8, 0xf3, 0x6d, 0xc4, 0xd8, 0xc5, 0x09, 0x62, 0x23,
+ 0x35, 0x1f, 0x5d, 0x4a, 0xf7, 0x6b, 0xd4, 0xe8, 0xb6, 0xf1, 0x9d, 0x40,
+ 0x63, 0xe0, 0x41, 0x3d, 0x2b, 0xfa, 0x50, 0x12, 0xa7, 0x4f, 0x93, 0xe9,
+ 0x38, 0x58, 0xea, 0xc5, 0xf3, 0x18, 0xfe, 0x3f, 0xf3, 0xa0, 0xa7, 0x48,
+ 0x69, 0x85, 0xf5, 0xa6, 0x18, 0x1e, 0x40, 0x75, 0xdc, 0x1e, 0xb0, 0x75,
+ 0xa5, 0x2f, 0x32, 0xa1, 0xa1, 0x7f, 0xa5, 0x32, 0x52, 0x37, 0x66, 0x1b,
+ 0xf2, 0xff, 0x64, 0x97, 0xf0, 0xa1, 0xd7, 0x27, 0x98, 0x5d, 0xa3, 0x55,
+ 0x1a, 0x67, 0x81, 0x2e, 0x41, 0xfd, 0x1f, 0xac, 0x08, 0x71, 0x4c, 0x43,
+ 0x31, 0xab, 0x35, 0x8b, 0xc5, 0x54, 0xce, 0xc8, 0x73, 0x85, 0xc9, 0x6e,
+ 0x08, 0xd1, 0xa8, 0x26, 0x3f, 0x70, 0x51, 0x02, 0x81, 0x81, 0x00, 0xc5,
+ 0x24, 0xea, 0x16, 0x9d, 0xcb, 0x2c, 0x7d, 0x60, 0xab, 0xb2, 0xe0, 0xd6,
+ 0x12, 0x87, 0x94, 0xef, 0x56, 0x61, 0xdf, 0xe6, 0xc3, 0xf7, 0xa1, 0x85,
+ 0xb3, 0x6f, 0x42, 0x74, 0x86, 0xc7, 0xa5, 0xc6, 0xf1, 0x85, 0x66, 0x23,
+ 0x03, 0xd4, 0x4c, 0xf3, 0x2c, 0x5b, 0x18, 0xfa, 0x29, 0x7b, 0x1c, 0xe8,
+ 0x19, 0xc5, 0x75, 0x1d, 0x7e, 0xa3, 0xf0, 0x4d, 0x6c, 0xd3, 0x17, 0xd8,
+ 0x64, 0x95, 0x76, 0xde, 0xbc, 0x68, 0x33, 0xd6, 0x63, 0xf6, 0x5e, 0x43,
+ 0x99, 0x90, 0x09, 0x40, 0xfc, 0x58, 0x5c, 0x87, 0x6e, 0xde, 0x1e, 0x0f,
+ 0xb2, 0x58, 0x59, 0x2d, 0xdd, 0xe9, 0xf8, 0x31, 0x07, 0x8d, 0xbb, 0x0b,
+ 0x0b, 0xf6, 0xaf, 0x93, 0x73, 0x38, 0x89, 0x98, 0xa6, 0xd4, 0x53, 0x0f,
+ 0x04, 0x93, 0x2c, 0xc0, 0xa4, 0x8b, 0xdb, 0x7c, 0xac, 0xa9, 0x7a, 0x18,
+ 0xff, 0x29, 0xe8, 0xaf, 0xe5, 0xb4, 0xe9, 0x02, 0x81, 0x80, 0x76, 0x1e,
+ 0xbb, 0xa3, 0x3a, 0x34, 0x78, 0x02, 0x60, 0x07, 0xb5, 0x6a, 0x2f, 0x87,
+ 0xab, 0x85, 0x9a, 0x1c, 0x53, 0x60, 0x3a, 0x88, 0x64, 0x25, 0x1a, 0x87,
+ 0xbf, 0xb5, 0x12, 0x91, 0x54, 0xa4, 0xbd, 0xbf, 0xac, 0xf4, 0xb0, 0xe5,
+ 0xe4, 0x60, 0xa1, 0x73, 0x1e, 0x29, 0x06, 0x65, 0xcd, 0x8f, 0xc9, 0x28,
+ 0xe6, 0xb8, 0xab, 0x5e, 0x47, 0xab, 0x10, 0x43, 0xa3, 0x1a, 0x07, 0x5a,
+ 0xa8, 0xc7, 0xc9, 0x94, 0xe3, 0x3d, 0xab, 0x22, 0x9b, 0xd2, 0xb5, 0x42,
+ 0xb5, 0x87, 0xf0, 0xe5, 0x10, 0x8f, 0x09, 0xc2, 0x8f, 0x19, 0x9a, 0xb2,
+ 0xbd, 0xd2, 0x46, 0x43, 0xbe, 0x2d, 0x7f, 0x4b, 0x8d, 0x04, 0xed, 0xf8,
+ 0x42, 0x01, 0x34, 0x47, 0xc9, 0x66, 0x31, 0xeb, 0xd2, 0xd1, 0x71, 0xcd,
+ 0x18, 0x23, 0xcf, 0x1a, 0x05, 0x74, 0x31, 0x27, 0xe2, 0x92, 0xf0, 0xfc,
+ 0xd8, 0xdd, 0x79, 0x0d, 0xed, 0x71, 0x02, 0x81, 0x80, 0x6e, 0xc6, 0x4c,
+ 0x46, 0xc3, 0x09, 0x7c, 0x09, 0x43, 0x3d, 0x97, 0x38, 0xa0, 0xf1, 0x2e,
+ 0x7f, 0xf0, 0x70, 0x30, 0x74, 0xd8, 0x3d, 0x3b, 0x32, 0xe6, 0x66, 0xa9,
+ 0xd8, 0xc4, 0x93, 0x4b, 0x31, 0x8a, 0x75, 0x01, 0xc9, 0x1f, 0x59, 0xb2,
+ 0x7c, 0x3e, 0x93, 0xa8, 0xe8, 0x83, 0x00, 0xb5, 0xed, 0xcb, 0x39, 0x57,
+ 0xeb, 0x73, 0xd4, 0x4a, 0x17, 0xe7, 0xd9, 0x83, 0x4f, 0xbd, 0xc6, 0xde,
+ 0xf9, 0x39, 0x34, 0xd2, 0xb4, 0x75, 0xfe, 0x1b, 0x5c, 0x62, 0x4d, 0xb2,
+ 0x52, 0x90, 0xd2, 0x7a, 0x70, 0x1b, 0xa5, 0x9f, 0x67, 0x72, 0xd8, 0x7a,
+ 0xae, 0x39, 0x88, 0x9d, 0x44, 0x59, 0x80, 0x6e, 0x12, 0x30, 0xa5, 0xdb,
+ 0x4a, 0x52, 0xe7, 0x06, 0x58, 0xc2, 0x8e, 0xd3, 0x75, 0x8c, 0x55, 0xbc,
+ 0xc1, 0x03, 0xca, 0x31, 0xcf, 0xf5, 0xe1, 0x2b, 0x25, 0xb1, 0x50, 0x07,
+ 0x63, 0x79, 0x1a, 0xf0, 0xa9, 0x02, 0x81, 0x80, 0x79, 0xf1, 0x03, 0x53,
+ 0xd5, 0x87, 0xc7, 0xde, 0x34, 0xba, 0xdb, 0xe9, 0x93, 0xda, 0x95, 0xea,
+ 0xa8, 0xb8, 0xcb, 0xaa, 0xfb, 0x03, 0xef, 0x8d, 0x95, 0x62, 0x71, 0x68,
+ 0x1d, 0x1f, 0x87, 0x04, 0xe9, 0xcd, 0xf2, 0xbc, 0xb4, 0x75, 0xd6, 0xb8,
+ 0x96, 0x0c, 0x0c, 0xd7, 0x4e, 0x8b, 0xe4, 0x58, 0x12, 0x83, 0xd0, 0xce,
+ 0x66, 0xf0, 0x12, 0x67, 0xe4, 0x06, 0x16, 0x4f, 0x90, 0x55, 0x0b, 0xfe,
+ 0x73, 0xbe, 0xc0, 0x49, 0x6a, 0x6e, 0x86, 0x60, 0x66, 0x6a, 0x66, 0x42,
+ 0xaf, 0x06, 0x57, 0xae, 0xaf, 0x57, 0x73, 0xdd, 0x91, 0x0c, 0xf9, 0x0a,
+ 0x16, 0xa9, 0xcf, 0xf4, 0xc5, 0x6f, 0xd3, 0xa8, 0x58, 0x28, 0xda, 0x74,
+ 0x9a, 0x84, 0x9d, 0x33, 0xc7, 0x48, 0x68, 0xce, 0xae, 0x4a, 0x8c, 0x2c,
+ 0xfe, 0xbf, 0xda, 0x0e, 0xce, 0x28, 0xb9, 0xdb, 0x9b, 0xcf, 0x6e, 0xa8,
+ 0xe4, 0x60, 0xca, 0x98};
+
+void InstallServerCertificate(PRFileDesc* fd, const uint8_t* cert_data,
+ size_t cert_len, const uint8_t* key_data,
+ size_t key_len) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ assert(slot);
+
+ SECItem certItem = {siBuffer, toUcharPtr(cert_data),
+ static_cast<unsigned int>(cert_len)};
+ SECItem pkcs8Item = {siBuffer, toUcharPtr(key_data),
+ static_cast<unsigned int>(key_len)};
+
+ // Import the certificate.
+ static CERTCertDBHandle* certDB = CERT_GetDefaultCertDB();
+ ScopedCERTCertificate cert(
+ CERT_NewTempCertificate(certDB, &certItem, nullptr, false, true));
+ assert(cert);
+
+ // Import the private key.
+ SECKEYPrivateKey* key = nullptr;
+ SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key,
+ nullptr);
+ assert(rv == SECSuccess);
+
+ // Adopt the private key to ensure it's freed.
+ ScopedSECKEYPrivateKey privKey(key);
+
+ // Configure server with the imported key and certificate.
+ rv = SSL_ConfigServerCert(fd, cert.get(), privKey.get(), nullptr, 0);
+ assert(rv == SECSuccess);
+}
+
+void InstallServerCertificates(PRFileDesc* fd) {
+ // ECDSA P-256 certificate.
+ InstallServerCertificate(fd, kP256ServerCert, sizeof(kP256ServerCert),
+ kP256ServerKey, sizeof(kP256ServerKey));
+
+ // RSA-2048 certificate.
+ InstallServerCertificate(fd, kRsaServerCert, sizeof(kRsaServerCert),
+ kRsaServerKey, sizeof(kRsaServerKey));
+}
diff --git a/nss/fuzz/tls_server_certs.h b/nss/fuzz/tls_server_certs.h
new file mode 100644
index 0000000..c0db253
--- /dev/null
+++ b/nss/fuzz/tls_server_certs.h
@@ -0,0 +1,12 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef tls_server_certs_h__
+#define tls_server_certs_h__
+
+#include "prio.h"
+
+void InstallServerCertificates(PRFileDesc* fd);
+
+#endif // tls_server_certs_h__
diff --git a/nss/fuzz/tls_server_config.cc b/nss/fuzz/tls_server_config.cc
new file mode 100644
index 0000000..fffb27b
--- /dev/null
+++ b/nss/fuzz/tls_server_config.cc
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "tls_server_config.h"
+
+const uint64_t CONFIG_ENABLE_EXTENDED_MS = 0x01;
+const uint64_t CONFIG_REQUEST_CERTIFICATE = 0x02;
+const uint64_t CONFIG_REQUIRE_CERTIFICATE = 0x04;
+const uint64_t CONFIG_ENABLE_DEFLATE = 0x08;
+const uint64_t CONFIG_ENABLE_CBC_RANDOM_IV = 0x10;
+const uint64_t CONFIG_REQUIRE_SAFE_NEGOTIATION = 0x20;
+const uint64_t CONFIG_ENABLE_CACHE = 0x40;
+
+// XOR 64-bit chunks of data to build a bitmap of config options derived from
+// the fuzzing input. This seems the only way to fuzz various options while
+// still maintaining compatibility with BoringSSL or OpenSSL fuzzers.
+ServerConfig::ServerConfig(const uint8_t* data, size_t len) {
+ for (size_t i = 0; i < len; i++) {
+ config_ ^= static_cast<uint64_t>(data[i]) << (8 * (i % 8));
+ }
+}
+
+bool ServerConfig::EnableExtendedMasterSecret() {
+ return config_ & CONFIG_ENABLE_EXTENDED_MS;
+}
+
+bool ServerConfig::RequestCertificate() {
+ return config_ & CONFIG_REQUEST_CERTIFICATE;
+}
+
+bool ServerConfig::RequireCertificate() {
+ return config_ & CONFIG_REQUIRE_CERTIFICATE;
+}
+
+bool ServerConfig::EnableDeflate() { return config_ & CONFIG_ENABLE_DEFLATE; }
+
+bool ServerConfig::EnableCbcRandomIv() {
+ return config_ & CONFIG_ENABLE_CBC_RANDOM_IV;
+}
+
+bool ServerConfig::RequireSafeNegotiation() {
+ return config_ & CONFIG_REQUIRE_SAFE_NEGOTIATION;
+}
+
+bool ServerConfig::EnableCache() { return config_ & CONFIG_ENABLE_CACHE; }
diff --git a/nss/fuzz/tls_server_config.h b/nss/fuzz/tls_server_config.h
new file mode 100644
index 0000000..bed8b49
--- /dev/null
+++ b/nss/fuzz/tls_server_config.h
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef tls_server_config_h__
+#define tls_server_config_h__
+
+#include <stdint.h>
+#include <cstddef>
+
+class ServerConfig {
+ public:
+ ServerConfig(const uint8_t* data, size_t len);
+
+ bool EnableExtendedMasterSecret();
+ bool RequestCertificate();
+ bool RequireCertificate();
+ bool EnableDeflate();
+ bool EnableCbcRandomIv();
+ bool RequireSafeNegotiation();
+ bool EnableCache();
+
+ private:
+ uint64_t config_;
+};
+
+#endif // tls_server_config_h__
diff --git a/nss/fuzz/tls_server_target.cc b/nss/fuzz/tls_server_target.cc
new file mode 100644
index 0000000..0c09020
--- /dev/null
+++ b/nss/fuzz/tls_server_target.cc
@@ -0,0 +1,141 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <assert.h>
+#include <stdint.h>
+#include <memory>
+
+#include "blapi.h"
+#include "prinit.h"
+#include "ssl.h"
+
+#include "shared.h"
+#include "tls_common.h"
+#include "tls_mutators.h"
+#include "tls_server_certs.h"
+#include "tls_server_config.h"
+#include "tls_socket.h"
+
+#ifdef IS_DTLS
+__attribute__((constructor)) static void set_is_dtls() {
+ TlsMutators::SetIsDTLS();
+}
+#endif
+
+PRFileDesc* ImportFD(PRFileDesc* model, PRFileDesc* fd) {
+#ifdef IS_DTLS
+ return DTLS_ImportFD(model, fd);
+#else
+ return SSL_ImportFD(model, fd);
+#endif
+}
+
+class SSLServerSessionCache {
+ public:
+ SSLServerSessionCache() {
+ assert(SSL_ConfigServerSessionIDCache(1024, 0, 0, ".") == SECSuccess);
+ }
+
+ ~SSLServerSessionCache() {
+ assert(SSL_ShutdownServerSessionIDCache() == SECSuccess);
+ }
+};
+
+static void SetSocketOptions(PRFileDesc* fd,
+ std::unique_ptr<ServerConfig>& config) {
+ SECStatus rv = SSL_OptionSet(fd, SSL_NO_CACHE, config->EnableCache());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_REUSE_SERVER_ECDHE_KEY, false);
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_ENABLE_EXTENDED_MASTER_SECRET,
+ config->EnableExtendedMasterSecret());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_REQUEST_CERTIFICATE, config->RequestCertificate());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_REQUIRE_CERTIFICATE, config->RequireCertificate());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_ENABLE_DEFLATE, config->EnableDeflate());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_CBC_RANDOM_IV, config->EnableCbcRandomIv());
+ assert(rv == SECSuccess);
+
+ rv = SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION,
+ config->RequireSafeNegotiation());
+ assert(rv == SECSuccess);
+
+#ifndef IS_DTLS
+ rv =
+ SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED);
+ assert(rv == SECSuccess);
+#endif
+}
+
+static PRStatus InitModelSocket(void* arg) {
+ PRFileDesc* fd = reinterpret_cast<PRFileDesc*>(arg);
+
+ EnableAllProtocolVersions();
+ EnableAllCipherSuites(fd);
+ InstallServerCertificates(fd);
+
+ return PR_SUCCESS;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
+ static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
+ assert(db != nullptr);
+
+ static std::unique_ptr<SSLServerSessionCache> cache(
+ new SSLServerSessionCache());
+ assert(cache != nullptr);
+
+ std::unique_ptr<ServerConfig> config(new ServerConfig(data, len));
+
+ // Clear the cache. We never want to resume as we couldn't reproduce that.
+ SSL_ClearSessionCache();
+
+ // Reset the RNG state.
+ assert(RNG_RandomUpdate(NULL, 0) == SECSuccess);
+
+ // Create model socket.
+ static ScopedPRFileDesc model(ImportFD(nullptr, PR_NewTCPSocket()));
+ assert(model);
+
+ // Initialize the model socket once.
+ static PRCallOnceType initModelOnce;
+ PR_CallOnceWithArg(&initModelOnce, InitModelSocket, model.get());
+
+ // Create and import dummy socket.
+ std::unique_ptr<DummyPrSocket> socket(new DummyPrSocket(data, len));
+ static PRDescIdentity id = PR_GetUniqueIdentity("fuzz-server");
+ ScopedPRFileDesc fd(DummyIOLayerMethods::CreateFD(id, socket.get()));
+ PRFileDesc* ssl_fd = ImportFD(model.get(), fd.get());
+ assert(ssl_fd == fd.get());
+
+ SetSocketOptions(ssl_fd, config);
+ DoHandshake(ssl_fd, true);
+
+ return 0;
+}
+
+extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
+ size_t max_size, unsigned int seed) {
+ using namespace TlsMutators;
+ return CustomMutate({DropRecord, ShuffleRecords, DuplicateRecord,
+ TruncateRecord, FragmentRecord},
+ data, size, max_size, seed);
+}
+
+extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t* data1, size_t size1,
+ const uint8_t* data2, size_t size2,
+ uint8_t* out, size_t max_out_size,
+ unsigned int seed) {
+ return TlsMutators::CrossOver(data1, size1, data2, size2, out, max_out_size,
+ seed);
+}
diff --git a/nss/fuzz/tls_socket.cc b/nss/fuzz/tls_socket.cc
new file mode 100644
index 0000000..05aed34
--- /dev/null
+++ b/nss/fuzz/tls_socket.cc
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <assert.h>
+#include <string.h>
+#include <algorithm>
+
+#include "prerror.h"
+#include "prio.h"
+
+#include "tls_socket.h"
+
+int32_t DummyPrSocket::Read(PRFileDesc *f, void *data, int32_t len) {
+ assert(data && len > 0);
+
+ int32_t amount = std::min(len, static_cast<int32_t>(len_));
+ memcpy(data, buf_, amount);
+
+ buf_ += amount;
+ len_ -= amount;
+
+ return amount;
+}
+
+int32_t DummyPrSocket::Write(PRFileDesc *f, const void *buf, int32_t length) {
+ return length;
+}
+
+int32_t DummyPrSocket::Recv(PRFileDesc *f, void *buf, int32_t buflen,
+ int32_t flags, PRIntervalTime to) {
+ assert(flags == 0);
+ return Read(f, buf, buflen);
+}
diff --git a/nss/fuzz/tls_socket.h b/nss/fuzz/tls_socket.h
new file mode 100644
index 0000000..61fa4b3
--- /dev/null
+++ b/nss/fuzz/tls_socket.h
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef tls_socket_h__
+#define tls_socket_h__
+
+#include "dummy_io.h"
+
+class DummyPrSocket : public DummyIOLayerMethods {
+ public:
+ DummyPrSocket(const uint8_t *buf, size_t len) : buf_(buf), len_(len) {}
+
+ int32_t Read(PRFileDesc *f, void *data, int32_t len) override;
+ int32_t Write(PRFileDesc *f, const void *buf, int32_t length) override;
+ int32_t Recv(PRFileDesc *f, void *buf, int32_t buflen, int32_t flags,
+ PRIntervalTime to) override;
+
+ private:
+ const uint8_t *buf_;
+ size_t len_;
+};
+
+#endif // tls_socket_h__
diff --git a/nss/fuzz/warning.txt b/nss/fuzz/warning.txt
index 2c83d7e..fdfa90e 100644
--- a/nss/fuzz/warning.txt
+++ b/nss/fuzz/warning.txt
@@ -1,15 +1,16 @@
-##############################################
-## ##
-## WARNING: You're building with -Dfuzz=1 ##
-## ##
-## This means: ##
-## ##
-## * Your PRNG is DETERMINISTIC. ##
-## * TLS transcripts are PLAINTEXT. ##
-## * TLS signature checks are DISABLED. ##
-## ##
-## Thank you for fuzzing! ##
-## ##
-##############################################
+##################################################
+## ##
+## WARNING: You're building with -Dfuzz_tls=1 ##
+## ##
+## This means: ##
+## ##
+## * Your PRNG is DETERMINISTIC. ##
+## * TLS transcripts are PLAINTEXT. ##
+## * Session tickets are NOT encrypted. ##
+## * TLS signature/MAC checks are DISABLED. ##
+## ##
+## Thank you for fuzzing! ##
+## ##
+##################################################