Bug 1411683 - Add foreach and segment utility methods to nsNSSCertList r?keeler draft
authorJ.C. Jones <jjones@mozilla.com>
Wed, 25 Oct 2017 13:37:50 -0500
changeset 686344 bc3c42964f34c1e029526830f2fe14e642913426
parent 680782 c6a2643362a67cdf7a87ac165454fce4b383debb
child 686345 8a1bebf0075b3e1232bc026a224935a9e6cf5b8d
push id86170
push userbmo:jjones@mozilla.com
push dateWed, 25 Oct 2017 19:20:48 +0000
reviewerskeeler
bugs1411683, 1409259
milestone58.0a1
Bug 1411683 - Add foreach and segment utility methods to nsNSSCertList r?keeler This adds two methods to nsNSSCertList: ForEachCertificateInChain, and SegmentCertificateChain. The ForEach method calls a supplied function for each certificate in the chain, one by one. That method is then used by the Segment method, which (assuming the chain is ordered) splits it into Root, End Entity, and everything in-between as a list of Intermediates. This patch does _not_ try to add these methods to the IDL, as it's not straightforward to me on how to handle the nsCOMPtr or std::function arguments. These methods will be first used by Bug 1409259. I've duplicated the nature of the security/manager/ssl/tests/unit certspec functions in here to provide an appropriate set of certs for the gtests. I hope I did that correctly; seems to be OK! MozReview-Commit-ID: 8qjwF3juLTr
security/manager/ssl/nsNSSCertificate.cpp
security/manager/ssl/nsNSSCertificate.h
security/manager/ssl/tests/gtest/NSSCertListTest.cpp
security/manager/ssl/tests/gtest/moz.build
security/manager/ssl/tests/gtest/test_certlist/ca-1.pem
security/manager/ssl/tests/gtest/test_certlist/ca-1.pem.certspec
security/manager/ssl/tests/gtest/test_certlist/ca-2.pem
security/manager/ssl/tests/gtest/test_certlist/ca-2.pem.certspec
security/manager/ssl/tests/gtest/test_certlist/ca-3.pem
security/manager/ssl/tests/gtest/test_certlist/ca-3.pem.certspec
security/manager/ssl/tests/gtest/test_certlist/ee.pem
security/manager/ssl/tests/gtest/test_certlist/ee.pem.certspec
security/manager/ssl/tests/gtest/test_certlist/moz.build
--- a/security/manager/ssl/nsNSSCertificate.cpp
+++ b/security/manager/ssl/nsNSSCertificate.cpp
@@ -1400,16 +1400,105 @@ nsNSSCertList::Equals(nsIX509CertList* o
   }
   if (otherHasMore) {
     *result = false;
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+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 continueLoop = false;
+  rv = chainElt->HasMoreElements(&continueLoop);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  if (!continueLoop) {
+    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(&continueLoop);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    // If the called function forces continueLoop true even when there aren't
+    // more elements, the GetNext iterator will catch it and fail us out safely.
+    rv = aOperation(cert, &continueLoop);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  } while (continueLoop);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+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();
+
+  ForEachCertificateInChain(
+    [&aRoot, &aIntermediates, &aEndEntity] (nsCOMPtr<nsIX509Cert> aCert,
+                                            bool* aContinue) {
+      if (!aContinue) {
+        return NS_ERROR_INVALID_POINTER;
+      }
+
+      if (!aRoot) {
+        // This is the root
+        aRoot = aCert.forget();
+      } else if (!*aContinue) {
+        // This is the end entity
+        aEndEntity = aCert.forget();
+      } else {
+        // One of (potentially many) intermediates
+        if (NS_FAILED(aIntermediates->AddCert(aCert))) {
+          return NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+
+      return NS_OK;
+  });
+
+  if (!aRoot || !aEndEntity) {
+    // No self-sigend (or empty) chains allowed
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  return NS_OK;
+}
+
 NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
 
 nsNSSCertListEnumerator::nsNSSCertListEnumerator(
   const UniqueCERTCertList& certList,
   const nsNSSShutDownPreventionLock& proofOfLock)
 {
   MOZ_ASSERT(certList);
   mCertList = nsNSSCertList::DupCertList(certList, proofOfLock);
--- a/security/manager/ssl/nsNSSCertificate.h
+++ b/security/manager/ssl/nsNSSCertificate.h
@@ -64,16 +64,18 @@ private:
 namespace mozilla {
 
 SECStatus ConstructCERTCertListFromReversedDERArray(
             const mozilla::pkix::DERArray& certArray,
             /*out*/ mozilla::UniqueCERTCertList& certList);
 
 } // namespace mozilla
 
+typedef const std::function<nsresult(nsCOMPtr<nsIX509Cert>& aCert, bool* aContinue)> ForEachCertOperation;
+
 class nsNSSCertList: public nsIX509CertList,
                      public nsISerializable,
                      public nsNSSShutDownObject
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIX509CERTLIST
   NS_DECL_NSISERIALIZABLE
@@ -83,16 +85,26 @@ public:
                 const nsNSSShutDownPreventionLock& proofOfLock);
 
   nsNSSCertList();
 
   static mozilla::UniqueCERTCertList DupCertList(
     const mozilla::UniqueCERTCertList& certList,
     const nsNSSShutDownPreventionLock& proofOfLock);
 
+  // For each certificate in this CertList, run the operation aOperation.
+  // To end early with NS_OK, set the boolean argument false before returning.
+  NS_IMETHODIMP ForEachCertificateInChain(ForEachCertOperation& aOperation);
+
+  // Split a certificate chain into the root, intermediates (if any), and end
+  // entity. Will return error if used on self-signed or empty chains.
+  NS_IMETHODIMP SegmentCertificateChain(/* out */ nsCOMPtr<nsIX509Cert>& aRoot,
+                           /* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
+                           /* out */ nsCOMPtr<nsIX509Cert>& aEndEntity);
+
 private:
    virtual ~nsNSSCertList();
    virtual void virtualDestroyNSSReference() override;
    void destructorSafeDestroyNSSReference();
 
    mozilla::UniqueCERTCertList mCertList;
 
    nsNSSCertList(const nsNSSCertList&) = delete;
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/NSSCertListTest.cpp
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "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"
+
+class psm_CertList : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+    ASSERT_TRUE(prefs) << "couldn't get nsIPrefBranch";
+
+    // When PSM initializes, it attempts to get some localized strings.
+    // As a result, Android flips out if this isn't set.
+    nsresult rv = prefs->SetBoolPref("intl.locale.matchOS", true);
+    ASSERT_TRUE(NS_SUCCEEDED(rv)) << "couldn't set pref 'intl.locale.matchOS'";
+
+    nsCOMPtr<nsIX509CertDB> certdb(do_GetService(NS_X509CERTDB_CONTRACTID));
+    ASSERT_TRUE(certdb) << "couldn't get certdb";
+ }
+};
+
+template <size_t N>
+nsresult
+ReadFileToBuffer(const char* basePath, const char* filename, char (&buf)[N])
+{
+  static_assert(N > 0, "input buffer too small for ReadFileToBuffer");
+  if (snprintf(buf, N - 1, "%s/%s", basePath, filename) == 0) {
+    return NS_ERROR_FAILURE;
+  }
+  mozilla::UniquePRFileDesc fd(PR_OpenFile(buf, PR_RDONLY, 0));
+  if (!fd) {
+    return NS_ERROR_FAILURE;
+  }
+  int32_t fileSize = PR_Available(fd.get());
+  if (fileSize < 0) {
+    return NS_ERROR_FAILURE;
+  }
+  if (static_cast<size_t>(fileSize) > N - 1) {
+    return NS_ERROR_FAILURE;
+  }
+  int32_t bytesRead = PR_Read(fd.get(), buf, fileSize);
+  if (bytesRead != fileSize) {
+    return NS_ERROR_FAILURE;
+  }
+  buf[bytesRead] = 0;
+  return NS_OK;
+}
+
+static nsresult
+LoadCertificateFromFile(const char* aBasePath, const char* aFilename,
+                        /* out */ nsCOMPtr<nsIX509Cert>& aCert)
+{
+  char buf[16384] = { 0 };
+  nsresult rv = ReadFileToBuffer(aBasePath, aFilename, buf);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsNSSCertificate* cert = nsNSSCertificate::ConstructFromDER(buf, strlen(buf));
+  if (!cert) {
+    return NS_ERROR_FAILURE;
+  }
+
+  aCert = cert;
+  return NS_OK;
+}
+
+static nsresult
+AddCertFromFileToList(const char* aBasePath, const char* aFilename,
+                      /* out */ nsIX509CertList* aCertList) {
+  nsCOMPtr<nsIX509Cert> cert;
+  nsresult rv = LoadCertificateFromFile(aBasePath, aFilename, cert);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  return aCertList->AddCert(cert);
+}
+
+static int
+CountCertsInList(nsCOMPtr<nsIX509CertList>& aCertList) {
+  int counter = 0;
+  nsNSSCertList* certList = static_cast<nsNSSCertList*>(aCertList.get());
+  certList->ForEachCertificateInChain(
+    [&counter] (nsCOMPtr<nsIX509Cert> aCert, bool* aContinue) {
+      if (!aContinue) {
+        return NS_ERROR_INVALID_POINTER;
+      }
+
+      counter++;
+      return NS_OK;
+  });
+
+  return counter;
+}
+
+TEST_F(psm_CertList, TestInvalidSegmenting)
+{
+  nsNSSCertList* certList = new nsNSSCertList();
+
+  nsCOMPtr<nsIX509Cert> rootCert;
+  nsCOMPtr<nsIX509CertList> intCerts;
+  nsCOMPtr<nsIX509Cert> eeCert;
+  nsresult rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
+  ASSERT_EQ(rv, NS_ERROR_INVALID_ARG) << "Empty lists can't be segmented";
+
+  rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-1.pem", 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;
+  rootCert = eeCert = nullptr;
+
+  rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
+  ASSERT_EQ(rv, NS_ERROR_INVALID_ARG) << "Lists of one can't be segmented";
+}
+
+TEST_F(psm_CertList, TestValidSegmenting)
+{
+  nsNSSCertList* certList = new nsNSSCertList();
+
+  nsresult rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-1.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+  rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-2.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+
+  nsCOMPtr<nsIX509Cert> rootCert;
+  nsCOMPtr<nsIX509CertList> intCerts;
+  nsCOMPtr<nsIX509Cert> eeCert;
+
+  rv = certList->SegmentCertificateChain(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) << "There should be no intermediates";
+
+  rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ee.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+
+  intCerts = nullptr;
+  rootCert = eeCert = nullptr;
+  rv = certList->SegmentCertificateChain(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) << "There should be one intermediate";
+
+  rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-3.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+
+  intCerts = nullptr;
+  rootCert = eeCert = nullptr;
+  rv = certList->SegmentCertificateChain(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) << "There should be two intermediates";
+}
+
+TEST_F(psm_CertList, TestForEach)
+{
+  nsNSSCertList* certList = new nsNSSCertList();
+
+  bool called = false;
+  nsresult rv = certList->ForEachCertificateInChain(
+    [&called] (nsCOMPtr<nsIX509Cert> aCert, 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 = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-1.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+  rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-2.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+
+  int counter = 0;
+  rv = certList->ForEachCertificateInChain(
+    [&counter] (nsCOMPtr<nsIX509Cert> aCert, bool* aContinue) -> nsresult {
+      if (!aCert || !aContinue) {
+        GTEST_NONFATAL_FAILURE_("Unexpected arguments");
+        return NS_ERROR_FAILURE;
+      }
+
+      switch(counter) {
+      case 0:
+        if (!*aContinue) {
+          return NS_ERROR_FAILURE;
+        }
+        break;
+      case 1:
+        if (*aContinue) {
+          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)
+{
+  nsNSSCertList* certList = new nsNSSCertList();
+
+  // Add two certificates
+  nsresult rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-1.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+  rv = AddCertFromFileToList("../../../security/manager/ssl/tests/gtest/test_certlist", "ca-2.pem", certList);
+  ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
+
+  int counter = 0;
+  rv = certList->ForEachCertificateInChain(
+    [&counter] (nsCOMPtr<nsIX509Cert> aCert, bool* aContinue) {
+      counter++;
+      *aContinue = true; // Try to keep it going illegally
+      return NS_OK;
+    });
+  ASSERT_EQ(counter, 2) << "There should have been only two iterations regardless!";
+  ASSERT_EQ(rv, NS_ERROR_FAILURE) << "Should not have completed as OK, since this was bad.";
+}
--- a/security/manager/ssl/tests/gtest/moz.build
+++ b/security/manager/ssl/tests/gtest/moz.build
@@ -4,25 +4,30 @@
 # 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/.
 
 SOURCES += [
     'CertDBTest.cpp',
     'DataStorageTest.cpp',
     'DeserializeCertTest.cpp',
     'MD4Test.cpp',
+    'NSSCertListTest.cpp',
     'OCSPCacheTest.cpp',
     'TLSIntoleranceTest.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/security/certverifier',
     '/security/manager/ssl',
     '/security/pkix/include',
     '/security/pkix/test/lib',
 ]
 
+TEST_DIRS += [
+    'test_certlist',
+]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul-gtest'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ca-1.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsjCCAZygAwIBAgIBATALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCY2Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgHAMAsGCSqGSIb3DQEB
+CwOCAQEAA8Itk+xWCB48etYN+MDCway+vIgnyPIXmOzpygMXNyU+hRBKIaYslyhA
+rDtQCmj01Bf+rEnVzd/HUHQTjESyFyGQ7DQhUkbwgpnr0h0wmi811JLNsJ7T9lel
+bCNo6eCfm5fWkN5eaBfzZ7WmNmp5xmIoQKg6Sv5p2reKVDLdL1D6NcYTKN+7QSMt
+UhVY5rMx6ILSBddX6gnb01jHTAjk/Fp7KK9eiGr7YNZNJqdT90iFbgVneJvIg1PT
+qF29MoWsr7BuVIrWsC7aNUa9pZq66YO/krioAGgZwIAWNkHsPqgFc1hbEYTcTgZU
+WQH5ndFUreEsS1jwUZBTpjdF1HDlcA==
+-----END CERTIFICATE-----
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ca-1.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+serialNumber:1
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ca-2.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvzCCAamgAwIBAgIBAjALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowGjEYMBYGA1UEAwwPY2Et
+aW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
+qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
+WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
+JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
+Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
+clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB
+wDALBgkqhkiG9w0BAQsDggEBALT9RFOLGhDXWVMFw76I5HwX7sCseh+FZN4NA3hm
+vL5sl3/0rZp0ybFj+cUUzY3nbe+fS88ubZHX59c1aZ1ROCKDplL7sM0p7ZdOLJXb
+ZvRiOYE3lCQJVkzDhig/plyhdy7ptxdCqDICM1f9tnYWCZYdrPARPcSUnckFNtZ5
+jYx/6MFzApVGAWBlmWLVI+GRr4pLka/vv3ul2ggJ/oOg3ZTdG0XnKMyK7sRaolPp
+q6Nqypa4PfAXeAtq/3AsrgoKBY3CXXJxtnyUQYhIrerXYdWNEKJFDWp46VJTVJC4
+DWCe/SWo+XcM3IoXMDs250KMEh6zT3UjXsKztvoQic4UY00=
+-----END CERTIFICATE-----
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ca-2.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:ca-intermediate
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+serialNumber:2
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ca-3.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAb2gAwIBAgIBAzALBgkqhkiG9w0BAQswGjEYMBYGA1UEAwwPY2EtaW50
+ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMCEx
+HzAdBgNVBAMMFmNhLXNlY29uZC1pbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1Ud
+EwQFMAMBAf8wCwYDVR0PBAQDAgHAMAsGCSqGSIb3DQEBCwOCAQEAn5H1Wkdn/dx4
+ordvtqsgvC8w4X3gVajHguGAg0oACfEoyzom8Tw3jDhLNeCS8sNuD3VxNRbtXtpN
+77hdKPjOKiz0LA/6JgHyh+YmX4ESDHI/gBL+1fK08mg5ouJwwJTFPFjlkMI6h04z
+SSEvvhUEBOYYvhnPdj5F9FyRd8jxmtTiWROpoPkhM1yfEBUDK5vfNR4QfcHKBIRQ
+87fw8C9HIw/ukX0XSfukYAXwv/IgHVNPn6NXGlpscXwxQCEutwJNgfIX34evIVRl
+XDqmQIuAVXpwBGlRv7tGvHV0nCaCEuukYs4qcSYpUTFWm/q5MaXVpo6aPcev77Fw
+gxqTmAntSA==
+-----END CERTIFICATE-----
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ca-3.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca-intermediate
+subject:ca-second-intermediate
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+serialNumber:3
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICujCCAaSgAwIBAgIUMy8NE67P/4jkaCra7rOVVvX4+GswCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmNhLXNlY29uZC1pbnRlcm1lZGlhdGUwIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCZWUwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq0
+7PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D
+/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuw
+JJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyX
+rZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWd
+q5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJ
+KoZIhvcNAQELA4IBAQCE5V5YiFPtbb1dOCIMGC5X/6kfQkQmIfvEZIol0MRXmP4g
+CsOPbTI+BNxYVNk5RHIlr+6e0d8TNiABem4FZK3kea4ugN8ez3IsK7ug7qdrooNA
+MiHOvrLmAw2nQWexdDRf7OPeVj03BwELzGTOGPjAqDktTsK57OfXyFTm9nl75WQo
++EWX+CdV4L1o2rgABvSiMnMdycftCC73Hr/3ypADqY7nDrKpxYdrGgzAQvx3DjPv
+b7nBKH/gXg3kzoWpeQmJYPl9Vd+DvGljS5i71oLbvCwlDX7ZswGcvb8pQ7Tni5HA
+VYpAYLokxIDFnyVT9oCACJuJ5LvpBBrhd0+1uUPE
+-----END CERTIFICATE-----
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/ee.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-second-intermediate
+subject:ee
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/test_certlist/moz.build
@@ -0,0 +1,16 @@
+# -*- Mode: python; 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 = (
+#    'ca-1.pem',
+#    'ca-2.pem',
+#    'ca-3.pem',
+#    'ee.pem',
+#)
+#
+#for test_certificate in test_certificates:
+#    GeneratedTestCertificate(test_certificate)