/* -*- 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 #include #include "secerr.h" #include "ssl.h" #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" #include "tls_parser.h" namespace nss_test { // variant, version, cipher suite typedef std::tuple CipherSuiteProfile; class TlsCipherSuiteTestBase : public TlsConnectTestBase { public: TlsCipherSuiteTestBase(SSLProtocolVariant variant, uint16_t version, uint16_t cipher_suite, SSLNamedGroup group, SSLSignatureScheme sig_scheme) : TlsConnectTestBase(variant, version), cipher_suite_(cipher_suite), group_(group), sig_scheme_(sig_scheme), csinfo_({0}) { SECStatus rv = SSL_GetCipherSuiteInfo(cipher_suite_, &csinfo_, sizeof(csinfo_)); EXPECT_EQ(SECSuccess, rv); if (rv == SECSuccess) { std::cerr << "Cipher suite: " << csinfo_.cipherSuiteName << std::endl; } auth_type_ = csinfo_.authType; kea_type_ = csinfo_.keaType; } protected: void EnableSingleCipher() { EnsureTlsSetup(); // It doesn't matter which does this, but the test is better if both do it. client_->EnableSingleCipher(cipher_suite_); server_->EnableSingleCipher(cipher_suite_); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { std::vector groups = {group_}; if (cert_group_ != ssl_grp_none) { groups.push_back(cert_group_); } client_->ConfigNamedGroups(groups); server_->ConfigNamedGroups(groups); kea_type_ = SSLInt_GetKEAType(group_); client_->SetSignatureSchemes(&sig_scheme_, 1); server_->SetSignatureSchemes(&sig_scheme_, 1); } } virtual void SetupCertificate() { 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_; break; } } else { switch (csinfo_.authType) { case ssl_auth_rsa_sign: Reset(TlsAgent::kServerRsaSign); break; case ssl_auth_rsa_decrypt: Reset(TlsAgent::kServerRsaDecrypt); 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); break; case ssl_auth_dsa: Reset(TlsAgent::kServerDsa); break; default: ASSERT_TRUE(false) << "Unsupported cipher suite: " << cipher_suite_; break; } } } void ConnectAndCheckCipherSuite() { Connect(); SendReceive(); // Check that we used the right cipher suite, auth type and kea type. uint16_t actual = TLS_NULL_WITH_NULL_NULL; EXPECT_TRUE(client_->cipher_suite(&actual)); EXPECT_EQ(cipher_suite_, actual); EXPECT_TRUE(server_->cipher_suite(&actual)); EXPECT_EQ(cipher_suite_, actual); SSLAuthType auth = ssl_auth_size; EXPECT_TRUE(client_->auth_type(&auth)); EXPECT_EQ(auth_type_, auth); EXPECT_TRUE(server_->auth_type(&auth)); EXPECT_EQ(auth_type_, auth); SSLKEAType kea = ssl_kea_size; EXPECT_TRUE(client_->kea_type(&kea)); EXPECT_EQ(kea_type_, kea); EXPECT_TRUE(server_->kea_type(&kea)); EXPECT_EQ(kea_type_, kea); } // Get the expected limit on the number of records that can be sent for the // cipher suite. uint64_t record_limit() const { switch (csinfo_.symCipher) { case ssl_calg_rc4: case ssl_calg_3des: return 1ULL << 20; case ssl_calg_aes: case ssl_calg_aes_gcm: return 0x5aULL << 28; case ssl_calg_null: case ssl_calg_chacha20: return (1ULL << 48) - 1; case ssl_calg_rc2: case ssl_calg_des: case ssl_calg_idea: case ssl_calg_fortezza: case ssl_calg_camellia: case ssl_calg_seed: break; } ADD_FAILURE() << "No limit for " << csinfo_.cipherSuiteName; return 0; } uint64_t last_safe_write() const { uint64_t limit = record_limit() - 1; if (version_ < SSL_LIBRARY_VERSION_TLS_1_1 && (csinfo_.symCipher == ssl_calg_3des || csinfo_.symCipher == ssl_calg_aes)) { // 1/n-1 record splitting needs space for two records. limit--; } return limit; } protected: uint16_t cipher_suite_; SSLAuthType auth_type_; SSLKEAType kea_type_; SSLNamedGroup group_; SSLNamedGroup cert_group_ = ssl_grp_none; SSLSignatureScheme sig_scheme_; SSLCipherSuiteInfo csinfo_; }; class TlsCipherSuiteTest : public TlsCipherSuiteTestBase, public ::testing::WithParamInterface { public: TlsCipherSuiteTest() : TlsCipherSuiteTestBase(std::get<0>(GetParam()), std::get<1>(GetParam()), std::get<2>(GetParam()), std::get<3>(GetParam()), std::get<4>(GetParam())) {} protected: bool SkipIfCipherSuiteIsDSA() { bool isDSA = csinfo_.authType == ssl_auth_dsa; if (isDSA) { std::cerr << "Skipping DSA suite: " << csinfo_.cipherSuiteName << std::endl; } return isDSA; } }; TEST_P(TlsCipherSuiteTest, SingleCipherSuite) { SetupCertificate(); EnableSingleCipher(); ConnectAndCheckCipherSuite(); } TEST_P(TlsCipherSuiteTest, ResumeCipherSuite) { if (SkipIfCipherSuiteIsDSA()) { GTEST_SKIP() << "Tickets not supported with DSA (bug 1174677)."; } SetupCertificate(); // This is only needed once. ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); EnableSingleCipher(); ConnectAndCheckCipherSuite(); Reset(); ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); EnableSingleCipher(); ExpectResumption(RESUME_TICKET); ConnectAndCheckCipherSuite(); } TEST_P(TlsCipherSuiteTest, ReadLimit) { SetupCertificate(); EnableSingleCipher(); TlsSendCipherSpecCapturer capturer(client_); ConnectAndCheckCipherSuite(); if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) { uint64_t last = last_safe_write(); EXPECT_EQ(SECSuccess, SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), last)); EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), last)); client_->SendData(10, 10); server_->ReadBytes(); // This should be OK. server_->ReadBytes(); // Read twice to flush any 1,N-1 record splitting. } else { // In TLS 1.3, reading or writing triggers a KeyUpdate. That would mean // that the sequence numbers would reset and we wouldn't hit the limit. So // move the sequence number to the limit directly and don't test sending and // receiving just before the limit. uint64_t last = record_limit(); EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), last)); } // The payload needs to be big enough to pass for encrypted. The code checks // the limit before it tries to decrypt. static const uint8_t payload[32] = {6}; DataBuffer record; uint64_t epoch; if (variant_ == ssl_variant_datagram) { if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) { epoch = 3; // Application traffic keys. } else { epoch = 1; } } else { epoch = 0; } uint64_t seqno = (epoch << 48) | record_limit(); // DTLS 1.3 masks the sequence number if (variant_ == ssl_variant_datagram && version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { auto spec = capturer.spec(1); ASSERT_NE(nullptr, spec.get()); ASSERT_EQ(3, spec->epoch()); DataBuffer pt, ct; uint8_t dtls13_ctype = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno | kCtDtlsCiphertextLengthPresent; TlsRecordHeader hdr(variant_, version_, dtls13_ctype, seqno); pt.Assign(payload, sizeof(payload)); TlsRecordHeader out_hdr; spec->Protect(hdr, pt, &ct, &out_hdr); auto rv = out_hdr.Write(&record, 0, ct); EXPECT_EQ(out_hdr.header_length() + ct.len(), rv); } else { TlsAgentTestBase::MakeRecord(variant_, ssl_ct_application_data, version_, payload, sizeof(payload), &record, seqno); } client_->SendDirect(record); server_->ExpectReadWriteError(); server_->ReadBytes(); EXPECT_EQ(SSL_ERROR_TOO_MANY_RECORDS, server_->error_code()); } TEST_P(TlsCipherSuiteTest, WriteLimit) { // This asserts in TLS 1.3 because we expect an automatic update. if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { GTEST_SKIP(); } SetupCertificate(); EnableSingleCipher(); ConnectAndCheckCipherSuite(); EXPECT_EQ(SECSuccess, SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), last_safe_write())); client_->SendData(10, 10); client_->ExpectReadWriteError(); client_->SendData(10, 10); EXPECT_EQ(SSL_ERROR_TOO_MANY_RECORDS, client_->error_code()); } // This awful macro makes the test instantiations easier to read. #define INSTANTIATE_CIPHER_TEST_P(name, modes, versions, groups, sigalgs, ...) \ static const uint16_t k##name##CiphersArr[] = {__VA_ARGS__}; \ static const ::testing::internal::ParamGenerator \ k##name##Ciphers = ::testing::ValuesIn(k##name##CiphersArr); \ INSTANTIATE_TEST_SUITE_P( \ CipherSuite##name, TlsCipherSuiteTest, \ ::testing::Combine(TlsConnectTestBase::kTlsVariants##modes, \ TlsConnectTestBase::kTls##versions, k##name##Ciphers, \ groups, sigalgs)); static const auto kDummyNamedGroupParams = ::testing::Values(ssl_grp_none); static const auto kDummySignatureSchemesParams = ::testing::Values(ssl_sig_none); static SSLSignatureScheme kSignatureSchemesParamsArr[] = { ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pkcs1_sha384, ssl_sig_rsa_pkcs1_sha512, ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384, ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_rsae_sha384, ssl_sig_rsa_pss_rsae_sha512, ssl_sig_rsa_pss_pss_sha256, ssl_sig_rsa_pss_pss_sha384, ssl_sig_rsa_pss_pss_sha512}; static SSLSignatureScheme kSignatureSchemesParamsArrTls13[] = { ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384, ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_rsae_sha384, ssl_sig_rsa_pss_rsae_sha512, ssl_sig_rsa_pss_pss_sha256, ssl_sig_rsa_pss_pss_sha384, ssl_sig_rsa_pss_pss_sha512}; INSTANTIATE_CIPHER_TEST_P(RC4, Stream, V10ToV12, kDummyNamedGroupParams, kDummySignatureSchemesParams, TLS_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA); INSTANTIATE_CIPHER_TEST_P(AEAD12, All, V12, kDummyNamedGroupParams, kDummySignatureSchemesParams, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384); INSTANTIATE_CIPHER_TEST_P(AEAD, All, V12, kDummyNamedGroupParams, kDummySignatureSchemesParams, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256); INSTANTIATE_CIPHER_TEST_P( CBC12, All, V12, kDummyNamedGroupParams, kDummySignatureSchemesParams, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256); INSTANTIATE_CIPHER_TEST_P( CBCStream, Stream, V10ToV12, kDummyNamedGroupParams, kDummySignatureSchemesParams, TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_NULL_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA); INSTANTIATE_CIPHER_TEST_P( CBCDatagram, Datagram, V11V12, kDummyNamedGroupParams, kDummySignatureSchemesParams, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA); INSTANTIATE_CIPHER_TEST_P( TLS12SigSchemes, All, V12, ::testing::ValuesIn(kFasterDHEGroups), ::testing::ValuesIn(kSignatureSchemesParamsArr), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256); #ifndef NSS_DISABLE_TLS_1_3 INSTANTIATE_CIPHER_TEST_P(TLS13, All, V13, ::testing::ValuesIn(kFasterDHEGroups), ::testing::ValuesIn(kSignatureSchemesParamsArrTls13), TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_256_GCM_SHA384); INSTANTIATE_CIPHER_TEST_P(TLS13AllGroups, All, V13, ::testing::ValuesIn(kAllDHEGroups), ::testing::Values(ssl_sig_ecdsa_secp384r1_sha384), TLS_AES_256_GCM_SHA384); #endif // Fields are: version, cipher suite, bulk cipher name, secretKeySize struct SecStatusParams { uint16_t version; uint16_t cipher_suite; std::string name; int keySize; }; inline std::ostream &operator<<(std::ostream &stream, const SecStatusParams &vals) { SSLCipherSuiteInfo csinfo; SECStatus rv = SSL_GetCipherSuiteInfo(vals.cipher_suite, &csinfo, sizeof(csinfo)); if (rv != SECSuccess) { return stream << "Error invoking SSL_GetCipherSuiteInfo()"; } return stream << "TLS " << VersionString(vals.version) << ", " << csinfo.cipherSuiteName << ", name = \"" << vals.name << "\", key size = " << vals.keySize; } class SecurityStatusTest : public TlsCipherSuiteTestBase, public ::testing::WithParamInterface { public: SecurityStatusTest() : TlsCipherSuiteTestBase(ssl_variant_stream, GetParam().version, GetParam().cipher_suite, ssl_grp_none, ssl_sig_none) {} }; // SSL_SecurityStatus produces fairly useless output when compared to // SSL_GetCipherSuiteInfo and SSL_GetChannelInfo, but we can't break it, so we // need to check it. TEST_P(SecurityStatusTest, CheckSecurityStatus) { SetupCertificate(); EnableSingleCipher(); ConnectAndCheckCipherSuite(); int on; char *cipher; int keySize; int secretKeySize; char *issuer; char *subject; EXPECT_EQ(SECSuccess, SSL_SecurityStatus(client_->ssl_fd(), &on, &cipher, &keySize, &secretKeySize, &issuer, &subject)); if (std::string(cipher) == "NULL") { EXPECT_EQ(0, on); } else { EXPECT_NE(0, on); } EXPECT_EQ(GetParam().name, std::string(cipher)); // All the ciphers we support have secret key size == key size. EXPECT_EQ(GetParam().keySize, keySize); EXPECT_EQ(GetParam().keySize, secretKeySize); EXPECT_LT(0U, strlen(issuer)); EXPECT_LT(0U, strlen(subject)); PORT_Free(cipher); PORT_Free(issuer); PORT_Free(subject); } static const SecStatusParams kSecStatusTestValuesArr[] = { {SSL_LIBRARY_VERSION_TLS_1_0, TLS_ECDHE_RSA_WITH_NULL_SHA, "NULL", 0}, {SSL_LIBRARY_VERSION_TLS_1_0, TLS_RSA_WITH_RC4_128_SHA, "RC4", 128}, {SSL_LIBRARY_VERSION_TLS_1_0, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "3DES-EDE-CBC", 168}, {SSL_LIBRARY_VERSION_TLS_1_0, TLS_RSA_WITH_AES_128_CBC_SHA, "AES-128", 128}, {SSL_LIBRARY_VERSION_TLS_1_2, TLS_RSA_WITH_AES_256_CBC_SHA256, "AES-256", 256}, {SSL_LIBRARY_VERSION_TLS_1_2, TLS_RSA_WITH_AES_128_GCM_SHA256, "AES-128-GCM", 128}, {SSL_LIBRARY_VERSION_TLS_1_2, TLS_RSA_WITH_AES_256_GCM_SHA384, "AES-256-GCM", 256}, {SSL_LIBRARY_VERSION_TLS_1_2, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "ChaCha20-Poly1305", 256}}; INSTANTIATE_TEST_SUITE_P(TestSecurityStatus, SecurityStatusTest, ::testing::ValuesIn(kSecStatusTestValuesArr)); } // namespace nss_test