summaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
authorTim Taubert <ttaubert@mozilla.com>2017-02-10 16:23:22 +0100
committerTim Taubert <ttaubert@mozilla.com>2017-02-10 16:23:22 +0100
commitff78450919bdcbc3444ca02642b45d24859ea7ff (patch)
tree4b847121aa2fce01604e7a3fb30b63851c1c2f72 /fuzz
parent2df7bf838163ff4bd104dc77f6cd375579decd27 (diff)
downloadnss-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.gyp18
-rw-r--r--fuzz/tls-client.options3
-rw-r--r--fuzz/tls_client_socket.cc34
-rw-r--r--fuzz/tls_client_socket.h24
-rw-r--r--fuzz/tls_client_target.cc113
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;
+}