2018-01-19 03:59:58 +08:00
|
|
|
/* 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 "blapi.h"
|
|
|
|
|
#include "ssl.h"
|
|
|
|
|
#include "sslimpl.h"
|
|
|
|
|
#include "tls_connect.h"
|
|
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
|
|
namespace nss_test {
|
|
|
|
|
|
|
|
|
|
#ifdef UNSAFE_FUZZER_MODE
|
2018-02-06 11:46:26 +01:00
|
|
|
#define FUZZ_F(c, f) TEST_F(c, Fuzz_##f)
|
|
|
|
|
#define FUZZ_P(c, f) TEST_P(c, Fuzz_##f)
|
|
|
|
|
#else
|
|
|
|
|
#define FUZZ_F(c, f) TEST_F(c, DISABLED_Fuzz_##f)
|
|
|
|
|
#define FUZZ_P(c, f) TEST_P(c, DISABLED_Fuzz_##f)
|
|
|
|
|
#endif
|
2018-01-19 03:59:58 +08:00
|
|
|
|
|
|
|
|
const uint8_t kShortEmptyFinished[8] = {0};
|
|
|
|
|
const uint8_t kLongEmptyFinished[128] = {0};
|
|
|
|
|
|
|
|
|
|
class TlsFuzzTest : public ::testing::Test {};
|
|
|
|
|
|
|
|
|
|
// Record the application data stream.
|
|
|
|
|
class TlsApplicationDataRecorder : public TlsRecordFilter {
|
|
|
|
|
public:
|
|
|
|
|
TlsApplicationDataRecorder() : buffer_() {}
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
2018-01-19 03:59:58 +08:00
|
|
|
const DataBuffer& input,
|
|
|
|
|
DataBuffer* output) {
|
|
|
|
|
if (header.content_type() == kTlsApplicationDataType) {
|
|
|
|
|
buffer_.Append(input);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return KEEP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DataBuffer& buffer() const { return buffer_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
DataBuffer buffer_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Ensure that ssl_Time() returns a constant value.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_F(TlsFuzzTest, SSL_Time_Constant) {
|
2018-04-25 21:33:33 +02:00
|
|
|
PRUint32 now = ssl_Time();
|
2018-01-19 03:59:58 +08:00
|
|
|
PR_Sleep(PR_SecondsToInterval(2));
|
2018-04-25 21:33:33 +02:00
|
|
|
EXPECT_EQ(ssl_Time(), now);
|
2018-01-19 03:59:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that due to the deterministic PRNG we derive
|
|
|
|
|
// the same master secret in two consecutive TLS sessions.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_P(TlsConnectGeneric, DeterministicExporter) {
|
2018-01-19 03:59:58 +08:00
|
|
|
const char kLabel[] = "label";
|
|
|
|
|
std::vector<unsigned char> out1(32), out2(32);
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
// Make sure we have RSA blinding params.
|
|
|
|
|
Connect();
|
|
|
|
|
|
|
|
|
|
Reset();
|
2018-01-19 03:59:58 +08:00
|
|
|
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
|
|
|
|
DisableECDHEServerKeyReuse();
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
// Reset the RNG state.
|
|
|
|
|
EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
|
2018-01-19 03:59:58 +08:00
|
|
|
Connect();
|
|
|
|
|
|
|
|
|
|
// Export a key derived from the MS and nonces.
|
|
|
|
|
SECStatus rv =
|
|
|
|
|
SSL_ExportKeyingMaterial(client_->ssl_fd(), kLabel, strlen(kLabel), false,
|
|
|
|
|
NULL, 0, out1.data(), out1.size());
|
|
|
|
|
EXPECT_EQ(SECSuccess, rv);
|
|
|
|
|
|
|
|
|
|
Reset();
|
|
|
|
|
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
|
|
|
|
DisableECDHEServerKeyReuse();
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
// Reset the RNG state.
|
|
|
|
|
EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
|
2018-01-19 03:59:58 +08:00
|
|
|
Connect();
|
|
|
|
|
|
|
|
|
|
// Export another key derived from the MS and nonces.
|
|
|
|
|
rv = SSL_ExportKeyingMaterial(client_->ssl_fd(), kLabel, strlen(kLabel),
|
|
|
|
|
false, NULL, 0, out2.data(), out2.size());
|
|
|
|
|
EXPECT_EQ(SECSuccess, rv);
|
|
|
|
|
|
|
|
|
|
// The two exported keys should be the same.
|
|
|
|
|
EXPECT_EQ(out1, out2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that due to the deterministic RNG two consecutive
|
|
|
|
|
// TLS sessions will have the exact same transcript.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_P(TlsConnectGeneric, DeterministicTranscript) {
|
|
|
|
|
// Make sure we have RSA blinding params.
|
|
|
|
|
Connect();
|
|
|
|
|
|
2018-01-19 03:59:58 +08:00
|
|
|
// Connect a few times and compare the transcripts byte-by-byte.
|
|
|
|
|
DataBuffer last;
|
|
|
|
|
for (size_t i = 0; i < 5; i++) {
|
|
|
|
|
Reset();
|
|
|
|
|
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
|
|
|
|
DisableECDHEServerKeyReuse();
|
|
|
|
|
|
|
|
|
|
DataBuffer buffer;
|
2018-02-06 11:46:26 +01:00
|
|
|
client_->SetPacketFilter(std::make_shared<TlsConversationRecorder>(buffer));
|
|
|
|
|
server_->SetPacketFilter(std::make_shared<TlsConversationRecorder>(buffer));
|
2018-01-19 03:59:58 +08:00
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
// Reset the RNG state.
|
|
|
|
|
EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
|
2018-01-19 03:59:58 +08:00
|
|
|
Connect();
|
|
|
|
|
|
|
|
|
|
// Ensure the filters go away before |buffer| does.
|
2018-02-06 11:46:26 +01:00
|
|
|
client_->DeletePacketFilter();
|
|
|
|
|
server_->DeletePacketFilter();
|
2018-01-19 03:59:58 +08:00
|
|
|
|
|
|
|
|
if (last.len() > 0) {
|
|
|
|
|
EXPECT_EQ(last, buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last = buffer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that we can establish and use a connection
|
|
|
|
|
// with all supported TLS versions, STREAM and DGRAM.
|
|
|
|
|
// Check that records are NOT encrypted.
|
|
|
|
|
// Check that records don't have a MAC.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
|
2018-01-19 03:59:58 +08:00
|
|
|
EnsureTlsSetup();
|
|
|
|
|
|
|
|
|
|
// Set up app data filters.
|
2018-02-06 11:46:26 +01:00
|
|
|
auto client_recorder = std::make_shared<TlsApplicationDataRecorder>();
|
2018-01-19 03:59:58 +08:00
|
|
|
client_->SetPacketFilter(client_recorder);
|
2018-02-06 11:46:26 +01:00
|
|
|
auto server_recorder = std::make_shared<TlsApplicationDataRecorder>();
|
2018-01-19 03:59:58 +08:00
|
|
|
server_->SetPacketFilter(server_recorder);
|
|
|
|
|
|
|
|
|
|
Connect();
|
|
|
|
|
|
|
|
|
|
// Construct the plaintext.
|
|
|
|
|
DataBuffer buf;
|
|
|
|
|
buf.Allocate(50);
|
|
|
|
|
for (size_t i = 0; i < buf.len(); ++i) {
|
|
|
|
|
buf.data()[i] = i & 0xff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send/Receive data.
|
|
|
|
|
client_->SendBuffer(buf);
|
|
|
|
|
server_->SendBuffer(buf);
|
|
|
|
|
Receive(buf.len());
|
|
|
|
|
|
|
|
|
|
// Check for plaintext on the wire.
|
|
|
|
|
EXPECT_EQ(buf, client_recorder->buffer());
|
|
|
|
|
EXPECT_EQ(buf, server_recorder->buffer());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that an invalid Finished message doesn't abort the connection.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
|
2018-01-19 03:59:58 +08:00
|
|
|
EnsureTlsSetup();
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
|
2018-01-19 03:59:58 +08:00
|
|
|
kTlsHandshakeFinished,
|
|
|
|
|
DataBuffer(kShortEmptyFinished, sizeof(kShortEmptyFinished)));
|
|
|
|
|
client_->SetPacketFilter(i1);
|
|
|
|
|
Connect();
|
|
|
|
|
SendReceive();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that an invalid Finished message doesn't abort the connection.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
|
2018-01-19 03:59:58 +08:00
|
|
|
EnsureTlsSetup();
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
|
2018-01-19 03:59:58 +08:00
|
|
|
kTlsHandshakeFinished,
|
|
|
|
|
DataBuffer(kLongEmptyFinished, sizeof(kLongEmptyFinished)));
|
|
|
|
|
server_->SetPacketFilter(i1);
|
|
|
|
|
Connect();
|
|
|
|
|
SendReceive();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that an invalid server auth signature doesn't abort the connection.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
|
2018-01-19 03:59:58 +08:00
|
|
|
EnsureTlsSetup();
|
|
|
|
|
uint8_t msg_type = version_ == SSL_LIBRARY_VERSION_TLS_1_3
|
|
|
|
|
? kTlsHandshakeCertificateVerify
|
|
|
|
|
: kTlsHandshakeServerKeyExchange;
|
2018-02-06 11:46:26 +01:00
|
|
|
server_->SetPacketFilter(std::make_shared<TlsLastByteDamager>(msg_type));
|
2018-01-19 03:59:58 +08:00
|
|
|
Connect();
|
|
|
|
|
SendReceive();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that an invalid client auth signature doesn't abort the connection.
|
2018-02-06 11:46:26 +01:00
|
|
|
FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
|
2018-01-19 03:59:58 +08:00
|
|
|
EnsureTlsSetup();
|
|
|
|
|
client_->SetupClientAuth();
|
|
|
|
|
server_->RequestClientAuth(true);
|
|
|
|
|
client_->SetPacketFilter(
|
2018-02-06 11:46:26 +01:00
|
|
|
std::make_shared<TlsLastByteDamager>(kTlsHandshakeCertificateVerify));
|
2018-01-19 03:59:58 +08:00
|
|
|
Connect();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
// Check that session ticket resumption works.
|
|
|
|
|
FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
|
|
|
|
|
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
|
|
|
|
Connect();
|
|
|
|
|
SendReceive();
|
|
|
|
|
|
|
|
|
|
Reset();
|
|
|
|
|
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
|
|
|
|
ExpectResumption(RESUME_TICKET);
|
|
|
|
|
Connect();
|
|
|
|
|
SendReceive();
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-25 21:33:33 +02:00
|
|
|
class TlsSessionTicketMacDamager : public TlsExtensionFilter {
|
|
|
|
|
public:
|
|
|
|
|
TlsSessionTicketMacDamager() {}
|
|
|
|
|
virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
|
|
|
|
|
const DataBuffer& input,
|
|
|
|
|
DataBuffer* output) {
|
|
|
|
|
if (extension_type != ssl_session_ticket_xtn &&
|
|
|
|
|
extension_type != ssl_tls13_pre_shared_key_xtn) {
|
|
|
|
|
return KEEP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*output = input;
|
|
|
|
|
|
|
|
|
|
// Handle everything before TLS 1.3.
|
|
|
|
|
if (extension_type == ssl_session_ticket_xtn) {
|
|
|
|
|
// Modify the last byte of the MAC.
|
|
|
|
|
output->data()[output->len() - 1] ^= 0xff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle TLS 1.3.
|
|
|
|
|
if (extension_type == ssl_tls13_pre_shared_key_xtn) {
|
|
|
|
|
TlsParser parser(input);
|
|
|
|
|
|
|
|
|
|
uint32_t ids_len;
|
|
|
|
|
EXPECT_TRUE(parser.Read(&ids_len, 2) && ids_len > 0);
|
|
|
|
|
|
|
|
|
|
uint32_t ticket_len;
|
|
|
|
|
EXPECT_TRUE(parser.Read(&ticket_len, 2) && ticket_len > 0);
|
|
|
|
|
|
|
|
|
|
// Modify the last byte of the MAC.
|
|
|
|
|
output->data()[2 + 2 + ticket_len - 1] ^= 0xff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CHANGE;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Check that session ticket resumption works with a bad MAC.
|
|
|
|
|
FUZZ_P(TlsConnectGeneric, SessionTicketResumptionBadMac) {
|
|
|
|
|
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
|
|
|
|
Connect();
|
|
|
|
|
SendReceive();
|
|
|
|
|
|
|
|
|
|
Reset();
|
|
|
|
|
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
|
|
|
|
ExpectResumption(RESUME_TICKET);
|
|
|
|
|
|
|
|
|
|
client_->SetPacketFilter(std::make_shared<TlsSessionTicketMacDamager>());
|
|
|
|
|
Connect();
|
|
|
|
|
SendReceive();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 11:46:26 +01:00
|
|
|
// Check that session tickets are not encrypted.
|
|
|
|
|
FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
|
|
|
|
|
ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
|
|
|
|
|
|
|
|
|
|
auto i1 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
|
|
|
|
|
kTlsHandshakeNewSessionTicket);
|
|
|
|
|
server_->SetPacketFilter(i1);
|
|
|
|
|
Connect();
|
|
|
|
|
|
|
|
|
|
size_t offset = 4; /* lifetime */
|
|
|
|
|
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
2018-04-25 21:33:33 +02:00
|
|
|
offset += 1 + 1 + /* ke_modes */
|
|
|
|
|
1 + 1; /* auth_modes */
|
2018-02-06 11:46:26 +01:00
|
|
|
}
|
|
|
|
|
offset += 2 + /* ticket length */
|
|
|
|
|
2; /* TLS_EX_SESS_TICKET_VERSION */
|
|
|
|
|
// Check the protocol version number.
|
|
|
|
|
uint32_t tls_version = 0;
|
|
|
|
|
EXPECT_TRUE(i1->buffer().Read(offset, sizeof(version_), &tls_version));
|
|
|
|
|
EXPECT_EQ(version_, static_cast<decltype(version_)>(tls_version));
|
|
|
|
|
|
|
|
|
|
// Check the cipher suite.
|
|
|
|
|
uint32_t suite = 0;
|
|
|
|
|
EXPECT_TRUE(i1->buffer().Read(offset + sizeof(version_), 2, &suite));
|
|
|
|
|
client_->CheckCipherSuite(static_cast<uint16_t>(suite));
|
|
|
|
|
}
|
2018-01-19 03:59:58 +08:00
|
|
|
}
|