ae11a9
diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp
ae11a9
--- a/security/manager/ssl/nsNSSComponent.cpp
ae11a9
+++ b/security/manager/ssl/nsNSSComponent.cpp
ae11a9
@@ -1654,6 +1654,51 @@
ae11a9
   }
ae11a9
   return AttemptToRenamePKCS11ModuleDB(profilePath, sqlModuleDBFilename);
ae11a9
 }
ae11a9
+
ae11a9
+// When we changed from the old dbm database format to the newer sqlite
ae11a9
+// implementation, the upgrade process left behind the existing files. Suppose a
ae11a9
+// user had not set a password for the old key3.db (which is about 99% of
ae11a9
+// users). After upgrading, both the old database and the new database are
ae11a9
+// unprotected. If the user then sets a password for the new database, the old
ae11a9
+// one will not be protected. In this scenario, we should probably just remove
ae11a9
+// the old database (it would only be relevant if the user downgraded to a
ae11a9
+// version of Firefox before 58, but we have to trade this off against the
ae11a9
+// user's old private keys being unexpectedly unprotected after setting a
ae11a9
+// password).
ae11a9
+// This was never an issue on Android because we always used the new
ae11a9
+// implementation.
ae11a9
+static void
ae11a9
+MaybeCleanUpOldNSSFiles(const nsACString& profilePath)
ae11a9
+{
ae11a9
+  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
ae11a9
+  if (!slot) {
ae11a9
+    return;
ae11a9
+  }
ae11a9
+  // Unfortunately we can't now tell the difference between "there already was a
ae11a9
+  // password when the upgrade happened" and "there was not a password but then
ae11a9
+  // the user added one after upgrading".
ae11a9
+  bool hasPassword = PK11_NeedLogin(slot.get()) &&
ae11a9
+                     !PK11_NeedUserInit(slot.get());
ae11a9
+  if (!hasPassword) {
ae11a9
+    return;
ae11a9
+  }
ae11a9
+  nsCOMPtr<nsIFile> dbFile = do_CreateInstance("@mozilla.org/file/local;1");
ae11a9
+  if (!dbFile) {
ae11a9
+    return;
ae11a9
+  }
ae11a9
+  nsresult rv = dbFile->InitWithNativePath(profilePath);
ae11a9
+  if (NS_FAILED(rv)) {
ae11a9
+    return;
ae11a9
+  }
ae11a9
+  NS_NAMED_LITERAL_CSTRING(keyDBFilename, "key3.db");
ae11a9
+  rv = dbFile->AppendNative(keyDBFilename);
ae11a9
+  if (NS_FAILED(rv)) {
ae11a9
+    return;
ae11a9
+  }
ae11a9
+  // Since this isn't a directory, the `recursive` argument to `Remove` is
ae11a9
+  // irrelevant.
ae11a9
+  Unused << dbFile->Remove(false);
ae11a9
+}
ae11a9
 #endif // ifndef ANDROID
ae11a9
 
ae11a9
 // Given a profile directory, attempt to initialize NSS. If nocertdb is true,
ae11a9
@@ -1685,6 +1730,9 @@
ae11a9
   SECStatus srv = ::mozilla::psm::InitializeNSS(profilePath, false, !safeMode);
ae11a9
   if (srv == SECSuccess) {
ae11a9
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r/w mode"));
ae11a9
+#ifndef ANDROID
ae11a9
+    MaybeCleanUpOldNSSFiles(profilePath);
ae11a9
+#endif // ifndef ANDROID
ae11a9
     return NS_OK;
ae11a9
   }
ae11a9
 #ifndef ANDROID
ae11a9