summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc')
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc190
1 files changed, 167 insertions, 23 deletions
diff --git a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
index 264bde67f..bfc3ccfeb 100644
--- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/security/nss/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();
@@ -421,6 +423,7 @@ static int32_t SwitchCertificates(TlsAgent* agent, const SECItem* srvNameArr,
TEST_P(TlsConnectGeneric, ServerSNICertSwitch) {
Connect();
ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
+ ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
@@ -429,6 +432,7 @@ TEST_P(TlsConnectGeneric, ServerSNICertSwitch) {
Connect();
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
+ ASSERT_NE(nullptr, cert2.get());
CheckKeys();
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@@ -437,6 +441,7 @@ TEST_P(TlsConnectGeneric, ServerSNICertTypeSwitch) {
Reset(TlsAgent::kServerEcdsa256);
Connect();
ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
+ ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
@@ -447,6 +452,7 @@ TEST_P(TlsConnectGeneric, ServerSNICertTypeSwitch) {
Connect();
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
+ ASSERT_NE(nullptr, cert2.get());
CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@@ -531,6 +537,7 @@ TEST_P(TlsConnectTls13, TestTls13ResumeNoCertificateRequest) {
Connect();
SendReceive(); // Need to read so that we absorb the session ticket.
ScopedCERTCertificate cert1(SSL_LocalCertificate(client_->ssl_fd()));
+ ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@@ -546,6 +553,7 @@ TEST_P(TlsConnectTls13, TestTls13ResumeNoCertificateRequest) {
// Sanity check whether the client certificate matches the one
// decrypted from ticket.
ScopedCERTCertificate cert2(SSL_PeerCertificate(server_->ssl_fd()));
+ ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@@ -561,6 +569,7 @@ TEST_P(TlsConnectTls13, WriteBeforeHandshakeCompleteOnResumption) {
Connect();
SendReceive(); // Absorb the session ticket.
ScopedCERTCertificate cert1(SSL_LocalCertificate(client_->ssl_fd()));
+ ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@@ -577,6 +586,7 @@ TEST_P(TlsConnectTls13, WriteBeforeHandshakeCompleteOnResumption) {
// Check whether the client certificate matches the one from the ticket.
ScopedCERTCertificate cert2(SSL_PeerCertificate(server_->ssl_fd()));
+ ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@@ -589,15 +599,17 @@ static uint16_t ChooseOneCipher(uint16_t version) {
return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
}
-static uint16_t ChooseAnotherCipher(uint16_t version) {
+static uint16_t ChooseIncompatibleCipher(uint16_t version) {
if (version >= SSL_LIBRARY_VERSION_TLS_1_3) {
return TLS_AES_256_GCM_SHA384;
}
return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
}
-// Test that we don't resume when we can't negotiate the same cipher.
-TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
+// Test that we don't resume when we can't negotiate the same cipher. Note that
+// for TLS 1.3, resumption is allowed between compatible ciphers, that is those
+// with the same KDF hash, but we choose an incompatible one here.
+TEST_P(TlsConnectGenericResumption, ResumeClientIncompatibleCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
client_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
@@ -607,7 +619,7 @@ TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_NONE);
- client_->EnableSingleCipher(ChooseAnotherCipher(version_));
+ client_->EnableSingleCipher(ChooseIncompatibleCipher(version_));
uint16_t ticket_extension;
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
ticket_extension = ssl_tls13_pre_shared_key_xtn;
@@ -622,24 +634,24 @@ TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
}
// Test that we don't resume when we can't negotiate the same cipher.
-TEST_P(TlsConnectGenericResumption, TestResumeServerDifferentCipher) {
+TEST_P(TlsConnectGenericResumption, ResumeServerIncompatibleCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
- SendReceive(); // Need to read so that we absorb the session ticket.
+ SendReceive(); // Absorb the session ticket.
CheckKeys();
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_NONE);
- server_->EnableSingleCipher(ChooseAnotherCipher(version_));
+ server_->EnableSingleCipher(ChooseIncompatibleCipher(version_));
Connect();
CheckKeys();
}
// Test that the client doesn't tolerate the server picking a different cipher
// suite for resumption.
-TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
+TEST_P(TlsConnectStream, ResumptionOverrideCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
@@ -648,8 +660,8 @@ TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
- MakeTlsFilter<SelectedCipherSuiteReplacer>(server_,
- ChooseAnotherCipher(version_));
+ MakeTlsFilter<SelectedCipherSuiteReplacer>(
+ server_, ChooseIncompatibleCipher(version_));
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
@@ -668,6 +680,38 @@ TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
}
}
+// In TLS 1.3, it is possible to resume with a different cipher if it has the
+// same hash.
+TEST_P(TlsConnectTls13, ResumeClientCompatibleCipher) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+ Connect();
+ SendReceive(); // Absorb the session ticket.
+ CheckKeys();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_TICKET);
+ client_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
+ Connect();
+ CheckKeys();
+}
+
+TEST_P(TlsConnectTls13, ResumeServerCompatibleCipher) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+ Connect();
+ SendReceive(); // Absorb the session ticket.
+ CheckKeys();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_TICKET);
+ server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
+ Connect();
+ CheckKeys();
+}
+
class SelectedVersionReplacer : public TlsHandshakeFilter {
public:
SelectedVersionReplacer(const std::shared_ptr<TlsAgent>& a, uint16_t version)
@@ -757,7 +801,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
ASSERT_LT(0U, initialTicket.len());
ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
- ASSERT_TRUE(!!cert1.get());
+ ASSERT_NE(nullptr, cert1.get());
Reset();
ClearStats();
@@ -773,7 +817,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
ASSERT_LT(0U, c2->extension().len());
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
- ASSERT_TRUE(!!cert2.get());
+ ASSERT_NE(nullptr, cert2.get());
// Check that the cipher suite is reported the same on both sides, though in
// TLS 1.3 resumption actually negotiates a different cipher suite.
@@ -1109,7 +1153,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 +1169,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
@@ -1174,8 +1218,9 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfo) {
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
+ ASSERT_NE(nullptr, cert.get());
- CheckGetInfoResult(0, 0, cert, token);
+ CheckGetInfoResult(now(), 0, 0, cert, token);
Handshake();
CheckConnected();
@@ -1183,6 +1228,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);
@@ -1204,8 +1299,9 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
+ ASSERT_NE(nullptr, cert.get());
- CheckGetInfoResult(1, 0, cert, token);
+ CheckGetInfoResult(now(), 1, 0, cert, token);
Handshake();
CheckConnected();
@@ -1216,7 +1312,7 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
EnableAlpn();
- SSLInt_RolloverAntiReplay();
+ RolloverAntiReplay();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->Set0RttEnabled(true);
Connect();
@@ -1239,8 +1335,8 @@ TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
-
- CheckGetInfoResult(1, 1024, cert, token);
+ ASSERT_NE(nullptr, cert.get());
+ CheckGetInfoResult(now(), 1, 1024, cert, token);
ZeroRttSendReceive(true, true);
Handshake();
@@ -1272,6 +1368,54 @@ TEST_P(TlsConnectGenericResumption, ConnectResumeClientAuth) {
SendReceive();
}
+// Check that resumption is blocked if the server requires client auth.
+TEST_P(TlsConnectGenericResumption, ClientAuthRequiredOnResumption) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ server_->RequestClientAuth(false);
+ Connect();
+ SendReceive();
+
+ Reset();
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(true);
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ ExpectResumption(RESUME_NONE);
+ Connect();
+ SendReceive();
+}
+
+// Check that resumption is blocked if the server requires client auth and
+// the client fails to provide a certificate.
+TEST_P(TlsConnectGenericResumption, ClientAuthRequiredOnResumptionNoCert) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ server_->RequestClientAuth(false);
+ Connect();
+ SendReceive();
+
+ Reset();
+ server_->RequestClientAuth(true);
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ // Drive handshake manually because TLS 1.3 needs it.
+ StartConnect();
+ client_->Handshake(); // CH
+ server_->Handshake(); // SH.. (no resumption)
+ client_->Handshake(); // ...
+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ // In TLS 1.3, the client thinks that everything is OK here.
+ ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+ ExpectAlert(server_, kTlsAlertCertificateRequired);
+ server_->Handshake(); // Alert
+ client_->Handshake(); // Receive Alert
+ client_->CheckErrorCode(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT);
+ } else {
+ ExpectAlert(server_, kTlsAlertBadCertificate);
+ server_->Handshake(); // Alert
+ client_->Handshake(); // Receive Alert
+ client_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
+ }
+ server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
+}
+
TEST_F(TlsConnectStreamTls13, ExternalTokenAfterHrr) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();