/* -*- 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 "secerr.h" #include "ssl.h" #include "ssl3prot.h" #include "sslerr.h" #include "sslproto.h" #include "gtest_utils.h" #include "nss_scoped_ptrs.h" #include "tls_connect.h" #include "tls_filter.h" #include "tls_parser.h" namespace nss_test { TEST_P(TlsConnectStream, ServerNegotiateTls10) { uint16_t minver, maxver; client_->GetVersionRange(&minver, &maxver); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, maxver); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, SSL_LIBRARY_VERSION_TLS_1_0); Connect(); } TEST_P(TlsConnectGeneric, ServerNegotiateTls11) { if (version_ < SSL_LIBRARY_VERSION_TLS_1_1) GTEST_SKIP(); uint16_t minver, maxver; client_->GetVersionRange(&minver, &maxver); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1, maxver); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1, SSL_LIBRARY_VERSION_TLS_1_1); Connect(); } TEST_P(TlsConnectGeneric, ServerNegotiateTls12) { if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) GTEST_SKIP(); uint16_t minver, maxver; client_->GetVersionRange(&minver, &maxver); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, maxver); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_2); Connect(); } // Test the ServerRandom version hack from // [draft-ietf-tls-tls13-11 Section 6.3.1.1]. // The first three tests test for active tampering. The next // 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(client_, kTlsHandshakeClientHello, SSL_LIBRARY_VERSION_TLS_1_1); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } // Attempt to negotiate the bogus DTLS 1.1 version. TEST_F(DtlsConnectTest, TestDtlsVersion11) { MakeTlsFilter(client_, kTlsHandshakeClientHello, ((~0x0101) & 0xffff)); ConnectExpectAlert(server_, kTlsAlertProtocolVersion); client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT); server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION); } TEST_F(TlsConnectTest, TestDowngradeDetectionToTls12) { client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE); MakeTlsFilter(client_, ssl_tls13_supported_versions_xtn); 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_3); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } // Disabling downgrade checks will be caught when the Finished MAC check fails. TEST_F(TlsConnectTest, TestDisableDowngradeDetection) { client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_FALSE); MakeTlsFilter(client_, ssl_tls13_supported_versions_xtn); 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_3); ConnectExpectAlert(server_, kTlsAlertDecryptError); client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); } typedef std::tuple // server version TlsDowngradeProfile; class TlsDowngradeTest : public TlsConnectTestBase, public ::testing::WithParamInterface { public: TlsDowngradeTest() : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())), c_ver(std::get<1>(GetParam())), s_ver(std::get<2>(GetParam())) {} protected: const uint16_t c_ver; const uint16_t s_ver; }; TEST_P(TlsDowngradeTest, TlsDowngradeSentinelTest) { static const uint8_t tls12_downgrade_random[] = {0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x01}; static const uint8_t tls1_downgrade_random[] = {0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x00}; static const size_t kRandomLen = 32; if (c_ver > s_ver) { GTEST_SKIP(); } client_->SetVersionRange(c_ver, c_ver); server_->SetVersionRange(c_ver, s_ver); auto sh = MakeTlsFilter(server_, ssl_hs_server_hello); Connect(); ASSERT_TRUE(sh->buffer().len() > (kRandomLen + 2)); const uint8_t* downgrade_sentinel = sh->buffer().data() + 2 + kRandomLen - sizeof(tls1_downgrade_random); if (c_ver < s_ver) { if (c_ver == SSL_LIBRARY_VERSION_TLS_1_2) { EXPECT_EQ(0, memcmp(downgrade_sentinel, tls12_downgrade_random, sizeof(tls12_downgrade_random))); } else { EXPECT_EQ(0, memcmp(downgrade_sentinel, tls1_downgrade_random, sizeof(tls1_downgrade_random))); } } else { EXPECT_NE(0, memcmp(downgrade_sentinel, tls12_downgrade_random, sizeof(tls12_downgrade_random))); EXPECT_NE(0, memcmp(downgrade_sentinel, tls1_downgrade_random, sizeof(tls1_downgrade_random))); } } // TLS 1.1 clients do not check the random values, so we should // instead get a handshake failure alert from the server. TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) { // Setting the option here has no effect. client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE); MakeTlsFilter(client_, kTlsHandshakeClientHello, SSL_LIBRARY_VERSION_TLS_1_0); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, SSL_LIBRARY_VERSION_TLS_1_1); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, SSL_LIBRARY_VERSION_TLS_1_2); ConnectExpectAlert(server_, kTlsAlertDecryptError); server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); } TEST_F(TlsConnectTest, TestFallbackFromTls12) { client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE); 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); } static SECStatus AllowFalseStart(PRFileDesc* fd, void* arg, PRBool* can_false_start) { bool* false_start_attempted = reinterpret_cast(arg); *false_start_attempted = true; *can_false_start = PR_TRUE; return SECSuccess; } // If we disable the downgrade check, the sentinel is still generated, and we // disable false start instead. TEST_F(TlsConnectTest, DisableFalseStartOnFallback) { // Don't call client_->EnableFalseStart(), because that sets the client up for // success, and we want false start to fail. client_->SetOption(SSL_ENABLE_FALSE_START, PR_TRUE); bool false_start_attempted = false; EXPECT_EQ(SECSuccess, SSL_SetCanFalseStartCallback(client_->ssl_fd(), AllowFalseStart, &false_start_attempted)); client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_FALSE); client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_3); 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); Connect(); EXPECT_FALSE(false_start_attempted); } TEST_F(TlsConnectTest, TestFallbackFromTls13) { client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE); client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_3); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_2); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1, SSL_LIBRARY_VERSION_TLS_1_3); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } TEST_P(TlsConnectGeneric, TestFallbackSCSVVersionMatch) { client_->SetOption(SSL_ENABLE_FALLBACK_SCSV, PR_TRUE); Connect(); } TEST_P(TlsConnectGenericPre13, TestFallbackSCSVVersionMismatch) { client_->SetOption(SSL_ENABLE_FALLBACK_SCSV, PR_TRUE); server_->SetVersionRange(version_, version_ + 1); ConnectExpectAlert(server_, kTlsAlertInappropriateFallback); client_->CheckErrorCode(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT); server_->CheckErrorCode(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT); } // The TLS v1.3 spec section C.4 states that 'Implementations MUST NOT send or // accept any records with a version less than { 3, 0 }'. Thus we will not // allow version ranges including both SSL v3 and TLS v1.3. TEST_F(TlsConnectTest, DisallowSSLv3HelloWithTLSv13Enabled) { SECStatus rv; SSLVersionRange vrange = {SSL_LIBRARY_VERSION_3_0, SSL_LIBRARY_VERSION_TLS_1_3}; EnsureTlsSetup(); rv = SSL_VersionRangeSet(client_->ssl_fd(), &vrange); EXPECT_EQ(SECFailure, rv); rv = SSL_VersionRangeSet(server_->ssl_fd(), &vrange); EXPECT_EQ(SECFailure, rv); } TEST_P(TlsConnectGeneric, AlertBeforeServerHello) { EnsureTlsSetup(); client_->ExpectReceiveAlert(kTlsAlertUnrecognizedName, kTlsAlertWarning); StartConnect(); client_->Handshake(); // Send ClientHello. static const uint8_t kWarningAlert[] = {kTlsAlertWarning, kTlsAlertUnrecognizedName}; DataBuffer alert; TlsAgentTestBase::MakeRecord(variant_, ssl_ct_alert, SSL_LIBRARY_VERSION_TLS_1_0, kWarningAlert, PR_ARRAY_SIZE(kWarningAlert), &alert); client_->adapter()->PacketReceived(alert); Handshake(); CheckConnected(); } class Tls13NoSupportedVersions : public TlsConnectStreamTls12 { protected: void Run(uint16_t overwritten_client_version, uint16_t max_server_version) { client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_2); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, max_server_version); MakeTlsFilter(client_, kTlsHandshakeClientHello, overwritten_client_version); auto capture = MakeTlsFilter(server_, kTlsHandshakeServerHello); ConnectExpectAlert(server_, kTlsAlertDecryptError); client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); const DataBuffer& server_hello = capture->buffer(); ASSERT_GT(server_hello.len(), 2U); uint32_t ver; ASSERT_TRUE(server_hello.Read(0, 2, &ver)); ASSERT_EQ(static_cast(SSL_LIBRARY_VERSION_TLS_1_2), ver); } }; // If we offer a 1.3 ClientHello w/o supported_versions, the server should // negotiate 1.2. TEST_F(Tls13NoSupportedVersions, Tls13ClientHelloWithoutSupportedVersionsServer12) { Run(SSL_LIBRARY_VERSION_TLS_1_3, SSL_LIBRARY_VERSION_TLS_1_2); } TEST_F(Tls13NoSupportedVersions, Tls13ClientHelloWithoutSupportedVersionsServer13) { Run(SSL_LIBRARY_VERSION_TLS_1_3, SSL_LIBRARY_VERSION_TLS_1_3); } TEST_F(Tls13NoSupportedVersions, Tls14ClientHelloWithoutSupportedVersionsServer13) { Run(SSL_LIBRARY_VERSION_TLS_1_3 + 1, SSL_LIBRARY_VERSION_TLS_1_3); } // Offer 1.3 but with ClientHello.legacy_version == TLS 1.4. This // causes a bad MAC error when we read EncryptedExtensions. TEST_F(TlsConnectStreamTls13, Tls14ClientHelloWithSupportedVersions) { MakeTlsFilter(client_, kTlsHandshakeClientHello, SSL_LIBRARY_VERSION_TLS_1_3 + 1); auto capture = MakeTlsFilter( server_, ssl_tls13_supported_versions_xtn); client_->ExpectSendAlert(kTlsAlertBadRecordMac); server_->ExpectSendAlert(kTlsAlertBadRecordMac); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); ASSERT_EQ(2U, capture->extension().len()); uint32_t version = 0; ASSERT_TRUE(capture->extension().Read(0, 2, &version)); // This way we don't need to change with new draft version. ASSERT_LT(static_cast(SSL_LIBRARY_VERSION_TLS_1_2), version); } // Offer 1.3 but with Server/ClientHello.legacy_version == SSL 3.0. This // causes a protocol version alert. See RFC 8446 Appendix D.5. TEST_F(TlsConnectStreamTls13, Ssl30ClientHelloWithSupportedVersions) { MakeTlsFilter(client_, kTlsHandshakeClientHello, SSL_LIBRARY_VERSION_3_0); ConnectExpectAlert(server_, kTlsAlertProtocolVersion); } TEST_F(TlsConnectStreamTls13, Ssl30ServerHelloWithSupportedVersions) { MakeTlsFilter(server_, kTlsHandshakeServerHello, SSL_LIBRARY_VERSION_3_0); StartConnect(); client_->ExpectSendAlert(kTlsAlertProtocolVersion); /* Since the handshake is not finished the client will send an unencrypted * alert. The server is expected to close the connection with a unexpected * message alert. */ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage); Handshake(); } // Verify the client sends only DTLS versions in supported_versions TEST_F(DtlsConnectTest, DtlsSupportedVersionsEncoding) { client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1, SSL_LIBRARY_VERSION_TLS_1_3); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1, SSL_LIBRARY_VERSION_TLS_1_3); auto capture = MakeTlsFilter( client_, ssl_tls13_supported_versions_xtn); Connect(); ASSERT_EQ(7U, capture->extension().len()); uint32_t version = 0; ASSERT_TRUE(capture->extension().Read(1, 2, &version)); EXPECT_EQ(0x7f00 | DTLS_1_3_DRAFT_VERSION, static_cast(version)); ASSERT_TRUE(capture->extension().Read(3, 2, &version)); EXPECT_EQ(SSL_LIBRARY_VERSION_DTLS_1_2_WIRE, static_cast(version)); ASSERT_TRUE(capture->extension().Read(5, 2, &version)); EXPECT_EQ(SSL_LIBRARY_VERSION_DTLS_1_0_WIRE, static_cast(version)); } // Verify the DTLS 1.3 supported_versions interop workaround. TEST_F(DtlsConnectTest, Dtls13VersionWorkaround) { static const uint16_t kExpectVersionsWorkaround[] = { 0x7f00 | DTLS_1_3_DRAFT_VERSION, SSL_LIBRARY_VERSION_DTLS_1_2_WIRE, SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_DTLS_1_0_WIRE, SSL_LIBRARY_VERSION_TLS_1_1}; const int min_ver = SSL_LIBRARY_VERSION_TLS_1_1, max_ver = SSL_LIBRARY_VERSION_TLS_1_3; // Toggle the workaround, then verify both encodings are present. EnsureTlsSetup(); SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_TRUE); SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_FALSE); SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_TRUE); client_->SetVersionRange(min_ver, max_ver); server_->SetVersionRange(min_ver, max_ver); auto capture = MakeTlsFilter( client_, ssl_tls13_supported_versions_xtn); Connect(); uint32_t version = 0; size_t off = 1; ASSERT_EQ(1 + sizeof(kExpectVersionsWorkaround), capture->extension().len()); for (unsigned int i = 0; i < PR_ARRAY_SIZE(kExpectVersionsWorkaround); i++) { ASSERT_TRUE(capture->extension().Read(off, 2, &version)); EXPECT_EQ(kExpectVersionsWorkaround[i], static_cast(version)); off += 2; } } // Verify the client sends only TLS versions in supported_versions TEST_F(TlsConnectTest, TlsSupportedVersionsEncoding) { client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, SSL_LIBRARY_VERSION_TLS_1_3); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, SSL_LIBRARY_VERSION_TLS_1_3); auto capture = MakeTlsFilter( client_, ssl_tls13_supported_versions_xtn); Connect(); ASSERT_EQ(9U, capture->extension().len()); uint32_t version = 0; ASSERT_TRUE(capture->extension().Read(1, 2, &version)); EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_3, static_cast(version)); ASSERT_TRUE(capture->extension().Read(3, 2, &version)); EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, static_cast(version)); ASSERT_TRUE(capture->extension().Read(5, 2, &version)); EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, static_cast(version)); ASSERT_TRUE(capture->extension().Read(7, 2, &version)); EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, static_cast(version)); } /* Test that on reception of unsupported ClientHello.legacy_version the TLS 1.3 * server sends the correct alert. * * If the "supported_versions" extension is absent and the server only supports * versions greater than ClientHello.legacy_version, the server MUST abort the * handshake with a "protocol_version" alert [RFC8446, Appendix D.2]. */ TEST_P(TlsConnectGenericPre13, ClientHelloUnsupportedTlsVersion) { StartConnect(); if (variant_ == ssl_variant_stream) { server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3, SSL_LIBRARY_VERSION_TLS_1_3); } else { server_->SetVersionRange(SSL_LIBRARY_VERSION_DTLS_1_3, SSL_LIBRARY_VERSION_DTLS_1_3); } // Try to handshake client_->Handshake(); // Expect protocol version alert server_->ExpectSendAlert(kTlsAlertProtocolVersion); server_->Handshake(); // Digest alert at peer client_->ExpectReceiveAlert(kTlsAlertProtocolVersion); client_->ReadBytes(); } INSTANTIATE_TEST_SUITE_P( TlsDowngradeSentinelTest, TlsDowngradeTest, ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream, TlsConnectTestBase::kTlsVAll, TlsConnectTestBase::kTlsV12Plus)); } // namespace nss_test