Revert "Bug 1960743 - Add line breaks and indentation in Fonts panel @font-face description. r=devtools-reviewers,nchevobbe" for cauisng failures at browser_appmenu.js.
This reverts commit cf3e48657a14a73ef6e5364f424b6f25b723b6f3.
/* -*- 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"BinaryPath.h"#include"CryptoTask.h"#include"EnterpriseRoots.h"#include"ExtendedValidation.h"#include"NSSCertDBTrustDomain.h"#include"PKCS11ModuleDB.h"#include"SSLTokensCache.h"#include"ScopedNSSTypes.h"#include"cert.h"#include"cert_storage/src/cert_storage.h"#include"certdb.h"#include"mozilla/AppShutdown.h"#include"mozilla/Atomics.h"#include"mozilla/ArrayUtils.h"#include"mozilla/Assertions.h"#include"mozilla/Base64.h"#include"mozilla/Casting.h"#include"mozilla/EndianUtils.h"#include"mozilla/FilePreferences.h"#include"mozilla/PodOperations.h"#include"mozilla/Preferences.h"#include"mozilla/ProfilerLabels.h"#include"mozilla/ProfilerMarkers.h"#include"mozilla/PublicSSL.h"#include"mozilla/ScopeExit.h"#include"mozilla/Services.h"#include"mozilla/StaticMutex.h"#include"mozilla/StaticPrefs_security.h"#include"mozilla/StaticPtr.h"#include"mozilla/SyncRunnable.h"#include"mozilla/TimeStamp.h"#include"mozilla/Unused.h"#include"mozilla/Vector.h"#include"mozilla/dom/Promise.h"#include"mozilla/glean/SecurityManagerSslMetrics.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"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"nsNSSHelper.h"#include"nsNSSIOLayer.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>#endifusingnamespacemozilla;usingnamespacemozilla::psm;LazyLogModulegPIPNSSLog("pipnss");intnsNSSComponent::mInstanceCount=0;// Forward declaration.nsresultCommonInit();template<constglean::impl::QuantityMetric*metric>classMOZ_RAIIAutoGleanTimer{public:explicitAutoGleanTimer(TimeStampaStart=TimeStamp::Now()):mStart(aStart){}~AutoGleanTimer(){TimeStampend=TimeStamp::Now();uint32_tdelta=static_cast<uint32_t>((end-mStart).ToMilliseconds());metric->Set(delta);}private:constTimeStampmStart;};// Take an nsIFile and get a UTF-8-encoded c-string representation of the// location of that file (encapsulated in an nsACString).// This operation is generally to be avoided, except when interacting with// third-party or legacy libraries that cannot handle `nsIFile`s (such as NSS).// |result| is encoded in UTF-8.nsresultFileToCString(constnsCOMPtr<nsIFile>&file,nsACString&result){#ifdef XP_WINnsAutoStringpath;nsresultrv=file->GetPath(path);if(NS_SUCCEEDED(rv)){CopyUTF16toUTF8(path,result);}returnrv;#elsereturnfile->GetNativePath(result);#endif}voidTruncateFromLastDirectorySeparator(nsCString&path){staticconstnsAutoCStringkSeparatorString(mozilla::FilePreferences::kPathSeparator);int32_tindex=path.RFind(kSeparatorString);if(index==kNotFound){return;}path.Truncate(index);}boolLoadIPCClientCerts(){if(!LoadIPCClientCertsModule()){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("failed to load ipcclientcerts"));returnfalse;}returntrue;}// 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,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;}// If ipcclientcerts fails to load, client certificate authentication won't// work (if networking is done on the socket process). This is preferable// to stopping the program entirely, so treat this as best-effort.Unused<<NS_WARN_IF(!LoadIPCClientCerts());initialized=true;returntrue;}if(NS_FAILED(mozilla::psm::InitializeCipherSuite())){returnfalse;}mozilla::psm::DisableMD5();mozilla::pkix::RegisterErrorTable();initialized=true;returntrue;}staticconstuint32_tOCSP_TIMEOUT_MILLISECONDS_SOFT_MAX=5000;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){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 onlyuint32_tocspLevel=StaticPrefs::security_OCSP_enabled();switch(ocspLevel){case0:*odc=CertVerifier::ocspOff;break;case2:*odc=CertVerifier::ocspEVOnly;break;default:*odc=CertVerifier::ocspOn;break;}*osc=StaticPrefs::security_OCSP_require()?CertVerifier::ocspStrict:CertVerifier::ocspRelaxed;*certShortLifetimeInDays=StaticPrefs::security_pki_cert_short_lifetime_in_days();uint32_tsoftTimeoutMillis=StaticPrefs::security_OCSP_timeoutMilliseconds_soft();softTimeoutMillis=std::min(softTimeoutMillis,OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX);softTimeout=TimeDuration::FromMilliseconds(softTimeoutMillis);uint32_thardTimeoutMillis=StaticPrefs::security_OCSP_timeoutMilliseconds_hard();hardTimeoutMillis=std::min(hardTimeoutMillis,OCSP_TIMEOUT_MILLISECONDS_HARD_MAX);hardTimeout=TimeDuration::FromMilliseconds(hardTimeoutMillis);}nsNSSComponent::nsNSSComponent():mLoadableCertsLoadedMonitor("nsNSSComponent.mLoadableCertsLoadedMonitor"),mLoadableCertsLoaded(false),mLoadableCertsLoadedResult(NS_ERROR_FAILURE),mMutex("nsNSSComponent.mMutex"),mMitmDetecionEnabled(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_shutdownPrepareForShutdown();nsSSLIOLayerHelpers::GlobalCleanup();--mInstanceCount;MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::dtor finished\n"));}voidnsNSSComponent::UnloadEnterpriseRoots(){MOZ_ASSERT(NS_IsMainThread());if(!NS_IsMainThread()){return;}MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("UnloadEnterpriseRoots"));MutexAutoLocklock(mMutex);mEnterpriseCerts.Clear();setValidationOptions(lock);ClearSSLExternalAndInternalSessionCache();}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=StaticPrefs::security_enterprise_roots_enabled();if(importEnterpriseRoots){RefPtr<BackgroundImportEnterpriseCertsTask>task=newBackgroundImportEnterpriseCertsTask(this);Unused<<task->Dispatch();}}voidnsNSSComponent::ImportEnterpriseRoots(){MOZ_ASSERT(!NS_IsMainThread());if(NS_IsMainThread()){return;}nsTArray<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;}enterpriseCerts.Clear();MutexAutoLocknsNSSComponentLock(mMutex);for(constauto&cert:mEnterpriseCerts){nsTArray<uint8_t>certCopy;// mEnterpriseCerts includes both roots and intermediates.if(cert.GetIsRoot()==getRoots){cert.CopyBytes(certCopy);enterpriseCerts.AppendElement(std::move(certCopy));}}returnNS_OK;}NS_IMETHODIMPnsNSSComponent::GetEnterpriseRoots(nsTArray<nsTArray<uint8_t>>&enterpriseRoots){returnCommonGetEnterpriseCerts(enterpriseRoots,true);}nsresultBytesArrayToPEM(constnsTArray<nsTArray<uint8_t>>&bytesArray,nsACString&pemArray){for(constauto&bytes:bytesArray){nsAutoCStringbase64;nsresultrv=Base64Encode(reinterpret_cast<constchar*>(bytes.Elements()),bytes.Length(),base64);if(NS_FAILED(rv)){returnrv;}if(!pemArray.IsEmpty()){pemArray.AppendLiteral("\n");}pemArray.AppendLiteral("-----BEGIN CERTIFICATE-----\n");for(size_ti=0;i<base64.Length()/64;i++){pemArray.Append(Substring(base64,i*64,64));pemArray.AppendLiteral("\n");}if(base64.Length()%64!=0){size_tchunks=base64.Length()/64;pemArray.Append(Substring(base64,chunks*64));pemArray.AppendLiteral("\n");}pemArray.AppendLiteral("-----END CERTIFICATE-----");}returnNS_OK;}NS_IMETHODIMPnsNSSComponent::GetEnterpriseRootsPEM(nsACString&enterpriseRootsPEM){nsTArray<nsTArray<uint8_t>>enterpriseRoots;nsresultrv=GetEnterpriseRoots(enterpriseRoots);if(NS_FAILED(rv)){returnrv;}returnBytesArrayToPEM(enterpriseRoots,enterpriseRootsPEM);}NS_IMETHODIMPnsNSSComponent::GetEnterpriseIntermediates(nsTArray<nsTArray<uint8_t>>&enterpriseIntermediates){returnCommonGetEnterpriseCerts(enterpriseIntermediates,false);}NS_IMETHODIMPnsNSSComponent::GetEnterpriseIntermediatesPEM(nsACString&enterpriseIntermediatesPEM){nsTArray<nsTArray<uint8_t>>enterpriseIntermediates;nsresultrv=GetEnterpriseIntermediates(enterpriseIntermediates);if(NS_FAILED(rv)){returnrv;}returnBytesArrayToPEM(enterpriseIntermediates,enterpriseIntermediatesPEM);}NS_IMETHODIMPnsNSSComponent::AddEnterpriseIntermediate(constnsTArray<uint8_t>&intermediateBytes){nsresultrv=BlockUntilLoadableCertsLoaded();if(NS_FAILED(rv)){returnrv;}EnterpriseCertintermediate(intermediateBytes.Elements(),intermediateBytes.Length(),false);{MutexAutoLocknsNSSComponentLock(mMutex);mEnterpriseCerts.AppendElement(std::move(intermediate));}UpdateCertVerifierWithEnterpriseRoots();returnNS_OK;}classLoadLoadableCertsTaskfinal:publicRunnable{public:LoadLoadableCertsTask(nsNSSComponent*nssComponent,boolimportEnterpriseRoots,nsAutoCString&&greBinDir):Runnable("LoadLoadableCertsTask"),mNSSComponent(nssComponent),mImportEnterpriseRoots(importEnterpriseRoots),mGreBinDir(std::move(greBinDir)){MOZ_ASSERT(nssComponent);}~LoadLoadableCertsTask()=default;nsresultDispatch();private:NS_IMETHODRun()override;nsresultLoadLoadableRoots();RefPtr<nsNSSComponent>mNSSComponent;boolmImportEnterpriseRoots;nsAutoCStringmGreBinDir;};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(){AutoGleanTimer<&glean::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(mImportEnterpriseRoots){mNSSComponent->ImportEnterpriseRoots();mNSSComponent->UpdateCertVerifierWithEnterpriseRoots();}if(StaticPrefs::security_osclientcerts_autoload()){boolsuccess=LoadOSClientCertsModule();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;}classBackgroundLoadOSClientCertsModuleTaskfinal:publicCryptoTask{public:explicitBackgroundLoadOSClientCertsModuleTask(){}private:virtualnsresultCalculateResult()override{boolsuccess=LoadOSClientCertsModule();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);}}};voidAsyncLoadOrUnloadOSClientCertsModule(boolload){if(load){RefPtr<BackgroundLoadOSClientCertsModuleTask>task=newBackgroundLoadOSClientCertsModuleTask();Unused<<task->Dispatch();}else{UniqueSECMODModuleosClientCertsModule(SECMOD_FindModule(kOSClientCertsModuleName.get()));if(osClientCertsModule){SECMOD_UnloadUserModule(osClientCertsModule.get());}}}nsresultnsNSSComponent::BlockUntilLoadableCertsLoaded(){MonitorAutoLockrootsLoadedLock(mLoadableCertsLoadedMonitor);while(!mLoadableCertsLoaded){rootsLoadedLock.Wait();}MOZ_ASSERT(mLoadableCertsLoaded);returnmLoadableCertsLoadedResult;}#ifndef MOZ_NO_SMART_CARDSstaticStaticMutexsCheckForSmartCardChangesMutexMOZ_UNANNOTATED;MOZ_RUNINITstaticTimeStampsLastCheckedForSmartCardChanges=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 three steps.Vector<UniqueSECMODModule>modulesWithRemovableSlots;{AutoSECMODListReadLocksecmodLock;SECMODModuleList*list=SECMOD_GetDefaultModuleList();while(list){if(SECMOD_LockedModuleHasRemovableSlots(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());}AutoSECMODListReadLocksecmodLock;for(auto&module:modulesWithRemovableSlots){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;}#ifdef MOZ_SYSTEM_NSS// Returns by reference the path to the directory containing the file that has// been loaded as MOZ_DLL_PREFIX nss3 MOZ_DLL_SUFFIX.// |result| is encoded in UTF-8.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;nsresultrv=NS_NewNativeLocalFile(nsDependentCString(nss3Path.get()),getter_AddRefs(nss3File));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;}returnFileToCString(nss3Directory,result);}#endif // MOZ_SYSTEM_NSS// Returns by reference the path to the desired directory, based on the current// settings in the directory service.// |result| is encoded in UTF-8.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;}returnFileToCString(directory,result);}nsresultLoadLoadableCertsTask::LoadLoadableRoots(){// We first start checking if the MOZ_SYSTEM_NSS is used// If it's not - we check if there is nssckbi library in bin directory// If not found again - we finally load the library from XUL#ifdef MOZ_SYSTEM_NSS// First try checking the OS' default library search path.nsAutoCStringemptyString;if(mozilla::psm::LoadLoadableRoots(emptyString)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("loaded CKBI from from OS default library path"));returnNS_OK;}// Trying the library provided by NSSnsAutoCStringnss3Dir;nsresultrv=GetNSS3Directory(nss3Dir);if(NS_SUCCEEDED(rv)){if(mozilla::psm::LoadLoadableRoots(nss3Dir)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("loaded CKBI from %s",nss3Dir.get()));returnNS_OK;}}else{MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("could not determine where nss was loaded from"));}#endif // MOZ_SYSTEM_NSSif(mozilla::psm::LoadLoadableRoots(mGreBinDir)){mozilla::glean::pkcs11::external_trust_anchor_module_loaded.Set(true);MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("loaded external CKBI from gre directory"));returnNS_OK;}mozilla::glean::pkcs11::external_trust_anchor_module_loaded.Set(false);if(LoadLoadableRootsFromXul()){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("loaded CKBI from xul"));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;int32_tid;bool(*prefGetter)();}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,StaticPrefs::security_ssl3_ecdhe_rsa_aes_128_gcm_sha256},{"security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256",TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_128_gcm_sha256},{"security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256",TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,StaticPrefs::security_ssl3_ecdhe_ecdsa_chacha20_poly1305_sha256},{"security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256",TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,StaticPrefs::security_ssl3_ecdhe_rsa_chacha20_poly1305_sha256},{"security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384",TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_256_gcm_sha384},{"security.ssl3.ecdhe_rsa_aes_256_gcm_sha384",TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,StaticPrefs::security_ssl3_ecdhe_rsa_aes_256_gcm_sha384},{"security.ssl3.ecdhe_rsa_aes_128_sha",TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,StaticPrefs::security_ssl3_ecdhe_rsa_aes_128_sha},{"security.ssl3.ecdhe_ecdsa_aes_128_sha",TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_128_sha},{"security.ssl3.ecdhe_rsa_aes_256_sha",TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,StaticPrefs::security_ssl3_ecdhe_rsa_aes_256_sha},{"security.ssl3.ecdhe_ecdsa_aes_256_sha",TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_256_sha},{"security.ssl3.dhe_rsa_aes_128_sha",TLS_DHE_RSA_WITH_AES_128_CBC_SHA,StaticPrefs::security_ssl3_dhe_rsa_aes_128_sha},{"security.ssl3.dhe_rsa_aes_256_sha",TLS_DHE_RSA_WITH_AES_256_CBC_SHA,StaticPrefs::security_ssl3_dhe_rsa_aes_256_sha},{"security.tls13.aes_128_gcm_sha256",TLS_AES_128_GCM_SHA256,StaticPrefs::security_tls13_aes_128_gcm_sha256},{"security.tls13.chacha20_poly1305_sha256",TLS_CHACHA20_POLY1305_SHA256,StaticPrefs::security_tls13_chacha20_poly1305_sha256},{"security.tls13.aes_256_gcm_sha384",TLS_AES_256_GCM_SHA384,StaticPrefs::security_tls13_aes_256_gcm_sha384},{"security.ssl3.rsa_aes_128_gcm_sha256",TLS_RSA_WITH_AES_128_GCM_SHA256,StaticPrefs::security_ssl3_rsa_aes_128_gcm_sha256},{"security.ssl3.rsa_aes_256_gcm_sha384",TLS_RSA_WITH_AES_256_GCM_SHA384,StaticPrefs::security_ssl3_rsa_aes_256_gcm_sha384},{"security.ssl3.rsa_aes_128_sha",TLS_RSA_WITH_AES_128_CBC_SHA,StaticPrefs::security_ssl3_rsa_aes_128_sha},{"security.ssl3.rsa_aes_256_sha",TLS_RSA_WITH_AES_256_CBC_SHA,StaticPrefs::security_ssl3_rsa_aes_256_sha},};// These ciphersuites can only be enabled if deprecated versions of TLS are// also enabled (via the preference "security.tls.version.enable-deprecated").staticconstCipherPrefsDeprecatedTLS1CipherPrefs[]={{"security.ssl3.deprecated.rsa_des_ede3_sha",TLS_RSA_WITH_3DES_EDE_CBC_SHA,StaticPrefs::security_ssl3_deprecated_rsa_des_ede3_sha},};// 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;}staticvoidConfigureTLSSessionIdentifiers(){booldisableSessionIdentifiers=StaticPrefs::security_ssl_disable_session_identifiers();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();SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION,StaticPrefs::security_ssl_require_safe_negotiation());SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,SSL_RENEGOTIATE_REQUIRES_XTN);SSL_OptionSetDefault(SSL_ENABLE_EXTENDED_MASTER_SECRET,true);SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK,StaticPrefs::security_tls_hello_downgrade_check());SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,StaticPrefs::security_ssl_enable_false_start());// 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,StaticPrefs::security_ssl_enable_alpn());SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,StaticPrefs::security_tls_enable_0rtt_data());SSL_OptionSetDefault(SSL_ENABLE_POST_HANDSHAKE_AUTH,StaticPrefs::security_tls_enable_post_handshake_auth());SSL_OptionSetDefault(SSL_ENABLE_DELEGATED_CREDENTIALS,StaticPrefs::security_tls_enable_delegated_credentials());SSL_OptionSetDefault(SSL_DB_LOAD_CERTIFICATE_CHAIN,false);rv=InitializeCipherSuite();if(NS_FAILED(rv)){MOZ_LOG(gPIPNSSLog,LogLevel::Error,("Unable to initialize cipher suite settings\n"));returnrv;}DisableMD5();mozilla::pkix::RegisterErrorTable();nsSSLIOLayerHelpers::GlobalInit();returnNS_OK;}voidPrepareForShutdownInSocketProcess(){MOZ_ASSERT(XRE_IsSocketProcess());nsSSLIOLayerHelpers::GlobalCleanup();}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")){Unused<<nsNSSComponent::SetEnabledTLSVersions();}elseif(prefName.EqualsLiteral("security.tls.hello_downgrade_check")){SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK,StaticPrefs::security_tls_hello_downgrade_check());}elseif(prefName.EqualsLiteral("security.ssl.require_safe_negotiation")){SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION,StaticPrefs::security_ssl_require_safe_negotiation());}elseif(prefName.EqualsLiteral("security.ssl.enable_false_start")){SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,StaticPrefs::security_ssl_enable_false_start());}elseif(prefName.EqualsLiteral("security.ssl.enable_alpn")){SSL_OptionSetDefault(SSL_ENABLE_ALPN,StaticPrefs::security_ssl_enable_alpn());}elseif(prefName.EqualsLiteral("security.tls.enable_0rtt_data")){SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,StaticPrefs::security_tls_enable_0rtt_data());}elseif(prefName.EqualsLiteral("security.tls.enable_post_handshake_auth")){SSL_OptionSetDefault(SSL_ENABLE_POST_HANDSHAKE_AUTH,StaticPrefs::security_tls_enable_post_handshake_auth());}elseif(prefName.EqualsLiteral("security.tls.enable_delegated_credentials")){SSL_OptionSetDefault(SSL_ENABLE_DELEGATED_CREDENTIALS,StaticPrefs::security_tls_enable_delegated_credentials());}elseif(prefName.EqualsLiteral("security.ssl.disable_session_identifiers")){ConfigureTLSSessionIdentifiers();}else{prefFound=false;}returnprefFound;}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;}// Enables or disabled ciphersuites from deprecated versions of TLS as// appropriate. If security.tls.version.enable-deprecated is true, these// ciphersuites may be enabled, if the corresponding preference is true.// Otherwise, these ciphersuites will be disabled.voidSetDeprecatedTLS1CipherPrefs(){if(StaticPrefs::security_tls_version_enable_deprecated()){for(constauto&deprecatedTLS1CipherPref:sDeprecatedTLS1CipherPrefs){SSL_CipherPrefSetDefault(deprecatedTLS1CipherPref.id,deprecatedTLS1CipherPref.prefGetter());}}else{for(constauto&deprecatedTLS1CipherPref:sDeprecatedTLS1CipherPrefs){SSL_CipherPrefSetDefault(deprecatedTLS1CipherPref.id,false);}}}// staticvoidSetKyberPolicy(){if(StaticPrefs::security_tls_enable_kyber()){NSS_SetAlgorithmPolicy(SEC_OID_MLKEM768X25519,NSS_USE_ALG_IN_SSL_KX,0);}else{NSS_SetAlgorithmPolicy(SEC_OID_MLKEM768X25519,0,NSS_USE_ALG_IN_SSL_KX);}}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 settingfor(constauto&cipherPref:sCipherPrefs){if(prefName.Equals(cipherPref.pref)){SSL_CipherPrefSetDefault(cipherPref.id,cipherPref.prefGetter());break;}}SetDeprecatedTLS1CipherPrefs();SetKyberPolicy();nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();}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(constmozilla::MutexAutoLock&proofOfLock){// We access prefs so this must be done on the main thread.mMutex.AssertCurrentThreadOwns();MOZ_ASSERT(NS_IsMainThread());if(NS_WARN_IF(!NS_IsMainThread())){return;}CertVerifier::CertificateTransparencyModectMode=GetCertificateTransparencyMode();nsCStringskipCTForHosts;Preferences::GetCString("security.pki.certificate_transparency.disable_for_hosts",skipCTForHosts);nsAutoCStringskipCTForSPKIHashesBase64;Preferences::GetCString("security.pki.certificate_transparency.disable_for_spki_hashes",skipCTForSPKIHashesBase64);nsTArray<CopyableTArray<uint8_t>>skipCTForSPKIHashes;for(constauto&spkiHashBase64:skipCTForSPKIHashesBase64.Split(',')){nsAutoCStringspkiHashString;if(NS_SUCCEEDED(Base64Decode(spkiHashBase64,spkiHashString))){nsTArray<uint8_t>spkiHash(spkiHashString.Data(),spkiHashString.Length());skipCTForSPKIHashes.AppendElement(std::move(spkiHash));}}CertVerifier::CertificateTransparencyConfigctConfig(ctMode,std::move(skipCTForHosts),std::move(skipCTForSPKIHashes));NetscapeStepUpPolicynetscapeStepUpPolicy=static_cast<NetscapeStepUpPolicy>(StaticPrefs::security_pki_netscape_step_up_policy());switch(netscapeStepUpPolicy){caseNetscapeStepUpPolicy::AlwaysMatch:caseNetscapeStepUpPolicy::MatchBefore23August2016:caseNetscapeStepUpPolicy::MatchBefore23August2015:caseNetscapeStepUpPolicy::NeverMatch:break;default:netscapeStepUpPolicy=NetscapeStepUpPolicy::AlwaysMatch;break;}CRLiteModedefaultCRLiteMode=CRLiteMode::Disabled;CRLiteModecrliteMode=static_cast<CRLiteMode>(StaticPrefs::security_pki_crlite_mode());switch(crliteMode){caseCRLiteMode::Disabled:caseCRLiteMode::TelemetryOnly:caseCRLiteMode::Enforce:caseCRLiteMode::ConfirmRevocations:break;default:crliteMode=defaultCRLiteMode;break;}CertVerifier::OcspDownloadConfigodc;CertVerifier::OcspStrictConfigosc;uint32_tcertShortLifetimeInDays;TimeDurationsoftTimeout;TimeDurationhardTimeout;GetRevocationBehaviorFromPrefs(&odc,&osc,&certShortLifetimeInDays,softTimeout,hardTimeout);mDefaultCertVerifier=newSharedCertVerifier(odc,osc,softTimeout,hardTimeout,certShortLifetimeInDays,netscapeStepUpPolicy,std::move(ctConfig),crliteMode,mEnterpriseCerts);}voidnsNSSComponent::UpdateCertVerifierWithEnterpriseRoots(){MutexAutoLocklock(mMutex);if(!mDefaultCertVerifier){return;}RefPtr<SharedCertVerifier>oldCertVerifier=mDefaultCertVerifier;nsCStringskipCTForHosts(oldCertVerifier->mCTConfig.mSkipForHosts);CertVerifier::CertificateTransparencyConfigctConfig(oldCertVerifier->mCTConfig.mMode,std::move(skipCTForHosts),oldCertVerifier->mCTConfig.mSkipForSPKIHashes.Clone());mDefaultCertVerifier=newSharedCertVerifier(oldCertVerifier->mOCSPDownloadConfig,oldCertVerifier->mOCSPStrict?CertVerifier::ocspStrict:CertVerifier::ocspRelaxed,oldCertVerifier->mOCSPTimeoutSoft,oldCertVerifier->mOCSPTimeoutHard,oldCertVerifier->mCertShortLifetimeInDays,oldCertVerifier->mNetscapeStepUpPolicy,std::move(ctConfig),oldCertVerifier->mCRLiteMode,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=StaticPrefs::security_tls_version_min();uint32_tmaxFromPrefs=StaticPrefs::security_tls_version_max();// This override should be removed some time after// PSM_DEFAULT_MIN_TLS_VERSION is increased to 3.boolenableDeprecated=StaticPrefs::security_tls_version_enable_deprecated();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.nsAutoStringu16ProfilePath;rv=profileFile->GetPath(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;// |profilePath| is encoded in UTF-8 because SQLite always takes UTF-8 file// paths regardless of the current system code page.MOZ_TRY(NS_NewUTF8LocalFile(profilePath,getter_AddRefs(profileDir)));constchar*moduleDBFilename="pkcs11.txt";nsAutoCStringdestModuleDBFilename(moduleDBFilename);destModuleDBFilename.Append(".fips");nsCOMPtr<nsIFile>dbFile;nsresultrv=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;}#if defined(NIGHTLY_BUILD) && !defined(ANDROID)// dbType is either "cert9.db" or "key4.db"voidUnmigrateOneCertDB(constnsCOMPtr<nsIFile>&profileDirectory,constnsACString&dbType){nsCOMPtr<nsIFile>dbFile;nsresultrv=profileDirectory->Clone(getter_AddRefs(dbFile));if(NS_FAILED(rv)){return;}rv=dbFile->AppendNative(dbType);if(NS_FAILED(rv)){return;}boolexists;rv=dbFile->Exists(&exists);if(NS_FAILED(rv)){return;}// If the unprefixed DB already exists, don't overwrite it.if(exists){return;}nsCOMPtr<nsIFile>prefixedDBFile;rv=profileDirectory->Clone(getter_AddRefs(prefixedDBFile));if(NS_FAILED(rv)){return;}nsAutoCStringprefixedDBName("gecko-no-share-");prefixedDBName.Append(dbType);rv=prefixedDBFile->AppendNative(prefixedDBName);if(NS_FAILED(rv)){return;}Unused<<prefixedDBFile->MoveToNative(nullptr,dbType);}voidUnmigrateFromPrefixedCertDBs(){nsCOMPtr<nsIFile>profileDirectory;nsresultrv=NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,getter_AddRefs(profileDirectory));if(NS_FAILED(rv)){return;}UnmigrateOneCertDB(profileDirectory,"cert9.db"_ns);UnmigrateOneCertDB(profileDirectory,"key4.db"_ns);}#endif // defined(NIGHTLY_BUILD) && !defined(ANDROID)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(NIGHTLY_BUILD) && !defined(ANDROID)if(!profileStr.IsEmpty()){UnmigrateFromPrefixedCertDBs();}#endif#if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))SetNSSDatabaseCacheModeAsAppropriate();#endifboolnocertdb=StaticPrefs::security_nocertdb_AtStartup();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::GetCString("security.test.built_in_root_hash",mTestBuiltInRootHash);#endifmMitmCanaryIssuer.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(lock);boolimportEnterpriseRoots=StaticPrefs::security_enterprise_roots_enabled();nsAutoCStringgreBinDir;rv=GetDirectoryPath(NS_GRE_BIN_DIR,greBinDir);if(NS_FAILED(rv)){returnrv;}RefPtr<LoadLoadableCertsTask>loadLoadableCertsTask(newLoadLoadableCertsTask(this,importEnterpriseRoots,std::move(greBinDir)));rv=loadLoadableCertsTask->Dispatch();MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));if(NS_FAILED(rv)){returnrv;}returnNS_OK;}}voidnsNSSComponent::PrepareForShutdown(){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("nsNSSComponent::PrepareForShutdown"));MOZ_RELEASE_ASSERT(NS_IsMainThread());PK11_SetPasswordFunc((PK11PasswordFunc)nullptr);Preferences::RemoveObserver(this,"security.");// Release the default CertVerifier. This will cause any held NSS resources// to be released.{MutexAutoLocklock(mMutex);mDefaultCertVerifier=nullptr;}// Unload osclientcerts so it drops any held resources and stops its// background thread.AsyncLoadOrUnloadOSClientCertsModule(false);// 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).}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;}AutoGleanTimer<&glean::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;}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"));PrepareForShutdown();}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.pki.certificate_transparency.disable_for_hosts")||prefName.EqualsLiteral("security.pki.certificate_transparency.disable_for_spki_hashes")||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")){MutexAutoLocklock(mMutex);setValidationOptions(lock);#ifdef DEBUG}elseif(prefName.EqualsLiteral("security.test.built_in_root_hash")){MutexAutoLocklock(mMutex);mTestBuiltInRootHash.Truncate();Preferences::GetCString("security.test.built_in_root_hash",mTestBuiltInRootHash);#endif // DEBUG}elseif(prefName.Equals("security.enterprise_roots.enabled")){UnloadEnterpriseRoots();MaybeImportEnterpriseRoots();}elseif(prefName.Equals("security.osclientcerts.autoload")){boolloadOSClientCertsModule=StaticPrefs::security_osclientcerts_autoload();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();}}elseif(!nsCRT::strcmp(aTopic,"last-pb-context-exited")){nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();}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(){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);observerService->AddObserver(this,"last-pb-context-exited",false);returnNS_OK;}nsresultDoesCertMatchFingerprint(constnsTArray<uint8_t>&cert,constnsCString&fingerprint,bool&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())};UniquePORTStringcertFingerprint(CERT_Hexify(&digestItem,true/* use colon delimiters */));if(!certFingerprint){returnNS_ERROR_FAILURE;}result=fingerprint.Equals(certFingerprint.get());returnNS_OK;}NS_IMETHODIMPnsNSSComponent::IsCertTestBuiltInRoot(constnsTArray<uint8_t>&cert,bool*result){NS_ENSURE_ARG_POINTER(result);*result=false;#ifdef DEBUGMutexAutoLocklock(mMutex);nsresultrv=DoesCertMatchFingerprint(cert,mTestBuiltInRootHash,*result);if(NS_FAILED(rv)){returnrv;}#endif // DEBUGreturnNS_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([](){RefPtr<mozilla::net::SocketProcessParent>socketParent=mozilla::net::SocketProcessParent::GetSingleton();Unused<<socketParent->SendClearSessionCache();});}}DoClearSSLExternalAndInternalSessionCache();returnNS_OK;}NS_IMETHODIMPnsNSSComponent::AsyncClearSSLExternalAndInternalSessionCache(JSContext*aCx,::mozilla::dom::Promise**aPromise){MOZ_ASSERT(XRE_IsParentProcess());if(!XRE_IsParentProcess()){returnNS_ERROR_NOT_AVAILABLE;}nsIGlobalObject*globalObject=xpc::CurrentNativeGlobal(aCx);if(NS_WARN_IF(!globalObject)){returnNS_ERROR_FAILURE;}ErrorResultresult;RefPtr<mozilla::dom::Promise>promise=mozilla::dom::Promise::Create(globalObject,result);if(NS_WARN_IF(result.Failed())){returnresult.StealNSResult();}if(mozilla::net::nsIOService::UseSocketProcess()&&mozilla::net::gIOService){mozilla::net::gIOService->CallOrWaitForSocketProcess([p=RefPtr{promise}](){RefPtr<mozilla::net::SocketProcessParent>socketParent=mozilla::net::SocketProcessParent::GetSingleton();Unused<<socketParent->SendClearSessionCache()->Then(GetCurrentSerialEventTarget(),__func__,[promise=RefPtr{p}]{promise->MaybeResolveWithUndefined();},[promise=RefPtr{p}]{promise->MaybeReject(NS_ERROR_UNEXPECTED);});});}else{promise->MaybeResolveWithUndefined();}DoClearSSLExternalAndInternalSessionCache();promise.forget(aPromise);returnNS_OK;}Atomic<bool>sSearchingForClientAuthCertificates{false};extern"C"{// Returns true once if gecko is searching for client authentication// certificates (i.e., if some thread has an// AutoSearchingForClientAuthCertificates on the stack).// The idea is when gecko instantiates an// AutoSearchingForClientAuthCertificates, sSearchingForClientAuthCertificates// will get set to true. Some thread running some NSS code will result in a// call to IsGeckoSearchingForClientAuthCertificates(), which will essentially// claim the search by swapping the value for false. The search will happen,// but for the rest of the lifetime of the// AutoSearchingForClientAuthCertificates, this function will return false,// meaning no other threads will also cause searches to happen.boolIsGeckoSearchingForClientAuthCertificates(){returnsSearchingForClientAuthCertificates.exchange(false);}}AutoSearchingForClientAuthCertificates::AutoSearchingForClientAuthCertificates(){sSearchingForClientAuthCertificates=true;}AutoSearchingForClientAuthCertificates::~AutoSearchingForClientAuthCertificates(){sSearchingForClientAuthCertificates=false;}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();}// Helper for FindClientCertificatesWithPrivateKeys. Copies all// CERTCertificates from `from` to `to`.staticinlinevoidCopyCertificatesTo(UniqueCERTCertList&from,UniqueCERTCertList&to){MOZ_ASSERT(from);MOZ_ASSERT(to);for(CERTCertListNode*n=CERT_LIST_HEAD(from.get());!CERT_LIST_END(n,from.get());n=CERT_LIST_NEXT(n)){UniqueCERTCertificatecert(CERT_DupCertificate(n->cert));MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" provisionally adding '%s'",n->cert->subjectName));if(CERT_AddCertToListTail(to.get(),cert.get())==SECSuccess){Unused<<cert.release();}}}// Lists all private keys on all modules and returns a list of any corresponding// client certificates. Returns an empty list if no such certificates can be// found. Returns null if an error is encountered.UniqueCERTCertListFindClientCertificatesWithPrivateKeys(){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,("FindClientCertificatesWithPrivateKeys"));AutoSearchingForClientAuthCertificates_;(void)BlockUntilLoadableCertsLoaded();(void)CheckForSmartCardChanges();UniqueCERTCertListcertsWithPrivateKeys(CERT_NewCertList());if(!certsWithPrivateKeys){returnnullptr;}UniquePK11SlotInfointernalSlot(PK11_GetInternalKeySlot());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 this is the internal certificate/key slot or the slot on the// builtin roots module, there may be many more certificates than private// keys, so search by private keys (PK11_HasRootCerts will be true if the// slot contains an object with the vendor-specific CK_CLASS// CKO_NSS_BUILTIN_ROOT_LIST, which should only be the case for the NSS// builtin roots module).if(internalSlot.get()==slot||PK11_HasRootCerts(slot)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (looking at internal/builtin slot)"));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 "));continue;}if(CERT_LIST_EMPTY(certs)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (no certs for key)"));continue;}CopyCertificatesTo(certs,certsWithPrivateKeys);}}else{// ... otherwise, optimistically assume that searching by certificate// won't take too much time. Since "friendly" slots expose certificates// without needing to be authenticated to, this results in fewer PIN// dialogs shown to the user.MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (looking at non-internal slot)"));if(!PK11_IsPresent(slot)){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (not present)"));continue;}// If this isn't a "friendly" slot, authenticate to expose certificates.if(!PK11_IsFriendly(slot)&&PK11_Authenticate(slot,true,nullptr)!=SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (couldn't authenticate)"));continue;}UniqueCERTCertListcertsInSlot(PK11_ListCertsInSlot(slot));if(!certsInSlot){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (couldn't list certs in slot)"));continue;}// When NSS decodes a certificate, if that certificate has a// corresponding private key (or public key, if the slot it's on hasn't// been logged into), it notes it as a "user cert".if(CERT_FilterCertListForUserCerts(certsInSlot.get())!=SECSuccess){MOZ_LOG(gPIPNSSLog,LogLevel::Debug,(" (couldn't filter certs)"));continue;}CopyCertificatesTo(certsInSlot,certsWithPrivateKeys);}}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));}}returncertsWithPrivateKeys;}CertVerifier::CertificateTransparencyModeGetCertificateTransparencyMode(){constCertVerifier::CertificateTransparencyModedefaultCTMode=CertVerifier::CertificateTransparencyMode::TelemetryOnly;CertVerifier::CertificateTransparencyModectMode=static_cast<CertVerifier::CertificateTransparencyMode>(StaticPrefs::security_pki_certificate_transparency_mode());switch(ctMode){caseCertVerifier::CertificateTransparencyMode::Disabled:caseCertVerifier::CertificateTransparencyMode::TelemetryOnly:caseCertVerifier::CertificateTransparencyMode::Enforce:break;default:ctMode=defaultCTMode;break;}returnctMode;}}// 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;}staticPRBoolConvertBetweenUCS2andASCII(PRBooltoUnicode,unsignedchar*inBuf,unsignedintinBufLen,unsignedchar*outBuf,unsignedintmaxOutBufLen,unsignedint*outBufLen,PRBoolswapBytes){std::unique_ptr<unsignedchar[]>inBufDup(newunsignedchar[inBufLen]);if(!inBufDup){returnPR_FALSE;}std::memcpy(inBufDup.get(),inBuf,inBufLen*sizeof(unsignedchar));// If converting Unicode to ASCII, swap bytes before conversion as neccessary.if(!toUnicode&&swapBytes){if(inBufLen%2!=0){returnPR_FALSE;}mozilla::NativeEndian::swapFromLittleEndianInPlace(reinterpret_cast<char16_t*>(inBufDup.get()),inBufLen/2);}returnPORT_UCS2_UTF8Conversion(toUnicode,inBufDup.get(),inBufLen,outBuf,maxOutBufLen,outBufLen);}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 timefor(constauto&cipherPref:sCipherPrefs){SSL_CipherPrefSetDefault(cipherPref.id,cipherPref.prefGetter());}SetDeprecatedTLS1CipherPrefs();// 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(ConvertBetweenUCS2andASCII);// 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);SetKyberPolicy();// Observe preference change around cipher suite setting.returnCipherSuiteChangeObserver::StartObserve();}}// namespace psm}// namespace mozilla