/* -*- 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 #include "tls_connect.h" #include "tls_filter.h" #include "tls_parser.h" namespace nss_test { // Tests for Certificate Transparency (RFC 6962) // These don't work with TLS 1.3: see bug 1252745. // Helper class - stores signed certificate timestamps as provided // by the relevant callbacks on the client. class SignedCertificateTimestampsExtractor { public: SignedCertificateTimestampsExtractor(std::shared_ptr& client) : client_(client) { client->SetAuthCertificateCallback( [this](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus { const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd()); EXPECT_TRUE(scts); if (!scts) { return SECFailure; } auth_timestamps_.reset(new DataBuffer(scts->data, scts->len)); return SECSuccess; }); client->SetHandshakeCallback([this](TlsAgent* agent) { const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd()); ASSERT_TRUE(scts); handshake_timestamps_.reset(new DataBuffer(scts->data, scts->len)); }); } void assertTimestamps(const DataBuffer& timestamps) { ASSERT_NE(nullptr, auth_timestamps_); EXPECT_EQ(timestamps, *auth_timestamps_); ASSERT_NE(nullptr, handshake_timestamps_); EXPECT_EQ(timestamps, *handshake_timestamps_); const SECItem* current = SSL_PeerSignedCertTimestamps(client_.lock()->ssl_fd()); EXPECT_EQ(timestamps, DataBuffer(current->data, current->len)); } private: std::weak_ptr client_; std::unique_ptr auth_timestamps_; std::unique_ptr handshake_timestamps_; }; static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89}; static const SECItem kSctItem = {siBuffer, const_cast(kSctValue), sizeof(kSctValue)}; static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue)); static const SSLExtraServerCertData kExtraSctData = { ssl_auth_null, nullptr, nullptr, &kSctItem, nullptr, nullptr}; // Test timestamps extraction during a successful handshake. TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsLegacy) { EnsureTlsSetup(); // We have to use the legacy API consistently here for configuring certs. // Also, this doesn't work in TLS 1.3 because this only configures the SCT for // RSA decrypt and PKCS#1 signing, not PSS. ScopedCERTCertificate cert; ScopedSECKEYPrivateKey priv; ASSERT_TRUE(TlsAgent::LoadCertificate(TlsAgent::kServerRsa, &cert, &priv)); EXPECT_EQ(SECSuccess, SSL_ConfigSecureServerWithCertChain( server_->ssl_fd(), cert.get(), nullptr, priv.get(), ssl_kea_rsa)); EXPECT_EQ(SECSuccess, SSL_SetSignedCertTimestamps(server_->ssl_fd(), &kSctItem, ssl_kea_rsa)); client_->SetOption(SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, PR_TRUE); SignedCertificateTimestampsExtractor timestamps_extractor(client_); Connect(); timestamps_extractor.assertTimestamps(kSctBuffer); } TEST_P(TlsConnectGeneric, SignedCertificateTimestampsSuccess) { EnsureTlsSetup(); EXPECT_TRUE( server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraSctData)); client_->SetOption(SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, PR_TRUE); SignedCertificateTimestampsExtractor timestamps_extractor(client_); Connect(); timestamps_extractor.assertTimestamps(kSctBuffer); } // Test SSL_PeerSignedCertTimestamps returning zero-length SECItem // when the client / the server / both have not enabled the feature. TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveClient) { EnsureTlsSetup(); EXPECT_TRUE( server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraSctData)); SignedCertificateTimestampsExtractor timestamps_extractor(client_); Connect(); timestamps_extractor.assertTimestamps(DataBuffer()); } TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveServer) { EnsureTlsSetup(); client_->SetOption(SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, PR_TRUE); SignedCertificateTimestampsExtractor timestamps_extractor(client_); Connect(); timestamps_extractor.assertTimestamps(DataBuffer()); } TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveBoth) { EnsureTlsSetup(); SignedCertificateTimestampsExtractor timestamps_extractor(client_); Connect(); timestamps_extractor.assertTimestamps(DataBuffer()); } // Check that the given agent doesn't have an OCSP response for its peer. static SECStatus CheckNoOCSP(TlsAgent* agent, bool checksig, bool isServer) { const SECItemArray* ocsp = SSL_PeerStapledOCSPResponses(agent->ssl_fd()); EXPECT_TRUE(ocsp); EXPECT_EQ(0U, ocsp->len); return SECSuccess; } static const uint8_t kOcspValue1[] = {1, 2, 3, 4, 5, 6}; static const uint8_t kOcspValue2[] = {7, 8, 9}; static const SECItem kOcspItems[] = { {siBuffer, const_cast(kOcspValue1), sizeof(kOcspValue1)}, {siBuffer, const_cast(kOcspValue2), sizeof(kOcspValue2)}}; static const SECItemArray kOcspResponses = {const_cast(kOcspItems), PR_ARRAY_SIZE(kOcspItems)}; const static SSLExtraServerCertData kOcspExtraData = { ssl_auth_null, nullptr, &kOcspResponses, nullptr, nullptr, nullptr}; TEST_P(TlsConnectGeneric, NoOcsp) { EnsureTlsSetup(); client_->SetAuthCertificateCallback(CheckNoOCSP); Connect(); } // The client doesn't get OCSP stapling unless it asks. TEST_P(TlsConnectGeneric, OcspNotRequested) { EnsureTlsSetup(); client_->SetAuthCertificateCallback(CheckNoOCSP); EXPECT_TRUE( server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kOcspExtraData)); Connect(); } // Even if the client asks, the server has nothing unless it is configured. TEST_P(TlsConnectGeneric, OcspNotProvided) { EnsureTlsSetup(); client_->SetOption(SSL_ENABLE_OCSP_STAPLING, PR_TRUE); client_->SetAuthCertificateCallback(CheckNoOCSP); Connect(); } TEST_P(TlsConnectGenericPre13, OcspMangled) { EnsureTlsSetup(); client_->SetOption(SSL_ENABLE_OCSP_STAPLING, PR_TRUE); EXPECT_TRUE( server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kOcspExtraData)); static const uint8_t val[] = {1}; auto replacer = MakeTlsFilter( server_, ssl_cert_status_xtn, DataBuffer(val, sizeof(val))); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } TEST_P(TlsConnectGeneric, OcspSuccess) { EnsureTlsSetup(); client_->SetOption(SSL_ENABLE_OCSP_STAPLING, PR_TRUE); auto capture_ocsp = MakeTlsFilter(server_, ssl_cert_status_xtn); // The value should be available during the AuthCertificateCallback client_->SetAuthCertificateCallback([](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus { const SECItemArray* ocsp = SSL_PeerStapledOCSPResponses(agent->ssl_fd()); if (!ocsp) { return SECFailure; } EXPECT_EQ(1U, ocsp->len) << "We only provide the first item"; EXPECT_EQ(0, SECITEM_CompareItem(&kOcspItems[0], &ocsp->items[0])); return SECSuccess; }); EXPECT_TRUE( server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kOcspExtraData)); Connect(); // In TLS 1.3, the server doesn't provide a visible ServerHello extension. // For earlier versions, the extension is just empty. EXPECT_EQ(0U, capture_ocsp->extension().len()); } TEST_P(TlsConnectGeneric, OcspHugeSuccess) { EnsureTlsSetup(); client_->SetOption(SSL_ENABLE_OCSP_STAPLING, PR_TRUE); uint8_t hugeOcspValue[16385]; memset(hugeOcspValue, 0xa1, sizeof(hugeOcspValue)); const SECItem hugeOcspItems[] = { {siBuffer, const_cast(hugeOcspValue), sizeof(hugeOcspValue)}}; const SECItemArray hugeOcspResponses = {const_cast(hugeOcspItems), PR_ARRAY_SIZE(hugeOcspItems)}; const SSLExtraServerCertData hugeOcspExtraData = { ssl_auth_null, nullptr, &hugeOcspResponses, nullptr, nullptr, nullptr}; // The value should be available during the AuthCertificateCallback client_->SetAuthCertificateCallback([&](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus { const SECItemArray* ocsp = SSL_PeerStapledOCSPResponses(agent->ssl_fd()); if (!ocsp) { return SECFailure; } EXPECT_EQ(1U, ocsp->len) << "We only provide the first item"; EXPECT_EQ(0, SECITEM_CompareItem(&hugeOcspItems[0], &ocsp->items[0])); return SECSuccess; }); EXPECT_TRUE(server_->ConfigServerCert(TlsAgent::kServerRsa, true, &hugeOcspExtraData)); Connect(); } } // namespace nss_test