diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc')
-rw-r--r-- | security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc | 723 |
1 files changed, 723 insertions, 0 deletions
diff --git a/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc b/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc new file mode 100644 index 0000000000..5e01dee518 --- /dev/null +++ b/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc @@ -0,0 +1,723 @@ +/* -*- 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 <ctime> + +#include "prtime.h" +#include "secerr.h" +#include "ssl.h" +#include "nss.h" +#include "blapit.h" + +#include "gtest_utils.h" +#include "tls_agent.h" +#include "tls_connect.h" + +namespace nss_test { + +const std::string kEcdsaDelegatorId = TlsAgent::kDelegatorEcdsa256; +const std::string kRsaeDelegatorId = TlsAgent::kDelegatorRsae2048; +const std::string kPssDelegatorId = TlsAgent::kDelegatorRsaPss2048; +const std::string kDCId = TlsAgent::kServerEcdsa256; +const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256; +const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds) */; + +static void CheckPreliminaryPeerDelegCred( + const std::shared_ptr<TlsAgent>& client, bool expected, + PRUint32 key_bits = 0, SSLSignatureScheme sig_scheme = ssl_sig_none) { + EXPECT_NE(0U, (client->pre_info().valuesSet & ssl_preinfo_peer_auth)); + EXPECT_EQ(expected, client->pre_info().peerDelegCred); + if (expected) { + EXPECT_EQ(key_bits, client->pre_info().authKeyBits); + EXPECT_EQ(sig_scheme, client->pre_info().signatureScheme); + } +} + +static void CheckPeerDelegCred(const std::shared_ptr<TlsAgent>& client, + bool expected, PRUint32 key_bits = 0) { + EXPECT_EQ(expected, client->info().peerDelegCred); + EXPECT_EQ(expected, client->pre_info().peerDelegCred); + if (expected) { + EXPECT_EQ(key_bits, client->info().authKeyBits); + EXPECT_EQ(key_bits, client->pre_info().authKeyBits); + EXPECT_EQ(client->info().signatureScheme, + client->pre_info().signatureScheme); + } +} + +// AuthCertificate callbacks to simulate DC validation +static SECStatus CheckPreliminaryDC(TlsAgent* agent, bool checksig, + bool isServer) { + agent->UpdatePreliminaryChannelInfo(); + EXPECT_EQ(PR_TRUE, agent->pre_info().peerDelegCred); + EXPECT_EQ(256U, agent->pre_info().authKeyBits); + EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, agent->pre_info().signatureScheme); + return SECSuccess; +} + +static SECStatus CheckPreliminaryNoDC(TlsAgent* agent, bool checksig, + bool isServer) { + agent->UpdatePreliminaryChannelInfo(); + EXPECT_EQ(PR_FALSE, agent->pre_info().peerDelegCred); + return SECSuccess; +} + +// AuthCertificate callbacks for modifying DC attributes. +// This allows testing tls13_CertificateVerify for rejection +// of DC attributes that have changed since AuthCertificateHook +// may have handled them. +static SECStatus ModifyDCAuthKeyBits(TlsAgent* agent, bool checksig, + bool isServer) { + return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(), + PR_TRUE, // Change authKeyBits + PR_FALSE); // Change scheme +} + +static SECStatus ModifyDCScheme(TlsAgent* agent, bool checksig, bool isServer) { + return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(), + PR_FALSE, // Change authKeyBits + PR_TRUE); // Change scheme +} + +// Attempt to configure a DC when either the DC or DC private key is missing. +TEST_P(TlsConnectTls13, DCNotConfigured) { + // Load and delegate the credential. + ScopedSECKEYPublicKey pub; + ScopedSECKEYPrivateKey priv; + EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv)); + + StackSECItem dc; + TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor, + now(), &dc); + + // Attempt to install the certificate and DC with a missing DC private key. + EnsureTlsSetup(); + SSLExtraServerCertData extra_data_missing_dc_priv_key = { + ssl_auth_null, nullptr, nullptr, nullptr, &dc, nullptr}; + EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true, + &extra_data_missing_dc_priv_key)); + + // Attempt to install the certificate and with only the DC private key. + EnsureTlsSetup(); + SSLExtraServerCertData extra_data_missing_dc = { + ssl_auth_null, nullptr, nullptr, nullptr, nullptr, priv.get()}; + EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true, + &extra_data_missing_dc)); +} + +// Connected with ECDSA-P256. +TEST_P(TlsConnectTls13, DCConnectEcdsaP256) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256, + ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor, + now()); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, true, 256); + EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme); +} + +// Connected with ECDSA-P384. +TEST_P(TlsConnectTls13, DCConnectEcdsaP483) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa384, + ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor, + now()); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, true, 384); + EXPECT_EQ(ssl_sig_ecdsa_secp384r1_sha384, client_->info().signatureScheme); +} + +// Connected with ECDSA-P521. +TEST_P(TlsConnectTls13, DCConnectEcdsaP521) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521, + ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor, + now()); + client_->EnableDelegatedCredentials(); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, true, 521); + EXPECT_EQ(ssl_sig_ecdsa_secp521r1_sha512, client_->info().signatureScheme); +} + +// Connected with RSA-PSS, using a PSS SPKI and ECDSA delegation cert. +TEST_P(TlsConnectTls13, DCConnectRsaPssEcdsa) { + Reset(kEcdsaDelegatorId); + + // Need to enable PSS-PSS, which is not on by default. + static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256, + ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential( + TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now()); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, true, 1024); + EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme); +} + +// Connected with RSA-PSS, using a PSS SPKI and PSS delegation cert. +TEST_P(TlsConnectTls13, DCConnectRsaPssRsaPss) { + Reset(kPssDelegatorId); + + // Need to enable PSS-PSS, which is not on by default. + static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256, + ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential( + TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now()); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, true, 1024); + EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme); +} + +// Connected with ECDSA-P256 using a PSS delegation cert. +TEST_P(TlsConnectTls13, DCConnectEcdsaP256RsaPss) { + Reset(kPssDelegatorId); + + // Need to enable PSS-PSS, which is not on by default. + static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256, + ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256, + ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor, + now()); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, true, 256); + EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme); +} + +// Simulate the client receiving a DC containing algorithms not advertised. +// Do this by tweaking the client's supported sigSchemes after the CH. +TEST_P(TlsConnectTls13, DCReceiveUnadvertisedScheme) { + Reset(kEcdsaDelegatorId); + static const SSLSignatureScheme kClientSchemes[] = { + ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384}; + static const SSLSignatureScheme kServerSchemes[] = { + ssl_sig_ecdsa_secp384r1_sha384, ssl_sig_ecdsa_secp256r1_sha256}; + static const SSLSignatureScheme kEcdsaP256Only[] = { + ssl_sig_ecdsa_secp256r1_sha256}; + client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes)); + server_->SetSignatureSchemes(kServerSchemes, PR_ARRAY_SIZE(kServerSchemes)); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa384, + ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor, + now()); + StartConnect(); + client_->Handshake(); // CH with P256/P384. + server_->Handshake(); // Respond with P384 DC. + // Tell the client it only advertised P256. + SECStatus rv = SSLInt_SetDCAdvertisedSigSchemes( + client_->ssl_fd(), kEcdsaP256Only, PR_ARRAY_SIZE(kEcdsaP256Only)); + EXPECT_EQ(SECSuccess, rv); + ExpectAlert(client_, kTlsAlertIllegalParameter); + Handshake(); + client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); +} + +// Server schemes includes only RSAE schemes. Connection should succeed +// without delegation. +TEST_P(TlsConnectTls13, DCConnectServerRsaeOnly) { + Reset(kRsaeDelegatorId); + static const SSLSignatureScheme kClientSchemes[] = { + ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_pss_sha256}; + static const SSLSignatureScheme kServerSchemes[] = { + ssl_sig_rsa_pss_rsae_sha256}; + client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes)); + server_->SetSignatureSchemes(kServerSchemes, PR_ARRAY_SIZE(kServerSchemes)); + client_->EnableDelegatedCredentials(); + Connect(); + + CheckPeerDelegCred(client_, false); +} + +// Connect with an RSA-PSS DC SPKI, and an RSAE Delegator SPKI. +TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) { + Reset(kRsaeDelegatorId); + + static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256, + ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential( + TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now()); + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); + client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); +} + +// Client schemes includes only RSAE schemes. Connection should succeed +// without delegation, and no DC extension should be present in the CH. +TEST_P(TlsConnectTls13, DCConnectClientRsaeOnly) { + Reset(kRsaeDelegatorId); + static const SSLSignatureScheme kClientSchemes[] = { + ssl_sig_rsa_pss_rsae_sha256}; + static const SSLSignatureScheme kServerSchemes[] = { + ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes)); + server_->SetSignatureSchemes(kServerSchemes, PR_ARRAY_SIZE(kServerSchemes)); + client_->EnableDelegatedCredentials(); + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + EXPECT_FALSE(cfilter->captured()); + CheckPeerDelegCred(client_, false); +} + +// Test fallback. DC extension will not advertise RSAE schemes. +// The server will attempt to set one, but decline to after seeing +// the client-advertised schemes does not include it. Expect non- +// delegated success. +TEST_P(TlsConnectTls13, DCConnectRsaeDcSpki) { + Reset(kRsaeDelegatorId); + + static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256, + ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + client_->EnableDelegatedCredentials(); + + EnsureTlsSetup(); + ScopedSECKEYPublicKey pub; + ScopedSECKEYPrivateKey priv; + EXPECT_TRUE( + TlsAgent::LoadKeyPairFromCert(TlsAgent::kDelegatorRsae2048, &pub, &priv)); + + StackSECItem dc; + server_->DelegateCredential(server_->name(), pub, ssl_sig_rsa_pss_rsae_sha256, + kDCValidFor, now(), &dc); + + SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr, + nullptr, &dc, priv.get()}; + EXPECT_TRUE(server_->ConfigServerCert(server_->name(), true, &extra_data)); + auto sfilter = MakeTlsFilter<TlsExtensionCapture>( + server_, ssl_delegated_credentials_xtn); + Connect(); + EXPECT_FALSE(sfilter->captured()); + CheckPeerDelegCred(client_, false); +} + +// Generate a weak key. We can't do this in the fixture because certutil +// won't sign with such a tiny key. That's OK, because this is fast(ish). +static void GenerateWeakRsaKey(ScopedSECKEYPrivateKey& priv, + ScopedSECKEYPublicKey& pub) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + PK11RSAGenParams rsaparams; +// The absolute minimum size of RSA key that we can use with SHA-256 is +// 256bit (hash) + 256bit (salt) + 8 (start byte) + 8 (end byte) = 528. +#define RSA_WEAK_KEY 528 +#if RSA_MIN_MODULUS_BITS < RSA_WEAK_KEY + rsaparams.keySizeInBits = 528; +#else + rsaparams.keySizeInBits = RSA_MIN_MODULUS_BITS + 1; +#endif + rsaparams.pe = 65537; + + SECKEYPublicKey* p_pub = nullptr; + priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsaparams, &p_pub, false, false, nullptr)); + pub.reset(p_pub); + PR_ASSERT(priv); + return; +} + +// Fail to connect with a weak RSA key. +TEST_P(TlsConnectTls13, DCWeakKey) { + Reset(kPssDelegatorId); + EnsureTlsSetup(); + static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256, + ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); +#if RSA_MIN_MODULUS_BITS > RSA_WEAK_KEY + // save the MIN POLICY length. + PRInt32 minRsa; + + ASSERT_EQ(SECSuccess, NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minRsa)); +#if RSA_MIN_MODULUS_BITS >= 2048 + ASSERT_EQ(SECSuccess, + NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, RSA_MIN_MODULUS_BITS + 1024)); +#else + ASSERT_EQ(SECSuccess, NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 2048)); +#endif +#endif + + ScopedSECKEYPrivateKey dc_priv; + ScopedSECKEYPublicKey dc_pub; + GenerateWeakRsaKey(dc_priv, dc_pub); + ASSERT_TRUE(dc_priv); + + // Construct a DC. + StackSECItem dc; + TlsAgent::DelegateCredential(kPssDelegatorId, dc_pub, + ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now(), + &dc); + + // Configure the DC on the server. + SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr, + nullptr, &dc, dc_priv.get()}; + EXPECT_TRUE(server_->ConfigServerCert(kPssDelegatorId, true, &extra_data)); + + client_->EnableDelegatedCredentials(); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + ConnectExpectAlert(client_, kTlsAlertInsufficientSecurity); +#if RSA_MIN_MODULUS_BITS > RSA_WEAK_KEY + ASSERT_EQ(SECSuccess, NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, minRsa)); +#endif +} + +class ReplaceDCSigScheme : public TlsHandshakeFilter { + public: + ReplaceDCSigScheme(const std::shared_ptr<TlsAgent>& a) + : TlsHandshakeFilter(a, {ssl_hs_certificate_verify}) {} + + protected: + PacketFilter::Action FilterHandshake(const HandshakeHeader& header, + const DataBuffer& input, + DataBuffer* output) override { + *output = input; + output->Write(0, ssl_sig_ecdsa_secp384r1_sha384, 2); + return CHANGE; + } +}; + +// Aborted because of incorrect DC signature algorithm indication. +TEST_P(TlsConnectTls13, DCAbortBadExpectedCertVerifyAlg) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256, + ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor, + now()); + auto filter = MakeTlsFilter<ReplaceDCSigScheme>(server_); + filter->EnableDecryption(); + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); + client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); +} + +// Aborted because of invalid DC signature. +TEST_P(TlsConnectTls13, DCAbortBadSignature) { + Reset(kEcdsaDelegatorId); + EnsureTlsSetup(); + client_->EnableDelegatedCredentials(); + + ScopedSECKEYPublicKey pub; + ScopedSECKEYPrivateKey priv; + EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv)); + + StackSECItem dc; + TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor, + now(), &dc); + ASSERT_TRUE(dc.data != nullptr); + + // Flip the last bit of the DC so that the signature is invalid. + dc.data[dc.len - 1] ^= 0x01; + + SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr, + nullptr, &dc, priv.get()}; + EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data)); + + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); + client_->CheckErrorCode(SSL_ERROR_DC_BAD_SIGNATURE); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); +} + +// Aborted because of expired DC. +TEST_P(TlsConnectTls13, DCAbortExpired) { + Reset(kEcdsaDelegatorId); + server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now()); + client_->EnableDelegatedCredentials(); + // When the client checks the time, it will be at least one second after the + // DC expired. + AdvanceTime((static_cast<PRTime>(kDCValidFor) + 1) * PR_USEC_PER_SEC); + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); + client_->CheckErrorCode(SSL_ERROR_DC_EXPIRED); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); +} + +// Aborted due to remaining TTL > max validity period. +TEST_P(TlsConnectTls13, DCAbortExcessiveTTL) { + Reset(kEcdsaDelegatorId); + server_->AddDelegatedCredential(kDCId, kDCScheme, + kDCValidFor + 1 /* seconds */, now()); + client_->EnableDelegatedCredentials(); + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); + client_->CheckErrorCode(SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); +} + +// Aborted because of invalid key usage. +TEST_P(TlsConnectTls13, DCAbortBadKeyUsage) { + // The sever does not have the delegationUsage extension. + Reset(TlsAgent::kServerEcdsa256); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now()); + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); +} + +// Connected without DC because of no client indication. +TEST_P(TlsConnectTls13, DCConnectNoClientSupport) { + Reset(kEcdsaDelegatorId); + server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now()); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_FALSE(cfilter->captured()); + CheckPeerDelegCred(client_, false); +} + +// Connected without DC because of no server DC. +TEST_P(TlsConnectTls13, DCConnectNoServerSupport) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, false); +} + +// Connected without DC because client doesn't support TLS 1.3. +TEST_P(TlsConnectTls13, DCConnectClientNoTls13) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now()); + + 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); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + // Should fallback to TLS 1.2 and not negotiate a DC. + EXPECT_FALSE(cfilter->captured()); + CheckPeerDelegCred(client_, false); +} + +// Connected without DC because server doesn't support TLS 1.3. +TEST_P(TlsConnectTls13, DCConnectServerNoTls13) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now()); + + 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_2); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + // Should fallback to TLS 1.2 and not negotiate a DC. The client will still + // send the indication because it supports 1.3. + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, false); +} + +// Connected without DC because client doesn't support the signature scheme. +TEST_P(TlsConnectTls13, DCConnectExpectedCertVerifyAlgNotSupported) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + static const SSLSignatureScheme kClientSchemes[] = { + ssl_sig_ecdsa_secp256r1_sha256, + }; + client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes)); + + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521, + ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor, + now()); + + auto cfilter = MakeTlsFilter<TlsExtensionCapture>( + client_, ssl_delegated_credentials_xtn); + Connect(); + + // Client sends indication, but the server doesn't send a DC. + EXPECT_TRUE(cfilter->captured()); + CheckPeerDelegCred(client_, false); +} + +// Check that preliminary channel info properly reflects the DC. +TEST_P(TlsConnectTls13, DCCheckPreliminaryInfo) { + Reset(kEcdsaDelegatorId); + EnsureTlsSetup(); + client_->EnableDelegatedCredentials(); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256, + ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor, + now()); + + auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_); + filter->SetHandshakeTypes( + {kTlsHandshakeCertificateVerify, kTlsHandshakeFinished}); + filter->EnableDecryption(); + StartConnect(); + client_->Handshake(); // Send ClientHello + server_->Handshake(); // Send ServerHello + + client_->SetAuthCertificateCallback(CheckPreliminaryDC); + client_->Handshake(); // Process response + + client_->UpdatePreliminaryChannelInfo(); + CheckPreliminaryPeerDelegCred(client_, true, 256, + ssl_sig_ecdsa_secp256r1_sha256); +} + +// Check that preliminary channel info properly reflects a lack of DC. +TEST_P(TlsConnectTls13, DCCheckPreliminaryInfoNoDC) { + Reset(kEcdsaDelegatorId); + EnsureTlsSetup(); + client_->EnableDelegatedCredentials(); + auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_); + filter->SetHandshakeTypes( + {kTlsHandshakeCertificateVerify, kTlsHandshakeFinished}); + filter->EnableDecryption(); + StartConnect(); + client_->Handshake(); // Send ClientHello + server_->Handshake(); // Send ServerHello + + client_->SetAuthCertificateCallback(CheckPreliminaryNoDC); + client_->Handshake(); // Process response + + client_->UpdatePreliminaryChannelInfo(); + CheckPreliminaryPeerDelegCred(client_, false); +} + +// Tweak the scheme in between |Cert| and |CertVerify|. +TEST_P(TlsConnectTls13, DCRejectModifiedDCScheme) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + client_->SetAuthCertificateCallback(ModifyDCScheme); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521, + ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor, + now()); + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); + client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH); +} + +// Tweak the authKeyBits in between |Cert| and |CertVerify|. +TEST_P(TlsConnectTls13, DCRejectModifiedDCAuthKeyBits) { + Reset(kEcdsaDelegatorId); + client_->EnableDelegatedCredentials(); + client_->SetAuthCertificateCallback(ModifyDCAuthKeyBits); + server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521, + ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor, + now()); + ConnectExpectAlert(client_, kTlsAlertIllegalParameter); + server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT); + client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH); +} + +class DCDelegation : public ::testing::Test {}; + +TEST_F(DCDelegation, DCDelegations) { + PRTime now = PR_Now(); + ScopedCERTCertificate cert; + ScopedSECKEYPrivateKey priv; + ASSERT_TRUE(TlsAgent::LoadCertificate(kEcdsaDelegatorId, &cert, &priv)); + + ScopedSECKEYPublicKey pub_rsa; + ScopedSECKEYPrivateKey priv_rsa; + ASSERT_TRUE( + TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerRsa, &pub_rsa, &priv_rsa)); + + StackSECItem dc; + EXPECT_EQ(SECFailure, + SSL_DelegateCredential(cert.get(), priv.get(), pub_rsa.get(), + ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor, + now, &dc)); + EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError()); + + // Using different PSS hashes should be OK. + EXPECT_EQ(SECSuccess, SSL_DelegateCredential( + cert.get(), priv.get(), pub_rsa.get(), + ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc)); + // Make sure to reset |dc| after each success. + dc.Reset(); + EXPECT_EQ(SECSuccess, SSL_DelegateCredential( + cert.get(), priv.get(), pub_rsa.get(), + ssl_sig_rsa_pss_pss_sha384, kDCValidFor, now, &dc)); + dc.Reset(); + EXPECT_EQ(SECSuccess, SSL_DelegateCredential( + cert.get(), priv.get(), pub_rsa.get(), + ssl_sig_rsa_pss_pss_sha512, kDCValidFor, now, &dc)); + dc.Reset(); + + ScopedSECKEYPublicKey pub_ecdsa; + ScopedSECKEYPrivateKey priv_ecdsa; + ASSERT_TRUE(TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerEcdsa256, + &pub_ecdsa, &priv_ecdsa)); + + EXPECT_EQ(SECFailure, + SSL_DelegateCredential(cert.get(), priv.get(), pub_ecdsa.get(), + ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, + now, &dc)); + EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError()); + EXPECT_EQ(SECFailure, SSL_DelegateCredential( + cert.get(), priv.get(), pub_ecdsa.get(), + ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc)); + EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError()); + EXPECT_EQ(SECFailure, + SSL_DelegateCredential(cert.get(), priv.get(), pub_ecdsa.get(), + ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor, + now, &dc)); + EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError()); +} + +} // namespace nss_test |