tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ssl_fuzz_unittest.cc (10384B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include <limits>
      6 #include <unordered_set>
      7 
      8 #include "blapi.h"
      9 #include "ssl.h"
     10 #include "sslimpl.h"
     11 #include "tls_connect.h"
     12 
     13 #include "gtest/gtest.h"
     14 
     15 namespace nss_test {
     16 
     17 #ifdef UNSAFE_FUZZER_MODE
     18 #define FUZZ_F(c, f) TEST_F(c, Fuzz_##f)
     19 #define FUZZ_P(c, f) TEST_P(c, Fuzz_##f)
     20 #else
     21 #define FUZZ_F(c, f) TEST_F(c, DISABLED_Fuzz_##f)
     22 #define FUZZ_P(c, f) TEST_P(c, DISABLED_Fuzz_##f)
     23 #endif
     24 
     25 static std::unordered_set<PRInt32> gFuzzedSslOptions = {
     26    SSL_SECURITY,             // irrelevant
     27    SSL_SOCKS,                // irrelevant
     28    SSL_REQUEST_CERTIFICATE,  // tls_server
     29    SSL_HANDSHAKE_AS_CLIENT,  // irrelevant
     30    SSL_HANDSHAKE_AS_SERVER,  // irrelevant
     31    SSL_ENABLE_SSL2,          // obsolete
     32    SSL_ENABLE_SSL3,          // obsolete
     33    SSL_NO_CACHE,             // tls_client, tls_server
     34    SSL_REQUIRE_CERTIFICATE,  // tls_server
     35    SSL_ENABLE_FDX,
     36    SSL_V2_COMPATIBLE_HELLO,  // obsolete
     37    SSL_ENABLE_TLS,           // obsolete
     38    SSL_ROLLBACK_DETECTION,
     39    SSL_NO_STEP_DOWN,            // unsupported
     40    SSL_BYPASS_PKCS11,           // unsupported
     41    SSL_NO_LOCKS,                // tls_client, tls_server
     42    SSL_ENABLE_SESSION_TICKETS,  // tls_client, tls_server
     43    SSL_ENABLE_DEFLATE,          // tls_client, tls_server
     44    SSL_ENABLE_RENEGOTIATION,
     45    SSL_REQUIRE_SAFE_NEGOTIATION,  // tls_client, tls_server
     46    SSL_ENABLE_FALSE_START,        // tls_client
     47    SSL_CBC_RANDOM_IV,             // tls_client, tls_server
     48    SSL_ENABLE_OCSP_STAPLING,      // tls_client
     49    SSL_ENABLE_NPN,                // defunct
     50    SSL_ENABLE_ALPN,               // tls_client, tls_server
     51    SSL_REUSE_SERVER_ECDHE_KEY,
     52    SSL_ENABLE_FALLBACK_SCSV,  // tls_client, tls_server
     53    SSL_ENABLE_SERVER_DHE,
     54    SSL_ENABLE_EXTENDED_MASTER_SECRET,  // tls_client, tls_server
     55    SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
     56    SSL_REQUIRE_DH_NAMED_GROUPS,  // tls_client
     57    SSL_ENABLE_0RTT_DATA,         // tls_client, tls_server
     58    SSL_RECORD_SIZE_LIMIT,
     59    SSL_ENABLE_TLS13_COMPAT_MODE,  // tls_client
     60    SSL_ENABLE_DTLS_SHORT_HEADER,  // tls_client, tls_server
     61    SSL_ENABLE_HELLO_DOWNGRADE_CHECK,
     62    SSL_ENABLE_V2_COMPATIBLE_HELLO,
     63    SSL_ENABLE_POST_HANDSHAKE_AUTH,    // tls_client
     64    SSL_ENABLE_DELEGATED_CREDENTIALS,  // tls_client, tls_server
     65    SSL_SUPPRESS_END_OF_EARLY_DATA,
     66    SSL_ENABLE_GREASE,                    // tls_client, tls_server
     67    SSL_ENABLE_CH_EXTENSION_PERMUTATION,  // tls_client
     68    SSL_DB_LOAD_CERTIFICATE_CHAIN,
     69 };
     70 
     71 const uint8_t kShortEmptyFinished[8] = {0};
     72 const uint8_t kLongEmptyFinished[128] = {0};
     73 
     74 class TlsFuzzTest : public TlsConnectGeneric {};
     75 
     76 // Record the application data stream.
     77 class TlsApplicationDataRecorder : public TlsRecordFilter {
     78 public:
     79  TlsApplicationDataRecorder(const std::shared_ptr<TlsAgent>& a)
     80      : TlsRecordFilter(a), buffer_() {}
     81 
     82  virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
     83                                            const DataBuffer& input,
     84                                            DataBuffer* output) {
     85    if (header.content_type() == ssl_ct_application_data) {
     86      buffer_.Append(input);
     87    }
     88 
     89    return KEEP;
     90  }
     91 
     92  const DataBuffer& buffer() const { return buffer_; }
     93 
     94 private:
     95  DataBuffer buffer_;
     96 };
     97 
     98 // Check that due to the deterministic PRNG we derive
     99 // the same master secret in two consecutive TLS sessions.
    100 FUZZ_P(TlsFuzzTest, DeterministicExporter) {
    101  const char kLabel[] = "label";
    102  std::vector<unsigned char> out1(32), out2(32);
    103 
    104  // Make sure we have RSA blinding params.
    105  Connect();
    106 
    107  Reset();
    108  ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
    109 
    110  // Reset the RNG state.
    111  EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
    112  Connect();
    113 
    114  // Export a key derived from the MS and nonces.
    115  SECStatus rv =
    116      SSL_ExportKeyingMaterial(client_->ssl_fd(), kLabel, strlen(kLabel), false,
    117                               NULL, 0, out1.data(), out1.size());
    118  EXPECT_EQ(SECSuccess, rv);
    119 
    120  Reset();
    121  ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
    122 
    123  // Reset the RNG state.
    124  EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
    125  Connect();
    126 
    127  // Export another key derived from the MS and nonces.
    128  rv = SSL_ExportKeyingMaterial(client_->ssl_fd(), kLabel, strlen(kLabel),
    129                                false, NULL, 0, out2.data(), out2.size());
    130  EXPECT_EQ(SECSuccess, rv);
    131 
    132  // The two exported keys should be the same.
    133  EXPECT_EQ(out1, out2);
    134 }
    135 
    136 // Check that due to the deterministic RNG two consecutive
    137 // TLS sessions will have the exact same transcript.
    138 FUZZ_P(TlsFuzzTest, DeterministicTranscript) {
    139  // Make sure we have RSA blinding params.
    140  Connect();
    141 
    142  // Connect a few times and compare the transcripts byte-by-byte.
    143  DataBuffer last;
    144  for (size_t i = 0; i < 5; i++) {
    145    Reset();
    146    ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
    147 
    148    DataBuffer buffer;
    149    MakeTlsFilter<TlsConversationRecorder>(client_, buffer);
    150    MakeTlsFilter<TlsConversationRecorder>(server_, buffer);
    151 
    152    // Reset the RNG state.
    153    EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
    154    Connect();
    155 
    156    // Ensure the filters go away before |buffer| does.
    157    client_->ClearFilter();
    158    server_->ClearFilter();
    159 
    160    if (last.len() > 0) {
    161      EXPECT_EQ(last, buffer);
    162    }
    163 
    164    last = buffer;
    165  }
    166 }
    167 
    168 // Check that we can establish and use a connection
    169 // with all supported TLS versions, STREAM and DGRAM.
    170 // Check that records are NOT encrypted.
    171 // Check that records don't have a MAC.
    172 FUZZ_P(TlsFuzzTest, ConnectSendReceive_NullCipher) {
    173  // Set up app data filters.
    174  auto client_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(client_);
    175  auto server_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(server_);
    176 
    177  Connect();
    178 
    179  // Construct the plaintext.
    180  DataBuffer buf;
    181  buf.Allocate(50);
    182  for (size_t i = 0; i < buf.len(); ++i) {
    183    buf.data()[i] = i & 0xff;
    184  }
    185 
    186  // Send/Receive data.
    187  client_->SendBuffer(buf);
    188  server_->SendBuffer(buf);
    189  Receive(buf.len());
    190 
    191  // Check for plaintext on the wire.
    192  EXPECT_EQ(buf, client_recorder->buffer());
    193  EXPECT_EQ(buf, server_recorder->buffer());
    194 }
    195 
    196 // Check that an invalid Finished message doesn't abort the connection.
    197 FUZZ_P(TlsFuzzTest, BogusClientFinished) {
    198  EnsureTlsSetup();
    199 
    200  MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
    201      client_, kTlsHandshakeFinished,
    202      DataBuffer(kShortEmptyFinished, sizeof(kShortEmptyFinished)));
    203  Connect();
    204  SendReceive();
    205 }
    206 
    207 // Check that an invalid Finished message doesn't abort the connection.
    208 FUZZ_P(TlsFuzzTest, BogusServerFinished) {
    209  EnsureTlsSetup();
    210 
    211  MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
    212      server_, kTlsHandshakeFinished,
    213      DataBuffer(kLongEmptyFinished, sizeof(kLongEmptyFinished)));
    214  Connect();
    215  SendReceive();
    216 }
    217 
    218 // Check that an invalid server auth signature doesn't abort the connection.
    219 FUZZ_P(TlsFuzzTest, BogusServerAuthSignature) {
    220  EnsureTlsSetup();
    221  uint8_t msg_type = version_ == SSL_LIBRARY_VERSION_TLS_1_3
    222                         ? kTlsHandshakeCertificateVerify
    223                         : kTlsHandshakeServerKeyExchange;
    224  MakeTlsFilter<TlsLastByteDamager>(server_, msg_type);
    225  Connect();
    226  SendReceive();
    227 }
    228 
    229 // Check that an invalid client auth signature doesn't abort the connection.
    230 FUZZ_P(TlsFuzzTest, BogusClientAuthSignature) {
    231  EnsureTlsSetup();
    232  client_->SetupClientAuth();
    233  server_->RequestClientAuth(true);
    234  MakeTlsFilter<TlsLastByteDamager>(client_, kTlsHandshakeCertificateVerify);
    235  Connect();
    236 }
    237 
    238 // Check that session ticket resumption works.
    239 FUZZ_P(TlsFuzzTest, SessionTicketResumption) {
    240  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
    241  Connect();
    242  SendReceive();
    243 
    244  Reset();
    245  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
    246  ExpectResumption(RESUME_TICKET);
    247  Connect();
    248  SendReceive();
    249 }
    250 
    251 // Check that session tickets are not encrypted.
    252 FUZZ_P(TlsFuzzTest, UnencryptedSessionTickets) {
    253  ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
    254 
    255  auto filter = MakeTlsFilter<TlsHandshakeRecorder>(
    256      server_, kTlsHandshakeNewSessionTicket);
    257  Connect();
    258 
    259  std::cerr << "ticket" << filter->buffer() << std::endl;
    260  size_t offset = 4;  // Skip lifetime.
    261 
    262  if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
    263    offset += 4;  // Skip ticket_age_add.
    264    uint32_t nonce_len = 0;
    265    EXPECT_TRUE(filter->buffer().Read(offset, 1, &nonce_len));
    266    offset += 1 + nonce_len;
    267  }
    268 
    269  offset += 2;  // Skip the ticket length.
    270 
    271  // This bit parses the contents of the ticket, which would ordinarily be
    272  // encrypted.  Start by checking that we have the right version.  This needs
    273  // to be updated every time that TLS_EX_SESS_TICKET_VERSION is changed.  But
    274  // we don't use the #define.  That way, any time that code is updated, this
    275  // test will fail unless it is manually checked.
    276  uint32_t ticket_version;
    277  EXPECT_TRUE(filter->buffer().Read(offset, 2, &ticket_version));
    278  EXPECT_EQ(0x010aU, ticket_version);
    279  offset += 2;
    280 
    281  // Check the protocol version number.
    282  uint32_t tls_version = 0;
    283  EXPECT_TRUE(filter->buffer().Read(offset, sizeof(version_), &tls_version));
    284  EXPECT_EQ(version_, static_cast<decltype(version_)>(tls_version));
    285  offset += sizeof(version_);
    286 
    287  // Check the cipher suite.
    288  uint32_t suite = 0;
    289  EXPECT_TRUE(filter->buffer().Read(offset, 2, &suite));
    290  client_->CheckCipherSuite(static_cast<uint16_t>(suite));
    291 }
    292 
    293 class MiscFuzzTest : public ::testing::Test {};
    294 
    295 FUZZ_F(MiscFuzzTest, UnfuzzedSslOption) {
    296  PRIntn val;
    297  SECStatus rv;
    298 
    299  for (PRInt32 option = 0; option < std::numeric_limits<PRUint8>::max();
    300       ++option) {
    301    rv = SSL_OptionGetDefault(option, &val);
    302    // The return value should either be  a failure (=> there is no such
    303    // option) or the the option should be in the fuzzed options.
    304    EXPECT_TRUE(rv == SECFailure || gFuzzedSslOptions.count(option));
    305  }
    306 }
    307 
    308 INSTANTIATE_TEST_SUITE_P(
    309    FuzzStream, TlsFuzzTest,
    310    ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
    311                       TlsConnectTestBase::kTlsVAll));
    312 INSTANTIATE_TEST_SUITE_P(
    313    FuzzDatagram, TlsFuzzTest,
    314    ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
    315                       TlsConnectTestBase::kTlsV11Plus));
    316 }  // namespace nss_test