Based on upstream changeset: https://hg.mozilla.org/releases/mozilla-esr60/rev/300efdbc9fe1 but with the git binary patch and related test changes omitted, and adapted to apply cleanly to GNU IceCat. # HG changeset patch # User David Keeler # Date 1531860660 25200 # Node ID 300efdbc9fe1f9165428c7934861033935b5abfa # Parent 80a4a7ef281374dbb2afda8edac54665b14b9ef8 Bug 1475775 - Clean up old NSS DB file after upgrade if necessary. r=franziskus, r=mattn, a=RyanVM Reviewers: franziskus, mattn Bug #: 1475775 Differential Revision: https://phabricator.services.mozilla.com/D2202 diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -1935,16 +1935,61 @@ AttemptToRenameBothPKCS11ModuleDBVersion NS_NAMED_LITERAL_CSTRING(sqlModuleDBFilename, "pkcs11.txt"); nsresult rv = AttemptToRenamePKCS11ModuleDB(profilePath, legacyModuleDBFilename); if (NS_FAILED(rv)) { return rv; } return AttemptToRenamePKCS11ModuleDB(profilePath, sqlModuleDBFilename); } + +// When we changed from the old dbm database format to the newer sqlite +// implementation, the upgrade process left behind the existing files. Suppose a +// user had not set a password for the old key3.db (which is about 99% of +// users). After upgrading, both the old database and the new database are +// unprotected. If the user then sets a password for the new database, the old +// one will not be protected. In this scenario, we should probably just remove +// the old database (it would only be relevant if the user downgraded to a +// version of IceCat before 58, but we have to trade this off against the +// user's old private keys being unexpectedly unprotected after setting a +// password). +// This was never an issue on Android because we always used the new +// implementation. +static void +MaybeCleanUpOldNSSFiles(const nsACString& profilePath) +{ + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); + if (!slot) { + return; + } + // Unfortunately we can't now tell the difference between "there already was a + // password when the upgrade happened" and "there was not a password but then + // the user added one after upgrading". + bool hasPassword = PK11_NeedLogin(slot.get()) && + !PK11_NeedUserInit(slot.get()); + if (!hasPassword) { + return; + } + nsCOMPtr dbFile = do_CreateInstance("@mozilla.org/file/local;1"); + if (!dbFile) { + return; + } + nsresult rv = dbFile->InitWithNativePath(profilePath); + if (NS_FAILED(rv)) { + return; + } + NS_NAMED_LITERAL_CSTRING(keyDBFilename, "key3.db"); + rv = dbFile->AppendNative(keyDBFilename); + if (NS_FAILED(rv)) { + return; + } + // Since this isn't a directory, the `recursive` argument to `Remove` is + // irrelevant. + Unused << dbFile->Remove(false); +} #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 @@ -1966,16 +2011,19 @@ InitializeNSSWithFallbacks(const nsACStr // Try read/write mode. If we're in safeMode, we won't load PKCS#11 modules. #ifndef ANDROID PRErrorCode savedPRErrorCode1; #endif // ifndef ANDROID SECStatus srv = ::mozilla::psm::InitializeNSS(profilePath, false, !safeMode); if (srv == SECSuccess) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r/w mode")); +#ifndef ANDROID + MaybeCleanUpOldNSSFiles(profilePath); +#endif // ifndef ANDROID return NS_OK; } #ifndef ANDROID savedPRErrorCode1 = PR_GetError(); PRErrorCode savedPRErrorCode2; #endif // ifndef ANDROID // That failed. Try read-only mode. srv = ::mozilla::psm::InitializeNSS(profilePath, true, !safeMode);