summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Thomson <mt@lowentropy.net>2019-05-20 09:45:56 +0100
committerMartin Thomson <mt@lowentropy.net>2019-05-20 09:45:56 +0100
commit2fb285c533cb19a01eeae798c76affea460f30ec (patch)
tree1cc155148ee7d1c7563561da10de1be4932f4ef9
parent390d9cfd74daaa3542ba11456ec36f0db74fd4df (diff)
downloadnss-hg-2fb285c533cb19a01eeae798c76affea460f30ec.tar.gz
Bug 1543874 - Use an external clock for SSL functions, r=ekr,kevinjacobs
Summary: This adds a new (experimental) API that allows users of libssl to provide their own clock function. This is primarily of use in testing, but it also enables our QUIC implementation, which also runs off an external clock. SSL Sockets (and session IDs, when they are in memory) now have a "now()" function and void* arg attached to them. By default, this is a function that calls PR_Now(). These values are copied from the socket to any session ID that is created from the socket, and to any session ID that is restored from the session cache. The ssl_Time() and ssl_TimeUsec() functions have been removed. As part of this, the experimental SSL_SetupAntiReplay() function had to be modified to take an external clock (PR_Now() suffices generally). That function relies on knowing the time, and it doesn't have a socket to work from. To avoid problems arising from the change in the signature, SSL_SetupAntiReplay is now removed. There are now three uses of time in the library: * The primary source of time runs of these newly added functions. This governs session expiry, 0-RTT checks, and related functions. * The session cache uses a separate time to manage its locking. This is of type PRUint32 in seconds (rather than PRTime in microseconds). In investigating this, I found several places where this time in seconds was leaking across to the main functions via the lastAccessTime property. That was fixed. The cache functions that use time now all call ssl_CacheNow() to get time. * DTLS timers run using PRIntervalTime. This is a little annoying and these could be made to use the main time source, but that would result in conversions between PRTime and PRIntervalTime at the DTLS API. PRIntervalTime has a different epoch to PRTime, so this would be a little awkward. Only the first of these can be controlled using the new API. Bugs found: * Expiration time of resumption tokens was based on the sid->expirationTime, which didn't account for the lifetime provided by the server. These are now capped by the minimum of ssl_ticket_lifetime and the value the server indicates. I removed ssl3_sid_timeout, the old limit, because inconsistent lifetimes between client and server messed with tests. The client would have a lower cap than the server, which prevented testing of the enforcement of server limits without jumping through hoops. * There was a missing time conversion in tls13_InWindow which made the window checks too lenient. * lastAccessTime was being set to seconds-since-epoch instead of microseconds-since-epoch in a few places. Reviewers: ekr, KevinJacobs Reviewed By: KevinJacobs Subscribers: cjpatton Bug #: 1543874 Differential Revision: https://phabricator.services.mozilla.com/D27238
-rw-r--r--cmd/selfserv/selfserv.c2
-rw-r--r--fuzz/tls_client_target.cc1
-rw-r--r--fuzz/tls_common.cc9
-rw-r--r--fuzz/tls_common.h1
-rw-r--r--fuzz/tls_server_target.cc1
-rw-r--r--gtests/ssl_gtest/libssl_internals.c15
-rw-r--r--gtests/ssl_gtest/libssl_internals.h2
-rw-r--r--gtests/ssl_gtest/ssl_0rtt_unittest.cc83
-rw-r--r--gtests/ssl_gtest/ssl_fuzz_unittest.cc61
-rw-r--r--gtests/ssl_gtest/ssl_resumption_unittest.cc72
-rw-r--r--gtests/ssl_gtest/tls_connect.cc44
-rw-r--r--gtests/ssl_gtest/tls_connect.h6
-rw-r--r--lib/ssl/authcert.c14
-rw-r--r--lib/ssl/ssl3con.c13
-rw-r--r--lib/ssl/ssl3exthandle.c11
-rw-r--r--lib/ssl/sslcon.c20
-rw-r--r--lib/ssl/sslexp.h33
-rw-r--r--lib/ssl/sslimpl.h34
-rw-r--r--lib/ssl/sslnonce.c69
-rw-r--r--lib/ssl/sslsnce.c31
-rw-r--r--lib/ssl/sslsock.c35
-rw-r--r--lib/ssl/tls13con.c6
-rw-r--r--lib/ssl/tls13con.h4
-rw-r--r--lib/ssl/tls13exthandle.c2
-rw-r--r--lib/ssl/tls13replay.c37
25 files changed, 384 insertions, 222 deletions
diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
index 6c00d3a15..4b1adb028 100644
--- a/cmd/selfserv/selfserv.c
+++ b/cmd/selfserv/selfserv.c
@@ -1954,7 +1954,7 @@ server_main(
if (enabledVersions.max < SSL_LIBRARY_VERSION_TLS_1_3) {
errExit("You tried enabling 0RTT without enabling TLS 1.3!");
}
- rv = SSL_SetupAntiReplay(10 * PR_USEC_PER_SEC, 7, 14);
+ rv = SSL_InitAntiReplay(PR_Now(), 10L * PR_USEC_PER_SEC, 7, 14);
if (rv != SECSuccess) {
errExit("error configuring anti-replay ");
}
diff --git a/fuzz/tls_client_target.cc b/fuzz/tls_client_target.cc
index a5b2a2c5f..461962c5d 100644
--- a/fuzz/tls_client_target.cc
+++ b/fuzz/tls_client_target.cc
@@ -106,6 +106,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
// Probably not too important for clients.
SSL_SetURL(ssl_fd, "server");
+ FixTime(ssl_fd);
SetSocketOptions(ssl_fd, config);
EnableAllCipherSuites(ssl_fd);
SetupCallbacks(ssl_fd, config.get());
diff --git a/fuzz/tls_common.cc b/fuzz/tls_common.cc
index 1e66684dc..b00ab26bf 100644
--- a/fuzz/tls_common.cc
+++ b/fuzz/tls_common.cc
@@ -5,9 +5,18 @@
#include <assert.h>
#include "ssl.h"
+#include "sslexp.h"
#include "tls_common.h"
+static PRTime FixedTime(void*) { return 1234; }
+
+// Fix the time input, to avoid any time-based variation.
+void FixTime(PRFileDesc* fd) {
+ SECStatus rv = SSL_SetTimeFunc(fd, FixedTime, nullptr);
+ assert(rv == SECSuccess);
+}
+
PRStatus EnableAllProtocolVersions() {
SSLVersionRange supported;
diff --git a/fuzz/tls_common.h b/fuzz/tls_common.h
index 8843347fa..e53accead 100644
--- a/fuzz/tls_common.h
+++ b/fuzz/tls_common.h
@@ -7,6 +7,7 @@
#include "prinit.h"
+void FixTime(PRFileDesc* fd);
PRStatus EnableAllProtocolVersions();
void EnableAllCipherSuites(PRFileDesc* fd);
void DoHandshake(PRFileDesc* fd, bool isServer);
diff --git a/fuzz/tls_server_target.cc b/fuzz/tls_server_target.cc
index 0c0902077..41a55541c 100644
--- a/fuzz/tls_server_target.cc
+++ b/fuzz/tls_server_target.cc
@@ -118,6 +118,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
PRFileDesc* ssl_fd = ImportFD(model.get(), fd.get());
assert(ssl_fd == fd.get());
+ FixTime(ssl_fd);
SetSocketOptions(ssl_fd, config);
DoHandshake(ssl_fd, true);
diff --git a/gtests/ssl_gtest/libssl_internals.c b/gtests/ssl_gtest/libssl_internals.c
index 2a9803daa..998e4b934 100644
--- a/gtests/ssl_gtest/libssl_internals.c
+++ b/gtests/ssl_gtest/libssl_internals.c
@@ -109,9 +109,10 @@ void SSLInt_PrintCipherSpecs(const char *label, PRFileDesc *fd) {
}
}
-/* Force a timer expiry by backdating when all active timers were started. We
- * could set the remaining time to 0 but then backoff would not work properly if
- * we decide to test it. */
+/* DTLS timers are separate from the time that the rest of the stack uses.
+ * Force a timer expiry by backdating when all active timers were started.
+ * We could set the remaining time to 0 but then backoff would not work properly
+ * if we decide to test it. */
SECStatus SSLInt_ShiftDtlsTimers(PRFileDesc *fd, PRIntervalTime shift) {
size_t i;
sslSocket *ss = ssl_FindSocket(fd);
@@ -297,10 +298,6 @@ SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) {
return groupDef->keaType;
}
-void SSLInt_SetTicketLifetime(uint32_t lifetime) {
- ssl_ticket_lifetime = lifetime;
-}
-
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
sslSocket *ss;
@@ -324,10 +321,6 @@ SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
return SECSuccess;
}
-void SSLInt_RolloverAntiReplay(void) {
- tls13_AntiReplayRollover(ssl_TimeUsec());
-}
-
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending) {
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
diff --git a/gtests/ssl_gtest/libssl_internals.h b/gtests/ssl_gtest/libssl_internals.h
index 8c78de28f..b831dcafe 100644
--- a/gtests/ssl_gtest/libssl_internals.h
+++ b/gtests/ssl_gtest/libssl_internals.h
@@ -40,8 +40,6 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to);
SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra);
SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group);
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending);
-void SSLInt_SetTicketLifetime(uint32_t lifetime);
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
-void SSLInt_RolloverAntiReplay(void);
#endif // ndef libssl_internals_h_
diff --git a/gtests/ssl_gtest/ssl_0rtt_unittest.cc b/gtests/ssl_gtest/ssl_0rtt_unittest.cc
index 4a47592ca..863e07d1c 100644
--- a/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -46,7 +46,7 @@ TEST_P(TlsConnectTls13, ZeroRttServerRejectByOption) {
}
TEST_P(TlsConnectTls13, ZeroRttApparentReplayAfterRestart) {
- // The test fixtures call SSL_SetupAntiReplay() in SetUp(). This results in
+ // The test fixtures call SSL_InitAntiReplay() 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.
@@ -106,7 +106,7 @@ class TlsZeroRttReplayTest : public TlsConnectTls13 {
SendReceive();
if (rollover) {
- SSLInt_RolloverAntiReplay();
+ RolloverAntiReplay();
}
// Now replay that packet against the server.
@@ -184,20 +184,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;
+ EXPECT_EQ(SECSuccess, SSL_InitAntiReplay(now(), kWindow, 1, 3));
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 +213,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;
+ EXPECT_EQ(SECSuccess, SSL_InitAntiReplay(now(), kWindow, 1, 3));
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 +230,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();
@@ -870,6 +870,59 @@ TEST_F(TlsConnectDatagram13, ZeroRttShortReadDtls) {
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) {
+ // 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;
+ EXPECT_EQ(SECSuccess, SSL_InitAntiReplay(
+ PR_Now(), kTinyWindowMs * PR_USEC_PER_MSEC, 1, 5));
+
+ // Calling EnsureTlsSetup() replaces the time function on client and server,
+ // which we don't want, so initialize each directly.
+ client_->EnsureTlsSetup();
+ server_->EnsureTlsSetup();
+ client_->StartConnect(); // Also avoid StartConnect().
+ server_->StartConnect();
+
+ 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();
+}
+
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(Tls13ZeroRttReplayTest, TlsZeroRttReplayTest,
TlsConnectTestBase::kTlsVariantsAll);
diff --git a/gtests/ssl_gtest/ssl_fuzz_unittest.cc b/gtests/ssl_gtest/ssl_fuzz_unittest.cc
index f033b7843..bb78bc3d1 100644
--- a/gtests/ssl_gtest/ssl_fuzz_unittest.cc
+++ b/gtests/ssl_gtest/ssl_fuzz_unittest.cc
@@ -22,7 +22,7 @@ namespace nss_test {
const uint8_t kShortEmptyFinished[8] = {0};
const uint8_t kLongEmptyFinished[128] = {0};
-class TlsFuzzTest : public ::testing::Test {};
+class TlsFuzzTest : public TlsConnectGeneric {};
// Record the application data stream.
class TlsApplicationDataRecorder : public TlsRecordFilter {
@@ -46,16 +46,9 @@ class TlsApplicationDataRecorder : public TlsRecordFilter {
DataBuffer buffer_;
};
-// Ensure that ssl_Time() returns a constant value.
-FUZZ_F(TlsFuzzTest, SSL_Time_Constant) {
- PRUint32 now = ssl_TimeSec();
- PR_Sleep(PR_SecondsToInterval(2));
- EXPECT_EQ(ssl_TimeSec(), now);
-}
-
// Check that due to the deterministic PRNG we derive
// the same master secret in two consecutive TLS sessions.
-FUZZ_P(TlsConnectGeneric, DeterministicExporter) {
+FUZZ_P(TlsFuzzTest, DeterministicExporter) {
const char kLabel[] = "label";
std::vector<unsigned char> out1(32), out2(32);
@@ -95,7 +88,7 @@ FUZZ_P(TlsConnectGeneric, DeterministicExporter) {
// Check that due to the deterministic RNG two consecutive
// TLS sessions will have the exact same transcript.
-FUZZ_P(TlsConnectGeneric, DeterministicTranscript) {
+FUZZ_P(TlsFuzzTest, DeterministicTranscript) {
// Make sure we have RSA blinding params.
Connect();
@@ -130,9 +123,7 @@ FUZZ_P(TlsConnectGeneric, DeterministicTranscript) {
// with all supported TLS versions, STREAM and DGRAM.
// Check that records are NOT encrypted.
// Check that records don't have a MAC.
-FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
- EnsureTlsSetup();
-
+FUZZ_P(TlsFuzzTest, ConnectSendReceive_NullCipher) {
// Set up app data filters.
auto client_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(client_);
auto server_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(server_);
@@ -157,7 +148,7 @@ FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
}
// Check that an invalid Finished message doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
+FUZZ_P(TlsFuzzTest, BogusClientFinished) {
EnsureTlsSetup();
MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
@@ -168,7 +159,7 @@ FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
}
// Check that an invalid Finished message doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
+FUZZ_P(TlsFuzzTest, BogusServerFinished) {
EnsureTlsSetup();
MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
@@ -179,7 +170,7 @@ FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
}
// Check that an invalid server auth signature doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
+FUZZ_P(TlsFuzzTest, BogusServerAuthSignature) {
EnsureTlsSetup();
uint8_t msg_type = version_ == SSL_LIBRARY_VERSION_TLS_1_3
? kTlsHandshakeCertificateVerify
@@ -190,7 +181,7 @@ FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
}
// Check that an invalid client auth signature doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
+FUZZ_P(TlsFuzzTest, BogusClientAuthSignature) {
EnsureTlsSetup();
client_->SetupClientAuth();
server_->RequestClientAuth(true);
@@ -199,7 +190,7 @@ FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
}
// Check that session ticket resumption works.
-FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
+FUZZ_P(TlsFuzzTest, SessionTicketResumption) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
SendReceive();
@@ -212,7 +203,7 @@ FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
}
// Check that session tickets are not encrypted.
-FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
+FUZZ_P(TlsFuzzTest, UnencryptedSessionTickets) {
ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
auto filter = MakeTlsFilter<TlsHandshakeRecorder>(
@@ -220,23 +211,45 @@ FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
Connect();
std::cerr << "ticket" << filter->buffer() << std::endl;
- size_t offset = 4; /* lifetime */
+ size_t offset = 4; // Skip lifetime.
+
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
- offset += 4; /* ticket_age_add */
+ offset += 4; // Skip ticket_age_add.
uint32_t nonce_len = 0;
EXPECT_TRUE(filter->buffer().Read(offset, 1, &nonce_len));
offset += 1 + nonce_len;
}
- offset += 2 + /* ticket length */
- 2; /* TLS_EX_SESS_TICKET_VERSION */
+
+ offset += 2; // Skip the ticket length.
+
+ // This bit parses the contents of the ticket, which would ordinarily be
+ // encrypted. Start by checking that we have the right version. This needs
+ // to be updated every time that TLS_EX_SESS_TICKET_VERSION is changed. But
+ // we don't use the #define. That way, any time that code is updated, this
+ // test will fail unless it is manually checked.
+ uint32_t ticket_version;
+ EXPECT_TRUE(filter->buffer().Read(offset, 2, &ticket_version));
+ EXPECT_EQ(0x010aU, ticket_version);
+ offset += 2;
+
// Check the protocol version number.
uint32_t tls_version = 0;
EXPECT_TRUE(filter->buffer().Read(offset, sizeof(version_), &tls_version));
EXPECT_EQ(version_, static_cast<decltype(version_)>(tls_version));
+ offset += sizeof(version_);
// Check the cipher suite.
uint32_t suite = 0;
- EXPECT_TRUE(filter->buffer().Read(offset + sizeof(version_), 2, &suite));
+ EXPECT_TRUE(filter->buffer().Read(offset, 2, &suite));
client_->CheckCipherSuite(static_cast<uint16_t>(suite));
}
+
+INSTANTIATE_TEST_CASE_P(
+ FuzzStream, TlsFuzzTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsVAll));
+INSTANTIATE_TEST_CASE_P(
+ FuzzDatagram, TlsFuzzTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
+ TlsConnectTestBase::kTlsV11Plus));
}
diff --git a/gtests/ssl_gtest/ssl_resumption_unittest.cc b/gtests/ssl_gtest/ssl_resumption_unittest.cc
index 264bde67f..22a90f3b2 100644
--- a/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -325,14 +325,17 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicketForget) {
SendReceive();
}
+// Tickets last two days maximum; this is a time longer than that.
+static const PRTime kLongerThanTicketLifetime =
+ 3LL * 24 * 60 * 60 * PR_USEC_PER_SEC;
+
TEST_P(TlsConnectGenericResumption, ConnectWithExpiredTicketAtClient) {
- SSLInt_SetTicketLifetime(1); // one second
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
SendReceive();
- WAIT_(false, 1000);
+ AdvanceTime(kLongerThanTicketLifetime);
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@@ -354,7 +357,6 @@ TEST_P(TlsConnectGenericResumption, ConnectWithExpiredTicketAtClient) {
}
TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) {
- SSLInt_SetTicketLifetime(1); // one second
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
@@ -373,7 +375,7 @@ TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) {
EXPECT_TRUE(capture->captured());
EXPECT_LT(0U, capture->extension().len());
- WAIT_(false, 1000); // Let the ticket expire on the server.
+ AdvanceTime(kLongerThanTicketLifetime);
Handshake();
CheckConnected();
@@ -1109,7 +1111,7 @@ TEST_P(TlsConnectGenericResumption, ReConnectAgainTicket) {
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}
-void CheckGetInfoResult(uint32_t alpnSize, uint32_t earlyDataSize,
+void CheckGetInfoResult(PRTime now, uint32_t alpnSize, uint32_t earlyDataSize,
ScopedCERTCertificate& cert,
ScopedSSLResumptionTokenInfo& token) {
ASSERT_TRUE(cert);
@@ -1125,7 +1127,7 @@ void CheckGetInfoResult(uint32_t alpnSize, uint32_t earlyDataSize,
ASSERT_EQ(earlyDataSize, token->maxEarlyDataSize);
- ASSERT_LT(ssl_TimeUsec(), token->expirationTime);
+ ASSERT_LT(now, token->expirationTime);
}
// The client should generate a new, randomized session_id
@@ -1175,7 +1177,7 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfo) {
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
- CheckGetInfoResult(0, 0, cert, token);
+ CheckGetInfoResult(now(), 0, 0, cert, token);
Handshake();
CheckConnected();
@@ -1183,6 +1185,56 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfo) {
SendReceive();
}
+TEST_P(TlsConnectGenericResumptionToken, RefuseExpiredTicketClient) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ Connect();
+ SendReceive();
+
+ // Move the clock to the expiration time of the ticket.
+ SSLResumptionTokenInfo tokenInfo = {0};
+ ScopedSSLResumptionTokenInfo token(&tokenInfo);
+ client_->GetTokenInfo(token);
+ AdvanceTime(token->expirationTime - now());
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ ExpectResumption(RESUME_TICKET);
+
+ StartConnect();
+ ASSERT_EQ(SECFailure,
+ SSL_SetResumptionToken(client_->ssl_fd(),
+ client_->GetResumptionToken().data(),
+ client_->GetResumptionToken().size()));
+ EXPECT_EQ(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, PORT_GetError());
+}
+
+TEST_P(TlsConnectGenericResumptionToken, RefuseExpiredTicketServer) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ Connect();
+ SendReceive();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ ExpectResumption(RESUME_NONE);
+
+ // Start the handshake and send the ClientHello.
+ StartConnect();
+ ASSERT_EQ(SECSuccess,
+ SSL_SetResumptionToken(client_->ssl_fd(),
+ client_->GetResumptionToken().data(),
+ client_->GetResumptionToken().size()));
+ client_->Handshake();
+
+ // Move the clock to the expiration time of the ticket.
+ SSLResumptionTokenInfo tokenInfo = {0};
+ ScopedSSLResumptionTokenInfo token(&tokenInfo);
+ client_->GetTokenInfo(token);
+ AdvanceTime(token->expirationTime - now());
+
+ Handshake();
+ CheckConnected();
+}
+
TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
@@ -1205,7 +1257,7 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
- CheckGetInfoResult(1, 0, cert, token);
+ CheckGetInfoResult(now(), 1, 0, cert, token);
Handshake();
CheckConnected();
@@ -1216,7 +1268,7 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
EnableAlpn();
- SSLInt_RolloverAntiReplay();
+ RolloverAntiReplay();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->Set0RttEnabled(true);
Connect();
@@ -1240,7 +1292,7 @@ TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
- CheckGetInfoResult(1, 1024, cert, token);
+ CheckGetInfoResult(now(), 1, 1024, cert, token);
ZeroRttSendReceive(true, true);
Handshake();
diff --git a/gtests/ssl_gtest/tls_connect.cc b/gtests/ssl_gtest/tls_connect.cc
index 596da6252..fa3376937 100644
--- a/gtests/ssl_gtest/tls_connect.cc
+++ b/gtests/ssl_gtest/tls_connect.cc
@@ -106,6 +106,10 @@ std::string VersionString(uint16_t version) {
}
}
+// The default anti-replay window for tests. Tests that rely on a different
+// value call SSL_InitAntiReplay directly.
+static PRTime kAntiReplayWindow = 100 * PR_USEC_PER_SEC;
+
TlsConnectTestBase::TlsConnectTestBase(SSLProtocolVariant variant,
uint16_t version)
: variant_(variant),
@@ -203,11 +207,15 @@ void TlsConnectTestBase::RestoreAlgorithmPolicy() {
}
}
+PRTime TlsConnectTestBase::TimeFunc(void* arg) {
+ return *reinterpret_cast<PRTime*>(arg);
+}
+
void TlsConnectTestBase::SetUp() {
SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
SSLInt_ClearSelfEncryptKey();
- SSLInt_SetTicketLifetime(30);
- SSL_SetupAntiReplay(1 * PR_USEC_PER_SEC, 1, 3);
+ now_ = PR_Now();
+ SSL_InitAntiReplay(now_, kAntiReplayWindow, 1, 3);
ClearStats();
SaveAlgorithmPolicy();
Init();
@@ -282,10 +290,13 @@ void TlsConnectTestBase::EnsureTlsSetup() {
: nullptr));
EXPECT_TRUE(client_->EnsureTlsSetup(client_model_ ? client_model_->ssl_fd()
: nullptr));
+ EXPECT_EQ(SECSuccess, SSL_SetTimeFunc(client_->ssl_fd(),
+ TlsConnectTestBase::TimeFunc, &now_));
+ EXPECT_EQ(SECSuccess, SSL_SetTimeFunc(server_->ssl_fd(),
+ TlsConnectTestBase::TimeFunc, &now_));
}
void TlsConnectTestBase::Handshake() {
- EnsureTlsSetup();
client_->SetServerKeyBits(server_->server_key_bits());
client_->Handshake();
server_->Handshake();
@@ -302,16 +313,16 @@ void TlsConnectTestBase::EnableExtendedMasterSecret() {
}
void TlsConnectTestBase::Connect() {
- server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
- client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
+ StartConnect();
client_->MaybeSetResumptionToken();
Handshake();
CheckConnected();
}
void TlsConnectTestBase::StartConnect() {
- server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
- client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
+ EnsureTlsSetup();
+ server_->StartConnect();
+ client_->StartConnect();
}
void TlsConnectTestBase::ConnectWithCipherSuite(uint16_t cipher_suite) {
@@ -679,8 +690,9 @@ void TlsConnectTestBase::SendReceive(size_t total) {
// Do a first connection so we can do 0-RTT on the second one.
void TlsConnectTestBase::SetupForZeroRtt() {
+ // Force rollover of the anti-replay window.
// If we don't do this, then all 0-RTT attempts will be rejected.
- SSLInt_RolloverAntiReplay();
+ RolloverAntiReplay();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
@@ -792,12 +804,20 @@ void TlsConnectTestBase::ShiftDtlsTimers() {
time_shift = time;
}
- if (time_shift == PR_INTERVAL_NO_TIMEOUT) {
- return;
+ if (time_shift != PR_INTERVAL_NO_TIMEOUT) {
+ AdvanceTime(PR_IntervalToMicroseconds(time_shift));
+ EXPECT_EQ(SECSuccess,
+ SSLInt_ShiftDtlsTimers(client_->ssl_fd(), time_shift));
+ EXPECT_EQ(SECSuccess,
+ SSLInt_ShiftDtlsTimers(server_->ssl_fd(), time_shift));
}
+}
+
+void TlsConnectTestBase::AdvanceTime(PRTime time_shift) { now_ += time_shift; }
- EXPECT_EQ(SECSuccess, SSLInt_ShiftDtlsTimers(client_->ssl_fd(), time_shift));
- EXPECT_EQ(SECSuccess, SSLInt_ShiftDtlsTimers(server_->ssl_fd(), time_shift));
+// Advance time by a full anti-replay window.
+void TlsConnectTestBase::RolloverAntiReplay() {
+ AdvanceTime(kAntiReplayWindow);
}
TlsConnectGeneric::TlsConnectGeneric()
diff --git a/gtests/ssl_gtest/tls_connect.h b/gtests/ssl_gtest/tls_connect.h
index 1a6137601..6d74df972 100644
--- a/gtests/ssl_gtest/tls_connect.h
+++ b/gtests/ssl_gtest/tls_connect.h
@@ -48,6 +48,8 @@ class TlsConnectTestBase : public ::testing::Test {
virtual void SetUp();
virtual void TearDown();
+ PRTime now() const { return now_; }
+
// Initialize client and server.
void Init();
// Clear the statistics.
@@ -131,6 +133,8 @@ class TlsConnectTestBase : public ::testing::Test {
// Move the DTLS timers for both endpoints to pop the next timer.
void ShiftDtlsTimers();
+ void AdvanceTime(PRTime time_shift);
+ void RolloverAntiReplay();
void SaveAlgorithmPolicy();
void RestoreAlgorithmPolicy();
@@ -164,10 +168,12 @@ class TlsConnectTestBase : public ::testing::Test {
void CheckResumption(SessionResumptionMode expected);
void CheckExtendedMasterSecret();
void CheckEarlyDataAccepted();
+ static PRTime TimeFunc(void* arg);
bool expect_extended_master_secret_;
bool expect_early_data_accepted_;
bool skip_version_checks_;
+ PRTime now_;
// Track groups and make sure that there are no duplicates.
class DuplicateGroupChecker {
diff --git a/lib/ssl/authcert.c b/lib/ssl/authcert.c
index d05b30a72..737b4e797 100644
--- a/lib/ssl/authcert.c
+++ b/lib/ssl/authcert.c
@@ -20,12 +20,12 @@
#include "sslimpl.h"
/*
- * This callback used by SSL to pull client sertificate upon
+ * This callback used by SSL to pull client certificate upon
* server request
*/
SECStatus
NSS_GetClientAuthData(void *arg,
- PRFileDesc *socket,
+ PRFileDesc *fd,
struct CERTDistNamesStr *caNames,
struct CERTCertificateStr **pRetCert,
struct SECKEYPrivateKeyStr **pRetKey)
@@ -33,10 +33,14 @@ NSS_GetClientAuthData(void *arg,
CERTCertificate *cert = NULL;
SECKEYPrivateKey *privkey = NULL;
char *chosenNickName = (char *)arg; /* CONST */
- void *proto_win = NULL;
SECStatus rv = SECFailure;
- proto_win = SSL_RevealPinArg(socket);
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+ void *proto_win = SSL_RevealPinArg(fd);
+ PRTime now = ssl_Time(ss);
if (chosenNickName) {
cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
@@ -64,7 +68,7 @@ NSS_GetClientAuthData(void *arg,
if (!cert)
continue;
/* Only check unexpired certs */
- if (CERT_CheckCertValidTimes(cert, ssl_TimeUsec(), PR_TRUE) !=
+ if (CERT_CheckCertValidTimes(cert, now, PR_TRUE) !=
secCertTimeValid) {
CERT_DestroyCertificate(cert);
continue;
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index 142c8bccf..0386789a1 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -4841,7 +4841,8 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
* XXX If we've been called from ssl_BeginClientHandshake, then
* this lookup is duplicative and wasteful.
*/
- sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+ sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
+ ss->sec.ci.port, ss->peerID, ss->url);
} else {
sid = NULL;
}
@@ -8578,8 +8579,8 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
ss->sec.ci.peer.pr_s6_addr32[2],
ss->sec.ci.peer.pr_s6_addr32[3]));
if (ssl_sid_lookup) {
- sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sidBytes.data,
- sidBytes.len, ss->dbHandle);
+ sid = (*ssl_sid_lookup)(ssl_Time(ss), &ss->sec.ci.peer,
+ sidBytes.data, sidBytes.len, ss->dbHandle);
} else {
errCode = SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED;
goto loser;
@@ -10276,7 +10277,7 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
* until it has verified the server's Finished message." See the comment in
* ssl3_FinishHandshake for more details.
*/
- ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_TimeUsec();
+ ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_Time(ss);
if (length < 4) {
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
@@ -11584,8 +11585,8 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret)
sid->keaGroup = ssl_grp_none;
}
sid->sigScheme = ss->sec.signatureScheme;
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
- sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
+ sid->lastAccessTime = sid->creationTime = ssl_Time(ss);
+ sid->expirationTime = sid->creationTime + (ssl_ticket_lifetime * PR_USEC_PER_SEC);
sid->localCert = CERT_DupCertificate(ss->sec.localCert);
if (ss->sec.isServer) {
sid->namedCurve = ss->sec.serverCert->namedCurve;
diff --git a/lib/ssl/ssl3exthandle.c b/lib/ssl/ssl3exthandle.c
index e25a8f887..f4b50f8a7 100644
--- a/lib/ssl/ssl3exthandle.c
+++ b/lib/ssl/ssl3exthandle.c
@@ -246,7 +246,7 @@ ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
session_ticket = &sid->u.ssl3.locked.sessionTicket;
if (session_ticket->ticket.data &&
(xtnData->ticketTimestampVerified ||
- ssl_TicketTimeValid(session_ticket))) {
+ ssl_TicketTimeValid(ss, session_ticket))) {
xtnData->ticketTimestampVerified = PR_FALSE;
@@ -608,7 +608,6 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData
return SECSuccess;
}
-PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
#define TLS_EX_SESS_TICKET_VERSION (0x010a)
/*
@@ -742,7 +741,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
}
/* timestamp */
- now = ssl_TimeUsec();
+ now = ssl_Time(ss);
PORT_Assert(sizeof(now) == 8);
rv = sslBuffer_AppendNumber(&plaintext, now, 8);
if (rv != SECSuccess)
@@ -797,7 +796,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
* This is compared to the expected time, which should differ only as a
* result of clock errors or errors in the RTT estimate.
*/
- ticketAgeBaseline = (ssl_TimeUsec() - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
+ ticketAgeBaseline = (ssl_Time(ss) - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
ticketAgeBaseline -= ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(&plaintext, ticketAgeBaseline, 4);
if (rv != SECSuccess)
@@ -1242,8 +1241,8 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
}
/* Use the ticket if it is valid and unexpired. */
- if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC >
- ssl_TimeUsec()) {
+ PRTime end = parsedTicket.timestamp + (ssl_ticket_lifetime * PR_USEC_PER_SEC);
+ if (end > ssl_Time(ss)) {
rv = ssl_CreateSIDFromTicket(ss, ticket, &parsedTicket, &sid);
if (rv != SECSuccess) {
diff --git a/lib/ssl/sslcon.c b/lib/ssl/sslcon.c
index 603da3e15..ed733bffb 100644
--- a/lib/ssl/sslcon.c
+++ b/lib/ssl/sslcon.c
@@ -155,8 +155,8 @@ ssl_BeginClientHandshake(sslSocket *ss)
SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
} else if (!ss->opt.noCache) {
/* Try to find server in our session-id cache */
- sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
- ss->url);
+ sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
+ ss->sec.ci.port, ss->peerID, ss->url);
}
if (sid) {
@@ -170,25 +170,15 @@ ssl_BeginClientHandshake(sslSocket *ss)
}
}
if (!sid) {
- sid = PORT_ZNew(sslSessionID);
+ sid = ssl3_NewSessionID(ss, PR_FALSE);
if (!sid) {
goto loser;
}
- sid->references = 1;
- sid->cached = never_cached;
- sid->addr = ss->sec.ci.peer;
- sid->port = ss->sec.ci.port;
- if (ss->peerID != NULL) {
- sid->peerID = PORT_Strdup(ss->peerID);
- }
- if (ss->url != NULL) {
- sid->urlSvrName = PORT_Strdup(ss->url);
- }
+ /* This session is a dummy, which we don't want to resume. */
+ sid->u.ssl3.keys.resumable = PR_FALSE;
}
ss->sec.ci.sid = sid;
- PORT_Assert(sid != NULL);
-
ss->gs.state = GS_INIT;
ss->handshake = ssl_GatherRecord1stHandshake;
diff --git a/lib/ssl/sslexp.h b/lib/ssl/sslexp.h
index d8f050ea5..a1ef52736 100644
--- a/lib/ssl/sslexp.h
+++ b/lib/ssl/sslexp.h
@@ -159,7 +159,7 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
handler, handlerArg))
/*
- * Setup the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers.
+ * Initialize the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers.
*
* To use 0-RTT on a server, you must call this function. Failing to call this
* function will result in all 0-RTT being rejected. Connections will complete,
@@ -181,11 +181,11 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
* The first tuning parameter to consider is |window|, which determines the
* window over which ClientHello messages will be tracked. This also causes
* early data to be rejected if a ClientHello contains a ticket age parameter
- * that is outside of this window (see Section 4.2.10.4 of
- * draft-ietf-tls-tls13-20 for details). Set |window| to account for any
- * potential sources of clock error. |window| is the entire width of the
- * window, which is symmetrical. Therefore to allow 5 seconds of clock error in
- * both directions, set the value to 10 seconds (i.e., 10 * PR_USEC_PER_SEC).
+ * that is outside of this window (see Section 8.3 of RFC 8446 for details).
+ * Set |window| to account for any potential sources of clock error. |window|
+ * is the entire width of the window, which is symmetrical. Therefore to allow
+ * 5 seconds of clock error in both directions, set the value to 10 seconds
+ * (i.e., 10 * PR_USEC_PER_SEC).
*
* After calling this function, early data will be rejected until |window|
* elapses. This prevents replay across crashes and restarts. Only call this
@@ -219,10 +219,11 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
* Early data can be replayed at least once with every server instance that will
* accept tickets that are encrypted with the same key.
*/
-#define SSL_SetupAntiReplay(window, k, bits) \
- SSL_EXPERIMENTAL_API("SSL_SetupAntiReplay", \
- (PRTime _window, unsigned int _k, unsigned int _bits), \
- (window, k, bits))
+#define SSL_InitAntiReplay(now, window, k, bits) \
+ SSL_EXPERIMENTAL_API("SSL_InitAntiReplay", \
+ (PRTime _now, PRTime _window, \
+ unsigned int _k, unsigned int _bits), \
+ (now, window, k, bits))
/*
* This function allows a server application to generate a session ticket that
@@ -723,8 +724,20 @@ typedef struct SSLAeadContextStr SSLAeadContext;
hsHash, hsHashLen, label, labelLen, \
mech, keySize, keyp))
+/* SSL_SetTimeFunc overrides the default time function (PR_Now()) and provides
+ * an alternative source of time for the socket. This is used in testing, and in
+ * applications that need better control over how the clock is accessed. Set the
+ * function to NULL to use PR_Now().*/
+typedef PRTime(PR_CALLBACK *SSLTimeFunc)(void *arg);
+
+#define SSL_SetTimeFunc(fd, f, arg) \
+ SSL_EXPERIMENTAL_API("SSL_SetTimeFunc", \
+ (PRFileDesc * _fd, SSLTimeFunc _f, void *_arg), \
+ (fd, f, arg))
+
/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
+#define SSL_SetupAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index a9b766290..8c472580b 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -183,10 +183,11 @@ typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
void ssl_CacheSessionID(sslSocket *ss);
void ssl_UncacheSessionID(sslSocket *ss);
-void ssl_ServerCacheSessionID(sslSessionID *sid);
+void ssl_ServerCacheSessionID(sslSessionID *sid, PRTime creationTime);
void ssl_ServerUncacheSessionID(sslSessionID *sid);
-typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
+typedef sslSessionID *(*sslSessionIDLookupFunc)(PRTime ssl_now,
+ const PRIPv6Addr *addr,
unsigned char *sid,
unsigned int sidLen,
CERTCertDBHandle *dbHandle);
@@ -946,6 +947,10 @@ struct sslSocketStr {
/* Enabled version range */
SSLVersionRange vrange;
+ /* A function that returns the current time. */
+ SSLTimeFunc now;
+ void *nowArg;
+
/* State flags */
unsigned long clientAuthRequested;
unsigned long delayDisabled; /* Nagle delay disabled */
@@ -1104,8 +1109,7 @@ extern char ssl_trace;
extern FILE *ssl_trace_iob;
extern FILE *ssl_keylog_iob;
extern PZLock *ssl_keylog_lock;
-extern PRUint32 ssl3_sid_timeout;
-extern PRUint32 ssl_ticket_lifetime;
+static const PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; // 2 days.
extern const char *const ssl3_cipherName[];
@@ -1195,8 +1199,9 @@ extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
PRBool derive);
extern void ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
-extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
- const char *peerID, const char *urlSvrName);
+extern sslSessionID *ssl_LookupSID(PRTime now, const PRIPv6Addr *addr,
+ PRUint16 port, const char *peerID,
+ const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt);
extern sslSessionID *ssl_ReferenceSID(sslSessionID *sid);
@@ -1606,8 +1611,8 @@ PRBool ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
/* calls for accessing wrapping keys across processes. */
extern SECStatus
-ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex,
- SSLWrappedSymWrappingKey *wswk);
+ssl_GetWrappingKey(unsigned int symWrapMechIndex,
+ unsigned int wrapKeyIndex, SSLWrappedSymWrappingKey *wswk);
/* The caller passes in the new value it wants
* to set. This code tests the wrapped sym key entry in the file on disk.
@@ -1719,13 +1724,8 @@ extern void ssl3_CheckCipherSuiteOrderConsistency();
extern int ssl_MapLowLevelError(int hiLevelError);
-extern PRUint32 ssl_TimeSec(void);
-#ifdef UNSAFE_FUZZER_MODE
-#define ssl_TimeUsec() ((PRTime)12345678)
-#else
-#define ssl_TimeUsec() (PR_Now())
-#endif
-extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket);
+PRTime ssl_Time(const sslSocket *ss);
+PRBool ssl_TicketTimeValid(const sslSocket *ss, const NewSessionTicket *ticket);
extern void SSL_AtomicIncrementLong(long *x);
@@ -1763,7 +1763,7 @@ PK11SymKey *ssl_unwrapSymKey(PK11SymKey *wrapKey,
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
int keySize, CK_FLAGS keyFlags, void *pinArg);
-/* Remove when stable. */
+/* Experimental APIs. Remove when stable. */
SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
SSLResumptionTokenCallback cb,
@@ -1815,6 +1815,8 @@ SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKe
CK_MECHANISM_TYPE mech, unsigned int keySize,
PK11SymKey **keyp);
+SECStatus SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg);
+
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
diff --git a/lib/ssl/sslnonce.c b/lib/ssl/sslnonce.c
index f8fb5d50f..b7b5b7fe5 100644
--- a/lib/ssl/sslnonce.c
+++ b/lib/ssl/sslnonce.c
@@ -20,8 +20,6 @@
#include <time.h>
#endif
-PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
-
static sslSessionID *cache = NULL;
static PZLock *cacheLock = NULL;
@@ -259,30 +257,28 @@ ssl_ReferenceSID(sslSessionID *sid)
*/
sslSessionID *
-ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
+ssl_LookupSID(PRTime now, const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
const char *urlSvrName)
{
sslSessionID **sidp;
sslSessionID *sid;
- PRUint32 now;
if (!urlSvrName)
return NULL;
- now = ssl_TimeSec();
LOCK_CACHE;
sidp = &cache;
while ((sid = *sidp) != 0) {
PORT_Assert(sid->cached == in_client_cache);
PORT_Assert(sid->references >= 1);
- SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
+ SSL_TRC(8, ("SSL: lookup: sid=0x%x", sid));
if (sid->expirationTime < now) {
/*
** This session-id timed out.
** Don't even care who it belongs to, blow it out of our cache.
*/
- SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
+ SSL_TRC(7, ("SSL: lookup, throwing sid out, age=%d refs=%d",
now - sid->creationTime, sid->references));
*sidp = sid->next; /* delink it from the list. */
@@ -316,7 +312,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
** Although this is static, it is called via ss->sec.cache().
*/
static void
-CacheSID(sslSessionID *sid)
+CacheSID(sslSessionID *sid, PRTime creationTime)
{
PORT_Assert(sid);
PORT_Assert(sid->cached == never_cached);
@@ -353,11 +349,16 @@ CacheSID(sslSessionID *sid)
if (!sid->u.ssl3.lock) {
return;
}
- PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
- if (!sid->creationTime)
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
- if (!sid->expirationTime)
- sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
+ PORT_Assert(sid->creationTime != 0);
+ if (!sid->creationTime) {
+ sid->lastAccessTime = sid->creationTime = creationTime;
+ }
+ PORT_Assert(sid->expirationTime != 0);
+ if (!sid->expirationTime) {
+ sid->expirationTime = sid->creationTime + (PR_MIN(ssl_ticket_lifetime,
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint) *
+ PR_USEC_PER_SEC);
+ }
/*
* Put sid into the cache. Bump reference count to indicate that
@@ -726,13 +727,13 @@ ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid)
if (ticket->ticket_lifetime_hint != 0) {
endTime = ticket->received_timestamp +
(PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
- if (endTime < ssl_TimeUsec()) {
+ if (endTime <= ssl_Time(ss)) {
return PR_FALSE;
}
}
// Check that the session entry didn't expire.
- if (sid->expirationTime < ssl_TimeUsec()) {
+ if (sid->expirationTime < ssl_Time(ss)) {
return PR_FALSE;
}
@@ -1087,10 +1088,12 @@ ssl_CacheExternalToken(sslSocket *ss)
}
if (!sid->creationTime) {
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+ sid->lastAccessTime = sid->creationTime = ssl_Time(ss);
}
if (!sid->expirationTime) {
- sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
+ sid->expirationTime = sid->creationTime + (PR_MIN(ssl_ticket_lifetime,
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint) *
+ PR_USEC_PER_SEC);
}
sslBuffer encodedToken = SSL_BUFFER_EMPTY;
@@ -1129,11 +1132,11 @@ ssl_CacheSessionID(sslSocket *ss)
PORT_Assert(!ss->resumptionTokenCallback);
if (sec->isServer) {
- ssl_ServerCacheSessionID(sec->ci.sid);
+ ssl_ServerCacheSessionID(sec->ci.sid, ssl_Time(ss));
return;
}
- CacheSID(sec->ci.sid);
+ CacheSID(sec->ci.sid, ssl_Time(ss));
}
void
@@ -1165,32 +1168,8 @@ SSL_ClearSessionCache(void)
UNLOCK_CACHE;
}
-/* returns an unsigned int containing the number of seconds in PR_Now() */
-PRUint32
-ssl_TimeSec(void)
-{
-#ifdef UNSAFE_FUZZER_MODE
- return 1234;
-#endif
-
- PRUint32 myTime;
-#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
- myTime = time(NULL); /* accurate until the year 2038. */
-#else
- /* portable, but possibly slower */
- PRTime now;
- PRInt64 ll;
-
- now = PR_Now();
- LL_I2L(ll, 1000000L);
- LL_DIV(now, now, ll);
- LL_L2UI(myTime, now);
-#endif
- return myTime;
-}
-
PRBool
-ssl_TicketTimeValid(const NewSessionTicket *ticket)
+ssl_TicketTimeValid(const sslSocket *ss, const NewSessionTicket *ticket)
{
PRTime endTime;
@@ -1200,7 +1179,7 @@ ssl_TicketTimeValid(const NewSessionTicket *ticket)
endTime = ticket->received_timestamp +
(PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
- return endTime > ssl_TimeUsec();
+ return endTime > ssl_Time(ss);
}
void
diff --git a/lib/ssl/sslsnce.c b/lib/ssl/sslsnce.c
index d7abb3dc3..75402a780 100644
--- a/lib/ssl/sslsnce.c
+++ b/lib/ssl/sslsnce.c
@@ -276,14 +276,24 @@ typedef struct inheritanceStr inheritance;
/************************************************************************/
+/* This is used to set locking times for the cache. It is not used to set the
+ * PRTime attributes of sessions, which are driven by ss->now(). */
+static PRUint32
+ssl_CacheNow()
+{
+ return PR_Now() / PR_USEC_PER_SEC;
+}
+
static PRUint32
LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
{
SECStatus rv = sslMutex_Lock(&lock->mutex);
if (rv != SECSuccess)
return 0;
- if (!now)
- now = ssl_TimeSec();
+ if (!now) {
+ now = ssl_CacheNow();
+ }
+
lock->timeStamp = now;
lock->pid = myPid;
return now;
@@ -299,7 +309,7 @@ UnlockSidCacheLock(sidCacheLock *lock)
return rv;
}
-/* returns the value of ssl_TimeSec on success, zero on failure. */
+/* Returns non-zero |now| or ssl_CacheNow() on success, zero on failure. */
static PRUint32
LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
{
@@ -630,9 +640,12 @@ FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
/* This is the primary function for finding entries in the server's sid cache.
* Although it is static, this function is called via the global function
* pointer ssl_sid_lookup.
+ *
+ * sslNow is the time that the calling socket understands, which might be
+ * different than what the cache uses to maintain its locks.
*/
static sslSessionID *
-ServerSessionIDLookup(const PRIPv6Addr *addr,
+ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
unsigned char *sessionID,
unsigned int sessionIDLength,
CERTCertDBHandle *dbHandle)
@@ -712,7 +725,7 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
}
}
if (psce) {
- psce->lastAccessTime = now;
+ psce->lastAccessTime = sslNow;
sce = *psce; /* grab a copy while holding the lock */
}
}
@@ -730,7 +743,7 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
** Place a sid into the cache, if it isn't already there.
*/
void
-ssl_ServerCacheSessionID(sslSessionID *sid)
+ssl_ServerCacheSessionID(sslSessionID *sid, PRTime creationTime)
{
PORT_Assert(sid);
@@ -748,7 +761,7 @@ ssl_ServerCacheSessionID(sslSessionID *sid)
PORT_Assert(sid->creationTime != 0);
if (!sid->creationTime)
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+ sid->lastAccessTime = sid->creationTime = creationTime;
/* override caller's expiration time, which uses client timeout
* duration, not server timeout duration.
*/
@@ -1089,7 +1102,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData);
/* initialize the locks */
- init_time = ssl_TimeSec();
+ init_time = ssl_CacheNow();
pLock = cache->sidCacheLocks;
for (locks_to_initialize = cache->numSIDCacheLocks + 3;
locks_initialized < locks_to_initialize;
@@ -1518,7 +1531,7 @@ LockPoller(void *arg)
if (sharedCache->stopPolling)
break;
- now = ssl_TimeSec();
+ now = ssl_CacheNow();
then = now - expiration;
for (pLock = cache->sidCacheLocks, locks_polled = 0;
locks_to_poll > locks_polled && !sharedCache->stopPolling;
diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
index 96b963bc2..802ef6714 100644
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -277,6 +277,8 @@ ssl_DupSocket(sslSocket *os)
goto loser;
}
ss->vrange = os->vrange;
+ ss->now = os->now;
+ ss->nowArg = os->nowArg;
ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
ss->url = !os->url ? NULL : PORT_Strdup(os->url);
@@ -2215,6 +2217,8 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
ss->opt = sm->opt;
ss->vrange = sm->vrange;
+ ss->now = sm->now;
+ ss->nowArg = sm->nowArg;
PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites);
PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, sm->ssl3.dtlsSRTPCiphers,
sizeof(PRUint16) * sm->ssl3.dtlsSRTPCipherCount);
@@ -3902,6 +3906,15 @@ ssl_FreeEphemeralKeyPairs(sslSocket *ss)
}
}
+PRTime
+ssl_Time(const sslSocket *ss)
+{
+ if (!ss->now) {
+ return PR_Now();
+ }
+ return ss->now(ss->nowArg);
+}
+
/*
** Create a newsocket structure for a file descriptor.
*/
@@ -3917,7 +3930,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
makeLocks = PR_TRUE;
/* Make a new socket and get it ready */
- ss = (sslSocket *)PORT_ZAlloc(sizeof(sslSocket));
+ ss = PORT_ZNew(sslSocket);
if (!ss) {
return NULL;
}
@@ -4051,6 +4064,7 @@ struct {
EXP(GetExtensionSupport),
EXP(GetResumptionTokenInfo),
EXP(HelloRetryRequestCallback),
+ EXP(InitAntiReplay),
EXP(InstallExtensionHooks),
EXP(HkdfExtract),
EXP(HkdfExpandLabel),
@@ -4066,7 +4080,7 @@ struct {
EXP(SetMaxEarlyDataSize),
EXP(SetResumptionTokenCallback),
EXP(SetResumptionToken),
- EXP(SetupAntiReplay),
+ EXP(SetTimeFunc),
#endif
{ "", NULL }
};
@@ -4102,6 +4116,21 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *))
}
}
+SECStatus
+SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTimeFunc",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ ss->now = f;
+ ss->nowArg = arg;
+ return SECSuccess;
+}
+
/* Experimental APIs for session cache handling. */
SECStatus
@@ -4185,7 +4214,7 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
/* Use the sid->cached as marker that this is from an external cache and
* we don't have to look up anything in the NSS internal cache. */
sid->cached = in_external_cache;
- sid->lastAccessTime = ssl_TimeSec();
+ sid->lastAccessTime = ssl_Time(ss);
ss->sec.ci.sid = sid;
diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c
index 19397d5c3..16f0b35bb 100644
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -479,7 +479,7 @@ tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType)
session_ticket = &sid->u.ssl3.locked.sessionTicket;
PORT_Assert(session_ticket && session_ticket->ticket.data);
- if (ssl_TicketTimeValid(session_ticket)) {
+ if (ssl_TicketTimeValid(ss, session_ticket)) {
ss->statelessResume = PR_TRUE;
}
@@ -2724,7 +2724,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
}
- ss->ssl3.hs.serverHelloTime = ssl_TimeUsec();
+ ss->ssl3.hs.serverHelloTime = ssl_Time(ss);
return SECSuccess;
}
@@ -4981,7 +4981,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- ticket.received_timestamp = ssl_TimeUsec();
+ ticket.received_timestamp = ssl_Time(ss);
rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
&length);
if (rv != SECSuccess) {
diff --git a/lib/ssl/tls13con.h b/lib/ssl/tls13con.h
index 668d9aad2..d634f4b84 100644
--- a/lib/ssl/tls13con.h
+++ b/lib/ssl/tls13con.h
@@ -117,8 +117,8 @@ PRBool tls13_ShouldRequestClientAuth(sslSocket *ss);
PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid);
void tls13_AntiReplayRollover(PRTime now);
-SECStatus SSLExp_SetupAntiReplay(PRTime window, unsigned int k,
- unsigned int bits);
+SECStatus SSLExp_InitAntiReplay(PRTime now, PRTime window, unsigned int k,
+ unsigned int bits);
SECStatus SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
SSLHelloRetryRequestCallback cb,
diff --git a/lib/ssl/tls13exthandle.c b/lib/ssl/tls13exthandle.c
index 9def16d41..9d7c50efb 100644
--- a/lib/ssl/tls13exthandle.c
+++ b/lib/ssl/tls13exthandle.c
@@ -448,7 +448,7 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
goto loser;
/* Obfuscated age. */
- age = ssl_TimeUsec() - session_ticket->received_timestamp;
+ age = ssl_Time(ss) - session_ticket->received_timestamp;
age /= PR_USEC_PER_MSEC;
age += session_ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(buf, age, 4);
diff --git a/lib/ssl/tls13replay.c b/lib/ssl/tls13replay.c
index b090f9bca..2770be761 100644
--- a/lib/ssl/tls13replay.c
+++ b/lib/ssl/tls13replay.c
@@ -109,7 +109,7 @@ loser:
* memory barrier between the setup and use of this function.
*/
SECStatus
-SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits)
+SSLExp_InitAntiReplay(PRTime now, PRTime window, unsigned int k, unsigned int bits)
{
SECStatus rv;
@@ -153,7 +153,7 @@ SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits)
sslBloom_Fill(&ssl_anti_replay.filters[1]);
ssl_anti_replay.current = 0;
- ssl_anti_replay.nextUpdate = ssl_TimeUsec() + window;
+ ssl_anti_replay.nextUpdate = now + window;
ssl_anti_replay.window = window;
return SECSuccess;
@@ -162,29 +162,15 @@ loser:
return SECFailure;
}
-/* This is exposed to tests. Though it could, this doesn't take the lock on the
- * basis that those tests use thread confinement. */
-void
-tls13_AntiReplayRollover(PRTime now)
-{
- ssl_anti_replay.current ^= 1;
- ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window;
- sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current);
-}
-
static void
-tls13_AntiReplayUpdate()
+tls13_AntiReplayUpdate(PRTime now)
{
- PRTime now;
-
PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ssl_anti_replay.lock);
-
- now = ssl_TimeUsec();
- if (now < ssl_anti_replay.nextUpdate) {
- return;
+ if (now >= ssl_anti_replay.nextUpdate) {
+ ssl_anti_replay.current ^= 1;
+ ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window;
+ sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current);
}
-
- tls13_AntiReplayRollover(now);
}
PRBool
@@ -197,7 +183,7 @@ tls13_InWindow(const sslSocket *ss, const sslSessionID *sid)
* calculate. The result should be close to zero. timeDelta is signed to
* make the comparisons below easier. */
timeDelta = ss->xtnData.ticketAge -
- ((ssl_TimeUsec() - sid->creationTime) / PR_USEC_PER_MSEC);
+ ((ssl_Time(ss) - sid->creationTime) / PR_USEC_PER_MSEC);
/* Only allow the time delta to be at most half of our window. This is
* symmetrical, though it doesn't need to be; this assumes that clock errors
@@ -221,7 +207,7 @@ tls13_InWindow(const sslSocket *ss, const sslSessionID *sid)
* prevent the same 0-RTT attempt from being accepted during window 1 and
* later window 3.
*/
- return PR_ABS(timeDelta) < (ssl_anti_replay.window / 2);
+ return PR_ABS(timeDelta) < (ssl_anti_replay.window / (PR_USEC_PER_MSEC * 2));
}
/* Checks for a duplicate in the two filters we have. Performs maintenance on
@@ -262,13 +248,12 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
}
PZ_EnterMonitor(ssl_anti_replay.lock);
- tls13_AntiReplayUpdate();
+ tls13_AntiReplayUpdate(ssl_Time(ss));
index = ssl_anti_replay.current;
replay = sslBloom_Add(&ssl_anti_replay.filters[index], buf);
if (!replay) {
- replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1],
- buf);
+ replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1], buf);
}
PZ_ExitMonitor(ssl_anti_replay.lock);