Backed out 4 changesets (bug 1705622) for causing dt failures in browser_touch_simulation.js CLOSED TREE
Backed out changeset 44277989aa32 (bug 1705622)
Backed out changeset 5a374b87bffb (bug 1705622)
Backed out changeset 8eab73ad3b4b (bug 1705622)
Backed out changeset dfcbcfbe0e47 (bug 1705622)
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * 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"nsNSSComponent.h"#include"CryptoTask.h"#include"EnterpriseRoots.h"#include"ExtendedValidation.h"#include"NSSCertDBTrustDomain.h"#include"SSLTokensCache.h"#include"ScopedNSSTypes.h"#include"SharedSSLState.h"#include"cert.h"#include"cert_storage/src/cert_storage.h"#include"certdb.h"#include"mozilla/AppShutdown.h"#include"mozilla/ArrayUtils.h"#include"mozilla/Assertions.h"#include"mozilla/Casting.h"#include"mozilla/PodOperations.h"#include"mozilla/Preferences.h"#include"mozilla/ProfilerLabels.h"#include"mozilla/ProfilerMarkers.h"#include"mozilla/PublicSSL.h"#include"mozilla/Services.h"#include"mozilla/StaticMutex.h"#include"mozilla/StaticPtr.h"#include"mozilla/SyncRunnable.h"#include"mozilla/Telemetry.h"#include"mozilla/TimeStamp.h"#include"mozilla/Unused.h"#include"mozilla/Vector.h"#include"mozilla/net/SocketProcessParent.h"#include"mozpkix/pkixnss.h"#include"nsAppDirectoryServiceDefs.h"#include"nsCRT.h"#include"nsClientAuthRemember.h"#include"nsComponentManagerUtils.h"#include"nsDirectoryServiceDefs.h"#include"nsICertOverrideService.h"#include"nsIFile.h"#include"nsILocalFileWin.h"#include"nsIOService.h"#include"nsIObserverService.h"#include"nsIPrompt.h"#include"nsIProperties.h"#include"nsISerialEventTarget.h"#include"nsISiteSecurityService.h"#include"nsITimer.h"#include"nsITokenPasswordDialogs.h"#include"nsIWindowWatcher.h"#include"nsIXULRuntime.h"#include"nsLiteralString.h"#include"nsNSSCertificateDB.h"#include"nsNSSHelper.h"#include"nsNetCID.h"#include"nsPK11TokenDB.h"#include"nsPrintfCString.h"#include"nsServiceManagerUtils.h"#include"nsThreadUtils.h"#include"nsXULAppAPI.h"#include"nss.h"#include"p12plcy.h"#include"pk11pub.h"#include"prmem.h"#include"secerr.h"#include"secmod.h"#include"ssl.h"#include"sslerr.h"#include"sslproto.h"#if defined(XP_LINUX) && !defined(ANDROID)# include <linux/magic.h># include <sys/vfs.h>#endif#ifdef XP_WIN# include "mozilla/WindowsVersion.h"# include "nsILocalFileWin.h"# include "windows.h" // this needs to be before the following includes# include "lmcons.h"# include "sddl.h"# include "wincrypt.h"# include "nsIWindowsRegKey.h"#endifusingnamespacemozilla;usingnamespacemozilla::psm;LazyLogModulegPIPNSSLog("pipnss");intnsNSSComponent::mInstanceCount=0;// Forward declaration.nsresultCommonInit();// This function can be called from chrome or content or socket processes// to ensure that NSS is initialized.boolEnsureNSSInitializedChromeOrContent(){staticAtomic<bool>initialized(false);if(initialized){returntrue;}// If this is not the main thread (i.e. probably a worker) then forward this// call to the main thread.if(!NS_IsMainThread()){nsCOMPtr<nsIThread>mainThread;nsresultrv=NS_GetMainThread(getter_AddRefs(mainThread));if(NS_FAILED(rv)){returnfalse;}// Forward to the main thread synchronously.mozilla::SyncRunnable::DispatchToThread(mainThread,newSyncRunnable(NS_NewRunnableFunction("EnsureNSSInitializedChromeOrContent",[](){EnsureNSSInitializedChromeOrContent();})));returninitialized;}if(XRE_IsParentProcess()){nsCOMPtr<nsISupports>nss=do_GetService(PSM_COMPONENT_CONTRACTID);if(!nss){returnfalse;}initialized=true;returntrue;}if(NSS_IsInitialized()){initialized=true;returntrue;}if(NSS_NoDB_Init(nullptr)!=SECSuccess){returnfalse;}if(XRE_IsSocketProcess()){if(NS_FAILED(CommonInit())){returnfalse;}initialized=true;returntrue;}if(NS_FAILED(mozilla::psm::InitializeCipherSuite())){returnfalse;}mozilla::psm::DisableMD5();mozilla::pkix::RegisterErrorTable();initialized=true;returntrue;}staticconstuint32_tOCSP_TIMEOUT_MILLISECONDS_SOFT_DEFAULT=2000;staticconstuint32_tOCSP_TIMEOUT_MILLISECONDS_SOFT_MAX=5000;staticconstuint32_tOCSP_TIMEOUT_MILLISECONDS_HARD_DEFAULT=10000;staticconstuint32_tOCSP_TIMEOUT_MILLISECONDS_HARD_MAX=20000;voidnsNSSComponent::GetRevocationBehaviorFromPrefs(/*out*/CertVerifier::OcspDownloadConfig*odc,/*out*/CertVerifier::OcspStrictConfig*osc,/*out*/uint32_t*certShortLifetimeInDays,/*out*/TimeDuration&softTimeout,/*out*/TimeDuration&hardTimeout,constMutexAutoLock&/*proofOfLock*/){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(odc);MOZ_ASSERT(osc);MOZ_ASSERT(certShortLifetimeInDays);// 0 = disabled// 1 = enabled for everything (default)// 2 = enabled for EV certificates onlyint32_tocspLevel=Preferences::GetInt("security.OCSP.enabled",1);switch(ocspLevel){case0:*odc=CertVerifier::ocspOff;break;case2:*odc=CertVerifier::ocspEVOnly;break;default:*odc=CertVerifier::ocspOn;break;}*osc=Preferences::GetBool("security.OCSP.require",false)?CertVerifier::ocspStrict:CertVerifier::ocspRelaxed;// If we pass in just 0 as the second argument to Preferences::GetUint, there// are two function signatures that match (given that 0 can be intepreted as// a null pointer). Thus the compiler will complain without the cast.*certShortLifetimeInDays=Preferences::GetUint("security.pki.cert_short_lifetime_in_days",static_cast<uint32_t>(0));uint32_tsoftTimeoutMillis=Preferences::GetUint("security.OCSP.timeoutMilliseconds.soft",OCSP_TIMEOUT_MILLISECONDS_SOFT_DEFAULT);softTimeoutMillis=std::min(softTimeoutMillis,OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX);softTimeout=TimeDuration::FromMilliseconds(softTimeoutMillis);uint32_thardTimeoutMillis=Preferences::GetUint("security.OCSP.timeoutMilliseconds.hard",OCSP_TIMEOUT_MILLISECONDS_HARD_DEFAULT);hardTimeoutMillis=std::min(hardTimeoutMillis,OCSP_TIMEOUT_MILLISECONDS_HARD_MAX);hardTimeout=TimeDuration::FromMilliseconds(hardTimeoutMillis);ClearSSLExternalAndInternalSessionCache();}nsNSSComponent::nsNSSComponent():mLoadableCertsLoadedMonitor("nsNSSComponent.mLoadableCertsLoadedMonitor"),mLoadableCertsLoaded(false),mLoadableCertsLoadedResult(NS_ERROR_FAILURE),mMutex("nsNSSComponent.mMutex"),mMitmDetecionEnabled(false),mLoadLoadableCertsTaskDispatched(false){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::ctor\n"));MOZ_RELEASE_ASSERT(NS_IsMainThread());MOZ_ASSERT(mInstanceCount==0,"nsNSSComponent is a singleton, but instantiated multiple times!");++mInstanceCount;}nsNSSComponent::~nsNSSComponent(){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::dtor\n"));MOZ_RELEASE_ASSERT(NS_IsMainThread());// All cleanup code requiring services needs to happen in xpcom_shutdownShutdownNSS();SharedSSLState::GlobalCleanup();RememberCertErrorsTable::Cleanup();--mInstanceCount;MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::dtor finished\n"));}#ifdef XP_WINstaticboolGetUserSid(nsAString&sidString){// UNLEN is the maximum user name length (see Lmcons.h). +1 for the null// terminator.WCHARlpAccountName[UNLEN+1];DWORDlcAccountName=sizeof(lpAccountName)/sizeof(lpAccountName[0]);BOOLsuccess=GetUserName(lpAccountName,&lcAccountName);if(!success){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("GetUserName failed"));returnfalse;}charsid_buffer[SECURITY_MAX_SID_SIZE];SID*sid=BitwiseCast<SID*,char*>(sid_buffer);DWORDcbSid=ArrayLength(sid_buffer);SID_NAME_USEeUse;// There doesn't appear to be a defined maximum length for the domain name// here. To deal with this, we start with a reasonable buffer length and// see if that works. If it fails and the error indicates insufficient length,// we use the indicated required length and try again.DWORDcchReferencedDomainName=128;autoReferencedDomainName(MakeUnique<WCHAR[]>(cchReferencedDomainName));success=LookupAccountName(nullptr,lpAccountName,sid,&cbSid,ReferencedDomainName.get(),&cchReferencedDomainName,&eUse);if(!success&&GetLastError()!=ERROR_INSUFFICIENT_BUFFER){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("LookupAccountName failed"));returnfalse;}if(!success){ReferencedDomainName=MakeUnique<WCHAR[]>(cchReferencedDomainName);success=LookupAccountName(nullptr,lpAccountName,sid,&cbSid,ReferencedDomainName.get(),&cchReferencedDomainName,&eUse);}if(!success){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("LookupAccountName failed"));returnfalse;}LPTSTRStringSid;success=ConvertSidToStringSid(sid,&StringSid);if(!success){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("ConvertSidToStringSid failed"));returnfalse;}sidString.Assign(StringSid);LocalFree(StringSid);returntrue;}// This is a specialized helper function to read the value of a registry key// that might not be present. If it is present, returns (via the output// parameter) its value. Otherwise, returns the given default value.// This function handles one level of nesting. That is, if the desired value// is actually in a direct child of the given registry key (where the child// and/or the value being sought may not actually be present), this function// will handle that. In the normal case, though, optionalChildName will be// null.staticnsresultReadRegKeyValueWithDefault(nsCOMPtr<nsIWindowsRegKey>regKey,uint32_tflags,constwchar_t*optionalChildName,constwchar_t*valueName,uint32_tdefaultValue,uint32_t&valueOut){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("ReadRegKeyValueWithDefault"));MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("attempting to read '%S%s%S' with default '%u'",optionalChildName?optionalChildName:L"",optionalChildName?"\\":"",valueName,defaultValue));if(optionalChildName){nsDependentStringchildNameString(optionalChildName);boolhasChild;nsresultrv=regKey->HasChild(childNameString,&hasChild);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to determine if child key is present"));returnrv;}if(!hasChild){valueOut=defaultValue;returnNS_OK;}nsCOMPtr<nsIWindowsRegKey>childRegKey;rv=regKey->OpenChild(childNameString,flags,getter_AddRefs(childRegKey));if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't open child key"));returnrv;}returnReadRegKeyValueWithDefault(childRegKey,flags,nullptr,valueName,defaultValue,valueOut);}nsDependentStringvalueNameString(valueName);boolhasValue;nsresultrv=regKey->HasValue(valueNameString,&hasValue);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to determine if value is present"));returnrv;}if(!hasValue){valueOut=defaultValue;returnNS_OK;}rv=regKey->ReadIntValue(valueNameString,&valueOut);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to read value"));returnrv;}returnNS_OK;}staticnsresultAccountHasFamilySafetyEnabled(bool&enabled){enabled=false;MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("AccountHasFamilySafetyEnabled?"));nsCOMPtr<nsIWindowsRegKey>parentalControlsKey(do_CreateInstance("@mozilla.org/windows-registry-key;1"));if(!parentalControlsKey){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't create nsIWindowsRegKey"));returnNS_ERROR_FAILURE;}uint32_tflags=nsIWindowsRegKey::ACCESS_READ|nsIWindowsRegKey::WOW64_64;constexprautofamilySafetyPath=u"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Parental Controls"_ns;nsresultrv=parentalControlsKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,familySafetyPath,flags);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't open parentalControlsKey"));returnrv;}constexprautousersString=u"Users"_ns;boolhasUsers;rv=parentalControlsKey->HasChild(usersString,&hasUsers);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("HasChild(Users) failed"));returnrv;}if(!hasUsers){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Users subkey not present - Parental Controls not enabled"));returnNS_OK;}nsCOMPtr<nsIWindowsRegKey>usersKey;rv=parentalControlsKey->OpenChild(usersString,flags,getter_AddRefs(usersKey));if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to open Users subkey"));returnrv;}nsAutoStringsid;if(!GetUserSid(sid)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't get sid"));returnNS_ERROR_FAILURE;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("our sid is '%S'",sid.get()));boolhasSid;rv=usersKey->HasChild(sid,&hasSid);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("HasChild(sid) failed"));returnrv;}if(!hasSid){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("sid not present in Family Safety Users"));returnNS_OK;}nsCOMPtr<nsIWindowsRegKey>sidKey;rv=usersKey->OpenChild(sid,flags,getter_AddRefs(sidKey));if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't open sid key"));returnrv;}// There are three keys we're interested in: "Parental Controls On",// "Logging Required", and "Web\\Filter On". These keys will have value 0// or 1, indicating a particular feature is disabled or enabled,// respectively. So, if "Parental Controls On" is not 1, Family Safety is// disabled and we don't care about anything else. If both "Logging// Required" and "Web\\Filter On" are 0, the proxy will not be running,// so for our purposes we can consider Family Safety disabled in that// case.// By default, "Logging Required" is 1 and "Web\\Filter On" is 0,// reflecting the initial settings when Family Safety is enabled for an// account for the first time, However, these sub-keys are not created// unless they are switched away from the default value.uint32_tparentalControlsOn;rv=sidKey->ReadIntValue(u"Parental Controls On"_ns,&parentalControlsOn);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't read Parental Controls On"));returnrv;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Parental Controls On: %u",parentalControlsOn));if(parentalControlsOn!=1){returnNS_OK;}uint32_tloggingRequired;rv=ReadRegKeyValueWithDefault(sidKey,flags,nullptr,L"Logging Required",1,loggingRequired);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to read value of Logging Required"));returnrv;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Logging Required: %u",loggingRequired));uint32_twebFilterOn;rv=ReadRegKeyValueWithDefault(sidKey,flags,L"Web",L"Filter On",0,webFilterOn);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to read value of Web\\Filter On"));returnrv;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Web\\Filter On: %u",webFilterOn));enabled=loggingRequired==1||webFilterOn==1;returnNS_OK;}#endif // XP_WIN// On Windows 8.1, if the following preference is 2, we will attempt to detect// if the Family Safety TLS interception feature has been enabled. If so, we// will behave as if the enterprise roots feature has been enabled (i.e. import// and trust third party root certificates from the OS).// With any other value of the pref or on any other platform, this does nothing.// This preference takes precedence over "security.enterprise_roots.enabled".constchar*kFamilySafetyModePref="security.family_safety.mode";constuint32_tkFamilySafetyModeDefault=0;boolnsNSSComponent::ShouldEnableEnterpriseRootsForFamilySafety(uint32_tfamilySafetyMode){#ifdef XP_WINif(!(IsWin8Point1OrLater()&&!IsWin10OrLater())){returnfalse;}if(familySafetyMode!=2){returnfalse;}boolfamilySafetyEnabled;nsresultrv=AccountHasFamilySafetyEnabled(familySafetyEnabled);if(NS_FAILED(rv)){returnfalse;}returnfamilySafetyEnabled;#elsereturnfalse;#endif // XP_WIN}voidnsNSSComponent::UnloadEnterpriseRoots(){MOZ_ASSERT(NS_IsMainThread());if(!NS_IsMainThread()){return;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("UnloadEnterpriseRoots"));MutexAutoLocklock(mMutex);mEnterpriseCerts.clear();setValidationOptions(false,lock);}staticconstchar*kEnterpriseRootModePref="security.enterprise_roots.enabled";staticconstchar*kOSClientCertsModulePref="security.osclientcerts.autoload";classBackgroundImportEnterpriseCertsTaskfinal:publicCryptoTask{public:explicitBackgroundImportEnterpriseCertsTask(nsNSSComponent*nssComponent):mNSSComponent(nssComponent){}private:virtualnsresultCalculateResult()override{mNSSComponent->ImportEnterpriseRoots();mNSSComponent->UpdateCertVerifierWithEnterpriseRoots();returnNS_OK;}virtualvoidCallCallback(nsresultrv)override{nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();if(observerService){observerService->NotifyObservers(nullptr,"psm:enterprise-certs-imported",nullptr);}}RefPtr<nsNSSComponent>mNSSComponent;};voidnsNSSComponent::MaybeImportEnterpriseRoots(){MOZ_ASSERT(NS_IsMainThread());if(!NS_IsMainThread()){return;}boolimportEnterpriseRoots=Preferences::GetBool(kEnterpriseRootModePref,false);uint32_tfamilySafetyMode=Preferences::GetUint(kFamilySafetyModePref,kFamilySafetyModeDefault);// If we've been configured to detect the Family Safety TLS interception// feature, see if it's enabled. If so, we want to import enterprise roots.if(ShouldEnableEnterpriseRootsForFamilySafety(familySafetyMode)){importEnterpriseRoots=true;}if(importEnterpriseRoots){RefPtr<BackgroundImportEnterpriseCertsTask>task=newBackgroundImportEnterpriseCertsTask(this);Unused<<task->Dispatch();}}voidnsNSSComponent::ImportEnterpriseRoots(){MOZ_ASSERT(!NS_IsMainThread());if(NS_IsMainThread()){return;}Vector<EnterpriseCert>enterpriseCerts;nsresultrv=GatherEnterpriseCerts(enterpriseCerts);if(NS_SUCCEEDED(rv)){MutexAutoLocklock(mMutex);mEnterpriseCerts=std::move(enterpriseCerts);}else{MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed gathering enterprise roots"));}}nsresultnsNSSComponent::CommonGetEnterpriseCerts(nsTArray<nsTArray<uint8_t>>&enterpriseCerts,boolgetRoots){nsresultrv=BlockUntilLoadableCertsLoaded();if(NS_FAILED(rv)){returnrv;}MutexAutoLocknsNSSComponentLock(mMutex);enterpriseCerts.Clear();for(constauto&cert:mEnterpriseCerts){nsTArray<uint8_t>certCopy;// mEnterpriseCerts includes both roots and intermediates.if(cert.GetIsRoot()==getRoots){nsresultrv=cert.CopyBytes(certCopy);if(NS_FAILED(rv)){returnrv;}// XXX(Bug 1631371) Check if this should use a fallible operation as it// pretended earlier.enterpriseCerts.AppendElement(std::move(certCopy));}}returnNS_OK;}NS_IMETHODIMPnsNSSComponent::GetEnterpriseRoots(nsTArray<nsTArray<uint8_t>>&enterpriseRoots){returnCommonGetEnterpriseCerts(enterpriseRoots,true);}NS_IMETHODIMPnsNSSComponent::GetEnterpriseIntermediates(nsTArray<nsTArray<uint8_t>>&enterpriseIntermediates){returnCommonGetEnterpriseCerts(enterpriseIntermediates,false);}NS_IMETHODIMPnsNSSComponent::AddEnterpriseIntermediate(constnsTArray<uint8_t>&intermediateBytes){nsresultrv=BlockUntilLoadableCertsLoaded();if(NS_FAILED(rv)){returnrv;}EnterpriseCertintermediate;rv=intermediate.Init(intermediateBytes.Elements(),intermediateBytes.Length(),false);if(NS_FAILED(rv)){returnrv;}{MutexAutoLocknsNSSComponentLock(mMutex);if(!mEnterpriseCerts.append(std::move(intermediate))){returnNS_ERROR_OUT_OF_MEMORY;}}UpdateCertVerifierWithEnterpriseRoots();returnNS_OK;}classLoadLoadableCertsTaskfinal:publicRunnable{public:LoadLoadableCertsTask(nsNSSComponent*nssComponent,boolimportEnterpriseRoots,uint32_tfamilySafetyMode,Vector<nsCString>&&possibleLoadableRootsLocations,Maybe<nsCString>&&osClientCertsModuleLocation):Runnable("LoadLoadableCertsTask"),mNSSComponent(nssComponent),mImportEnterpriseRoots(importEnterpriseRoots),mFamilySafetyMode(familySafetyMode),mPossibleLoadableRootsLocations(std::move(possibleLoadableRootsLocations)),mOSClientCertsModuleLocation(std::move(osClientCertsModuleLocation)){MOZ_ASSERT(nssComponent);}~LoadLoadableCertsTask()=default;nsresultDispatch();private:NS_IMETHODRun()override;nsresultLoadLoadableRoots();RefPtr<nsNSSComponent>mNSSComponent;boolmImportEnterpriseRoots;uint32_tmFamilySafetyMode;Vector<nsCString>mPossibleLoadableRootsLocations;Maybe<nsCString>mOSClientCertsModuleLocation;};nsresultLoadLoadableCertsTask::Dispatch(){// The stream transport service (note: not the socket transport service) can// be used to perform background tasks or I/O that would otherwise block the// main thread.nsCOMPtr<nsIEventTarget>target(do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID));if(!target){returnNS_ERROR_FAILURE;}returntarget->Dispatch(this,NS_DISPATCH_NORMAL);}NS_IMETHODIMPLoadLoadableCertsTask::Run(){Telemetry::AutoScalarTimer<Telemetry::ScalarID::NETWORKING_LOADING_CERTS_TASK>timer;nsresultloadLoadableRootsResult=LoadLoadableRoots();if(NS_WARN_IF(NS_FAILED(loadLoadableRootsResult))){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("LoadLoadableRoots failed"));// We don't return loadLoadableRootsResult here because then// BlockUntilLoadableCertsLoaded will just wait forever. Instead we'll save// its value (below) so we can inform code that relies on the roots module// being present that loading it failed.}// Loading EV information will only succeed if we've successfully loaded the// loadable roots module.if(NS_SUCCEEDED(loadLoadableRootsResult)){if(NS_FAILED(LoadExtendedValidationInfo())){// This isn't a show-stopper in the same way that failing to load the// roots module is.MOZ_LOG(gPIPNSSLog,LogLevel::Error,("failed to load EV info"));}}// If we've been configured to detect the Family Safety TLS interception// feature, see if it's enabled. If so, we want to import enterprise roots.if(mNSSComponent->ShouldEnableEnterpriseRootsForFamilySafety(mFamilySafetyMode)){mImportEnterpriseRoots=true;}if(mImportEnterpriseRoots){mNSSComponent->ImportEnterpriseRoots();mNSSComponent->UpdateCertVerifierWithEnterpriseRoots();}if(mOSClientCertsModuleLocation.isSome()){boolsuccess=LoadOSClientCertsModule(*mOSClientCertsModuleLocation);MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("loading OS client certs module %s",success?"succeeded":"failed"));}{MonitorAutoLockrootsLoadedLock(mNSSComponent->mLoadableCertsLoadedMonitor);mNSSComponent->mLoadableCertsLoaded=true;// Cache the result of LoadLoadableRoots so BlockUntilLoadableCertsLoaded// can return it to all callers later (we use that particular result because// if that operation fails, it's unlikely that any TLS connection will// succeed whereas the browser may still be able to operate if the other// tasks fail).mNSSComponent->mLoadableCertsLoadedResult=loadLoadableRootsResult;mNSSComponent->mLoadableCertsLoadedMonitor.NotifyAll();}returnNS_OK;}// Returns by reference the path to the desired directory, based on the current// settings in the directory service.staticnsresultGetDirectoryPath(constchar*directoryKey,nsCString&result){MOZ_ASSERT(NS_IsMainThread());nsCOMPtr<nsIProperties>directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));if(!directoryService){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("could not get directory service"));returnNS_ERROR_FAILURE;}nsCOMPtr<nsIFile>directory;nsresultrv=directoryService->Get(directoryKey,NS_GET_IID(nsIFile),getter_AddRefs(directory));if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("could not get '%s' from directory service",directoryKey));returnrv;}#ifdef XP_WIN// Native path will drop Unicode characters that cannot be mapped to system's// codepage, using short (canonical) path as workaround.nsCOMPtr<nsILocalFileWin>directoryWin=do_QueryInterface(directory);if(!directoryWin){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't get nsILocalFileWin"));returnNS_ERROR_FAILURE;}returndirectoryWin->GetNativeCanonicalPath(result);#elsereturndirectory->GetNativePath(result);#endif}classBackgroundLoadOSClientCertsModuleTaskfinal:publicCryptoTask{public:explicitBackgroundLoadOSClientCertsModuleTask(constnsCString&&libraryDir):mLibraryDir(std::move(libraryDir)){}private:virtualnsresultCalculateResult()override{boolsuccess=LoadOSClientCertsModule(mLibraryDir);returnsuccess?NS_OK:NS_ERROR_FAILURE;}virtualvoidCallCallback(nsresultrv)override{MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("loading OS client certs module %s",NS_SUCCEEDED(rv)?"succeeded":"failed"));nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();if(observerService){observerService->NotifyObservers(nullptr,"psm:load-os-client-certs-module-task-ran",nullptr);}}nsCStringmLibraryDir;};voidAsyncLoadOrUnloadOSClientCertsModule(boolload){if(load){nsCStringlibraryDir;nsresultrv=GetDirectoryPath(NS_GRE_BIN_DIR,libraryDir);if(NS_FAILED(rv)){return;}RefPtr<BackgroundLoadOSClientCertsModuleTask>task=newBackgroundLoadOSClientCertsModuleTask(std::move(libraryDir));Unused<<task->Dispatch();}else{UniqueSECMODModuleosClientCertsModule(SECMOD_FindModule(kOSClientCertsModuleName));if(osClientCertsModule){SECMOD_UnloadUserModule(osClientCertsModule.get());}}}NS_IMETHODIMPnsNSSComponent::HasActiveSmartCards(bool*result){NS_ENSURE_ARG_POINTER(result);BlockUntilLoadableCertsLoaded();#ifndef MOZ_NO_SMART_CARDSAutoSECMODListReadLocksecmodLock;SECMODModuleList*list=SECMOD_GetDefaultModuleList();while(list){SECMODModule*module=list->module;if(SECMOD_HasRemovableSlots(module)){*result=true;returnNS_OK;}for(inti=0;i<module->slotCount;i++){if(!PK11_IsFriendly(module->slots[i])){*result=true;returnNS_OK;}}list=list->next;}#endif*result=false;returnNS_OK;}NS_IMETHODIMPnsNSSComponent::HasUserCertsInstalled(bool*result){NS_ENSURE_ARG_POINTER(result);BlockUntilLoadableCertsLoaded();// FindClientCertificatesWithPrivateKeys won't ever return an empty list, so// all we need to do is check if this is null or not.UniqueCERTCertListcertList(FindClientCertificatesWithPrivateKeys());*result=!!certList;returnNS_OK;}nsresultnsNSSComponent::BlockUntilLoadableCertsLoaded(){MonitorAutoLockrootsLoadedLock(mLoadableCertsLoadedMonitor);while(!mLoadableCertsLoaded){rootsLoadedLock.Wait();}MOZ_ASSERT(mLoadableCertsLoaded);returnmLoadableCertsLoadedResult;}#ifndef MOZ_NO_SMART_CARDSstaticStaticMutexsCheckForSmartCardChangesMutex;staticTimeStampsLastCheckedForSmartCardChanges=TimeStamp::Now();#endifnsresultnsNSSComponent::CheckForSmartCardChanges(){#ifndef MOZ_NO_SMART_CARDS{StaticMutexAutoLocklock(sCheckForSmartCardChangesMutex);// Do this at most once every 3 seconds.TimeStampnow=TimeStamp::Now();if(now-sLastCheckedForSmartCardChanges<TimeDuration::FromSeconds(3.0)){returnNS_OK;}sLastCheckedForSmartCardChanges=now;}// SECMOD_UpdateSlotList attempts to acquire the list lock as well,// so we have to do this in two steps. The lock protects the list itself, so// if we get our own owned references to the modules we're interested in,// there's no thread safety concern here.Vector<UniqueSECMODModule>modulesWithRemovableSlots;{AutoSECMODListReadLocksecmodLock;SECMODModuleList*list=SECMOD_GetDefaultModuleList();while(list){if(SECMOD_HasRemovableSlots(list->module)){UniqueSECMODModulemodule(SECMOD_ReferenceModule(list->module));if(!modulesWithRemovableSlots.append(std::move(module))){returnNS_ERROR_OUT_OF_MEMORY;}}list=list->next;}}for(auto&module:modulesWithRemovableSlots){// Best-effort.Unused<<SECMOD_UpdateSlotList(module.get());for(inti=0;i<module->slotCount;i++){// We actually don't care about the return value here - we just need to// call this to get NSS to update its view of this slot.Unused<<PK11_IsPresent(module->slots[i]);}}#endifreturnNS_OK;}// Returns by reference the path to the directory containing the file that has// been loaded as MOZ_DLL_PREFIX nss3 MOZ_DLL_SUFFIX.staticnsresultGetNSS3Directory(nsCString&result){MOZ_ASSERT(NS_IsMainThread());UniquePRStringnss3Path(PR_GetLibraryFilePathname(MOZ_DLL_PREFIX"nss3"MOZ_DLL_SUFFIX,reinterpret_cast<PRFuncPtr>(NSS_Initialize)));if(!nss3Path){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nss not loaded?"));returnNS_ERROR_FAILURE;}nsCOMPtr<nsIFile>nss3File(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));if(!nss3File){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't create a file?"));returnNS_ERROR_FAILURE;}nsAutoCStringnss3PathAsString(nss3Path.get());nsresultrv=nss3File->InitWithNativePath(nss3PathAsString);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't initialize file with path '%s'",nss3Path.get()));returnrv;}nsCOMPtr<nsIFile>nss3Directory;rv=nss3File->GetParent(getter_AddRefs(nss3Directory));if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't get parent directory?"));returnrv;}#ifdef XP_WIN// Native path will drop Unicode characters that cannot be mapped to system's// codepage, using short (canonical) path as workaround.nsCOMPtr<nsILocalFileWin>nss3DirectoryWin=do_QueryInterface(nss3Directory);if(!nss3DirectoryWin){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't get nsILocalFileWin"));returnNS_ERROR_FAILURE;}returnnss3DirectoryWin->GetNativeCanonicalPath(result);#elsereturnnss3Directory->GetNativePath(result);#endif}// The loadable roots library is probably in the same directory we loaded the// NSS shared library from, but in some cases it may be elsewhere. This function// enumerates and returns the possible locations as nsCStrings.staticnsresultListPossibleLoadableRootsLocations(Vector<nsCString>&possibleLoadableRootsLocations){MOZ_ASSERT(NS_IsMainThread());if(!NS_IsMainThread()){returnNS_ERROR_NOT_SAME_THREAD;}// First try in the directory where we've already loaded// MOZ_DLL_PREFIX nss3 MOZ_DLL_SUFFIX, since that's likely to be correct.nsAutoCStringnss3Dir;nsresultrv=GetNSS3Directory(nss3Dir);if(NS_SUCCEEDED(rv)){if(!possibleLoadableRootsLocations.append(std::move(nss3Dir))){returnNS_ERROR_OUT_OF_MEMORY;}}else{// For some reason this fails on android. In any case, we should try with// the other potential locations we have.MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("could not determine where nss was loaded from"));}nsAutoCStringcurrentProcessDir;rv=GetDirectoryPath(NS_XPCOM_CURRENT_PROCESS_DIR,currentProcessDir);if(NS_SUCCEEDED(rv)){if(!possibleLoadableRootsLocations.append(std::move(currentProcessDir))){returnNS_ERROR_OUT_OF_MEMORY;}}else{MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("could not get current process directory"));}nsAutoCStringgreDir;rv=GetDirectoryPath(NS_GRE_DIR,greDir);if(NS_SUCCEEDED(rv)){if(!possibleLoadableRootsLocations.append(std::move(greDir))){returnNS_ERROR_OUT_OF_MEMORY;}}else{MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("could not get gre directory"));}// As a last resort, this will cause the library loading code to use the OS'// default library search path.nsAutoCStringemptyString;if(!possibleLoadableRootsLocations.append(std::move(emptyString))){returnNS_ERROR_OUT_OF_MEMORY;}returnNS_OK;}nsresultLoadLoadableCertsTask::LoadLoadableRoots(){for(constauto&possibleLocation:mPossibleLoadableRootsLocations){if(mozilla::psm::LoadLoadableRoots(possibleLocation)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("loaded CKBI from %s",possibleLocation.get()));returnNS_OK;}}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("could not load loadable roots"));returnNS_ERROR_FAILURE;}// Table of pref names and SSL cipher IDtypedefstruct{constchar*pref;longid;boolenabledByDefault;}CipherPref;// Update the switch statement in AccumulateCipherSuite in nsNSSCallbacks.cpp// when you add/remove cipher suites here.staticconstCipherPrefsCipherPrefs[]={{"security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,true},{"security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256",TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,true},{"security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256",TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,true},{"security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256",TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,true},{"security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384",TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,true},{"security.ssl3.ecdhe_rsa_aes_256_gcm_sha384",TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,true},{"security.ssl3.ecdhe_rsa_aes_128_sha",TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,true},{"security.ssl3.ecdhe_ecdsa_aes_128_sha",TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,true},{"security.ssl3.ecdhe_rsa_aes_256_sha",TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,true},{"security.ssl3.ecdhe_ecdsa_aes_256_sha",TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,true},{"security.ssl3.dhe_rsa_aes_128_sha",TLS_DHE_RSA_WITH_AES_128_CBC_SHA,false},{"security.ssl3.dhe_rsa_aes_256_sha",TLS_DHE_RSA_WITH_AES_256_CBC_SHA,false},{"security.tls13.aes_128_gcm_sha256",TLS_AES_128_GCM_SHA256,true},{"security.tls13.chacha20_poly1305_sha256",TLS_CHACHA20_POLY1305_SHA256,true},{"security.tls13.aes_256_gcm_sha384",TLS_AES_256_GCM_SHA384,true},{"security.ssl3.rsa_aes_128_gcm_sha256",TLS_RSA_WITH_AES_128_GCM_SHA256,true},// deprecated (RSA key exchange){"security.ssl3.rsa_aes_256_gcm_sha384",TLS_RSA_WITH_AES_256_GCM_SHA384,true},// deprecated (RSA key exchange){"security.ssl3.rsa_aes_128_sha",TLS_RSA_WITH_AES_128_CBC_SHA,true},// deprecated (RSA key exchange){"security.ssl3.rsa_aes_256_sha",TLS_RSA_WITH_AES_256_CBC_SHA,true},// deprecated (RSA key exchange){"security.ssl3.rsa_des_ede3_sha",TLS_RSA_WITH_3DES_EDE_CBC_SHA,true},// deprecated (RSA key exchange, 3DES)// All the rest are disabled{nullptr,0}// end marker};// This function will convert from pref values like 1, 2, ...// to the internal values of SSL_LIBRARY_VERSION_TLS_1_0,// SSL_LIBRARY_VERSION_TLS_1_1, .../*static*/voidnsNSSComponent::FillTLSVersionRange(SSLVersionRange&rangeOut,uint32_tminFromPrefs,uint32_tmaxFromPrefs,SSLVersionRangedefaults){rangeOut=defaults;// determine what versions are supportedSSLVersionRangesupported;if(SSL_VersionRangeGetSupported(ssl_variant_stream,&supported)!=SECSuccess){return;}// Clip the defaults by what NSS actually supports to enable// working with a system NSS with different ranges.rangeOut.min=std::max(rangeOut.min,supported.min);rangeOut.max=std::min(rangeOut.max,supported.max);// convert min/maxFromPrefs to the internal representationminFromPrefs+=SSL_LIBRARY_VERSION_3_0;maxFromPrefs+=SSL_LIBRARY_VERSION_3_0;// if min/maxFromPrefs are invalid, use defaultsif(minFromPrefs>maxFromPrefs||minFromPrefs<supported.min||maxFromPrefs>supported.max||minFromPrefs<SSL_LIBRARY_VERSION_TLS_1_0){return;}// fill out rangeOutrangeOut.min=(uint16_t)minFromPrefs;rangeOut.max=(uint16_t)maxFromPrefs;}staticconstint32_tOCSP_ENABLED_DEFAULT=1;staticconstboolREQUIRE_SAFE_NEGOTIATION_DEFAULT=false;staticconstboolFALSE_START_ENABLED_DEFAULT=true;staticconstboolALPN_ENABLED_DEFAULT=false;staticconstboolENABLED_0RTT_DATA_DEFAULT=false;staticconstboolHELLO_DOWNGRADE_CHECK_DEFAULT=true;staticconstboolENABLED_POST_HANDSHAKE_AUTH_DEFAULT=false;staticconstboolDELEGATED_CREDENTIALS_ENABLED_DEFAULT=false;staticvoidConfigureTLSSessionIdentifiers(){booldisableSessionIdentifiers=Preferences::GetBool("security.ssl.disable_session_identifiers",false);SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS,!disableSessionIdentifiers);SSL_OptionSetDefault(SSL_NO_CACHE,disableSessionIdentifiers);}nsresultCommonInit(){SSL_OptionSetDefault(SSL_ENABLE_SSL2,false);SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO,false);nsresultrv=nsNSSComponent::SetEnabledTLSVersions();if(NS_FAILED(rv)){returnrv;}ConfigureTLSSessionIdentifiers();boolrequireSafeNegotiation=Preferences::GetBool("security.ssl.require_safe_negotiation",REQUIRE_SAFE_NEGOTIATION_DEFAULT);SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION,requireSafeNegotiation);SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,SSL_RENEGOTIATE_REQUIRES_XTN);SSL_OptionSetDefault(SSL_ENABLE_EXTENDED_MASTER_SECRET,true);boolenableDowngradeCheck=Preferences::GetBool("security.tls.hello_downgrade_check",HELLO_DOWNGRADE_CHECK_DEFAULT);SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK,enableDowngradeCheck);SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,Preferences::GetBool("security.ssl.enable_false_start",FALSE_START_ENABLED_DEFAULT));// SSL_ENABLE_ALPN also requires calling SSL_SetNextProtoNego in order for// the extensions to be negotiated.// WebRTC does not do that so it will not use ALPN even when this preference// is true.SSL_OptionSetDefault(SSL_ENABLE_ALPN,Preferences::GetBool("security.ssl.enable_alpn",ALPN_ENABLED_DEFAULT));SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,Preferences::GetBool("security.tls.enable_0rtt_data",ENABLED_0RTT_DATA_DEFAULT));SSL_OptionSetDefault(SSL_ENABLE_POST_HANDSHAKE_AUTH,Preferences::GetBool("security.tls.enable_post_handshake_auth",ENABLED_POST_HANDSHAKE_AUTH_DEFAULT));SSL_OptionSetDefault(SSL_ENABLE_DELEGATED_CREDENTIALS,Preferences::GetBool("security.tls.enable_delegated_credentials",DELEGATED_CREDENTIALS_ENABLED_DEFAULT));rv=InitializeCipherSuite();if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("Unable to initialize cipher suite settings\n"));returnrv;}DisableMD5();mozilla::pkix::RegisterErrorTable();SharedSSLState::GlobalInit();RememberCertErrorsTable::Init();SetValidationOptionsCommon();returnNS_OK;}voidNSSShutdownForSocketProcess(){MOZ_ASSERT(XRE_IsSocketProcess());SharedSSLState::GlobalCleanup();RememberCertErrorsTable::Cleanup();}boolHandleTLSPrefChange(constnsCString&prefName){// Note that the code in this function should be kept in sync with// gCallbackSecurityPrefs in nsIOService.cpp.boolprefFound=true;if(prefName.EqualsLiteral("security.tls.version.min")||prefName.EqualsLiteral("security.tls.version.max")||prefName.EqualsLiteral("security.tls.version.enable-deprecated")){(void)nsNSSComponent::SetEnabledTLSVersions();}elseif(prefName.EqualsLiteral("security.tls.hello_downgrade_check")){boolenableDowngradeCheck=Preferences::GetBool("security.tls.hello_downgrade_check",HELLO_DOWNGRADE_CHECK_DEFAULT);SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK,enableDowngradeCheck);}elseif(prefName.EqualsLiteral("security.ssl.require_safe_negotiation")){boolrequireSafeNegotiation=Preferences::GetBool("security.ssl.require_safe_negotiation",REQUIRE_SAFE_NEGOTIATION_DEFAULT);SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION,requireSafeNegotiation);}elseif(prefName.EqualsLiteral("security.ssl.enable_false_start")){SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,Preferences::GetBool("security.ssl.enable_false_start",FALSE_START_ENABLED_DEFAULT));}elseif(prefName.EqualsLiteral("security.ssl.enable_alpn")){SSL_OptionSetDefault(SSL_ENABLE_ALPN,Preferences::GetBool("security.ssl.enable_alpn",ALPN_ENABLED_DEFAULT));}elseif(prefName.EqualsLiteral("security.tls.enable_0rtt_data")){SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,Preferences::GetBool("security.tls.enable_0rtt_data",ENABLED_0RTT_DATA_DEFAULT));}elseif(prefName.EqualsLiteral("security.tls.enable_post_handshake_auth")){SSL_OptionSetDefault(SSL_ENABLE_POST_HANDSHAKE_AUTH,Preferences::GetBool("security.tls.enable_post_handshake_auth",ENABLED_POST_HANDSHAKE_AUTH_DEFAULT));}elseif(prefName.EqualsLiteral("security.tls.enable_delegated_credentials")){SSL_OptionSetDefault(SSL_ENABLE_DELEGATED_CREDENTIALS,Preferences::GetBool("security.tls.enable_delegated_credentials",DELEGATED_CREDENTIALS_ENABLED_DEFAULT));}elseif(prefName.EqualsLiteral("security.ssl.disable_session_identifiers")){ConfigureTLSSessionIdentifiers();}else{prefFound=false;}returnprefFound;}voidSetValidationOptionsCommon(){// Note that the code in this function should be kept in sync with// gCallbackSecurityPrefs in nsIOService.cpp.boolocspStaplingEnabled=Preferences::GetBool("security.ssl.enable_ocsp_stapling",true);PublicSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);PrivateSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);boolocspMustStapleEnabled=Preferences::GetBool("security.ssl.enable_ocsp_must_staple",true);PublicSSLState()->SetOCSPMustStapleEnabled(ocspMustStapleEnabled);PrivateSSLState()->SetOCSPMustStapleEnabled(ocspMustStapleEnabled);constCertVerifier::CertificateTransparencyModedefaultCTMode=CertVerifier::CertificateTransparencyMode::TelemetryOnly;CertVerifier::CertificateTransparencyModectMode=static_cast<CertVerifier::CertificateTransparencyMode>(Preferences::GetInt("security.pki.certificate_transparency.mode",static_cast<int32_t>(defaultCTMode)));switch(ctMode){caseCertVerifier::CertificateTransparencyMode::Disabled:caseCertVerifier::CertificateTransparencyMode::TelemetryOnly:break;default:ctMode=defaultCTMode;break;}boolsctsEnabled=ctMode!=CertVerifier::CertificateTransparencyMode::Disabled;PublicSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);PrivateSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);CertVerifier::PinningModepinningMode=static_cast<CertVerifier::PinningMode>(Preferences::GetInt("security.cert_pinning.enforcement_level",CertVerifier::pinningDisabled));if(pinningMode>CertVerifier::pinningEnforceTestMode){pinningMode=CertVerifier::pinningDisabled;}PublicSSLState()->SetPinningMode(pinningMode);PrivateSSLState()->SetPinningMode(pinningMode);BRNameMatchingPolicy::ModenameMatchingMode=static_cast<BRNameMatchingPolicy::Mode>(Preferences::GetInt("security.pki.name_matching_mode",static_cast<int32_t>(BRNameMatchingPolicy::Mode::DoNotEnforce)));switch(nameMatchingMode){caseBRNameMatchingPolicy::Mode::Enforce:caseBRNameMatchingPolicy::Mode::EnforceAfter23August2015:caseBRNameMatchingPolicy::Mode::EnforceAfter23August2016:caseBRNameMatchingPolicy::Mode::DoNotEnforce:break;default:nameMatchingMode=BRNameMatchingPolicy::Mode::DoNotEnforce;break;}PublicSSLState()->SetNameMatchingMode(nameMatchingMode);PrivateSSLState()->SetNameMatchingMode(nameMatchingMode);}namespace{classCipherSuiteChangeObserver:publicnsIObserver{public:NS_DECL_ISUPPORTSNS_DECL_NSIOBSERVERstaticnsresultStartObserve();protected:virtual~CipherSuiteChangeObserver()=default;private:staticStaticRefPtr<CipherSuiteChangeObserver>sObserver;CipherSuiteChangeObserver()=default;};NS_IMPL_ISUPPORTS(CipherSuiteChangeObserver,nsIObserver)// staticStaticRefPtr<CipherSuiteChangeObserver>CipherSuiteChangeObserver::sObserver;// staticnsresultCipherSuiteChangeObserver::StartObserve(){MOZ_ASSERT(NS_IsMainThread(),"CipherSuiteChangeObserver::StartObserve() can only be accessed ""on the main thread");if(!sObserver){RefPtr<CipherSuiteChangeObserver>observer=newCipherSuiteChangeObserver();nsresultrv=Preferences::AddStrongObserver(observer.get(),"security.");if(NS_FAILED(rv)){sObserver=nullptr;returnrv;}nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();observerService->AddObserver(observer,NS_XPCOM_SHUTDOWN_OBSERVER_ID,false);sObserver=observer;}returnNS_OK;}nsresultCipherSuiteChangeObserver::Observe(nsISupports*/*aSubject*/,constchar*aTopic,constchar16_t*someData){MOZ_ASSERT(NS_IsMainThread(),"CipherSuiteChangeObserver::Observe can only be accessed on main ""thread");if(nsCRT::strcmp(aTopic,NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)==0){NS_ConvertUTF16toUTF8prefName(someData);// Look through the cipher table and set according to pref settingconstCipherPref*constcp=sCipherPrefs;for(size_ti=0;cp[i].pref;++i){if(prefName.Equals(cp[i].pref)){boolcipherEnabled=Preferences::GetBool(cp[i].pref,cp[i].enabledByDefault);SSL_CipherPrefSetDefault(cp[i].id,cipherEnabled);nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();break;}}}elseif(nsCRT::strcmp(aTopic,NS_XPCOM_SHUTDOWN_OBSERVER_ID)==0){Preferences::RemoveObserver(this,"security.");MOZ_ASSERT(sObserver.get()==this);sObserver=nullptr;nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();observerService->RemoveObserver(this,NS_XPCOM_SHUTDOWN_OBSERVER_ID);}returnNS_OK;}}// namespacevoidnsNSSComponent::setValidationOptions(boolisInitialSetting,constmozilla::MutexAutoLock&proofOfLock){// We access prefs so this must be done on the main thread.MOZ_ASSERT(NS_IsMainThread());if(NS_WARN_IF(!NS_IsMainThread())){return;}SetValidationOptionsCommon();constCertVerifier::CertificateTransparencyModedefaultCTMode=CertVerifier::CertificateTransparencyMode::TelemetryOnly;CertVerifier::CertificateTransparencyModectMode=static_cast<CertVerifier::CertificateTransparencyMode>(Preferences::GetInt("security.pki.certificate_transparency.mode",static_cast<int32_t>(defaultCTMode)));switch(ctMode){caseCertVerifier::CertificateTransparencyMode::Disabled:caseCertVerifier::CertificateTransparencyMode::TelemetryOnly:break;default:ctMode=defaultCTMode;break;}// This preference controls whether we do OCSP fetching and does not affect// OCSP stapling.// 0 = disabled, 1 = enabledint32_tocspEnabled=Preferences::GetInt("security.OCSP.enabled",OCSP_ENABLED_DEFAULT);boolocspRequired=ocspEnabled&&Preferences::GetBool("security.OCSP.require",false);// We measure the setting of the pref at startup only to minimize noise by// addons that may muck with the settings, though it probably doesn't matter.if(isInitialSetting){Telemetry::Accumulate(Telemetry::CERT_OCSP_ENABLED,ocspEnabled);Telemetry::Accumulate(Telemetry::CERT_OCSP_REQUIRED,ocspRequired);}CertVerifier::SHA1Modesha1Mode=static_cast<CertVerifier::SHA1Mode>(Preferences::GetInt("security.pki.sha1_enforcement_level",static_cast<int32_t>(CertVerifier::SHA1Mode::Allowed)));switch(sha1Mode){caseCertVerifier::SHA1Mode::Allowed:caseCertVerifier::SHA1Mode::Forbidden:caseCertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:caseCertVerifier::SHA1Mode::ImportedRoot:caseCertVerifier::SHA1Mode::ImportedRootOrBefore2016:break;default:sha1Mode=CertVerifier::SHA1Mode::Allowed;break;}// Convert a previously-available setting to a safe one.if(sha1Mode==CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden){sha1Mode=CertVerifier::SHA1Mode::Forbidden;}NetscapeStepUpPolicynetscapeStepUpPolicy=static_cast<NetscapeStepUpPolicy>(Preferences::GetUint("security.pki.netscape_step_up_policy",static_cast<uint32_t>(NetscapeStepUpPolicy::AlwaysMatch)));switch(netscapeStepUpPolicy){caseNetscapeStepUpPolicy::AlwaysMatch:caseNetscapeStepUpPolicy::MatchBefore23August2016:caseNetscapeStepUpPolicy::MatchBefore23August2015:caseNetscapeStepUpPolicy::NeverMatch:break;default:netscapeStepUpPolicy=NetscapeStepUpPolicy::AlwaysMatch;break;}CRLiteModedefaultCRLiteMode=CRLiteMode::Disabled;CRLiteModecrliteMode=static_cast<CRLiteMode>(Preferences::GetUint("security.pki.crlite_mode",static_cast<uint32_t>(defaultCRLiteMode)));switch(crliteMode){caseCRLiteMode::Disabled:caseCRLiteMode::TelemetryOnly:caseCRLiteMode::Enforce:break;default:crliteMode=defaultCRLiteMode;break;}uint32_tdefaultCRLiteCTMergeDelaySeconds=60*60*28;// 28 hours in secondsuint64_tmaxCRLiteCTMergeDelaySeconds=60*60*24*365;uint64_tcrliteCTMergeDelaySeconds=Preferences::GetUint("security.pki.crlite_ct_merge_delay_seconds",defaultCRLiteCTMergeDelaySeconds);if(crliteCTMergeDelaySeconds>maxCRLiteCTMergeDelaySeconds){crliteCTMergeDelaySeconds=maxCRLiteCTMergeDelaySeconds;}CertVerifier::OcspDownloadConfigodc;CertVerifier::OcspStrictConfigosc;uint32_tcertShortLifetimeInDays;TimeDurationsoftTimeout;TimeDurationhardTimeout;GetRevocationBehaviorFromPrefs(&odc,&osc,&certShortLifetimeInDays,softTimeout,hardTimeout,proofOfLock);mDefaultCertVerifier=newSharedCertVerifier(odc,osc,softTimeout,hardTimeout,certShortLifetimeInDays,PublicSSLState()->PinningMode(),sha1Mode,PublicSSLState()->NameMatchingMode(),netscapeStepUpPolicy,ctMode,crliteMode,crliteCTMergeDelaySeconds,mEnterpriseCerts);}voidnsNSSComponent::UpdateCertVerifierWithEnterpriseRoots(){MutexAutoLocklock(mMutex);MOZ_ASSERT(mDefaultCertVerifier);if(NS_WARN_IF(!mDefaultCertVerifier)){return;}RefPtr<SharedCertVerifier>oldCertVerifier=mDefaultCertVerifier;mDefaultCertVerifier=newSharedCertVerifier(oldCertVerifier->mOCSPDownloadConfig,oldCertVerifier->mOCSPStrict?CertVerifier::ocspStrict:CertVerifier::ocspRelaxed,oldCertVerifier->mOCSPTimeoutSoft,oldCertVerifier->mOCSPTimeoutHard,oldCertVerifier->mCertShortLifetimeInDays,oldCertVerifier->mPinningMode,oldCertVerifier->mSHA1Mode,oldCertVerifier->mNameMatchingMode,oldCertVerifier->mNetscapeStepUpPolicy,oldCertVerifier->mCTMode,oldCertVerifier->mCRLiteMode,oldCertVerifier->mCRLiteCTMergeDelaySeconds,mEnterpriseCerts);}// 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.nsresultnsNSSComponent::SetEnabledTLSVersions(){// Keep these values in sync with all.js.// 1 means TLS 1.0, 2 means TLS 1.1, etc.staticconstuint32_tPSM_DEFAULT_MIN_TLS_VERSION=3;staticconstuint32_tPSM_DEFAULT_MAX_TLS_VERSION=4;staticconstuint32_tPSM_DEPRECATED_TLS_VERSION=1;uint32_tminFromPrefs=Preferences::GetUint("security.tls.version.min",PSM_DEFAULT_MIN_TLS_VERSION);uint32_tmaxFromPrefs=Preferences::GetUint("security.tls.version.max",PSM_DEFAULT_MAX_TLS_VERSION);// This override should be removed some time after// PSM_DEFAULT_MIN_TLS_VERSION is increased to 3.boolenableDeprecated=Preferences::GetBool("security.tls.version.enable-deprecated",false);if(enableDeprecated){minFromPrefs=std::min(minFromPrefs,PSM_DEPRECATED_TLS_VERSION);}SSLVersionRangedefaults={SSL_LIBRARY_VERSION_3_0+PSM_DEFAULT_MIN_TLS_VERSION,SSL_LIBRARY_VERSION_3_0+PSM_DEFAULT_MAX_TLS_VERSION};SSLVersionRangefilledInRange;FillTLSVersionRange(filledInRange,minFromPrefs,maxFromPrefs,defaults);SECStatussrv=SSL_VersionRangeSetDefault(ssl_variant_stream,&filledInRange);if(srv!=SECSuccess){returnNS_ERROR_FAILURE;}returnNS_OK;}#if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))// If the profile directory is on a networked drive, we want to set the// environment variable NSS_SDB_USE_CACHE to yes (as long as it hasn't been set// before).staticvoidSetNSSDatabaseCacheModeAsAppropriate(){MOZ_ASSERT(NS_IsMainThread());nsCOMPtr<nsIFile>profileFile;nsresultrv=NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,getter_AddRefs(profileFile));if(NS_FAILED(rv)){// We're probably running without a profile directory, so this is// irrelevant.return;}staticconstcharsNSS_SDB_USE_CACHE[]="NSS_SDB_USE_CACHE";staticconstcharsNSS_SDB_USE_CACHE_WITH_VALUE[]="NSS_SDB_USE_CACHE=yes";autoprofilePath=profileFile->NativePath();# if defined(XP_LINUX) && !defined(ANDROID)structstatfsstatfs_s;if(statfs(profilePath.get(),&statfs_s)==0&&statfs_s.f_type==NFS_SUPER_MAGIC&&!PR_GetEnv(sNSS_SDB_USE_CACHE)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("profile is remote (and NSS_SDB_USE_CACHE wasn't set): ""setting NSS_SDB_USE_CACHE"));PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);}else{MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("not setting NSS_SDB_USE_CACHE"));}# endif // defined(XP_LINUX) && !defined(ANDROID)# ifdef XP_WINwchar_tvolPath[MAX_PATH];if(::GetVolumePathNameW(profilePath.get(),volPath,MAX_PATH)&&::GetDriveTypeW(volPath)==DRIVE_REMOTE&&!PR_GetEnv(sNSS_SDB_USE_CACHE)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("profile is remote (and NSS_SDB_USE_CACHE wasn't set): ""setting NSS_SDB_USE_CACHE"));PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);}else{MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("not setting NSS_SDB_USE_CACHE"));}# endif // XP_WIN}#endif // defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))staticnsresultGetNSSProfilePath(nsAutoCString&aProfilePath){aProfilePath.Truncate();nsCOMPtr<nsIFile>profileFile;nsresultrv=NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,getter_AddRefs(profileFile));if(NS_FAILED(rv)){NS_WARNING("NSS will be initialized without a profile directory. ""Some things may not work as expected.");returnNS_OK;}#if defined(XP_WIN)// SQLite always takes UTF-8 file paths regardless of the current system// code page.nsCOMPtr<nsILocalFileWin>profileFileWin(do_QueryInterface(profileFile));if(!profileFileWin){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("Could not get nsILocalFileWin for profile directory.\n"));returnNS_ERROR_FAILURE;}nsAutoStringu16ProfilePath;rv=profileFileWin->GetCanonicalPath(u16ProfilePath);CopyUTF16toUTF8(u16ProfilePath,aProfilePath);#elserv=profileFile->GetNativePath(aProfilePath);#endifif(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("Could not get native path for profile directory.\n"));returnrv;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("NSS profile at '%s'\n",aProfilePath.get()));returnNS_OK;}#ifndef ANDROID// Given a profile path, attempt to rename the PKCS#11 module DB to// "pkcs11.txt.fips". In the case of a catastrophic failure (e.g. out of// memory), returns a failing nsresult. If execution could conceivably proceed,// returns NS_OK even if renaming the file didn't work. This simplifies the// logic of the calling code.// |profilePath| is encoded in UTF-8.staticnsresultAttemptToRenamePKCS11ModuleDB(constnsACString&profilePath){nsCOMPtr<nsIFile>profileDir=do_CreateInstance("@mozilla.org/file/local;1");if(!profileDir){returnNS_ERROR_FAILURE;}# ifdef XP_WIN// |profilePath| is encoded in UTF-8 because SQLite always takes UTF-8 file// paths regardless of the current system code page.nsresultrv=profileDir->InitWithPath(NS_ConvertUTF8toUTF16(profilePath));# elsensresultrv=profileDir->InitWithNativePath(profilePath);# endifif(NS_FAILED(rv)){returnrv;}constchar*moduleDBFilename="pkcs11.txt";nsAutoCStringdestModuleDBFilename(moduleDBFilename);destModuleDBFilename.Append(".fips");nsCOMPtr<nsIFile>dbFile;rv=profileDir->Clone(getter_AddRefs(dbFile));if(NS_FAILED(rv)||!dbFile){returnNS_ERROR_FAILURE;}rv=dbFile->AppendNative(nsAutoCString(moduleDBFilename));if(NS_FAILED(rv)){returnrv;}// If the PKCS#11 module DB doesn't exist, renaming it won't help.boolexists;rv=dbFile->Exists(&exists);if(NS_FAILED(rv)){returnrv;}// This is strange, but not a catastrophic failure.if(!exists){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("%s doesn't exist?",moduleDBFilename));returnNS_OK;}nsCOMPtr<nsIFile>destDBFile;rv=profileDir->Clone(getter_AddRefs(destDBFile));if(NS_FAILED(rv)||!destDBFile){returnNS_ERROR_FAILURE;}rv=destDBFile->AppendNative(destModuleDBFilename);if(NS_FAILED(rv)){returnrv;}// If the destination exists, presumably we've already tried this. Doing it// again won't help.rv=destDBFile->Exists(&exists);if(NS_FAILED(rv)){returnrv;}// Unfortunate, but not a catastrophic failure.if(exists){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("%s already exists - not overwriting",destModuleDBFilename.get()));returnNS_OK;}// Now do the actual move.// This may fail on, e.g., a read-only file system. This would be unfortunate,// but again it isn't catastropic and we would want to fall back to// initializing NSS in no-DB mode.Unused<<dbFile->MoveToNative(profileDir,destModuleDBFilename);returnNS_OK;}#endif // ifndef ANDROID// Given a profile directory, attempt to initialize NSS. If nocertdb is true,// (or if we don't have a profile directory) simply initialize NSS in no DB mode// and return. Otherwise, first attempt to initialize in read/write mode, and// then read-only mode if that fails. If both attempts fail, we may be failing// to initialize an NSS DB collection that has FIPS mode enabled. Attempt to// ascertain if this is the case, and if so, rename the offending PKCS#11 module// DB so we can (hopefully) initialize NSS in read-write mode. Again attempt// read-only mode if that fails. Finally, fall back to no DB mode. On Android// we can skip the FIPS workaround since it was never possible to enable FIPS// there anyway.// |profilePath| is encoded in UTF-8.staticnsresultInitializeNSSWithFallbacks(constnsACString&profilePath,boolnocertdb,boolsafeMode){if(nocertdb||profilePath.IsEmpty()){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nocertdb mode or empty profile path -> NSS_NoDB_Init"));SECStatussrv=NSS_NoDB_Init(nullptr);#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLEDif(srv!=SECSuccess){MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",PR_GetError());}#endifreturnsrv==SECSuccess?NS_OK:NS_ERROR_FAILURE;}// Try read/write mode. If we're in safeMode, we won't load PKCS#11 modules.#ifndef ANDROIDPRErrorCodesavedPRErrorCode1;#endif // ifndef ANDROIDPKCS11DBConfigsafeModeDBConfig=safeMode?PKCS11DBConfig::DoNotLoadModules:PKCS11DBConfig::LoadModules;SECStatussrv=::mozilla::psm::InitializeNSS(profilePath,NSSDBConfig::ReadWrite,safeModeDBConfig);if(srv==SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("initialized NSS in r/w mode"));returnNS_OK;}#ifndef ANDROIDsavedPRErrorCode1=PR_GetError();PRErrorCodesavedPRErrorCode2;#endif // ifndef ANDROID// That failed. Try read-only mode.srv=::mozilla::psm::InitializeNSS(profilePath,NSSDBConfig::ReadOnly,safeModeDBConfig);if(srv==SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("initialized NSS in r-o mode"));returnNS_OK;}#ifndef ANDROIDsavedPRErrorCode2=PR_GetError();MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to initialize NSS with codes %d %d",savedPRErrorCode1,savedPRErrorCode2));#endif // ifndef ANDROID#ifndef ANDROID// That failed as well. Maybe we're trying to load a PKCS#11 module DB that is// in FIPS mode, but we don't support FIPS? Test load NSS without PKCS#11// modules. If that succeeds, that's probably what's going on.if(!safeMode&&(savedPRErrorCode1==SEC_ERROR_LEGACY_DATABASE||savedPRErrorCode2==SEC_ERROR_LEGACY_DATABASE||savedPRErrorCode1==SEC_ERROR_PKCS11_DEVICE_ERROR||savedPRErrorCode2==SEC_ERROR_PKCS11_DEVICE_ERROR)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("attempting no-module db init"));// It would make sense to initialize NSS in read-only mode here since this// is just a test to see if the PKCS#11 module DB being in FIPS mode is the// problem, but for some reason the combination of read-only and no-moddb// flags causes NSS initialization to fail, so unfortunately we have to use// read-write mode.srv=::mozilla::psm::InitializeNSS(profilePath,NSSDBConfig::ReadWrite,PKCS11DBConfig::DoNotLoadModules);if(srv==SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("FIPS may be the problem"));// Unload NSS so we can attempt to fix this situation for the user.srv=NSS_Shutdown();if(srv!=SECSuccess){# ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLEDMOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",PR_GetError());# endifreturnNS_ERROR_FAILURE;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("trying to rename module db"));// If this fails non-catastrophically, we'll attempt to initialize NSS// again in r/w then r-o mode (both of which will fail), and then we'll// fall back to NSS_NoDB_Init, which is the behavior we want.nsresultrv=AttemptToRenamePKCS11ModuleDB(profilePath);if(NS_FAILED(rv)){# ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED// An nsresult is a uint32_t, but at least one of our compilers doesn't// like this format string unless we include the cast. <shruggie emoji>MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %u",(uint32_t)rv);# endifreturnrv;}srv=::mozilla::psm::InitializeNSS(profilePath,NSSDBConfig::ReadWrite,PKCS11DBConfig::LoadModules);if(srv==SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("initialized in r/w mode"));returnNS_OK;}srv=::mozilla::psm::InitializeNSS(profilePath,NSSDBConfig::ReadOnly,PKCS11DBConfig::LoadModules);if(srv==SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("initialized in r-o mode"));returnNS_OK;}}}#endifMOZ_LOG(gPIPNSSLog,LogLevel::Debug,("last-resort NSS_NoDB_Init"));srv=NSS_NoDB_Init(nullptr);#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLEDif(srv!=SECSuccess){MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",PR_GetError());}#endifreturnsrv==SECSuccess?NS_OK:NS_ERROR_FAILURE;}nsresultnsNSSComponent::InitializeNSS(){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::InitializeNSS\n"));AUTO_PROFILER_LABEL("nsNSSComponent::InitializeNSS",OTHER);AUTO_PROFILER_TRACING_MARKER("NSS","nsNSSComponent::InitializeNSS",OTHER);static_assert(nsINSSErrorsService::NSS_SEC_ERROR_BASE==SEC_ERROR_BASE&&nsINSSErrorsService::NSS_SEC_ERROR_LIMIT==SEC_ERROR_LIMIT&&nsINSSErrorsService::NSS_SSL_ERROR_BASE==SSL_ERROR_BASE&&nsINSSErrorsService::NSS_SSL_ERROR_LIMIT==SSL_ERROR_LIMIT,"You must update the values in nsINSSErrorsService.idl");MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("NSS Initialization beginning\n"));nsAutoCStringprofileStr;nsresultrv=GetNSSProfilePath(profileStr);MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));if(NS_FAILED(rv)){returnNS_ERROR_NOT_AVAILABLE;}#if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))SetNSSDatabaseCacheModeAsAppropriate();#endifboolnocertdb=Preferences::GetBool("security.nocertdb",false);boolinSafeMode=true;nsCOMPtr<nsIXULRuntime>runtime(do_GetService("@mozilla.org/xre/runtime;1"));// There might not be an nsIXULRuntime in embedded situations. This will// default to assuming we are in safe mode (as a result, no external PKCS11// modules will be loaded).if(runtime){rv=runtime->GetInSafeMode(&inSafeMode);MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));if(NS_FAILED(rv)){returnrv;}}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("inSafeMode: %u\n",inSafeMode));rv=InitializeNSSWithFallbacks(profileStr,nocertdb,inSafeMode);MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to initialize NSS"));returnrv;}PK11_SetPasswordFunc(PK11PasswordPrompt);// Register an observer so we can inform NSS when these prefs changePreferences::AddStrongObserver(this,"security.");rv=CommonInit();MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));if(NS_FAILED(rv)){returnNS_ERROR_UNEXPECTED;}nsCOMPtr<nsICertOverrideService>certOverrideService(do_GetService(NS_CERTOVERRIDE_CONTRACTID));nsCOMPtr<nsIClientAuthRememberService>clientAuthRememberService(do_GetService(NS_CLIENTAUTHREMEMBERSERVICE_CONTRACTID));nsCOMPtr<nsISiteSecurityService>siteSecurityService(do_GetService(NS_SSSERVICE_CONTRACTID));nsCOMPtr<nsICertStorage>certStorage(do_GetService(NS_CERT_STORAGE_CID));MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("NSS Initialization done\n"));{MutexAutoLocklock(mMutex);// ensure we have initial values for various root hashes#ifdef DEBUGmTestBuiltInRootHash.Truncate();Preferences::GetString("security.test.built_in_root_hash",mTestBuiltInRootHash);#endifmContentSigningRootHash.Truncate();Preferences::GetCString("security.content.signature.root_hash",mContentSigningRootHash);mMitmCanaryIssuer.Truncate();Preferences::GetString("security.pki.mitm_canary_issuer",mMitmCanaryIssuer);mMitmDetecionEnabled=Preferences::GetBool("security.pki.mitm_canary_issuer.enabled",true);// Set dynamic options from prefs.setValidationOptions(true,lock);boolimportEnterpriseRoots=Preferences::GetBool(kEnterpriseRootModePref,false);uint32_tfamilySafetyMode=Preferences::GetUint(kFamilySafetyModePref,kFamilySafetyModeDefault);Vector<nsCString>possibleLoadableRootsLocations;rv=ListPossibleLoadableRootsLocations(possibleLoadableRootsLocations);MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));if(NS_FAILED(rv)){returnrv;}boolloadOSClientCertsModule=Preferences::GetBool(kOSClientCertsModulePref,false);Maybe<nsCString>maybeOSClientCertsModuleLocation;if(loadOSClientCertsModule){nsAutoCStringlibraryDir;if(NS_SUCCEEDED(GetDirectoryPath(NS_GRE_BIN_DIR,libraryDir))){maybeOSClientCertsModuleLocation.emplace(libraryDir);}}RefPtr<LoadLoadableCertsTask>loadLoadableCertsTask(newLoadLoadableCertsTask(this,importEnterpriseRoots,familySafetyMode,std::move(possibleLoadableRootsLocations),std::move(maybeOSClientCertsModuleLocation)));rv=loadLoadableCertsTask->Dispatch();MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));if(NS_FAILED(rv)){returnrv;}mLoadLoadableCertsTaskDispatched=true;returnNS_OK;}}voidnsNSSComponent::ShutdownNSS(){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::ShutdownNSS\n"));MOZ_RELEASE_ASSERT(NS_IsMainThread());boolloadLoadableCertsTaskDispatched;{MutexAutoLocklock(mMutex);loadLoadableCertsTaskDispatched=mLoadLoadableCertsTaskDispatched;}// We have to block until the load loadable certs task has completed, because// otherwise we might try to unload the loaded modules while the loadable// certs loading thread is setting up EV information, which can cause// it to fail to find the roots it is expecting. However, if initialization// failed, we won't have dispatched the load loadable certs background task.// In that case, we don't want to block on an event that will never happen.if(loadLoadableCertsTaskDispatched){Unused<<BlockUntilLoadableCertsLoaded();}::mozilla::psm::UnloadUserModules();PK11_SetPasswordFunc((PK11PasswordFunc)nullptr);Preferences::RemoveObserver(this,"security.");if(mIntermediatePreloadingHealerTimer){mIntermediatePreloadingHealerTimer->Cancel();mIntermediatePreloadingHealerTimer=nullptr;}// Release the default CertVerifier. This will cause any held NSS resources// to be released.MutexAutoLocklock(mMutex);mDefaultCertVerifier=nullptr;// We don't actually shut down NSS - XPCOM does, after all threads have been// joined and the component manager has been shut down (and so there shouldn't// be any XPCOM objects holding NSS resources).}// The aim of the intermediate preloading healer is to remove intermediates// that were previously cached by PSM in the NSS certdb that are now preloaded// in cert_storage. When cached by PSM, these certificates will have no// particular trust set - they are intended to inherit their trust. If, upon// examination, these certificates do have trust bits set that affect// certificate validation, they must have been modified by the user, so we want// to leave them alone.boolCertHasDefaultTrust(CERTCertificate*cert){CERTCertTrusttrust;if(CERT_GetCertTrust(cert,&trust)!=SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("CERT_GetCertTrust failed"));returnfalse;}// This is the active distrust test for CA certificates (this is expected to// be an intermediate).if((trust.sslFlags&(CERTDB_TRUSTED_CA|CERTDB_TERMINAL_RECORD))==CERTDB_TERMINAL_RECORD){returnfalse;}// This is the trust anchor test.if(trust.sslFlags&CERTDB_TRUSTED_CA){returnfalse;}// This is the active distrust test for CA certificates (this is expected to// be an intermediate).if((trust.emailFlags&(CERTDB_TRUSTED_CA|CERTDB_TERMINAL_RECORD))==CERTDB_TERMINAL_RECORD){returnfalse;}// This is the trust anchor test.if(trust.emailFlags&CERTDB_TRUSTED_CA){returnfalse;}returntrue;}voidIntermediatePreloadingHealerCallback(nsITimer*,void*){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("IntermediatePreloadingHealerCallback"));if(AppShutdown::IsShuttingDown()){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Exiting healer due to app shutdown"));return;}// Get the slot corresponding to the NSS certdb.UniquePK11SlotInfosoftokenSlot(PK11_GetInternalKeySlot());if(!softokenSlot){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("PK11_GetInternalKeySlot failed"));return;}// List the certificates in the NSS certdb.UniqueCERTCertListsoftokenCertificates(PK11_ListCertsInSlot(softokenSlot.get()));if(!softokenCertificates){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("PK11_ListCertsInSlot failed"));return;}nsCOMPtr<nsICertStorage>certStorage(do_GetService(NS_CERT_STORAGE_CID));if(!certStorage){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("couldn't get cert_storage"));return;}Vector<UniqueCERTCertificate>certsToDelete;// For each certificate, look it up in cert_storage. If there's a match, this// is a preloaded intermediate.for(CERTCertListNode*n=CERT_LIST_HEAD(softokenCertificates);!CERT_LIST_END(n,softokenCertificates);n=CERT_LIST_NEXT(n)){if(AppShutdown::IsShuttingDown()){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Exiting healer due to app shutdown"));return;}nsTArray<uint8_t>subject;subject.AppendElements(n->cert->derSubject.data,n->cert->derSubject.len);nsTArray<nsTArray<uint8_t>>certs;nsresultrv=certStorage->FindCertsBySubject(subject,certs);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("FindCertsBySubject failed"));break;}for(constauto&encodedCert:certs){if(encodedCert.Length()!=n->cert->derCert.len){continue;}if(memcmp(encodedCert.Elements(),n->cert->derCert.data,encodedCert.Length())!=0){continue;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("found preloaded intermediate in certdb"));if(!CertHasDefaultTrust(n->cert)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("certificate doesn't have default trust - skipping"));continue;}UniqueCERTCertificatecertCopy(CERT_DupCertificate(n->cert));if(!certCopy){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("CERT_DupCertificate failed"));continue;}// Note that we want to remove this certificate from the NSS certdb// because it also exists in preloaded intermediate storage and is thus// superfluous.if(!certsToDelete.append(std::move(certCopy))){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("append failed - out of memory?"));return;}break;}// Only delete 20 at a time.if(certsToDelete.length()>=20){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("found limit of 20 preloaded intermediates in certdb"));break;}}for(constauto&certToDelete:certsToDelete){if(AppShutdown::IsShuttingDown()){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Exiting healer due to app shutdown"));return;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("attempting to delete preloaded intermediate '%s'",certToDelete->subjectName));if(SEC_DeletePermCertificate(certToDelete.get())!=SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("SEC_DeletePermCertificate failed"));}}// This is for tests - notify that this ran.nsCOMPtr<nsIRunnable>runnable(NS_NewRunnableFunction("IntermediatePreloadingHealerCallbackDone",[]()->void{nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();if(observerService){observerService->NotifyObservers(nullptr,"psm:intermediate-preloading-healer-ran",nullptr);}}));Unused<<NS_DispatchToMainThread(runnable.forget());}nsresultnsNSSComponent::Init(){MOZ_RELEASE_ASSERT(NS_IsMainThread());if(!NS_IsMainThread()){returnNS_ERROR_NOT_SAME_THREAD;}MOZ_ASSERT(XRE_IsParentProcess());if(!XRE_IsParentProcess()){returnNS_ERROR_NOT_AVAILABLE;}Telemetry::AutoScalarTimer<Telemetry::ScalarID::NETWORKING_NSS_INITIALIZATION>timer;MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("Beginning NSS initialization\n"));nsresultrv=InitializeNSS();if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("nsNSSComponent::InitializeNSS() failed\n"));returnrv;}rv=RegisterObservers();if(NS_FAILED(rv)){returnrv;}rv=MaybeEnableIntermediatePreloadingHealer();if(NS_FAILED(rv)){returnrv;}returnNS_OK;}nsresultnsNSSComponent::MaybeEnableIntermediatePreloadingHealer(){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::MaybeEnableIntermediatePreloadingHealer"));MOZ_ASSERT(NS_IsMainThread());if(!NS_IsMainThread()){returnNS_ERROR_NOT_SAME_THREAD;}if(mIntermediatePreloadingHealerTimer){mIntermediatePreloadingHealerTimer->Cancel();mIntermediatePreloadingHealerTimer=nullptr;}if(!Preferences::GetBool("security.intermediate_preloading_healer.enabled",false)){returnNS_OK;}if(!mIntermediatePreloadingHealerTaskQueue){nsresultrv=NS_CreateBackgroundTaskQueue("IntermediatePreloadingHealer",getter_AddRefs(mIntermediatePreloadingHealerTaskQueue));if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("NS_CreateBackgroundTaskQueue failed"));returnrv;}}uint32_ttimerDelayMS=Preferences::GetUint("security.intermediate_preloading_healer.timer_interval_ms",5*60*1000);nsresultrv=NS_NewTimerWithFuncCallback(getter_AddRefs(mIntermediatePreloadingHealerTimer),IntermediatePreloadingHealerCallback,nullptr,timerDelayMS,nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,"IntermediatePreloadingHealer",mIntermediatePreloadingHealerTaskQueue);if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("NS_NewTimerWithFuncCallback failed"));returnrv;}returnNS_OK;}// nsISupports Implementation for the classNS_IMPL_ISUPPORTS(nsNSSComponent,nsINSSComponent,nsIObserver)staticconstchar*constPROFILE_BEFORE_CHANGE_TOPIC="profile-before-change";NS_IMETHODIMPnsNSSComponent::Observe(nsISupports*aSubject,constchar*aTopic,constchar16_t*someData){// In some tests, we don't receive a "profile-before-change" topic. However,// we still have to shut down before the storage service shuts down, because// closing the sql-backed softoken requires sqlite still be available. Thus,// we observe "xpcom-shutdown" just in case.if(nsCRT::strcmp(aTopic,PROFILE_BEFORE_CHANGE_TOPIC)==0||nsCRT::strcmp(aTopic,NS_XPCOM_SHUTDOWN_OBSERVER_ID)==0){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("receiving profile change or XPCOM shutdown notification"));ShutdownNSS();}elseif(nsCRT::strcmp(aTopic,NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)==0){boolclearSessionCache=true;NS_ConvertUTF16toUTF8prefName(someData);if(HandleTLSPrefChange(prefName)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("HandleTLSPrefChange done"));}elseif(prefName.EqualsLiteral("security.OCSP.enabled")||prefName.EqualsLiteral("security.OCSP.require")||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.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.pki.crlite_mode")||prefName.EqualsLiteral("security.pki.crlite_ct_merge_delay_seconds")){MutexAutoLocklock(mMutex);setValidationOptions(false,lock);#ifdef DEBUG}elseif(prefName.EqualsLiteral("security.test.built_in_root_hash")){MutexAutoLocklock(mMutex);mTestBuiltInRootHash.Truncate();Preferences::GetString("security.test.built_in_root_hash",mTestBuiltInRootHash);#endif // DEBUG}elseif(prefName.EqualsLiteral("security.content.signature.root_hash")){MutexAutoLocklock(mMutex);mContentSigningRootHash.Truncate();Preferences::GetCString("security.content.signature.root_hash",mContentSigningRootHash);}elseif(prefName.Equals(kEnterpriseRootModePref)||prefName.Equals(kFamilySafetyModePref)){UnloadEnterpriseRoots();MaybeImportEnterpriseRoots();}elseif(prefName.Equals(kOSClientCertsModulePref)){boolloadOSClientCertsModule=Preferences::GetBool(kOSClientCertsModulePref,false);AsyncLoadOrUnloadOSClientCertsModule(loadOSClientCertsModule);}elseif(prefName.EqualsLiteral("security.pki.mitm_canary_issuer")){MutexAutoLocklock(mMutex);mMitmCanaryIssuer.Truncate();Preferences::GetString("security.pki.mitm_canary_issuer",mMitmCanaryIssuer);}elseif(prefName.EqualsLiteral("security.pki.mitm_canary_issuer.enabled")){MutexAutoLocklock(mMutex);mMitmDetecionEnabled=Preferences::GetBool("security.pki.mitm_canary_issuer.enabled",true);}else{clearSessionCache=false;}if(clearSessionCache){ClearSSLExternalAndInternalSessionCache();}// Preferences that don't affect certificate verification.if(prefName.Equals("security.intermediate_preloading_healer.enabled")||prefName.Equals("security.intermediate_preloading_healer.timer_interval_ms")){MaybeEnableIntermediatePreloadingHealer();}}returnNS_OK;}/*static*/nsresultnsNSSComponent::GetNewPrompter(nsIPrompt**result){NS_ENSURE_ARG_POINTER(result);*result=nullptr;if(!NS_IsMainThread()){NS_ERROR("nsSDRContext::GetNewPrompter called off the main thread");returnNS_ERROR_NOT_SAME_THREAD;}nsresultrv;nsCOMPtr<nsIWindowWatcher>wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID,&rv));NS_ENSURE_SUCCESS(rv,rv);rv=wwatch->GetNewPrompter(0,result);NS_ENSURE_SUCCESS(rv,rv);returnrv;}nsresultnsNSSComponent::LogoutAuthenticatedPK11(){nsCOMPtr<nsICertOverrideService>icos=do_GetService("@mozilla.org/security/certoverride;1");if(icos){icos->ClearValidityOverride("all:temporary-certificates"_ns,0);}ClearSSLExternalAndInternalSessionCache();nsCOMPtr<nsIObserverService>os=mozilla::services::GetObserverService();if(os){os->NotifyObservers(nullptr,"net:cancel-all-connections",nullptr);}returnNS_OK;}nsresultnsNSSComponent::RegisterObservers(){nsCOMPtr<nsIObserverService>observerService(do_GetService("@mozilla.org/observer-service;1"));if(!observerService){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent: couldn't get observer service\n"));returnNS_ERROR_FAILURE;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent: adding observers\n"));// Using false for the ownsweak parameter means the observer service will// keep a strong reference to this component. As a result, this will live at// least as long as the observer service.observerService->AddObserver(this,PROFILE_BEFORE_CHANGE_TOPIC,false);observerService->AddObserver(this,NS_XPCOM_SHUTDOWN_OBSERVER_ID,false);returnNS_OK;}NS_IMETHODIMPnsNSSComponent::IsCertTestBuiltInRoot(CERTCertificate*cert,bool*result){NS_ENSURE_ARG_POINTER(cert);NS_ENSURE_ARG_POINTER(result);*result=false;#ifdef DEBUGRefPtr<nsNSSCertificate>nsc=nsNSSCertificate::Create(cert);if(!nsc){returnNS_ERROR_FAILURE;}nsAutoStringcertHash;nsresultrv=nsc->GetSha256Fingerprint(certHash);if(NS_FAILED(rv)){returnrv;}MutexAutoLocklock(mMutex);if(mTestBuiltInRootHash.IsEmpty()){returnNS_OK;}*result=mTestBuiltInRootHash.Equals(certHash);#endif // DEBUGreturnNS_OK;}NS_IMETHODIMPnsNSSComponent::IsCertContentSigningRoot(constnsTArray<uint8_t>&cert,bool*result){NS_ENSURE_ARG_POINTER(result);*result=false;if(cert.Length()>std::numeric_limits<uint32_t>::max()){returnNS_ERROR_INVALID_ARG;}nsTArray<uint8_t>digestArray;nsresultrv=Digest::DigestBuf(SEC_OID_SHA256,cert.Elements(),cert.Length(),digestArray);if(NS_FAILED(rv)){returnrv;}SECItemdigestItem={siBuffer,digestArray.Elements(),static_cast<unsignedint>(digestArray.Length())};UniquePORTStringfingerprintCString(CERT_Hexify(&digestItem,true/* use colon delimiters */));if(!fingerprintCString){returnNS_ERROR_FAILURE;}MutexAutoLocklock(mMutex);*result=mContentSigningRootHash.Equals(fingerprintCString.get());returnNS_OK;}NS_IMETHODIMPnsNSSComponent::IssuerMatchesMitmCanary(constchar*aCertIssuer){MutexAutoLocklock(mMutex);if(mMitmDetecionEnabled&&!mMitmCanaryIssuer.IsEmpty()){nsStringcertIssuer=NS_ConvertUTF8toUTF16(aCertIssuer);if(mMitmCanaryIssuer.Equals(certIssuer)){returnNS_OK;}}returnNS_ERROR_FAILURE;}SharedCertVerifier::~SharedCertVerifier()=default;NS_IMETHODIMPnsNSSComponent::GetDefaultCertVerifier(SharedCertVerifier**result){MutexAutoLocklock(mMutex);NS_ENSURE_ARG_POINTER(result);RefPtr<SharedCertVerifier>certVerifier(mDefaultCertVerifier);certVerifier.forget(result);returnNS_OK;}// staticvoidnsNSSComponent::DoClearSSLExternalAndInternalSessionCache(){SSL_ClearSessionCache();mozilla::net::SSLTokensCache::Clear();}NS_IMETHODIMPnsNSSComponent::ClearSSLExternalAndInternalSessionCache(){MOZ_ASSERT(XRE_IsParentProcess());if(!XRE_IsParentProcess()){returnNS_ERROR_NOT_AVAILABLE;}if(mozilla::net::nsIOService::UseSocketProcess()){if(mozilla::net::gIOService){mozilla::net::gIOService->CallOrWaitForSocketProcess([](){Unused<<mozilla::net::SocketProcessParent::GetSingleton()->SendClearSessionCache();});}}DoClearSSLExternalAndInternalSessionCache();returnNS_OK;}namespacemozilla{namespacepsm{already_AddRefed<SharedCertVerifier>GetDefaultCertVerifier(){staticNS_DEFINE_CID(kNSSComponentCID,NS_NSSCOMPONENT_CID);nsCOMPtr<nsINSSComponent>nssComponent(do_GetService(kNSSComponentCID));if(!nssComponent){returnnullptr;}nsresultrv=nssComponent->BlockUntilLoadableCertsLoaded();if(NS_FAILED(rv)){returnnullptr;}RefPtr<SharedCertVerifier>result;rv=nssComponent->GetDefaultCertVerifier(getter_AddRefs(result));if(NS_FAILED(rv)){returnnullptr;}returnresult.forget();}// Lists all private keys on all modules and returns a list of any corresponding// client certificates. Returns null if no such certificates can be found. Also// returns null if an error is encountered, because this is called as part of// the client auth data callback, and NSS ignores any errors returned by the// callback.UniqueCERTCertListFindClientCertificatesWithPrivateKeys(){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("FindClientCertificatesWithPrivateKeys"));UniqueCERTCertListcertsWithPrivateKeys(CERT_NewCertList());if(!certsWithPrivateKeys){returnnullptr;}AutoSECMODListReadLocksecmodLock;SECMODModuleList*list=SECMOD_GetDefaultModuleList();while(list){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" module '%s'",list->module->commonName));for(inti=0;i<list->module->slotCount;i++){PK11SlotInfo*slot=list->module->slots[i];MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" slot '%s'",PK11_GetSlotName(slot)));if(!PK11_IsPresent(slot)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (not present)"));continue;}// We may need to log in to be able to find private keys.if(PK11_Authenticate(slot,true,nullptr)!=SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (couldn't authenticate)"));continue;}UniqueSECKEYPrivateKeyListprivateKeys(PK11_ListPrivKeysInSlot(slot,nullptr,nullptr));if(!privateKeys){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (no private keys)"));continue;}for(SECKEYPrivateKeyListNode*node=PRIVKEY_LIST_HEAD(privateKeys);!PRIVKEY_LIST_END(node,privateKeys);node=PRIVKEY_LIST_NEXT(node)){UniqueCERTCertListcerts(PK11_GetCertsMatchingPrivateKey(node->key));if(!certs){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" PK11_GetCertsMatchingPrivateKey encountered an error ""- returning"));returnnullptr;}if(CERT_LIST_EMPTY(certs)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (no certs for key)"));continue;}for(CERTCertListNode*n=CERT_LIST_HEAD(certs);!CERT_LIST_END(n,certs);n=CERT_LIST_NEXT(n)){UniqueCERTCertificatecert(CERT_DupCertificate(n->cert));MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" provisionally adding '%s'",n->cert->subjectName));if(CERT_AddCertToListTail(certsWithPrivateKeys.get(),cert.get())==SECSuccess){Unused<<cert.release();}}}}list=list->next;}if(CERT_FilterCertListByUsage(certsWithPrivateKeys.get(),certUsageSSLClient,false)!=SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" CERT_FilterCertListByUsage encountered an error - returning"));returnnullptr;}if(MOZ_UNLIKELY(MOZ_LOG_TEST(gPIPNSSLog,LogLevel::Debug))){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" returning:"));for(CERTCertListNode*n=CERT_LIST_HEAD(certsWithPrivateKeys);!CERT_LIST_END(n,certsWithPrivateKeys);n=CERT_LIST_NEXT(n)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" %s",n->cert->subjectName));}}if(CERT_LIST_EMPTY(certsWithPrivateKeys)){returnnullptr;}returncertsWithPrivateKeys;}}// namespace psm}// namespace mozillaNS_IMPL_ISUPPORTS(PipUIContext,nsIInterfaceRequestor)PipUIContext::PipUIContext()=default;PipUIContext::~PipUIContext()=default;NS_IMETHODIMPPipUIContext::GetInterface(constnsIID&uuid,void**result){NS_ENSURE_ARG_POINTER(result);*result=nullptr;if(!NS_IsMainThread()){NS_ERROR("PipUIContext::GetInterface called off the main thread");returnNS_ERROR_NOT_SAME_THREAD;}if(!uuid.Equals(NS_GET_IID(nsIPrompt)))returnNS_ERROR_NO_INTERFACE;nsIPrompt*prompt=nullptr;nsresultrv=nsNSSComponent::GetNewPrompter(&prompt);*result=prompt;returnrv;}nsresultgetNSSDialogs(void**_result,REFNSIIDaIID,constchar*contract){if(!NS_IsMainThread()){NS_ERROR("getNSSDialogs called off the main thread");returnNS_ERROR_NOT_SAME_THREAD;}nsresultrv;nsCOMPtr<nsISupports>svc=do_GetService(contract,&rv);if(NS_FAILED(rv)){returnrv;}rv=svc->QueryInterface(aIID,_result);returnrv;}nsresultsetPassword(PK11SlotInfo*slot,nsIInterfaceRequestor*ctx){MOZ_ASSERT(slot);MOZ_ASSERT(ctx);NS_ENSURE_ARG_POINTER(slot);NS_ENSURE_ARG_POINTER(ctx);if(PK11_NeedUserInit(slot)){nsCOMPtr<nsITokenPasswordDialogs>dialogs;nsresultrv=getNSSDialogs(getter_AddRefs(dialogs),NS_GET_IID(nsITokenPasswordDialogs),NS_TOKENPASSWORDSDIALOG_CONTRACTID);if(NS_FAILED(rv)){returnrv;}boolcanceled;nsCOMPtr<nsIPK11Token>token=newnsPK11Token(slot);rv=dialogs->SetPassword(ctx,token,&canceled);if(NS_FAILED(rv)){returnrv;}if(canceled){returnNS_ERROR_NOT_AVAILABLE;}}returnNS_OK;}// NSS will call this during PKCS12 export to potentially switch the endianness// of the characters of `inBuf` to big (network) endian. Since we already did// that in nsPKCS12Blob::stringToBigEndianBytes, we just perform a memcpy here.extern"C"{PRBoolpkcs12StringEndiannessConversion(PRBool,unsignedchar*inBuf,unsignedintinBufLen,unsignedchar*outBuf,unsignedint,unsignedint*outBufLen,PRBool){*outBufLen=inBufLen;memcpy(outBuf,inBuf,inBufLen);returntrue;}}namespacemozilla{namespacepsm{nsresultInitializeCipherSuite(){MOZ_ASSERT(NS_IsMainThread(),"InitializeCipherSuite() can only be accessed on the main thread");if(NSS_SetDomesticPolicy()!=SECSuccess){returnNS_ERROR_FAILURE;}// Disable any ciphers that NSS might have enabled by defaultfor(uint16_ti=0;i<SSL_NumImplementedCiphers;++i){uint16_tcipher_id=SSL_ImplementedCiphers[i];SSL_CipherPrefSetDefault(cipher_id,false);}// Now only set SSL/TLS ciphers we knew about at compile timeconstCipherPref*constcp=sCipherPrefs;for(size_ti=0;cp[i].pref;++i){boolcipherEnabled=Preferences::GetBool(cp[i].pref,cp[i].enabledByDefault);SSL_CipherPrefSetDefault(cp[i].id,cipherEnabled);}// Enable ciphers for PKCS#12SEC_PKCS12EnableCipher(PKCS12_RC4_40,1);SEC_PKCS12EnableCipher(PKCS12_RC4_128,1);SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40,1);SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128,1);SEC_PKCS12EnableCipher(PKCS12_DES_56,1);SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168,1);SEC_PKCS12EnableCipher(PKCS12_AES_CBC_128,1);SEC_PKCS12EnableCipher(PKCS12_AES_CBC_192,1);SEC_PKCS12EnableCipher(PKCS12_AES_CBC_256,1);SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168,1);PORT_SetUCS2_ASCIIConversionFunction(pkcs12StringEndiannessConversion);// PSM enforces a minimum RSA key size of 1024 bits, which is overridable.// NSS has its own minimum, which is not overridable (the default is 1023// bits). This sets the NSS minimum to 512 bits so users can still connect to// devices like wifi routers with woefully small keys (they would have to add// an override to do so, but they already do for such devices).NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE,512);// Observe preference change around cipher suite setting.returnCipherSuiteChangeObserver::StartObserve();}}// namespace psm}// namespace mozilla