Update NSS to 3.48 while keeping vc2013 hackfix and no-sslkeylogfile intact.

This commit is contained in:
Roy Tam 2020-01-03 13:36:26 +08:00
commit 171849c8e5
351 changed files with 115185 additions and 57946 deletions

View file

@ -12,6 +12,48 @@
#include "seccomon.h"
#include "selfencrypt.h"
SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
PRBool changeScheme) {
if (!fd) {
return SECFailure;
}
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
// Just toggle so we'll always have a valid value.
if (changeScheme) {
ss->sec.signatureScheme = (ss->sec.signatureScheme == ssl_sig_ed25519)
? ssl_sig_ecdsa_secp256r1_sha256
: ssl_sig_ed25519;
}
if (changeAuthKeyBits) {
ss->sec.authKeyBits = ss->sec.authKeyBits ? ss->sec.authKeyBits * 2 : 384;
}
return SECSuccess;
}
SECStatus SSLInt_GetHandshakeRandoms(PRFileDesc *fd, SSL3Random client_random,
SSL3Random server_random) {
if (!fd) {
return SECFailure;
}
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
if (client_random) {
memcpy(client_random, ss->ssl3.hs.client_random, sizeof(SSL3Random));
}
if (server_random) {
memcpy(server_random, ss->ssl3.hs.server_random, sizeof(SSL3Random));
}
return SECSuccess;
}
SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd) {
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
@ -109,9 +151,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 +340,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 +363,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) {

View file

@ -20,7 +20,8 @@ SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd);
SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd,
size_t rnd_len, uint8_t *msg,
size_t msg_len);
SECStatus SSLInt_GetHandshakeRandoms(PRFileDesc *fd, SSL3Random client_random,
SSL3Random server_random);
PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext);
void SSLInt_ClearSelfEncryptKey();
void SSLInt_SetSelfEncryptMacKey(PK11SymKey *key);
@ -40,8 +41,8 @@ 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);
SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
PRBool changeScheme);
#endif // ndef libssl_internals_h_

View file

@ -17,9 +17,11 @@ CPPSRCS = \
ssl_agent_unittest.cc \
ssl_auth_unittest.cc \
ssl_cert_ext_unittest.cc \
ssl_cipherorder_unittest.cc \
ssl_ciphersuite_unittest.cc \
ssl_custext_unittest.cc \
ssl_damage_unittest.cc \
ssl_debug_env_unittest.cc \
ssl_dhe_unittest.cc \
ssl_drop_unittest.cc \
ssl_ecdh_unittest.cc \
@ -53,6 +55,7 @@ CPPSRCS = \
tls_hkdf_unittest.cc \
tls_filter.cc \
tls_protect.cc \
tls_subcerts_unittest.cc \
tls_esni_unittest.cc \
$(SSLKEYLOGFILE_FILES) \
$(NULL)

View file

@ -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();
@ -870,6 +899,130 @@ 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) {
// 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);

View file

@ -247,7 +247,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuth) {
capture_certificate->buffer().data(),
capture_cert_req->buffer().len()));
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@ -289,7 +291,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMultiple) {
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
// Send 2nd CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
@ -302,7 +306,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMultiple) {
server_->ReadBytes(50);
EXPECT_EQ(2U, called);
ScopedCERTCertificate cert3(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert3.get());
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert4.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert4->derCert));
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert1->derCert));
}
@ -383,7 +389,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterClientAuth) {
Connect();
EXPECT_EQ(1U, called);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
@ -396,7 +404,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterClientAuth) {
server_->ReadBytes(50);
EXPECT_EQ(2U, called);
ScopedCERTCertificate cert3(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert3.get());
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert4.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert4->derCert));
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert1->derCert));
}
@ -537,14 +547,63 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDecline) {
capture_cert_req->buffer().len()));
}
// In TLS 1.3, the client sends its cert rejection on the
// second flight, and since it has already received the
// server's Finished, it transitions to complete and
// then gets an alert from the server. The test harness
// doesn't handle this right yet.
TEST_P(TlsConnectStream, DISABLED_ClientAuthRequiredRejected) {
// Check if post-handshake auth still works when session tickets are enabled:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1553443
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthWithSessionTicketsEnabled) {
EnsureTlsSetup();
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_SESSION_TICKETS, PR_TRUE));
EXPECT_EQ(SECSuccess, SSL_OptionSet(server_->ssl_fd(),
SSL_ENABLE_SESSION_TICKETS, PR_TRUE));
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
called++;
return SECSuccess;
});
Connect();
EXPECT_EQ(0U, called);
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
client_->ssl_fd(), GetClientAuthDataHook, nullptr));
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
TEST_P(TlsConnectGenericPre13, ClientAuthRequiredRejected) {
server_->RequestClientAuth(true);
ConnectExpectFail();
ConnectExpectAlert(server_, kTlsAlertBadCertificate);
client_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
}
// In TLS 1.3, the client will claim that the connection is done and then
// receive the alert afterwards. So drive the handshake manually.
TEST_P(TlsConnectTls13, ClientAuthRequiredRejected) {
server_->RequestClientAuth(true);
StartConnect();
client_->Handshake(); // CH
server_->Handshake(); // SH.. (no resumption)
client_->Handshake(); // Next message
ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
ExpectAlert(server_, kTlsAlertCertificateRequired);
server_->Handshake(); // Alert
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
client_->Handshake(); // Receive Alert
client_->CheckErrorCode(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT);
}
TEST_P(TlsConnectGeneric, ClientAuthRequestedRejected) {
@ -580,7 +639,9 @@ static void CheckSigScheme(std::shared_ptr<TlsHandshakeRecorder>& capture,
EXPECT_EQ(expected_scheme, static_cast<uint16_t>(scheme));
ScopedCERTCertificate remote_cert(SSL_PeerCertificate(peer->ssl_fd()));
ASSERT_NE(nullptr, remote_cert.get());
ScopedSECKEYPublicKey remote_key(CERT_ExtractPublicKey(remote_cert.get()));
ASSERT_NE(nullptr, remote_key.get());
EXPECT_EQ(expected_size, SECKEY_PublicKeyStrengthInBits(remote_key.get()));
}
@ -722,6 +783,7 @@ TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureScheme) {
1024);
}
// Client should refuse to connect without a usable signature scheme.
TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) {
static const SSLSignatureScheme kSignatureScheme[] = {
ssl_sig_rsa_pkcs1_sha256};
@ -729,7 +791,21 @@ TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) {
Reset(TlsAgent::kServerRsa, "rsa");
client_->SetSignatureSchemes(kSignatureScheme,
PR_ARRAY_SIZE(kSignatureScheme));
server_->SetSignatureSchemes(kSignatureScheme,
client_->SetupClientAuth();
client_->StartConnect();
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
// Though the client has a usable signature scheme, when a certificate is
// requested, it can't produce one.
TEST_P(TlsConnectTls13, ClientAuthPkcs1AndEcdsaScheme) {
static const SSLSignatureScheme kSignatureScheme[] = {
ssl_sig_rsa_pkcs1_sha256, ssl_sig_ecdsa_secp256r1_sha256};
Reset(TlsAgent::kServerRsa, "rsa");
client_->SetSignatureSchemes(kSignatureScheme,
PR_ARRAY_SIZE(kSignatureScheme));
client_->SetupClientAuth();
server_->RequestClientAuth(true);
@ -1288,11 +1364,11 @@ TEST_P(TlsConnectGeneric, AuthFailImmediate) {
}
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Decrypt = {
ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr};
ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr, nullptr, nullptr};
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Sign = {
ssl_auth_rsa_sign, nullptr, nullptr, nullptr};
ssl_auth_rsa_sign, nullptr, nullptr, nullptr, nullptr, nullptr};
static const SSLExtraServerCertData ServerCertDataRsaPss = {
ssl_auth_rsa_pss, nullptr, nullptr, nullptr};
ssl_auth_rsa_pss, nullptr, nullptr, nullptr, nullptr, nullptr};
// Test RSA cert with usage=[signature, encipherment].
TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPkcs1SignAndKEX) {
@ -1372,6 +1448,109 @@ TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPss) {
&ServerCertDataRsaPss));
}
// A server should refuse to even start a handshake with
// misconfigured certificate and signature scheme.
TEST_P(TlsConnectTls12Plus, MisconfiguredCertScheme) {
Reset(TlsAgent::kServerDsa);
static const SSLSignatureScheme kScheme[] = {ssl_sig_ecdsa_secp256r1_sha256};
server_->SetSignatureSchemes(kScheme, PR_ARRAY_SIZE(kScheme));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
// TLS 1.2 disables cipher suites, which leads to a different error.
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
} else {
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
// In TLS 1.2, disabling an EC group causes ECDSA to be invalid.
TEST_P(TlsConnectTls12, Tls12CertDisabledGroup) {
Reset(TlsAgent::kServerEcdsa256);
static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
server_->ConfigNamedGroups(k25519);
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
// In TLS 1.3, ECDSA configuration only depends on the signature scheme.
TEST_P(TlsConnectTls13, Tls13CertDisabledGroup) {
Reset(TlsAgent::kServerEcdsa256);
static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
server_->ConfigNamedGroups(k25519);
Connect();
}
// A client should refuse to even start a handshake with only DSA.
TEST_P(TlsConnectTls13, Tls13DsaOnlyClient) {
static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
client_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
client_->StartConnect();
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
TEST_P(TlsConnectTls13, Tls13DsaOnlyServer) {
Reset(TlsAgent::kServerDsa);
static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
server_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyClient) {
static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
client_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
client_->StartConnect();
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyServer) {
static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
server_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedClient) {
EnsureTlsSetup();
static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
ssl_sig_rsa_pss_rsae_sha256};
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
auto capture =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
Connect();
// We should only have the one signature algorithm advertised.
static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
ssl_sig_rsa_pss_rsae_sha256 & 0xff};
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
capture->extension());
}
TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedServer) {
EnsureTlsSetup();
static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
ssl_sig_rsa_pss_rsae_sha256};
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
auto capture = MakeTlsFilter<TlsExtensionCapture>(
server_, ssl_signature_algorithms_xtn, true);
capture->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
capture->EnableDecryption();
server_->RequestClientAuth(false); // So we get a CertificateRequest.
Connect();
// We should only have the one signature algorithm advertised.
static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
ssl_sig_rsa_pss_rsae_sha256 & 0xff};
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
capture->extension());
}
// variant, version, certificate, auth type, signature scheme
typedef std::tuple<SSLProtocolVariant, uint16_t, std::string, SSLAuthType,
SSLSignatureScheme>

View file

@ -43,10 +43,10 @@ class SignedCertificateTimestampsExtractor {
}
void assertTimestamps(const DataBuffer& timestamps) {
EXPECT_TRUE(auth_timestamps_);
ASSERT_NE(nullptr, auth_timestamps_);
EXPECT_EQ(timestamps, *auth_timestamps_);
EXPECT_TRUE(handshake_timestamps_);
ASSERT_NE(nullptr, handshake_timestamps_);
EXPECT_EQ(timestamps, *handshake_timestamps_);
const SECItem* current =
@ -64,8 +64,8 @@ static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89};
static const SECItem kSctItem = {siBuffer, const_cast<uint8_t*>(kSctValue),
sizeof(kSctValue)};
static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue));
static const SSLExtraServerCertData kExtraSctData = {ssl_auth_null, nullptr,
nullptr, &kSctItem};
static const SSLExtraServerCertData kExtraSctData = {
ssl_auth_null, nullptr, nullptr, &kSctItem, nullptr, nullptr};
// Test timestamps extraction during a successful handshake.
TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsLegacy) {
@ -147,8 +147,8 @@ static const SECItem kOcspItems[] = {
{siBuffer, const_cast<uint8_t*>(kOcspValue2), sizeof(kOcspValue2)}};
static const SECItemArray kOcspResponses = {const_cast<SECItem*>(kOcspItems),
PR_ARRAY_SIZE(kOcspItems)};
const static SSLExtraServerCertData kOcspExtraData = {ssl_auth_null, nullptr,
&kOcspResponses, nullptr};
const static SSLExtraServerCertData kOcspExtraData = {
ssl_auth_null, nullptr, &kOcspResponses, nullptr, nullptr, nullptr};
TEST_P(TlsConnectGeneric, NoOcsp) {
EnsureTlsSetup();
@ -224,7 +224,7 @@ TEST_P(TlsConnectGeneric, OcspHugeSuccess) {
const SECItemArray hugeOcspResponses = {const_cast<SECItem*>(hugeOcspItems),
PR_ARRAY_SIZE(hugeOcspItems)};
const SSLExtraServerCertData hugeOcspExtraData = {
ssl_auth_null, nullptr, &hugeOcspResponses, nullptr};
ssl_auth_null, nullptr, &hugeOcspResponses, nullptr, nullptr, nullptr};
// The value should be available during the AuthCertificateCallback
client_->SetAuthCertificateCallback([&](TlsAgent* agent, bool checksig,

View file

@ -0,0 +1,241 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ssl.h"
#include "sslerr.h"
#include "sslproto.h"
#include <memory>
#include "tls_connect.h"
#include "tls_filter.h"
namespace nss_test {
class TlsCipherOrderTest : public TlsConnectTestBase {
protected:
virtual void ConfigureTLS() {
EnsureTlsSetup();
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
}
virtual SECStatus BuildTestLists(std::vector<uint16_t> &cs_initial_list,
std::vector<uint16_t> &cs_new_list) {
// This is the current CipherSuites order of enabled CipherSuites as defined
// in ssl3con.c
const PRUint16 *kCipherSuites = SSL_GetImplementedCiphers();
for (unsigned int i = 0; i < kNumImplementedCiphers; i++) {
PRBool pref = PR_FALSE, policy = PR_FALSE;
SECStatus rv;
rv = SSL_CipherPolicyGet(kCipherSuites[i], &policy);
if (rv != SECSuccess) {
return SECFailure;
}
rv = SSL_CipherPrefGetDefault(kCipherSuites[i], &pref);
if (rv != SECSuccess) {
return SECFailure;
}
if (pref && policy) {
cs_initial_list.push_back(kCipherSuites[i]);
}
}
// We will test set function with the first 15 enabled ciphers.
const PRUint16 kNumCiphersToSet = 15;
for (unsigned int i = 0; i < kNumCiphersToSet; i++) {
cs_new_list.push_back(cs_initial_list[i]);
}
cs_new_list[0] = cs_initial_list[1];
cs_new_list[1] = cs_initial_list[0];
return SECSuccess;
}
public:
TlsCipherOrderTest() : TlsConnectTestBase(ssl_variant_stream, 0) {}
const unsigned int kNumImplementedCiphers = SSL_GetNumImplementedCiphers();
};
const PRUint16 kCSUnsupported[] = {20196, 10101};
const PRUint16 kNumCSUnsupported = PR_ARRAY_SIZE(kCSUnsupported);
const PRUint16 kCSEmpty[] = {0};
// Get the active CipherSuites odered as they were compiled
TEST_F(TlsCipherOrderTest, CipherOrderGet) {
std::vector<uint16_t> initial_cs_order;
std::vector<uint16_t> new_cs_order;
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
ASSERT_EQ(result, SECSuccess);
ConfigureTLS();
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
unsigned int current_num_active_cs = 0;
result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
&current_num_active_cs);
ASSERT_EQ(result, SECSuccess);
ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
for (unsigned int i = 0; i < initial_cs_order.size(); i++) {
EXPECT_EQ(initial_cs_order[i], current_cs_order[i]);
}
// Get the chosen CipherSuite during the Handshake without any modification.
Connect();
SSLChannelInfo channel;
result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel);
ASSERT_EQ(result, SECSuccess);
EXPECT_EQ(channel.cipherSuite, initial_cs_order[0]);
}
// The "server" used for gtests honor only its ciphersuites order.
// So, we apply the new set for the server instead of client.
// This is enough to test the effect of SSL_CipherSuiteOrderSet function.
TEST_F(TlsCipherOrderTest, CipherOrderSet) {
std::vector<uint16_t> initial_cs_order;
std::vector<uint16_t> new_cs_order;
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
ASSERT_EQ(result, SECSuccess);
ConfigureTLS();
// change the server_ ciphersuites order.
result = SSL_CipherSuiteOrderSet(server_->ssl_fd(), new_cs_order.data(),
new_cs_order.size());
ASSERT_EQ(result, SECSuccess);
// The function expect an array. We are using vector for VStudio
// compatibility.
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
unsigned int current_num_active_cs = 0;
result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
&current_num_active_cs);
ASSERT_EQ(result, SECSuccess);
ASSERT_EQ(current_num_active_cs, new_cs_order.size());
for (unsigned int i = 0; i < new_cs_order.size(); i++) {
ASSERT_EQ(new_cs_order[i], current_cs_order[i]);
}
Connect();
SSLChannelInfo channel;
// changes in server_ order reflect in client chosen ciphersuite.
result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel);
ASSERT_EQ(result, SECSuccess);
EXPECT_EQ(channel.cipherSuite, new_cs_order[0]);
}
// Duplicate socket configuration from a model.
TEST_F(TlsCipherOrderTest, CipherOrderCopySocket) {
std::vector<uint16_t> initial_cs_order;
std::vector<uint16_t> new_cs_order;
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
ASSERT_EQ(result, SECSuccess);
ConfigureTLS();
// Use the existing sockets for this test.
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
new_cs_order.size());
ASSERT_EQ(result, SECSuccess);
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
unsigned int current_num_active_cs = 0;
result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
&current_num_active_cs);
ASSERT_EQ(result, SECSuccess);
ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
for (unsigned int i = 0; i < current_num_active_cs; i++) {
ASSERT_EQ(initial_cs_order[i], current_cs_order[i]);
}
// Import/Duplicate configurations from client_ to server_
PRFileDesc *rv = SSL_ImportFD(client_->ssl_fd(), server_->ssl_fd());
EXPECT_NE(nullptr, rv);
result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
&current_num_active_cs);
ASSERT_EQ(result, SECSuccess);
ASSERT_EQ(current_num_active_cs, new_cs_order.size());
for (unsigned int i = 0; i < new_cs_order.size(); i++) {
EXPECT_EQ(new_cs_order.data()[i], current_cs_order[i]);
}
}
// If the infomed num of elements is lower than the actual list size, only the
// first "informed num" elements will be considered. The rest is ignored.
TEST_F(TlsCipherOrderTest, CipherOrderSetLower) {
std::vector<uint16_t> initial_cs_order;
std::vector<uint16_t> new_cs_order;
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
ASSERT_EQ(result, SECSuccess);
ConfigureTLS();
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
new_cs_order.size() - 1);
ASSERT_EQ(result, SECSuccess);
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
unsigned int current_num_active_cs = 0;
result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
&current_num_active_cs);
ASSERT_EQ(result, SECSuccess);
ASSERT_EQ(current_num_active_cs, new_cs_order.size() - 1);
for (unsigned int i = 0; i < new_cs_order.size() - 1; i++) {
ASSERT_EQ(new_cs_order.data()[i], current_cs_order[i]);
}
}
// Testing Errors Controls
TEST_F(TlsCipherOrderTest, CipherOrderSetControls) {
std::vector<uint16_t> initial_cs_order;
std::vector<uint16_t> new_cs_order;
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
ASSERT_EQ(result, SECSuccess);
ConfigureTLS();
// Create a new vector with diplicated entries
std::vector<uint16_t> repeated_cs_order(SSL_GetNumImplementedCiphers() + 1);
std::copy(initial_cs_order.begin(), initial_cs_order.end(),
repeated_cs_order.begin());
repeated_cs_order[0] = repeated_cs_order[1];
// Repeated ciphersuites in the list
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), repeated_cs_order.data(),
initial_cs_order.size());
EXPECT_EQ(result, SECFailure);
// Zero size for the sent list
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(), 0);
EXPECT_EQ(result, SECFailure);
// Wrong size, greater than actual
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
SSL_GetNumImplementedCiphers() + 1);
EXPECT_EQ(result, SECFailure);
// Wrong ciphersuites, not implemented
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSUnsupported,
kNumCSUnsupported);
EXPECT_EQ(result, SECFailure);
// Null list
result =
SSL_CipherSuiteOrderSet(client_->ssl_fd(), nullptr, new_cs_order.size());
EXPECT_EQ(result, SECFailure);
// Empty list
result =
SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSEmpty, new_cs_order.size());
EXPECT_EQ(result, SECFailure);
// Confirm that the controls are working, as the current ciphersuites
// remained untouched
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
unsigned int current_num_active_cs = 0;
result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
&current_num_active_cs);
ASSERT_EQ(result, SECSuccess);
ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
for (unsigned int i = 0; i < initial_cs_order.size(); i++) {
ASSERT_EQ(initial_cs_order[i], current_cs_order[i]);
}
}
} // namespace nss_test

View file

@ -56,6 +56,9 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
std::vector<SSLNamedGroup> groups = {group_};
if (cert_group_ != ssl_grp_none) {
groups.push_back(cert_group_);
}
client_->ConfigNamedGroups(groups);
server_->ConfigNamedGroups(groups);
kea_type_ = SSLInt_GetKEAType(group_);
@ -69,34 +72,47 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
switch (sig_scheme_) {
case ssl_sig_rsa_pss_rsae_sha256:
std::cerr << "Signature scheme: rsa_pss_rsae_sha256" << std::endl;
Reset(TlsAgent::kServerRsaSign);
auth_type_ = ssl_auth_rsa_sign;
break;
case ssl_sig_rsa_pss_rsae_sha384:
std::cerr << "Signature scheme: rsa_pss_rsae_sha384" << std::endl;
Reset(TlsAgent::kServerRsaSign);
auth_type_ = ssl_auth_rsa_sign;
break;
case ssl_sig_rsa_pss_rsae_sha512:
// You can't fit SHA-512 PSS in a 1024-bit key.
std::cerr << "Signature scheme: rsa_pss_rsae_sha512" << std::endl;
Reset(TlsAgent::kRsa2048);
auth_type_ = ssl_auth_rsa_sign;
break;
case ssl_sig_rsa_pss_pss_sha256:
std::cerr << "Signature scheme: rsa_pss_pss_sha256" << std::endl;
Reset(TlsAgent::kServerRsaPss);
auth_type_ = ssl_auth_rsa_pss;
break;
case ssl_sig_rsa_pss_pss_sha384:
std::cerr << "Signature scheme: rsa_pss_pss_sha384" << std::endl;
Reset("rsa_pss384");
auth_type_ = ssl_auth_rsa_pss;
break;
case ssl_sig_rsa_pss_pss_sha512:
std::cerr << "Signature scheme: rsa_pss_pss_sha512" << std::endl;
Reset("rsa_pss512");
auth_type_ = ssl_auth_rsa_pss;
break;
case ssl_sig_ecdsa_secp256r1_sha256:
std::cerr << "Signature scheme: ecdsa_secp256r1_sha256" << std::endl;
Reset(TlsAgent::kServerEcdsa256);
auth_type_ = ssl_auth_ecdsa;
cert_group_ = ssl_grp_ec_secp256r1;
break;
case ssl_sig_ecdsa_secp384r1_sha384:
std::cerr << "Signature scheme: ecdsa_secp384r1_sha384" << std::endl;
Reset(TlsAgent::kServerEcdsa384);
auth_type_ = ssl_auth_ecdsa;
cert_group_ = ssl_grp_ec_secp384r1;
break;
default:
ADD_FAILURE() << "Unsupported signature scheme: " << sig_scheme_;
@ -112,9 +128,11 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
break;
case ssl_auth_ecdsa:
Reset(TlsAgent::kServerEcdsa256);
cert_group_ = ssl_grp_ec_secp256r1;
break;
case ssl_auth_ecdh_ecdsa:
Reset(TlsAgent::kServerEcdhEcdsa);
cert_group_ = ssl_grp_ec_secp256r1;
break;
case ssl_auth_ecdh_rsa:
Reset(TlsAgent::kServerEcdhRsa);
@ -192,6 +210,7 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
SSLAuthType auth_type_;
SSLKEAType kea_type_;
SSLNamedGroup group_;
SSLNamedGroup cert_group_ = ssl_grp_none;
SSLSignatureScheme sig_scheme_;
SSLCipherSuiteInfo csinfo_;
};

View file

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <cstdlib>
#include <fstream>
#include <sstream>
#include "gtest_utils.h"
#include "tls_connect.h"
namespace nss_test {
extern "C" {
extern FILE* ssl_trace_iob;
#ifdef NSS_ALLOW_SSLKEYLOGFILE
extern FILE* ssl_keylog_iob;
#endif
}
// These tests ensure that when the associated environment variables are unset
// that the lazily-initialized defaults are what they are supposed to be.
#ifdef DEBUG
TEST_P(TlsConnectGeneric, DebugEnvTraceFileNotSet) {
char* ev = PR_GetEnvSecure("SSLDEBUGFILE");
if (ev && ev[0]) {
// note: should use GTEST_SKIP when GTest gets updated to support it
return;
}
Connect();
EXPECT_EQ(stderr, ssl_trace_iob);
}
#endif
#ifdef NSS_ALLOW_SSLKEYLOGFILE
TEST_P(TlsConnectGeneric, DebugEnvKeylogFileNotSet) {
char* ev = PR_GetEnvSecure("SSLKEYLOGFILE");
if (ev && ev[0]) {
// note: should use GTEST_SKIP when GTest gets updated to support it
return;
}
Connect();
EXPECT_EQ(nullptr, ssl_keylog_iob);
}
#endif
} // namespace nss_test

View file

@ -682,4 +682,100 @@ TEST_P(TlsConnectTls12, ConnectInconsistentSigAlgDHE) {
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
}
static void CheckSkeSigScheme(
std::shared_ptr<TlsHandshakeRecorder>& capture_ske,
uint16_t expected_scheme) {
TlsParser parser(capture_ske->buffer());
EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_p";
EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_q";
EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_Ys";
uint32_t tmp;
EXPECT_TRUE(parser.Read(&tmp, 2)) << " read sig_scheme";
EXPECT_EQ(expected_scheme, static_cast<uint16_t>(tmp));
}
TEST_P(TlsConnectTls12, ConnectSigAlgEnabledByPolicyDhe) {
EnableOnlyDheCiphers();
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
ssl_sig_rsa_pkcs1_sha384};
EnsureTlsSetup();
client_->SetSignatureSchemes(schemes.data(), schemes.size());
server_->SetSignatureSchemes(schemes.data(), schemes.size());
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
server_, kTlsHandshakeServerKeyExchange);
StartConnect();
client_->Handshake(); // Send ClientHello
// Enable SHA-1 by policy.
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_SSL_KX, 0);
ASSERT_EQ(SECSuccess, rv);
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
0);
ASSERT_EQ(SECSuccess, rv);
Handshake(); // Remainder of handshake
// The server should now report that it is connected
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha1);
}
TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicyDhe) {
EnableOnlyDheCiphers();
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
ssl_sig_rsa_pkcs1_sha384};
EnsureTlsSetup();
client_->SetSignatureSchemes(schemes.data(), schemes.size());
server_->SetSignatureSchemes(schemes.data(), schemes.size());
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
server_, kTlsHandshakeServerKeyExchange);
StartConnect();
client_->Handshake(); // Send ClientHello
// Disable SHA-1 by policy after sending ClientHello so that CH
// includes SHA-1 signature scheme.
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX);
ASSERT_EQ(SECSuccess, rv);
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
0);
ASSERT_EQ(SECSuccess, rv);
Handshake(); // Remainder of handshake
// The server should now report that it is connected
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384);
}
TEST_P(TlsConnectPre12, ConnectSigAlgDisabledByPolicyDhePre12) {
EnableOnlyDheCiphers();
EnsureTlsSetup();
StartConnect();
client_->Handshake(); // Send ClientHello
// Disable SHA-1 by policy. This will cause the connection fail as
// TLS 1.1 or earlier uses combined SHA-1 + MD5 signature.
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX);
ASSERT_EQ(SECSuccess, rv);
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
0);
ASSERT_EQ(SECSuccess, rv);
server_->ExpectSendAlert(kTlsAlertHandshakeFailure);
client_->ExpectReceiveAlert(kTlsAlertHandshakeFailure);
// Remainder of handshake
Handshake();
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
}
} // namespace nss_test

View file

@ -666,6 +666,80 @@ TEST_P(TlsConnectTls12, ConnectIncorrectSigAlg) {
client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
}
static void CheckSkeSigScheme(
std::shared_ptr<TlsHandshakeRecorder> &capture_ske,
uint16_t expected_scheme) {
TlsParser parser(capture_ske->buffer());
uint32_t tmp = 0;
EXPECT_TRUE(parser.Read(&tmp, 1)) << " read curve_type";
EXPECT_EQ(3U, tmp) << "curve type has to be 3";
EXPECT_TRUE(parser.Skip(2)) << " read namedcurve";
EXPECT_TRUE(parser.SkipVariable(1)) << " read public";
EXPECT_TRUE(parser.Read(&tmp, 2)) << " read sig_scheme";
EXPECT_EQ(expected_scheme, static_cast<uint16_t>(tmp));
}
TEST_P(TlsConnectTls12, ConnectSigAlgEnabledByPolicy) {
EnsureTlsSetup();
client_->DisableAllCiphers();
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
ssl_sig_rsa_pkcs1_sha384};
client_->SetSignatureSchemes(schemes.data(), schemes.size());
server_->SetSignatureSchemes(schemes.data(), schemes.size());
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
server_, kTlsHandshakeServerKeyExchange);
StartConnect();
client_->Handshake(); // Send ClientHello
// Enable SHA-1 by policy.
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_SSL_KX, 0);
ASSERT_EQ(SECSuccess, rv);
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
0);
ASSERT_EQ(SECSuccess, rv);
Handshake(); // Remainder of handshake
// The server should now report that it is connected
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha1);
}
TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicy) {
EnsureTlsSetup();
client_->DisableAllCiphers();
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
ssl_sig_rsa_pkcs1_sha384};
client_->SetSignatureSchemes(schemes.data(), schemes.size());
server_->SetSignatureSchemes(schemes.data(), schemes.size());
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
server_, kTlsHandshakeServerKeyExchange);
StartConnect();
client_->Handshake(); // Send ClientHello
// Disable SHA-1 by policy.
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX);
ASSERT_EQ(SECSuccess, rv);
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
0);
ASSERT_EQ(SECSuccess, rv);
Handshake(); // Remainder of handshake
// The server should now report that it is connected
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384);
}
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV11Plus));

View file

@ -652,7 +652,7 @@ TEST_P(TlsExtensionTest12, SignatureAlgorithmDisableDSA) {
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
client_->SetSignatureSchemes(schemes.data(), schemes.size());
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
// Check if no DSA algorithms are advertised.

View file

@ -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));
} // namespace nss_test

View file

@ -18,9 +18,11 @@
'ssl_agent_unittest.cc',
'ssl_auth_unittest.cc',
'ssl_cert_ext_unittest.cc',
'ssl_cipherorder_unittest.cc',
'ssl_ciphersuite_unittest.cc',
'ssl_custext_unittest.cc',
'ssl_damage_unittest.cc',
'ssl_debug_env_unittest.cc',
'ssl_dhe_unittest.cc',
'ssl_drop_unittest.cc',
'ssl_ecdh_unittest.cc',
@ -53,7 +55,8 @@
'tls_filter.cc',
'tls_hkdf_unittest.cc',
'tls_esni_unittest.cc',
'tls_protect.cc'
'tls_protect.cc',
'tls_subcerts_unittest.cc'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',

View file

@ -13,20 +13,59 @@
namespace nss_test {
static const std::string keylog_file_path = "keylog.txt";
static const std::string keylog_env = "SSLKEYLOGFILE=" + keylog_file_path;
static const std::string kKeylogFilePath = "keylog.txt";
static const std::string kKeylogBlankEnv = "SSLKEYLOGFILE=";
static const std::string kKeylogSetEnv = kKeylogBlankEnv + kKeylogFilePath;
extern "C" {
extern FILE* ssl_keylog_iob;
}
class KeyLogFileTestBase : public TlsConnectGeneric {
private:
std::string env_to_set_;
class KeyLogFileTest : public TlsConnectGeneric {
public:
virtual void CheckKeyLog() = 0;
KeyLogFileTestBase(std::string env) : env_to_set_(env) {}
void SetUp() override {
TlsConnectGeneric::SetUp();
// Remove previous results (if any).
(void)remove(keylog_file_path.c_str());
PR_SetEnv(keylog_env.c_str());
(void)remove(kKeylogFilePath.c_str());
PR_SetEnv(env_to_set_.c_str());
}
void CheckKeyLog() {
std::ifstream f(keylog_file_path);
void ConnectAndCheck() {
// This is a child process, ensure that error messages immediately
// propagate or else it will not be visible.
::testing::GTEST_FLAG(throw_on_failure) = true;
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
SetupForZeroRtt();
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
ExpectResumption(RESUME_TICKET);
ZeroRttSendReceive(true, true);
Handshake();
ExpectEarlyDataAccepted(true);
CheckConnected();
SendReceive();
} else {
Connect();
}
CheckKeyLog();
_exit(0);
}
};
class KeyLogFileTest : public KeyLogFileTestBase {
public:
KeyLogFileTest() : KeyLogFileTestBase(kKeylogSetEnv) {}
void CheckKeyLog() override {
std::ifstream f(kKeylogFilePath);
std::map<std::string, size_t> labels;
std::set<std::string> client_randoms;
for (std::string line; std::getline(f, line);) {
@ -63,28 +102,6 @@ class KeyLogFileTest : public TlsConnectGeneric {
ASSERT_EQ(4U, labels["EXPORTER_SECRET"]);
}
}
void ConnectAndCheck() {
// This is a child process, ensure that error messages immediately
// propagate or else it will not be visible.
::testing::GTEST_FLAG(throw_on_failure) = true;
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
SetupForZeroRtt();
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
ExpectResumption(RESUME_TICKET);
ZeroRttSendReceive(true, true);
Handshake();
ExpectEarlyDataAccepted(true);
CheckConnected();
SendReceive();
} else {
Connect();
}
CheckKeyLog();
_exit(0);
}
};
// Tests are run in a separate process to ensure that NSS is not initialized yet
@ -111,4 +128,37 @@ INSTANTIATE_TEST_CASE_P(
TlsConnectTestBase::kTlsV13));
#endif
class KeyLogFileUnsetTest : public KeyLogFileTestBase {
public:
KeyLogFileUnsetTest() : KeyLogFileTestBase(kKeylogBlankEnv) {}
void CheckKeyLog() override {
std::ifstream f(kKeylogFilePath);
EXPECT_FALSE(f.good());
EXPECT_EQ(nullptr, ssl_keylog_iob);
}
};
TEST_P(KeyLogFileUnsetTest, KeyLogFile) {
testing::GTEST_FLAG(death_test_style) = "threadsafe";
ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
}
INSTANTIATE_TEST_CASE_P(
KeyLogFileDTLS12, KeyLogFileUnsetTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(
KeyLogFileTLS12, KeyLogFileUnsetTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsV10ToV12));
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(
KeyLogFileTLS13, KeyLogFileUnsetTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsV13));
#endif
} // namespace nss_test

View file

@ -33,6 +33,37 @@ TEST_F(TlsConnectTest, KeyUpdateClient) {
CheckEpochs(4, 3);
}
TEST_F(TlsConnectStreamTls13, KeyUpdateTooEarly_Client) {
StartConnect();
auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
server_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
ExpectAlert(client_, kTlsAlertUnexpectedMessage);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
server_->Handshake();
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
TEST_F(TlsConnectStreamTls13, KeyUpdateTooEarly_Server) {
StartConnect();
auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
client_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
client_->Handshake();
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
server_->Handshake();
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
TEST_F(TlsConnectTest, KeyUpdateClientRequestUpdate) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();

View file

@ -205,6 +205,42 @@ TEST_F(TlsConnectDatagram13, ShortHeadersServer) {
SendReceive();
}
TEST_F(TlsConnectStreamTls13, UnencryptedFinishedMessage) {
StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send first server flight
// Record and drop the first record, which is the Finished.
auto recorder = std::make_shared<TlsRecordRecorder>(client_);
recorder->EnableDecryption();
auto dropper = std::make_shared<SelectiveDropFilter>(1);
client_->SetFilter(std::make_shared<ChainedPacketFilter>(
ChainedPacketFilterInit({recorder, dropper})));
client_->Handshake(); // Save and drop CFIN.
EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
ASSERT_EQ(1U, recorder->count());
auto& finished = recorder->record(0);
DataBuffer d;
size_t offset = d.Write(0, ssl_ct_handshake, 1);
offset = d.Write(offset, SSL_LIBRARY_VERSION_TLS_1_2, 2);
offset = d.Write(offset, finished.buffer.len(), 2);
d.Append(finished.buffer);
client_->SendDirect(d);
// Now process the message.
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
// The server should generate an alert.
server_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE);
// Have the client consume the alert.
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
const static size_t kContentSizesArr[] = {
1, kMacSize - 1, kMacSize, 30, 31, 32, 36, 256, 257, 287, 288};

View file

@ -230,14 +230,15 @@ TEST_P(TlsConnectTls13, RecordSizePlaintextExceed) {
// Tweak the ciphertext of server records so that they greatly exceed the limit.
// This requires a much larger expansion than for plaintext to trigger the
// guard, which runs before decryption (current allowance is 304 octets).
// guard, which runs before decryption (current allowance is 320 octets,
// see MAX_EXPANSION in ssl3con.c).
TEST_P(TlsConnectTls13, RecordSizeCiphertextExceed) {
EnsureTlsSetup();
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
Connect();
auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 320);
auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 336);
server_->SendData(100);
client_->ExpectReadWriteError();

View file

@ -11,6 +11,11 @@
#include "sslerr.h"
#include "sslproto.h"
extern "C" {
// This is not something that should make you happy.
#include "libssl_internals.h"
}
#include "gtest_utils.h"
#include "tls_connect.h"
@ -34,6 +39,24 @@ TEST_P(TlsConnectStreamPre13, RenegotiateServer) {
CheckConnected();
}
TEST_P(TlsConnectStreamPre13, RenegotiateRandoms) {
SSL3Random crand1, crand2, srand1, srand2;
Connect();
EXPECT_EQ(SECSuccess,
SSLInt_GetHandshakeRandoms(client_->ssl_fd(), crand1, srand1));
// Renegotiate and check that both randoms have changed.
client_->PrepareForRenegotiate();
server_->StartRenegotiate();
Handshake();
CheckConnected();
EXPECT_EQ(SECSuccess,
SSLInt_GetHandshakeRandoms(client_->ssl_fd(), crand2, srand2));
EXPECT_NE(0, memcmp(crand1, crand2, sizeof(SSL3Random)));
EXPECT_NE(0, memcmp(srand1, srand2, sizeof(SSL3Random)));
}
// The renegotiation options shouldn't cause an error if TLS 1.3 is chosen.
TEST_F(TlsConnectTest, RenegotiationConfigTls13) {
EnsureTlsSetup();

View file

@ -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();

View file

@ -55,6 +55,10 @@ TEST_P(TlsConnectGeneric, ServerNegotiateTls12) {
// two validate that we can also detect fallback using the
// SSL_SetDowngradeCheckVersion() API.
TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
SSL_LIBRARY_VERSION_TLS_1_2);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
SSL_LIBRARY_VERSION_TLS_1_2);
client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
SSL_LIBRARY_VERSION_TLS_1_1);
@ -116,11 +120,11 @@ TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) {
TEST_F(TlsConnectTest, TestFallbackFromTls12) {
client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_1);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_2);
client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);

View file

@ -47,6 +47,8 @@ const std::string TlsAgent::kServerEcdsa521 = "ecdsa521";
const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
const std::string TlsAgent::kServerDsa = "dsa";
const std::string TlsAgent::kDelegatorEcdsa256 = "delegator_ecdsa256";
const std::string TlsAgent::kDelegatorRsae2048 = "delegator_rsae2048";
static const uint8_t kCannedTls13ServerHello[] = {
0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
@ -127,16 +129,76 @@ void TlsAgent::SetState(State s) {
ScopedCERTCertificate* cert,
ScopedSECKEYPrivateKey* priv) {
cert->reset(PK11_FindCertFromNickname(name.c_str(), nullptr));
EXPECT_NE(nullptr, cert);
if (!cert) return false;
EXPECT_NE(nullptr, cert->get());
if (!cert->get()) return false;
priv->reset(PK11_FindKeyByAnyCert(cert->get(), nullptr));
EXPECT_NE(nullptr, priv);
if (!priv) return false;
EXPECT_NE(nullptr, priv->get());
if (!priv->get()) return false;
return true;
}
// Loads a key pair from the certificate identified by |id|.
/*static*/ bool TlsAgent::LoadKeyPairFromCert(const std::string& name,
ScopedSECKEYPublicKey* pub,
ScopedSECKEYPrivateKey* priv) {
ScopedCERTCertificate cert;
if (!TlsAgent::LoadCertificate(name, &cert, priv)) {
return false;
}
pub->reset(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo));
if (!pub->get()) {
return false;
}
return true;
}
void TlsAgent::DelegateCredential(const std::string& name,
const ScopedSECKEYPublicKey& dc_pub,
SSLSignatureScheme dc_cert_verify_alg,
PRUint32 dc_valid_for, PRTime now,
SECItem* dc) {
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey cert_priv;
EXPECT_TRUE(TlsAgent::LoadCertificate(name, &cert, &cert_priv))
<< "Could not load delegate certificate: " << name
<< "; test db corrupt?";
EXPECT_EQ(SECSuccess,
SSL_DelegateCredential(cert.get(), cert_priv.get(), dc_pub.get(),
dc_cert_verify_alg, dc_valid_for, now, dc));
}
void TlsAgent::EnableDelegatedCredentials() {
ASSERT_TRUE(EnsureTlsSetup());
SetOption(SSL_ENABLE_DELEGATED_CREDENTIALS, PR_TRUE);
}
void TlsAgent::AddDelegatedCredential(const std::string& dc_name,
SSLSignatureScheme dc_cert_verify_alg,
PRUint32 dc_valid_for, PRTime now) {
ASSERT_TRUE(EnsureTlsSetup());
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(dc_name, &pub, &priv));
StackSECItem dc;
TlsAgent::DelegateCredential(name_, pub, dc_cert_verify_alg, dc_valid_for,
now, &dc);
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
nullptr, &dc, priv.get()};
EXPECT_TRUE(ConfigServerCert(name_, true, &extra_data));
}
bool TlsAgent::ConfigServerCert(const std::string& id, bool updateKeyBits,
const SSLExtraServerCertData* serverCertData) {
ScopedCERTCertificate cert;
@ -224,6 +286,9 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
// All these tests depend on having this disabled to start with.
SetOption(SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_FALSE);
return true;
}
@ -251,6 +316,10 @@ bool TlsAgent::MaybeSetResumptionToken() {
return true;
}
void TlsAgent::SetAntiReplayContext(ScopedSSLAntiReplayContext& ctx) {
EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(ssl_fd_.get(), ctx.get()));
}
void TlsAgent::SetupClientAuth() {
EXPECT_TRUE(EnsureTlsSetup());
ASSERT_EQ(CLIENT, role_);
@ -279,7 +348,7 @@ SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
ScopedCERTCertificate peerCert(SSL_PeerCertificate(agent->ssl_fd()));
EXPECT_TRUE(peerCert) << "Client should be able to see the server cert";
// See bug 1457716
// See bug 1573945
// CheckCertReqAgainstDefaultCAs(caNames);
ScopedCERTCertificate cert;
@ -725,26 +794,26 @@ void TlsAgent::WaitForErrorCode(int32_t expected, uint32_t delay) const {
}
void TlsAgent::CheckPreliminaryInfo() {
SSLPreliminaryChannelInfo info;
SSLPreliminaryChannelInfo preinfo;
EXPECT_EQ(SECSuccess,
SSL_GetPreliminaryChannelInfo(ssl_fd(), &info, sizeof(info)));
EXPECT_EQ(sizeof(info), info.length);
EXPECT_TRUE(info.valuesSet & ssl_preinfo_version);
EXPECT_TRUE(info.valuesSet & ssl_preinfo_cipher_suite);
SSL_GetPreliminaryChannelInfo(ssl_fd(), &preinfo, sizeof(preinfo)));
EXPECT_EQ(sizeof(preinfo), preinfo.length);
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_version);
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);
// A version of 0 is invalid and indicates no expectation. This value is
// initialized to 0 so that tests that don't explicitly set an expected
// version can negotiate a version.
if (!expected_version_) {
expected_version_ = info.protocolVersion;
expected_version_ = preinfo.protocolVersion;
}
EXPECT_EQ(expected_version_, info.protocolVersion);
EXPECT_EQ(expected_version_, preinfo.protocolVersion);
// As with the version; 0 is the null cipher suite (and also invalid).
if (!expected_cipher_suite_) {
expected_cipher_suite_ = info.cipherSuite;
expected_cipher_suite_ = preinfo.cipherSuite;
}
EXPECT_EQ(expected_cipher_suite_, info.cipherSuite);
EXPECT_EQ(expected_cipher_suite_, preinfo.cipherSuite);
}
// Check that all the expected callbacks have been called.
@ -776,6 +845,13 @@ void TlsAgent::ResetPreliminaryInfo() {
expected_cipher_suite_ = 0;
}
void TlsAgent::UpdatePreliminaryChannelInfo() {
SECStatus rv = SSL_GetPreliminaryChannelInfo(ssl_fd_.get(), &pre_info_,
sizeof(pre_info_));
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(sizeof(pre_info_), pre_info_.length);
}
void TlsAgent::ValidateCipherSpecs() {
PRInt32 cipherSpecs = SSLInt_CountCipherSpecs(ssl_fd());
// We use one ciphersuite in each direction.
@ -838,6 +914,7 @@ void TlsAgent::Connected() {
// Preliminary values are exposed through callbacks during the handshake.
// If either expected values were set or the callbacks were called, check
// that the final values are correct.
UpdatePreliminaryChannelInfo();
EXPECT_EQ(expected_version_, info_.protocolVersion);
EXPECT_EQ(expected_cipher_suite_, info_.cipherSuite);

View file

@ -76,6 +76,8 @@ class TlsAgent : public PollTarget {
static const std::string kServerEcdhEcdsa;
static const std::string kServerEcdhRsa;
static const std::string kServerDsa;
static const std::string kDelegatorEcdsa256; // draft-ietf-tls-subcerts
static const std::string kDelegatorRsae2048; // draft-ietf-tls-subcerts
TlsAgent(const std::string& name, Role role, SSLProtocolVariant variant);
virtual ~TlsAgent();
@ -108,9 +110,32 @@ class TlsAgent : public PollTarget {
void PrepareForRenegotiate();
// Prepares for renegotiation, then actually triggers it.
void StartRenegotiate();
void SetAntiReplayContext(ScopedSSLAntiReplayContext& ctx);
static bool LoadCertificate(const std::string& name,
ScopedCERTCertificate* cert,
ScopedSECKEYPrivateKey* priv);
static bool LoadKeyPairFromCert(const std::string& name,
ScopedSECKEYPublicKey* pub,
ScopedSECKEYPrivateKey* priv);
// Delegated credentials.
//
// Generate a delegated credential and sign it using the certificate
// associated with |name|.
static void DelegateCredential(const std::string& name,
const ScopedSECKEYPublicKey& dcPub,
SSLSignatureScheme dcCertVerifyAlg,
PRUint32 dcValidFor, PRTime now, SECItem* dc);
// Indicate support for the delegated credentials extension.
void EnableDelegatedCredentials();
// Generate and configure a delegated credential to use in the handshake with
// clients that support this extension..
void AddDelegatedCredential(const std::string& dc_name,
SSLSignatureScheme dcCertVerifyAlg,
PRUint32 dcValidFor, PRTime now);
void UpdatePreliminaryChannelInfo();
bool ConfigServerCert(const std::string& name, bool updateKeyBits = false,
const SSLExtraServerCertData* serverCertData = nullptr);
bool ConfigServerCertWithChain(const std::string& name);
@ -200,16 +225,20 @@ class TlsAgent : public PollTarget {
PRFileDesc* ssl_fd() const { return ssl_fd_.get(); }
std::shared_ptr<DummyPrSocket>& adapter() { return adapter_; }
const SSLChannelInfo& info() const {
EXPECT_EQ(STATE_CONNECTED, state_);
return info_;
}
const SSLPreliminaryChannelInfo& pre_info() const { return pre_info_; }
bool is_compressed() const {
return info_.compressionMethod != ssl_compression_null;
return info().compressionMethod != ssl_compression_null;
}
uint16_t server_key_bits() const { return server_key_bits_; }
uint16_t min_version() const { return vrange_.min; }
uint16_t max_version() const { return vrange_.max; }
uint16_t version() const {
EXPECT_EQ(STATE_CONNECTED, state_);
return info_.protocolVersion;
}
uint16_t version() const { return info().protocolVersion; }
bool cipher_suite(uint16_t* suite) const {
if (state_ != STATE_CONNECTED) return false;
@ -400,6 +429,7 @@ class TlsAgent : public PollTarget {
bool handshake_callback_called_;
bool resumption_callback_called_;
SSLChannelInfo info_;
SSLPreliminaryChannelInfo pre_info_;
SSLCipherSuiteInfo csinfo_;
SSLVersionRange vrange_;
PRErrorCode error_code_;

View file

@ -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();
ResetAntiReplay(kAntiReplayWindow);
ClearStats();
SaveAlgorithmPolicy();
Init();
@ -232,6 +240,14 @@ void TlsConnectTestBase::Init() {
}
}
void TlsConnectTestBase::ResetAntiReplay(PRTime window) {
SSLAntiReplayContext* p_anti_replay = nullptr;
EXPECT_EQ(SECSuccess,
SSL_CreateAntiReplayContext(now_, window, 1, 3, &p_anti_replay));
EXPECT_NE(nullptr, p_anti_replay);
anti_replay_.reset(p_anti_replay);
}
void TlsConnectTestBase::Reset() {
// Take a copy of the names because they are about to disappear.
std::string server_name = server_->name();
@ -250,7 +266,8 @@ void TlsConnectTestBase::Reset(const std::string& server_name,
server_->SkipVersionChecks();
}
std::cerr << "Reset" << std::endl;
std::cerr << "Reset server:" << server_name << ", client:" << client_name
<< std::endl;
Init();
}
@ -282,10 +299,14 @@ void TlsConnectTestBase::EnsureTlsSetup() {
: nullptr));
EXPECT_TRUE(client_->EnsureTlsSetup(client_model_ ? client_model_->ssl_fd()
: nullptr));
server_->SetAntiReplayContext(anti_replay_);
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 +323,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 +700,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 +814,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));
}
}
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; }
// Advance time by a full anti-replay window.
void TlsConnectTestBase::RolloverAntiReplay() {
AdvanceTime(kAntiReplayWindow);
}
TlsConnectGeneric::TlsConnectGeneric()

View file

@ -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,10 @@ 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 ResetAntiReplay(PRTime window);
void RolloverAntiReplay();
void SaveAlgorithmPolicy();
void RestoreAlgorithmPolicy();
@ -145,6 +151,7 @@ class TlsConnectTestBase : public ::testing::Test {
SessionResumptionMode expected_resumption_mode_;
uint8_t expected_resumptions_;
std::vector<std::vector<uint8_t>> session_ids_;
ScopedSSLAntiReplayContext anti_replay_;
// A simple value of "a", "b". Note that the preferred value of "a" is placed
// at the end, because the NSS API follows the now defunct NPN specification,
@ -157,17 +164,19 @@ class TlsConnectTestBase : public ::testing::Test {
// ssl_extension_unittest.cc.
const std::vector<SECOidTag> algorithms_ = {SEC_OID_APPLY_SSL_POLICY,
SEC_OID_ANSIX9_DSA_SIGNATURE,
SEC_OID_CURVE25519};
SEC_OID_CURVE25519, SEC_OID_SHA1};
std::vector<std::tuple<SECOidTag, uint32_t>> saved_policies_;
private:
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 {

View file

@ -4,8 +4,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <ctime>
#include "secerr.h"
#include "ssl.h"
@ -57,7 +55,7 @@ static void UpdateEsniKeysChecksum(DataBuffer* buf) {
buf->Write(2, sha256, 4);
}
static void GenerateEsniKey(time_t windowStart, SSLNamedGroup group,
static void GenerateEsniKey(PRTime now, SSLNamedGroup group,
std::vector<uint16_t>& cipher_suites,
DataBuffer* record,
ScopedSECKEYPublicKey* pubKey = nullptr,
@ -73,8 +71,9 @@ static void GenerateEsniKey(time_t windowStart, SSLNamedGroup group,
unsigned int encoded_len = 0;
SECStatus rv = SSL_EncodeESNIKeys(
&cipher_suites[0], cipher_suites.size(), group, pub, 100, windowStart,
windowStart + 10, encoded, &encoded_len, sizeof(encoded));
&cipher_suites[0], cipher_suites.size(), group, pub, 100,
(now / PR_USEC_PER_SEC) - 1, (now / PR_USEC_PER_SEC) + 10, encoded,
&encoded_len, sizeof(encoded));
ASSERT_EQ(SECSuccess, rv);
ASSERT_GT(encoded_len, 0U);
@ -92,15 +91,15 @@ static void GenerateEsniKey(time_t windowStart, SSLNamedGroup group,
record->Write(0, encoded, encoded_len);
}
static void SetupEsni(const std::shared_ptr<TlsAgent>& client,
static void SetupEsni(PRTime now, const std::shared_ptr<TlsAgent>& client,
const std::shared_ptr<TlsAgent>& server,
SSLNamedGroup group = ssl_grp_ec_curve25519) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now, ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
SECStatus rv = SSL_SetESNIKeyPair(server->ssl_fd(), priv.get(), record.data(),
record.len());
ASSERT_EQ(SECSuccess, rv);
@ -124,77 +123,87 @@ static void CheckSniExtension(const DataBuffer& data) {
ASSERT_EQ(expected, name);
}
static void ClientInstallEsni(std::shared_ptr<TlsAgent>& agent,
const DataBuffer& record, PRErrorCode err = 0) {
SECStatus rv =
SSL_EnableESNI(agent->ssl_fd(), record.data(), record.len(), kDummySni);
if (err == 0) {
ASSERT_EQ(SECSuccess, rv);
} else {
ASSERT_EQ(SECFailure, rv);
ASSERT_EQ(err, PORT_GetError());
}
}
class TlsAgentEsniTest : public TlsAgentTestClient13 {
public:
void SetUp() override { now_ = PR_Now(); }
TEST_P(TlsAgentTestClient13, EsniInstall) {
protected:
PRTime now() const { return now_; }
void InstallEsni(const DataBuffer& record, PRErrorCode err = 0) {
SECStatus rv = SSL_EnableESNI(agent_->ssl_fd(), record.data(), record.len(),
kDummySni);
if (err == 0) {
ASSERT_EQ(SECSuccess, rv);
} else {
ASSERT_EQ(SECFailure, rv);
ASSERT_EQ(err, PORT_GetError());
}
}
private:
PRTime now_ = 0;
};
TEST_P(TlsAgentEsniTest, EsniInstall) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
ClientInstallEsni(agent_, record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
InstallEsni(record);
}
// The next set of tests fail at setup time.
TEST_P(TlsAgentTestClient13, EsniInvalidHash) {
TEST_P(TlsAgentEsniTest, EsniInvalidHash) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.data()[2]++;
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
TEST_P(TlsAgentTestClient13, EsniInvalidVersion) {
TEST_P(TlsAgentEsniTest, EsniInvalidVersion) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(0, 0xffff, 2);
ClientInstallEsni(agent_, record, SSL_ERROR_UNSUPPORTED_VERSION);
InstallEsni(record, SSL_ERROR_UNSUPPORTED_VERSION);
}
TEST_P(TlsAgentTestClient13, EsniShort) {
TEST_P(TlsAgentEsniTest, EsniShort) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Truncate(record.len() - 1);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
TEST_P(TlsAgentTestClient13, EsniLong) {
TEST_P(TlsAgentEsniTest, EsniLong) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(record.len(), 1, 1);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
TEST_P(TlsAgentTestClient13, EsniExtensionMismatch) {
TEST_P(TlsAgentEsniTest, EsniExtensionMismatch) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(record.len() - 1, 1, 1);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
// The following tests fail by ignoring the Esni block.
TEST_P(TlsAgentTestClient13, EsniUnknownGroup) {
TEST_P(TlsAgentEsniTest, EsniUnknownGroup) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(8, 0xffff, 2); // Fake group
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, 0);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -202,11 +211,11 @@ TEST_P(TlsAgentTestClient13, EsniUnknownGroup) {
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniUnknownCS) {
TEST_P(TlsAgentEsniTest, EsniUnknownCS) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kBogusSuites, &record);
ClientInstallEsni(agent_, record, 0);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kBogusSuites, &record);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -214,12 +223,12 @@ TEST_P(TlsAgentTestClient13, EsniUnknownCS) {
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniInvalidCS) {
TEST_P(TlsAgentEsniTest, EsniInvalidCS) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kTls12Suites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kTls12Suites, &record);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, 0);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -227,36 +236,34 @@ TEST_P(TlsAgentTestClient13, EsniInvalidCS) {
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniNotReady) {
TEST_P(TlsAgentEsniTest, EsniNotReady) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0) + 1000, ssl_grp_ec_curve25519, kDefaultSuites,
&record);
ClientInstallEsni(agent_, record, 0);
GenerateEsniKey(now() + 1000, ssl_grp_ec_curve25519, kDefaultSuites, &record);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniExpired) {
TEST_P(TlsAgentEsniTest, EsniExpired) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0) - 1000, ssl_grp_ec_curve25519, kDefaultSuites,
&record);
ClientInstallEsni(agent_, record, 0);
GenerateEsniKey(now() - 1000, ssl_grp_ec_curve25519, kDefaultSuites, &record);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, NoSniSoNoEsni) {
TEST_P(TlsAgentEsniTest, NoSniSoNoEsni) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
SSL_SetURL(agent_->ssl_fd(), "");
ClientInstallEsni(agent_, record, 0);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -275,7 +282,7 @@ static int32_t SniCallback(TlsAgent* agent, const SECItem* srvNameAddr,
TEST_P(TlsConnectTls13, ConnectEsni) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto cFilterSni =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
auto cFilterEsni =
@ -300,7 +307,7 @@ TEST_P(TlsConnectTls13, ConnectEsniHrr) {
EnsureTlsSetup();
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
server_->ConfigNamedGroups(groups);
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto hrr_capture = MakeTlsFilter<TlsHandshakeRecorder>(
server_, kTlsHandshakeHelloRetryRequest);
auto filter =
@ -322,8 +329,8 @@ TEST_P(TlsConnectTls13, ConnectEsniNoDummy) {
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
SECStatus rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(),
record.data(), record.len());
ASSERT_EQ(SECSuccess, rv);
@ -346,8 +353,8 @@ TEST_P(TlsConnectTls13, ConnectEsniNullDummy) {
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
SECStatus rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(),
record.data(), record.len());
ASSERT_EQ(SECSuccess, rv);
@ -372,14 +379,15 @@ TEST_P(TlsConnectTls13, ConnectEsniCSMismatch) {
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
PRUint8 encoded[1024];
unsigned int encoded_len = 0;
SECStatus rv = SSL_EncodeESNIKeys(
&kChaChaSuite[0], kChaChaSuite.size(), ssl_grp_ec_curve25519, pub.get(),
100, time(0), time(0) + 10, encoded, &encoded_len, sizeof(encoded));
100, (now() / PR_USEC_PER_SEC) - 1, (now() / PR_USEC_PER_SEC) + 10,
encoded, &encoded_len, sizeof(encoded));
ASSERT_EQ(SECSuccess, rv);
ASSERT_LT(0U, encoded_len);
rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(), encoded, encoded_len);
@ -392,7 +400,7 @@ TEST_P(TlsConnectTls13, ConnectEsniCSMismatch) {
TEST_P(TlsConnectTls13, ConnectEsniP256) {
EnsureTlsSetup();
SetupEsni(client_, server_, ssl_grp_ec_secp256r1);
SetupEsni(now(), client_, server_, ssl_grp_ec_secp256r1);
auto cfilter =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
auto sfilter =
@ -405,18 +413,21 @@ TEST_P(TlsConnectTls13, ConnectEsniP256) {
TEST_P(TlsConnectTls13, ConnectMismatchedEsniKeys) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
// Now install a new set of keys on the client, so we have a mismatch.
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
ClientInstallEsni(client_, record, 0);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
SECStatus rv =
SSL_EnableESNI(client_->ssl_fd(), record.data(), record.len(), kDummySni);
ASSERT_EQ(SECSuccess, rv);
ConnectExpectAlert(server_, illegal_parameter);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
TEST_P(TlsConnectTls13, ConnectDamagedEsniExtensionCH) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto filter = MakeTlsFilter<TlsExtensionDamager>(
client_, ssl_tls13_encrypted_sni_xtn, 50); // in the ciphertext
ConnectExpectAlert(server_, illegal_parameter);
@ -425,7 +436,7 @@ TEST_P(TlsConnectTls13, ConnectDamagedEsniExtensionCH) {
TEST_P(TlsConnectTls13, ConnectRemoveEsniExtensionEE) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto filter =
MakeTlsFilter<TlsExtensionDropper>(server_, ssl_tls13_encrypted_sni_xtn);
filter->EnableDecryption();
@ -435,7 +446,7 @@ TEST_P(TlsConnectTls13, ConnectRemoveEsniExtensionEE) {
TEST_P(TlsConnectTls13, ConnectShortEsniExtensionEE) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
DataBuffer shortNonce;
auto filter = MakeTlsFilter<TlsExtensionReplacer>(
server_, ssl_tls13_encrypted_sni_xtn, shortNonce);
@ -446,7 +457,7 @@ TEST_P(TlsConnectTls13, ConnectShortEsniExtensionEE) {
TEST_P(TlsConnectTls13, ConnectBogusEsniExtensionEE) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
const uint8_t bogusNonceBuf[16] = {0};
DataBuffer bogusNonce(bogusNonceBuf, sizeof(bogusNonceBuf));
auto filter = MakeTlsFilter<TlsExtensionReplacer>(
@ -461,7 +472,7 @@ TEST_P(TlsConnectTls13, ConnectBogusEsniExtensionEE) {
// The client then aborts when it sees the server did TLS 1.2.
TEST_P(TlsConnectTls13, EsniButTLS12Server) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
@ -472,4 +483,4 @@ TEST_P(TlsConnectTls13, EsniButTLS12Server) {
ASSERT_FALSE(SSLInt_ExtensionNegotiated(server_->ssl_fd(),
ssl_tls13_encrypted_sni_xtn));
}
}
} // namespace nss_test

View file

@ -441,6 +441,80 @@ class TlsExtensionDropper : public TlsExtensionFilter {
uint16_t extension_;
};
class TlsHandshakeDropper : public TlsHandshakeFilter {
public:
TlsHandshakeDropper(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(a) {}
protected:
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) override {
return DROP;
}
};
class TlsEncryptedHandshakeMessageReplacer : public TlsRecordFilter {
public:
TlsEncryptedHandshakeMessageReplacer(const std::shared_ptr<TlsAgent>& a,
uint8_t old_ct, uint8_t new_ct)
: TlsRecordFilter(a), old_ct_(old_ct), new_ct_(new_ct) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record, size_t* offset,
DataBuffer* output) override {
if (header.content_type() != ssl_ct_application_data) {
return KEEP;
}
uint16_t protection_epoch = 0;
uint8_t inner_content_type;
DataBuffer plaintext;
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
&plaintext) ||
!plaintext.len()) {
return KEEP;
}
if (inner_content_type != ssl_ct_handshake) {
return KEEP;
}
size_t off = 0;
uint32_t msg_len = 0;
uint32_t msg_type = 255; // Not a real message
do {
if (!plaintext.Read(off, 1, &msg_type) || msg_type == old_ct_) {
break;
}
// Increment and check next messages
if (!plaintext.Read(++off, 3, &msg_len)) {
break;
}
off += 3 + msg_len;
} while (msg_type != old_ct_);
if (msg_type == old_ct_) {
plaintext.Write(off, new_ct_, 1);
}
DataBuffer ciphertext;
bool ok = Protect(spec(protection_epoch), header, inner_content_type,
plaintext, &ciphertext, 0);
if (!ok) {
return KEEP;
}
*offset = header.Write(output, *offset, ciphertext);
return CHANGE;
}
private:
uint8_t old_ct_;
uint8_t new_ct_;
};
class TlsExtensionInjector : public TlsHandshakeFilter {
public:
TlsExtensionInjector(const std::shared_ptr<TlsAgent>& a, uint16_t ext,

View file

@ -0,0 +1,568 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <ctime>
#include "prtime.h"
#include "secerr.h"
#include "ssl.h"
#include "gtest_utils.h"
#include "tls_agent.h"
#include "tls_connect.h"
namespace nss_test {
const std::string kEcdsaDelegatorId = TlsAgent::kDelegatorEcdsa256;
const std::string kRsaeDelegatorId = TlsAgent::kDelegatorRsae2048;
const std::string kDCId = TlsAgent::kServerEcdsa256;
const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256;
const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds */;
static void CheckPreliminaryPeerDelegCred(
const std::shared_ptr<TlsAgent>& client, bool expected,
PRUint32 key_bits = 0, SSLSignatureScheme sig_scheme = ssl_sig_none) {
EXPECT_NE(0U, (client->pre_info().valuesSet & ssl_preinfo_peer_auth));
EXPECT_EQ(expected, client->pre_info().peerDelegCred);
if (expected) {
EXPECT_EQ(key_bits, client->pre_info().authKeyBits);
EXPECT_EQ(sig_scheme, client->pre_info().signatureScheme);
}
}
static void CheckPeerDelegCred(const std::shared_ptr<TlsAgent>& client,
bool expected, PRUint32 key_bits = 0) {
EXPECT_EQ(expected, client->info().peerDelegCred);
EXPECT_EQ(expected, client->pre_info().peerDelegCred);
if (expected) {
EXPECT_EQ(key_bits, client->info().authKeyBits);
EXPECT_EQ(key_bits, client->pre_info().authKeyBits);
EXPECT_EQ(client->info().signatureScheme,
client->pre_info().signatureScheme);
}
}
// AuthCertificate callbacks to simulate DC validation
static SECStatus CheckPreliminaryDC(TlsAgent* agent, bool checksig,
bool isServer) {
agent->UpdatePreliminaryChannelInfo();
EXPECT_EQ(PR_TRUE, agent->pre_info().peerDelegCred);
EXPECT_EQ(256U, agent->pre_info().authKeyBits);
EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, agent->pre_info().signatureScheme);
return SECSuccess;
}
static SECStatus CheckPreliminaryNoDC(TlsAgent* agent, bool checksig,
bool isServer) {
agent->UpdatePreliminaryChannelInfo();
EXPECT_EQ(PR_FALSE, agent->pre_info().peerDelegCred);
return SECSuccess;
}
// AuthCertificate callbacks for modifying DC attributes.
// This allows testing tls13_CertificateVerify for rejection
// of DC attributes that have changed since AuthCertificateHook
// may have handled them.
static SECStatus ModifyDCAuthKeyBits(TlsAgent* agent, bool checksig,
bool isServer) {
return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(),
PR_TRUE, // Change authKeyBits
PR_FALSE); // Change scheme
}
static SECStatus ModifyDCScheme(TlsAgent* agent, bool checksig, bool isServer) {
return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(),
PR_FALSE, // Change authKeyBits
PR_TRUE); // Change scheme
}
// Attempt to configure a DC when either the DC or DC private key is missing.
TEST_P(TlsConnectTls13, DCNotConfigured) {
// Load and delegate the credential.
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
StackSECItem dc;
TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor,
now(), &dc);
// Attempt to install the certificate and DC with a missing DC private key.
EnsureTlsSetup();
SSLExtraServerCertData extra_data_missing_dc_priv_key = {
ssl_auth_null, nullptr, nullptr, nullptr, &dc, nullptr};
EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true,
&extra_data_missing_dc_priv_key));
// Attempt to install the certificate and with only the DC private key.
EnsureTlsSetup();
SSLExtraServerCertData extra_data_missing_dc = {
ssl_auth_null, nullptr, nullptr, nullptr, nullptr, priv.get()};
EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true,
&extra_data_missing_dc));
}
// Connected with ECDSA-P256.
TEST_P(TlsConnectTls13, DCConnectEcdsaP256) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 256);
EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme);
}
// Connected with ECDSA-P521.
TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
client_->EnableDelegatedCredentials();
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 521);
EXPECT_EQ(ssl_sig_ecdsa_secp521r1_sha512, client_->info().signatureScheme);
}
// Connected with RSA-PSS, using an RSAE DC SPKI.
TEST_P(TlsConnectTls13, DCConnectRsaPssRsae) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 1024);
EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, client_->info().signatureScheme);
}
// Connected with RSA-PSS, using a RSAE Delegator SPKI.
TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) {
Reset(kRsaeDelegatorId);
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
ssl_sig_rsa_pss_pss_sha256};
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 1024);
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
}
// Connected with RSA-PSS, using a PSS SPKI.
TEST_P(TlsConnectTls13, DCConnectRsaPssPss) {
Reset(kEcdsaDelegatorId);
// Need to enable PSS-PSS, which is not on by default.
static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256,
ssl_sig_rsa_pss_pss_sha256};
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 1024);
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
}
// Generate a weak key. We can't do this in the fixture because certutil
// won't sign with such a tiny key. That's OK, because this is fast(ish).
static void GenerateWeakRsaKey(ScopedSECKEYPrivateKey& priv,
ScopedSECKEYPublicKey& pub) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
PK11RSAGenParams rsaparams;
// The absolute minimum size of RSA key that we can use with SHA-256 is
// 256bit (hash) + 256bit (salt) + 8 (start byte) + 8 (end byte) = 528.
rsaparams.keySizeInBits = 528;
rsaparams.pe = 65537;
// Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient
// entropy to generate a random key. We can fake some.
for (int retry = 0; retry < 10; ++retry) {
SECKEYPublicKey* p_pub = nullptr;
priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
&rsaparams, &p_pub, false, false, nullptr));
pub.reset(p_pub);
if (priv) {
return;
}
ASSERT_FALSE(pub);
if (PORT_GetError() != SEC_ERROR_PKCS11_FUNCTION_FAILED) {
break;
}
// https://xkcd.com/221/
static const uint8_t FRESH_ENTROPY[16] = {4};
ASSERT_EQ(
SECSuccess,
PK11_RandomUpdate(
const_cast<void*>(reinterpret_cast<const void*>(FRESH_ENTROPY)),
sizeof(FRESH_ENTROPY)));
break;
}
ADD_FAILURE() << "Unable to generate an RSA key: "
<< PORT_ErrorToName(PORT_GetError());
}
// Fail to connect with a weak RSA key.
TEST_P(TlsConnectTls13, DCWeakKey) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
ScopedSECKEYPrivateKey dc_priv;
ScopedSECKEYPublicKey dc_pub;
GenerateWeakRsaKey(dc_priv, dc_pub);
ASSERT_TRUE(dc_priv);
// Construct a DC.
StackSECItem dc;
TlsAgent::DelegateCredential(kEcdsaDelegatorId, dc_pub,
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now(),
&dc);
// Configure the DC on the server.
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
nullptr, &dc, dc_priv.get()};
EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data));
client_->EnableDelegatedCredentials();
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
ConnectExpectAlert(client_, kTlsAlertInsufficientSecurity);
}
class ReplaceDCSigScheme : public TlsHandshakeFilter {
public:
ReplaceDCSigScheme(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(a, {ssl_hs_certificate_verify}) {}
protected:
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) override {
*output = input;
output->Write(0, ssl_sig_ecdsa_secp384r1_sha384, 2);
return CHANGE;
}
};
// Aborted because of incorrect DC signature algorithm indication.
TEST_P(TlsConnectTls13, DCAbortBadExpectedCertVerifyAlg) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now());
auto filter = MakeTlsFilter<ReplaceDCSigScheme>(server_);
filter->EnableDecryption();
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
// Aborted because of invalid DC signature.
TEST_P(TlsConnectTls13, DCAbortBadSignature) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
client_->EnableDelegatedCredentials();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
StackSECItem dc;
TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor,
now(), &dc);
ASSERT_TRUE(dc.data != nullptr);
// Flip the first bit of the DC so that the signature is invalid.
dc.data[0] ^= 0x01;
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
nullptr, &dc, priv.get()};
EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data));
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_DC_BAD_SIGNATURE);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
// Aborted because of expired DC.
TEST_P(TlsConnectTls13, DCAbortExpired) {
Reset(kEcdsaDelegatorId);
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
client_->EnableDelegatedCredentials();
// When the client checks the time, it will be at least one second after the
// DC expired.
AdvanceTime((static_cast<PRTime>(kDCValidFor) + 1) * PR_USEC_PER_SEC);
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_DC_EXPIRED);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
// Aborted because of invalid key usage.
TEST_P(TlsConnectTls13, DCAbortBadKeyUsage) {
// The sever does not have the delegationUsage extension.
Reset(TlsAgent::kServerEcdsa256);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
}
// Connected without DC because of no client indication.
TEST_P(TlsConnectTls13, DCConnectNoClientSupport) {
Reset(kEcdsaDelegatorId);
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_FALSE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because of no server DC.
TEST_P(TlsConnectTls13, DCConnectNoServerSupport) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because client doesn't support TLS 1.3.
TEST_P(TlsConnectTls13, DCConnectClientNoTls13) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
// Should fallback to TLS 1.2 and not negotiate a DC.
EXPECT_FALSE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because server doesn't support TLS 1.3.
TEST_P(TlsConnectTls13, DCConnectServerNoTls13) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
// Should fallback to TLS 1.2 and not negotiate a DC. The client will still
// send the indication because it supports 1.3.
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because client doesn't support the signature scheme.
TEST_P(TlsConnectTls13, DCConnectExpectedCertVerifyAlgNotSupported) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
static const SSLSignatureScheme kClientSchemes[] = {
ssl_sig_ecdsa_secp256r1_sha256,
};
client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes));
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
// Client sends indication, but the server doesn't send a DC.
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Check that preliminary channel info properly reflects the DC.
TEST_P(TlsConnectTls13, DCCheckPreliminaryInfo) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now());
auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
filter->SetHandshakeTypes(
{kTlsHandshakeCertificateVerify, kTlsHandshakeFinished});
filter->EnableDecryption();
StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send ServerHello
client_->SetAuthCertificateCallback(CheckPreliminaryDC);
client_->Handshake(); // Process response
client_->UpdatePreliminaryChannelInfo();
CheckPreliminaryPeerDelegCred(client_, true, 256,
ssl_sig_ecdsa_secp256r1_sha256);
}
// Check that preliminary channel info properly reflects a lack of DC.
TEST_P(TlsConnectTls13, DCCheckPreliminaryInfoNoDC) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
client_->EnableDelegatedCredentials();
auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
filter->SetHandshakeTypes(
{kTlsHandshakeCertificateVerify, kTlsHandshakeFinished});
filter->EnableDecryption();
StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send ServerHello
client_->SetAuthCertificateCallback(CheckPreliminaryNoDC);
client_->Handshake(); // Process response
client_->UpdatePreliminaryChannelInfo();
CheckPreliminaryPeerDelegCred(client_, false);
}
// Tweak the scheme in between |Cert| and |CertVerify|.
TEST_P(TlsConnectTls13, DCRejectModifiedDCScheme) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
client_->SetAuthCertificateCallback(ModifyDCScheme);
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
}
// Tweak the authKeyBits in between |Cert| and |CertVerify|.
TEST_P(TlsConnectTls13, DCRejectModifiedDCAuthKeyBits) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
client_->SetAuthCertificateCallback(ModifyDCAuthKeyBits);
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
}
class DCDelegation : public ::testing::Test {};
TEST_F(DCDelegation, DCDelegations) {
PRTime now = PR_Now();
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey priv;
ASSERT_TRUE(TlsAgent::LoadCertificate(kEcdsaDelegatorId, &cert, &priv));
ScopedSECKEYPublicKey pub_rsa;
ScopedSECKEYPrivateKey priv_rsa;
ASSERT_TRUE(
TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerRsa, &pub_rsa, &priv_rsa));
StackSECItem dc;
EXPECT_EQ(SECFailure,
SSL_DelegateCredential(cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
// Using different PSS hashes should be OK.
EXPECT_EQ(SECSuccess,
SSL_DelegateCredential(cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor,
now, &dc));
// Make sure to reset |dc| after each success.
dc.Reset();
EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc));
dc.Reset();
EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_rsa_pss_pss_sha384, kDCValidFor, now, &dc));
dc.Reset();
ScopedSECKEYPublicKey pub_ecdsa;
ScopedSECKEYPrivateKey priv_ecdsa;
ASSERT_TRUE(TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerEcdsa256,
&pub_ecdsa, &priv_ecdsa));
EXPECT_EQ(SECFailure,
SSL_DelegateCredential(cert.get(), priv.get(), pub_ecdsa.get(),
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor,
now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
EXPECT_EQ(SECFailure, SSL_DelegateCredential(
cert.get(), priv.get(), pub_ecdsa.get(),
ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
EXPECT_EQ(SECFailure,
SSL_DelegateCredential(cert.get(), priv.get(), pub_ecdsa.get(),
ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor,
now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
}
} // namespace nss_test