/* -*- 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/. */
// 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.
nsresult FileToCString(const nsCOMPtr<nsIFile>& file, nsACString& result) { #ifdef XP_WIN
nsAutoString path;
nsresult rv = file->GetPath(path); if (NS_SUCCEEDED(rv)) {
CopyUTF16toUTF8(path, result);
} return rv; #else return file->GetNativePath(result); #endif
}
bool LoadIPCClientCerts() { // This returns the path to the binary currently running, which in most // cases is "plugin-container".
UniqueFreePtr<char> pluginContainerPath(BinaryPath::Get()); if (!pluginContainerPath) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to get get plugin-container path")); returnfalse;
}
nsAutoCString ipcClientCertsDirString(pluginContainerPath.get()); // On most platforms, ipcclientcerts is in the same directory as // plugin-container. To obtain the path to that directory, truncate from // the last directory separator. // On macOS, plugin-container is in // Firefox.app/Contents/MacOS/plugin-container.app/Contents/MacOS/, // whereas ipcclientcerts is in Firefox.app/Contents/MacOS/. Consequently, // this truncation from the last directory separator has to happen 4 times // total. Normally this would be done using nsIFile APIs, but due to when // this is initialized in the socket process, those aren't available.
TruncateFromLastDirectorySeparator(ipcClientCertsDirString); #ifdef XP_MACOSX
TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
TruncateFromLastDirectorySeparator(ipcClientCertsDirString); #endif if (!LoadIPCClientCertsModule(ipcClientCertsDirString)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to load ipcclientcerts from '%s'",
ipcClientCertsDirString.get())); returnfalse;
} returntrue;
}
// This function can be called from chrome or content or socket processes // to ensure that NSS is initialized. bool EnsureNSSInitializedChromeOrContent() { static Atomic<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;
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread)); if (NS_FAILED(rv)) { returnfalse;
}
// Forward to the main thread synchronously.
mozilla::SyncRunnable::DispatchToThread(
mainThread,
NS_NewRunnableFunction("EnsureNSSInitializedChromeOrContent", []() {
EnsureNSSInitializedChromeOrContent();
}));
return initialized;
}
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;
}
class BackgroundImportEnterpriseCertsTask final : public CryptoTask { public: explicit BackgroundImportEnterpriseCertsTask(nsNSSComponent* nssComponent)
: mNSSComponent(nssComponent) {}
nsresult LoadLoadableCertsTask::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) { return NS_ERROR_FAILURE;
} return target->Dispatch(this, NS_DISPATCH_NORMAL);
}
nsresult loadLoadableRootsResult = 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();
}
{
MonitorAutoLock rootsLoadedLock(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();
} return NS_OK;
}
// Returns by reference the path to the desired directory, based on the current // settings in the directory service. // |result| is encoded in UTF-8. static nsresult GetDirectoryPath(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")); return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIFile> directory;
nsresult rv = 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)); return rv;
} return FileToCString(directory, result);
}
class BackgroundLoadOSClientCertsModuleTask final : public CryptoTask { public: explicit BackgroundLoadOSClientCertsModuleTask() {}
nsresult nsNSSComponent::CheckForSmartCardChanges() { #ifndef MOZ_NO_SMART_CARDS
{
StaticMutexAutoLock lock(sCheckForSmartCardChangesMutex); // Do this at most once every 3 seconds.
TimeStamp now = TimeStamp::Now(); if (now - sLastCheckedForSmartCardChanges <
TimeDuration::FromSeconds(3.0)) { return NS_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;
{
AutoSECMODListReadLock secmodLock;
SECMODModuleList* list = SECMOD_GetDefaultModuleList(); while (list) { if (SECMOD_LockedModuleHasRemovableSlots(list->module)) {
UniqueSECMODModule module(SECMOD_ReferenceModule(list->module)); if (!modulesWithRemovableSlots.append(std::move(module))) { return NS_ERROR_OUT_OF_MEMORY;
}
}
list = list->next;
}
} for (auto& module : modulesWithRemovableSlots) { // Best-effort.
Unused << SECMOD_UpdateSlotList(module.get());
}
AutoSECMODListReadLock secmodLock; for (auto& module : modulesWithRemovableSlots) { for (int i = 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]);
}
} #endif
return NS_OK;
}
// 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. static nsresult GetNSS3Directory(nsCString& result) {
MOZ_ASSERT(NS_IsMainThread());
UniquePRString nss3Path(
PR_GetLibraryFilePathname(MOZ_DLL_PREFIX "nss3" MOZ_DLL_SUFFIX, reinterpret_cast<PRFuncPtr>(NSS_Initialize))); if (!nss3Path) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nss not loaded?")); return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIFile> nss3File;
nsresult rv = 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())); return rv;
}
nsCOMPtr<nsIFile> nss3Directory;
rv = nss3File->GetParent(getter_AddRefs(nss3Directory)); if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get parent directory?")); return rv;
} return FileToCString(nss3Directory, result);
}
// 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. // |possibleLoadableRootsLocations| is encoded in UTF-8. static nsresult ListPossibleLoadableRootsLocations(
Vector<nsCString>& possibleLoadableRootsLocations) {
MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return NS_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.
nsAutoCString nss3Dir;
nsresult rv = GetNSS3Directory(nss3Dir); if (NS_SUCCEEDED(rv)) { if (!possibleLoadableRootsLocations.append(std::move(nss3Dir))) { return NS_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"));
}
nsAutoCString currentProcessDir;
rv = GetDirectoryPath(NS_XPCOM_CURRENT_PROCESS_DIR, currentProcessDir); if (NS_SUCCEEDED(rv)) { if (!possibleLoadableRootsLocations.append(std::move(currentProcessDir))) { return NS_ERROR_OUT_OF_MEMORY;
}
} else {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("could not get current process directory"));
}
nsAutoCString greDir;
rv = GetDirectoryPath(NS_GRE_DIR, greDir); if (NS_SUCCEEDED(rv)) { if (!possibleLoadableRootsLocations.append(std::move(greDir))) { return NS_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.
nsAutoCString emptyString; if (!possibleLoadableRootsLocations.append(std::move(emptyString))) { return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult LoadLoadableCertsTask::LoadLoadableRoots() { for (constauto& possibleLocation : mPossibleLoadableRootsLocations) { if (mozilla::psm::LoadLoadableRoots(possibleLocation)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("loaded CKBI from %s", possibleLocation.get())); return NS_OK;
}
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not load loadable roots")); return NS_ERROR_FAILURE;
}
// Table of pref names and SSL cipher ID typedefstruct { constchar* pref;
int32_t id; bool (*prefGetter)();
} CipherPref;
// These ciphersuites can only be enabled if deprecated versions of TLS are // also enabled (via the preference "security.tls.version.enable-deprecated"). staticconst CipherPref sDeprecatedTLS1CipherPrefs[] = {
{"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*/ void nsNSSComponent::FillTLSVersionRange(SSLVersionRange& rangeOut,
uint32_t minFromPrefs,
uint32_t maxFromPrefs,
SSLVersionRange defaults) {
rangeOut = defaults; // determine what versions are supported
SSLVersionRange supported; 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 representation
minFromPrefs += SSL_LIBRARY_VERSION_3_0;
maxFromPrefs += SSL_LIBRARY_VERSION_3_0; // if min/maxFromPrefs are invalid, use defaults if (minFromPrefs > maxFromPrefs || minFromPrefs < supported.min ||
maxFromPrefs > supported.max ||
minFromPrefs < SSL_LIBRARY_VERSION_TLS_1_0) { return;
}
// fill out rangeOut
rangeOut.min = (uint16_t)minFromPrefs;
rangeOut.max = (uint16_t)maxFromPrefs;
}
nsresult rv = nsNSSComponent::SetEnabledTLSVersions(); if (NS_FAILED(rv)) { return rv;
}
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());
rv = InitializeCipherSuite(); if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Error,
("Unable to initialize cipher suite settings\n")); return rv;
}
// static
nsresult CipherSuiteChangeObserver::StartObserve() {
MOZ_ASSERT(NS_IsMainThread(), "CipherSuiteChangeObserver::StartObserve() can only be accessed " "on the main thread"); if (!sObserver) {
RefPtr<CipherSuiteChangeObserver> observer = new CipherSuiteChangeObserver();
nsresult rv = Preferences::AddStrongObserver(observer.get(), "security."); if (NS_FAILED(rv)) {
sObserver = nullptr; return rv;
}
// 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. void SetDeprecatedTLS1CipherPrefs() { 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);
}
}
}
nsresult CipherSuiteChangeObserver::Observe(nsISupports* /*aSubject*/, constchar* aTopic, const char16_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_ConvertUTF16toUTF8 prefName(someData); // Look through the cipher table and set according to pref setting for (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);
} return NS_OK;
}
} // namespace
void nsNSSComponent::setValidationOptions( bool isInitialSetting, const mozilla::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;
}
// This preference controls whether we do OCSP fetching and does not affect // OCSP stapling. // 0 = disabled, 1 = enabled, 2 = only enabled for EV
uint32_t ocspEnabled = StaticPrefs::security_OCSP_enabled();
// 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);
}
NetscapeStepUpPolicy netscapeStepUpPolicy = static_cast<NetscapeStepUpPolicy>(
StaticPrefs::security_pki_netscape_step_up_policy()); switch (netscapeStepUpPolicy) { case NetscapeStepUpPolicy::AlwaysMatch: case NetscapeStepUpPolicy::MatchBefore23August2016: case NetscapeStepUpPolicy::MatchBefore23August2015: case NetscapeStepUpPolicy::NeverMatch: break; default:
netscapeStepUpPolicy = NetscapeStepUpPolicy::AlwaysMatch; break;
}
CRLiteMode defaultCRLiteMode = CRLiteMode::Disabled;
CRLiteMode crliteMode = static_cast<CRLiteMode>(StaticPrefs::security_pki_crlite_mode()); switch (crliteMode) { case CRLiteMode::Disabled: case CRLiteMode::TelemetryOnly: case CRLiteMode::Enforce: case CRLiteMode::ConfirmRevocations: break; default:
crliteMode = defaultCRLiteMode; break;
}
// Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and // TLS 1.2 (max) when the prefs aren't set or set to invalid values.
nsresult nsNSSComponent::SetEnabledTLSVersions() { // Keep these values in sync with all.js. // 1 means TLS 1.0, 2 means TLS 1.1, etc. staticconst uint32_t PSM_DEFAULT_MIN_TLS_VERSION = 3; staticconst uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 4; staticconst uint32_t PSM_DEPRECATED_TLS_VERSION = 1;
// This override should be removed some time after // PSM_DEFAULT_MIN_TLS_VERSION is increased to 3. bool enableDeprecated = StaticPrefs::security_tls_version_enable_deprecated(); if (enableDeprecated) {
minFromPrefs = std::min(minFromPrefs, PSM_DEPRECATED_TLS_VERSION);
}
#ifdefined(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). staticvoid SetNSSDatabaseCacheModeAsAppropriate() {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIFile> profileFile;
nsresult rv = 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;
}
static nsresult GetNSSProfilePath(nsAutoCString& aProfilePath) {
aProfilePath.Truncate();
nsCOMPtr<nsIFile> profileFile;
nsresult rv = 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."); return NS_OK;
}
#ifdefined(XP_WIN) // SQLite always takes UTF-8 file paths regardless of the current system // code page.
nsAutoString u16ProfilePath;
rv = profileFile->GetPath(u16ProfilePath);
CopyUTF16toUTF8(u16ProfilePath, aProfilePath); #else
rv = profileFile->GetNativePath(aProfilePath); #endif if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Error,
("Could not get native path for profile directory.\n")); return rv;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("NSS profile at '%s'\n", aProfilePath.get())); return NS_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. static nsresult AttemptToRenamePKCS11ModuleDB(const nsACString& 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";
nsAutoCString destModuleDBFilename(moduleDBFilename);
destModuleDBFilename.Append(".fips");
nsCOMPtr<nsIFile> dbFile;
nsresult rv = profileDir->Clone(getter_AddRefs(dbFile)); if (NS_FAILED(rv) || !dbFile) { return NS_ERROR_FAILURE;
}
rv = dbFile->AppendNative(nsAutoCString(moduleDBFilename)); if (NS_FAILED(rv)) { return rv;
} // If the PKCS#11 module DB doesn't exist, renaming it won't help. bool exists;
rv = dbFile->Exists(&exists); if (NS_FAILED(rv)) { return rv;
} // This is strange, but not a catastrophic failure. if (!exists) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("%s doesn't exist?", moduleDBFilename)); return NS_OK;
}
nsCOMPtr<nsIFile> destDBFile;
rv = profileDir->Clone(getter_AddRefs(destDBFile)); if (NS_FAILED(rv) || !destDBFile) { return NS_ERROR_FAILURE;
}
rv = destDBFile->AppendNative(destModuleDBFilename); if (NS_FAILED(rv)) { return rv;
} // If the destination exists, presumably we've already tried this. Doing it // again won't help.
rv = destDBFile->Exists(&exists); if (NS_FAILED(rv)) { return rv;
} // Unfortunate, but not a catastrophic failure. if (exists) {
MOZ_LOG(
gPIPNSSLog, LogLevel::Debug,
("%s already exists - not overwriting", destModuleDBFilename.get())); return NS_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); return NS_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. static nsresult InitializeNSSWithFallbacks(const nsACString& profilePath, bool nocertdb, bool safeMode) { if (nocertdb || profilePath.IsEmpty()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("nocertdb mode or empty profile path -> NSS_NoDB_Init"));
SECStatus srv = NSS_NoDB_Init(nullptr); #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED if (srv != SECSuccess) {
MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",
PR_GetError());
} #endif return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
}
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_ENABLED
MOZ_CRASH_UNSAFE_PRINTF("InitializeNSSWithFallbacks failed: %d",
PR_GetError()); # endif return NS_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.
nsresult rv = 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); # endif return rv;
}
srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadWrite,
PKCS11DBConfig::LoadModules); if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r/w mode")); return NS_OK;
}
srv = ::mozilla::psm::InitializeNSS(profilePath, NSSDBConfig::ReadOnly,
PKCS11DBConfig::LoadModules); if (srv == SECSuccess) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r-o mode")); return NS_OK;
}
}
} #endif
bool nocertdb = StaticPrefs::security_nocertdb_AtStartup(); bool inSafeMode = 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)) { return rv;
}
}
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")); return rv;
}
PK11_SetPasswordFunc(PK11PasswordPrompt);
// Register an observer so we can inform NSS when these prefs change
Preferences::AddStrongObserver(this, "security.");
rv = CommonInit();
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); if (NS_FAILED(rv)) { return NS_ERROR_UNEXPECTED;
}
// Release the default CertVerifier. This will cause any held NSS resources // to be released.
MutexAutoLock lock(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).
}
nsresult nsNSSComponent::Init() {
MOZ_RELEASE_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return NS_ERROR_NOT_SAME_THREAD;
}
MOZ_ASSERT(XRE_IsParentProcess()); if (!XRE_IsParentProcess()) { return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsNSSComponent::Observe(nsISupports* aSubject, constchar* aTopic, const char16_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) { bool clearSessionCache = true;
NS_ConvertUTF16toUTF8 prefName(someData);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.