From 6bc7f460fbc6b85c8d80b62c75daed0d624f07a1 Mon Sep 17 00:00:00 2001 From: Kai Engert Date: Tue, 24 Oct 2017 12:50:35 +0200 Subject: [PATCH] Backport several upstream patches for NSS sql db compatibility, see rhbz#1496565 --- sqlcompat-esr52-1-730495-backport | 521 ++++++++++++++++++++++ sqlcompat-esr52-2-backport-1389664 | 269 +++++++++++ sqlcompat-esr52-3-backport-1394871 | 15 + sqlcompat-esr52-4-backport-1329360 | 149 +++++++ sqlcompat-esr52-5-backport-1382866 | 390 ++++++++++++++++ sqlcompat-esr52-6-fix-logins-decrypt-test | 15 + thunderbird.spec | 26 +- 7 files changed, 1384 insertions(+), 1 deletion(-) create mode 100644 sqlcompat-esr52-1-730495-backport create mode 100644 sqlcompat-esr52-2-backport-1389664 create mode 100644 sqlcompat-esr52-3-backport-1394871 create mode 100644 sqlcompat-esr52-4-backport-1329360 create mode 100644 sqlcompat-esr52-5-backport-1382866 create mode 100644 sqlcompat-esr52-6-fix-logins-decrypt-test diff --git a/sqlcompat-esr52-1-730495-backport b/sqlcompat-esr52-1-730495-backport new file mode 100644 index 0000000..c486e9d --- /dev/null +++ b/sqlcompat-esr52-1-730495-backport @@ -0,0 +1,521 @@ +# HG changeset patch +# Parent 8632daab35b081a0bcb4fd7cc99d8a954c28066b + +diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp +--- a/js/xpconnect/src/XPCShellImpl.cpp ++++ b/js/xpconnect/src/XPCShellImpl.cpp +@@ -64,6 +64,8 @@ + #include "nsICrashReporter.h" + #endif + ++#include "AutoSQLiteLifetime.h" ++ + using namespace mozilla; + using namespace JS; + using mozilla::dom::AutoJSAPI; +@@ -1262,6 +1264,7 @@ XRE_XPCShellMain(int argc, char** argv, + const XREShellData* aShellData) + { + MOZ_ASSERT(aShellData); ++ AutoSQLiteLifetime mSQLLT; + + JSContext* cx; + int result = 0; +diff --git a/storage/TelemetryVFS.cpp b/storage/TelemetryVFS.cpp +--- a/storage/TelemetryVFS.cpp ++++ b/storage/TelemetryVFS.cpp +@@ -828,6 +828,11 @@ xNextSystemCall(sqlite3_vfs *vfs, const + namespace mozilla { + namespace storage { + ++const char *GetVFSName() ++{ ++ return "telemetry-vfs"; ++} ++ + sqlite3_vfs* ConstructTelemetryVFS() + { + #if defined(XP_WIN) +@@ -861,7 +866,7 @@ sqlite3_vfs* ConstructTelemetryVFS() + MOZ_ASSERT(vfs->iVersion <= LAST_KNOWN_VFS_VERSION); + tvfs->szOsFile = sizeof(telemetry_file) - sizeof(sqlite3_file) + vfs->szOsFile; + tvfs->mxPathname = vfs->mxPathname; +- tvfs->zName = "telemetry-vfs"; ++ tvfs->zName = GetVFSName(); + tvfs->pAppData = vfs; + tvfs->xOpen = xOpen; + tvfs->xDelete = xDelete; +diff --git a/storage/mozStorageConnection.cpp b/storage/mozStorageConnection.cpp +--- a/storage/mozStorageConnection.cpp ++++ b/storage/mozStorageConnection.cpp +@@ -72,6 +72,8 @@ namespace storage { + + using mozilla::dom::quota::QuotaObject; + ++const char *GetVFSName(); ++ + namespace { + + int +@@ -615,7 +617,7 @@ Connection::initialize() + js::ProfileEntry::Category::STORAGE); + + // in memory database requested, sqlite uses a magic file name +- int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, nullptr); ++ int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, GetVFSName()); + if (srv != SQLITE_OK) { + mDBConn = nullptr; + return convertResultCode(srv); +@@ -649,7 +651,7 @@ Connection::initialize(nsIFile *aDatabas + #else + static const char* sIgnoreLockingVFS = "unix-none"; + #endif +- const char* vfs = mIgnoreLockingMode ? sIgnoreLockingVFS : nullptr; ++ const char* vfs = mIgnoreLockingMode ? sIgnoreLockingVFS : GetVFSName(); + + int srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, + mFlags, vfs); +@@ -684,7 +686,7 @@ Connection::initialize(nsIFileURL *aFile + rv = aFileURL->GetSpec(spec); + NS_ENSURE_SUCCESS(rv, rv); + +- int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, nullptr); ++ int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, GetVFSName()); + if (srv != SQLITE_OK) { + mDBConn = nullptr; + return convertResultCode(srv); +diff --git a/storage/mozStorageService.cpp b/storage/mozStorageService.cpp +--- a/storage/mozStorageService.cpp ++++ b/storage/mozStorageService.cpp +@@ -26,6 +26,7 @@ + #include "mozIStoragePendingStatement.h" + + #include "sqlite3.h" ++#include "AutoSQLiteLifetime.h" + + #ifdef SQLITE_OS_WIN + // "windows.h" was included and it can #define lots of things we care about... +@@ -34,13 +35,6 @@ + + #include "nsIPromptService.h" + +-#ifdef MOZ_STORAGE_MEMORY +-# include "mozmemory.h" +-# ifdef MOZ_DMD +-# include "DMD.h" +-# endif +-#endif +- + //////////////////////////////////////////////////////////////////////////////// + //// Defines + +@@ -282,12 +276,6 @@ Service::~Service() + if (rc != SQLITE_OK) + NS_WARNING("Failed to unregister sqlite vfs wrapper."); + +- // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but +- // there is nothing actionable we can do in that case. +- rc = ::sqlite3_shutdown(); +- if (rc != SQLITE_OK) +- NS_WARNING("sqlite3 did not shutdown cleanly."); +- + DebugOnly shutdownObserved = !sXPConnect; + NS_ASSERTION(shutdownObserved, "Shutdown was not observed!"); + +@@ -387,121 +375,7 @@ Service::shutdown() + } + + sqlite3_vfs *ConstructTelemetryVFS(); +- +-#ifdef MOZ_STORAGE_MEMORY +- +-namespace { +- +-// By default, SQLite tracks the size of all its heap blocks by adding an extra +-// 8 bytes at the start of the block to hold the size. Unfortunately, this +-// causes a lot of 2^N-sized allocations to be rounded up by jemalloc +-// allocator, wasting memory. For example, a request for 1024 bytes has 8 +-// bytes added, becoming a request for 1032 bytes, and jemalloc rounds this up +-// to 2048 bytes, wasting 1012 bytes. (See bug 676189 for more details.) +-// +-// So we register jemalloc as the malloc implementation, which avoids this +-// 8-byte overhead, and thus a lot of waste. This requires us to provide a +-// function, sqliteMemRoundup(), which computes the actual size that will be +-// allocated for a given request. SQLite uses this function before all +-// allocations, and may be able to use any excess bytes caused by the rounding. +-// +-// Note: the wrappers for malloc, realloc and moz_malloc_usable_size are +-// necessary because the sqlite_mem_methods type signatures differ slightly +-// from the standard ones -- they use int instead of size_t. But we don't need +-// a wrapper for free. +- +-#ifdef MOZ_DMD +- +-// sqlite does its own memory accounting, and we use its numbers in our memory +-// reporters. But we don't want sqlite's heap blocks to show up in DMD's +-// output as unreported, so we mark them as reported when they're allocated and +-// mark them as unreported when they are freed. +-// +-// In other words, we are marking all sqlite heap blocks as reported even +-// though we're not reporting them ourselves. Instead we're trusting that +-// sqlite is fully and correctly accounting for all of its heap blocks via its +-// own memory accounting. Well, we don't have to trust it entirely, because +-// it's easy to keep track (while doing this DMD-specific marking) of exactly +-// how much memory SQLite is using. And we can compare that against what +-// SQLite reports it is using. +- +-MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(SqliteMallocSizeOfOnAlloc) +-MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(SqliteMallocSizeOfOnFree) +- +-#endif +- +-static void *sqliteMemMalloc(int n) +-{ +- void* p = ::malloc(n); +-#ifdef MOZ_DMD +- gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p); +-#endif +- return p; +-} +- +-static void sqliteMemFree(void *p) +-{ +-#ifdef MOZ_DMD +- gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p); +-#endif +- ::free(p); +-} +- +-static void *sqliteMemRealloc(void *p, int n) +-{ +-#ifdef MOZ_DMD +- gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p); +- void *pnew = ::realloc(p, n); +- if (pnew) { +- gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(pnew); +- } else { +- // realloc failed; undo the SqliteMallocSizeOfOnFree from above +- gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p); +- } +- return pnew; +-#else +- return ::realloc(p, n); +-#endif +-} +- +-static int sqliteMemSize(void *p) +-{ +- return ::moz_malloc_usable_size(p); +-} +- +-static int sqliteMemRoundup(int n) +-{ +- n = malloc_good_size(n); +- +- // jemalloc can return blocks of size 2 and 4, but SQLite requires that all +- // allocations be 8-aligned. So we round up sub-8 requests to 8. This +- // wastes a small amount of memory but is obviously safe. +- return n <= 8 ? 8 : n; +-} +- +-static int sqliteMemInit(void *p) +-{ +- return 0; +-} +- +-static void sqliteMemShutdown(void *p) +-{ +-} +- +-const sqlite3_mem_methods memMethods = { +- &sqliteMemMalloc, +- &sqliteMemFree, +- &sqliteMemRealloc, +- &sqliteMemSize, +- &sqliteMemRoundup, +- &sqliteMemInit, +- &sqliteMemShutdown, +- nullptr +-}; +- +-} // namespace +- +-#endif // MOZ_STORAGE_MEMORY ++const char *GetVFSName(); + + static const char* sObserverTopics[] = { + "memory-pressure", +@@ -514,28 +388,13 @@ Service::initialize() + { + MOZ_ASSERT(NS_IsMainThread(), "Must be initialized on the main thread"); + +- int rc; +- +-#ifdef MOZ_STORAGE_MEMORY +- rc = ::sqlite3_config(SQLITE_CONFIG_MALLOC, &memMethods); +- if (rc != SQLITE_OK) +- return convertResultCode(rc); +-#endif +- +- // TODO (bug 1191405): do not preallocate the connections caches until we +- // have figured the impact on our consumers and memory. +- sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0); +- +- // Explicitly initialize sqlite3. Although this is implicitly called by +- // various sqlite3 functions (and the sqlite3_open calls in our case), +- // the documentation suggests calling this directly. So we do. +- rc = ::sqlite3_initialize(); ++ int rc = AutoSQLiteLifetime::getInitResult(); + if (rc != SQLITE_OK) + return convertResultCode(rc); + + mSqliteVFS = ConstructTelemetryVFS(); + if (mSqliteVFS) { +- rc = sqlite3_vfs_register(mSqliteVFS, 1); ++ rc = sqlite3_vfs_register(mSqliteVFS, 0); + if (rc != SQLITE_OK) + return convertResultCode(rc); + } else { +diff --git a/toolkit/xre/AutoSQLiteLifetime.cpp b/toolkit/xre/AutoSQLiteLifetime.cpp +new file mode 100644 +--- /dev/null ++++ b/toolkit/xre/AutoSQLiteLifetime.cpp +@@ -0,0 +1,167 @@ ++/* -*- Mode: C++; tab-width: 8; 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 "nsDebug.h" ++#include "AutoSQLiteLifetime.h" ++#include "sqlite3.h" ++ ++#ifdef MOZ_STORAGE_MEMORY ++# include "mozmemory.h" ++# ifdef MOZ_DMD ++# include "DMD.h" ++# endif ++ ++namespace { ++ ++// By default, SQLite tracks the size of all its heap blocks by adding an extra ++// 8 bytes at the start of the block to hold the size. Unfortunately, this ++// causes a lot of 2^N-sized allocations to be rounded up by jemalloc ++// allocator, wasting memory. For example, a request for 1024 bytes has 8 ++// bytes added, becoming a request for 1032 bytes, and jemalloc rounds this up ++// to 2048 bytes, wasting 1012 bytes. (See bug 676189 for more details.) ++// ++// So we register jemalloc as the malloc implementation, which avoids this ++// 8-byte overhead, and thus a lot of waste. This requires us to provide a ++// function, sqliteMemRoundup(), which computes the actual size that will be ++// allocated for a given request. SQLite uses this function before all ++// allocations, and may be able to use any excess bytes caused by the rounding. ++// ++// Note: the wrappers for malloc, realloc and moz_malloc_usable_size are ++// necessary because the sqlite_mem_methods type signatures differ slightly ++// from the standard ones -- they use int instead of size_t. But we don't need ++// a wrapper for free. ++ ++#ifdef MOZ_DMD ++ ++// sqlite does its own memory accounting, and we use its numbers in our memory ++// reporters. But we don't want sqlite's heap blocks to show up in DMD's ++// output as unreported, so we mark them as reported when they're allocated and ++// mark them as unreported when they are freed. ++// ++// In other words, we are marking all sqlite heap blocks as reported even ++// though we're not reporting them ourselves. Instead we're trusting that ++// sqlite is fully and correctly accounting for all of its heap blocks via its ++// own memory accounting. Well, we don't have to trust it entirely, because ++// it's easy to keep track (while doing this DMD-specific marking) of exactly ++// how much memory SQLite is using. And we can compare that against what ++// SQLite reports it is using. ++ ++MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(SqliteMallocSizeOfOnAlloc) ++MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(SqliteMallocSizeOfOnFree) ++ ++#endif ++ ++static void *sqliteMemMalloc(int n) ++{ ++ void* p = ::malloc(n); ++#ifdef MOZ_DMD ++ gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p); ++#endif ++ return p; ++} ++ ++static void sqliteMemFree(void *p) ++{ ++#ifdef MOZ_DMD ++ gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p); ++#endif ++ ::free(p); ++} ++ ++static void *sqliteMemRealloc(void *p, int n) ++{ ++#ifdef MOZ_DMD ++ gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p); ++ void *pnew = ::realloc(p, n); ++ if (pnew) { ++ gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(pnew); ++ } else { ++ // realloc failed; undo the SqliteMallocSizeOfOnFree from above ++ gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p); ++ } ++ return pnew; ++#else ++ return ::realloc(p, n); ++#endif ++} ++ ++static int sqliteMemSize(void *p) ++{ ++ return ::moz_malloc_usable_size(p); ++} ++ ++static int sqliteMemRoundup(int n) ++{ ++ n = malloc_good_size(n); ++ ++ // jemalloc can return blocks of size 2 and 4, but SQLite requires that all ++ // allocations be 8-aligned. So we round up sub-8 requests to 8. This ++ // wastes a small amount of memory but is obviously safe. ++ return n <= 8 ? 8 : n; ++} ++ ++static int sqliteMemInit(void *p) ++{ ++ return 0; ++} ++ ++static void sqliteMemShutdown(void *p) ++{ ++} ++ ++const sqlite3_mem_methods memMethods = { ++ &sqliteMemMalloc, ++ &sqliteMemFree, ++ &sqliteMemRealloc, ++ &sqliteMemSize, ++ &sqliteMemRoundup, ++ &sqliteMemInit, ++ &sqliteMemShutdown, ++ nullptr ++}; ++ ++} // namespace ++ ++#endif // MOZ_STORAGE_MEMORY ++ ++namespace mozilla { ++ ++AutoSQLiteLifetime::AutoSQLiteLifetime() ++{ ++ if (++AutoSQLiteLifetime::sSingletonEnforcer != 1) { ++ NS_RUNTIMEABORT("multiple instances of AutoSQLiteLifetime constructed!"); ++ } ++ ++#ifdef MOZ_STORAGE_MEMORY ++ sResult = ::sqlite3_config(SQLITE_CONFIG_MALLOC, &memMethods); ++#else ++ sResult = SQLITE_OK; ++#endif ++ ++ if (sResult == SQLITE_OK) { ++ // TODO (bug 1191405): do not preallocate the connections caches until we ++ // have figured the impact on our consumers and memory. ++ sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0); ++ ++ // Explicitly initialize sqlite3. Although this is implicitly called by ++ // various sqlite3 functions (and the sqlite3_open calls in our case), ++ // the documentation suggests calling this directly. So we do. ++ sResult = ::sqlite3_initialize(); ++ } ++} ++ ++AutoSQLiteLifetime::~AutoSQLiteLifetime() ++{ ++ // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but ++ // there is nothing actionable we can do in that case. ++ sResult = ::sqlite3_shutdown(); ++ NS_WARNING_ASSERTION(sResult == SQLITE_OK, ++ "sqlite3 did not shutdown cleanly."); ++} ++ ++int AutoSQLiteLifetime::sSingletonEnforcer = 0; ++int AutoSQLiteLifetime::sResult = SQLITE_MISUSE; ++ ++} // namespace mozilla +diff --git a/toolkit/xre/AutoSQLiteLifetime.h b/toolkit/xre/AutoSQLiteLifetime.h +new file mode 100644 +--- /dev/null ++++ b/toolkit/xre/AutoSQLiteLifetime.h +@@ -0,0 +1,24 @@ ++/* -*- Mode: C++; tab-width: 8; 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/. */ ++ ++#ifndef mozilla_AutoSQLiteLifetime_h ++#define mozilla_AutoSQLiteLifetime_h ++ ++namespace mozilla { ++ ++class AutoSQLiteLifetime final ++{ ++private: ++ static int sSingletonEnforcer; ++ static int sResult; ++public: ++ AutoSQLiteLifetime(); ++ ~AutoSQLiteLifetime(); ++ static int getInitResult() { return AutoSQLiteLifetime::sResult; } ++}; ++ ++} // namespace mozilla ++ ++#endif +diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build +--- a/toolkit/xre/moz.build ++++ b/toolkit/xre/moz.build +@@ -21,7 +21,7 @@ if CONFIG['OS_ARCH'] == 'WINNT': + + XPIDL_MODULE = 'xulapp' + +-EXPORTS += ['nsAppRunner.h'] ++EXPORTS += ['AutoSQLiteLifetime.h', 'nsAppRunner.h'] + + if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']: + EXPORTS += ['EventTracer.h'] +@@ -81,6 +81,7 @@ UNIFIED_SOURCES += [ + # they pull in OS X system headers. + # nsEmbedFunctions.cpp cannot be built in unified mode because it pulls in X11 headers. + SOURCES += [ ++ 'AutoSQLiteLifetime.cpp', + 'nsAppRunner.cpp', + 'nsEmbedFunctions.cpp', + 'ProfileReset.cpp', +diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp +--- a/toolkit/xre/nsAppRunner.cpp ++++ b/toolkit/xre/nsAppRunner.cpp +@@ -276,6 +276,8 @@ extern "C" MOZ_EXPORT void XRE_LibFuzzer + } + #endif + ++#include "AutoSQLiteLifetime.h" ++ + namespace mozilla { + int (*RunGTest)() = 0; + } // namespace mozilla +@@ -2990,6 +2992,9 @@ bool fire_glxtest_process(); + // Encapsulates startup and shutdown state for XRE_main + class XREMain + { ++protected: ++ AutoSQLiteLifetime mSQLLT; ++ + public: + XREMain() : + mStartOffline(false) diff --git a/sqlcompat-esr52-2-backport-1389664 b/sqlcompat-esr52-2-backport-1389664 new file mode 100644 index 0000000..0d3b361 --- /dev/null +++ b/sqlcompat-esr52-2-backport-1389664 @@ -0,0 +1,269 @@ +# HG changeset patch +# Parent 77c27a1e264305362865d6d64af201299e04dece + +diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp +--- a/security/certverifier/NSSCertDBTrustDomain.cpp ++++ b/security/certverifier/NSSCertDBTrustDomain.cpp +@@ -1097,7 +1097,27 @@ InitializeNSS(const char* dir, bool read + if (!loadPKCS11Modules) { + flags |= NSS_INIT_NOMODDB; + } +- return ::NSS_Initialize(dir, "", "", SECMOD_DB, flags); ++ SECStatus srv = NSS_Initialize(dir, "", "", SECMOD_DB, flags); ++ if (srv != SECSuccess) { ++ return srv; ++ } ++ ++ if (!readOnly) { ++ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); ++ if (!slot) { ++ return SECFailure; ++ } ++ // If the key DB doesn't have a password set, PK11_NeedUserInit will return ++ // true. For the SQL DB, we need to set a password or we won't be able to ++ // import any certificates or change trust settings. ++ if (PK11_NeedUserInit(slot.get())) { ++ srv = PK11_InitPin(slot.get(), nullptr, nullptr); ++ MOZ_ASSERT(srv == SECSuccess); ++ Unused << srv; ++ } ++ } ++ ++ return SECSuccess; + } + + void +diff --git a/security/manager/ssl/nsIPK11Token.idl b/security/manager/ssl/nsIPK11Token.idl +--- a/security/manager/ssl/nsIPK11Token.idl ++++ b/security/manager/ssl/nsIPK11Token.idl +@@ -65,6 +65,14 @@ interface nsIPK11Token : nsISupports + void setAskPasswordDefaults([const] in long askTimes, [const] in long timeout); + + /* ++ * True if a password has been configured for this token, and false otherwise. ++ * (Whether or not the user is currently logged in makes no difference.) ++ * In particular, this can be used to determine if a user has set a master ++ * password (if this is the internal key token). ++ */ ++ readonly attribute boolean hasPassword; ++ ++ /* + * Other attributes + */ + boolean isHardwareToken(); +diff --git a/security/manager/ssl/nsNSSCertificateDB.cpp b/security/manager/ssl/nsNSSCertificateDB.cpp +--- a/security/manager/ssl/nsNSSCertificateDB.cpp ++++ b/security/manager/ssl/nsNSSCertificateDB.cpp +@@ -56,31 +56,6 @@ using mozilla::psm::SharedSSLState; + + extern LazyLogModule gPIPNSSLog; + +-static nsresult +-attemptToLogInWithDefaultPassword() +-{ +-#ifdef NSS_DISABLE_DBM +- // The SQL NSS DB requires the user to be authenticated to set certificate +- // trust settings, even if the user's password is empty. To maintain +- // compatibility with the DBM-based database, try to log in with the +- // default empty password. This will allow, at least, tests that need to +- // change certificate trust to pass on all platforms. TODO(bug 978120): Do +- // proper testing and/or implement a better solution so that we are confident +- // that this does the correct thing outside of xpcshell tests too. +- UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); +- if (!slot) { +- return MapSECStatus(SECFailure); +- } +- if (PK11_NeedUserInit(slot.get())) { +- // Ignore the return value. Presumably PK11_InitPin will fail if the user +- // has a non-default password. +- Unused << PK11_InitPin(slot.get(), nullptr, nullptr); +- } +-#endif +- +- return NS_OK; +-} +- + NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB) + + nsNSSCertificateDB::~nsNSSCertificateDB() +@@ -843,11 +818,6 @@ nsNSSCertificateDB::SetCertTrust(nsIX509 + nsresult rv; + UniqueCERTCertificate nsscert(cert->GetCert()); + +- rv = attemptToLogInWithDefaultPassword(); +- if (NS_WARN_IF(rv != NS_OK)) { +- return rv; +- } +- + SECStatus srv; + if (type == nsIX509Cert::CA_CERT) { + // always start with untrusted and move up +@@ -1366,11 +1336,6 @@ nsNSSCertificateDB::AddCertFromBase64(co + + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get())); + +- rv = attemptToLogInWithDefaultPassword(); +- if (NS_WARN_IF(rv != NS_OK)) { +- return rv; +- } +- + SECStatus srv = CERT_AddTempCertToPerm(tmpCert.get(), nickname.get(), + trust.GetTrust()); + return MapSECStatus(srv); +@@ -1400,11 +1365,6 @@ nsNSSCertificateDB::SetCertTrustFromStri + } + UniqueCERTCertificate nssCert(cert->GetCert()); + +- nsresult rv = attemptToLogInWithDefaultPassword(); +- if (NS_WARN_IF(rv != NS_OK)) { +- return rv; +- } +- + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust); + return MapSECStatus(srv); + } +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 +@@ -2081,8 +2081,14 @@ NS_IMETHODIMP + nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* someData) + { +- if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0) { +- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("receiving profile change topic\n")); ++ // 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")); + DoProfileBeforeChange(); + } else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) { + nsNSSShutDownPreventionLock locker; +@@ -2234,6 +2240,7 @@ nsNSSComponent::RegisterObservers() + // 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); + + return NS_OK; + } +diff --git a/security/manager/ssl/nsPK11TokenDB.cpp b/security/manager/ssl/nsPK11TokenDB.cpp +--- a/security/manager/ssl/nsPK11TokenDB.cpp ++++ b/security/manager/ssl/nsPK11TokenDB.cpp +@@ -293,11 +293,24 @@ NS_IMETHODIMP + nsPK11Token::InitPassword(const nsACString& initialPassword) + { + nsNSSShutDownPreventionLock locker; +- if (isAlreadyShutDown()) ++ if (isAlreadyShutDown()) { + return NS_ERROR_NOT_AVAILABLE; ++ } + +- return MapSECStatus( +- PK11_InitPin(mSlot.get(), "", PromiseFlatCString(initialPassword).get())); ++ const nsCString& passwordCStr = PromiseFlatCString(initialPassword); ++ // PSM initializes the sqlite-backed softoken with an empty password. The ++ // implementation considers this not to be a password (GetHasPassword returns ++ // false), but we can't actually call PK11_InitPin again. Instead, we call ++ // PK11_ChangePW with the empty password. ++ bool hasPassword; ++ nsresult rv = GetHasPassword(&hasPassword); ++ if (NS_FAILED(rv)) { ++ return rv; ++ } ++ if (!PK11_NeedUserInit(mSlot.get()) && !hasPassword) { ++ return MapSECStatus(PK11_ChangePW(mSlot.get(), "", passwordCStr.get())); ++ } ++ return MapSECStatus(PK11_InitPin(mSlot.get(), "", passwordCStr.get())); + } + + NS_IMETHODIMP +@@ -359,6 +372,23 @@ nsPK11Token::ChangePassword(const nsACSt + } + + NS_IMETHODIMP ++nsPK11Token::GetHasPassword(bool* hasPassword) ++{ ++ NS_ENSURE_ARG_POINTER(hasPassword); ++ ++ nsNSSShutDownPreventionLock locker; ++ if (isAlreadyShutDown()) { ++ return NS_ERROR_NOT_AVAILABLE; ++ } ++ ++ // PK11_NeedLogin returns true if the token is currently configured to require ++ // the user to log in (whether or not the user is actually logged in makes no ++ // difference). ++ *hasPassword = PK11_NeedLogin(mSlot.get()) && !PK11_NeedUserInit(mSlot.get()); ++ return NS_OK; ++} ++ ++NS_IMETHODIMP + nsPK11Token::IsHardwareToken(bool* _retval) + { + NS_ENSURE_ARG_POINTER(_retval); +diff --git a/security/manager/ssl/tests/unit/head_psm.js b/security/manager/ssl/tests/unit/head_psm.js +--- a/security/manager/ssl/tests/unit/head_psm.js ++++ b/security/manager/ssl/tests/unit/head_psm.js +@@ -770,14 +770,6 @@ function add_prevented_cert_override_tes + add_connection_test(aHost, aExpectedError); + } + +-function loginToDBWithDefaultPassword() { +- let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"] +- .getService(Ci.nsIPK11TokenDB); +- let token = tokenDB.getInternalKeyToken(); +- token.initPassword(""); +- token.login(/*force*/ false); +-} +- + // Helper for asyncTestCertificateUsages. + class CertVerificationResult { + constructor(certName, usageString, successExpected, resolve) { +diff --git a/security/manager/ssl/tests/unit/test_certDB_import.js b/security/manager/ssl/tests/unit/test_certDB_import.js +--- a/security/manager/ssl/tests/unit/test_certDB_import.js ++++ b/security/manager/ssl/tests/unit/test_certDB_import.js +@@ -89,11 +89,6 @@ function testImportCACert() { + } + + function run_test() { +- // We have to set a password and login before we attempt to import anything. +- // In particular, the SQL NSS DB requires the user to be authenticated to set +- // certificate trust settings, which we do when we import CA certs. +- loginToDBWithDefaultPassword(); +- + let certificateDialogsCID = + MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1", + gCertificateDialogs); +diff --git a/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js b/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js +--- a/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js ++++ b/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js +@@ -73,9 +73,6 @@ function testImportPKCS12Cert() { + } + + function run_test() { +- // We have to set a password and login before we attempt to import anything. +- loginToDBWithDefaultPassword(); +- + let certificateDialogsCID = + MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1", + gCertificateDialogs); +diff --git a/security/manager/ssl/tests/unit/test_sdr.js b/security/manager/ssl/tests/unit/test_sdr.js +--- a/security/manager/ssl/tests/unit/test_sdr.js ++++ b/security/manager/ssl/tests/unit/test_sdr.js +@@ -22,12 +22,6 @@ const gTokenPasswordDialogs = { + }; + + function run_test() { +- // We have to set a password and login before we attempt to encrypt anything. +- // In particular, failing to do so will cause the Encrypt() implementation to +- // pop up a dialog asking for a password to be set. This won't work in the +- // xpcshell environment and will lead to an assertion. +- loginToDBWithDefaultPassword(); +- + let sdr = Cc["@mozilla.org/security/sdr;1"] + .getService(Ci.nsISecretDecoderRing); + diff --git a/sqlcompat-esr52-3-backport-1394871 b/sqlcompat-esr52-3-backport-1394871 new file mode 100644 index 0000000..3d30627 --- /dev/null +++ b/sqlcompat-esr52-3-backport-1394871 @@ -0,0 +1,15 @@ +# HG changeset patch +# Parent d7181942327fc7ce8a820a2c09bd96534c2fef58 + +diff --git a/browser/components/migration/FirefoxProfileMigrator.js b/browser/components/migration/FirefoxProfileMigrator.js +--- a/browser/components/migration/FirefoxProfileMigrator.js ++++ b/browser/components/migration/FirefoxProfileMigrator.js +@@ -130,7 +130,7 @@ FirefoxProfileMigrator.prototype._getRes + let places = getFileResource(types.HISTORY, ["places.sqlite", "places.sqlite-wal"]); + let cookies = getFileResource(types.COOKIES, ["cookies.sqlite", "cookies.sqlite-wal"]); + let passwords = getFileResource(types.PASSWORDS, +- ["signons.sqlite", "logins.json", "key3.db", ++ ["signons.sqlite", "logins.json", "key3.db", "key4.db", + "signedInUser.json"]); + let formData = getFileResource(types.FORMDATA, ["formhistory.sqlite"]); + let bookmarksBackups = getFileResource(types.OTHERDATA, diff --git a/sqlcompat-esr52-4-backport-1329360 b/sqlcompat-esr52-4-backport-1329360 new file mode 100644 index 0000000..1a5e5d2 --- /dev/null +++ b/sqlcompat-esr52-4-backport-1329360 @@ -0,0 +1,149 @@ +# HG changeset patch +# Parent a2f525a055c84cb9617c275a48575fea7b0001ea + +diff --git a/config/external/nss/nss.symbols b/config/external/nss/nss.symbols +--- a/config/external/nss/nss.symbols ++++ b/config/external/nss/nss.symbols +@@ -25,7 +25,6 @@ CERT_AddCertToListHead + CERT_AddCertToListTail + CERT_AddExtension + CERT_AddExtensionByOID +-__CERT_AddTempCertToPerm + CERT_AsciiToName + CERT_CacheOCSPResponseFromSideChannel + CERT_CertChainFromCert +diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build +--- a/security/manager/ssl/moz.build ++++ b/security/manager/ssl/moz.build +@@ -182,8 +182,6 @@ DEFINES['NSS_ENABLE_ECC'] = 'True' + for var in ('DLL_PREFIX', 'DLL_SUFFIX'): + DEFINES[var] = '"%s"' % CONFIG[var] + +-DEFINES['CERT_AddTempCertToPerm'] = '__CERT_AddTempCertToPerm' +- + USE_LIBS += [ + 'crmf', + ] +diff --git a/security/manager/ssl/nsNSSCertificateDB.cpp b/security/manager/ssl/nsNSSCertificateDB.cpp +--- a/security/manager/ssl/nsNSSCertificateDB.cpp ++++ b/security/manager/ssl/nsNSSCertificateDB.cpp +@@ -349,9 +349,17 @@ nsNSSCertificateDB::handleCACertDownload + !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL), + !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN)); + +- if (CERT_AddTempCertToPerm(tmpCert.get(), nickname.get(), +- trust.GetTrust()) != SECSuccess) { +- return NS_ERROR_FAILURE; ++ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); ++ SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE, ++ nickname.get(), ++ false); // this parameter is ignored by NSS ++ if (srv != SECSuccess) { ++ return MapSECStatus(srv); ++ } ++ // NSS ignores the first argument to CERT_ChangeCertTrust ++ srv = CERT_ChangeCertTrust(nullptr, tmpCert.get(), trust.GetTrust()); ++ if (srv != SECSuccess) { ++ return MapSECStatus(srv); + } + + // Import additional delivered certificates that can be verified. +@@ -511,34 +519,30 @@ ImportCertsIntoTempStorage(int numcerts, + return NS_OK; + } + +-static SECStatus +-ImportCertsIntoPermanentStorage(const UniqueCERTCertList& certChain, +- const SECCertUsage usage, const bool caOnly) ++static nsresult ++ImportCertsIntoPermanentStorage(const UniqueCERTCertList& certChain) + { +- int chainLen = 0; +- for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain); ++ bool encounteredFailure = false; ++ PRErrorCode savedErrorCode = 0; ++ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); ++ for (CERTCertListNode* chainNode = CERT_LIST_HEAD(certChain); + !CERT_LIST_END(chainNode, certChain); + chainNode = CERT_LIST_NEXT(chainNode)) { +- chainLen++; ++ UniquePORTString nickname(CERT_MakeCANickname(chainNode->cert)); ++ SECStatus srv = PK11_ImportCert(slot.get(), chainNode->cert, ++ CK_INVALID_HANDLE, nickname.get(), ++ false); // this parameter is ignored by NSS ++ if (srv != SECSuccess) { ++ encounteredFailure = true; ++ savedErrorCode = PR_GetError(); ++ } + } + +- SECItem **rawArray; +- rawArray = (SECItem **) PORT_Alloc(chainLen * sizeof(SECItem *)); +- if (!rawArray) { +- return SECFailure; ++ if (encounteredFailure) { ++ return GetXPCOMFromNSSError(savedErrorCode); + } + +- int i = 0; +- for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain); +- !CERT_LIST_END(chainNode, certChain); +- chainNode = CERT_LIST_NEXT(chainNode), i++) { +- rawArray[i] = &chainNode->cert->derCert; +- } +- SECStatus srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), usage, chainLen, +- rawArray, nullptr, true, caOnly, nullptr); +- +- PORT_Free(rawArray); +- return srv; ++ return NS_OK; + } + + NS_IMETHODIMP +@@ -597,11 +601,9 @@ nsNSSCertificateDB::ImportEmailCertifica + DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker); + continue; + } +- SECStatus srv = ImportCertsIntoPermanentStorage(certChain, +- certUsageEmailRecipient, +- false); +- if (srv != SECSuccess) { +- return NS_ERROR_FAILURE; ++ rv = ImportCertsIntoPermanentStorage(certChain); ++ if (NS_FAILED(rv)) { ++ return rv; + } + CERT_SaveSMimeProfile(node->cert, nullptr, nullptr); + } +@@ -654,10 +656,9 @@ nsNSSCertificateDB::ImportValidCACertsIn + continue; + } + +- SECStatus srv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, +- true); +- if (srv != SECSuccess) { +- return NS_ERROR_FAILURE; ++ nsresult rv = ImportCertsIntoPermanentStorage(certChain); ++ if (NS_FAILED(rv)) { ++ return rv; + } + } + +@@ -1336,8 +1337,15 @@ nsNSSCertificateDB::AddCertFromBase64(co + + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get())); + +- SECStatus srv = CERT_AddTempCertToPerm(tmpCert.get(), nickname.get(), +- trust.GetTrust()); ++ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); ++ SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE, ++ nickname.get(), ++ false); // this parameter is ignored by NSS ++ if (srv != SECSuccess) { ++ return MapSECStatus(srv); ++ } ++ // NSS ignores the first argument to CERT_ChangeCertTrust ++ srv = CERT_ChangeCertTrust(nullptr, tmpCert.get(), trust.GetTrust()); + return MapSECStatus(srv); + } + diff --git a/sqlcompat-esr52-5-backport-1382866 b/sqlcompat-esr52-5-backport-1382866 new file mode 100644 index 0000000..17f4078 --- /dev/null +++ b/sqlcompat-esr52-5-backport-1382866 @@ -0,0 +1,390 @@ +# HG changeset patch +# Parent c8f9e7eadcb3068b796b575310a85411a0d90da1 + +diff --git a/security/manager/ssl/nsCertTree.cpp b/security/manager/ssl/nsCertTree.cpp +--- a/security/manager/ssl/nsCertTree.cpp ++++ b/security/manager/ssl/nsCertTree.cpp +@@ -16,6 +16,7 @@ + #include "nsIX509CertValidity.h" + #include "nsNSSCertHelper.h" + #include "nsNSSCertificate.h" ++#include "nsNSSCertificateDB.h" + #include "nsNSSComponent.h" // for PIPNSS string bundle calls. + #include "nsNSSHelper.h" + #include "nsReadableUtils.h" +@@ -800,8 +801,8 @@ nsCertTree::DeleteEntryObject(uint32_t i + + SECStatus srv = CERT_DecodeTrustString(&trust, ""); // no override + if (srv == SECSuccess) { +- CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nsscert.get(), +- &trust); ++ ChangeCertTrustWithPossibleAuthentication(nsscert, trust, ++ nullptr); + } + } + } +diff --git a/security/manager/ssl/nsNSSCertTrust.h b/security/manager/ssl/nsNSSCertTrust.h +--- a/security/manager/ssl/nsNSSCertTrust.h ++++ b/security/manager/ssl/nsNSSCertTrust.h +@@ -57,8 +57,7 @@ public: + /* set p <--> P */ + void AddPeerTrust(bool ssl, bool email, bool objSign); + +- /* get it (const?) (shallow?) */ +- CERTCertTrust * GetTrust() { return &mTrust; } ++ CERTCertTrust& GetTrust() { return mTrust; } + + private: + void addTrust(unsigned int *t, unsigned int v); +diff --git a/security/manager/ssl/nsNSSCertificateDB.cpp b/security/manager/ssl/nsNSSCertificateDB.cpp +--- a/security/manager/ssl/nsNSSCertificateDB.cpp ++++ b/security/manager/ssl/nsNSSCertificateDB.cpp +@@ -232,6 +232,38 @@ nsNSSCertificateDB::getCertsFromPackage( + return collectArgs; + } + ++// When using the sql-backed softoken, trust settings are authenticated using a ++// key in the secret database. Thus, if the user has a password, we need to ++// authenticate to the token in order to be able to change trust settings. ++SECStatus ++ChangeCertTrustWithPossibleAuthentication(const UniqueCERTCertificate& cert, ++ CERTCertTrust& trust, void* ctx) ++{ ++ MOZ_ASSERT(cert, "cert must be non-null"); ++ if (!cert) { ++ PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); ++ return SECFailure; ++ } ++ // NSS ignores the first argument to CERT_ChangeCertTrust ++ SECStatus srv = CERT_ChangeCertTrust(nullptr, cert.get(), &trust); ++ if (srv == SECSuccess || PR_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) { ++ return srv; ++ } ++ if (cert->slot) { ++ // If this certificate is on an external PKCS#11 token, we have to ++ // authenticate to that token. ++ srv = PK11_Authenticate(cert->slot, PR_TRUE, ctx); ++ } else { ++ // Otherwise, the certificate is on the internal module. ++ UniquePK11SlotInfo internalSlot(PK11_GetInternalKeySlot()); ++ srv = PK11_Authenticate(internalSlot.get(), PR_TRUE, ctx); ++ } ++ if (srv != SECSuccess) { ++ return srv; ++ } ++ return CERT_ChangeCertTrust(nullptr, cert.get(), &trust); ++} ++ + nsresult + nsNSSCertificateDB::handleCACertDownload(NotNull x509Certs, + nsIInterfaceRequestor *ctx, +@@ -356,8 +388,8 @@ nsNSSCertificateDB::handleCACertDownload + if (srv != SECSuccess) { + return MapSECStatus(srv); + } +- // NSS ignores the first argument to CERT_ChangeCertTrust +- srv = CERT_ChangeCertTrust(nullptr, tmpCert.get(), trust.GetTrust()); ++ srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(), ++ ctx); + if (srv != SECSuccess) { + return MapSECStatus(srv); + } +@@ -798,8 +830,8 @@ nsNSSCertificateDB::DeleteCertificate(ns + // the cert onto the card again at which point we *will* want to + // trust that cert if it chains up properly. + nsNSSCertTrust trust(0, 0, 0); +- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), +- cert.get(), trust.GetTrust()); ++ srv = ChangeCertTrustWithPossibleAuthentication(cert, trust.GetTrust(), ++ nullptr); + } + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("cert deleted: %d", srv)); + return (srv) ? NS_ERROR_FAILURE : NS_OK; +@@ -815,38 +847,33 @@ nsNSSCertificateDB::SetCertTrust(nsIX509 + if (isAlreadyShutDown()) { + return NS_ERROR_NOT_AVAILABLE; + } +- nsNSSCertTrust trust; +- nsresult rv; +- UniqueCERTCertificate nsscert(cert->GetCert()); + +- SECStatus srv; +- if (type == nsIX509Cert::CA_CERT) { +- // always start with untrusted and move up +- trust.SetValidCA(); +- trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL), +- !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), +- !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN)); +- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), +- nsscert.get(), +- trust.GetTrust()); +- } else if (type == nsIX509Cert::SERVER_CERT) { +- // always start with untrusted and move up +- trust.SetValidPeer(); +- trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0); +- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), +- nsscert.get(), +- trust.GetTrust()); +- } else if (type == nsIX509Cert::EMAIL_CERT) { +- // always start with untrusted and move up +- trust.SetValidPeer(); +- trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0); +- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), +- nsscert.get(), +- trust.GetTrust()); +- } else { +- // ignore user certs +- return NS_OK; ++ nsNSSCertTrust trust; ++ switch (type) { ++ case nsIX509Cert::CA_CERT: ++ trust.SetValidCA(); ++ trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL), ++ !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), ++ !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN)); ++ break; ++ case nsIX509Cert::SERVER_CERT: ++ trust.SetValidPeer(); ++ trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, false, false); ++ break; ++ case nsIX509Cert::EMAIL_CERT: ++ trust.SetValidPeer(); ++ trust.AddPeerTrust(false, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), ++ false); ++ break; ++ default: ++ // Ignore any other type of certificate (including invalid types). ++ return NS_OK; + } ++ ++ UniqueCERTCertificate nsscert(cert->GetCert()); ++ SECStatus srv = ChangeCertTrustWithPossibleAuthentication(nsscert, ++ trust.GetTrust(), ++ nullptr); + return MapSECStatus(srv); + } + +@@ -1311,7 +1338,7 @@ nsNSSCertificateDB::AddCertFromBase64(co + } + + nsNSSCertTrust trust; +- if (CERT_DecodeTrustString(trust.GetTrust(), PromiseFlatCString(aTrust).get()) ++ if (CERT_DecodeTrustString(&trust.GetTrust(), PromiseFlatCString(aTrust).get()) + != SECSuccess) { + return NS_ERROR_FAILURE; + } +@@ -1344,8 +1371,8 @@ nsNSSCertificateDB::AddCertFromBase64(co + if (srv != SECSuccess) { + return MapSECStatus(srv); + } +- // NSS ignores the first argument to CERT_ChangeCertTrust +- srv = CERT_ChangeCertTrust(nullptr, tmpCert.get(), trust.GetTrust()); ++ srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(), ++ nullptr); + return MapSECStatus(srv); + } + +@@ -1373,7 +1400,7 @@ nsNSSCertificateDB::SetCertTrustFromStri + } + UniqueCERTCertificate nssCert(cert->GetCert()); + +- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust); ++ srv = ChangeCertTrustWithPossibleAuthentication(nssCert, trust, nullptr); + return MapSECStatus(srv); + } + +diff --git a/security/manager/ssl/nsNSSCertificateDB.h b/security/manager/ssl/nsNSSCertificateDB.h +--- a/security/manager/ssl/nsNSSCertificateDB.h ++++ b/security/manager/ssl/nsNSSCertificateDB.h +@@ -74,4 +74,8 @@ private: + {0xb3, 0x2c, 0x80, 0x12, 0x46, 0x93, 0xd8, 0x71} \ + } + ++SECStatus ++ChangeCertTrustWithPossibleAuthentication( ++ const mozilla::UniqueCERTCertificate& cert, CERTCertTrust& trust, void* ctx); ++ + #endif // nsNSSCertificateDB_h +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 +@@ -682,8 +682,8 @@ nsNSSComponent::MaybeImportFamilySafetyR + 0, + 0 + }; +- if (CERT_ChangeCertTrust(nullptr, nssCertificate.get(), &trust) +- != SECSuccess) { ++ if (ChangeCertTrustWithPossibleAuthentication(nssCertificate, trust, ++ nullptr) != SECSuccess) { + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, + ("couldn't trust certificate for TLS server auth")); + return NS_ERROR_FAILURE; +@@ -769,8 +769,8 @@ nsNSSComponent::UnloadFamilySafetyRoot() + // they're the same. To work around this, we set a non-zero flag to ensure + // that the trust will get updated. + CERTCertTrust trust = { CERTDB_USER, 0, 0 }; +- if (CERT_ChangeCertTrust(nullptr, mFamilySafetyRoot.get(), &trust) +- != SECSuccess) { ++ if (ChangeCertTrustWithPossibleAuthentication(mFamilySafetyRoot, trust, ++ nullptr) != SECSuccess) { + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, + ("couldn't untrust certificate for TLS server auth")); + } +@@ -912,7 +912,9 @@ nsNSSComponent::UnloadEnterpriseRoots() + ("library failure: CERTCertListNode null or lacks cert")); + continue; + } +- if (CERT_ChangeCertTrust(nullptr, n->cert, &trust) != SECSuccess) { ++ UniqueCERTCertificate cert(CERT_DupCertificate(n->cert)); ++ if (ChangeCertTrustWithPossibleAuthentication(cert, trust, nullptr) ++ != SECSuccess) { + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, + ("couldn't untrust certificate for TLS server auth")); + } +@@ -1068,8 +1070,8 @@ nsNSSComponent::ImportEnterpriseRootsFor + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't add cert to list")); + continue; + } +- if (CERT_ChangeCertTrust(nullptr, nssCertificate.get(), &trust) +- != SECSuccess) { ++ if (ChangeCertTrustWithPossibleAuthentication(nssCertificate, trust, ++ nullptr) != SECSuccess) { + MOZ_LOG(gPIPNSSLog, LogLevel::Debug, + ("couldn't trust certificate for TLS server auth")); + } +diff --git a/security/manager/ssl/tests/unit/test_certDB_import_with_master_password.js b/security/manager/ssl/tests/unit/test_certDB_import_with_master_password.js +new file mode 100644 +--- /dev/null ++++ b/security/manager/ssl/tests/unit/test_certDB_import_with_master_password.js +@@ -0,0 +1,120 @@ ++// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- ++// Any copyright is dedicated to the Public Domain. ++// http://creativecommons.org/publicdomain/zero/1.0/ ++"use strict"; ++ ++// Tests that a CA certificate can still be imported if the user has a master ++// password set. ++ ++do_get_profile(); ++ ++const gCertDB = Cc["@mozilla.org/security/x509certdb;1"] ++ .getService(Ci.nsIX509CertDB); ++ ++const CA_CERT_COMMON_NAME = "importedCA"; ++ ++let gCACertImportDialogCount = 0; ++ ++// Mock implementation of nsICertificateDialogs. ++const gCertificateDialogs = { ++ confirmDownloadCACert: (ctx, cert, trust) => { ++ gCACertImportDialogCount++; ++ equal(cert.commonName, CA_CERT_COMMON_NAME, ++ "CA cert to import should have the correct CN"); ++ trust.value = Ci.nsIX509CertDB.TRUSTED_EMAIL; ++ return true; ++ }, ++ setPKCS12FilePassword: (ctx, password) => { ++ // This is only relevant to exporting. ++ ok(false, "setPKCS12FilePassword() should not have been called"); ++ }, ++ getPKCS12FilePassword: (ctx, password) => { ++ // We don't test anything that calls this method yet. ++ ok(false, "getPKCS12FilePassword() should not have been called"); ++ }, ++ viewCert: (ctx, cert) => { ++ // This shouldn't be called for import methods. ++ ok(false, "viewCert() should not have been called"); ++ }, ++ ++ QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs]) ++}; ++ ++var gMockPrompter = { ++ passwordToTry: "password", ++ numPrompts: 0, ++ ++ // This intentionally does not use arrow function syntax to avoid an issue ++ // where in the context of the arrow function, |this != gMockPrompter| due to ++ // how objects get wrapped when going across xpcom boundaries. ++ promptPassword(dialogTitle, text, password, checkMsg, checkValue) { ++ this.numPrompts++; ++ if (this.numPrompts > 1) { // don't keep retrying a bad password ++ return false; ++ } ++ equal(text, ++ "Please enter the master password for the Software Security Device.", ++ "password prompt text should be as expected"); ++ equal(checkMsg, null, "checkMsg should be null"); ++ ok(this.passwordToTry, "passwordToTry should be non-null"); ++ password.value = this.passwordToTry; ++ return true; ++ }, ++ ++ QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]), ++ ++ // Again with the arrow function issue. ++ getInterface(iid) { ++ if (iid.equals(Ci.nsIPrompt)) { ++ return this; ++ } ++ ++ throw new Error(Cr.NS_ERROR_NO_INTERFACE); ++ } ++}; ++ ++function getCertAsByteArray(certPath) { ++ let certFile = do_get_file(certPath, false); ++ let certBytes = readFile(certFile); ++ ++ let byteArray = []; ++ for (let i = 0; i < certBytes.length; i++) { ++ byteArray.push(certBytes.charCodeAt(i)); ++ } ++ ++ return byteArray; ++} ++ ++function run_test() { ++ let certificateDialogsCID = ++ MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1", ++ gCertificateDialogs); ++ do_register_cleanup(() => { ++ MockRegistrar.unregister(certificateDialogsCID); ++ }); ++ ++ // Set a master password. ++ let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"] ++ .getService(Ci.nsIPK11TokenDB); ++ let token = tokenDB.getInternalKeyToken(); ++ token.initPassword("password"); ++ token.logoutSimple(); ++ ++ // Sanity check the CA cert is missing. ++ throws(() => gCertDB.findCertByNickname(CA_CERT_COMMON_NAME), ++ /NS_ERROR_FAILURE/, ++ "CA cert should not be in the database before import"); ++ ++ // Import and check for success. ++ let caArray = getCertAsByteArray("test_certDB_import/importedCA.pem"); ++ gCertDB.importCertificates(caArray, caArray.length, Ci.nsIX509Cert.CA_CERT, ++ gMockPrompter); ++ equal(gCACertImportDialogCount, 1, ++ "Confirmation dialog for the CA cert should only be shown once"); ++ ++ let caCert = gCertDB.findCertByNickname(CA_CERT_COMMON_NAME); ++ notEqual(caCert, null, "CA cert should now be found in the database"); ++ ok(gCertDB.isCertTrusted(caCert, Ci.nsIX509Cert.CA_CERT, ++ Ci.nsIX509CertDB.TRUSTED_EMAIL), ++ "CA cert should be trusted for e-mail"); ++} +diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini +--- a/security/manager/ssl/tests/unit/xpcshell.ini ++++ b/security/manager/ssl/tests/unit/xpcshell.ini +@@ -55,6 +55,7 @@ run-sequentially = hardcoded ports + [test_cert_version.js] + [test_certDB_import.js] + [test_certDB_import_pkcs12.js] ++[test_certDB_import_with_master_password.js] + [test_certviewer_invalid_oids.js] + skip-if = toolkit == 'android' + [test_constructX509FromBase64.js] diff --git a/sqlcompat-esr52-6-fix-logins-decrypt-test b/sqlcompat-esr52-6-fix-logins-decrypt-test new file mode 100644 index 0000000..5aabb73 --- /dev/null +++ b/sqlcompat-esr52-6-fix-logins-decrypt-test @@ -0,0 +1,15 @@ +# HG changeset patch +# Parent f973c71c077df09ca6ec52254c79d3b654a2bb22 + +diff --git a/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js b/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js +--- a/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js ++++ b/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js +@@ -20,7 +20,7 @@ function resetMasterPassword() + let token = Cc["@mozilla.org/security/pk11tokendb;1"] + .getService(Ci.nsIPK11TokenDB).getInternalKeyToken(); + token.reset(); +- token.changePassword("", ""); ++ token.initPassword(""); + } + + // Tests diff --git a/thunderbird.spec b/thunderbird.spec index b6fb1b3..9fc31ea 100644 --- a/thunderbird.spec +++ b/thunderbird.spec @@ -96,7 +96,7 @@ Summary: Mozilla Thunderbird mail/newsgroup client Name: thunderbird Version: 52.4.0 -Release: 2%{?dist} +Release: 3%{?dist} URL: http://www.mozilla.org/projects/thunderbird/ License: MPLv1.1 or GPLv2+ or LGPLv2+ Group: Applications/Internet @@ -148,6 +148,15 @@ Patch403: rhbz-1400293-fix-mozilla-1324096.patch # Upstream patches +# Backported upstream patches for compatibility with NSS sql database +# format, rhbz#1496563 +Patch501: sqlcompat-esr52-1-730495-backport +Patch502: sqlcompat-esr52-2-backport-1389664 +Patch503: sqlcompat-esr52-3-backport-1394871 +Patch504: sqlcompat-esr52-4-backport-1329360 +Patch505: sqlcompat-esr52-5-backport-1382866 +Patch506: sqlcompat-esr52-6-fix-logins-decrypt-test + %if %{official_branding} # Required by Mozilla Corporation @@ -284,6 +293,17 @@ cd .. %patch105 -p1 -b .bad-langs %patch200 -p1 -b .addons +%if 0%{?fedora} > 27 +pushd mozilla +%patch501 -p1 -b .sqlcompat-1 +%patch502 -p1 -b .sqlcompat-2 +%patch503 -p1 -b .sqlcompat-3 +%patch504 -p1 -b .sqlcompat-4 +%patch505 -p1 -b .sqlcompat-5 +%patch506 -p1 -b .sqlcompat-6 +popd +%endif + %if %{official_branding} # Required by Mozilla Corporation @@ -732,6 +752,10 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : #=============================================================================== %changelog +* Tue Oct 24 2017 Kai Engert - 52.4.0-3 +- Backport several upstream patches for NSS sql db compatibility, + see rhbz#1496565 + * Wed Oct 4 2017 Jan Horak - 52.4.0-2 - Update to 52.4.0 (b2)