summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
commitf4a12fc67689a830e9da1c87fd11afe5bc09deb3 (patch)
tree211ae0cd022a6c11b0026ecc7761a550c584583c /security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
parentf7d30133221896638f7bf4f66c504255c4b14f48 (diff)
downloadUXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.gz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.lz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.xz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.zip
Issue #1338 - Part 2: Update NSS to 3.48-RTM
Diffstat (limited to 'security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc')
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc410
1 files changed, 392 insertions, 18 deletions
diff --git a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
index 07eadfbd1..928515067 100644
--- a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -45,11 +45,40 @@ TEST_P(TlsConnectTls13, ZeroRttServerRejectByOption) {
SendReceive();
}
+TEST_P(TlsConnectTls13, ZeroRttApplicationReject) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+
+ auto reject_0rtt = [](PRBool firstHello, const PRUint8* clientToken,
+ unsigned int clientTokenLen, PRUint8* appToken,
+ unsigned int* appTokenLen, unsigned int appTokenMax,
+ void* arg) {
+ auto* called = reinterpret_cast<bool*>(arg);
+ *called = true;
+
+ EXPECT_TRUE(firstHello);
+ EXPECT_EQ(0U, clientTokenLen);
+ return ssl_hello_retry_reject_0rtt;
+ };
+
+ bool cb_run = false;
+ EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(),
+ reject_0rtt, &cb_run));
+ ZeroRttSendReceive(true, false);
+ Handshake();
+ EXPECT_TRUE(cb_run);
+ CheckConnected();
+ SendReceive();
+}
+
TEST_P(TlsConnectTls13, ZeroRttApparentReplayAfterRestart) {
- // The test fixtures call SSL_SetupAntiReplay() in SetUp(). This results in
- // 0-RTT being rejected until at least one window passes. SetupFor0Rtt()
- // forces a rollover of the anti-replay filters, which clears this state.
- // Here, we do the setup manually here without that forced rollover.
+ // The test fixtures enable anti-replay in SetUp(). This results in 0-RTT
+ // being rejected until at least one window passes. SetupFor0Rtt() forces a
+ // rollover of the anti-replay filters, which clears that state and allows
+ // 0-RTT to work. Make the first connection manually to avoid that rollover
+ // and cause 0-RTT to be rejected.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
@@ -106,7 +135,7 @@ class TlsZeroRttReplayTest : public TlsConnectTls13 {
SendReceive();
if (rollover) {
- SSLInt_RolloverAntiReplay();
+ RolloverAntiReplay();
}
// Now replay that packet against the server.
@@ -184,20 +213,21 @@ TEST_P(TlsConnectTls13, ZeroRttServerOnly) {
CheckKeys();
}
-// A small sleep after sending the ClientHello means that the ticket age that
-// arrives at the server is too low. With a small tolerance for variation in
-// ticket age (which is determined by the |window| parameter that is passed to
-// SSL_SetupAntiReplay()), the server then rejects early data.
+// Advancing time after sending the ClientHello means that the ticket age that
+// arrives at the server is too low. The server then rejects early data if this
+// delay exceeds half the anti-replay window.
TEST_P(TlsConnectTls13, ZeroRttRejectOldTicket) {
+ static const PRTime kWindow = 10 * PR_USEC_PER_SEC;
+ ResetAntiReplay(kWindow);
SetupForZeroRtt();
+
+ Reset();
+ StartConnect();
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
- EXPECT_EQ(SECSuccess, SSL_SetupAntiReplay(1, 1, 3));
- SSLInt_RolloverAntiReplay(); // Make sure to flush replay state.
- SSLInt_RolloverAntiReplay();
ExpectResumption(RESUME_TICKET);
- ZeroRttSendReceive(true, false, []() {
- PR_Sleep(PR_MillisecondsToInterval(10));
+ ZeroRttSendReceive(true, false, [this]() {
+ AdvanceTime(1 + kWindow / 2);
return true;
});
Handshake();
@@ -212,13 +242,15 @@ TEST_P(TlsConnectTls13, ZeroRttRejectOldTicket) {
// small tolerance for variation in ticket age and the ticket will appear to
// arrive prematurely, causing the server to reject early data.
TEST_P(TlsConnectTls13, ZeroRttRejectPrematureTicket) {
+ static const PRTime kWindow = 10 * PR_USEC_PER_SEC;
+ ResetAntiReplay(kWindow);
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
server_->Set0RttEnabled(true);
StartConnect();
client_->Handshake(); // ClientHello
server_->Handshake(); // ServerHello
- PR_Sleep(PR_MillisecondsToInterval(10));
+ AdvanceTime(1 + kWindow / 2);
Handshake(); // Remainder of handshake
CheckConnected();
SendReceive();
@@ -227,9 +259,6 @@ TEST_P(TlsConnectTls13, ZeroRttRejectPrematureTicket) {
Reset();
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
- EXPECT_EQ(SECSuccess, SSL_SetupAntiReplay(1, 1, 3));
- SSLInt_RolloverAntiReplay(); // Make sure to flush replay state.
- SSLInt_RolloverAntiReplay();
ExpectResumption(RESUME_TICKET);
ExpectEarlyDataAccepted(false);
StartConnect();
@@ -649,6 +678,351 @@ TEST_P(TlsConnectTls13, ZeroRttOrdering) {
EXPECT_EQ(2U, step);
}
+// Early data remains available after the handshake completes for TLS.
+TEST_F(TlsConnectStreamTls13, ZeroRttLateReadTls) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+ client_->Handshake(); // ClientHello
+
+ // Write some early data.
+ const uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ PRInt32 rv = PR_Write(client_->ssl_fd(), data, sizeof(data));
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), rv);
+
+ // Consume the ClientHello and generate ServerHello..Finished.
+ server_->Handshake();
+
+ // Read some of the data.
+ std::vector<uint8_t> small_buffer(1 + sizeof(data) / 2);
+ rv = PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size());
+ EXPECT_EQ(static_cast<PRInt32>(small_buffer.size()), rv);
+ EXPECT_EQ(0, memcmp(data, small_buffer.data(), small_buffer.size()));
+
+ Handshake(); // Complete the handshake.
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+
+ // After the handshake, it should be possible to read the remainder.
+ uint8_t big_buf[100];
+ rv = PR_Read(server_->ssl_fd(), big_buf, sizeof(big_buf));
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - small_buffer.size()), rv);
+ EXPECT_EQ(0, memcmp(&data[small_buffer.size()], big_buf,
+ sizeof(data) - small_buffer.size()));
+
+ // And that's all there is to read.
+ rv = PR_Read(server_->ssl_fd(), big_buf, sizeof(big_buf));
+ EXPECT_GT(0, rv);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+}
+
+// Early data that arrives before the handshake can be read after the handshake
+// is complete.
+TEST_F(TlsConnectDatagram13, ZeroRttLateReadDtls) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+ client_->Handshake(); // ClientHello
+
+ // Write some early data.
+ const uint8_t data[] = {1, 2, 3};
+ PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data));
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
+
+ Handshake(); // Complete the handshake.
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+
+ // Reading at the server should return the early data, which was buffered.
+ uint8_t buf[sizeof(data) + 1] = {0};
+ PRInt32 read = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read);
+ EXPECT_EQ(0, memcmp(data, buf, sizeof(data)));
+}
+
+class PacketHolder : public PacketFilter {
+ public:
+ PacketHolder() = default;
+
+ virtual Action Filter(const DataBuffer& input, DataBuffer* output) {
+ packet_ = input;
+ Disable();
+ return DROP;
+ }
+
+ const DataBuffer& packet() const { return packet_; }
+
+ private:
+ DataBuffer packet_;
+};
+
+// Early data that arrives late is discarded for DTLS.
+TEST_F(TlsConnectDatagram13, ZeroRttLateArrivalDtls) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+ client_->Handshake(); // ClientHello
+
+ // Write some early data. Twice, so that we can read bits of it.
+ const uint8_t data[] = {1, 2, 3};
+ PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data));
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
+
+ // Block and capture the next packet.
+ auto holder = std::make_shared<PacketHolder>();
+ client_->SetFilter(holder);
+ written = PR_Write(client_->ssl_fd(), data, sizeof(data));
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
+ EXPECT_FALSE(holder->enabled()) << "the filter should disable itself";
+
+ // Consume the ClientHello and generate ServerHello..Finished.
+ server_->Handshake();
+
+ // Read some of the data.
+ std::vector<uint8_t> small_buffer(sizeof(data));
+ PRInt32 read =
+ PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size());
+
+ EXPECT_EQ(static_cast<PRInt32>(small_buffer.size()), read);
+ EXPECT_EQ(0, memcmp(data, small_buffer.data(), small_buffer.size()));
+
+ Handshake(); // Complete the handshake.
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+
+ server_->SendDirect(holder->packet());
+
+ // Reading now should return nothing, even though a valid packet was
+ // delivered.
+ read = PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size());
+ EXPECT_GT(0, read);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+}
+
+// Early data reads in TLS should be coalesced.
+TEST_F(TlsConnectStreamTls13, ZeroRttCoalesceReadTls) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+ client_->Handshake(); // ClientHello
+
+ // Write some early data. In two writes.
+ const uint8_t data[] = {1, 2, 3, 4, 5, 6};
+ PRInt32 written = PR_Write(client_->ssl_fd(), data, 1);
+ EXPECT_EQ(1, written);
+
+ written = PR_Write(client_->ssl_fd(), data + 1, sizeof(data) - 1);
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), written);
+
+ // Consume the ClientHello and generate ServerHello..Finished.
+ server_->Handshake();
+
+ // Read all of the data.
+ std::vector<uint8_t> buffer(sizeof(data));
+ PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read);
+ EXPECT_EQ(0, memcmp(data, buffer.data(), sizeof(data)));
+
+ Handshake(); // Complete the handshake.
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+}
+
+// Early data reads in DTLS should not be coalesced.
+TEST_F(TlsConnectDatagram13, ZeroRttNoCoalesceReadDtls) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+ client_->Handshake(); // ClientHello
+
+ // Write some early data. In two writes.
+ const uint8_t data[] = {1, 2, 3, 4, 5, 6};
+ PRInt32 written = PR_Write(client_->ssl_fd(), data, 1);
+ EXPECT_EQ(1, written);
+
+ written = PR_Write(client_->ssl_fd(), data + 1, sizeof(data) - 1);
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), written);
+
+ // Consume the ClientHello and generate ServerHello..Finished.
+ server_->Handshake();
+
+ // Try to read all of the data.
+ std::vector<uint8_t> buffer(sizeof(data));
+ PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
+ EXPECT_EQ(1, read);
+ EXPECT_EQ(0, memcmp(data, buffer.data(), 1));
+
+ // Read the remainder.
+ read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), read);
+ EXPECT_EQ(0, memcmp(data + 1, buffer.data(), sizeof(data) - 1));
+
+ Handshake(); // Complete the handshake.
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+}
+
+// Early data reads in DTLS should fail if the buffer is too small.
+TEST_F(TlsConnectDatagram13, ZeroRttShortReadDtls) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+ client_->Handshake(); // ClientHello
+
+ // Write some early data. In two writes.
+ const uint8_t data[] = {1, 2, 3, 4, 5, 6};
+ PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data));
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
+
+ // Consume the ClientHello and generate ServerHello..Finished.
+ server_->Handshake();
+
+ // Try to read all of the data into a small buffer.
+ std::vector<uint8_t> buffer(sizeof(data));
+ PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), 1);
+ EXPECT_GT(0, read);
+ EXPECT_EQ(SSL_ERROR_RX_SHORT_DTLS_READ, PORT_GetError());
+
+ // Read again with more space.
+ read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
+ EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read);
+ EXPECT_EQ(0, memcmp(data, buffer.data(), sizeof(data)));
+
+ Handshake(); // Complete the handshake.
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+}
+
+// There are few ways in which TLS uses the clock and most of those operate on
+// timescales that would be ridiculous to wait for in a test. This is the one
+// test we have that uses the real clock. It tests that time passes by checking
+// that a small sleep results in rejection of early data. 0-RTT has a
+// configurable timer, which makes it ideal for this.
+TEST_F(TlsConnectStreamTls13, TimePassesByDefault) {
+ // Calling EnsureTlsSetup() replaces the time function on client and server,
+ // and sets up anti-replay, which we don't want, so initialize each directly.
+ client_->EnsureTlsSetup();
+ server_->EnsureTlsSetup();
+ // StartConnect() calls EnsureTlsSetup(), so avoid that too.
+ client_->StartConnect();
+ server_->StartConnect();
+
+ // Set a tiny anti-replay window. This has to be at least 2 milliseconds to
+ // have any chance of being relevant as that is the smallest window that we
+ // can detect. Anything smaller rounds to zero.
+ static const unsigned int kTinyWindowMs = 5;
+ ResetAntiReplay(static_cast<PRTime>(kTinyWindowMs * PR_USEC_PER_MSEC));
+ server_->SetAntiReplayContext(anti_replay_);
+
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+ server_->Set0RttEnabled(true);
+ Handshake();
+ CheckConnected();
+ SendReceive(); // Absorb a session ticket.
+ CheckKeys();
+
+ // Clear the first window.
+ PR_Sleep(PR_MillisecondsToInterval(kTinyWindowMs));
+
+ Reset();
+ client_->EnsureTlsSetup();
+ server_->EnsureTlsSetup();
+ client_->StartConnect();
+ server_->StartConnect();
+
+ // Early data is rejected by the server only if time passes for it as well.
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+ ZeroRttSendReceive(true, false, []() {
+ // Sleep long enough that we minimize the risk of our RTT estimation being
+ // duped by stutters in test execution. This is very long to allow for
+ // flaky and low-end hardware, especially what our CI runs on.
+ PR_Sleep(PR_MillisecondsToInterval(1000));
+ return true;
+ });
+ Handshake();
+ ExpectEarlyDataAccepted(false);
+ CheckConnected();
+}
+
+// Test that SSL_CreateAntiReplayContext doesn't pass bad inputs.
+TEST_F(TlsConnectStreamTls13, BadAntiReplayArgs) {
+ SSLAntiReplayContext* p;
+ // Zero or negative window.
+ EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, -1, 1, 1, &p));
+ EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+ EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 0, 1, 1, &p));
+ EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+ // Zero k.
+ EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 0, 1, &p));
+ EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+ // Zero bits.
+ EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 1, 0, &p));
+ EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+ EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 1, 1, nullptr));
+ EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+ // Prove that these parameters do work, even if they are useless..
+ EXPECT_EQ(SECSuccess, SSL_CreateAntiReplayContext(0, 1, 1, 1, &p));
+ ASSERT_NE(nullptr, p);
+ ScopedSSLAntiReplayContext ctx(p);
+
+ // The socket isn't a client or server until later, so configuring a client
+ // should work OK.
+ client_->EnsureTlsSetup();
+ EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(client_->ssl_fd(), ctx.get()));
+ EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(client_->ssl_fd(), nullptr));
+}
+
+// See also TlsConnectGenericResumption.ResumeServerIncompatibleCipher
+TEST_P(TlsConnectTls13, ZeroRttDifferentCompatibleCipher) {
+ EnsureTlsSetup();
+ server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ // Change the ciphersuite. Resumption is OK because the hash is the same, but
+ // early data will be rejected.
+ server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
+ ExpectResumption(RESUME_TICKET);
+
+ StartConnect();
+ ZeroRttSendReceive(true, false);
+
+ Handshake();
+ ExpectEarlyDataAccepted(false);
+ CheckConnected();
+ SendReceive();
+}
+
+// See also TlsConnectGenericResumption.ResumeServerIncompatibleCipher
+TEST_P(TlsConnectTls13, ZeroRttDifferentIncompatibleCipher) {
+ EnsureTlsSetup();
+ server_->EnableSingleCipher(TLS_AES_256_GCM_SHA384);
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ // Resumption is rejected because the hash is different.
+ server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
+ ExpectResumption(RESUME_NONE);
+
+ StartConnect();
+ ZeroRttSendReceive(true, false);
+
+ Handshake();
+ ExpectEarlyDataAccepted(false);
+ CheckConnected();
+ SendReceive();
+}
+
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(Tls13ZeroRttReplayTest, TlsZeroRttReplayTest,
TlsConnectTestBase::kTlsVariantsAll);