Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 1399439 - API for external TLS session caches, r=mt
Reviewers: mt, ekr

Bug #: 1399439

Differential Revision: https://phabricator.services.mozilla.com/D284

--HG--
extra : rebase_source : b0bb342c952973b4d1ef6cfff7c4810904a8bbb1
extra : histedit_source : 3edefe0328a634ce2aec862458b8cb483a7a2dbd
  • Loading branch information
franziskuskiefer committed Jan 16, 2018
1 parent d2b3c94 commit d7c8d7d
Show file tree
Hide file tree
Showing 24 changed files with 1,499 additions and 193 deletions.
5 changes: 5 additions & 0 deletions cpputil/scoped_ptrs.h
Expand Up @@ -12,6 +12,7 @@
#include "keyhi.h"
#include "pk11pub.h"
#include "pkcs11uri.h"
#include "sslexp.h"

struct ScopedDelete {
void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
Expand All @@ -37,6 +38,9 @@ struct ScopedDelete {
void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
void operator()(SSLResumptionTokenInfo* token) {
SSL_DestroyResumptionTokenInfo(token);
}
};

template <class T>
Expand Down Expand Up @@ -68,6 +72,7 @@ SCOPED(PK11URI);
SCOPED(PLArenaPool);
SCOPED(PK11Context);
SCOPED(PK11GenericObject);
SCOPED(SSLResumptionTokenInfo);

#undef SCOPED

Expand Down
25 changes: 24 additions & 1 deletion gtests/ssl_gtest/ssl_loopback_unittest.cc
Expand Up @@ -535,4 +535,27 @@ INSTANTIATE_TEST_CASE_P(Version12Plus, TlsConnectTls12Plus,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus));

} // namespace nspr_test
INSTANTIATE_TEST_CASE_P(
GenericStream, TlsConnectGenericResumption,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsVAll,
::testing::Values(true, false)));
INSTANTIATE_TEST_CASE_P(
GenericDatagram, TlsConnectGenericResumption,
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11Plus,
::testing::Values(true, false)));

INSTANTIATE_TEST_CASE_P(
GenericStream, TlsConnectGenericResumptionToken,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsVAll));
INSTANTIATE_TEST_CASE_P(
GenericDatagram, TlsConnectGenericResumptionToken,
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11Plus));

INSTANTIATE_TEST_CASE_P(GenericDatagram, TlsConnectTls13ResumptionToken,
TlsConnectTestBase::kTlsVariantsAll);

} // namespace nss_test
140 changes: 126 additions & 14 deletions gtests/ssl_gtest/ssl_resumption_unittest.cc
Expand Up @@ -60,7 +60,7 @@ TEST_P(TlsConnectGenericPre13, ConnectResumed) {
Connect();
}

TEST_P(TlsConnectGeneric, ConnectClientCacheDisabled) {
TEST_P(TlsConnectGenericResumption, ConnectClientCacheDisabled) {
ConfigureSessionCache(RESUME_NONE, RESUME_SESSIONID);
Connect();
SendReceive();
Expand All @@ -71,7 +71,7 @@ TEST_P(TlsConnectGeneric, ConnectClientCacheDisabled) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectServerCacheDisabled) {
TEST_P(TlsConnectGenericResumption, ConnectServerCacheDisabled) {
ConfigureSessionCache(RESUME_SESSIONID, RESUME_NONE);
Connect();
SendReceive();
Expand All @@ -82,7 +82,7 @@ TEST_P(TlsConnectGeneric, ConnectServerCacheDisabled) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectSessionCacheDisabled) {
TEST_P(TlsConnectGenericResumption, ConnectSessionCacheDisabled) {
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
Connect();
SendReceive();
Expand All @@ -93,7 +93,7 @@ TEST_P(TlsConnectGeneric, ConnectSessionCacheDisabled) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectResumeSupportBoth) {
TEST_P(TlsConnectGenericResumption, ConnectResumeSupportBoth) {
// This prefers tickets.
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
Expand All @@ -106,7 +106,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeSupportBoth) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectResumeClientTicketServerBoth) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientTicketServerBoth) {
// This causes no resumption because the client needs the
// session cache to resume even with tickets.
ConfigureSessionCache(RESUME_TICKET, RESUME_BOTH);
Expand All @@ -120,7 +120,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientTicketServerBoth) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicket) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientBothTicketServerTicket) {
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
Expand All @@ -133,7 +133,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicket) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectResumeClientServerTicketOnly) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientServerTicketOnly) {
// This causes no resumption because the client needs the
// session cache to resume even with tickets.
ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
Expand All @@ -147,7 +147,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientServerTicketOnly) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectResumeClientBothServerNone) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientBothServerNone) {
ConfigureSessionCache(RESUME_BOTH, RESUME_NONE);
Connect();
SendReceive();
Expand All @@ -159,7 +159,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothServerNone) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectResumeClientNoneServerBoth) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientNoneServerBoth) {
ConfigureSessionCache(RESUME_NONE, RESUME_BOTH);
Connect();
SendReceive();
Expand Down Expand Up @@ -202,7 +202,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicketForget) {
SendReceive();
}

TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtClient) {
TEST_P(TlsConnectGenericResumption, ConnectWithExpiredTicketAtClient) {
SSLInt_SetTicketLifetime(1); // one second
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Expand Down Expand Up @@ -417,7 +417,7 @@ static uint16_t ChooseAnotherCipher(uint16_t version) {
}

// Test that we don't resume when we can't negotiate the same cipher.
TEST_P(TlsConnectGeneric, TestResumeClientDifferentCipher) {
TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
client_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
Expand All @@ -442,7 +442,7 @@ TEST_P(TlsConnectGeneric, TestResumeClientDifferentCipher) {
}

// Test that we don't resume when we can't negotiate the same cipher.
TEST_P(TlsConnectGeneric, TestResumeServerDifferentCipher) {
TEST_P(TlsConnectGenericResumption, TestResumeServerDifferentCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
Expand Down Expand Up @@ -845,7 +845,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionForcedDowngrade) {
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
}

TEST_P(TlsConnectGeneric, ReConnectTicket) {
TEST_P(TlsConnectGenericResumption, ReConnectTicket) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
Expand Down Expand Up @@ -877,7 +877,7 @@ TEST_P(TlsConnectGenericPre13, ReConnectCache) {
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}

TEST_P(TlsConnectGeneric, ReConnectAgainTicket) {
TEST_P(TlsConnectGenericResumption, ReConnectAgainTicket) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
Expand All @@ -902,4 +902,116 @@ TEST_P(TlsConnectGeneric, ReConnectAgainTicket) {
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}

void CheckGetInfoResult(uint32_t alpnSize, uint32_t earlyDataSize,
ScopedCERTCertificate& cert,
ScopedSSLResumptionTokenInfo& token) {
ASSERT_TRUE(cert);
ASSERT_TRUE(token->peerCert);

// Check that the server cert is the correct one.
ASSERT_EQ(cert->derCert.len, token->peerCert->derCert.len);
EXPECT_EQ(0, memcmp(cert->derCert.data, token->peerCert->derCert.data,
cert->derCert.len));

ASSERT_EQ(alpnSize, token->alpnSelectionLen);
EXPECT_EQ(0, memcmp("a", token->alpnSelection, token->alpnSelectionLen));

ASSERT_EQ(earlyDataSize, token->maxEarlyDataSize);
}

TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfo) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
SendReceive();

Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);

StartConnect();
ASSERT_TRUE(client_->MaybeSetResumptionToken());

// Get resumption token infos
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));

CheckGetInfoResult(0, 0, cert, token);

Handshake();
CheckConnected();

SendReceive();
}

TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
CheckAlpn("a");
SendReceive();

Reset();
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);

StartConnect();
ASSERT_TRUE(client_->MaybeSetResumptionToken());

// Get resumption token infos
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));

CheckGetInfoResult(1, 0, cert, token);

Handshake();
CheckConnected();
CheckAlpn("a");

SendReceive();
}

TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
EnableAlpn();
SSLInt_RolloverAntiReplay();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->Set0RttEnabled(true);
Connect();
CheckAlpn("a");
SendReceive();

Reset();
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);

StartConnect();
server_->Set0RttEnabled(true);
client_->Set0RttEnabled(true);
ASSERT_TRUE(client_->MaybeSetResumptionToken());

// Get resumption token infos
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));

CheckGetInfoResult(1, 1024, cert, token);

ZeroRttSendReceive(true, true);
Handshake();
ExpectEarlyDataAccepted(true);
CheckConnected();
CheckAlpn("a");

SendReceive();
}

} // namespace nss_test
46 changes: 45 additions & 1 deletion gtests/ssl_gtest/tls_agent.cc
Expand Up @@ -73,7 +73,8 @@ TlsAgent::TlsAgent(const std::string& name, Role role,
handshake_callback_(),
auth_certificate_callback_(),
sni_callback_(),
skip_version_checks_(false) {
skip_version_checks_(false),
resumption_token_() {
memset(&info_, 0, sizeof(info_));
memset(&csinfo_, 0, sizeof(csinfo_));
SECStatus rv = SSL_VersionRangeGetDefault(variant_, &vrange_);
Expand Down Expand Up @@ -207,6 +208,29 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
return true;
}

bool TlsAgent::MaybeSetResumptionToken() {
if (!resumption_token_.empty()) {
SECStatus rv = SSL_SetResumptionToken(ssl_fd(), resumption_token_.data(),
resumption_token_.size());

// rv is SECFailure with error set to SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR
// if the resumption token was bad (expired/malformed/etc.).
if (expect_resumption_) {
// Only in case we expect resumption this has to be successful. We might
// not expect resumption due to some reason but the token is totally fine.
EXPECT_EQ(SECSuccess, rv);
}
if (rv != SECSuccess) {
EXPECT_EQ(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, PORT_GetError());
resumption_token_.clear();
EXPECT_FALSE(expect_resumption_);
if (expect_resumption_) return false;
}
}

return true;
}

void TlsAgent::SetupClientAuth() {
EXPECT_TRUE(EnsureTlsSetup());
ASSERT_EQ(CLIENT, role_);
Expand Down Expand Up @@ -386,6 +410,26 @@ void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
}
}

SECStatus ResumptionTokenCallback(PRFileDesc* fd,
const PRUint8* resumptionToken,
unsigned int len, void* ctx) {
EXPECT_NE(nullptr, resumptionToken);
if (!resumptionToken) {
return SECFailure;
}

std::vector<uint8_t> new_token(resumptionToken, resumptionToken + len);
reinterpret_cast<TlsAgent*>(ctx)->SetResumptionToken(new_token);
return SECSuccess;
}

void TlsAgent::SetResumptionTokenCallback() {
EXPECT_TRUE(EnsureTlsSetup());
SECStatus rv =
SSL_SetResumptionTokenCallback(ssl_fd(), ResumptionTokenCallback, this);
EXPECT_EQ(SECSuccess, rv);
}

void TlsAgent::GetVersionRange(uint16_t* minver, uint16_t* maxver) {
*minver = vrange_.min;
*maxver = vrange_.max;
Expand Down
15 changes: 15 additions & 0 deletions gtests/ssl_gtest/tls_agent.h
Expand Up @@ -165,6 +165,20 @@ class TlsAgent : public PollTarget {
void DisableECDHEServerKeyReuse();
bool GetPeerChainLength(size_t* count);
void CheckCipherSuite(uint16_t cipher_suite);
void SetResumptionTokenCallback();
bool MaybeSetResumptionToken();
void SetResumptionToken(const std::vector<uint8_t>& resumption_token) {
resumption_token_ = resumption_token;
}
const std::vector<uint8_t>& GetResumptionToken() const {
return resumption_token_;
}
void GetTokenInfo(ScopedSSLResumptionTokenInfo& token) {
SECStatus rv = SSL_GetResumptionTokenInfo(
resumption_token_.data(), resumption_token_.size(), token.get(),
sizeof(SSLResumptionTokenInfo));
ASSERT_EQ(SECSuccess, rv);
}

const std::string& name() const { return name_; }

Expand Down Expand Up @@ -393,6 +407,7 @@ class TlsAgent : public PollTarget {
AuthCertificateCallbackFunction auth_certificate_callback_;
SniCallbackFunction sni_callback_;
bool skip_version_checks_;
std::vector<uint8_t> resumption_token_;
};

inline std::ostream& operator<<(std::ostream& stream,
Expand Down

0 comments on commit d7c8d7d

Please sign in to comment.