/* -*- 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 "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& 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& 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( 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( 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( 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( 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( 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( 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( 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( 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( 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& 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(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(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( 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( 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( 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( 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( 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(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(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