/* -*- 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 #include "secerr.h" #include "ssl.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(TlsConnectGeneric, ConnectDhe) { EnableOnlyDheCiphers(); Connect(); CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); } TEST_P(TlsConnectTls13, SharesForBothEcdheAndDhe) { EnsureTlsSetup(); client_->ConfigNamedGroups(kAllDHEGroups); auto groups_capture = std::make_shared(client_, ssl_supported_groups_xtn); auto shares_capture = std::make_shared(client_, ssl_tls13_key_share_xtn); std::vector> captures = {groups_capture, shares_capture}; client_->SetFilter(std::make_shared(captures)); Connect(); CheckKeys(); bool ec, dh; auto track_group_type = [&ec, &dh](SSLNamedGroup group) { if ((group & 0xff00U) == 0x100U) { dh = true; } else { ec = true; } }; CheckGroups(groups_capture->extension(), track_group_type); CheckShares(shares_capture->extension(), track_group_type); EXPECT_TRUE(ec) << "Should include an EC group and share"; EXPECT_TRUE(dh) << "Should include an FFDHE group and share"; } TEST_P(TlsConnectGeneric, ConnectFfdheClient) { EnableOnlyDheCiphers(); client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); auto groups_capture = std::make_shared(client_, ssl_supported_groups_xtn); auto shares_capture = std::make_shared(client_, ssl_tls13_key_share_xtn); std::vector> captures = {groups_capture, shares_capture}; client_->SetFilter(std::make_shared(captures)); Connect(); CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign); auto is_ffdhe = [](SSLNamedGroup group) { // The group has to be in this range. EXPECT_LE(ssl_grp_ffdhe_2048, group); EXPECT_GE(ssl_grp_ffdhe_8192, group); }; CheckGroups(groups_capture->extension(), is_ffdhe); if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) { CheckShares(shares_capture->extension(), is_ffdhe); } else { EXPECT_EQ(0U, shares_capture->extension().len()); } } // Requiring the FFDHE extension on the server alone means that clients won't be // able to connect using a DHE suite. They should still connect in TLS 1.3, // because the client automatically sends the supported groups extension. TEST_P(TlsConnectGenericPre13, ConnectFfdheServer) { EnableOnlyDheCiphers(); server_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { Connect(); CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign); } else { ConnectExpectAlert(server_, kTlsAlertHandshakeFailure); client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); } } class TlsDheServerKeyExchangeDamager : public TlsHandshakeFilter { public: TlsDheServerKeyExchangeDamager(const std::shared_ptr& a) : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}) {} virtual PacketFilter::Action FilterHandshake( const TlsHandshakeFilter::HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) { // Damage the first octet of dh_p. Anything other than the known prime will // be rejected as "weak" when we have SSL_REQUIRE_DH_NAMED_GROUPS enabled. *output = input; output->data()[3] ^= 73; return CHANGE; } }; // Changing the prime in the server's key share results in an error. This will // invalidate the signature over the ServerKeyShare. That's ok, NSS won't check // the signature until everything else has been checked. TEST_P(TlsConnectGenericPre13, DamageServerKeyShare) { EnableOnlyDheCiphers(); client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); MakeTlsFilter(server_); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); client_->CheckErrorCode(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } class TlsDheSkeChangeY : public TlsHandshakeFilter { public: enum ChangeYTo { kYZero, kYOne, kYPMinusOne, kYGreaterThanP, kYTooLarge, kYZeroPad }; TlsDheSkeChangeY(const std::shared_ptr& a, uint8_t handshake_type, ChangeYTo change) : TlsHandshakeFilter(a, {handshake_type}), change_Y_(change) {} protected: void ChangeY(const DataBuffer& input, DataBuffer* output, size_t offset, const DataBuffer& prime) { static const uint8_t kExtraZero = 0; static const uint8_t kTooLargeExtra = 1; uint32_t dh_Ys_len; EXPECT_TRUE(input.Read(offset, 2, &dh_Ys_len)); EXPECT_LT(offset + dh_Ys_len, input.len()); offset += 2; // This isn't generally true, but our code pads. EXPECT_EQ(prime.len(), dh_Ys_len) << "Length of dh_Ys must equal length of dh_p"; *output = input; switch (change_Y_) { case kYZero: memset(output->data() + offset, 0, prime.len()); break; case kYOne: memset(output->data() + offset, 0, prime.len() - 1); output->Write(offset + prime.len() - 1, 1U, 1); break; case kYPMinusOne: output->Write(offset, prime); EXPECT_TRUE(output->data()[offset + prime.len() - 1] & 0x01) << "P must at least be odd"; --output->data()[offset + prime.len() - 1]; break; case kYGreaterThanP: // Set the first 32 octets of Y to 0xff, except the first which we set // to p[0]. This will make Y > p. That is, unless p is Mersenne, or // improbably large (but still the same bit length). We currently only // use a fixed prime that isn't a problem for this code. EXPECT_LT(0, prime.data()[0]) << "dh_p should not be zero-padded"; offset = output->Write(offset, prime.data()[0], 1); memset(output->data() + offset, 0xff, 31); break; case kYTooLarge: // Increase the dh_Ys length. output->Write(offset - 2, prime.len() + sizeof(kTooLargeExtra), 2); // Then insert the octet. output->Splice(&kTooLargeExtra, sizeof(kTooLargeExtra), offset); break; case kYZeroPad: output->Write(offset - 2, prime.len() + sizeof(kExtraZero), 2); output->Splice(&kExtraZero, sizeof(kExtraZero), offset); break; } } private: ChangeYTo change_Y_; }; class TlsDheSkeChangeYServer : public TlsDheSkeChangeY { public: TlsDheSkeChangeYServer(const std::shared_ptr& a, ChangeYTo change, bool modify) : TlsDheSkeChangeY(a, kTlsHandshakeServerKeyExchange, change), modify_(modify), p_() {} const DataBuffer& prime() const { return p_; } protected: virtual PacketFilter::Action FilterHandshake( const TlsHandshakeFilter::HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) override { size_t offset = 2; // Read dh_p uint32_t dh_len = 0; EXPECT_TRUE(input.Read(0, 2, &dh_len)); EXPECT_GT(input.len(), offset + dh_len); p_.Assign(input.data() + offset, dh_len); offset += dh_len; // Skip dh_g to find dh_Ys EXPECT_TRUE(input.Read(offset, 2, &dh_len)); offset += 2 + dh_len; if (modify_) { ChangeY(input, output, offset, p_); return CHANGE; } return KEEP; } private: bool modify_; DataBuffer p_; }; class TlsDheSkeChangeYClient : public TlsDheSkeChangeY { public: TlsDheSkeChangeYClient( const std::shared_ptr& a, ChangeYTo change, std::shared_ptr server_filter) : TlsDheSkeChangeY(a, kTlsHandshakeClientKeyExchange, change), server_filter_(server_filter) {} protected: virtual PacketFilter::Action FilterHandshake( const TlsHandshakeFilter::HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) override { ChangeY(input, output, 0, server_filter_->prime()); return CHANGE; } private: std::shared_ptr server_filter_; }; /* This matrix includes: variant (stream/datagram), TLS version, what change to * make to dh_Ys, whether the client will be configured to require DH named * groups. Test all combinations. */ typedef std::tuple DamageDHYProfile; class TlsDamageDHYTest : public TlsConnectTestBase, public ::testing::WithParamInterface { public: TlsDamageDHYTest() : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {} }; TEST_P(TlsDamageDHYTest, DamageServerY) { EnableOnlyDheCiphers(); if (std::get<3>(GetParam())) { client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); } TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam()); MakeTlsFilter(server_, change, true); if (change == TlsDheSkeChangeY::kYZeroPad) { ExpectAlert(client_, kTlsAlertDecryptError); } else { ExpectAlert(client_, kTlsAlertIllegalParameter); } ConnectExpectFail(); if (change == TlsDheSkeChangeY::kYZeroPad) { // Zero padding Y only manifests in a signature failure. // In TLS 1.0 and 1.1, the client reports a device error. if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) { client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR); } else { client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE); } server_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); } else { client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } } TEST_P(TlsDamageDHYTest, DamageClientY) { EnableOnlyDheCiphers(); if (std::get<3>(GetParam())) { client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); } // The filter on the server is required to capture the prime. auto server_filter = MakeTlsFilter( server_, TlsDheSkeChangeY::kYZero, false); // The client filter does the damage. TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam()); MakeTlsFilter(client_, change, server_filter); if (change == TlsDheSkeChangeY::kYZeroPad) { ExpectAlert(server_, kTlsAlertDecryptError); } else { ExpectAlert(server_, kTlsAlertHandshakeFailure); } ConnectExpectFail(); if (change == TlsDheSkeChangeY::kYZeroPad) { // Zero padding Y only manifests in a finished error. client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); } else { client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT); server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE); } } static const TlsDheSkeChangeY::ChangeYTo kAllYArr[] = { TlsDheSkeChangeY::kYZero, TlsDheSkeChangeY::kYOne, TlsDheSkeChangeY::kYPMinusOne, TlsDheSkeChangeY::kYGreaterThanP, TlsDheSkeChangeY::kYTooLarge, TlsDheSkeChangeY::kYZeroPad}; static ::testing::internal::ParamGenerator kAllY = ::testing::ValuesIn(kAllYArr); static const bool kTrueFalseArr[] = {true, false}; static ::testing::internal::ParamGenerator kTrueFalse = ::testing::ValuesIn(kTrueFalseArr); INSTANTIATE_TEST_SUITE_P( DamageYStream, TlsDamageDHYTest, ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream, TlsConnectTestBase::kTlsV10ToV12, kAllY, kTrueFalse)); INSTANTIATE_TEST_SUITE_P( DamageYDatagram, TlsDamageDHYTest, ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram, TlsConnectTestBase::kTlsV11V12, kAllY, kTrueFalse)); class TlsDheSkeMakePEven : public TlsHandshakeFilter { public: TlsDheSkeMakePEven(const std::shared_ptr& a) : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}) {} virtual PacketFilter::Action FilterHandshake( const TlsHandshakeFilter::HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) { // Find the end of dh_p uint32_t dh_len = 0; EXPECT_TRUE(input.Read(0, 2, &dh_len)); EXPECT_GT(input.len(), 2 + dh_len) << "enough space for dh_p"; size_t offset = 2 + dh_len - 1; EXPECT_TRUE((input.data()[offset] & 0x01) == 0x01) << "p should be odd"; *output = input; output->data()[offset] &= 0xfe; return CHANGE; } }; // Even without requiring named groups, an even value for p is bad news. TEST_P(TlsConnectGenericPre13, MakeDhePEven) { EnableOnlyDheCiphers(); MakeTlsFilter(server_); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); } class TlsDheSkeZeroPadP : public TlsHandshakeFilter { public: TlsDheSkeZeroPadP(const std::shared_ptr& a) : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}) {} virtual PacketFilter::Action FilterHandshake( const TlsHandshakeFilter::HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) { *output = input; uint32_t dh_len = 0; EXPECT_TRUE(input.Read(0, 2, &dh_len)); static const uint8_t kZeroPad = 0; output->Write(0, dh_len + sizeof(kZeroPad), 2); // increment the length output->Splice(&kZeroPad, sizeof(kZeroPad), 2); // insert a zero return CHANGE; } }; // Zero padding only causes signature failure. TEST_P(TlsConnectGenericPre13, PadDheP) { EnableOnlyDheCiphers(); MakeTlsFilter(server_); ConnectExpectAlert(client_, kTlsAlertDecryptError); // In TLS 1.0 and 1.1, the client reports a device error. if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) { client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR); } else { client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE); } server_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); } // The server should not pick the weak DH group if the client includes FFDHE // named groups in the supported_groups extension. The server then picks a // commonly-supported named DH group and this connects. // // Note: This test case can take ages to generate the weak DH key. TEST_P(TlsConnectGenericPre13, WeakDHGroup) { EnableOnlyDheCiphers(); client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); EXPECT_EQ(SECSuccess, SSL_EnableWeakDHEPrimeGroup(server_->ssl_fd(), PR_TRUE)); Connect(); } TEST_P(TlsConnectGeneric, Ffdhe3072) { EnableOnlyDheCiphers(); static const std::vector groups = {ssl_grp_ffdhe_3072}; client_->ConfigNamedGroups(groups); Connect(); } // Even though the client doesn't have DHE groups enabled the server assumes it // does. Because the client doesn't require named groups it accepts FF3072 as // custom group. TEST_P(TlsConnectGenericPre13, NamedGroupMismatchPre13) { EnableOnlyDheCiphers(); static const std::vector server_groups = {ssl_grp_ffdhe_3072}; static const std::vector client_groups = { ssl_grp_ec_secp256r1}; server_->ConfigNamedGroups(server_groups); client_->ConfigNamedGroups(client_groups); Connect(); CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_custom, ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); } // Same test but for TLS 1.3. This has to fail. TEST_P(TlsConnectTls13, NamedGroupMismatch13) { EnableOnlyDheCiphers(); static const std::vector server_groups = {ssl_grp_ffdhe_3072}; static const std::vector client_groups = { ssl_grp_ec_secp256r1}; server_->ConfigNamedGroups(server_groups); client_->ConfigNamedGroups(client_groups); ConnectExpectAlert(server_, kTlsAlertHandshakeFailure); server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); } // Replace the key share in the server key exchange message with one that's // larger than 8192 bits. class TooLongDHEServerKEXFilter : public TlsHandshakeFilter { public: TooLongDHEServerKEXFilter(const std::shared_ptr& server) : TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}) {} protected: virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) { // Replace the server key exchange message very large DH shares that are // not supported by NSS. const uint32_t share_len = 0x401; const uint8_t zero_share[share_len] = {0x80}; size_t offset = 0; // Write dh_p. offset = output->Write(offset, share_len, 2); offset = output->Write(offset, zero_share, share_len); // Write dh_g. offset = output->Write(offset, share_len, 2); offset = output->Write(offset, zero_share, share_len); // Write dh_Y. offset = output->Write(offset, share_len, 2); offset = output->Write(offset, zero_share, share_len); return CHANGE; } }; TEST_P(TlsConnectGenericPre13, TooBigDHGroup) { EnableOnlyDheCiphers(); MakeTlsFilter(server_); client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_FALSE); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); client_->CheckErrorCode(SSL_ERROR_DH_KEY_TOO_LONG); } // Even though the client doesn't have DHE groups enabled the server assumes it // does. The client requires named groups and thus does not accept FF3072 as // custom group in contrast to the previous test. TEST_P(TlsConnectGenericPre13, RequireNamedGroupsMismatchPre13) { EnableOnlyDheCiphers(); client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); static const std::vector server_groups = {ssl_grp_ffdhe_3072}; static const std::vector client_groups = {ssl_grp_ec_secp256r1, ssl_grp_ffdhe_2048}; server_->ConfigNamedGroups(server_groups); client_->ConfigNamedGroups(client_groups); ConnectExpectAlert(server_, kTlsAlertHandshakeFailure); server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); } TEST_P(TlsConnectGenericPre13, PreferredFfdhe) { EnableOnlyDheCiphers(); static const SSLDHEGroupType groups[] = {ssl_ff_dhe_3072_group, ssl_ff_dhe_2048_group}; EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(server_->ssl_fd(), groups, PR_ARRAY_SIZE(groups))); Connect(); client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); client_->CheckAuthType(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); server_->CheckAuthType(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); } TEST_P(TlsConnectGenericPre13, MismatchDHE) { EnableOnlyDheCiphers(); client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE); static const SSLDHEGroupType serverGroups[] = {ssl_ff_dhe_3072_group}; EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(server_->ssl_fd(), serverGroups, PR_ARRAY_SIZE(serverGroups))); static const SSLDHEGroupType clientGroups[] = {ssl_ff_dhe_2048_group}; EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(client_->ssl_fd(), clientGroups, PR_ARRAY_SIZE(clientGroups))); ConnectExpectAlert(server_, kTlsAlertHandshakeFailure); server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); } TEST_P(TlsConnectTls13, ResumeFfdhe) { EnableOnlyDheCiphers(); ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); Connect(); SendReceive(); // Need to read so that we absorb the session ticket. CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); Reset(); ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); EnableOnlyDheCiphers(); auto clientCapture = MakeTlsFilter(client_, ssl_tls13_pre_shared_key_xtn); auto serverCapture = MakeTlsFilter(server_, ssl_tls13_pre_shared_key_xtn); ExpectResumption(RESUME_TICKET); Connect(); CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256); ASSERT_LT(0UL, clientCapture->extension().len()); ASSERT_LT(0UL, serverCapture->extension().len()); } class TlsDheSkeChangeSignature : public TlsHandshakeFilter { public: TlsDheSkeChangeSignature(const std::shared_ptr& a, uint16_t version, const uint8_t* data, size_t len) : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}), version_(version), data_(data), len_(len) {} protected: virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header, const DataBuffer& input, DataBuffer* output) { TlsParser parser(input); EXPECT_TRUE(parser.SkipVariable(2)); // dh_p EXPECT_TRUE(parser.SkipVariable(2)); // dh_g EXPECT_TRUE(parser.SkipVariable(2)); // dh_Ys // Copy DH params to output. size_t offset = output->Write(0, input.data(), parser.consumed()); if (version_ == SSL_LIBRARY_VERSION_TLS_1_2) { // Write signature algorithm. offset = output->Write(offset, ssl_sig_dsa_sha256, 2); } // Write new signature. offset = output->Write(offset, len_, 2); offset = output->Write(offset, data_, len_); return CHANGE; } private: uint16_t version_; const uint8_t* data_; size_t len_; }; TEST_P(TlsConnectGenericPre13, InvalidDERSignatureFfdhe) { const uint8_t kBogusDheSignature[] = { 0x30, 0x69, 0x3c, 0x02, 0x1c, 0x7d, 0x0b, 0x2f, 0x64, 0x00, 0x27, 0xae, 0xcf, 0x1e, 0x28, 0x08, 0x6a, 0x7f, 0xb1, 0xbd, 0x78, 0xb5, 0x3b, 0x8c, 0x8f, 0x59, 0xed, 0x8f, 0xee, 0x78, 0xeb, 0x2c, 0xe9, 0x02, 0x1c, 0x6d, 0x7f, 0x3c, 0x0f, 0xf4, 0x44, 0x35, 0x0b, 0xb2, 0x6d, 0xdc, 0xb8, 0x21, 0x87, 0xdd, 0x0d, 0xb9, 0x46, 0x09, 0x3e, 0xef, 0x81, 0x5b, 0x37, 0x09, 0x39, 0xeb}; Reset(TlsAgent::kServerDsa); const std::vector client_groups = {ssl_grp_ffdhe_2048}; client_->ConfigNamedGroups(client_groups); MakeTlsFilter(server_, version_, kBogusDheSignature, sizeof(kBogusDheSignature)); ConnectExpectAlert(client_, kTlsAlertDecryptError); client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); } TEST_P(TlsConnectTls12, ConnectInconsistentSigAlgDHE) { EnableOnlyDheCiphers(); MakeTlsFilter(server_, ssl_sig_ecdsa_secp256r1_sha256); ConnectExpectAlert(client_, kTlsAlertIllegalParameter); } static void CheckSkeSigScheme( std::shared_ptr& capture_ske, uint16_t expected_scheme) { TlsParser parser(capture_ske->buffer()); EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_p"; EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_q"; EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_Ys"; uint32_t tmp; EXPECT_TRUE(parser.Read(&tmp, 2)) << " read sig_scheme"; EXPECT_EQ(expected_scheme, static_cast(tmp)); } TEST_P(TlsConnectTls12, ConnectSigAlgEnabledByPolicyDhe) { EnableOnlyDheCiphers(); const std::vector schemes = {ssl_sig_rsa_pkcs1_sha1, ssl_sig_rsa_pkcs1_sha384}; EnsureTlsSetup(); client_->SetSignatureSchemes(schemes.data(), schemes.size()); server_->SetSignatureSchemes(schemes.data(), schemes.size()); auto capture_ske = MakeTlsFilter( server_, kTlsHandshakeServerKeyExchange); StartConnect(); client_->Handshake(); // Send ClientHello // Enable SHA-1 by policy. SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_SSL_KX, 0); ASSERT_EQ(SECSuccess, rv); rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL, 0); ASSERT_EQ(SECSuccess, rv); Handshake(); // Remainder of handshake // The server should now report that it is connected EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state()); CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha1); } TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicyDhe) { EnableOnlyDheCiphers(); const std::vector schemes = {ssl_sig_rsa_pkcs1_sha1, ssl_sig_rsa_pkcs1_sha384}; EnsureTlsSetup(); client_->SetSignatureSchemes(schemes.data(), schemes.size()); server_->SetSignatureSchemes(schemes.data(), schemes.size()); auto capture_ske = MakeTlsFilter( server_, kTlsHandshakeServerKeyExchange); StartConnect(); client_->Handshake(); // Send ClientHello // Disable SHA-1 by policy after sending ClientHello so that CH // includes SHA-1 signature scheme. SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX); ASSERT_EQ(SECSuccess, rv); rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL, 0); ASSERT_EQ(SECSuccess, rv); Handshake(); // Remainder of handshake // The server should now report that it is connected EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state()); CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384); } TEST_P(TlsConnectPre12, ConnectSigAlgDisabledWeakGroupByOption3072DhePre12) { EnableOnlyDheCiphers(); // explicitly enable the weak groups EXPECT_EQ(SECSuccess, SSL_EnableWeakDHEPrimeGroup(server_->ssl_fd(), PR_TRUE)); EXPECT_EQ(SECSuccess, SSL_EnableWeakDHEPrimeGroup(client_->ssl_fd(), PR_TRUE)); server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 3072); Connect(); client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); } TEST_P(TlsConnectPre12, ConnectSigAlgDisabledWeakGroupByOption2048DhePre12) { EnableOnlyDheCiphers(); // explicitly enable the weak groups EXPECT_EQ(SECSuccess, SSL_EnableWeakDHEPrimeGroup(server_->ssl_fd(), PR_TRUE)); EXPECT_EQ(SECSuccess, SSL_EnableWeakDHEPrimeGroup(client_->ssl_fd(), PR_TRUE)); server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 2048); Connect(); client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_2048, 2048); server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_2048, 2048); } TEST_P(TlsConnectPre12, ConnectSigAlgDisabledByPolicyDhePre12) { EnableOnlyDheCiphers(); EnsureTlsSetup(); StartConnect(); client_->Handshake(); // Send ClientHello // Disable SHA-1 by policy. This will cause the connection fail as // TLS 1.1 or earlier uses combined SHA-1 + MD5 signature. SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX); ASSERT_EQ(SECSuccess, rv); rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL, 0); ASSERT_EQ(SECSuccess, rv); server_->ExpectSendAlert(kTlsAlertHandshakeFailure); client_->ExpectReceiveAlert(kTlsAlertHandshakeFailure); // Remainder of handshake Handshake(); server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); } TEST_P(TlsConnectTls12, ConnectSigAlgDisablePreferredGroupByOption3072Dhe) { EnableOnlyDheCiphers(); static const SSLDHEGroupType dhe_groups[] = { ssl_ff_dhe_2048_group, // first in the lists is the preferred group ssl_ff_dhe_3072_group}; server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 3072); EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(server_->ssl_fd(), &dhe_groups[0], PR_ARRAY_SIZE(dhe_groups))); Connect(); // our option size should override the preferred group client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); } TEST_P(TlsConnectTls12, ConnectSigAlgDisableGroupByOption3072Dhe) { EnableOnlyDheCiphers(); server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 3072); Connect(); client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072); } } // namespace nss_test