bug 1240118 - add functionality to treat a test certificate as a built-in root r?mgoodwin
MozReview-Commit-ID: GJMd2zEAcmX
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -77,18 +77,28 @@ IsCertChainRootBuiltInRoot(CERTCertList*
Result
IsCertBuiltInRoot(CERTCertificate* cert, bool& result)
{
result = false;
nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
if (!component) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
+ nsresult rv;
+#ifdef DEBUG
+ rv = component->IsCertTestBuiltInRoot(cert, result);
+ if (NS_FAILED(rv)) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+ if (result) {
+ return Success;
+ }
+#endif // DEBUG
nsAutoString modName;
- nsresult rv = component->GetPIPNSSBundleString("RootCertModuleName", modName);
+ rv = component->GetPIPNSSBundleString("RootCertModuleName", modName);
if (NS_FAILED(rv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
NS_ConvertUTF16toUTF8 modNameUTF8(modName);
UniqueSECMODModule builtinRootsModule(SECMOD_FindModule(modNameUTF8.get()));
// If the built-in roots module isn't loaded, nothing is a built-in root.
if (!builtinRootsModule) {
return Success;
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1321,16 +1321,21 @@ nsNSSComponent::Observe(nsISupports* aSu
prefName.EqualsLiteral("security.OCSP.GET.enabled") ||
prefName.EqualsLiteral("security.pki.cert_short_lifetime_in_days") ||
prefName.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
prefName.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
prefName.EqualsLiteral("security.cert_pinning.enforcement_level") ||
prefName.EqualsLiteral("security.pki.sha1_enforcement_level")) {
MutexAutoLock lock(mutex);
setValidationOptions(false, lock);
+#ifdef DEBUG
+ } else if (prefName.EqualsLiteral("security.test.built_in_root_hash")) {
+ MutexAutoLock lock(mutex);
+ mTestBuiltInRootHash = Preferences::GetString("security.test.built_in_root_hash");
+#endif // DEBUG
} else {
clearSessionCache = false;
}
if (clearSessionCache)
SSL_ClearSessionCache();
}
return NS_OK;
@@ -1445,16 +1450,44 @@ nsNSSComponent::DoProfileBeforeChange()
NS_IMETHODIMP
nsNSSComponent::IsNSSInitialized(bool* initialized)
{
MutexAutoLock lock(mutex);
*initialized = mNSSInitialized;
return NS_OK;
}
+#ifdef DEBUG
+NS_IMETHODIMP
+nsNSSComponent::IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result)
+{
+ MutexAutoLock lock(mutex);
+ MOZ_ASSERT(mNSSInitialized);
+
+ result = false;
+
+ if (mTestBuiltInRootHash.IsEmpty()) {
+ return NS_OK;
+ }
+
+ RefPtr<nsNSSCertificate> nsc = nsNSSCertificate::Create(cert);
+ if (!nsc) {
+ return NS_ERROR_FAILURE;
+ }
+ nsAutoString certHash;
+ nsresult rv = nsc->GetSha256Fingerprint(certHash);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ result = mTestBuiltInRootHash.Equals(certHash);
+ return NS_OK;
+}
+#endif // DEBUG
+
SharedCertVerifier::~SharedCertVerifier() { }
already_AddRefed<SharedCertVerifier>
nsNSSComponent::GetDefaultCertVerifier()
{
MutexAutoLock lock(mutex);
MOZ_ASSERT(mNSSInitialized);
RefPtr<SharedCertVerifier> certVerifier(mDefaultCertVerifier);
--- a/security/manager/ssl/nsNSSComponent.h
+++ b/security/manager/ssl/nsNSSComponent.h
@@ -77,16 +77,20 @@ public:
#ifndef MOZ_NO_SMART_CARDS
NS_IMETHOD LaunchSmartCardThread(SECMODModule* module) = 0;
NS_IMETHOD ShutdownSmartCardThread(SECMODModule* module) = 0;
#endif
NS_IMETHOD IsNSSInitialized(bool* initialized) = 0;
+#ifdef DEBUG
+ NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) = 0;
+#endif
+
virtual ::already_AddRefed<mozilla::psm::SharedCertVerifier>
GetDefaultCertVerifier() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsINSSComponent, NS_INSSCOMPONENT_IID)
class nsNSSShutDownList;
class nsCertVerificationThread;
@@ -127,16 +131,20 @@ public:
void ShutdownSmartCardThreads();
nsresult DispatchEventToWindow(nsIDOMWindow* domWin,
const nsAString& eventType,
const nsAString& token);
#endif
NS_IMETHOD IsNSSInitialized(bool* initialized) override;
+#ifdef DEBUG
+ NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) override;
+#endif
+
::already_AddRefed<mozilla::psm::SharedCertVerifier>
GetDefaultCertVerifier() override;
// The following two methods are thread-safe.
static bool AreAnyWeakCiphersEnabled();
static void UseWeakCiphersOnSocket(PRFileDesc* fd);
static void FillTLSVersionRange(SSLVersionRange& rangeOut,
@@ -168,16 +176,20 @@ private:
nsCOMPtr<nsIStringBundle> mNSSErrorsBundle;
bool mNSSInitialized;
static int mInstanceCount;
nsNSSShutDownList* mShutdownObjectList;
#ifndef MOZ_NO_SMART_CARDS
SmartCardThreadList* mThreadList;
#endif
+#ifdef DEBUG
+ nsAutoString mTestBuiltInRootHash;
+#endif
+
void deleteBackgroundThreads();
void createBackgroundThreads();
nsCertVerificationThread* mCertVerificationThread;
nsNSSHttpInterface mHttpForNSS;
RefPtr<mozilla::psm::SharedCertVerifier> mDefaultCertVerifier;
static PRStatus IdentityInfoInit(void);
--- a/security/manager/ssl/tests/unit/test_cert_sha1.js
+++ b/security/manager/ssl/tests/unit/test_cert_sha1.js
@@ -58,18 +58,22 @@ function run_test() {
//
// Expected outcomes (accept / reject):
//
// a b c d e
// Allowed=0 Acc Acc Acc Acc Acc
// Forbidden=1 Rej Rej Rej Rej Rej
// Before2016=2 Acc Acc Rej Rej Rej
//
- // The pref setting of ImportedRoot (3) accepts everything because the
- // testing root is an imported one. This will be addressed in bug 1240118.
+ // The pref setting of ImportedRoot (3) accepts usage of SHA-1 for
+ // certificates valid before 2016 issued by built-in roots or SHA-1 for
+ // certificates issued any time by non-built-in roots. By default, the testing
+ // certificates are all considered issued by a non-built-in root. However, we
+ // now have the ability to treat a given non-built-in root as built-in. We
+ // test both of these situations below.
// SHA-1 allowed
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 0);
checkIntermediate(certFromFile("int-pre"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
checkIntermediate(certFromFile("int-post"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
@@ -85,17 +89,39 @@ function run_test() {
// SHA-1 allowed only before 2016
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 2);
checkIntermediate(certFromFile("int-pre"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
checkIntermediate(certFromFile("int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
- // SHA-1 allowed only before 2016 or when issued by an imported root (which
- // happens to be all of our test certificates).
+ // SHA-1 allowed only before 2016 or when issued by an imported root. First
+ // test with the test root considered a built-in (on debug only - this
+ // functionality is disabled on non-debug builds).
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 3);
+ if (isDebugBuild) {
+ let root = certFromFile("ca");
+ Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint);
+ checkIntermediate(certFromFile("int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ // This should fail but it doesn't, because the implementation makes no
+ // effort to enforce that when verifying a certificate for the capability
+ // of issuing TLS server auth certificates (i.e. the
+ // "certificateUsageSSLCA" usage), if SHA-1 was necessary, then the root of
+ // trust is an imported certificate. We don't really care, though, because
+ // the platform doesn't actually make trust decisions in this way and the
+ // ability to even verify a certificate for this purpose is intended to go
+ // away in bug 1257362.
+ // checkIntermediate(certFromFile("int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ Services.prefs.clearUserPref("security.test.built_in_root_hash");
+ }
+
+ // SHA-1 still allowed only before 2016 or when issued by an imported root.
+ // Now test with the test root considered a non-built-in.
checkIntermediate(certFromFile("int-pre"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
checkIntermediate(certFromFile("int-post"), PRErrorCodeSuccess);
checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
}