bug 1382866 - prompt for authentication when changing certificate trust fails r=Cykesiopka,jcj
authorDavid Keeler <dkeeler@mozilla.com>
Fri, 21 Jul 2017 16:58:42 -0700
changeset 419899 ac03688d438263275bd4c1b5dd801a41cc786847
parent 419898 be21461d6fefee39027719967a72c7ea774f4a23
child 419900 d2b2de8c314b98c466ab8309d32eb9114ab36c69
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersCykesiopka, jcj
bugs1382866
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1382866 - prompt for authentication when changing certificate trust fails r=Cykesiopka,jcj MozReview-Commit-ID: 3ryUyAfbNCs
security/manager/ssl/nsCertTree.cpp
security/manager/ssl/nsNSSCertTrust.h
security/manager/ssl/nsNSSCertificateDB.cpp
security/manager/ssl/nsNSSCertificateDB.h
security/manager/ssl/nsNSSComponent.cpp
security/manager/ssl/tests/unit/test_certDB_import_with_master_password.js
security/manager/ssl/tests/unit/xpcshell.ini
--- a/security/manager/ssl/nsCertTree.cpp
+++ b/security/manager/ssl/nsCertTree.cpp
@@ -11,16 +11,17 @@
 #include "nsHashKeys.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITreeColumns.h"
 #include "nsIX509CertDB.h"
 #include "nsIX509Cert.h"
 #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"
 #include "nsTHashtable.h"
 #include "nsUnicharUtils.h"
 #include "nsXPCOMCID.h"
 #include "nsXPIDLString.h"
 #include "pkix/pkixtypes.h"
@@ -795,18 +796,18 @@ nsCertTree::DeleteEntryObject(uint32_t i
             UniqueCERTCertificate nsscert(cert->GetCert());
 
             if (nsscert) {
               CERTCertTrust trust;
               memset((void*)&trust, 0, sizeof(trust));
 
               SECStatus srv = CERT_DecodeTrustString(&trust, ""); // no override
               if (srv == SECSuccess) {
-                CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nsscert.get(),
-                                     &trust);
+                ChangeCertTrustWithPossibleAuthentication(nsscert, trust,
+                                                          nullptr);
               }
             }
           }
           else {
             canRemoveEntry = true;
           }
         }
       }
--- a/security/manager/ssl/nsNSSCertTrust.h
+++ b/security/manager/ssl/nsNSSCertTrust.h
@@ -52,18 +52,17 @@ public:
                        bool ca,   bool tCA, bool tClientCA,
                        bool user, bool warn);
 
   /* set c <--> CT */
   void AddCATrust(bool ssl, bool email, bool objSign);
   /* 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);
   void removeTrust(unsigned int *t, unsigned int v);
   bool hasTrust(unsigned int t, unsigned int v);
   CERTCertTrust mTrust;
 };
 
--- a/security/manager/ssl/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/nsNSSCertificateDB.cpp
@@ -224,16 +224,48 @@ nsNSSCertificateDB::getCertsFromPackage(
   if (CERT_DecodeCertPackage(BitwiseCast<char*, uint8_t*>(data), length,
                              collect_certs, collectArgs) != SECSuccess) {
     return nullptr;
   }
 
   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<nsIArray*> x509Certs,
                                          nsIInterfaceRequestor *ctx,
                                          const nsNSSShutDownPreventionLock &proofOfLock)
 {
   // First thing we have to do is figure out which certificate we're
   // gonna present to the user.  The CA may have sent down a list of
   // certs which may or may not be a chained list of certs.  Until
@@ -348,18 +380,18 @@ nsNSSCertificateDB::handleCACertDownload
 
   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());
+  srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(),
+                                                  ctx);
   if (srv != SECSuccess) {
     return MapSECStatus(srv);
   }
 
   // Import additional delivered certificates that can be verified.
 
   // build a CertList for filtering
   UniqueCERTCertList certList(CERT_NewCertList());
@@ -790,70 +822,65 @@ nsNSSCertificateDB::DeleteCertificate(ns
     // To delete a cert of a slot (builtin, most likely), mark it as
     // completely untrusted.  This way we keep a copy cached in the
     // local database, and next time we try to load it off of the
     // external token/slot, we'll know not to trust it.  We don't
     // want to do that with user certs, because a user may  re-store
     // 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;
 }
 
 NS_IMETHODIMP
 nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
                                  uint32_t type,
                                  uint32_t trusted)
 {
   NS_ENSURE_ARG_POINTER(cert);
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  nsNSSCertTrust trust;
-  nsresult rv;
-  UniqueCERTCertificate nsscert(cert->GetCert());
 
-  rv = attemptToLogInWithDefaultPassword();
+  nsresult 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
-    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);
 }
 
 NS_IMETHODIMP
 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
                                   uint32_t certType,
                                   uint32_t trustType,
                                   bool *_isTrusted)
@@ -1231,17 +1258,17 @@ nsNSSCertificateDB::AddCertFromBase64(co
   *addedCertificate = nullptr;
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsNSSCertTrust trust;
-  if (CERT_DecodeTrustString(trust.GetTrust(), PromiseFlatCString(aTrust).get())
+  if (CERT_DecodeTrustString(&trust.GetTrust(), PromiseFlatCString(aTrust).get())
         != SECSuccess) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIX509Cert> newCert;
   nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
   if (NS_FAILED(rv)) {
     return rv;
@@ -1274,18 +1301,18 @@ nsNSSCertificateDB::AddCertFromBase64(co
 
   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());
+  srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(),
+                                                  nullptr);
   if (srv != SECSuccess) {
     return MapSECStatus(srv);
   }
   newCert.forget(addedCertificate);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1313,17 +1340,17 @@ 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);
+  srv = ChangeCertTrustWithPossibleAuthentication(nssCert, trust, nullptr);
   return MapSECStatus(srv);
 }
 
 NS_IMETHODIMP
 nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
--- a/security/manager/ssl/nsNSSCertificateDB.h
+++ b/security/manager/ssl/nsNSSCertificateDB.h
@@ -69,9 +69,13 @@ private:
 
 #define NS_X509CERTDB_CID { /* fb0bbc5c-452e-4783-b32c-80124693d871 */ \
     0xfb0bbc5c,                                                        \
     0x452e,                                                            \
     0x4783,                                                            \
     {0xb3, 0x2c, 0x80, 0x12, 0x46, 0x93, 0xd8, 0x71}                   \
   }
 
+SECStatus
+ChangeCertTrustWithPossibleAuthentication(
+  const mozilla::UniqueCERTCertificate& cert, CERTCertTrust& trust, void* ctx);
+
 #endif // nsNSSCertificateDB_h
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -638,18 +638,18 @@ nsNSSComponent::MaybeImportFamilySafetyR
           ("subject name is '%s'", subjectName.get()));
   if (kMicrosoftFamilySafetyCN.Equals(subjectName.get())) {
     wasFamilySafetyRoot = true;
     CERTCertTrust trust = {
       CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER,
       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;
     }
     MOZ_ASSERT(!mFamilySafetyRoot);
     mFamilySafetyRoot = Move(nssCertificate);
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("added Family Safety root"));
   }
@@ -726,18 +726,18 @@ nsNSSComponent::UnloadFamilySafetyRoot()
   // It would be intuitive to set the trust to { 0, 0, 0 } here. However, this
   // doesn't work for temporary certificates because CERT_ChangeCertTrust first
   // looks up the current trust settings in the permanent cert database, finds
   // that such trust doesn't exist, considers the current trust to be
   // { 0, 0, 0 }, and decides that it doesn't need to update the trust since
   // 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"));
   }
   mFamilySafetyRoot = nullptr;
 }
 
 #endif // XP_WIN
 
@@ -869,17 +869,19 @@ nsNSSComponent::UnloadEnterpriseRoots(co
   CERTCertTrust trust = { CERTDB_USER, 0, 0 };
   for (CERTCertListNode* n = CERT_LIST_HEAD(mEnterpriseRoots.get());
        !CERT_LIST_END(n, mEnterpriseRoots.get()); n = CERT_LIST_NEXT(n)) {
     if (!n || !n->cert) {
       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
               ("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"));
     }
   }
   mEnterpriseRoots = nullptr;
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("unloaded enterprise roots"));
 }
 
@@ -1030,18 +1032,18 @@ nsNSSComponent::ImportEnterpriseRootsFor
     if (!mEnterpriseRoots) {
       return;
     }
     if (CERT_AddCertToListTail(mEnterpriseRoots.get(), nssCertificate.get())
           != SECSuccess) {
       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"));
     }
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Imported '%s'", subjectName.get()));
     numImported++;
     // now owned by mEnterpriseRoots
     Unused << nssCertificate.release();
   }
copy from security/manager/ssl/tests/unit/test_certDB_import.js
copy to security/manager/ssl/tests/unit/test_certDB_import_with_master_password.js
--- a/security/manager/ssl/tests/unit/test_certDB_import.js
+++ b/security/manager/ssl/tests/unit/test_certDB_import_with_master_password.js
@@ -1,22 +1,22 @@
 // -*- 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 the various nsIX509CertDB import methods.
+// 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";
-const TEST_EMAIL_ADDRESS = "test@example.com";
 
 let gCACertImportDialogCount = 0;
 
 // Mock implementation of nsICertificateDialogs.
 const gCertificateDialogs = {
   confirmDownloadCACert: (ctx, cert, trust) => {
     gCACertImportDialogCount++;
     equal(cert.commonName, CA_CERT_COMMON_NAME,
@@ -35,24 +35,41 @@ const gCertificateDialogs = {
   viewCert: (ctx, cert) => {
     // This shouldn't be called for import methods.
     ok(false, "viewCert() should not have been called");
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs])
 };
 
-// Implements nsIInterfaceRequestor. Mostly serves to mock nsIPrompt.
-const gInterfaceRequestor = {
-  alert: (title, text) => {
-    // We don't test anything that calls this method yet.
-    ok(false, `alert() should not have been called: ${text}`);
+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;
   },
 
-  getInterface: iid => {
+  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);
   }
 };
 
@@ -74,55 +91,40 @@ function findCertByCommonName(commonName
     let cert = certEnumerator.getNext().QueryInterface(Ci.nsIX509Cert);
     if (cert.commonName == commonName) {
       return cert;
     }
   }
   return null;
 }
 
-function testImportCACert() {
+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.
   equal(findCertByCommonName(CA_CERT_COMMON_NAME), null,
         "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,
-                             gInterfaceRequestor);
+                             gMockPrompter);
   equal(gCACertImportDialogCount, 1,
         "Confirmation dialog for the CA cert should only be shown once");
 
   let caCert = findCertByCommonName(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");
 }
-
-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);
-  do_register_cleanup(() => {
-    MockRegistrar.unregister(certificateDialogsCID);
-  });
-
-  // Sanity check the e-mail cert is missing.
-  throws(() => gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS),
-         /NS_ERROR_FAILURE/,
-         "E-mail cert should not be in the database before import");
-
-  // Import the CA cert so that the e-mail import succeeds.
-  testImportCACert();
-
-  // Import the e-mail cert and check for success.
-  let emailArray = getCertAsByteArray("test_certDB_import/emailEE.pem");
-  gCertDB.importEmailCertificate(emailArray, emailArray.length,
-                                 gInterfaceRequestor);
-  notEqual(gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS), null,
-           "E-mail cert should now be found in the database");
-}
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -58,16 +58,17 @@ run-sequentially = hardcoded ports
 [test_cert_override_bits_mismatches.js]
 run-sequentially = hardcoded ports
 [test_cert_sha1.js]
 [test_cert_signatures.js]
 [test_cert_trust.js]
 [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]
 [test_content_signing.js]
 [test_ct.js]
 # Requires hard-coded debug-only data
 skip-if = !debug
 run-sequentially = hardcoded ports