diff options
author | Tim Taubert <ttaubert@mozilla.com> | 2017-02-10 16:23:22 +0100 |
---|---|---|
committer | Tim Taubert <ttaubert@mozilla.com> | 2017-02-10 16:23:22 +0100 |
commit | ff78450919bdcbc3444ca02642b45d24859ea7ff (patch) | |
tree | 4b847121aa2fce01604e7a3fb30b63851c1c2f72 /fuzz | |
parent | 2df7bf838163ff4bd104dc77f6cd375579decd27 (diff) | |
download | nss-hg-ff78450919bdcbc3444ca02642b45d24859ea7ff.tar.gz |
Bug 1330557 - Add basic TLS client fuzzer r=mt,franziskus
Differential Revision: https://nss-review.dev.mozaws.net/D145
Diffstat (limited to 'fuzz')
-rw-r--r-- | fuzz/fuzz.gyp | 18 | ||||
-rw-r--r-- | fuzz/tls-client.options | 3 | ||||
-rw-r--r-- | fuzz/tls_client_socket.cc | 34 | ||||
-rw-r--r-- | fuzz/tls_client_socket.h | 24 | ||||
-rw-r--r-- | fuzz/tls_client_target.cc | 113 |
5 files changed, 192 insertions, 0 deletions
diff --git a/fuzz/fuzz.gyp b/fuzz/fuzz.gyp index 9272c9dbb..9e0444100 100644 --- a/fuzz/fuzz.gyp +++ b/fuzz/fuzz.gyp @@ -29,6 +29,7 @@ '<(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', @@ -244,6 +245,22 @@ ], }, { + 'target_name': 'nssfuzz-tls-client', + 'type': 'executable', + 'sources': [ + 'tls_client_socket.cc', + 'tls_client_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/cpputil/cpputil.gyp:cpputil', + '<(DEPTH)/exports.gyp:nss_exports', + 'fuzz_base', + ], + 'include_dirs': [ + '<(DEPTH)/lib/freebl', + ], + }, + { 'target_name': 'nssfuzz', 'type': 'none', 'dependencies': [ @@ -251,6 +268,7 @@ 'nssfuzz-hash', 'nssfuzz-pkcs8', 'nssfuzz-quickder', + 'nssfuzz-tls-client', ], 'conditions': [ ['OS=="linux"', { diff --git a/fuzz/tls-client.options b/fuzz/tls-client.options new file mode 100644 index 000000000..8b017d2ce --- /dev/null +++ b/fuzz/tls-client.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 20000 + diff --git a/fuzz/tls_client_socket.cc b/fuzz/tls_client_socket.cc new file mode 100644 index 000000000..b5256a001 --- /dev/null +++ b/fuzz/tls_client_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_client_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/fuzz/tls_client_socket.h b/fuzz/tls_client_socket.h new file mode 100644 index 000000000..c9dc9ba34 --- /dev/null +++ b/fuzz/tls_client_socket.h @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef tls_client_socket_h__ +#define tls_client_socket_h__ + +#include "dummy_io.h" + +class DummyPrSocket : public DummyIOLayerMethods { + public: + DummyPrSocket(const uint8_t *buf, size_t len) : buf_(buf), len_(len) {} + + int32_t Read(PRFileDesc *f, void *data, int32_t len) override; + int32_t Write(PRFileDesc *f, const void *buf, int32_t length) override; + int32_t Recv(PRFileDesc *f, void *buf, int32_t buflen, int32_t flags, + PRIntervalTime to) override; + + private: + const uint8_t *buf_; + size_t len_; +}; + +#endif // tls_client_socket_h__ diff --git a/fuzz/tls_client_target.cc b/fuzz/tls_client_target.cc new file mode 100644 index 000000000..4d8ed9ee9 --- /dev/null +++ b/fuzz/tls_client_target.cc @@ -0,0 +1,113 @@ +/* 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_socket.h" + +static 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; +} + +static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checksig, + PRBool isServer) { + return SECSuccess; +} + +static void SetSocketOptions(PRFileDesc* fd) { + // Disable session cache for now. + SECStatus rv = SSL_OptionSet(fd, SSL_NO_CACHE, true); + assert(rv == SECSuccess); + + rv = SSL_OptionSet(fd, SSL_ENABLE_EXTENDED_MASTER_SECRET, true); + assert(rv == SECSuccess); + + rv = SSL_OptionSet(fd, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, true); + assert(rv == SECSuccess); + + rv = SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true); + assert(rv == SECSuccess); + + rv = SSL_OptionSet(fd, SSL_ENABLE_ALPN, true); + assert(rv == SECSuccess); + + rv = + SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED); + assert(rv == SECSuccess); +} + +static 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); + } +} + +static void SetupAuthCertificateHook(PRFileDesc* fd) { + SECStatus rv = SSL_AuthCertificateHook(fd, AuthCertificateHook, nullptr); + assert(rv == SECSuccess); +} + +static void DoHandshake(PRFileDesc* fd) { + SECStatus rv = SSL_ResetHandshake(fd, false /* asServer */); + 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); + } + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) { + static std::unique_ptr<NSSDatabase> db(new NSSDatabase()); + assert(db != nullptr); + + EnableAllProtocolVersions(); + + // Reset the RNG state. + SECStatus rv = RNG_ResetForFuzzing(); + assert(rv == 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 = SSL_ImportFD(nullptr, fd.get()); + assert(ssl_fd == fd.get()); + + // Probably not too important for clients. + SSL_SetURL(ssl_fd, "server"); + + SetSocketOptions(ssl_fd); + EnableAllCipherSuites(ssl_fd); + SetupAuthCertificateHook(ssl_fd); + DoHandshake(ssl_fd); + + return 0; +} |