/* -*- 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 "gtest_utils.h" #include "tls_connect.h" #include "util.h" namespace nss_test { const uint8_t kTlsGreaseExtensionMessages[] = {kTlsHandshakeEncryptedExtensions, kTlsHandshakeCertificate}; const uint16_t kTlsGreaseValues[] = { 0x0a0a, 0x1a1a, 0x2a2a, 0x3a3a, 0x4a4a, 0x5a5a, 0x6a6a, 0x7a7a, 0x8a8a, 0x9a9a, 0xaaaa, 0xbaba, 0xcaca, 0xdada, 0xeaea, 0xfafa}; const uint8_t kTlsGreasePskValues[] = {0x0B, 0x2A, 0x49, 0x68, 0x87, 0xA6, 0xC5, 0xE4}; size_t countGreaseInBuffer(const DataBuffer& list) { if (!list.len()) { return 0; } size_t occurrence = 0; for (uint16_t greaseVal : kTlsGreaseValues) { for (size_t i = 0; i < (list.len() - 1); i += 2) { uint16_t sample = list.data()[i + 1] + (list.data()[i] << 8); if (greaseVal == sample) { occurrence++; } } } return occurrence; } class GreasePresenceAbsenceTestBase : public TlsConnectTestBase { public: GreasePresenceAbsenceTestBase(SSLProtocolVariant variant, uint16_t version, bool shouldGrease) : TlsConnectTestBase(variant, version), set_grease_(shouldGrease){}; void SetupGrease() { EnsureTlsSetup(); ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, set_grease_), SECSuccess); ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, set_grease_), SECSuccess); } bool expectGrease() { return set_grease_ && version_ >= SSL_LIBRARY_VERSION_TLS_1_3; } void checkGreasePresence(const int ifEnabled, const int ifDisabled, const DataBuffer& buffer) { size_t expected = expectGrease() ? size_t(ifEnabled) : size_t(ifDisabled); EXPECT_EQ(expected, countGreaseInBuffer(buffer)); } private: bool set_grease_; }; class GreasePresenceAbsenceTestAllVersions : public GreasePresenceAbsenceTestBase, public ::testing::WithParamInterface< std::tuple> { public: GreasePresenceAbsenceTestAllVersions() : GreasePresenceAbsenceTestBase(std::get<0>(GetParam()), std::get<1>(GetParam()), std::get<2>(GetParam())){}; }; // Varies stream/datagram, TLS Version and whether GREASE is enabled INSTANTIATE_TEST_SUITE_P(GreaseTests, GreasePresenceAbsenceTestAllVersions, ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll, TlsConnectTestBase::kTlsV11Plus, ::testing::Values(true, false))); // Varies whether GREASE is enabled for TLS13 only class GreasePresenceAbsenceTestTlsStream13 : public GreasePresenceAbsenceTestBase, public ::testing::WithParamInterface { public: GreasePresenceAbsenceTestTlsStream13() : GreasePresenceAbsenceTestBase( ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3, GetParam()){}; }; INSTANTIATE_TEST_SUITE_P(GreaseTests, GreasePresenceAbsenceTestTlsStream13, ::testing::Values(true, false)); // These tests check for the presence / absence of GREASE values in the various // positions that we are permitted to add them. For positions which existed in // prior versions of TLS, we check that enabling GREASE is only effective when // negotiating TLS1.3 or higher and that disabling GREASE results in the absence // of any GREASE values. // For positions that specific to TLS1.3, we only check that enabling/disabling // GREASE results in the correct presence/absence of the GREASE value. TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseCiphersuites) { SetupGrease(); auto ch1 = MakeTlsFilter(client_); Connect(); EXPECT_TRUE(ch1->captured()); checkGreasePresence(1, 0, ch1->contents()); } TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseNamedGroups) { SetupGrease(); auto ch1 = MakeTlsFilter(client_, ssl_supported_groups_xtn); Connect(); EXPECT_TRUE(ch1->captured()); checkGreasePresence(1, 0, ch1->extension()); } TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseKeyShare) { SetupGrease(); auto ch1 = MakeTlsFilter(client_, ssl_tls13_key_share_xtn); Connect(); EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_3) == ch1->captured()); checkGreasePresence(1, 0, ch1->extension()); } TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseSigAlg) { SetupGrease(); auto ch1 = MakeTlsFilter(client_, ssl_signature_algorithms_xtn); Connect(); EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_2) == ch1->captured()); checkGreasePresence(1, 0, ch1->extension()); } TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseSupportedVersions) { SetupGrease(); auto ch1 = MakeTlsFilter( client_, ssl_tls13_supported_versions_xtn); Connect(); EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_3) == ch1->captured()); // Supported Versions have a 1 byte length field. TlsParser extParser(ch1->extension()); DataBuffer versions; extParser.ReadVariable(&versions, 1); checkGreasePresence(1, 0, versions); } TEST_P(GreasePresenceAbsenceTestTlsStream13, ClientGreasePskExchange) { SetupGrease(); auto ch1 = MakeTlsFilter( client_, ssl_tls13_psk_key_exchange_modes_xtn); Connect(); EXPECT_TRUE(ch1->captured()); // PSK Exchange Modes have a 1 byte length field TlsParser extParser(ch1->extension()); DataBuffer modes; extParser.ReadVariable(&modes, 1); // Scan for single byte GREASE PSK Values size_t numGrease = 0; for (uint8_t greaseVal : kTlsGreasePskValues) { for (unsigned long i = 0; i < modes.len(); i++) { if (greaseVal == modes.data()[i]) { numGrease++; } } } EXPECT_EQ(expectGrease() ? size_t(1) : size_t(0), numGrease); } TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseAlpn) { SetupGrease(); EnableAlpn(); auto ch1 = MakeTlsFilter(client_, ssl_app_layer_protocol_xtn); Connect(); EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_1) == ch1->captured()); // ALPN Xtns have a redundant two-byte length TlsParser alpnParser(ch1->extension()); alpnParser.Skip(2); // Skip the length DataBuffer alpnEntry; // Each ALPN entry has a single byte length prefixed. size_t greaseAlpnEntrys = 0; while (alpnParser.remaining()) { alpnParser.ReadVariable(&alpnEntry, 1); if (alpnEntry.len() == 2) { greaseAlpnEntrys += countGreaseInBuffer(alpnEntry); } } EXPECT_EQ(expectGrease() ? size_t(1) : size_t(0), greaseAlpnEntrys); } TEST_P(GreasePresenceAbsenceTestAllVersions, GreaseClientHelloExtension) { SetupGrease(); auto ch1 = MakeTlsFilter(client_, kTlsHandshakeClientHello); Connect(); EXPECT_TRUE(ch1->buffer().len() > 0); TlsParser extParser(ch1->buffer()); EXPECT_TRUE(extParser.Skip(2 + 32)); // Version + Random EXPECT_TRUE(extParser.SkipVariable(1)); // Session ID if (variant_ == ssl_variant_datagram) { EXPECT_TRUE(extParser.SkipVariable(1)); // Cookie } EXPECT_TRUE(extParser.SkipVariable(2)); // Ciphersuites EXPECT_TRUE(extParser.SkipVariable(1)); // Compression Methods EXPECT_TRUE(extParser.Skip(2)); // Extension Lengths // Scan for a 1-byte and a 0-byte extension. uint32_t extType; DataBuffer extBuf; bool foundSmall = false; bool foundLarge = false; size_t numFound = 0; while (extParser.remaining()) { extParser.Read(&extType, 2); extParser.ReadVariable(&extBuf, 2); for (uint16_t greaseVal : kTlsGreaseValues) { if (greaseVal == extType) { numFound++; foundSmall |= extBuf.len() == 0; foundLarge |= extBuf.len() > 0; } } } EXPECT_EQ(foundSmall, expectGrease()); EXPECT_EQ(foundLarge, expectGrease()); EXPECT_EQ(numFound, expectGrease() ? size_t(2) : size_t(0)); } TEST_P(GreasePresenceAbsenceTestTlsStream13, GreaseCertificateRequestSigAlg) { SetupGrease(); client_->SetupClientAuth(); server_->RequestClientAuth(true); auto cr = MakeTlsFilter(server_, ssl_signature_algorithms_xtn); cr->SetHandshakeTypes({kTlsHandshakeCertificateRequest}); cr->EnableDecryption(); Connect(); EXPECT_TRUE(cr->captured()); checkGreasePresence(1, 0, cr->extension()); } TEST_P(GreasePresenceAbsenceTestTlsStream13, GreaseCertificateRequestExtension) { SetupGrease(); client_->SetupClientAuth(); server_->RequestClientAuth(true); auto cr = MakeTlsFilter( server_, kTlsHandshakeCertificateRequest); cr->EnableDecryption(); Connect(); EXPECT_TRUE(cr->buffer().len() > 0); TlsParser extParser(cr->buffer()); EXPECT_TRUE(extParser.SkipVariable(1)); // Context EXPECT_TRUE(extParser.Skip(2)); // Extension Lengths uint32_t extType; DataBuffer extBuf; bool found = false; // Scan for a single, empty extension while (extParser.remaining()) { extParser.Read(&extType, 2); extParser.ReadVariable(&extBuf, 2); for (uint16_t greaseVal : kTlsGreaseValues) { if (greaseVal == extType) { EXPECT_TRUE(!found); EXPECT_EQ(extBuf.len(), size_t(0)); found = true; } } } EXPECT_EQ(expectGrease(), found); } TEST_P(GreasePresenceAbsenceTestTlsStream13, GreaseNewSessionTicketExtension) { SetupGrease(); auto nst = MakeTlsFilter(server_, kTlsHandshakeNewSessionTicket); nst->EnableDecryption(); Connect(); EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0)); EXPECT_TRUE(nst->buffer().len() > 0); TlsParser extParser(nst->buffer()); EXPECT_TRUE(extParser.Skip(4)); // lifetime EXPECT_TRUE(extParser.Skip(4)); // age EXPECT_TRUE(extParser.SkipVariable(1)); // Nonce EXPECT_TRUE(extParser.SkipVariable(2)); // Ticket EXPECT_TRUE(extParser.Skip(2)); // Extension Length uint32_t extType; DataBuffer extBuf; bool found = false; // Scan for a single, empty extension while (extParser.remaining()) { extParser.Read(&extType, 2); extParser.ReadVariable(&extBuf, 2); for (uint16_t greaseVal : kTlsGreaseValues) { if (greaseVal == extType) { EXPECT_TRUE(!found); EXPECT_EQ(extBuf.len(), size_t(0)); found = true; } } } EXPECT_EQ(expectGrease(), found); } // Generic Client GREASE test TEST_P(TlsConnectGeneric, ClientGrease) { EnsureTlsSetup(); ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); Connect(); } // Generic Server GREASE test TEST_P(TlsConnectGeneric, ServerGrease) { EnsureTlsSetup(); ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); Connect(); } // Generic GREASE test TEST_P(TlsConnectGeneric, Grease) { EnsureTlsSetup(); ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); Connect(); } // Check that GREASE values can be correctly reconstructed after HRR. TEST_P(TlsConnectGeneric, GreaseHRR) { EnsureTlsSetup(); const std::vector client_groups = { ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1}; const std::vector server_groups = { ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519}; client_->ConfigNamedGroups(client_groups); server_->ConfigNamedGroups(server_groups); ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); Connect(); } // Check that GREASE additions interact correctly with psk-only handshake. TEST_F(TlsConnectStreamTls13, GreasePsk) { EnsureTlsSetup(); ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); const uint8_t kPskDummyVal_[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; SECItem psk_item; psk_item.type = siBuffer; psk_item.len = sizeof(kPskDummyVal_); psk_item.data = const_cast(kPskDummyVal_); PK11SymKey* key = PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap, CKA_DERIVE, &psk_item, NULL); ScopedPK11SymKey scoped_psk_(key); const std::string kPskDummyLabel_ = "NSS PSK GTEST label"; const SSLHashType kPskHash_ = ssl_hash_sha384; AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_); Connect(); SendReceive(); CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none); } // Test that ECH and GREASE work together successfully TEST_F(TlsConnectStreamTls13, GreaseAndECH) { EnsureTlsSetup(); SetupEch(client_, server_); ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); Connect(); } // Test that TLS12 Server handles Client GREASE correctly TEST_F(TlsConnectTest, GreaseTLS12Server) { EnsureTlsSetup(); ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_2); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_3); Connect(); } // Test that TLS12 Client handles Server GREASE correctly TEST_F(TlsConnectTest, GreaseTLS12Client) { EnsureTlsSetup(); ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE), SECSuccess); server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_3); client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_TLS_1_2); Connect(); } class GreaseOnlyTestStreamTls13 : public TlsConnectStreamTls13 { public: GreaseOnlyTestStreamTls13() : TlsConnectStreamTls13() {} void ConnectWithCustomChExpectFail(const std::string& ch, uint8_t server_alert, uint32_t server_code, uint32_t client_code) { std::vector ch_vec = hex_string_to_bytes(ch); DataBuffer ch_buf; EnsureTlsSetup(); TlsAgentTestBase::MakeRecord(variant_, ssl_ct_handshake, SSL_LIBRARY_VERSION_TLS_1_3, ch_vec.data(), ch_vec.size(), &ch_buf, 0); StartConnect(); client_->SendDirect(ch_buf); ExpectAlert(server_, server_alert); server_->Handshake(); server_->CheckErrorCode(server_code); client_->ExpectReceiveAlert(server_alert, kTlsAlertFatal); client_->Handshake(); client_->CheckErrorCode(client_code); } }; // Client: Offer only GREASE CipherSuite value TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientCipherSuite) { // 0xdada std::string ch = "010000b003038afacda2963358e98f464f3ff0680ed3a9d382a8c3eac5e5604f5721add9" "855c000002dada010000850000000b0009000006736572766572ff01000100000a001400" "12001d00170018001901000101010201030104003300260024001d0020683668992de470" "38660ee37bafc7392b05b8a94402ea1f3463ad3cfd7a694a46002b0003020304000d0018" "001604030503060302030804080508060401050106010201002d00020101001c0002400" "1"; ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure, SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_NO_CYPHER_OVERLAP); } // Client: Offer only GREASE SupportedGroups value TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSupportedGroup) { // 0x3a3a std::string ch = "010000a40303484a4e14f547404da6115d7f73bbb0f1c9d65e66ac073dee6c4a62f72de9" "a36f000006130113031302010000750000000b0009000006736572766572ff0100010000" "0a000400023a3a003300260024001d0020e75cb8e217c95176954e8b5fb95843882462ce" "2cd3fcfe67cf31463a05ea3d57002b0003020304000d0018001604030503060302030804" "080508060401050106010201002d00020101001c00024001"; ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure, SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_NO_CYPHER_OVERLAP); } // Client: Offer only GREASE SigAlgs value TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSignatureAlgorithm) { // 0x8a8a std::string ch = "010000a00303dfd8e2438a8d1b9f48d921dfc08959108807bd1105238bb3da2a2a8e3db0" "6990000006130113031302010000710000000b0009000006736572766572ff0100010000" "0a00140012001d00170018001901000101010201030104003300260024001d002074bb2c" "94996d3ffc7ae5792f0c3c58676358a85ea304cd029fa3d6551013b333002b0003020304" "000d000400028a8a002d00020101001c00024001"; ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure, SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM, SSL_ERROR_NO_CYPHER_OVERLAP); } // Client: Offer only GREASE SupportedVersions value TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSupportedVersion) { // 0xeaea std::string ch = "010000b203037e3618abae0dd0b3f06a504c47354551d1d5be36e9c3e1eac9c139c246b1" "66da000006130113031302010000830000000b0009000006736572766572ff0100010000" "0a00140012001d00170018001901000101010201030104003300260024001d00206b1816" "577ff2e69d4d2661419150eaefa0328ffd396425cf1733ec06536b4e55002b000100000d" "0018001604030503060302030804080508060401050106010201002d00020101001c0002" "4001"; ConnectWithCustomChExpectFail(ch, kTlsAlertIllegalParameter, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } class GreaseTestStreamTls12 : public TlsConnectStreamTls12, public ::testing::WithParamInterface { public: GreaseTestStreamTls12() : TlsConnectStreamTls12(), grease_(GetParam()){}; void ConnectExpectSigAlgFail() { client_->ExpectSendAlert(kTlsAlertIllegalParameter); server_->ExpectReceiveAlert(kTlsAlertIllegalParameter); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } protected: uint16_t grease_; }; class TlsCertificateRequestSigAlgSetterFilter : public TlsHandshakeFilter { public: TlsCertificateRequestSigAlgSetterFilter(const std::shared_ptr& a, uint16_t sigAlg) : TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}), sigAlg_(sigAlg) {} virtual PacketFilter::Action FilterHandshake( const TlsHandshakeFilter::HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) { TlsParser parser(input); DataBuffer cert_types; if (!parser.ReadVariable(&cert_types, 1)) { ADD_FAILURE(); return KEEP; } if (!parser.SkipVariable(2)) { ADD_FAILURE(); return KEEP; } DataBuffer cas; if (!parser.ReadVariable(&cas, 2)) { ADD_FAILURE(); return KEEP; } size_t idx = 0; // Write certificate types. idx = output->Write(idx, cert_types.len(), 1); idx = output->Write(idx, cert_types); // Write signature algorithm. idx = output->Write(idx, sizeof(sigAlg_), 2); idx = output->Write(idx, sigAlg_, 2); // Write certificate authorities. idx = output->Write(idx, cas.len(), 2); idx = output->Write(idx, cas); return CHANGE; } private: uint16_t sigAlg_; }; // Server: Offer only GREASE CertificateRequest SigAlg value TEST_P(GreaseTestStreamTls12, GreaseOnlyServerTLS12CertificateRequestSigAlg) { EnsureTlsSetup(); client_->SetupClientAuth(); server_->RequestClientAuth(true); MakeTlsFilter(server_, grease_); client_->ExpectSendAlert(kTlsAlertHandshakeFailure); server_->ExpectReceiveAlert(kTlsAlertHandshakeFailure); ConnectExpectFail(); server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT); client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); } // Illegally GREASE ServerKeyExchange ECC SignatureAlgorithm TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexEccSigAlg) { MakeTlsFilter(server_, grease_); EnableSomeEcdhCiphers(); client_->ExpectSendAlert(kTlsAlertIllegalParameter); server_->ExpectReceiveAlert(kTlsAlertIllegalParameter); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } // Illegally GREASE ServerKeyExchange DHE SignatureAlgorithm TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexDheSigAlg) { MakeTlsFilter(server_, grease_); EnableOnlyDheCiphers(); client_->ExpectSendAlert(kTlsAlertIllegalParameter); server_->ExpectReceiveAlert(kTlsAlertIllegalParameter); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } // Illegally GREASE ServerKeyExchange ECDHE NamedCurve TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexEcdheNamedCurve) { MakeTlsFilter(server_, grease_); EnableSomeEcdhCiphers(); client_->ExpectSendAlert(kTlsAlertHandshakeFailure); server_->ExpectReceiveAlert(kTlsAlertHandshakeFailure); ConnectExpectFail(); server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT); client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); } // Illegally GREASE TLS12 Client CertificateVerify SignatureAlgorithm TEST_P(GreaseTestStreamTls12, GreasedTLS12ClientCertificateVerifySigAlg) { client_->SetupClientAuth(); server_->RequestClientAuth(true); MakeTlsFilter(client_, grease_); server_->ExpectSendAlert(kTlsAlertIllegalParameter); client_->ExpectReceiveAlert(kTlsAlertIllegalParameter); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); } class GreaseTestStreamTls13 : public TlsConnectStreamTls13, public ::testing::WithParamInterface { public: GreaseTestStreamTls13() : grease_(GetParam()){}; protected: uint16_t grease_; }; // Illegally GREASE TLS13 Client CertificateVerify SignatureAlgorithm TEST_P(GreaseTestStreamTls13, GreasedTLS13ClientCertificateVerifySigAlg) { client_->SetupClientAuth(); server_->RequestClientAuth(true); auto filter = MakeTlsFilter(client_, grease_); filter->EnableDecryption(); server_->ExpectSendAlert(kTlsAlertIllegalParameter); client_->ExpectReceiveAlert(kTlsAlertIllegalParameter); // Manually trigger handshake to avoid race conditions StartConnect(); client_->Handshake(); server_->Handshake(); client_->Handshake(); server_->Handshake(); client_->Handshake(); server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY); client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } // Illegally GREASE TLS13 Server CertificateVerify SignatureAlgorithm TEST_P(GreaseTestStreamTls13, GreasedTLS13ServerCertificateVerifySigAlg) { EnsureTlsSetup(); auto filter = MakeTlsFilter(server_, grease_); filter->EnableDecryption(); client_->ExpectSendAlert(kTlsAlertIllegalParameter); server_->ExpectReceiveAlert(kTlsAlertIllegalParameter); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY); } // Illegally GREASE HelloRetryRequest version value TEST_P(GreaseTestStreamTls13, GreasedHelloRetryRequestVersion) { EnsureTlsSetup(); // Trigger HelloRetryRequest MakeTlsFilter(client_, ssl_tls13_key_share_xtn); auto filter = MakeTlsFilter( server_, kTlsHandshakeHelloRetryRequest, grease_); filter->EnableDecryption(); client_->ExpectSendAlert(kTlsAlertIllegalParameter); server_->ExpectReceiveAlert(kTlsAlertIllegalParameter); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } class GreaseTestStreamTls123 : public TlsConnectTestBase, public ::testing::WithParamInterface< std::tuple> { public: GreaseTestStreamTls123() : TlsConnectTestBase(ssl_variant_stream, std::get<0>(GetParam())), grease_(std::get<1>(GetParam())){}; void ConnectExpectIllegalGreaseFail() { client_->ExpectSendAlert(kTlsAlertIllegalParameter); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { // Server expects handshake but receives encrypted alert. server_->ExpectSendAlert(kTlsAlertUnexpectedMessage); } else { server_->ExpectReceiveAlert(kTlsAlertIllegalParameter); } ConnectExpectFail(); } protected: uint16_t grease_; }; // Illegally GREASE TLS12 and TLS13 ServerHello version value TEST_P(GreaseTestStreamTls123, GreasedServerHelloVersion) { EnsureTlsSetup(); auto filter = MakeTlsFilter( server_, kTlsHandshakeServerHello, grease_); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { filter->EnableDecryption(); } ConnectExpectIllegalGreaseFail(); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); } // Illegally GREASE TLS12 and TLS13 selected CipherSuite value TEST_P(GreaseTestStreamTls123, GreasedServerHelloCipherSuite) { EnsureTlsSetup(); auto filter = MakeTlsFilter(server_, grease_); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { filter->EnableDecryption(); } ConnectExpectIllegalGreaseFail(); client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); } class GreaseExtensionTestStreamTls13 : public TlsConnectStreamTls13, public ::testing::WithParamInterface< std::tuple> { public: GreaseExtensionTestStreamTls13() : TlsConnectStreamTls13(), message_(std::get<0>(GetParam())), grease_(std::get<1>(GetParam())){}; protected: uint8_t message_; uint16_t grease_; }; // Illegally GREASE TLS13 Server EncryptedExtensions and Certificate Extensions // NSS currently allows offering unkown extensions in HelloRetryRequests! TEST_P(GreaseExtensionTestStreamTls13, GreasedServerExtensions) { EnsureTlsSetup(); DataBuffer empty = DataBuffer(1); auto filter = MakeTlsFilter(server_, message_, grease_, empty); filter->EnableDecryption(); server_->ExpectReceiveAlert(kTlsAlertUnsupportedExtension); client_->ExpectSendAlert(kTlsAlertUnsupportedExtension); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION); server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT); } // Illegally GREASE TLS12 and TLS13 ServerHello Extensions TEST_P(GreaseTestStreamTls123, GreasedServerHelloExtensions) { EnsureTlsSetup(); DataBuffer empty = DataBuffer(1); auto filter = MakeTlsFilter( server_, kTlsHandshakeServerHello, grease_, empty); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { filter->EnableDecryption(); server_->ExpectSendAlert(kTlsAlertUnexpectedMessage); } else { server_->ExpectReceiveAlert(kTlsAlertUnsupportedExtension); } client_->ExpectSendAlert(kTlsAlertUnsupportedExtension); ConnectExpectFail(); client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION); } // Illegally GREASE TLS13 Client Certificate Extensions // Server ignores injected client extensions and fails on CertificateVerify TEST_P(GreaseTestStreamTls13, GreasedClientCertificateExtensions) { client_->SetupClientAuth(); server_->RequestClientAuth(true); DataBuffer empty = DataBuffer(1); auto filter = MakeTlsFilter( client_, kTlsHandshakeCertificate, grease_, empty); filter->EnableDecryption(); server_->ExpectSendAlert(kTlsAlertDecryptError); client_->ExpectReceiveAlert(kTlsAlertDecryptError); // Manually trigger handshake to avoid race conditions StartConnect(); client_->Handshake(); server_->Handshake(); client_->Handshake(); server_->Handshake(); client_->Handshake(); server_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE); client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); } TEST_F(TlsConnectStreamTls13, GreaseClientHelloExtensionPermutation) { EnsureTlsSetup(); ASSERT_TRUE(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_CH_EXTENSION_PERMUTATION, PR_TRUE) == SECSuccess); ASSERT_TRUE(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE) == SECSuccess); Connect(); } INSTANTIATE_TEST_SUITE_P(GreaseTestTls12, GreaseTestStreamTls12, ::testing::ValuesIn(kTlsGreaseValues)); INSTANTIATE_TEST_SUITE_P(GreaseTestTls13, GreaseTestStreamTls13, ::testing::ValuesIn(kTlsGreaseValues)); INSTANTIATE_TEST_SUITE_P( GreaseTestTls123, GreaseTestStreamTls123, ::testing::Combine(TlsConnectTestBase::kTlsV12Plus, ::testing::ValuesIn(kTlsGreaseValues))); INSTANTIATE_TEST_SUITE_P( GreaseExtensionTest, GreaseExtensionTestStreamTls13, testing::Combine(testing::ValuesIn(kTlsGreaseExtensionMessages), testing::ValuesIn(kTlsGreaseValues))); } // namespace nss_test