diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/nss/fuzz | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/fuzz')
60 files changed, 2651 insertions, 0 deletions
diff --git a/security/nss/fuzz/.clang-format b/security/nss/fuzz/.clang-format new file mode 100644 index 0000000000..06e3c5115f --- /dev/null +++ b/security/nss/fuzz/.clang-format @@ -0,0 +1,4 @@ +--- +Language: Cpp +BasedOnStyle: Google +... diff --git a/security/nss/fuzz/asn1_mutators.cc b/security/nss/fuzz/asn1_mutators.cc new file mode 100644 index 0000000000..12d8c37283 --- /dev/null +++ b/security/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/security/nss/fuzz/asn1_mutators.h b/security/nss/fuzz/asn1_mutators.h new file mode 100644 index 0000000000..8bf02d49f5 --- /dev/null +++ b/security/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/security/nss/fuzz/certDN_target.cc b/security/nss/fuzz/certDN_target.cc new file mode 100644 index 0000000000..264880ac15 --- /dev/null +++ b/security/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/security/nss/fuzz/config/clone_corpus.sh b/security/nss/fuzz/config/clone_corpus.sh new file mode 100755 index 0000000000..856f63d95a --- /dev/null +++ b/security/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/security/nss/fuzz/config/git-copy.sh b/security/nss/fuzz/config/git-copy.sh new file mode 100755 index 0000000000..fac8cbecf4 --- /dev/null +++ b/security/nss/fuzz/config/git-copy.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +set -ex + +if [ $# -lt 3 ]; then + echo "Usage: $0 <repo> <branch> <directory>" 1>&2 + exit 2 +fi + +REPO="$1" +COMMIT="$2" +DIR="$3" + +echo "Copy '$COMMIT' from '$REPO' to '$DIR'" +if [ -f "$DIR"/.git-copy ]; then + CURRENT=$(cat "$DIR"/.git-copy) + if [ $(echo -n "$COMMIT" | wc -c) != "40" ]; then + # On the off chance that $COMMIT is a remote head. + ACTUAL=$(git ls-remote "$REPO" "$COMMIT" | cut -c 1-40 -) + else + ACTUAL="$COMMIT" + fi + if [ "$CURRENT" = "$ACTUAL" ]; then + echo "Up to date." + exit + fi +fi + +rm -rf "$DIR" +git init -q "$DIR" +git -C "$DIR" fetch -q --depth=1 "$REPO" "$COMMIT" +git -C "$DIR" reset -q --hard FETCH_HEAD +git -C "$DIR" rev-parse --verify HEAD > "$DIR"/.git-copy +rm -rf "$DIR"/.git diff --git a/security/nss/fuzz/fuzz.gyp b/security/nss/fuzz/fuzz.gyp new file mode 100644 index 0000000000..46a114ddf6 --- /dev/null +++ b/security/nss/fuzz/fuzz.gyp @@ -0,0 +1,374 @@ +# 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/. +{ + 'includes': [ + '../coreconf/config.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': 'fuzz_base', + 'type': 'static_library', + 'sources': [ + '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', + '<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix', + ], + 'cflags_cc': [ + '-Wno-error=shadow', + ], + 'conditions': [ + ['fuzz_oss==0', { + 'all_dependent_settings': { + 'libraries': [ + '-fsanitize=fuzzer', + ], + } + }, { + '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 static 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-pkcs8', + 'type': 'executable', + 'sources': [ + 'asn1_mutators.cc', + 'pkcs8_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + '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', + ], + }], + ], + } + ], +} diff --git a/security/nss/fuzz/mpi_add_target.cc b/security/nss/fuzz/mpi_add_target.cc new file mode 100644 index 0000000000..3ebad370d0 --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_addmod_target.cc b/security/nss/fuzz/mpi_addmod_target.cc new file mode 100644 index 0000000000..a7802b62e2 --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_div_target.cc b/security/nss/fuzz/mpi_div_target.cc new file mode 100644 index 0000000000..08c714ee68 --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_expmod_target.cc b/security/nss/fuzz/mpi_expmod_target.cc new file mode 100644 index 0000000000..b9be5854fb --- /dev/null +++ b/security/nss/fuzz/mpi_expmod_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 + + auto modulus = get_modulus(data, size, ctx); + // Compare with OpenSSL exp mod + m1 = &std::get<1>(modulus); + // The exponent b (B) can get really big. Make it smaller if necessary. + if (MP_USED(&b) > 100) { + size_t shift = (MP_USED(&b) - 100) * MP_DIGIT_BIT; + mp_div_2d(&b, shift, &b, nullptr); + BN_rshift(B, B, shift); + } + check_equal(A, &a, max_size); + check_equal(B, &b, max_size); + check_equal(std::get<0>(modulus), m1, 3 * max_size); + 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/security/nss/fuzz/mpi_helper.cc b/security/nss/fuzz/mpi_helper.cc new file mode 100644 index 0000000000..d092fdb119 --- /dev/null +++ b/security/nss/fuzz/mpi_helper.cc @@ -0,0 +1,106 @@ +/* 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)); +} + +void print_bn(std::string label, BIGNUM *x) { + char *xc = BN_bn2hex(x); + std::cout << label << ": " << std::hex << xc << std::endl; + OPENSSL_free(xc); +} + +// 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/security/nss/fuzz/mpi_helper.h b/security/nss/fuzz/mpi_helper.h new file mode 100644 index 0000000000..ef7041b257 --- /dev/null +++ b/security/nss/fuzz/mpi_helper.h @@ -0,0 +1,87 @@ +/* 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); +void print_bn(std::string label, BIGNUM *x); + +// 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/security/nss/fuzz/mpi_invmod_target.cc b/security/nss/fuzz/mpi_invmod_target.cc new file mode 100644 index 0000000000..6480d5437e --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_mod_target.cc b/security/nss/fuzz/mpi_mod_target.cc new file mode 100644 index 0000000000..85c883faff --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_mulmod_target.cc b/security/nss/fuzz/mpi_mulmod_target.cc new file mode 100644 index 0000000000..75585e2d76 --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_sqr_target.cc b/security/nss/fuzz/mpi_sqr_target.cc new file mode 100644 index 0000000000..b404d624c9 --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_sqrmod_target.cc b/security/nss/fuzz/mpi_sqrmod_target.cc new file mode 100644 index 0000000000..ca403b5706 --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_sub_target.cc b/security/nss/fuzz/mpi_sub_target.cc new file mode 100644 index 0000000000..da20d74dab --- /dev/null +++ b/security/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/security/nss/fuzz/mpi_submod_target.cc b/security/nss/fuzz/mpi_submod_target.cc new file mode 100644 index 0000000000..26b2c5323d --- /dev/null +++ b/security/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/security/nss/fuzz/options/certDN.options b/security/nss/fuzz/options/certDN.options new file mode 100644 index 0000000000..635be52a51 --- /dev/null +++ b/security/nss/fuzz/options/certDN.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 4096 + diff --git a/security/nss/fuzz/options/dtls-client-no_fuzzer_mode.options b/security/nss/fuzz/options/dtls-client-no_fuzzer_mode.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/dtls-client-no_fuzzer_mode.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/options/dtls-client.options b/security/nss/fuzz/options/dtls-client.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/dtls-client.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/options/dtls-server-no_fuzzer_mode.options b/security/nss/fuzz/options/dtls-server-no_fuzzer_mode.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/dtls-server-no_fuzzer_mode.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/options/dtls-server.options b/security/nss/fuzz/options/dtls-server.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/dtls-server.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/options/mpi-add.options b/security/nss/fuzz/options/mpi-add.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-add.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-addmod.options b/security/nss/fuzz/options/mpi-addmod.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-addmod.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-div.options b/security/nss/fuzz/options/mpi-div.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-div.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-expmod.options b/security/nss/fuzz/options/mpi-expmod.options new file mode 100644 index 0000000000..98fcc343a9 --- /dev/null +++ b/security/nss/fuzz/options/mpi-expmod.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 1024 + diff --git a/security/nss/fuzz/options/mpi-invmod.options b/security/nss/fuzz/options/mpi-invmod.options new file mode 100644 index 0000000000..a38c2fe331 --- /dev/null +++ b/security/nss/fuzz/options/mpi-invmod.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 256 diff --git a/security/nss/fuzz/options/mpi-mod.options b/security/nss/fuzz/options/mpi-mod.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-mod.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-mulmod.options b/security/nss/fuzz/options/mpi-mulmod.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-mulmod.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-sqr.options b/security/nss/fuzz/options/mpi-sqr.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-sqr.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-sqrmod.options b/security/nss/fuzz/options/mpi-sqrmod.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-sqrmod.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-sub.options b/security/nss/fuzz/options/mpi-sub.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-sub.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/mpi-submod.options b/security/nss/fuzz/options/mpi-submod.options new file mode 100644 index 0000000000..fd32ac16e1 --- /dev/null +++ b/security/nss/fuzz/options/mpi-submod.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 2048 + diff --git a/security/nss/fuzz/options/quickder.options b/security/nss/fuzz/options/quickder.options new file mode 100644 index 0000000000..369977dc4a --- /dev/null +++ b/security/nss/fuzz/options/quickder.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 10000 + diff --git a/security/nss/fuzz/options/tls-client-no_fuzzer_mode.options b/security/nss/fuzz/options/tls-client-no_fuzzer_mode.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/tls-client-no_fuzzer_mode.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/options/tls-client.options b/security/nss/fuzz/options/tls-client.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/tls-client.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/options/tls-server-no_fuzzer_mode.options b/security/nss/fuzz/options/tls-server-no_fuzzer_mode.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/tls-server-no_fuzzer_mode.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/options/tls-server.options b/security/nss/fuzz/options/tls-server.options new file mode 100644 index 0000000000..8b017d2ce6 --- /dev/null +++ b/security/nss/fuzz/options/tls-server.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/security/nss/fuzz/pkcs8_target.cc b/security/nss/fuzz/pkcs8_target.cc new file mode 100644 index 0000000000..6ce6f6d043 --- /dev/null +++ b/security/nss/fuzz/pkcs8_target.cc @@ -0,0 +1,39 @@ +/* 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 <memory> +#include <vector> + +#include "keyhi.h" +#include "pk11pub.h" + +#include "asn1_mutators.h" +#include "shared.h" + +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()); + assert(db != nullptr); + + PK11SlotInfo *slot = PK11_GetInternalSlot(); + assert(slot != nullptr); + + SECKEYPrivateKey *key = nullptr; + if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &data, nullptr, nullptr, + false, false, KU_ALL, &key, + nullptr) == SECSuccess) { + SECKEY_DestroyPrivateKey(key); + } + + PK11_FreeSlot(slot); + 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/security/nss/fuzz/quickder_target.cc b/security/nss/fuzz/quickder_target.cc new file mode 100644 index 0000000000..e24627590b --- /dev/null +++ b/security/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/security/nss/fuzz/shared.cc b/security/nss/fuzz/shared.cc new file mode 100644 index 0000000000..47fb21638d --- /dev/null +++ b/security/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/security/nss/fuzz/shared.h b/security/nss/fuzz/shared.h new file mode 100644 index 0000000000..35621eb9de --- /dev/null +++ b/security/nss/fuzz/shared.h @@ -0,0 +1,30 @@ +/* -*- 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 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() { 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/security/nss/fuzz/tls_client_config.cc b/security/nss/fuzz/tls_client_config.cc new file mode 100644 index 0000000000..81f3f57fe4 --- /dev/null +++ b/security/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/security/nss/fuzz/tls_client_config.h b/security/nss/fuzz/tls_client_config.h new file mode 100644 index 0000000000..4abdc3e87a --- /dev/null +++ b/security/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/security/nss/fuzz/tls_client_target.cc b/security/nss/fuzz/tls_client_target.cc new file mode 100644 index 0000000000..461962c5d3 --- /dev/null +++ b/security/nss/fuzz/tls_client_target.cc @@ -0,0 +1,135 @@ +/* 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) { + std::unique_ptr<NSSDatabase> db(new NSSDatabase()); + assert(db != nullptr); + + EnableAllProtocolVersions(); + std::unique_ptr<ClientConfig> config(new ClientConfig(data, len)); + + // 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"); + + FixTime(ssl_fd); + SetSocketOptions(ssl_fd, config); + EnableAllCipherSuites(ssl_fd); + SetupCallbacks(ssl_fd, config.get()); + DoHandshake(ssl_fd, false); + + // Release all SIDs. + SSL_ClearSessionCache(); + + 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/security/nss/fuzz/tls_common.cc b/security/nss/fuzz/tls_common.cc new file mode 100644 index 0000000000..b00ab26bf6 --- /dev/null +++ b/security/nss/fuzz/tls_common.cc @@ -0,0 +1,57 @@ +/* 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 "sslexp.h" + +#include "tls_common.h" + +static PRTime FixedTime(void*) { return 1234; } + +// Fix the time input, to avoid any time-based variation. +void FixTime(PRFileDesc* fd) { + SECStatus rv = SSL_SetTimeFunc(fd, FixedTime, nullptr); + assert(rv == SECSuccess); +} + +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/security/nss/fuzz/tls_common.h b/security/nss/fuzz/tls_common.h new file mode 100644 index 0000000000..e53acceade --- /dev/null +++ b/security/nss/fuzz/tls_common.h @@ -0,0 +1,15 @@ +/* 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" + +void FixTime(PRFileDesc* fd); +PRStatus EnableAllProtocolVersions(); +void EnableAllCipherSuites(PRFileDesc* fd); +void DoHandshake(PRFileDesc* fd, bool isServer); + +#endif // tls_common_h__ diff --git a/security/nss/fuzz/tls_mutators.cc b/security/nss/fuzz/tls_mutators.cc new file mode 100644 index 0000000000..228bd0bb7a --- /dev/null +++ b/security/nss/fuzz/tls_mutators.cc @@ -0,0 +1,298 @@ +/* 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 <algorithm> +#include "shared.h" +#include "tls_parser.h" + +#include "ssl.h" +extern "C" { +#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_); + size_t l = length - (5 + gExtraHeaderBytes); + dest[3] = (l >> 8) & 0xff; + dest[4] = l & 0xff; + 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> rand_record(0, records.size() - 1); + auto &rec = records.at(rand_record(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. + std::uniform_int_distribution<size_t> rand_size(1, content_length - 1); + size_t first_length = rand_size(rng); + size_t second_length = content_length - first_length; + rdata[3] = (first_length >> 8) & 0xff; + rdata[4] = first_length & 0xff; + uint8_t *second_record = rdata + 5 + first_length; + + // Make room for the header of the second record. + memmove(second_record + 5, second_record, + rec->remaining() + content_length - first_length); + + // Write second header. + memcpy(second_record, rdata, 3); + second_record[3] = (second_length >> 8) & 0xff; + second_record[4] = second_length & 0xff; + + 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/security/nss/fuzz/tls_mutators.h b/security/nss/fuzz/tls_mutators.h new file mode 100644 index 0000000000..03a2147514 --- /dev/null +++ b/security/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/security/nss/fuzz/tls_server_certs.cc b/security/nss/fuzz/tls_server_certs.cc new file mode 100644 index 0000000000..20732a5e0a --- /dev/null +++ b/security/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 "nss_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/security/nss/fuzz/tls_server_certs.h b/security/nss/fuzz/tls_server_certs.h new file mode 100644 index 0000000000..c0db253935 --- /dev/null +++ b/security/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/security/nss/fuzz/tls_server_config.cc b/security/nss/fuzz/tls_server_config.cc new file mode 100644 index 0000000000..fffb27b635 --- /dev/null +++ b/security/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/security/nss/fuzz/tls_server_config.h b/security/nss/fuzz/tls_server_config.h new file mode 100644 index 0000000000..bed8b49e27 --- /dev/null +++ b/security/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/security/nss/fuzz/tls_server_target.cc b/security/nss/fuzz/tls_server_target.cc new file mode 100644 index 0000000000..900214329f --- /dev/null +++ b/security/nss/fuzz/tls_server_target.cc @@ -0,0 +1,139 @@ +/* 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_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()); + + FixTime(ssl_fd); + 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/security/nss/fuzz/tls_socket.cc b/security/nss/fuzz/tls_socket.cc new file mode 100644 index 0000000000..05aed34267 --- /dev/null +++ b/security/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/security/nss/fuzz/tls_socket.h b/security/nss/fuzz/tls_socket.h new file mode 100644 index 0000000000..e30f6fa3ca --- /dev/null +++ b/security/nss/fuzz/tls_socket.h @@ -0,0 +1,25 @@ +/* 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) {} + virtual ~DummyPrSocket() {} + + 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/security/nss/fuzz/warning.txt b/security/nss/fuzz/warning.txt new file mode 100644 index 0000000000..fdfa90e467 --- /dev/null +++ b/security/nss/fuzz/warning.txt @@ -0,0 +1,16 @@ + +################################################## +## ## +## 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! ## +## ## +################################################## + |