Bug 1250258 - Partially clean up nsNSSCertificateDB.cpp import methods. r=keeler draft
authorCykesiopka <cykesiopka.bmo@gmail.com>
Wed, 16 Mar 2016 03:54:26 -0700
changeset 340998 b3b70150a6b5390fd1db91338159fd71f1a2bccc
parent 340835 e9a5d52d88dd6226871c6adeae8a48b003074ab8
child 516313 fc1b318347c8e3ea0fb7be5ca7da34bb3b279fc6
push id13115
push usercykesiopka.bmo@gmail.com
push dateWed, 16 Mar 2016 10:55:41 +0000
reviewerskeeler
bugs1250258
milestone48.0a1
Bug 1250258 - Partially clean up nsNSSCertificateDB.cpp import methods. r=keeler MozReview-Commit-ID: Dbk5N1FwdWB
security/manager/ssl/ScopedNSSTypes.h
security/manager/ssl/nsNSSCertificateDB.cpp
security/manager/ssl/nsNSSCertificateDB.h
security/manager/ssl/tests/unit/head_psm.js
security/manager/ssl/tests/unit/moz.build
security/manager/ssl/tests/unit/test_certDB_import.js
security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem
security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem.certspec
security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem
security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem.certspec
security/manager/ssl/tests/unit/test_certDB_import/moz.build
security/manager/ssl/tests/unit/test_sdr.js
security/manager/ssl/tests/unit/xpcshell.ini
--- a/security/manager/ssl/ScopedNSSTypes.h
+++ b/security/manager/ssl/ScopedNSSTypes.h
@@ -321,19 +321,25 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLAT
 // Emulates MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE, but for UniquePtrs.
 #define MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(name, Type, Deleter) \
 struct name##DeletePolicy \
 { \
   void operator()(Type* aValue) { Deleter(aValue); } \
 }; \
 typedef UniquePtr<Type, name##DeletePolicy> name;
 
+MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificate,
+                                      CERTCertificate,
+                                      CERT_DestroyCertificate)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificatePolicies,
                                       CERTCertificatePolicies,
                                       CERT_DestroyCertificatePoliciesExtension)
+MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertList,
+                                      CERTCertList,
+                                      CERT_DestroyCertList)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertNicknames,
                                       CERTCertNicknames,
                                       CERT_FreeNicknames)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTOidSequence,
                                       CERTOidSequence,
                                       CERT_DestroyOidSequence)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTUserNotice,
                                       CERTUserNotice,
@@ -361,14 +367,15 @@ MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(Un
                                       SECItem,
                                       internal::SECITEM_FreeItem_true)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPublicKey,
                                       SECKEYPublicKey,
                                       SECKEY_DestroyPublicKey)
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECMODModule,
                                       SECMODModule,
                                       SECMOD_DestroyModule)
+
 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueVFYContext,
                                       VFYContext,
                                       internal::VFY_DestroyContext_true)
 } // namespace mozilla
 
 #endif // mozilla_ScopedNSSTypes_h
--- a/security/manager/ssl/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/nsNSSCertificateDB.cpp
@@ -2,47 +2,47 @@
  * 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/. */
 
 // XXX: This must be done prior to including cert.h (directly or indirectly).
 // CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm, but it is
 // only exported so PSM can use it for this specific purpose.
 #define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
 
-#include "nsNSSComponent.h"
 #include "nsNSSCertificateDB.h"
 
 #include "CertVerifier.h"
 #include "ExtendedValidation.h"
 #include "NSSCertDBTrustDomain.h"
-#include "pkix/pkixtypes.h"
-#include "pkix/Time.h"
-#include "nsNSSComponent.h"
+#include "SharedSSLState.h"
 #include "mozilla/Base64.h"
+#include "mozilla/unused.h"
+#include "nsArrayUtils.h"
 #include "nsCOMPtr.h"
+#include "nsCRT.h"
+#include "nsComponentManagerUtils.h"
+#include "nsICertificateDialogs.h"
+#include "nsIFile.h"
+#include "nsIMutableArray.h"
+#include "nsIObserverService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "nsIPrompt.h"
+#include "nsNSSCertHelper.h"
+#include "nsNSSCertTrust.h"
 #include "nsNSSCertificate.h"
+#include "nsNSSComponent.h"
 #include "nsNSSHelper.h"
-#include "nsNSSCertHelper.h"
-#include "nsCRT.h"
-#include "nsICertificateDialogs.h"
-#include "nsNSSCertTrust.h"
-#include "nsIFile.h"
+#include "nsNSSShutDown.h"
+#include "nsPK11TokenDB.h"
 #include "nsPKCS12Blob.h"
-#include "nsPK11TokenDB.h"
 #include "nsReadableUtils.h"
-#include "nsIMutableArray.h"
-#include "nsArrayUtils.h"
-#include "nsNSSShutDown.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIPrompt.h"
 #include "nsThreadUtils.h"
-#include "nsIObserverService.h"
-#include "SharedSSLState.h"
+#include "pkix/Time.h"
+#include "pkix/pkixtypes.h"
 
 #include "nspr.h"
 #include "certdb.h"
 #include "secerr.h"
 #include "nssb64.h"
 #include "secasn1.h"
 #include "secder.h"
 #include "ssl.h"
@@ -220,31 +220,31 @@ collect_certs(void *arg, SECItem **certs
     cert++;
     certs++;
   }
 
   return (SECSuccess);
 }
 
 CERTDERCerts*
-nsNSSCertificateDB::getCertsFromPackage(PLArenaPool *arena, uint8_t *data, 
-                                        uint32_t length,
-                                        const nsNSSShutDownPreventionLock &/*proofOfLock*/)
+nsNSSCertificateDB::getCertsFromPackage(const UniquePLArenaPool& arena,
+                                        uint8_t* data, uint32_t length,
+                                        const nsNSSShutDownPreventionLock& /*proofOfLock*/)
 {
-  CERTDERCerts *collectArgs = 
-               (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
-  if (!collectArgs)
+  CERTDERCerts* collectArgs =
+    (CERTDERCerts*)PORT_ArenaZAlloc(arena.get(), sizeof(CERTDERCerts));
+  if (!collectArgs) {
     return nullptr;
+  }
 
-  collectArgs->arena = arena;
-  SECStatus sec_rv = CERT_DecodeCertPackage(reinterpret_cast<char *>(data), 
-                                            length, collect_certs, 
-                                            (void *)collectArgs);
-  if (sec_rv != SECSuccess)
+  collectArgs->arena = arena.get();
+  if (CERT_DecodeCertPackage(char_ptr_cast(data), length, collect_certs,
+                             collectArgs) != SECSuccess) {
     return nullptr;
+  }
 
   return collectArgs;
 }
 
 nsresult
 nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs,
                                          nsIInterfaceRequestor *ctx,
                                          const nsNSSShutDownPreventionLock &proofOfLock)
@@ -385,17 +385,17 @@ nsNSSCertificateDB::handleCACertDownload
                                            trust.GetTrust());
 
   if (srv != SECSuccess)
     return NS_ERROR_FAILURE;
 
   // Import additional delivered certificates that can be verified.
 
   // build a CertList for filtering
-  ScopedCERTCertList certList(CERT_NewCertList());
+  UniqueCERTCertList certList(CERT_NewCertList());
   if (!certList) {
     return NS_ERROR_FAILURE;
   }
 
   // get all remaining certs into temp store
 
   for (uint32_t i=0; i<numCerts; i++) {
     if (i == selCertIndex) {
@@ -412,85 +412,150 @@ nsNSSCertificateDB::handleCACertDownload
     free(der.data);
     der.data = nullptr;
     der.len = 0;
 
     if (!tmpCert2) {
       NS_ERROR("Couldn't create temp cert from DER blob");
       continue;  // Let's try to import the rest of 'em
     }
-    
+
     CERT_AddCertToListTail(certList.get(), tmpCert2);
   }
 
-  return ImportValidCACertsInList(certList.get(), ctx, proofOfLock);
+  return ImportValidCACertsInList(certList, ctx, proofOfLock);
 }
 
-NS_IMETHODIMP 
-nsNSSCertificateDB::ImportCertificates(uint8_t * data, uint32_t length, 
-                                       uint32_t type, 
-                                       nsIInterfaceRequestor *ctx)
-
+NS_IMETHODIMP
+nsNSSCertificateDB::ImportCertificates(uint8_t* data, uint32_t length,
+                                       uint32_t type,
+                                       nsIInterfaceRequestor* ctx)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  nsresult nsrv;
-
-  PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-  if (!arena)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
-  if (!certCollection) {
-    PORT_FreeArena(arena, false);
+  // We currently only handle CA certificates.
+  if (type != nsIX509Cert::CA_CERT) {
     return NS_ERROR_FAILURE;
   }
-  nsCOMPtr<nsIMutableArray> array =
-    do_CreateInstance(NS_ARRAY_CONTRACTID, &nsrv);
-  if (NS_FAILED(nsrv)) {
-    PORT_FreeArena(arena, false);
-    return nsrv;
+
+  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+  if (!arena) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  CERTDERCerts* certCollection = getCertsFromPackage(arena, data, length,
+                                                     locker);
+  if (!certCollection) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
   // Now let's create some certs to work with
-  nsCOMPtr<nsIX509Cert> x509Cert;
-  nsNSSCertificate *nssCert;
-  SECItem *currItem;
-  for (int i=0; i<certCollection->numcerts; i++) {
-     currItem = &certCollection->rawCerts[i];
-     nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len);
-     if (!nssCert)
-       return NS_ERROR_FAILURE;
-     x509Cert = do_QueryInterface((nsIX509Cert*)nssCert);
-     array->AppendElement(x509Cert, false);
+  for (int i = 0; i < certCollection->numcerts; i++) {
+    SECItem* currItem = &certCollection->rawCerts[i];
+    nsCOMPtr<nsIX509Cert> cert =
+      nsNSSCertificate::ConstructFromDER(reinterpret_cast<char*>(currItem->data),
+                                         currItem->len);
+    if (!cert) {
+      return NS_ERROR_FAILURE;
+    }
+    rv = array->AppendElement(cert, false);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
   }
-  switch (type) {
-  case nsIX509Cert::CA_CERT:
-    nsrv = handleCACertDownload(array, ctx, locker);
-    break;
-  default:
-    // We only deal with import CA certs in this method currently.
-     nsrv = NS_ERROR_FAILURE;
-     break;
-  }  
-  PORT_FreeArena(arena, false);
-  return nsrv;
+
+  return handleCACertDownload(array, ctx, locker);
 }
 
-static 
-SECStatus 
-ImportCertsIntoPermanentStorage(
-  const ScopedCERTCertList& certChain,
-  const SECCertUsage usage, const PRBool caOnly)
+/**
+ * Filters an array of certs by usage and imports them into temporary storage.
+ *
+ * @param numcerts
+ *        Size of the |certs| array.
+ * @param certs
+ *        Pointer to array of certs to import.
+ * @param usage
+ *        Usage the certs should be filtered on.
+ * @param caOnly
+ *        Whether to import only CA certs.
+ * @param filteredCerts
+ *        List of certs that weren't filtered out and were successfully imported.
+ */
+static nsresult
+ImportCertsIntoTempStorage(int numcerts, SECItem* certs,
+                           const SECCertUsage usage, const bool caOnly,
+                           const nsNSSShutDownPreventionLock& /*proofOfLock*/,
+                   /*out*/ const UniqueCERTCertList& filteredCerts)
 {
-  CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
+  NS_ENSURE_ARG_MIN(numcerts, 1);
+  NS_ENSURE_ARG_POINTER(certs);
+  NS_ENSURE_ARG_POINTER(filteredCerts.get());
+
+  // CERT_ImportCerts() expects an array of *pointers* to SECItems, so we have
+  // to convert |certs| to such a format first.
+  SECItem** ptrArray =
+    static_cast<SECItem**>(PORT_Alloc(sizeof(SECItem*) * numcerts));
+  if (!ptrArray) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  for (int i = 0; i < numcerts; i++) {
+    ptrArray[i] = &certs[i];
+  }
+
+  CERTCertificate** importedCerts = nullptr;
+  SECStatus srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), usage,
+                                   numcerts, ptrArray, &importedCerts, false,
+                                   caOnly, nullptr);
+  PORT_Free(ptrArray);
+  ptrArray = nullptr;
+  if (srv != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
 
+  for (int i = 0; i < numcerts; i++) {
+    if (!importedCerts[i]) {
+      continue;
+    }
+
+    UniqueCERTCertificate cert(CERT_DupCertificate(importedCerts[i]));
+    if (!cert) {
+      continue;
+    }
+
+    if (CERT_AddCertToListTail(filteredCerts.get(), cert.get()) == SECSuccess) {
+      Unused << cert.release();
+    }
+  }
+
+  CERT_DestroyCertArray(importedCerts, numcerts);
+
+  // CERT_ImportCerts() ignores its |usage| parameter, so we have to manually
+  // filter out unwanted certs.
+  if (CERT_FilterCertListByUsage(filteredCerts.get(), usage, caOnly)
+        != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+static SECStatus
+ImportCertsIntoPermanentStorage(const ScopedCERTCertList& certChain,
+                                const SECCertUsage usage, const bool caOnly)
+{
   int chainLen = 0;
   for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain);
        !CERT_LIST_END(chainNode, certChain);
        chainNode = CERT_LIST_NEXT(chainNode)) {
     chainLen++;
   }
 
   SECItem **rawArray;
@@ -500,207 +565,125 @@ ImportCertsIntoPermanentStorage(
   }
 
   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(certdb, usage, chainLen, rawArray,
-                                   nullptr, true, caOnly, nullptr);
+  SECStatus srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), usage, chainLen,
+                                   rawArray, nullptr, true, caOnly, nullptr);
 
   PORT_Free(rawArray);
   return srv;
-} 
-
+}
 
 NS_IMETHODIMP
-nsNSSCertificateDB::ImportEmailCertificate(uint8_t * data, uint32_t length, 
-                                       nsIInterfaceRequestor *ctx)
-
+nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length,
+                                           nsIInterfaceRequestor* ctx)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  SECStatus srv = SECFailure;
-  nsresult nsrv = NS_OK;
-  CERTCertDBHandle *certdb;
-  CERTCertificate **certArray = nullptr;
-  ScopedCERTCertList certList;
-  CERTCertListNode *node;
-  SECItem **rawArray;
-  int numcerts;
-  int i;
-
-  PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-  if (!arena)
+  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+  if (!arena) {
     return NS_ERROR_OUT_OF_MEMORY;
+  }
 
   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
   if (!certCollection) {
-    PORT_FreeArena(arena, false);
+    return NS_ERROR_FAILURE;
+  }
+
+  UniqueCERTCertList filteredCerts(CERT_NewCertList());
+  if (!filteredCerts) {
     return NS_ERROR_FAILURE;
   }
 
+  nsresult rv = ImportCertsIntoTempStorage(certCollection->numcerts,
+                                           certCollection->rawCerts,
+                                           certUsageEmailRecipient,
+                                           false, locker, filteredCerts);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
-  NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
-
-  certdb = CERT_GetDefaultCertDB();
-
-  numcerts = certCollection->numcerts;
-
-  rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
-  if ( !rawArray ) {
-    nsrv = NS_ERROR_FAILURE;
-    goto loser;
-  }
-
-  for (i=0; i < numcerts; i++) {
-    rawArray[i] = &certCollection->rawCerts[i];
+  if (!certVerifier) {
+    return NS_ERROR_UNEXPECTED;
   }
 
-  srv = CERT_ImportCerts(certdb, certUsageEmailRecipient, numcerts, rawArray,
-                         &certArray, false, false, nullptr);
-
-  PORT_Free(rawArray);
-  rawArray = nullptr;
-
-  if (srv != SECSuccess) {
-    nsrv = NS_ERROR_FAILURE;
-    goto loser;
-  }
-
-  // build a CertList for filtering
-  certList = CERT_NewCertList();
-  if (!certList) {
-    nsrv = NS_ERROR_FAILURE;
-    goto loser;
-  }
-  for (i=0; i < numcerts; i++) {
-    CERTCertificate *cert = certArray[i];
-    if (cert)
-      cert = CERT_DupCertificate(cert);
-    if (cert)
-      CERT_AddCertToListTail(certList.get(), cert);
-  }
-
-  /* go down the remaining list of certs and verify that they have
-   * valid chains, then import them.
-   */
-
-  for (node = CERT_LIST_HEAD(certList);
-       !CERT_LIST_END(node,certList);
+  // Iterate through the filtered cert list and import verified certs into
+  // permanent storage.
+  // Note: We verify the certs in order to prevent DoS attacks. See Bug 249004.
+  for (CERTCertListNode* node = CERT_LIST_HEAD(filteredCerts.get());
+       !CERT_LIST_END(node, filteredCerts.get());
        node = CERT_LIST_NEXT(node)) {
-
     if (!node->cert) {
       continue;
     }
 
     ScopedCERTCertList certChain;
-
-    SECStatus rv = certVerifier->VerifyCert(node->cert,
-                                            certificateUsageEmailRecipient,
-                                            mozilla::pkix::Now(), ctx,
-                                            nullptr, certChain);
-
-    if (rv != SECSuccess) {
+    SECStatus srv = certVerifier->VerifyCert(node->cert,
+                                             certificateUsageEmailRecipient,
+                                             mozilla::pkix::Now(), ctx,
+                                             nullptr, certChain);
+    if (srv != SECSuccess) {
       nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
       DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker);
       continue;
     }
-    rv = ImportCertsIntoPermanentStorage(certChain, certUsageEmailRecipient,
-                                         false);
-    if (rv != SECSuccess) {
-      goto loser;
-    } 
+    srv = ImportCertsIntoPermanentStorage(certChain, certUsageEmailRecipient,
+                                          false);
+    if (srv != SECSuccess) {
+      return NS_ERROR_FAILURE;
+    }
     CERT_SaveSMimeProfile(node->cert, nullptr, nullptr);
-
   }
 
-loser:
-  if (certArray) {
-    CERT_DestroyCertArray(certArray, numcerts);
-  }
-  if (arena) 
-    PORT_FreeArena(arena, true);
-  return nsrv;
+  return NS_OK;
 }
 
 nsresult
-nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx,  const nsNSSShutDownPreventionLock &proofOfLock)
+nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem* caCerts,
+                                       nsIInterfaceRequestor* ctx,
+                                       const nsNSSShutDownPreventionLock& proofOfLock)
 {
-  ScopedCERTCertList certList;
-  SECItem **rawArray;
-
-  // build a CertList for filtering
-  certList = CERT_NewCertList();
-  if (!certList) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // get all certs into temp store
-  SECStatus srv = SECFailure;
-  CERTCertificate **certArray = nullptr;
-
-  rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numCACerts);
-  if ( !rawArray ) {
+  UniqueCERTCertList filteredCerts(CERT_NewCertList());
+  if (!filteredCerts) {
     return NS_ERROR_FAILURE;
   }
 
-  for (int i=0; i < numCACerts; i++) {
-    rawArray[i] = &CACerts[i];
+  nsresult rv = ImportCertsIntoTempStorage(numCACerts, caCerts, certUsageAnyCA,
+                                           true, proofOfLock, filteredCerts);
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
-  srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, numCACerts, rawArray, 
-                         &certArray, false, true, nullptr);
-
-  PORT_Free(rawArray);
-  rawArray = nullptr;
-
-  if (srv != SECSuccess) {
-    return NS_ERROR_FAILURE;
-  }
-
-  for (int i2=0; i2 < numCACerts; i2++) {
-    CERTCertificate *cacert = certArray[i2];
-    if (cacert)
-      cacert = CERT_DupCertificate(cacert);
-    if (cacert)
-      CERT_AddCertToListTail(certList, cacert);
-  }
-
-  CERT_DestroyCertArray(certArray, numCACerts);
-
-  return ImportValidCACertsInList(certList, ctx, proofOfLock);
+  return ImportValidCACertsInList(filteredCerts, ctx, proofOfLock);
 }
 
 nsresult
-nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx,
-                                             const nsNSSShutDownPreventionLock &proofOfLock)
+nsNSSCertificateDB::ImportValidCACertsInList(const UniqueCERTCertList& filteredCerts,
+                                             nsIInterfaceRequestor* ctx,
+                                             const nsNSSShutDownPreventionLock& proofOfLock)
 {
   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
-  if (!certVerifier)
+  if (!certVerifier) {
     return NS_ERROR_UNEXPECTED;
-
-  /* filter out the certs we don't want */
-  SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, true);
-  if (srv != SECSuccess) {
-    return NS_ERROR_FAILURE;
   }
 
-  /* go down the remaining list of certs and verify that they have
-   * valid chains, if yes, then import.
-   */
-  CERTCertListNode *node;
-
-  for (node = CERT_LIST_HEAD(certList);
-       !CERT_LIST_END(node,certList);
+  // Iterate through the filtered cert list and import verified certs into
+  // permanent storage.
+  // Note: We verify the certs in order to prevent DoS attacks. See Bug 249004.
+  for (CERTCertListNode* node = CERT_LIST_HEAD(filteredCerts.get());
+       !CERT_LIST_END(node, filteredCerts.get());
        node = CERT_LIST_NEXT(node)) {
     ScopedCERTCertList certChain;
     SECStatus rv = certVerifier->VerifyCert(node->cert,
                                             certificateUsageVerifyCA,
                                             mozilla::pkix::Now(), ctx,
                                             nullptr, certChain);
     if (rv != SECSuccess) {
       nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
@@ -708,17 +691,17 @@ nsNSSCertificateDB::ImportValidCACertsIn
       continue;
     }
 
     rv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true);
     if (rv != SECSuccess) {
       return NS_ERROR_FAILURE;
     }
   }
-  
+
   return NS_OK;
 }
 
 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx, 
                                                  const char *stringID, 
                                                  nsIX509Cert *certToShow,
                                                  const nsNSSShutDownPreventionLock &/*proofOfLock*/)
 {
@@ -747,101 +730,82 @@ void nsNSSCertificateDB::DisplayCertific
     if (!prompt) {
       return;
     }
 
     prompt->Alert(nullptr, tmpMessage.get());
   }
 }
 
-
-NS_IMETHODIMP 
-nsNSSCertificateDB::ImportUserCertificate(uint8_t *data, uint32_t length, nsIInterfaceRequestor *ctx)
+NS_IMETHODIMP
+nsNSSCertificateDB::ImportUserCertificate(uint8_t* data, uint32_t length,
+                                          nsIInterfaceRequestor* ctx)
 {
   if (!NS_IsMainThread()) {
     NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread");
     return NS_ERROR_NOT_SAME_THREAD;
   }
-  
+
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  ScopedPK11SlotInfo slot;
-  nsAutoCString nickname;
-  nsresult rv = NS_ERROR_FAILURE;
-  int numCACerts;
-  SECItem *CACerts;
-  CERTDERCerts * collectArgs;
-  PLArenaPool *arena;
-  ScopedCERTCertificate cert;
-
-  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
   if (!arena) {
-    goto loser;
+    return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  collectArgs = getCertsFromPackage(arena, data, length, locker);
+  CERTDERCerts* collectArgs = getCertsFromPackage(arena, data, length, locker);
   if (!collectArgs) {
-    goto loser;
+    return NS_ERROR_FAILURE;
   }
 
-  cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
-                                 nullptr, false, true);
+  UniqueCERTCertificate cert(
+    CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
+                            nullptr, false, true));
   if (!cert) {
-    goto loser;
+    return NS_ERROR_FAILURE;
   }
 
-  slot = PK11_KeyForCertExists(cert.get(), nullptr, ctx);
+  UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert.get(), nullptr, ctx));
   if (!slot) {
     nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
     DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker);
-    goto loser;
+    return NS_ERROR_FAILURE;
   }
   slot = nullptr;
 
   /* pick a nickname for the cert */
+  nsAutoCString nickname;
   if (cert->nickname) {
-	/* sigh, we need a call to look up other certs with this subject and
-	 * identify nicknames from them. We can no longer walk down internal
-	 * database structures  rjr */
-  	nickname = cert->nickname;
-  }
-  else {
+    nickname = cert->nickname;
+  } else {
     get_default_nickname(cert.get(), ctx, nickname, locker);
   }
 
   /* user wants to import the cert */
-  {
-    char *cast_const_away = const_cast<char*>(nickname.get());
-    slot = PK11_ImportCertForKey(cert.get(), cast_const_away, ctx);
-  }
+  slot.reset(PK11_ImportCertForKey(cert.get(), nickname.get(), ctx));
   if (!slot) {
-    goto loser;
+    return NS_ERROR_FAILURE;
   }
   slot = nullptr;
 
   {
     nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
     DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker);
   }
-  rv = NS_OK;
 
-  numCACerts = collectArgs->numcerts - 1;
+  int numCACerts = collectArgs->numcerts - 1;
   if (numCACerts) {
-    CACerts = collectArgs->rawCerts+1;
-    rv = ImportValidCACerts(numCACerts, CACerts, ctx, locker);
+    SECItem* caCerts = collectArgs->rawCerts + 1;
+    return ImportValidCACerts(numCACerts, caCerts, ctx, locker);
   }
-  
-loser:
-  if (arena) {
-    PORT_FreeArena(arena, false);
-  }
-  return rv;
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
 {
   NS_ENSURE_ARG_POINTER(aCert);
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
--- a/security/manager/ssl/nsNSSCertificateDB.h
+++ b/security/manager/ssl/nsNSSCertificateDB.h
@@ -6,16 +6,17 @@
 #define nsNSSCertificateDB_h
 
 #include "certt.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "nsIX509CertDB.h"
 #include "nsNSSShutDown.h"
+#include "ScopedNSSTypes.h"
 
 class nsCString;
 class nsIArray;
 
 class nsNSSCertificateDB final : public nsIX509CertDB
                                , public nsNSSShutDownObject
 
 {
@@ -35,26 +36,27 @@ public:
                      const nsNSSShutDownPreventionLock &proofOfLock);
 
 protected:
   virtual ~nsNSSCertificateDB();
 
 private:
 
   static nsresult
-  ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx,
-                           const nsNSSShutDownPreventionLock &proofOfLock);
+  ImportValidCACertsInList(const mozilla::UniqueCERTCertList& filteredCerts,
+                           nsIInterfaceRequestor* ctx,
+                           const nsNSSShutDownPreventionLock& proofOfLock);
 
   static void DisplayCertificateAlert(nsIInterfaceRequestor *ctx, 
                                       const char *stringID, nsIX509Cert *certToShow,
                                       const nsNSSShutDownPreventionLock &proofOfLock);
 
-  CERTDERCerts *getCertsFromPackage(PLArenaPool *arena, uint8_t *data, 
-                                    uint32_t length,
-                                    const nsNSSShutDownPreventionLock &proofOfLock);
+  CERTDERCerts* getCertsFromPackage(const mozilla::UniquePLArenaPool& arena,
+                                    uint8_t* data, uint32_t length,
+                                    const nsNSSShutDownPreventionLock& proofOfLock);
   nsresult handleCACertDownload(nsIArray *x509Certs, 
                                 nsIInterfaceRequestor *ctx,
                                 const nsNSSShutDownPreventionLock &proofOfLock);
 
   // We don't own any NSS objects here, so no need to clean up
   virtual void virtualDestroyNSSReference() override { };
 };
 
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -700,8 +700,16 @@ function attempt_adding_cert_override(aH
 // subsequent connection succeeding (i.e. the same error code is encountered).
 // The idea here is that for HSTS hosts or hosts with key pins, no error is
 // overridable, even if an entry is added to the override service.
 function add_prevented_cert_override_test(aHost, aExpectedBits, aExpectedError) {
   add_connection_test(aHost, aExpectedError, null,
                       attempt_adding_cert_override.bind(this, aHost, aExpectedBits));
   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);
+}
--- a/security/manager/ssl/tests/unit/moz.build
+++ b/security/manager/ssl/tests/unit/moz.build
@@ -14,16 +14,17 @@ TEST_DIRS += [
     'ocsp_certs',
     'test_cert_eku',
     'test_cert_embedded_null',
     'test_cert_keyUsage',
     'test_cert_sha1',
     'test_cert_signatures',
     'test_cert_trust',
     'test_cert_version',
+    'test_certDB_import',
     'test_ev_certs',
     'test_getchain',
     'test_intermediate_basic_usage_constraints',
     'test_keysize',
     'test_keysize_ev',
     'test_name_constraints',
     'test_ocsp_fetch_method',
     'test_ocsp_url',
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import.js
@@ -0,0 +1,118 @@
+// -*- 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.
+
+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,
+          "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])
+};
+
+// 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}`);
+  },
+
+  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 testImportCACert() {
+  // 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,
+                             gInterfaceRequestor);
+  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");
+}
+
+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");
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUP71Va37c54kapFAS+PSgTI+oHhQwCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCmltcG9ydGVkQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3
+MDIwNDAwMDAwMFowITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAATALBgkqhkiG9w0BAQsDggEBAEJPROEDLfrf3huYWfh6ejaAV2DWQjXK7Bj5
+zvprH1yx2j9CnlLf0HRknTRSsfgb4JWOc3gKtiBLk2WjI6etp4JiRdn+fadA5LXV
+a0KfJiztdsbjzFADvRUy43z2aX16mcT0qy+FXMyE+50AHV79y2YlXDYsQHuteJDy
+7S3lVU/weE/tSNC9DatdcSP8vCecgzTiDu20qbYMbBXq+2zFRCk+/3Y58k3ps66H
+z5IvQC8ddDwUbn+bD1ULeR0WIap9Zt+nap5GiCZVpekdWfSNX/k9QZjlt5aC671L
+Wq/5qSnOS1Y2onCnZ/ZP68UBsU9fSAX7jbiryCtPdMJRSnGFzEk=
+-----END CERTIFICATE-----
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem.certspec
@@ -0,0 +1,2 @@
+issuer:importedCA
+subject:/emailAddress=test@example.com
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyDCCAbKgAwIBAgIURx1jxEZp5WQaQO8kyUnTTK/e/E8wCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCmltcG9ydGVkQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3
+MDIwNDAwMDAwMFowFTETMBEGA1UEAwwKaW1wb3J0ZWRDQTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
+bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
+OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
+uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
+t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
+NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zALBgkqhkiG9w0BAQsDggEBACVHxcZWyN5G1GosA3lWVbsKCSmS
+JJg8z7fPFoHfQncSyuMQwI9D01a2XYjNjHB1QUz9N4MlV3E4ieTWSwtSeRcHxV/g
+1tFCEbzKZLa3rCdyozyj+0ReLVhkXr+XBb731WAOvcybLuzAS6dJvoXq7TSZckbq
+hLhXDRrWlZVGzPAn6oaaSAn3dcD8BTDwzyTZ8HaDzyUnwottzl8Ik29G6o3cqkAQ
+SDscNpP+DgZXZJA6HmpT6jCad4E/Y103ExipG70bhT0D2khT/0f06YuVbwsZqAc5
+mSm90y3NLjTORW1DQ3A8M86auq7O+oLMh6lLbtR/x6NMxMDHzmLWnqXOFh4=
+-----END CERTIFICATE-----
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem.certspec
@@ -0,0 +1,3 @@
+issuer:importedCA
+subject:importedCA
+extension:basicConstraints:cA,
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+# Temporarily disabled. See Bug 1256495.
+#test_certificates = (
+#    'emailEE.pem',
+#    'importedCA.pem',
+#)
+#
+#for test_certificate in test_certificates:
+#    GeneratedTestCertificate(test_certificate)
--- a/security/manager/ssl/tests/unit/test_sdr.js
+++ b/security/manager/ssl/tests/unit/test_sdr.js
@@ -24,21 +24,17 @@ const gTokenPasswordDialogs = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsITokenPasswordDialogs])
 };
 
 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.
-  let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
-                  .getService(Ci.nsIPK11TokenDB);
-  let token = tokenDB.getInternalKeyToken();
-  token.initPassword("");
-  token.login(/*force*/ false);
+  loginToDBWithDefaultPassword();
 
   let sdr = Cc["@mozilla.org/security/sdr;1"]
               .getService(Ci.nsISecretDecoderRing);
 
   // Test valid inputs for encryptString() and decryptString().
   let inputs = [
     "",
     "foo",
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -6,16 +6,17 @@ support-files =
   ocsp_common/**
   test_cert_eku/**
   test_cert_embedded_null/**
   test_cert_keyUsage/**
   test_cert_sha1/**
   test_cert_signatures/**
   test_cert_trust/**
   test_cert_version/**
+  test_certDB_import/**
   test_certviewer_invalid_oids/**
   test_ev_certs/**
   test_getchain/**
   test_intermediate_basic_usage_constraints/**
   test_keysize/**
   test_keysize_ev/**
   test_name_constraints/**
   test_ocsp_fetch_method/**
@@ -40,16 +41,17 @@ run-sequentially = hardcoded ports
 [test_cert_overrides.js]
 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_certviewer_invalid_oids.js]
 skip-if = toolkit == 'android' || buildapp == 'b2g'
 [test_constructX509FromBase64.js]
 [test_datasignatureverifier.js]
 [test_ev_certs.js]
 run-sequentially = hardcoded ports
 [test_getchain.js]
 [test_hash_algorithms.js]