Bug 1580304 - Remove nsNSSCertList/nsIX509CertList r=keeler
authorSean Feng <sefeng@mozilla.com>
Fri, 22 Nov 2019 19:25:31 +0000
changeset 503415 2aaf1c7b7f1c2e6b6b9a8ab3880fe7acacf0a3f1
parent 503414 2c912e46295e4f8a3fa5824a7f378e06760ec7dd
child 503416 436e3e84cb9e70beeac8c46a35c4f7e997cb85fb
push id36834
push usernbeleuzu@mozilla.com
push dateSat, 23 Nov 2019 09:47:42 +0000
treeherdermozilla-central@cf114f3b7494 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs1580304
milestone72.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 1580304 - Remove nsNSSCertList/nsIX509CertList r=keeler nsNSSCertList/nsIX509CertList are redundant, and also contructing them are expensive. so it is replaced by Array<nsIX509Cert> Differential Revision: https://phabricator.services.mozilla.com/D44245
security/apps/AppSignatureVerification.cpp
security/manager/ssl/SSLServerCertVerification.cpp
security/manager/ssl/TransportSecurityInfo.cpp
security/manager/ssl/TransportSecurityInfo.h
security/manager/ssl/components.conf
security/manager/ssl/moz.build
security/manager/ssl/nsINSSComponent.idl
security/manager/ssl/nsIX509CertList.idl
security/manager/ssl/nsNSSCertificate.cpp
security/manager/ssl/nsNSSCertificate.h
security/manager/ssl/nsNSSComponent.h
security/manager/ssl/nsNSSModule.cpp
security/manager/ssl/tests/gtest/CertListTest.cpp
security/manager/ssl/tests/gtest/DeserializeCertTest.cpp
security/manager/ssl/tests/unit/test_cert_chains.js
toolkit/components/downloads/DownloadCore.jsm
toolkit/components/securityreporter/SecurityReporter.jsm
--- a/security/apps/AppSignatureVerification.cpp
+++ b/security/apps/AppSignatureVerification.cpp
@@ -1277,17 +1277,16 @@ nsresult OpenSignedAppFile(AppTrustedRoo
   }
 
   // Return the reader to the caller if they want it
   if (aZipReader) {
     zip.forget(aZipReader);
   }
 
   // Return the signer's certificate to the reader if they want it.
-  // XXX: We should return an nsIX509CertList with the whole validated chain.
   if (aSignerCert) {
     // The COSE certificate is authoritative.
     if (aPolicy.COSERequired() || (coseCertItem && coseCertItem->len != 0)) {
       if (!coseCertItem || coseCertItem->len == 0) {
         return NS_ERROR_FAILURE;
       }
       CERTCertDBHandle* dbHandle = CERT_GetDefaultCertDB();
       if (!dbHandle) {
--- a/security/manager/ssl/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
@@ -454,17 +454,17 @@ static nsresult OverrideAllowedForHost(
 
 class SSLServerCertVerificationJob : public Runnable {
  public:
   // Must be called only on the socket transport thread
   static SECStatus Dispatch(const RefPtr<SharedCertVerifier>& certVerifier,
                             const void* fdForLogging,
                             TransportSecurityInfo* infoObject,
                             const UniqueCERTCertificate& serverCert,
-                            const UniqueCERTCertList& peerCertChain,
+                            UniqueCERTCertList& peerCertChain,
                             Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
                             Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
                             Maybe<DelegatedCredentialInfo>& dcInfo,
                             uint32_t providerFlags, Time time, PRTime prtime,
                             uint32_t certVerifierFlags);
 
  private:
   NS_DECL_NSIRUNNABLE
@@ -1145,41 +1145,34 @@ Result AuthCertificate(CertVerifier& cer
                             rv == Success);
   return rv;
 }
 
 /*static*/
 SECStatus SSLServerCertVerificationJob::Dispatch(
     const RefPtr<SharedCertVerifier>& certVerifier, const void* fdForLogging,
     TransportSecurityInfo* infoObject, const UniqueCERTCertificate& serverCert,
-    const UniqueCERTCertList& peerCertChain,
+    UniqueCERTCertList& peerCertChain,
     Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
     Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
     Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, Time time,
     PRTime prtime, uint32_t certVerifierFlags) {
   // Runs on the socket transport thread
   if (!certVerifier || !infoObject || !serverCert) {
     NS_ERROR("Invalid parameters for SSL server cert validation");
     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     return SECFailure;
   }
 
   if (!gCertVerificationThreadPool) {
     PR_SetError(PR_INVALID_STATE_ERROR, 0);
     return SECFailure;
   }
 
-  // Copy the certificate list so the runnable can take ownership of it in the
-  // constructor.
-  UniqueCERTCertList peerCertChainCopy =
-      nsNSSCertList::DupCertList(peerCertChain);
-  if (!peerCertChainCopy) {
-    PR_SetError(SEC_ERROR_NO_MEMORY, 0);
-    return SECFailure;
-  }
+  UniqueCERTCertList peerCertChainCopy = std::move(peerCertChain);
 
   RefPtr<SSLServerCertVerificationJob> job(new SSLServerCertVerificationJob(
       certVerifier, fdForLogging, infoObject, serverCert,
       std::move(peerCertChainCopy), stapledOCSPResponse, sctsFromTLSExtension,
       dcInfo, providerFlags, time, prtime, certVerifierFlags));
 
   nsresult nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
   if (NS_FAILED(nrv)) {
--- a/security/manager/ssl/TransportSecurityInfo.cpp
+++ b/security/manager/ssl/TransportSecurityInfo.cpp
@@ -450,61 +450,16 @@ nsresult TransportSecurityInfo::ReadCert
       return NS_ERROR_UNEXPECTED;
     }
     RefPtr<nsIX509Cert> castedCert(cert.get());
     aCertList.AppendElement(castedCert);
   }
   return NS_OK;
 }
 
-nsresult TransportSecurityInfo::ConvertCertArrayToCertList(
-    const nsTArray<RefPtr<nsIX509Cert>>& aCertArray,
-    nsIX509CertList** aCertList) {
-  NS_ENSURE_ARG_POINTER(aCertList);
-  *aCertList = nullptr;
-
-  // aCertList will be null if aCertArray is empty, this also matches
-  // the original certList behaviour
-  if (aCertArray.IsEmpty()) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIX509CertList> certList = new nsNSSCertList();
-  for (const auto& cert : aCertArray) {
-    nsresult rv = certList->AddCert(cert);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-
-  certList.forget(aCertList);
-
-  return NS_OK;
-}
-
-nsresult TransportSecurityInfo::ConvertCertListToCertArray(
-    const nsCOMPtr<nsIX509CertList>& aCertList,
-    nsTArray<RefPtr<nsIX509Cert>>& aCertArray) {
-  MOZ_ASSERT(aCertList);
-  if (!aCertList) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  aCertArray.Clear();
-  RefPtr<nsNSSCertList> certList = aCertList->GetCertList();
-
-  return certList->ForEachCertificateInChain(
-      [&aCertArray](nsCOMPtr<nsIX509Cert>& aCert, bool aHasMore,
-                    bool& aContinue) {
-        RefPtr<nsIX509Cert> cert(aCert.get());
-        aCertArray.AppendElement(cert);
-        return NS_OK;
-      });
-}
-
 // NB: Any updates (except disk-only fields) must be kept in sync with
 //     |DeserializeFromIPC|.
 NS_IMETHODIMP
 TransportSecurityInfo::Read(nsIObjectInputStream* aStream) {
   nsID id;
   nsresult rv = aStream->ReadID(&id);
   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
   if (NS_FAILED(rv)) {
--- a/security/manager/ssl/TransportSecurityInfo.h
+++ b/security/manager/ssl/TransportSecurityInfo.h
@@ -105,20 +105,16 @@ class TransportSecurityInfo : public nsI
   bool mIsEV;
 
   bool mHasIsEVStatus;
   bool mHaveCipherSuiteAndProtocol;
 
   /* mHaveCertErrrorBits is relied on to determine whether or not a SPDY
      connection is eligible for joining in nsNSSSocketInfo::JoinConnection() */
   bool mHaveCertErrorBits;
-
-  static nsresult ConvertCertArrayToCertList(
-      const nsTArray<RefPtr<nsIX509Cert>>& aCertArray,
-      nsIX509CertList** aCertList);
  private:
   // True if SetCanceled has been called (or if this was deserialized with a
   // non-zero mErrorCode, which can only be the case if SetCanceled was called
   // on the original TransportSecurityInfo).
   Atomic<bool> mCanceled;
 
   mutable ::mozilla::Mutex mMutex;
 
@@ -136,19 +132,16 @@ class TransportSecurityInfo : public nsI
   OriginAttributes mOriginAttributes;
 
   nsCOMPtr<nsIX509Cert> mServerCert;
 
   /* Peer cert chain for failed connections (for error reporting) */
   nsTArray<RefPtr<nsIX509Cert>> mFailedCertChain;
 
   nsresult ReadSSLStatus(nsIObjectInputStream* aStream);
-  static nsresult ConvertCertListToCertArray(
-      const nsCOMPtr<nsIX509CertList>& aCertList,
-      nsTArray<RefPtr<nsIX509Cert>>& aCertArray);
 
   // This function is used to read the binary that are serialized
   // by using nsIX509CertList
   nsresult ReadCertList(nsIObjectInputStream* aStream,
                         nsTArray<RefPtr<nsIX509Cert>>& aCertList);
   nsresult ReadCertificatesFromStream(nsIObjectInputStream* aStream,
                                       uint32_t aSize,
                                       nsTArray<RefPtr<nsIX509Cert>>& aCertList);
--- a/security/manager/ssl/components.conf
+++ b/security/manager/ssl/components.conf
@@ -85,22 +85,16 @@ Classes = [
     },
     {
         'cid': '{fb0bbc5c-452e-4783-b32c-80124693d871}',
         'contract_ids': ['@mozilla.org/security/x509certdb;1'],
         'type': 'nsNSSCertificateDB',
         'legacy_constructor': 'mozilla::psm::NSSConstructor<nsNSSCertificateDB>',
     },
     {
-        'cid': '{959fb165-6517-487f-ab9b-d8913be53197}',
-        'contract_ids': ['@mozilla.org/security/x509certlist;1'],
-        'type': 'nsNSSCertList',
-        'legacy_constructor': 'mozilla::psm::NSSConstructor<nsNSSCertList>',
-    },
-    {
         'cid': '{36a1d3b3-d886-4317-96ff-87b0005cfef7}',
         'contract_ids': ['@mozilla.org/security/hash;1'],
         'type': 'nsCryptoHash',
         'legacy_constructor': 'mozilla::psm::NSSConstructor<nsCryptoHash>',
     },
     {
         'cid': '{a496d0a2-dff7-4e23-bd65-1ca742fa178a}',
         'contract_ids': ['@mozilla.org/security/hmac;1'],
--- a/security/manager/ssl/moz.build
+++ b/security/manager/ssl/moz.build
@@ -37,17 +37,16 @@ XPIDL_SOURCES += [
     'nsIProtectedAuthThread.idl',
     'nsISecretDecoderRing.idl',
     'nsISecurityUITelemetry.idl',
     'nsISiteSecurityService.idl',
     'nsITokenDialogs.idl',
     'nsITokenPasswordDialogs.idl',
     'nsIX509Cert.idl',
     'nsIX509CertDB.idl',
-    'nsIX509CertList.idl',
     'nsIX509CertValidity.idl',
 ]
 
 if CONFIG['MOZ_XUL']:
     XPIDL_SOURCES += [
         'nsICertTree.idl',
     ]
 
--- a/security/manager/ssl/nsINSSComponent.idl
+++ b/security/manager/ssl/nsINSSComponent.idl
@@ -7,18 +7,16 @@
 #include "nsISupports.idl"
 
 %{C++
 #include "cert.h"
 #include "SharedCertVerifier.h"
 #define PSM_COMPONENT_CONTRACTID "@mozilla.org/psm;1"
 %}
 
-interface nsIX509CertList;
-
 [ptr] native CERTCertificatePtr(CERTCertificate);
 [ptr] native SharedCertVerifierPtr(mozilla::psm::SharedCertVerifier);
 
 [scriptable, uuid(a0a8f52b-ea18-4abc-a3ca-eccf704ffe63)]
 interface nsINSSComponent : nsISupports {
   /**
    * When we log out of a PKCS#11 token, any TLS connections that may have
    * involved a client certificate stored on that token must be closed. Since we
deleted file mode 100644
--- a/security/manager/ssl/nsIX509CertList.idl
+++ /dev/null
@@ -1,62 +0,0 @@
-/* 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 "nsISupports.idl"
-
-interface nsISimpleEnumerator;
-interface nsIX509Cert;
-
-%{C++
-namespace IPC {
-  class Message;
-}
-class PickleIterator;
-class nsNSSCertList;
-%}
-
-[ptr] native nsNSSCertListPtr(nsNSSCertList);
-[ptr] native IpcMessagePtr(IPC::Message);
-[ptr] native PickleIteratorPtr(PickleIterator);
-
-[scriptable, builtinclass, uuid(ae74cda5-cd2f-473f-96f5-f0b7fff62c68)]
-interface nsIX509CertList : nsISupports {
-  [must_use]
-  void addCert(in nsIX509Cert cert);
-  [must_use]
-  nsISimpleEnumerator getEnumerator();
-
-  /**
-   * Test whether two certificate list instances represent the same
-   * certificate list.
-   *
-   * @return Whether the certificate lists are equal
-   */
-  [must_use]
-  boolean equals(in nsIX509CertList other);
-
-  /**
-   * Retrieves the PSM helper class that wraps the NSS certificate list
-   */
-  [notxpcom, noscript, must_use]
-  nsNSSCertListPtr getCertList();
-
-  [notxpcom, noscript]
-  void SerializeToIPC(in IpcMessagePtr aMsg);
-
-  [notxpcom, noscript]
-  bool DeserializeFromIPC([const] in IpcMessagePtr aMsg, in PickleIteratorPtr aIter);
-};
-
-%{C++
-
-#define NS_X509CERTLIST_CID { /* 959fb165-6517-487f-ab9b-d8913be53197 */  \
-    0x959fb165,                                                           \
-    0x6517,                                                               \
-    0x487f,                                                               \
-    {0xab, 0x9b, 0xd8, 0x91, 0x3b, 0xe5, 0x31, 0x97}                      \
-  }
-
-#define NS_X509CERTLIST_CONTRACTID "@mozilla.org/security/x509certlist;1"
-
-%}
--- a/security/manager/ssl/nsNSSCertificate.cpp
+++ b/security/manager/ssl/nsNSSCertificate.cpp
@@ -52,35 +52,16 @@
 #  include <winsock.h>  // for htonl
 #endif
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 extern LazyLogModule gPIPNSSLog;
 
-class nsNSSCertListEnumerator : public nsSimpleEnumerator {
- public:
-  NS_DECL_NSISIMPLEENUMERATOR
-
-  const nsID& DefaultInterface() override { return NS_GET_IID(nsIX509Cert); }
-
-  explicit nsNSSCertListEnumerator(
-      const std::vector<UniqueCERTCertificate>& certs);
-
-  nsNSSCertListEnumerator(const nsNSSCertListEnumerator&) = delete;
-  void operator=(const nsNSSCertListEnumerator&) = delete;
-
- private:
-  virtual ~nsNSSCertListEnumerator() = default;
-
-  std::vector<UniqueCERTCertificate> mCerts;
-  std::vector<UniqueCERTCertificate>::const_iterator mPosition;
-};
-
 // This is being stored in an uint32_t that can otherwise
 // only take values from nsIX509Cert's list of cert types.
 // As nsIX509Cert is frozen, we choose a value not contained
 // in the list to mean not yet initialized.
 #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
 
 NS_IMPL_ISUPPORTS(nsNSSCertificate, nsIX509Cert, nsISerializable, nsIClassInfo)
 
@@ -791,344 +772,16 @@ SECStatus ConstructCERTCertListFromRever
     Unused << cert.release();  // cert is now owned by certList.
   }
 
   return SECSuccess;
 }
 
 }  // namespace mozilla
 
-NS_IMPL_CLASSINFO(nsNSSCertList, nullptr,
-                  // inferred from nsIX509Cert
-                  nsIClassInfo::THREADSAFE, NS_X509CERTLIST_CID)
-
-NS_IMPL_ISUPPORTS_CI(nsNSSCertList, nsIX509CertList, nsISerializable)
-
-nsNSSCertList::nsNSSCertList(UniqueCERTCertList certList) {
-  // Commonly we'll store only 3 certificates. If this is a verified certificate
-  // chain, it may be as many as 8 certificates. If this is a list of all known
-  // certificates, it may be a few hundred. We'll optimize for the common case
-  // (i.e. a verified certificate chain).
-  mCerts.reserve(8);
-  if (certList.get()) {
-    for (CERTCertListNode* node = CERT_LIST_HEAD(certList.get());
-         !CERT_LIST_END(node, certList.get()); node = CERT_LIST_NEXT(node)) {
-      UniqueCERTCertificate cert(CERT_DupCertificate(node->cert));
-      mCerts.push_back(std::move(cert));
-    }
-  }
-}
-
-nsNSSCertList::nsNSSCertList() {
-  // Commonly we'll store only 3 certificates. If this is a verified certificate
-  // chain, it may be as many as 8 certificates. If this is a list of all known
-  // certificates, it may be a few hundred. We'll optimize for the common case
-  // (i.e. a verified certificate chain).
-  mCerts.reserve(8);
-}
-
-// This is the implementation of nsIX509CertList.getCertList().
-nsNSSCertList* nsNSSCertList::GetCertList() { return this; }
-
-NS_IMETHODIMP
-nsNSSCertList::AddCert(nsIX509Cert* aCert) {
-  if (!aCert) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  // We need an owning handle when calling nsIX509Cert::GetCert().
-  UniqueCERTCertificate cert(aCert->GetCert());
-  if (!cert) {
-    NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
-    return NS_ERROR_FAILURE;
-  }
-  mCerts.push_back(std::move(cert));
-  return NS_OK;
-}
-
-UniqueCERTCertList nsNSSCertList::DupCertList(
-    const UniqueCERTCertList& certList) {
-  if (!certList) {
-    return nullptr;
-  }
-
-  UniqueCERTCertList newList(CERT_NewCertList());
-  if (!newList) {
-    return nullptr;
-  }
-
-  for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
-       !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) {
-    UniqueCERTCertificate cert(CERT_DupCertificate(node->cert));
-    if (!cert) {
-      return nullptr;
-    }
-
-    if (CERT_AddCertToListTail(newList.get(), cert.get()) != SECSuccess) {
-      return nullptr;
-    }
-
-    Unused << cert.release();  // Ownership transferred to the cert list.
-  }
-  return newList;
-}
-
-// NB: Any updates (except disk-only fields) must be kept in sync with
-//     |SerializeToIPC|.
-NS_IMETHODIMP
-nsNSSCertList::Write(nsIObjectOutputStream* aStream) {
-  // Write the length of the list
-  nsresult rv = aStream->Write32(mCerts.size());
-
-  // Serialize each certificate
-  for (const auto& certRef : mCerts) {
-    nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(certRef.get());
-    if (!cert) {
-      rv = NS_ERROR_OUT_OF_MEMORY;
-      break;
-    }
-
-    nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
-    rv = aStream->WriteCompoundObject(serializableCert, NS_GET_IID(nsIX509Cert),
-                                      true);
-    if (NS_FAILED(rv)) {
-      break;
-    }
-  }
-
-  return rv;
-}
-
-// NB: Any updates (except disk-only fields) must be kept in sync with
-//     |DeserializeFromIPC|.
-NS_IMETHODIMP
-nsNSSCertList::Read(nsIObjectInputStream* aStream) {
-  uint32_t certListLen;
-  nsresult rv = aStream->Read32(&certListLen);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  for (uint32_t i = 0; i < certListLen; ++i) {
-    nsCOMPtr<nsISupports> certSupports;
-    rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
-    if (!cert) {
-      return NS_ERROR_UNEXPECTED;
-    }
-    rv = AddCert(cert);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-
-  return NS_OK;
-}
-
-void nsNSSCertList::SerializeToIPC(IPC::Message* aMsg) {
-  const size_t certCount = static_cast<size_t>(mCerts.size());
-  WriteParam(aMsg, certCount);
-
-  for (const auto& certRef : mCerts) {
-    RefPtr<nsIX509Cert> cert = nsNSSCertificate::Create(certRef.get());
-    MOZ_RELEASE_ASSERT(cert);
-
-    WriteParam(aMsg, cert);
-  }
-}
-
-bool nsNSSCertList::DeserializeFromIPC(const IPC::Message* aMsg,
-                                       PickleIterator* aIter) {
-  size_t count = 0;
-  if (!ReadParam(aMsg, aIter, &count)) {
-    return false;
-  }
-
-  for (size_t i = 0; i < count; i++) {
-    RefPtr<nsIX509Cert> cert;
-    if (!ReadParam(aMsg, aIter, &cert) || !cert || NS_FAILED(AddCert(cert))) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-NS_IMETHODIMP
-nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval) {
-  nsCOMPtr<nsISimpleEnumerator> enumerator(new nsNSSCertListEnumerator(mCerts));
-  enumerator.forget(_retval);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertList::Equals(nsIX509CertList* other, bool* result) {
-  NS_ENSURE_ARG(result);
-  *result = true;
-
-  nsresult rv;
-
-  nsCOMPtr<nsISimpleEnumerator> selfEnumerator;
-  rv = GetEnumerator(getter_AddRefs(selfEnumerator));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsCOMPtr<nsISimpleEnumerator> otherEnumerator;
-  rv = other->GetEnumerator(getter_AddRefs(otherEnumerator));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsCOMPtr<nsISupports> selfSupports;
-  nsCOMPtr<nsISupports> otherSupports;
-  while (NS_SUCCEEDED(selfEnumerator->GetNext(getter_AddRefs(selfSupports)))) {
-    if (NS_SUCCEEDED(otherEnumerator->GetNext(getter_AddRefs(otherSupports)))) {
-      nsCOMPtr<nsIX509Cert> selfCert = do_QueryInterface(selfSupports);
-      nsCOMPtr<nsIX509Cert> otherCert = do_QueryInterface(otherSupports);
-
-      bool certsEqual = false;
-      rv = selfCert->Equals(otherCert, &certsEqual);
-      if (NS_FAILED(rv)) {
-        return rv;
-      }
-      if (!certsEqual) {
-        *result = false;
-        break;
-      }
-    } else {
-      // other is shorter than self
-      *result = false;
-      break;
-    }
-  }
-
-  // Make sure self is the same length as other
-  bool otherHasMore = false;
-  rv = otherEnumerator->HasMoreElements(&otherHasMore);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  if (otherHasMore) {
-    *result = false;
-  }
-
-  return NS_OK;
-}
-
-nsresult nsNSSCertList::ForEachCertificateInChain(
-    ForEachCertOperation& aOperation) {
-  nsCOMPtr<nsISimpleEnumerator> chainElt;
-  nsresult rv = GetEnumerator(getter_AddRefs(chainElt));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Each chain may have multiple certificates.
-  bool hasMore = false;
-  rv = chainElt->HasMoreElements(&hasMore);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  if (!hasMore) {
-    return NS_OK;  // Empty lists are fine
-  }
-
-  do {
-    nsCOMPtr<nsISupports> certSupports;
-    rv = chainElt->GetNext(getter_AddRefs(certSupports));
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports, &rv);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    rv = chainElt->HasMoreElements(&hasMore);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    bool continueLoop = true;
-    rv = aOperation(cert, hasMore, continueLoop);
-    if (NS_FAILED(rv) || !continueLoop) {
-      return rv;
-    }
-  } while (hasMore);
-
-  return NS_OK;
-}
-
-nsresult nsNSSCertList::SegmentCertificateChain(
-    /* out */ nsCOMPtr<nsIX509Cert>& aRoot,
-    /* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
-    /* out */ nsCOMPtr<nsIX509Cert>& aEndEntity) {
-  if (aRoot || aIntermediates || aEndEntity) {
-    // All passed-in nsCOMPtrs should be empty for the state machine to work
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  aIntermediates = new nsNSSCertList();
-
-  nsresult rv = ForEachCertificateInChain(
-      [&aRoot, &aIntermediates, &aEndEntity](nsCOMPtr<nsIX509Cert> aCert,
-                                             bool hasMore, bool& aContinue) {
-        if (!aEndEntity) {
-          // This is the end entity
-          aEndEntity = aCert;
-        } else if (!hasMore) {
-          // This is the root
-          aRoot = aCert;
-        } else {
-          // One of (potentially many) intermediates
-          if (NS_FAILED(aIntermediates->AddCert(aCert))) {
-            return NS_ERROR_OUT_OF_MEMORY;
-          }
-        }
-
-        return NS_OK;
-      });
-
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  if (!aRoot || !aEndEntity) {
-    // No self-signed (or empty) chains allowed
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  return NS_OK;
-}
-
-nsresult nsNSSCertList::GetRootCertificate(
-    /* out */ nsCOMPtr<nsIX509Cert>& aRoot) {
-  if (aRoot) {
-    return NS_ERROR_UNEXPECTED;
-  }
-  // If the list is empty, leave aRoot empty.
-  if (mCerts.size() < 1) {
-    return NS_OK;
-  }
-  const UniqueCERTCertificate& cert = mCerts.back();
-  // This increases the refcount on the underlying CERTCertificate, which aRoot
-  // will own.
-  aRoot = nsNSSCertificate::Create(cert.get());
-  if (!aRoot) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
-}
-
 nsresult nsNSSCertificate::SegmentCertificateChain(
     /* in */ const nsTArray<RefPtr<nsIX509Cert>>& aCertList,
     /* out */ nsCOMPtr<nsIX509Cert>& aRoot,
     /* out */ nsTArray<RefPtr<nsIX509Cert>>& aIntermediates,
     /* out */ nsCOMPtr<nsIX509Cert>& aEndEntity) {
   if (aRoot || aEndEntity) {
     // All passed-in nsCOMPtrs should be empty for the state machine to work
     return NS_ERROR_UNEXPECTED;
@@ -1172,52 +825,16 @@ nsresult nsNSSCertificate::GetRootCertif
   nsCOMPtr<nsIX509Cert> cert(aCertList.LastElement());
   aRoot = cert;
   if (!aRoot) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
-nsNSSCertListEnumerator::nsNSSCertListEnumerator(
-    const std::vector<UniqueCERTCertificate>& certs) {
-  mCerts.reserve(certs.size());
-  // Unfortunately we can't just clone the vector because we have to ensure the
-  // reference counts on the CERTCertificates are accurate.
-  for (const auto& certRef : certs) {
-    UniqueCERTCertificate cert(CERT_DupCertificate(certRef.get()));
-    mCerts.push_back(std::move(cert));
-  }
-  mPosition = mCerts.cbegin();
-}
-
-NS_IMETHODIMP
-nsNSSCertListEnumerator::HasMoreElements(bool* _retval) {
-  *_retval = mPosition != mCerts.cend();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSCertListEnumerator::GetNext(nsISupports** _retval) {
-  *_retval = nullptr;
-  if (mPosition == mCerts.cend()) {
-    return NS_ERROR_UNEXPECTED;
-  }
-  const UniqueCERTCertificate& certRef = *mPosition;
-  // nsNSSCertificate::Create calls nsNSSCertificate::nsNSSCertificate, which
-  // increases the reference count on the underlying CERTCertificate itself.
-  nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(certRef.get());
-  if (!nssCert) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  nssCert.forget(_retval);
-  mPosition++;
-  return NS_OK;
-}
-
 // NB: Any updates (except disk-only fields) must be kept in sync with
 //     |SerializeToIPC|.
 NS_IMETHODIMP
 nsNSSCertificate::Write(nsIObjectOutputStream* aStream) {
   NS_ENSURE_STATE(mCert);
   // This field used to be the cached EV status, but it is no longer necessary.
   nsresult rv = aStream->Write32(0);
   if (NS_FAILED(rv)) {
--- a/security/manager/ssl/nsNSSCertificate.h
+++ b/security/manager/ssl/nsNSSCertificate.h
@@ -12,17 +12,16 @@
 #include "ScopedNSSTypes.h"
 #include "certt.h"
 #include "nsCOMPtr.h"
 #include "nsIASN1Object.h"
 #include "nsIClassInfo.h"
 #include "nsISerializable.h"
 #include "nsIX509Cert.h"
 #include "nsIX509CertDB.h"
-#include "nsIX509CertList.h"
 #include "nsSimpleEnumerator.h"
 #include "nsStringFwd.h"
 
 namespace mozilla {
 namespace pkix {
 class DERArray;
 }
 }  // namespace mozilla
@@ -90,74 +89,16 @@ class nsNSSCertificate final : public ns
 namespace mozilla {
 
 SECStatus ConstructCERTCertListFromReversedDERArray(
     const mozilla::pkix::DERArray& certArray,
     /*out*/ mozilla::UniqueCERTCertList& certList);
 
 }  // namespace mozilla
 
-typedef const std::function<nsresult(nsCOMPtr<nsIX509Cert>& aCert,
-                                     bool aHasMore, /* out */ bool& aContinue)>
-    ForEachCertOperation;
-
-class nsNSSCertList : public nsIX509CertList, public nsISerializable {
- public:
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIX509CERTLIST
-  NS_DECL_NSISERIALIZABLE
-
-  // The only way to call this is with std::move(some cert list) (because the
-  // copy constructor should be deleted for UniqueCERTCertList), so we
-  // effectively take ownership of it. What actually happens is we iterate
-  // through the list getting our own owned reference to each certificate in the
-  // list, and then the UniqueCERTCertList is dropped as it goes out of scope
-  // (thus releasing its own reference to each certificate).
-  explicit nsNSSCertList(mozilla::UniqueCERTCertList certList);
-
-  nsNSSCertList();
-
-  static mozilla::UniqueCERTCertList DupCertList(
-      const mozilla::UniqueCERTCertList& certList);
-
-  // For each certificate in this CertList, run the operation aOperation.
-  // To end early with NS_OK, set the `aContinue` argument false before
-  // returning. To end early with an error, return anything except NS_OK.
-  // The `aHasMore` argument is false when this is the last certificate in the
-  // chain.
-  nsresult ForEachCertificateInChain(ForEachCertOperation& aOperation);
-
-  // Split a certificate chain into the root, intermediates (if any), and end
-  // entity. This method does so blindly, assuming that the current list object
-  // is ordered [end entity, intermediates..., root]. If that isn't true, this
-  // method will return the certificates at the two ends without regard to the
-  // actual chain of trust. Callers are encouraged to check, if there's any
-  // doubt.
-  // Will return error if used on self-signed or empty chains.
-  // This method requires that all arguments be empty, notably the list
-  // `aIntermediates` must be empty.
-  nsresult SegmentCertificateChain(
-      /* out */ nsCOMPtr<nsIX509Cert>& aRoot,
-      /* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
-      /* out */ nsCOMPtr<nsIX509Cert>& aEndEntity);
-
-  // Obtain the root certificate of a certificate chain. This method does so
-  // blindly, as SegmentCertificateChain; the same restrictions apply. On an
-  // empty list, leaves aRoot empty and returns OK.
-  nsresult GetRootCertificate(/* out */ nsCOMPtr<nsIX509Cert>& aRoot);
-
- private:
-  virtual ~nsNSSCertList() {}
-
-  std::vector<mozilla::UniqueCERTCertificate> mCerts;
-
-  nsNSSCertList(const nsNSSCertList&) = delete;
-  void operator=(const nsNSSCertList&) = delete;
-};
-
 #define NS_X509CERT_CID                              \
   { /* 660a3226-915c-4ffb-bb20-8985a632df05 */       \
     0x660a3226, 0x915c, 0x4ffb, {                    \
       0xbb, 0x20, 0x89, 0x85, 0xa6, 0x32, 0xdf, 0x05 \
     }                                                \
   }
 
 #endif  // nsNSSCertificate_h
--- a/security/manager/ssl/nsNSSComponent.h
+++ b/security/manager/ssl/nsNSSComponent.h
@@ -24,17 +24,16 @@
 
 #ifdef XP_WIN
 #  include "windows.h"  // this needs to be before the following includes
 #  include "wincrypt.h"
 #endif  // XP_WIN
 
 class nsIDOMWindow;
 class nsIPrompt;
-class nsIX509CertList;
 class SmartCardThreadList;
 
 namespace mozilla {
 namespace psm {
 
 MOZ_MUST_USE
 ::already_AddRefed<mozilla::psm::SharedCertVerifier> GetDefaultCertVerifier();
 UniqueCERTCertList FindNonCACertificatesWithPrivateKeys();
--- a/security/manager/ssl/nsNSSModule.cpp
+++ b/security/manager/ssl/nsNSSModule.cpp
@@ -129,17 +129,16 @@ static nsresult Constructor(nsISupports*
 // in necko code (bug 1418752). To prevent it we initialize all such components
 // on main thread in advance in net_EnsurePSMInit(). Update that function when
 // new component with ThreadRestriction::MainThreadOnly is added.
 IMPL(SecretDecoderRing, nullptr)
 IMPL(nsPK11TokenDB, nullptr)
 IMPL(PKCS11ModuleDB, nullptr)
 IMPL(nsNSSCertificate, nullptr, ProcessRestriction::AnyProcess)
 IMPL(nsNSSCertificateDB, nullptr)
-IMPL(nsNSSCertList, nullptr, ProcessRestriction::AnyProcess)
 #ifdef MOZ_XUL
 IMPL(nsCertTree, nullptr)
 #endif
 IMPL(nsCryptoHash, nullptr, ProcessRestriction::AnyProcess)
 IMPL(nsCryptoHMAC, nullptr, ProcessRestriction::AnyProcess)
 IMPL(nsKeyObject, nullptr, ProcessRestriction::AnyProcess)
 IMPL(nsKeyObjectFactory, nullptr, ProcessRestriction::AnyProcess)
 IMPL(ContentSignatureVerifier, nullptr)
--- a/security/manager/ssl/tests/gtest/CertListTest.cpp
+++ b/security/manager/ssl/tests/gtest/CertListTest.cpp
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gtest/gtest.h"
 #include "nsCOMPtr.h"
 #include "nsIPrefService.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIX509Cert.h"
 #include "nsIX509CertDB.h"
-#include "nsIX509CertList.h"
 #include "nsNSSCertificate.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 
 // certspec (for pycert.py)
 //
 // issuer:ca
 // subject:ca
@@ -130,88 +129,71 @@ class psm_CertList : public ::testing::T
     << "couldn't set pref 'intl.locale.matchOS'";
 
     nsCOMPtr<nsIX509CertDB> certdb(do_GetService(NS_X509CERTDB_CONTRACTID));
     ASSERT_TRUE(certdb)
     << "couldn't get certdb";
   }
 };
 
-static nsresult AddCertFromStringToList(const char* aPem,
-                                        nsIX509CertList* aCertList) {
-  if (!aCertList) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  nsCOMPtr<nsIX509Cert> cert;
+static nsresult AddCertFromStringToList(
+    const char* aPem, nsTArray<RefPtr<nsIX509Cert>>& aCertList) {
+  RefPtr<nsIX509Cert> cert;
   cert =
       nsNSSCertificate::ConstructFromDER(const_cast<char*>(aPem), strlen(aPem));
   if (!cert) {
     return NS_ERROR_FAILURE;
   }
 
-  return aCertList->AddCert(cert);
-}
-
-static int CountCertsInList(nsCOMPtr<nsIX509CertList>& aCertList) {
-  int counter = 0;
-  RefPtr<nsNSSCertList> certList = aCertList->GetCertList();
-  certList->ForEachCertificateInChain(
-      [&counter](nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
-        counter++;
-        return NS_OK;
-      });
-
-  return counter;
+  aCertList.AppendElement(cert);
+  return NS_OK;
 }
 
 TEST_F(psm_CertList, TestInvalidSegmenting) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
+  nsTArray<RefPtr<nsIX509Cert>> certList;
 
   nsCOMPtr<nsIX509Cert> rootCert;
-  nsCOMPtr<nsIX509CertList> intCerts;
+  nsTArray<RefPtr<nsIX509Cert>> intCerts;
   nsCOMPtr<nsIX509Cert> eeCert;
-  nsresult rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
+  nsresult rv = nsNSSCertificate::SegmentCertificateChain(certList, rootCert,
+                                                          intCerts, eeCert);
   ASSERT_EQ(rv, NS_ERROR_INVALID_ARG) << "Empty lists can't be segmented";
 
   rv = AddCertFromStringToList(kCaPem, certList);
   ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
 
-  // We should need to clear out the in-vars, but let's make sure behavior is OK
-  rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
-  ASSERT_EQ(rv, NS_ERROR_UNEXPECTED)
-      << "Don't permit already-filled-in arguments";
-
-  intCerts = nullptr;
+  intCerts.Clear();
   rootCert = nullptr;
   eeCert = nullptr;
 
-  rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
+  rv = nsNSSCertificate::SegmentCertificateChain(certList, rootCert, intCerts,
+                                                 eeCert);
   ASSERT_EQ(rv, NS_ERROR_INVALID_ARG) << "Lists of one can't be segmented";
 }
 
 TEST_F(psm_CertList, TestValidSegmenting) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
+  nsTArray<RefPtr<nsIX509Cert>> certList;
 
   nsresult rv = AddCertFromStringToList(kEePem, certList);
   ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
   rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
   ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
 
   nsCOMPtr<nsIX509Cert> rootCert;
-  nsCOMPtr<nsIX509CertList> intCerts;
+  nsTArray<RefPtr<nsIX509Cert>> intCerts;
   nsCOMPtr<nsIX509Cert> eeCert;
 
-  rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
+  rv = nsNSSCertificate::SegmentCertificateChain(certList, rootCert, intCerts,
+                                                 eeCert);
   ASSERT_EQ(rv, NS_OK) << "Should have segmented OK";
   ASSERT_TRUE(rootCert)
   << "Root cert should be filled in";
   ASSERT_TRUE(eeCert)
   << "End entity cert should be filled in";
-  ASSERT_EQ(CountCertsInList(intCerts), 0)
+  ASSERT_EQ(intCerts.Length(), static_cast<size_t>(0))
       << "There should be no intermediates";
 
   bool selfSigned;
   ASSERT_TRUE(NS_SUCCEEDED(rootCert->GetIsSelfSigned(&selfSigned)))
   << "Getters should work.";
   ASSERT_FALSE(selfSigned)
   << "Roots are self signed, but this was ca-second-intermediate";
 
@@ -219,43 +201,45 @@ TEST_F(psm_CertList, TestValidSegmenting
   ASSERT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn)))
   << "Getters should work.";
   ASSERT_TRUE(rootCn.EqualsLiteral("ca-second-intermediate"))
   << "Second Intermediate CN should match";
 
   rv = AddCertFromStringToList(kCaIntermediatePem, certList);
   ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
 
-  intCerts = nullptr;
+  intCerts.Clear();
   rootCert = nullptr;
   eeCert = nullptr;
-  rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
+  rv = nsNSSCertificate::SegmentCertificateChain(certList, rootCert, intCerts,
+                                                 eeCert);
   ASSERT_EQ(rv, NS_OK) << "Should have segmented OK";
 
   ASSERT_TRUE(rootCert)
   << "Root cert should be filled in";
   ASSERT_TRUE(eeCert)
   << "End entity cert should be filled in";
-  ASSERT_EQ(CountCertsInList(intCerts), 1)
+  ASSERT_EQ(intCerts.Length(), static_cast<size_t>(1))
       << "There should be one intermediate";
 
   rv = AddCertFromStringToList(kCaPem, certList);
   ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
 
-  intCerts = nullptr;
+  intCerts.Clear();
   rootCert = nullptr;
   eeCert = nullptr;
-  rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
+  rv = nsNSSCertificate::SegmentCertificateChain(certList, rootCert, intCerts,
+                                                 eeCert);
   ASSERT_EQ(rv, NS_OK) << "Should have segmented OK";
 
   ASSERT_TRUE(rootCert)
   << "Root cert should be filled in";
   ASSERT_TRUE(eeCert)
   << "End entity cert should be filled in";
-  ASSERT_EQ(CountCertsInList(intCerts), 2)
+  ASSERT_EQ(intCerts.Length(), static_cast<size_t>(2))
       << "There should be two intermediates";
 
   ASSERT_TRUE(NS_SUCCEEDED(rootCert->GetIsSelfSigned(&selfSigned)))
   << "Getters should work.";
   ASSERT_TRUE(selfSigned)
   << "Roots are self signed";
 
   ASSERT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn)))
@@ -264,227 +248,107 @@ TEST_F(psm_CertList, TestValidSegmenting
   << "Root CN should match";
 
   nsAutoString eeCn;
   ASSERT_TRUE(NS_SUCCEEDED(eeCert->GetCommonName(eeCn)))
   << "Getters should work.";
   ASSERT_TRUE(eeCn.EqualsLiteral("ee"))
   << "EE CN should match";
 
-  rv = intCerts->GetCertList()->ForEachCertificateInChain(
-      [](nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
-        nsAutoString cn;
-        nsresult rv = aCert->GetCommonName(cn);
-        if (NS_FAILED(rv)) {
-          return rv;
-        }
+  for (size_t i = 0; i < intCerts.Length(); ++i) {
+    nsAutoString cn;
+    const auto& cert = intCerts[i];
+    rv = cert->GetCommonName(cn);
+    if (NS_FAILED(rv)) {
+      break;
+    }
 
-        if (aHasMore) {
-          if (!cn.EqualsLiteral("ca-second-intermediate")) {
-            return NS_ERROR_FAILURE;
-          }
-        } else {
-          if (!cn.EqualsLiteral("ca-intermediate")) {
-            return NS_ERROR_FAILURE;
-          }
-        }
-        return NS_OK;
-      });
+    if (i < intCerts.Length() - 1) {
+      if (!cn.EqualsLiteral("ca-second-intermediate")) {
+        rv = NS_ERROR_FAILURE;
+        break;
+      }
+    } else {
+      if (!cn.EqualsLiteral("ca-intermediate")) {
+        rv = NS_ERROR_FAILURE;
+        break;
+      }
+    }
+  }
+
   ASSERT_EQ(rv, NS_OK) << "Should have looped OK.";
 }
 
-TEST_F(psm_CertList, TestForEach) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
-
-  bool called = false;
-  nsresult rv = certList->ForEachCertificateInChain(
-      [&called](nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
-        called = true;
-        return NS_OK;
-      });
-  ASSERT_EQ(rv, NS_OK) << "Should have iterated OK";
-  ASSERT_FALSE(called)
-  << "There are no certificates in this chain, it shouldn't be called";
-
-  // Add two certificates
-  rv = AddCertFromStringToList(kCaPem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-  rv = AddCertFromStringToList(kCaIntermediatePem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-
-  int counter = 0;
-  rv = certList->ForEachCertificateInChain(
-      [&counter](nsCOMPtr<nsIX509Cert> aCert, bool aHasMore,
-                 bool& aContinue) -> nsresult {
-        if (!aCert) {
-          GTEST_NONFATAL_FAILURE_("Unexpected arguments");
-          return NS_ERROR_FAILURE;
-        }
-
-        nsAutoString cn;
-        nsresult rv = aCert->GetCommonName(cn);
-        if (NS_FAILED(rv)) {
-          return rv;
-        }
-
-        switch (counter) {
-          case 0:
-            if (!aHasMore) {
-              return NS_ERROR_FAILURE;
-            }
-
-            if (!cn.EqualsLiteral("ca")) {
-              return NS_ERROR_FAILURE;
-            }
-            break;
-          case 1:
-            if (aHasMore) {
-              return NS_ERROR_FAILURE;
-            }
-
-            if (!cn.EqualsLiteral("ca-intermediate")) {
-              return NS_ERROR_FAILURE;
-            }
-            break;
-          default:
-            GTEST_NONFATAL_FAILURE_("Unexpected count");
-            return NS_ERROR_UNEXPECTED;
-        }
-        counter++;
-        return NS_OK;
-      });
-  ASSERT_EQ(rv, NS_OK) << "Should have iterated OK";
-}
-
-TEST_F(psm_CertList, TestForEachContinueSafety) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
-
-  // Add two certificates
-  nsresult rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-  rv = AddCertFromStringToList(kEePem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-
-  int counter = 0;
-  rv = certList->ForEachCertificateInChain(
-      [&counter](nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
-        counter++;
-        aContinue = true;  // Try to keep it going
-        return NS_OK;
-      });
-  ASSERT_EQ(counter, 2)
-      << "There should have been only two iterations regardless!";
-  ASSERT_EQ(rv, NS_OK) << "Should complete OK.";
-}
-
-TEST_F(psm_CertList, TestForEachStopEarly) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
-
-  // Add two certificates
-  nsresult rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-  rv = AddCertFromStringToList(kEePem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-
-  int counter = 0;
-  rv = certList->ForEachCertificateInChain(
-      [&counter](nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
-        counter++;
-        aContinue = false;
-        return NS_OK;
-      });
-  ASSERT_EQ(counter, 1) << "There should have been only the one call";
-  ASSERT_EQ(rv, NS_OK) << "Should complete OK.";
-}
-
-TEST_F(psm_CertList, TestForEachStopOnError) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
-
-  // Add two certificates
-  nsresult rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-  rv = AddCertFromStringToList(kEePem, certList);
-  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
-
-  int counter = 0;
-  rv = certList->ForEachCertificateInChain(
-      [&counter](nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
-        counter++;
-        return NS_ERROR_FAILURE;
-      });
-  ASSERT_EQ(counter, 1) << "There should have been only the one call";
-  ASSERT_EQ(rv, NS_ERROR_FAILURE) << "Should propagate the error.";
-}
-
 TEST_F(psm_CertList, TestGetRootCertificateChainTwo) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
+  nsTArray<RefPtr<nsIX509Cert>> certList;
 
   nsresult rv = AddCertFromStringToList(kCaIntermediatePem, certList);
   ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
   rv = AddCertFromStringToList(kCaPem, certList);
   ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
 
   nsCOMPtr<nsIX509Cert> rootCert;
-  rv = certList->GetRootCertificate(rootCert);
+  rv = nsNSSCertificate::GetRootCertificate(certList, rootCert);
   EXPECT_EQ(NS_OK, rv) << "Should have fetched the root OK";
   ASSERT_TRUE(rootCert)
   << "Root cert should be filled in";
 
   bool selfSigned;
   EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetIsSelfSigned(&selfSigned)))
       << "Getters should work.";
   EXPECT_TRUE(selfSigned) << "Roots are self signed";
 
   nsAutoString rootCn;
   EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn)))
       << "Getters should work.";
   EXPECT_TRUE(rootCn.EqualsLiteral("ca")) << "Root CN should match";
 
   // Re-fetch and ensure we get the same certificate.
   nsCOMPtr<nsIX509Cert> rootCertRepeat;
-  rv = certList->GetRootCertificate(rootCertRepeat);
+  rv = nsNSSCertificate::GetRootCertificate(certList, rootCertRepeat);
   EXPECT_EQ(NS_OK, rv) << "Should have fetched the root OK the second time";
   ASSERT_TRUE(rootCertRepeat)
   << "Root cert should still be filled in";
 
   nsAutoString rootRepeatCn;
   EXPECT_TRUE(NS_SUCCEEDED(rootCertRepeat->GetCommonName(rootRepeatCn)))
       << "Getters should work.";
   EXPECT_TRUE(rootRepeatCn.EqualsLiteral("ca")) << "Root CN should still match";
 }
 
 TEST_F(psm_CertList, TestGetRootCertificateChainFour) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
+  nsTArray<RefPtr<nsIX509Cert>> certList;
 
   nsresult rv = AddCertFromStringToList(kEePem, certList);
   ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
   rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
   ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
   rv = AddCertFromStringToList(kCaIntermediatePem, certList);
   ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
   rv = AddCertFromStringToList(kCaPem, certList);
   ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
 
   nsCOMPtr<nsIX509Cert> rootCert;
-  rv = certList->GetRootCertificate(rootCert);
+  rv = nsNSSCertificate::GetRootCertificate(certList, rootCert);
   EXPECT_EQ(NS_OK, rv) << "Should have again fetched the root OK";
   ASSERT_TRUE(rootCert)
   << "Root cert should be filled in";
 
   bool selfSigned;
   EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetIsSelfSigned(&selfSigned)))
       << "Getters should work.";
   EXPECT_TRUE(selfSigned) << "Roots are self signed";
 
   nsAutoString rootCn;
   EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn)))
       << "Getters should work.";
   EXPECT_TRUE(rootCn.EqualsLiteral("ca")) << "Root CN should match";
 }
 
 TEST_F(psm_CertList, TestGetRootCertificateChainEmpty) {
-  RefPtr<nsNSSCertList> certList = new nsNSSCertList();
+  nsTArray<RefPtr<nsIX509Cert>> certList;
 
   nsCOMPtr<nsIX509Cert> rootCert;
-  nsresult rv = certList->GetRootCertificate(rootCert);
-  EXPECT_EQ(NS_OK, rv) << "Should have again fetched the root OK";
+  nsresult rv = nsNSSCertificate::GetRootCertificate(certList, rootCert);
+  EXPECT_EQ(NS_ERROR_FAILURE, rv)
+      << "Should have returned NS_ERROR_FAILURE because certList was empty";
   EXPECT_FALSE(rootCert) << "Root cert should be empty";
 }
--- a/security/manager/ssl/tests/gtest/DeserializeCertTest.cpp
+++ b/security/manager/ssl/tests/gtest/DeserializeCertTest.cpp
@@ -4,17 +4,16 @@
  * 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 "gtest/gtest.h"
 #include "nsCOMPtr.h"
 #include "nsISimpleEnumerator.h"
 #include "nsITransportSecurityInfo.h"
 #include "nsIX509Cert.h"
-#include "nsIX509CertList.h"
 #include "nsSerializationHelper.h"
 #include "nsString.h"
 
 // nsITransportSecurityInfo de-serializatin tests
 //
 // These tests verify that we can still deserialize old binary strings
 // generated for security info.  This is necessary because service workers
 // stores these strings on disk.
--- a/security/manager/ssl/tests/unit/test_cert_chains.js
+++ b/security/manager/ssl/tests/unit/test_cert_chains.js
@@ -22,37 +22,16 @@ function test_cert_equals() {
   );
   ok(
     !certA.equals(certC),
     "equals() on cert objects constructed from files for different certs" +
       " should return false"
   );
 }
 
-function test_bad_cert_list_serialization() {
-  // Normally the serialization of an nsIX509CertList consists of some header
-  // junk (IIDs and whatnot), 4 bytes representing how many nsIX509Cert follow,
-  // and then the serialization of each nsIX509Cert. This serialization consists
-  // of the header junk for an nsIX509CertList with 1 "nsIX509Cert", but then
-  // instead of an nsIX509Cert, the subsequent bytes represent the serialization
-  // of another nsIX509CertList (with 0 nsIX509Cert). This test ensures that
-  // nsIX509CertList safely handles this unexpected input when deserializing.
-  const badCertListSerialization =
-    "lZ+xZWUXSH+rm9iRO+UxlwAAAAAAAAAAwAAAAAAAAEYAAAABlZ+xZWUXSH+rm9iRO+UxlwAAAAAA" +
-    "AAAAwAAAAAAAAEYAAAAA";
-  let serHelper = Cc["@mozilla.org/network/serialization-helper;1"].getService(
-    Ci.nsISerializationHelper
-  );
-  throws(
-    () => serHelper.deserializeObject(badCertListSerialization),
-    /NS_ERROR_UNEXPECTED/,
-    "deserializing a bogus nsIX509CertList should throw NS_ERROR_UNEXPECTED"
-  );
-}
-
 // We hard-code the following certificates for the pkcs7 export tests so that we
 // don't have to change the test data when the certificates change each year.
 // Luckily these tests don't depend on the certificates being valid, so it's ok
 // to let them expire.
 const gDefaultEEPEM = `-----BEGIN CERTIFICATE-----
 MIIDiTCCAnGgAwIBAgIUDUo/9G0rz7fJiWTw0hY6TIyPRSIwDQYJKoZIhvcNAQEL
 BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAiGA8yMDE3MTEyNzAwMDAwMFoYDzIwMjAw
 MjA1MDAwMDAwWjAaMRgwFgYDVQQDDA9UZXN0IEVuZC1lbnRpdHkwggEiMA0GCSqG
@@ -682,21 +661,16 @@ function run_test() {
 
   // Test nsIX509Cert.equals
   add_test(function() {
     test_cert_equals();
     run_next_test();
   });
 
   add_test(function() {
-    test_bad_cert_list_serialization();
-    run_next_test();
-  });
-
-  add_test(function() {
     test_cert_pkcs7_export();
     run_next_test();
   });
 
   add_test(function() {
     test_cert_pkcs7_empty_array();
     run_next_test();
   });
--- a/toolkit/components/downloads/DownloadCore.jsm
+++ b/toolkit/components/downloads/DownloadCore.jsm
@@ -1935,17 +1935,17 @@ this.DownloadCopySaver.prototype = {
 
   /**
    * Save the SHA-256 hash in raw bytes of the downloaded file. This is null
    * unless BackgroundFileSaver has successfully completed saving the file.
    */
   _sha256Hash: null,
 
   /**
-   * Save the signature info as an nsIArray of nsIX509CertList of nsIX509Cert
+   * Save the signature info as an Array of Array of raw bytes of nsIX509Cert
    * if the file is signed. This is empty if the file is unsigned, and null
    * unless BackgroundFileSaver has successfully completed saving the file.
    */
   _signatureInfo: null,
 
   /**
    * Save the redirects chain as an nsIArray of nsIPrincipal.
    */
@@ -2465,17 +2465,17 @@ this.DownloadLegacySaver.prototype = {
   /**
    * Save the SHA-256 hash in raw bytes of the downloaded file. This may be
    * null when nsExternalHelperAppService (and thus BackgroundFileSaver) is not
    * invoked.
    */
   _sha256Hash: null,
 
   /**
-   * Save the signature info as an nsIArray of nsIX509CertList of nsIX509Cert
+   * Save the signature info as an Array of Array of raw bytes of nsIX509Cert
    * if the file is signed. This is empty if the file is unsigned, and null
    * unless BackgroundFileSaver has successfully completed saving the file.
    */
   _signatureInfo: null,
 
   /**
    * Save the redirect chain as an nsIArray of nsIPrincipal.
    */
--- a/toolkit/components/securityreporter/SecurityReporter.jsm
+++ b/toolkit/components/securityreporter/SecurityReporter.jsm
@@ -45,17 +45,17 @@ SecurityReporter.prototype = {
       "security.ssl.errorReporting.url"
     );
     let reportURI = Services.io.newURI(endpoint);
 
     if (reportURI.host == hostname) {
       return;
     }
 
-    // Convert the nsIX509CertList into a format that can be parsed into
+    // Convert the array of nsIX509Cert into a format that can be parsed into
     // JSON
     let asciiCertChain = [];
 
     if (transportSecurityInfo.failedCertChain) {
       for (let cert of transportSecurityInfo.failedCertChain) {
         asciiCertChain.push(cert.getBase64DERString());
       }
     }