mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-22 08:27:31 +09:00
Update NSS to 3.48 while keeping vc2013 hackfix and no-sslkeylogfile intact.
This commit is contained in:
parent
0b9855b841
commit
171849c8e5
351 changed files with 115185 additions and 57946 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
241
security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
Normal file
241
security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
Normal 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(),
|
||||
¤t_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(),
|
||||
¤t_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(),
|
||||
¤t_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(),
|
||||
¤t_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(),
|
||||
¤t_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(),
|
||||
¤t_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
|
||||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
53
security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
Normal file
53
security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
568
security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
Normal file
568
security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue