summaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
authorTim Taubert <ttaubert@mozilla.com>2017-03-31 16:32:54 +0200
committerTim Taubert <ttaubert@mozilla.com>2017-03-31 16:32:54 +0200
commita1d6082c30f4bfea3f08a1c698a3e39adfd2f94a (patch)
tree5ea43964710e494b3f9f45b2da86b8bdf5234695 /fuzz
parent6f031f8434c7a2406a69d972e1414caa23e08ad4 (diff)
downloadnss-hg-a1d6082c30f4bfea3f08a1c698a3e39adfd2f94a.tar.gz
Bug 1351600 - Add DTLS client and server fuzzers r=franziskus
Differential Revision: https://nss-review.dev.mozaws.net/D282
Diffstat (limited to 'fuzz')
-rw-r--r--fuzz/fuzz.gyp35
-rw-r--r--fuzz/options/dtls-client-no_fuzzer_mode.options3
-rw-r--r--fuzz/options/dtls-client.options3
-rw-r--r--fuzz/options/dtls-server-no_fuzzer_mode.options3
-rw-r--r--fuzz/options/dtls-server.options3
-rw-r--r--fuzz/tls_client_target.cc27
-rw-r--r--fuzz/tls_mutators.cc65
-rw-r--r--fuzz/tls_mutators.h32
-rw-r--r--fuzz/tls_server_target.cc29
9 files changed, 150 insertions, 50 deletions
diff --git a/fuzz/fuzz.gyp b/fuzz/fuzz.gyp
index da52d6e37..a7339b78c 100644
--- a/fuzz/fuzz.gyp
+++ b/fuzz/fuzz.gyp
@@ -301,10 +301,45 @@
],
},
{
+ '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',
diff --git a/fuzz/options/dtls-client-no_fuzzer_mode.options b/fuzz/options/dtls-client-no_fuzzer_mode.options
new file mode 100644
index 000000000..8b017d2ce
--- /dev/null
+++ b/fuzz/options/dtls-client-no_fuzzer_mode.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/fuzz/options/dtls-client.options b/fuzz/options/dtls-client.options
new file mode 100644
index 000000000..8b017d2ce
--- /dev/null
+++ b/fuzz/options/dtls-client.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/fuzz/options/dtls-server-no_fuzzer_mode.options b/fuzz/options/dtls-server-no_fuzzer_mode.options
new file mode 100644
index 000000000..8b017d2ce
--- /dev/null
+++ b/fuzz/options/dtls-server-no_fuzzer_mode.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/fuzz/options/dtls-server.options b/fuzz/options/dtls-server.options
new file mode 100644
index 000000000..8b017d2ce
--- /dev/null
+++ b/fuzz/options/dtls-server.options
@@ -0,0 +1,3 @@
+[libfuzzer]
+max_len = 20000
+
diff --git a/fuzz/tls_client_target.cc b/fuzz/tls_client_target.cc
index 82e4a5dfb..e59550984 100644
--- a/fuzz/tls_client_target.cc
+++ b/fuzz/tls_client_target.cc
@@ -16,6 +16,20 @@
#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);
@@ -49,9 +63,11 @@ static void SetSocketOptions(PRFileDesc* fd,
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,
@@ -87,7 +103,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
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());
+ PRFileDesc* ssl_fd = ImportFD(nullptr, fd.get());
assert(ssl_fd == fd.get());
// Probably not too important for clients.
@@ -103,9 +119,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
size_t max_size, unsigned int seed) {
- return CustomMutate({TlsMutatorDropRecord, TlsMutatorShuffleRecords,
- TlsMutatorDuplicateRecord, TlsMutatorTruncateRecord,
- TlsMutatorFragmentRecord},
+ using namespace TlsMutators;
+ return CustomMutate({DropRecord, ShuffleRecords, DuplicateRecord,
+ TruncateRecord, FragmentRecord},
data, size, max_size, seed);
}
@@ -113,5 +129,6 @@ 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 TlsCrossOver(data1, size1, data2, size2, out, max_out_size, seed);
+ return TlsMutators::CrossOver(data1, size1, data2, size2, out, max_out_size,
+ seed);
}
diff --git a/fuzz/tls_mutators.cc b/fuzz/tls_mutators.cc
index ccf1935bf..e9770cb39 100644
--- a/fuzz/tls_mutators.cc
+++ b/fuzz/tls_mutators.cc
@@ -10,6 +10,10 @@
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:
@@ -33,9 +37,9 @@ class Record {
}
void truncate(size_t length) {
- assert(length >= 5);
+ assert(length >= 5 + gExtraHeaderBytes);
uint8_t *dest = const_cast<uint8_t *>(data_);
- (void)ssl_EncodeUintX(length - 5, 2, &dest[3]);
+ (void)ssl_EncodeUintX(length - 5 - gExtraHeaderBytes, 2, &dest[3]);
memmove(dest + length, data_ + size_, remaining_);
}
@@ -66,13 +70,8 @@ std::vector<std::unique_ptr<Record>> ParseRecords(const uint8_t *data,
while (parser.remaining()) {
size_t offset = parser.consumed();
- uint32_t type;
- if (!parser.Read(&type, 1)) {
- break;
- }
-
- uint32_t version;
- if (!parser.Read(&version, 2)) {
+ // Skip type, version, and DTLS seqnums.
+ if (!parser.Skip(3 + gExtraHeaderBytes)) {
break;
}
@@ -81,16 +80,22 @@ std::vector<std::unique_ptr<Record>> ParseRecords(const uint8_t *data,
break;
}
- records.push_back(
- Record::Create(data + offset, fragment.len() + 5, parser.remaining()));
+ 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 TlsMutatorDropRecord(uint8_t *data, size_t size, size_t max_size,
- unsigned int seed) {
+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.
@@ -111,8 +116,8 @@ size_t TlsMutatorDropRecord(uint8_t *data, size_t size, size_t max_size,
}
// Mutator that shuffles TLS records in a transcript.
-size_t TlsMutatorShuffleRecords(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) {
std::mt19937 rng(seed);
// Store the original corpus.
@@ -142,8 +147,8 @@ size_t TlsMutatorShuffleRecords(uint8_t *data, size_t size, size_t max_size,
}
// Mutator that duplicates a single TLS record and randomly inserts it.
-size_t TlsMutatorDuplicateRecord(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) {
std::mt19937 rng(seed);
// Find TLS records in the corpus.
@@ -167,8 +172,8 @@ size_t TlsMutatorDuplicateRecord(uint8_t *data, size_t size, size_t max_size,
}
// Mutator that truncates a TLS record.
-size_t TlsMutatorTruncateRecord(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) {
std::mt19937 rng(seed);
// Find TLS records in the corpus.
@@ -182,12 +187,13 @@ size_t TlsMutatorTruncateRecord(uint8_t *data, size_t size, size_t max_size,
auto &rec = records.at(dist(rng));
// Need a record with data.
- if (rec->size() <= 5) {
+ if (rec->size() <= 5 + gExtraHeaderBytes) {
return 0;
}
// Truncate.
- std::uniform_int_distribution<size_t> dist2(5, rec->size() - 1);
+ std::uniform_int_distribution<size_t> dist2(5 + gExtraHeaderBytes,
+ rec->size() - 1);
size_t new_length = dist2(rng);
rec->truncate(new_length);
@@ -196,10 +202,15 @@ size_t TlsMutatorTruncateRecord(uint8_t *data, size_t size, size_t max_size,
}
// Mutator that splits a TLS record in two.
-size_t TlsMutatorFragmentRecord(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) {
std::mt19937 rng(seed);
+ // We can't deal with DTLS yet.
+ if (gExtraHeaderBytes > 0) {
+ return 0;
+ }
+
if (size + 5 > max_size) {
return 0;
}
@@ -238,9 +249,9 @@ size_t TlsMutatorFragmentRecord(uint8_t *data, size_t size, size_t max_size,
}
// Cross-over function that merges and shuffles two transcripts.
-size_t TlsCrossOver(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) {
+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.
@@ -274,3 +285,5 @@ size_t TlsCrossOver(const uint8_t *data1, size_t size1, const uint8_t *data2,
return total;
}
+
+} // namespace TlsMutators
diff --git a/fuzz/tls_mutators.h b/fuzz/tls_mutators.h
index 48429626f..03a214751 100644
--- a/fuzz/tls_mutators.h
+++ b/fuzz/tls_mutators.h
@@ -5,19 +5,25 @@
#ifndef tls_mutators_h__
#define tls_mutators_h__
-size_t TlsMutatorDropRecord(uint8_t *data, size_t size, size_t max_size,
- unsigned int seed);
-size_t TlsMutatorShuffleRecords(uint8_t *data, size_t size, size_t max_size,
- unsigned int seed);
-size_t TlsMutatorDuplicateRecord(uint8_t *data, size_t size, size_t max_size,
- unsigned int seed);
-size_t TlsMutatorTruncateRecord(uint8_t *data, size_t size, size_t max_size,
- unsigned int seed);
-size_t TlsMutatorFragmentRecord(uint8_t *data, size_t size, size_t max_size,
- unsigned int seed);
+namespace TlsMutators {
-size_t TlsCrossOver(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);
+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/fuzz/tls_server_target.cc b/fuzz/tls_server_target.cc
index 67193368f..0c0902077 100644
--- a/fuzz/tls_server_target.cc
+++ b/fuzz/tls_server_target.cc
@@ -17,6 +17,20 @@
#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() {
@@ -56,9 +70,11 @@ static void SetSocketOptions(PRFileDesc* fd,
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) {
@@ -88,7 +104,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
assert(RNG_RandomUpdate(NULL, 0) == SECSuccess);
// Create model socket.
- static ScopedPRFileDesc model(SSL_ImportFD(nullptr, PR_NewTCPSocket()));
+ static ScopedPRFileDesc model(ImportFD(nullptr, PR_NewTCPSocket()));
assert(model);
// Initialize the model socket once.
@@ -99,7 +115,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
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 = SSL_ImportFD(model.get(), fd.get());
+ PRFileDesc* ssl_fd = ImportFD(model.get(), fd.get());
assert(ssl_fd == fd.get());
SetSocketOptions(ssl_fd, config);
@@ -110,9 +126,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
size_t max_size, unsigned int seed) {
- return CustomMutate({TlsMutatorDropRecord, TlsMutatorShuffleRecords,
- TlsMutatorDuplicateRecord, TlsMutatorTruncateRecord,
- TlsMutatorFragmentRecord},
+ using namespace TlsMutators;
+ return CustomMutate({DropRecord, ShuffleRecords, DuplicateRecord,
+ TruncateRecord, FragmentRecord},
data, size, max_size, seed);
}
@@ -120,5 +136,6 @@ 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 TlsCrossOver(data1, size1, data2, size2, out, max_out_size, seed);
+ return TlsMutators::CrossOver(data1, size1, data2, size2, out, max_out_size,
+ seed);
}