--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -88,28 +88,30 @@ CertVerifier::CertVerifier(OcspDownloadC
OcspGetConfig ogc,
mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays,
PinningMode pinningMode,
SHA1Mode sha1Mode,
BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
- CertificateTransparencyMode ctMode)
+ CertificateTransparencyMode ctMode,
+ DistrustedCAPolicy distrustedCAPolicy)
: mOCSPDownloadConfig(odc)
, mOCSPStrict(osc == ocspStrict)
, mOCSPGETEnabled(ogc == ocspGetEnabled)
, mOCSPTimeoutSoft(ocspTimeoutSoft)
, mOCSPTimeoutHard(ocspTimeoutHard)
, mCertShortLifetimeInDays(certShortLifetimeInDays)
, mPinningMode(pinningMode)
, mSHA1Mode(sha1Mode)
, mNameMatchingMode(nameMatchingMode)
, mNetscapeStepUpPolicy(netscapeStepUpPolicy)
, mCTMode(ctMode)
+ , mDistrustedCAPolicy(distrustedCAPolicy)
{
LoadKnownCTLogs();
}
CertVerifier::~CertVerifier()
{
}
@@ -549,17 +551,17 @@ CertVerifier::VerifyCert(CERTCertificate
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch,
- originAttributes,
+ mDistrustedCAPolicy, originAttributes,
builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature,
KeyPurposeId::id_kp_clientAuth,
CertPolicyId::anyPolicy, stapledOCSPResponse);
break;
}
@@ -624,18 +626,18 @@ CertVerifier::VerifyCert(CERTCertificate
NSSCertDBTrustDomain
trustDomain(trustSSL, evOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays, mPinningMode, MIN_RSA_BITS,
ValidityCheckingMode::CheckForEV,
sha1ModeConfigurations[i], mNetscapeStepUpPolicy,
- originAttributes, builtChain, pinningTelemetryInfo,
- hostname);
+ mDistrustedCAPolicy, originAttributes, builtChain,
+ pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
KeyUsage::digitalSignature,// (EC)DHE
KeyUsage::keyEncipherment, // RSA
KeyUsage::keyAgreement, // (EC)DH
KeyPurposeId::id_kp_serverAuth,
evPolicy, stapledOCSPResponse,
ocspStaplingStatus);
if (rv == Success &&
@@ -713,18 +715,19 @@ CertVerifier::VerifyCert(CERTCertificate
NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays,
mPinningMode, keySizeOptions[i],
ValidityCheckingMode::CheckingOff,
sha1ModeConfigurations[j],
mNetscapeStepUpPolicy,
- originAttributes, builtChain,
- pinningTelemetryInfo, hostname);
+ mDistrustedCAPolicy, originAttributes,
+ builtChain, pinningTelemetryInfo,
+ hostname);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
KeyUsage::digitalSignature,//(EC)DHE
KeyUsage::keyEncipherment,//RSA
KeyUsage::keyAgreement,//(EC)DH
KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy,
stapledOCSPResponse,
ocspStaplingStatus);
@@ -777,36 +780,36 @@ CertVerifier::VerifyCert(CERTCertificate
case certificateUsageSSLCA: {
NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, mNetscapeStepUpPolicy,
- originAttributes, builtChain, nullptr,
- nullptr);
+ mDistrustedCAPolicy, originAttributes,
+ builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy, stapledOCSPResponse);
break;
}
case certificateUsageEmailSigner: {
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch,
- originAttributes, builtChain, nullptr,
- nullptr);
+ mDistrustedCAPolicy, originAttributes,
+ builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature,
KeyPurposeId::id_kp_emailProtection,
CertPolicyId::anyPolicy, stapledOCSPResponse);
if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
@@ -824,18 +827,18 @@ CertVerifier::VerifyCert(CERTCertificate
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch,
- originAttributes, builtChain, nullptr,
- nullptr);
+ mDistrustedCAPolicy, originAttributes,
+ builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA
KeyPurposeId::id_kp_emailProtection,
CertPolicyId::anyPolicy, stapledOCSPResponse);
if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
--- a/security/certverifier/CertVerifier.h
+++ b/security/certverifier/CertVerifier.h
@@ -56,16 +56,23 @@ enum class SHA1ModeResult {
NeverChecked = 0,
SucceededWithoutSHA1 = 1,
SucceededWithImportedRoot = 2,
SucceededWithImportedRootOrSHA1Before2016 = 3,
SucceededWithSHA1 = 4,
Failed = 5,
};
+// Whether or not we are enforcing one of our CA distrust policies. For context,
+// see Bug 1437754 and Bug 1409257.
+enum class DistrustedCAPolicy : uint32_t {
+ Permit = 0,
+ DistrustSymantecRoots = 1,
+};
+
enum class NetscapeStepUpPolicy : uint32_t;
class PinningTelemetryInfo
{
public:
PinningTelemetryInfo() { Reset(); }
// Should we accumulate pinning telemetry for the result?
@@ -189,32 +196,34 @@ public:
CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc, OcspGetConfig ogc,
mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays,
PinningMode pinningMode, SHA1Mode sha1Mode,
BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
- CertificateTransparencyMode ctMode);
+ CertificateTransparencyMode ctMode,
+ DistrustedCAPolicy distrustedCAPolicy);
~CertVerifier();
void ClearOCSPCache() { mOCSPCache.Clear(); }
const OcspDownloadConfig mOCSPDownloadConfig;
const bool mOCSPStrict;
const bool mOCSPGETEnabled;
const mozilla::TimeDuration mOCSPTimeoutSoft;
const mozilla::TimeDuration mOCSPTimeoutHard;
const uint32_t mCertShortLifetimeInDays;
const PinningMode mPinningMode;
const SHA1Mode mSHA1Mode;
const BRNameMatchingPolicy::Mode mNameMatchingMode;
const NetscapeStepUpPolicy mNetscapeStepUpPolicy;
const CertificateTransparencyMode mCTMode;
+ const DistrustedCAPolicy mDistrustedCAPolicy;
private:
OCSPCache mOCSPCache;
// We only have a forward declarations of these classes (see above)
// so we must allocate dynamically.
UniquePtr<mozilla::ct::MultiLogCTVerifier> mCTVerifier;
UniquePtr<mozilla::ct::CTDiversityPolicy> mCTDiversityPolicy;
--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -57,16 +57,17 @@ NSSCertDBTrustDomain::NSSCertDBTrustDoma
TimeDuration ocspTimeoutSoft,
TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays,
CertVerifier::PinningMode pinningMode,
unsigned int minRSABits,
ValidityCheckingMode validityCheckingMode,
CertVerifier::SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
+ DistrustedCAPolicy distrustedCAPolicy,
const OriginAttributes& originAttributes,
UniqueCERTCertList& builtChain,
/*optional*/ PinningTelemetryInfo* pinningTelemetryInfo,
/*optional*/ const char* hostname)
: mCertDBTrustType(certDBTrustType)
, mOCSPFetching(ocspFetching)
, mOCSPCache(ocspCache)
, mPinArg(pinArg)
@@ -74,16 +75,17 @@ NSSCertDBTrustDomain::NSSCertDBTrustDoma
, mOCSPTimeoutSoft(ocspTimeoutSoft)
, mOCSPTimeoutHard(ocspTimeoutHard)
, mCertShortLifetimeInDays(certShortLifetimeInDays)
, mPinningMode(pinningMode)
, mMinRSABits(minRSABits)
, mValidityCheckingMode(validityCheckingMode)
, mSHA1Mode(sha1Mode)
, mNetscapeStepUpPolicy(netscapeStepUpPolicy)
+ , mDistrustedCAPolicy(distrustedCAPolicy)
, mOriginAttributes(originAttributes)
, mBuiltChain(builtChain)
, mPinningTelemetryInfo(pinningTelemetryInfo)
, mHostname(hostname)
, mCertBlocklist(do_GetService(NS_CERTBLOCKLIST_CONTRACTID))
, mOCSPStaplingStatus(CertVerifier::OCSP_STAPLING_NEVER_CHECKED)
, mSCTListFromCertificate()
, mSCTListFromOCSPStapling()
@@ -882,17 +884,19 @@ NSSCertDBTrustDomain::IsChainValid(const
// See bug 1434300. If the root is a Symantec root, see if we distrust this
// path. Since we already have the root available, we can check that cheaply
// here before proceeding with the rest of the algorithm.
// This algorithm only applies if we are verifying in the context of a TLS
// handshake. To determine this, we check mHostname: If it isn't set, this is
// not TLS, so don't run the algorithm.
- if (mHostname && CertDNIsInList(root.get(), RootSymantecDNs)) {
+ if (mHostname && CertDNIsInList(root.get(), RootSymantecDNs) &&
+ mDistrustedCAPolicy == DistrustedCAPolicy::DistrustSymantecRoots) {
+
rootCert = nullptr; // Clear the state for Segment...
nsCOMPtr<nsIX509CertList> intCerts;
nsCOMPtr<nsIX509Cert> eeCert;
nsrv = nssCertList->SegmentCertificateChain(rootCert, intCerts, eeCert);
if (NS_FAILED(nsrv)) {
// This chain is supposed to be complete, so this is an error.
return Result::FATAL_ERROR_LIBRARY_FAILURE;
--- a/security/certverifier/NSSCertDBTrustDomain.h
+++ b/security/certverifier/NSSCertDBTrustDomain.h
@@ -82,16 +82,17 @@ public:
mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays,
CertVerifier::PinningMode pinningMode,
unsigned int minRSABits,
ValidityCheckingMode validityCheckingMode,
CertVerifier::SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
+ DistrustedCAPolicy distrustedCAPolicy,
const OriginAttributes& originAttributes,
UniqueCERTCertList& builtChain,
/*optional*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
/*optional*/ const char* hostname = nullptr);
virtual Result FindIssuer(mozilla::pkix::Input encodedIssuerName,
IssuerChecker& checker,
mozilla::pkix::Time time) override;
@@ -191,16 +192,17 @@ private:
const mozilla::TimeDuration mOCSPTimeoutSoft;
const mozilla::TimeDuration mOCSPTimeoutHard;
const uint32_t mCertShortLifetimeInDays;
CertVerifier::PinningMode mPinningMode;
const unsigned int mMinRSABits;
ValidityCheckingMode mValidityCheckingMode;
CertVerifier::SHA1Mode mSHA1Mode;
NetscapeStepUpPolicy mNetscapeStepUpPolicy;
+ DistrustedCAPolicy mDistrustedCAPolicy;
const OriginAttributes& mOriginAttributes;
UniqueCERTCertList& mBuiltChain; // non-owning
PinningTelemetryInfo* mPinningTelemetryInfo;
const char* mHostname; // non-owning - only used for pinning checks
nsCOMPtr<nsICertBlocklist> mCertBlocklist;
CertVerifier::OCSPStaplingStatus mOCSPStaplingStatus;
// Certificate Transparency data extracted during certificate verification
UniqueSECItem mSCTListFromCertificate;
--- a/security/manager/ssl/SharedCertVerifier.h
+++ b/security/manager/ssl/SharedCertVerifier.h
@@ -22,20 +22,22 @@ public:
SharedCertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
OcspGetConfig ogc,
mozilla::TimeDuration ocspSoftTimeout,
mozilla::TimeDuration ocspHardTimeout,
uint32_t certShortLifetimeInDays,
PinningMode pinningMode, SHA1Mode sha1Mode,
BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
- CertificateTransparencyMode ctMode)
+ CertificateTransparencyMode ctMode,
+ DistrustedCAPolicy distrustedCAPolicy)
: mozilla::psm::CertVerifier(odc, osc, ogc, ocspSoftTimeout,
ocspHardTimeout, certShortLifetimeInDays,
pinningMode, sha1Mode, nameMatchingMode,
- netscapeStepUpPolicy, ctMode)
+ netscapeStepUpPolicy, ctMode,
+ distrustedCAPolicy)
{
}
};
} } // namespace mozilla::psm
#endif // SharedCertVerifier_h
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1684,32 +1684,47 @@ void nsNSSComponent::setValidationOption
case NetscapeStepUpPolicy::MatchBefore23August2015:
case NetscapeStepUpPolicy::NeverMatch:
break;
default:
netscapeStepUpPolicy = NetscapeStepUpPolicy::AlwaysMatch;
break;
}
+ DistrustedCAPolicy defaultCAPolicyMode =
+ DistrustedCAPolicy::DistrustSymantecRoots;
+ DistrustedCAPolicy distrustedCAPolicy =
+ static_cast<DistrustedCAPolicy>
+ (Preferences::GetUint("security.pki.distrust_ca_policy",
+ static_cast<uint32_t>(defaultCAPolicyMode)));
+ switch(distrustedCAPolicy) {
+ case DistrustedCAPolicy::Permit:
+ case DistrustedCAPolicy::DistrustSymantecRoots:
+ break;
+ default:
+ distrustedCAPolicy = defaultCAPolicyMode;
+ break;
+ }
+
CertVerifier::OcspDownloadConfig odc;
CertVerifier::OcspStrictConfig osc;
CertVerifier::OcspGetConfig ogc;
uint32_t certShortLifetimeInDays;
TimeDuration softTimeout;
TimeDuration hardTimeout;
GetRevocationBehaviorFromPrefs(&odc, &osc, &ogc, &certShortLifetimeInDays,
softTimeout, hardTimeout, lock);
mDefaultCertVerifier = new SharedCertVerifier(odc, osc, ogc, softTimeout,
hardTimeout,
certShortLifetimeInDays,
pinningMode, sha1Mode,
nameMatchingMode,
netscapeStepUpPolicy,
- ctMode);
+ ctMode, distrustedCAPolicy);
}
// Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and
// TLS 1.2 (max) when the prefs aren't set or set to invalid values.
nsresult
nsNSSComponent::setEnabledTLSVersions()
{
// keep these values in sync with security-prefs.js
@@ -2268,17 +2283,18 @@ nsNSSComponent::Observe(nsISupports* aSu
prefName.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
prefName.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
prefName.EqualsLiteral("security.pki.certificate_transparency.mode") ||
prefName.EqualsLiteral("security.cert_pinning.enforcement_level") ||
prefName.EqualsLiteral("security.pki.sha1_enforcement_level") ||
prefName.EqualsLiteral("security.pki.name_matching_mode") ||
prefName.EqualsLiteral("security.pki.netscape_step_up_policy") ||
prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.soft") ||
- prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.hard")) {
+ prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.hard") ||
+ prefName.EqualsLiteral("security.pki.distrust_ca_policy")) {
setValidationOptions(false);
#ifdef DEBUG
} else if (prefName.EqualsLiteral("security.test.built_in_root_hash")) {
MutexAutoLock lock(mMutex);
mTestBuiltInRootHash.Truncate();
Preferences::GetString("security.test.built_in_root_hash",
mTestBuiltInRootHash);
#endif // DEBUG
--- a/security/manager/ssl/security-prefs.js
+++ b/security/manager/ssl/security-prefs.js
@@ -124,8 +124,15 @@ pref("security.webauth.webauthn_enable_u
pref("security.ssl.errorReporting.enabled", true);
pref("security.ssl.errorReporting.url", "https://incoming.telemetry.mozilla.org/submit/sslreports/");
pref("security.ssl.errorReporting.automatic", false);
// Impose a maximum age on HPKP headers, to avoid sites getting permanently
// blacking themselves out by setting a bad pin. (60 days by default)
// https://tools.ietf.org/html/rfc7469#section-4.1
pref("security.cert_pinning.max_max_age_seconds", 5184000);
+
+// security.pki.distrust_ca_policy controls what root program distrust policies
+// are enforced at this time:
+// 0: No distrust policies enforced
+// 1: Symantec root distrust policy enforced
+// See https://wiki.mozilla.org/CA/Upcoming_Distrust_Actions for more details.
+pref("security.pki.distrust_ca_policy", 0);
--- a/security/manager/ssl/tests/unit/test_symantec_apple_google.js
+++ b/security/manager/ssl/tests/unit/test_symantec_apple_google.js
@@ -24,27 +24,46 @@ add_tls_server_setup("SymantecSanctionsS
// Not-whitelisted certs after the cutoff are to be distrusted
add_connection_test("symantec-not-whitelisted-after-cutoff.example.com",
PRErrorCodeSuccess, null, shouldBeImminentlyDistrusted);
// Not whitelisted certs before the cutoff are to be distrusted
add_connection_test("symantec-not-whitelisted-before-cutoff.example.com",
SEC_ERROR_UNKNOWN_ISSUER, null, null);
+// Disable the distrust, should be back to the console warning
+add_test(function() {
+ clearSessionCache();
+ Services.prefs.setIntPref("security.pki.distrust_ca_policy",
+ /* DistrustedCAPolicy::Permit */ 0);
+ run_next_test();
+});
+
+add_connection_test("symantec-not-whitelisted-before-cutoff.example.com",
+ PRErrorCodeSuccess, null, shouldBeImminentlyDistrusted);
+
+add_test(function() {
+ clearSessionCache();
+ Services.prefs.clearUserPref("security.pki.distrust_ca_policy");
+ run_next_test();
+});
// Load the wildcard *.google.com cert and its intermediate, then verify
// it at a reasonable time and make sure the whitelists work
function run_test() {
addCertFromFile(certDB, "test_symantec_apple_google/real-google-g2-intermediate.pem", ",,");
let whitelistedCert = constructCertFromFile("test_symantec_apple_google/real-googlecom.pem");
// Since we don't want to actually try to fetch OCSP for this certificate,
// (as an external fetch is bad in the tests), disable OCSP first.
Services.prefs.setIntPref("security.OCSP.enabled", 0);
+ Services.prefs.setIntPref("security.pki.distrust_ca_policy",
+ /* DistrustedCAPolicy::DistrustSymantecRoots */ 1);
+
// (new Date("2018-02-16")).getTime() / 1000
const VALIDATION_TIME = 1518739200;
checkCertErrorGenericAtTime(certDB, whitelistedCert, PRErrorCodeSuccess,
certificateUsageSSLServer, VALIDATION_TIME);
run_next_test();
}