author | David Keeler <dkeeler@mozilla.com> |
Mon, 07 May 2018 17:05:30 -0700 | |
changeset 417821 | 33ae17f18193912b12e7a890175a4d8749d75d9a |
parent 417820 | 4e08519eb8f0726820d67ac458d289d9dc503006 |
child 417822 | 29e58ed3f991b1887d743d49237b65b51db15c5d |
push id | 33980 |
push user | ebalazs@mozilla.com |
push date | Fri, 11 May 2018 09:35:12 +0000 |
treeherder | mozilla-central@8e9a4a323f0c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | fkiefer, jcj |
bugs | 1427248 |
milestone | 62.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
security/manager/ssl/nsNSSComponent.cpp | file | annotate | diff | comparison | revisions | |
security/manager/ssl/nsNSSComponent.h | file | annotate | diff | comparison | revisions |
--- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -558,27 +558,16 @@ nsNSSComponent::MaybeImportFamilySafetyR return NS_ERROR_FAILURE; } // Looking for a certificate with the common name 'Microsoft Family Safety' UniquePORTString subjectName(CERT_GetCommonName(&nssCertificate->subject)); MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("subject name is '%s'", subjectName.get())); if (kMicrosoftFamilySafetyCN.Equals(subjectName.get())) { wasFamilySafetyRoot = true; - CERTCertTrust trust = { - CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER, - 0, - 0 - }; - if (ChangeCertTrustWithPossibleAuthentication(nssCertificate, trust, - nullptr) != SECSuccess) { - MOZ_LOG(gPIPNSSLog, LogLevel::Debug, - ("couldn't trust certificate for TLS server auth")); - return NS_ERROR_FAILURE; - } MOZ_ASSERT(!mFamilySafetyRoot); mFamilySafetyRoot = Move(nssCertificate); MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("added Family Safety root")); } return NS_OK; } // Because HCERTSTORE is just a typedef void*, we can't use any of the nice @@ -659,36 +648,32 @@ nsNSSComponent::UnloadFamilySafetyRoot() if (ChangeCertTrustWithPossibleAuthentication(mFamilySafetyRoot, trust, nullptr) != SECSuccess) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't untrust certificate for TLS server auth")); } mFamilySafetyRoot = nullptr; } -#endif // XP_WIN - // The supported values of this pref are: // 0: disable detecting Family Safety mode and importing the root // 1: only attempt to detect Family Safety mode (don't import the root) // 2: detect Family Safety mode and import the root const char* kFamilySafetyModePref = "security.family_safety.mode"; // The telemetry gathered by this function is as follows: // 0-2: the value of the Family Safety mode pref // 3: detecting Family Safety mode failed // 4: Family Safety was not enabled // 5: Family Safety was enabled // 6: failed to import the Family Safety root // 7: successfully imported the root void nsNSSComponent::MaybeEnableFamilySafetyCompatibility() { -#ifdef XP_WIN - UnloadFamilySafetyRoot(); if (!(IsWin8Point1OrLater() && !IsWin10OrLater())) { return; } // Detect but don't import by default. uint32_t familySafetyMode = Preferences::GetUint(kFamilySafetyModePref, 1); if (familySafetyMode > 2) { familySafetyMode = 0; } @@ -705,20 +690,18 @@ nsNSSComponent::MaybeEnableFamilySafetyC } if (familySafetyMode == 2) { rv = LoadFamilySafetyRoot(); if (NS_FAILED(rv)) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to load Family Safety root")); } } -#endif // XP_WIN } -#ifdef XP_WIN // Helper function to determine if the OS considers the given certificate to be // a trust anchor for TLS server auth certificates. This is to be used in the // context of importing what are presumed to be root certificates from the OS. // If this function returns true but it turns out that the given certificate is // in some way unsuitable to issue certificates, mozilla::pkix will never build // a valid chain that includes the certificate, so importing it even if it // isn't a valid CA poses no risk. static bool @@ -761,18 +744,19 @@ CertIsTrustAnchorForTLSServerAuth(PCCERT return true; } MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("certificate not trust anchor for TLS server auth")); return false; } void -nsNSSComponent::UnloadEnterpriseRoots(const MutexAutoLock& /*proof of lock*/) +nsNSSComponent::UnloadEnterpriseRoots() { + MutexAutoLock lock(mMutex); MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return; } MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadEnterpriseRoots")); if (!mEnterpriseRoots) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("no enterprise roots were present")); return; @@ -825,30 +809,27 @@ nsNSSComponent::GetEnterpriseRoots(nsIX5 nsCOMPtr<nsIX509CertList> enterpriseRootsCertList( new nsNSSCertList(Move(enterpriseRootsCopy))); if (!enterpriseRootsCertList) { return NS_ERROR_FAILURE; } enterpriseRootsCertList.forget(enterpriseRoots); return NS_OK; } -#endif // XP_WIN static const char* kEnterpriseRootModePref = "security.enterprise_roots.enabled"; void nsNSSComponent::MaybeImportEnterpriseRoots() { -#ifdef XP_WIN MutexAutoLock lock(mMutex); MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return; } - UnloadEnterpriseRoots(lock); bool importEnterpriseRoots = Preferences::GetBool(kEnterpriseRootModePref, false); if (!importEnterpriseRoots) { return; } MOZ_ASSERT(!mEnterpriseRoots); mEnterpriseRoots.reset(CERT_NewCertList()); @@ -858,20 +839,18 @@ nsNSSComponent::MaybeImportEnterpriseRoo return; } ImportEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE, lock); ImportEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, lock); ImportEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, lock); -#endif // XP_WIN } -#ifdef XP_WIN // Loads the enterprise roots at the registry location corresponding to the // given location flag. // Supported flags are: // CERT_SYSTEM_STORE_LOCAL_MACHINE // (for HKLM\SOFTWARE\Microsoft\SystemCertificates) // CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY // (for HKLM\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\Certificates) // CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE @@ -904,21 +883,16 @@ nsNSSComponent::ImportEnterpriseRootsFor // https://msdn.microsoft.com/en-us/library/windows/desktop/aa376559%28v=vs.85%29.aspx ScopedCertStore enterpriseRootStore(CertOpenStore( CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, NULL, flags, kWindowsDefaultRootStoreName)); if (!enterpriseRootStore.get()) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to open enterprise root store")); return; } - CERTCertTrust trust = { - CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER, - 0, - 0 - }; PCCERT_CONTEXT certificate = nullptr; uint32_t numImported = 0; while ((certificate = CertFindCertificateInStore(enterpriseRootStore.get(), X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, certificate))) { if (!CertIsTrustAnchorForTLSServerAuth(certificate)) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, @@ -944,28 +918,58 @@ nsNSSComponent::ImportEnterpriseRootsFor if (!mEnterpriseRoots) { return; } if (CERT_AddCertToListTail(mEnterpriseRoots.get(), nssCertificate.get()) != SECSuccess) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't add cert to list")); continue; } - if (ChangeCertTrustWithPossibleAuthentication(nssCertificate, trust, - nullptr) != SECSuccess) { - MOZ_LOG(gPIPNSSLog, LogLevel::Debug, - ("couldn't trust certificate for TLS server auth")); - } MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Imported '%s'", subjectName.get())); numImported++; // now owned by mEnterpriseRoots Unused << nssCertificate.release(); } MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("imported %u roots", numImported)); } + +NS_IMETHODIMP +nsNSSComponent::TrustLoaded3rdPartyRoots() +{ + MutexAutoLock lock(mMutex); + + CERTCertTrust trust = { + CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER, + 0, + 0 + }; + if (mEnterpriseRoots) { + for (CERTCertListNode* n = CERT_LIST_HEAD(mEnterpriseRoots.get()); + !CERT_LIST_END(n, mEnterpriseRoots.get()); n = CERT_LIST_NEXT(n)) { + if (!n || !n->cert) { + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, + ("library failure: CERTCertListNode null or lacks cert")); + continue; + } + UniqueCERTCertificate cert(CERT_DupCertificate(n->cert)); + if (ChangeCertTrustWithPossibleAuthentication(cert, trust, nullptr) + != SECSuccess) { + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, + ("couldn't trust enterprise certificate for TLS server auth")); + } + } + } + if (mFamilySafetyRoot && + ChangeCertTrustWithPossibleAuthentication(mFamilySafetyRoot, trust, + nullptr) != SECSuccess) { + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, + ("couldn't trust family safety certificate for TLS server auth")); + } + return NS_OK; +} #endif // XP_WIN class LoadLoadableRootsTask final : public Runnable { public: explicit LoadLoadableRootsTask(nsNSSComponent* nssComponent) : Runnable("LoadLoadableRootsTask") , mNSSComponent(nssComponent) @@ -2088,18 +2092,26 @@ nsNSSComponent::InitializeNSS() rv = setEnabledTLSVersions(); if (NS_FAILED(rv)) { return NS_ERROR_UNEXPECTED; } DisableMD5(); +#ifdef XP_WIN + // Note that these functions do not change the trust of any loaded 3rd party + // roots. Because we're initializing the nsNSSComponent, and because if the + // user has a master password set on the softoken it could cause the + // authentication dialog to come up, we could conceivably re-enter + // nsNSSComponent initialization, which would be bad. Instead, we schedule an + // event to set the trust after the component has been initialized (below). MaybeEnableFamilySafetyCompatibility(); MaybeImportEnterpriseRoots(); +#endif // XP_WIN ConfigureTLSSessionIdentifiers(); bool requireSafeNegotiation = Preferences::GetBool("security.ssl.require_safe_negotiation", REQUIRE_SAFE_NEGOTIATION_DEFAULT); SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation); @@ -2188,16 +2200,24 @@ nsNSSComponent::InitializeNSS() Preferences::GetString("security.pki.mitm_canary_issuer", mMitmCanaryIssuer); mMitmDetecionEnabled = Preferences::GetBool("security.pki.mitm_canary_issuer.enabled", true); mNSSInitialized = true; } +#ifdef XP_WIN + nsCOMPtr<nsINSSComponent> handle(this); + NS_DispatchToCurrentThread(NS_NewRunnableFunction("nsNSSComponent::TrustLoaded3rdPartyRoots", + [handle]() { + MOZ_ALWAYS_SUCCEEDS(handle->TrustLoaded3rdPartyRoots()); + })); +#endif // XP_WIN + RefPtr<LoadLoadableRootsTask> loadLoadableRootsTask( new LoadLoadableRootsTask(this)); return loadLoadableRootsTask->Dispatch(); } void nsNSSComponent::ShutdownNSS() { @@ -2341,25 +2361,37 @@ nsNSSComponent::Observe(nsISupports* aSu 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 +#ifdef XP_WIN } else if (prefName.Equals(kFamilySafetyModePref)) { + // When the pref changes, it is safe to change the trust of 3rd party + // roots in the same event tick that they're loaded. + UnloadFamilySafetyRoot(); MaybeEnableFamilySafetyCompatibility(); + TrustLoaded3rdPartyRoots(); +#endif // XP_WIN } else if (prefName.EqualsLiteral("security.content.signature.root_hash")) { MutexAutoLock lock(mMutex); mContentSigningRootHash.Truncate(); Preferences::GetString("security.content.signature.root_hash", mContentSigningRootHash); +#ifdef XP_WIN } else if (prefName.Equals(kEnterpriseRootModePref)) { + // When the pref changes, it is safe to change the trust of 3rd party + // roots in the same event tick that they're loaded. + UnloadEnterpriseRoots(); MaybeImportEnterpriseRoots(); + TrustLoaded3rdPartyRoots(); +#endif // XP_WIN } else if (prefName.EqualsLiteral("security.pki.mitm_canary_issuer")) { MutexAutoLock lock(mMutex); mMitmCanaryIssuer.Truncate(); Preferences::GetString("security.pki.mitm_canary_issuer", mMitmCanaryIssuer); } else if (prefName.EqualsLiteral( "security.pki.mitm_canary_issuer.enabled")) { MutexAutoLock lock(mMutex);
--- a/security/manager/ssl/nsNSSComponent.h +++ b/security/manager/ssl/nsNSSComponent.h @@ -70,16 +70,17 @@ public: #ifdef DEBUG NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) = 0; #endif NS_IMETHOD IsCertContentSigningRoot(CERTCertificate* cert, bool& result) = 0; #ifdef XP_WIN NS_IMETHOD GetEnterpriseRoots(nsIX509CertList** enterpriseRoots) = 0; + NS_IMETHOD TrustLoaded3rdPartyRoots() = 0; #endif NS_IMETHOD BlockUntilLoadableRootsLoaded() = 0; NS_IMETHOD CheckForSmartCardChanges() = 0; // IssuerMatchesMitmCanary succeeds if aCertIssuer matches the canary and // the feature is enabled. It returns an error if the strings don't match, // the canary is not set, or the feature is disabled. NS_IMETHOD IssuerMatchesMitmCanary(const char* aCertIssuer) = 0; @@ -126,16 +127,17 @@ public: #ifdef DEBUG NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) override; #endif NS_IMETHOD IsCertContentSigningRoot(CERTCertificate* cert, bool& result) override; #ifdef XP_WIN NS_IMETHOD GetEnterpriseRoots(nsIX509CertList** enterpriseRoots) override; + NS_IMETHOD TrustLoaded3rdPartyRoots() override; #endif NS_IMETHOD BlockUntilLoadableRootsLoaded() override; NS_IMETHOD CheckForSmartCardChanges() override; NS_IMETHOD IssuerMatchesMitmCanary(const char* aCertIssuer) override; // Main thread only NS_IMETHOD HasActiveSmartCards(bool& result) override; @@ -172,17 +174,17 @@ private: #ifdef XP_WIN void ImportEnterpriseRootsForLocation( DWORD locationFlag, const mozilla::MutexAutoLock& proofOfLock); nsresult MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate, bool& wasFamilySafetyRoot); nsresult LoadFamilySafetyRoot(); void UnloadFamilySafetyRoot(); - void UnloadEnterpriseRoots(const mozilla::MutexAutoLock& proofOfLock); + void UnloadEnterpriseRoots(); #endif // XP_WIN // mLoadableRootsLoadedMonitor protects mLoadableRootsLoaded. mozilla::Monitor mLoadableRootsLoadedMonitor; bool mLoadableRootsLoaded; nsresult mLoadableRootsLoadedResult; // mMutex protects all members that are accessed from more than one thread.