bug 1382866 - prompt for authentication when changing certificate trust fails r?Cykesiopka,jcj draft
authorDavid Keeler <dkeeler@mozilla.com>
Fri, 21 Jul 2017 16:58:42 -0700
changeset 616104 e8b27722714781e7cef6a2b20a522e55ac44bdaa
parent 614262 60a5308fa987676fa5ed9fd5b3ad6c9938af0539
child 639380 2c9053c39806409101e79c551bfe2e98837bc7fc
push id70586
push userbmo:dkeeler@mozilla.com
push dateWed, 26 Jul 2017 18:21:37 +0000
reviewersCykesiopka, jcj
bugs1382866
milestone56.0a1
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