Bug 1061021, Part 14: Stop using PLArenaPool in CreateEncodedCertificate, r=keeler
authorBrian Smith <brian@briansmith.org>
Sat, 30 Aug 2014 23:09:18 -0700
changeset 14685 8743adefe38aa1f100d74405ab7fc76caec1ceaf
parent 14684 1fd4a7e00bd180cf93d16905190eb62e46ac48e7
child 14686 88a132d5b1ab3f40e7634f2fc8727e72eb6653ab
push id3202
push userfranziskuskiefer@gmail.com
push dateMon, 01 Oct 2018 08:30:12 +0000
reviewerskeeler
bugs1061021
Bug 1061021, Part 14: Stop using PLArenaPool in CreateEncodedCertificate, r=keeler
lib/mozpkix/test/gtest/pkixbuild_tests.cpp
lib/mozpkix/test/gtest/pkixcert_extension_tests.cpp
lib/mozpkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
lib/mozpkix/test/lib/pkixtestutil.cpp
lib/mozpkix/test/lib/pkixtestutil.h
--- a/lib/mozpkix/test/gtest/pkixbuild_tests.cpp
+++ b/lib/mozpkix/test/gtest/pkixbuild_tests.cpp
@@ -33,20 +33,20 @@
 
 using namespace mozilla::pkix;
 using namespace mozilla::pkix::test;
 
 typedef ScopedPtr<CERTCertificate, CERT_DestroyCertificate>
           ScopedCERTCertificate;
 typedef ScopedPtr<CERTCertList, CERT_DestroyCertList> ScopedCERTCertList;
 
-// The result is owned by the arena
-static Input
-CreateCert(PLArenaPool* arena, const char* issuerCN,
-           const char* subjectCN, EndEntityOrCA endEntityOrCA,
+static ByteString
+CreateCert(const char* issuerCN,
+           const char* subjectCN,
+           EndEntityOrCA endEntityOrCA,
            /*optional*/ SECKEYPrivateKey* issuerKey,
            /*out*/ ScopedSECKEYPrivateKey& subjectKey,
            /*out*/ ScopedCERTCertificate* subjectCert = nullptr)
 {
   static long serialNumberValue = 0;
   ++serialNumberValue;
   ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
   EXPECT_NE(ENCODING_FAILED, serialNumber);
@@ -59,31 +59,35 @@ CreateCert(PLArenaPool* arena, const cha
   ByteString extensions[2];
   if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
     extensions[0] =
       CreateEncodedBasicConstraints(true, nullptr,
                                     ExtensionCriticality::Critical);
     EXPECT_NE(ENCODING_FAILED, extensions[0]);
   }
 
-  SECItem* certDER(CreateEncodedCertificate(
-                     arena, v3, sha256WithRSAEncryption,
-                     serialNumber, issuerDER, oneDayBeforeNow, oneDayAfterNow,
-                     subjectDER, extensions, issuerKey,
-                     SignatureAlgorithm::rsa_pkcs1_with_sha256,
-                     subjectKey));
-  EXPECT_TRUE(certDER);
+  ByteString certDER(CreateEncodedCertificate(
+                       v3, sha256WithRSAEncryption,
+                       serialNumber, issuerDER,
+                       oneDayBeforeNow, oneDayAfterNow,
+                       subjectDER, extensions, issuerKey,
+                       SignatureAlgorithm::rsa_pkcs1_with_sha256,
+                       subjectKey));
+  EXPECT_NE(ENCODING_FAILED, certDER);
   if (subjectCert) {
-    *subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER,
-                                           nullptr, false, true);
+    SECItem certDERItem = {
+      siBuffer,
+      const_cast<uint8_t*>(certDER.data()),
+      static_cast<unsigned int>(certDER.length())
+    };
+    *subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+                                           &certDERItem, nullptr, false, true);
     EXPECT_TRUE(*subjectCert);
   }
-  Input result;
-  EXPECT_EQ(Success, result.Init(certDER->data, certDER->len));
-  return result;
+  return certDER;
 }
 
 class TestTrustDomain : public TrustDomain
 {
 public:
   // The "cert chain tail" is a longish chain of certificates that is used by
   // all of the tests here. We share this chain across all the tests in order
   // to speed up the tests (generating keypairs for the certs is very slow).
@@ -92,26 +96,20 @@ public:
     static char const* const names[] = {
         "CA1 (Root)", "CA2", "CA3", "CA4", "CA5", "CA6", "CA7"
     };
 
     static_assert(MOZILLA_PKIX_ARRAY_LENGTH(names) ==
                     MOZILLA_PKIX_ARRAY_LENGTH(certChainTail),
                   "mismatch in sizes of names and certChainTail arrays");
 
-    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
-    if (!arena) {
-      return false;
-    }
-
     for (size_t i = 0; i < MOZILLA_PKIX_ARRAY_LENGTH(names); ++i) {
       const char* issuerName = i == 0 ? names[0] : names[i-1];
-      (void) CreateCert(arena.get(), issuerName, names[i],
-                 EndEntityOrCA::MustBeCA, leafCAKey.get(), leafCAKey,
-                 &certChainTail[i]);
+      (void) CreateCert(issuerName, names[i], EndEntityOrCA::MustBeCA,
+                        leafCAKey.get(), leafCAKey, &certChainTail[i]);
     }
 
     return true;
   }
 
 private:
   virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
                               Input candidateCert,
@@ -237,22 +235,24 @@ TEST_F(pkixbuild, MaxAcceptableCertChain
                              KeyPurposeId::id_kp_serverAuth,
                              CertPolicyId::anyPolicy,
                              nullptr/*stapledOCSPResponse*/));
   }
 
   {
     ScopedSECKEYPrivateKey privateKey;
     ScopedCERTCertificate cert;
-    Input certDER(CreateCert(arena.get(),
-                             "CA7", "Direct End-Entity",
-                             EndEntityOrCA::MustBeEndEntity,
-                             trustDomain.leafCAKey.get(), privateKey));
+    ByteString certDER(CreateCert("CA7", "Direct End-Entity",
+                                  EndEntityOrCA::MustBeEndEntity,
+                                  trustDomain.leafCAKey.get(), privateKey));
+    ASSERT_NE(ENCODING_FAILED, certDER);
+    Input certDERInput;
+    ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
     ASSERT_EQ(Success,
-              BuildCertChain(trustDomain, certDER, Now(),
+              BuildCertChain(trustDomain, certDERInput, Now(),
                              EndEntityOrCA::MustBeEndEntity,
                              KeyUsage::noParticularKeyUsageRequired,
                              KeyPurposeId::id_kp_serverAuth,
                              CertPolicyId::anyPolicy,
                              nullptr/*stapledOCSPResponse*/));
   }
 }
 
@@ -261,36 +261,40 @@ TEST_F(pkixbuild, BeyondMaxAcceptableCer
   static char const* const caCertName = "CA Too Far";
   ScopedSECKEYPrivateKey caPrivateKey;
 
   // We need a CERTCertificate for caCert so that the trustdomain's FindIssuer
   // method can find it through the NSS cert DB.
   ScopedCERTCertificate caCert;
 
   {
-    Input cert(CreateCert(arena.get(), "CA7",
-                          caCertName, EndEntityOrCA::MustBeCA,
-                          trustDomain.leafCAKey.get(), caPrivateKey,
-                          &caCert));
+    ByteString certDER(CreateCert("CA7", caCertName, EndEntityOrCA::MustBeCA,
+                                  trustDomain.leafCAKey.get(), caPrivateKey,
+                                  &caCert));
+    ASSERT_NE(ENCODING_FAILED, certDER);
+    Input certDERInput;
+    ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
     ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
-              BuildCertChain(trustDomain, cert, Now(),
+              BuildCertChain(trustDomain, certDERInput, Now(),
                              EndEntityOrCA::MustBeCA,
                              KeyUsage::noParticularKeyUsageRequired,
                              KeyPurposeId::id_kp_serverAuth,
                              CertPolicyId::anyPolicy,
                              nullptr/*stapledOCSPResponse*/));
   }
 
   {
     ScopedSECKEYPrivateKey privateKey;
-    Input cert(CreateCert(arena.get(), caCertName,
-                          "End-Entity Too Far",
-                          EndEntityOrCA::MustBeEndEntity,
-                          caPrivateKey.get(), privateKey));
+    ByteString certDER(CreateCert(caCertName, "End-Entity Too Far",
+                                  EndEntityOrCA::MustBeEndEntity,
+                                  caPrivateKey.get(), privateKey));
+    ASSERT_NE(ENCODING_FAILED, certDER);
+    Input certDERInput;
+    ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
     ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
-              BuildCertChain(trustDomain, cert, Now(),
+              BuildCertChain(trustDomain, certDERInput, Now(),
                              EndEntityOrCA::MustBeEndEntity,
                              KeyUsage::noParticularKeyUsageRequired,
                              KeyPurposeId::id_kp_serverAuth,
                              CertPolicyId::anyPolicy,
                              nullptr/*stapledOCSPResponse*/));
   }
 }
--- a/lib/mozpkix/test/gtest/pkixcert_extension_tests.cpp
+++ b/lib/mozpkix/test/gtest/pkixcert_extension_tests.cpp
@@ -27,51 +27,46 @@
 #include "pkix/pkixnss.h"
 #include "pkixtestutil.h"
 #include "secerr.h"
 
 using namespace mozilla::pkix;
 using namespace mozilla::pkix::test;
 
 // Creates a self-signed certificate with the given extension.
-static Input
-CreateCert(PLArenaPool* arena, const char* subjectCN,
+static ByteString
+CreateCert(const char* subjectCN,
            const ByteString* extensions, // empty-string-terminated array
            /*out*/ ScopedSECKEYPrivateKey& subjectKey)
 {
   static long serialNumberValue = 0;
   ++serialNumberValue;
   ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
   EXPECT_NE(ENCODING_FAILED, serialNumber);
   ByteString issuerDER(CNToDERName(subjectCN));
   EXPECT_NE(ENCODING_FAILED, issuerDER);
   ByteString subjectDER(CNToDERName(subjectCN));
   EXPECT_NE(ENCODING_FAILED, subjectDER);
-  SECItem* cert = CreateEncodedCertificate(
-                                  arena, v3, sha256WithRSAEncryption,
+  return CreateEncodedCertificate(v3, sha256WithRSAEncryption,
                                   serialNumber, issuerDER,
                                   oneDayBeforeNow, oneDayAfterNow,
                                   subjectDER, extensions,
                                   nullptr,
                                   SignatureAlgorithm::rsa_pkcs1_with_sha256,
                                   subjectKey);
-  EXPECT_TRUE(cert);
-  Input result;
-  EXPECT_EQ(Success, result.Init(cert->data, cert->len));
-  return result;
 }
 
 // Creates a self-signed certificate with the given extension.
-static Input
-CreateCert(PLArenaPool* arena, const char* subjectStr,
+static ByteString
+CreateCert(const char* subjectStr,
            const ByteString& extension,
            /*out*/ ScopedSECKEYPrivateKey& subjectKey)
 {
   const ByteString extensions[] = { extension, ByteString() };
-  return CreateCert(arena, subjectStr, extensions, subjectKey);
+  return CreateCert(subjectStr, extensions, subjectKey);
 }
 
 class TrustEverythingTrustDomain : public TrustDomain
 {
 private:
   virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
                               Input candidateCert,
                               /*out*/ TrustLevel& trustLevel)
@@ -146,20 +141,22 @@ TEST_F(pkixcert_extension, UnknownCritic
       0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
       0x04, 0x00 // OCTET STRING (length = 0)
   };
   static const ByteString
     unknownCriticalExtension(unknownCriticalExtensionBytes,
                              sizeof(unknownCriticalExtensionBytes));
   const char* certCN = "Cert With Unknown Critical Extension";
   ScopedSECKEYPrivateKey key;
-  // cert is owned by the arena
-  Input cert(CreateCert(arena.get(), certCN, unknownCriticalExtension, key));
+  ByteString cert(CreateCert(certCN, unknownCriticalExtension, key));
+  ASSERT_NE(ENCODING_FAILED, cert);
+  Input certInput;
+  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
-            BuildCertChain(trustDomain, cert, Now(),
+            BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
 
 // Tests that a non-critical extension not in the id-ce or id-pe arcs (which is
@@ -174,20 +171,22 @@ TEST_F(pkixcert_extension, UnknownNonCri
         0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03,
       0x04, 0x00 // OCTET STRING (length = 0)
   };
   static const ByteString
     unknownNonCriticalExtension(unknownNonCriticalExtensionBytes,
                                 sizeof(unknownNonCriticalExtensionBytes));
   const char* certCN = "Cert With Unknown NonCritical Extension";
   ScopedSECKEYPrivateKey key;
-  // cert is owned by the arena
-  Input cert(CreateCert(arena.get(), certCN, unknownNonCriticalExtension, key));
+  ByteString cert(CreateCert(certCN, unknownNonCriticalExtension, key));
+  ASSERT_NE(ENCODING_FAILED, cert);
+  Input certInput;
+  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Success,
-            BuildCertChain(trustDomain, cert, Now(),
+            BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
 
 // Tests that an incorrect OID for id-pe-authorityInformationAccess
@@ -203,20 +202,22 @@ TEST_F(pkixcert_extension, WrongOIDCriti
       0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
       0x04, 0x00 // OCTET STRING (length = 0)
   };
   static const ByteString
     wrongOIDCriticalExtension(wrongOIDCriticalExtensionBytes,
                               sizeof(wrongOIDCriticalExtensionBytes));
   const char* certCN = "Cert With Critical Wrong OID Extension";
   ScopedSECKEYPrivateKey key;
-  // cert is owned by the arena
-  Input cert(CreateCert(arena.get(), certCN, wrongOIDCriticalExtension, key));
+  ByteString cert(CreateCert(certCN, wrongOIDCriticalExtension, key));
+  ASSERT_NE(ENCODING_FAILED, cert);
+  Input certInput;
+  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
-            BuildCertChain(trustDomain, cert, Now(),
+            BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
 
 // Tests that a id-pe-authorityInformationAccess critical extension
@@ -234,20 +235,22 @@ TEST_F(pkixcert_extension, CriticalAIAEx
       0x04, 0x02, // OCTET STRING (length = 2)
         0x30, 0x00, // SEQUENCE (length = 0)
   };
   static const ByteString
     criticalAIAExtension(criticalAIAExtensionBytes,
                          sizeof(criticalAIAExtensionBytes));
   const char* certCN = "Cert With Critical AIA Extension";
   ScopedSECKEYPrivateKey key;
-  // cert is owned by the arena
-  Input cert(CreateCert(arena.get(), certCN, criticalAIAExtension, key));
+  ByteString cert(CreateCert(certCN, criticalAIAExtension, key));
+  ASSERT_NE(ENCODING_FAILED, cert);
+  Input certInput;
+  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Success,
-            BuildCertChain(trustDomain, cert, Now(),
+            BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
 
 // We know about some id-ce extensions (OID arc 2.5.29), but not all of them.
@@ -262,20 +265,22 @@ TEST_F(pkixcert_extension, UnknownCritic
       0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
       0x04, 0x00 // OCTET STRING (length = 0)
   };
   static const ByteString
     unknownCriticalCEExtension(unknownCriticalCEExtensionBytes,
                                sizeof(unknownCriticalCEExtensionBytes));
   const char* certCN = "Cert With Unknown Critical id-ce Extension";
   ScopedSECKEYPrivateKey key;
-  // cert is owned by the arena
-  Input cert(CreateCert(arena.get(), certCN, unknownCriticalCEExtension, key));
+  ByteString cert(CreateCert(certCN, unknownCriticalCEExtension, key));
+  ASSERT_NE(ENCODING_FAILED, cert);
+  Input certInput;
+  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
-            BuildCertChain(trustDomain, cert, Now(),
+            BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
 
 // Tests that a certificate with a known critical id-ce extension (in this case,
@@ -290,20 +295,22 @@ TEST_F(pkixcert_extension, KnownCritical
       0x04, 0x03, // OCTET STRING (length = 3)
         0x02, 0x01, 0x00, // INTEGER (length = 1, value = 0)
   };
   static const ByteString
     criticalCEExtension(criticalCEExtensionBytes,
                         sizeof(criticalCEExtensionBytes));
   const char* certCN = "Cert With Known Critical id-ce Extension";
   ScopedSECKEYPrivateKey key;
-  // cert is owned by the arena
-  Input cert(CreateCert(arena.get(), certCN, criticalCEExtension, key));
+  ByteString cert(CreateCert(certCN, criticalCEExtension, key));
+  ASSERT_NE(ENCODING_FAILED, cert);
+  Input certInput;
+  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Success,
-            BuildCertChain(trustDomain, cert, Now(),
+            BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
 
 // Two subjectAltNames must result in an error.
@@ -317,18 +324,20 @@ TEST_F(pkixcert_extension, DuplicateSubj
         0x30, 13, // GeneralNames (SEQUENCE) (length = 13)
           0x82, 11, // [2] (dNSName) (length = 11)
             'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'
   };
   static const ByteString DER(DER_BYTES, sizeof(DER_BYTES));
   static const ByteString extensions[] = { DER, DER, ByteString() };
   static const char* certCN = "Cert With Duplicate subjectAltName";
   ScopedSECKEYPrivateKey key;
-  // cert is owned by the arena
-  Input cert(CreateCert(arena.get(), certCN, extensions, key));
+  ByteString cert(CreateCert(certCN, extensions, key));
+  ASSERT_NE(ENCODING_FAILED, cert);
+  Input certInput;
+  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
-            BuildCertChain(trustDomain, cert, Now(),
+            BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
--- a/lib/mozpkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
+++ b/lib/mozpkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
@@ -268,17 +268,17 @@ public:
   // The result is owned by the arena
   Input CreateEncodedOCSPSuccessfulResponse(
                     OCSPResponseContext::CertStatus certStatus,
                     const CertID& certID,
                     /*optional*/ const char* signerName,
                     const ScopedSECKEYPrivateKey& signerPrivateKey,
                     time_t producedAt, time_t thisUpdate,
                     /*optional*/ const time_t* nextUpdate,
-                    /*optional*/ SECItem const* const* certs = nullptr)
+                    /*optional*/ const ByteString* certs = nullptr)
   {
     OCSPResponseContext context(arena.get(), certID, producedAt);
     if (signerName) {
       context.signerNameDER = CNToDERName(signerName);
       EXPECT_NE(ENCODING_FAILED, context.signerNameDER);
     }
     context.signerPrivateKey = SECKEY_CopyPrivateKey(signerPrivateKey.get());
     EXPECT_TRUE(context.signerPrivateKey);
@@ -385,83 +385,79 @@ protected:
   // signerName should be byKey to use the byKey ResponderID construction, or
   // another value (usually equal to certSubjectName) to use the byName
   // ResponderID construction.
   //
   // If signerEKU is omitted, then the certificate will have the
   // id-kp-OCSPSigning EKU. If signerEKU is SEC_OID_UNKNOWN then it will not
   // have any EKU extension. Otherwise, the certificate will have the given
   // EKU.
-  //
-  // signerDEROut is owned by the arena
   Input CreateEncodedIndirectOCSPSuccessfulResponse(
               const char* certSubjectName,
               OCSPResponseContext::CertStatus certStatus,
               const char* signerName,
               /*optional*/ const Input* signerEKUDER = &OCSPSigningEKUDER,
-              /*optional, out*/ Input* signerDEROut = nullptr)
+              /*optional, out*/ ByteString* signerDEROut = nullptr)
   {
     assert(certSubjectName);
 
     const ByteString extensions[] = {
       signerEKUDER
         ? CreateEncodedEKUExtension(*signerEKUDER,
                                     ExtensionCriticality::NotCritical)
         : ByteString(),
       ByteString()
     };
     ScopedSECKEYPrivateKey signerPrivateKey;
-    SECItem* signerDER(CreateEncodedCertificate(
-                          arena.get(), ++rootIssuedCount, rootName,
-                          oneDayBeforeNow, oneDayAfterNow, certSubjectName,
-                          signerEKUDER ? extensions : nullptr,
-                          rootPrivateKey.get(), signerPrivateKey));
-    EXPECT_TRUE(signerDER);
+    ByteString signerDER(CreateEncodedCertificate(
+                           ++rootIssuedCount, rootName,
+                           oneDayBeforeNow, oneDayAfterNow, certSubjectName,
+                           signerEKUDER ? extensions : nullptr,
+                           rootPrivateKey.get(), signerPrivateKey));
+    EXPECT_NE(ENCODING_FAILED, signerDER);
     if (signerDEROut) {
-      EXPECT_EQ(Success,
-                signerDEROut->Init(signerDER->data, signerDER->len));
+      *signerDEROut = signerDER;
     }
 
     ByteString signerNameDER;
     if (signerName) {
       signerNameDER = CNToDERName(signerName);
       EXPECT_NE(ENCODING_FAILED, signerNameDER);
     }
-    SECItem const* const certs[] = { signerDER, nullptr };
+    ByteString certs[] = { signerDER, ByteString() };
     return CreateEncodedOCSPSuccessfulResponse(certStatus, *endEntityCertID,
                                                signerName, signerPrivateKey,
                                                oneDayBeforeNow,
                                                oneDayBeforeNow,
                                                &oneDayAfterNow, certs);
   }
 
-  static SECItem* CreateEncodedCertificate(PLArenaPool* arena,
-                                           uint32_t serialNumber,
-                                           const char* issuer,
-                                           time_t notBefore,
-                                           time_t notAfter,
-                                           const char* subject,
-                              /*optional*/ const ByteString* extensions,
-                              /*optional*/ SECKEYPrivateKey* signerKey,
-                                   /*out*/ ScopedSECKEYPrivateKey& privateKey)
+  static ByteString CreateEncodedCertificate(uint32_t serialNumber,
+                                             const char* issuer,
+                                             time_t notBefore,
+                                             time_t notAfter,
+                                             const char* subject,
+                                /*optional*/ const ByteString* extensions,
+                                /*optional*/ SECKEYPrivateKey* signerKey,
+                                     /*out*/ ScopedSECKEYPrivateKey& privateKey)
   {
     ByteString serialNumberDER(CreateEncodedSerialNumber(serialNumber));
     if (serialNumberDER == ENCODING_FAILED) {
-      return nullptr;
+      return ENCODING_FAILED;
     }
     ByteString issuerDER(CNToDERName(issuer));
     if (issuerDER == ENCODING_FAILED) {
-      return nullptr;
+      return ENCODING_FAILED;
     }
     ByteString subjectDER(CNToDERName(subject));
     if (subjectDER == ENCODING_FAILED) {
-      return nullptr;
+      return ENCODING_FAILED;
     }
     return ::mozilla::pkix::test::CreateEncodedCertificate(
-                                    arena, v3,
+                                    v3,
                                     sha256WithRSAEncryption,
                                     serialNumberDER, issuerDER, notBefore,
                                     notAfter, subjectDER, extensions,
                                     signerKey,
                                     SignatureAlgorithm::rsa_pkcs1_with_sha256,
                                     privateKey);
   }
 
@@ -541,26 +537,25 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
 
   const ByteString extensions[] = {
     CreateEncodedEKUExtension(OCSPSigningEKUDER,
                               ExtensionCriticality::NotCritical),
     ByteString()
   };
 
   ScopedSECKEYPrivateKey signerPrivateKey;
-  SECItem* signerDER(CreateEncodedCertificate(arena.get(), ++rootIssuedCount,
-                                              rootName,
-                                              now - (10 * Time::ONE_DAY_IN_SECONDS),
-                                              now - (2 * Time::ONE_DAY_IN_SECONDS),
-                                              signerName, extensions,
-                                              rootPrivateKey.get(),
-                                              signerPrivateKey));
-  ASSERT_TRUE(signerDER);
+  ByteString signerDER(CreateEncodedCertificate(
+                          ++rootIssuedCount, rootName,
+                          now - (10 * Time::ONE_DAY_IN_SECONDS),
+                          now - (2 * Time::ONE_DAY_IN_SECONDS),
+                          signerName, extensions, rootPrivateKey.get(),
+                          signerPrivateKey));
+  ASSERT_NE(ENCODING_FAILED, signerDER);
 
-  SECItem const* const certs[] = { signerDER, nullptr };
+  ByteString certs[] = { signerDER, ByteString() };
   Input response(CreateEncodedOCSPSuccessfulResponse(
                          OCSPResponseContext::good, *endEntityCertID,
                          signerName, signerPrivateKey, oneDayBeforeNow,
                          oneDayBeforeNow, &oneDayAfterNow, certs));
   bool expired;
   ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
             VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
                                       END_ENTITY_MAX_LIFETIME_IN_DAYS,
@@ -573,26 +568,25 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
 
   const ByteString extensions[] = {
     CreateEncodedEKUExtension(OCSPSigningEKUDER,
                               ExtensionCriticality::NotCritical),
     ByteString()
   };
 
   ScopedSECKEYPrivateKey signerPrivateKey;
-  SECItem* signerDER(CreateEncodedCertificate(arena.get(), ++rootIssuedCount,
-                                              rootName,
-                                              now + (2 * Time::ONE_DAY_IN_SECONDS),
-                                              now + (10 * Time::ONE_DAY_IN_SECONDS),
-                                              signerName, extensions,
-                                              rootPrivateKey.get(),
-                                              signerPrivateKey));
-  ASSERT_TRUE(signerDER);
+  ByteString signerDER(CreateEncodedCertificate(
+                         ++rootIssuedCount, rootName,
+                         now + (2 * Time::ONE_DAY_IN_SECONDS),
+                         now + (10 * Time::ONE_DAY_IN_SECONDS),
+                         signerName, extensions, rootPrivateKey.get(),
+                         signerPrivateKey));
+  ASSERT_NE(ENCODING_FAILED, signerDER);
 
-  SECItem const* const certs[] = { signerDER, nullptr };
+  ByteString certs[] = { signerDER, ByteString() };
   Input response(CreateEncodedOCSPSuccessfulResponse(
                          OCSPResponseContext::good, *endEntityCertID,
                          signerName, signerPrivateKey, oneDayBeforeNow,
                          oneDayBeforeNow, &oneDayAfterNow, certs));
   bool expired;
   ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
             VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
                                       END_ENTITY_MAX_LIFETIME_IN_DAYS,
@@ -667,24 +661,24 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
 
   // Delegated responder cert signed by unknown issuer
   const ByteString extensions[] = {
     CreateEncodedEKUExtension(OCSPSigningEKUDER,
                               ExtensionCriticality::NotCritical),
     ByteString()
   };
   ScopedSECKEYPrivateKey signerPrivateKey;
-  SECItem* signerDER(CreateEncodedCertificate(arena.get(), 1,
-                        subCAName, oneDayBeforeNow, oneDayAfterNow,
-                        signerName, extensions, unknownPrivateKey.get(),
-                        signerPrivateKey));
-  ASSERT_TRUE(signerDER);
+  ByteString signerDER(CreateEncodedCertificate(
+                         1, subCAName, oneDayBeforeNow, oneDayAfterNow,
+                         signerName, extensions, unknownPrivateKey.get(),
+                         signerPrivateKey));
+  ASSERT_NE(ENCODING_FAILED, signerDER);
 
   // OCSP response signed by that delegated responder
-  SECItem const* const certs[] = { signerDER, nullptr };
+  ByteString certs[] = { signerDER, ByteString() };
   Input response(CreateEncodedOCSPSuccessfulResponse(
                          OCSPResponseContext::good, *endEntityCertID,
                          signerName, signerPrivateKey, oneDayBeforeNow,
                          oneDayBeforeNow, &oneDayAfterNow, certs));
   bool expired;
   ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
             VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
                                       END_ENTITY_MAX_LIFETIME_IN_DAYS,
@@ -702,41 +696,39 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
   static const char* signerName = "good_indirect_subca_1_first OCSP signer";
 
   // sub-CA of root (root is the direct issuer of endEntity)
   const ByteString subCAExtensions[] = {
     CreateEncodedBasicConstraints(true, 0, ExtensionCriticality::NotCritical),
     ByteString()
   };
   ScopedSECKEYPrivateKey subCAPrivateKey;
-  SECItem* subCADER(CreateEncodedCertificate(arena.get(), ++rootIssuedCount,
-                                             rootName,
-                                             oneDayBeforeNow, oneDayAfterNow,
-                                             subCAName, subCAExtensions,
-                                             rootPrivateKey.get(),
-                                             subCAPrivateKey));
-  ASSERT_TRUE(subCADER);
+  ByteString subCADER(CreateEncodedCertificate(
+                        ++rootIssuedCount, rootName,
+                        oneDayBeforeNow, oneDayAfterNow,
+                        subCAName, subCAExtensions, rootPrivateKey.get(),
+                        subCAPrivateKey));
+  ASSERT_NE(ENCODING_FAILED, subCADER);
 
   // Delegated responder cert signed by that sub-CA
   const ByteString extensions[] = {
     CreateEncodedEKUExtension(OCSPSigningEKUDER,
                               ExtensionCriticality::NotCritical),
     ByteString(),
   };
   ScopedSECKEYPrivateKey signerPrivateKey;
-  SECItem* signerDER(CreateEncodedCertificate(arena.get(), 1, subCAName,
-                                              oneDayBeforeNow, oneDayAfterNow,
-                                              signerName, extensions,
-                                              subCAPrivateKey.get(),
-                                              signerPrivateKey));
-  ASSERT_TRUE(signerDER);
+  ByteString signerDER(CreateEncodedCertificate(
+                         1, subCAName, oneDayBeforeNow, oneDayAfterNow,
+                         signerName, extensions, subCAPrivateKey.get(),
+                         signerPrivateKey));
+  ASSERT_NE(ENCODING_FAILED, signerDER);
 
   // OCSP response signed by the delegated responder issued by the sub-CA
   // that is trying to impersonate the root.
-  SECItem const* const certs[] = { subCADER, signerDER, nullptr };
+  ByteString certs[] = { subCADER, signerDER, ByteString() };
   Input response(CreateEncodedOCSPSuccessfulResponse(
                          OCSPResponseContext::good, *endEntityCertID,
                          signerName, signerPrivateKey, oneDayBeforeNow,
                          oneDayBeforeNow, &oneDayAfterNow, certs));
   bool expired;
   ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
             VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
                                       END_ENTITY_MAX_LIFETIME_IN_DAYS,
@@ -754,41 +746,39 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
   static const char* signerName = "good_indirect_subca_1_second OCSP signer";
 
   // sub-CA of root (root is the direct issuer of endEntity)
   const ByteString subCAExtensions[] = {
     CreateEncodedBasicConstraints(true, 0, ExtensionCriticality::NotCritical),
     ByteString()
   };
   ScopedSECKEYPrivateKey subCAPrivateKey;
-  SECItem* subCADER(CreateEncodedCertificate(arena.get(), ++rootIssuedCount,
-                                             rootName,
-                                             oneDayBeforeNow, oneDayAfterNow,
-                                             subCAName, subCAExtensions,
-                                             rootPrivateKey.get(),
-                                             subCAPrivateKey));
-  ASSERT_TRUE(subCADER);
+  ByteString subCADER(CreateEncodedCertificate(++rootIssuedCount, rootName,
+                                               oneDayBeforeNow, oneDayAfterNow,
+                                               subCAName, subCAExtensions,
+                                               rootPrivateKey.get(),
+                                               subCAPrivateKey));
+  ASSERT_NE(ENCODING_FAILED, subCADER);
 
   // Delegated responder cert signed by that sub-CA
   const ByteString extensions[] = {
     CreateEncodedEKUExtension(OCSPSigningEKUDER,
                               ExtensionCriticality::NotCritical),
     ByteString()
   };
   ScopedSECKEYPrivateKey signerPrivateKey;
-  SECItem* signerDER(CreateEncodedCertificate(arena.get(), 1, subCAName,
-                                              oneDayBeforeNow, oneDayAfterNow,
-                                              signerName, extensions,
-                                              subCAPrivateKey.get(),
-                                              signerPrivateKey));
-  ASSERT_TRUE(signerDER);
+  ByteString signerDER(CreateEncodedCertificate(
+                         1, subCAName, oneDayBeforeNow, oneDayAfterNow,
+                         signerName, extensions, subCAPrivateKey.get(),
+                         signerPrivateKey));
+  ASSERT_NE(ENCODING_FAILED, signerDER);
 
   // OCSP response signed by the delegated responder issued by the sub-CA
   // that is trying to impersonate the root.
-  SECItem const* const certs[] = { signerDER, subCADER, nullptr };
+  ByteString certs[] = { signerDER, subCADER, ByteString() };
   Input response(CreateEncodedOCSPSuccessfulResponse(
                          OCSPResponseContext::good, *endEntityCertID,
                          signerName, signerPrivateKey, oneDayBeforeNow,
                          oneDayBeforeNow, &oneDayAfterNow, certs));
   bool expired;
   ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
             VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
                                       END_ENTITY_MAX_LIFETIME_IN_DAYS,
@@ -807,54 +797,56 @@ public:
       createdResponse(
         CreateEncodedIndirectOCSPSuccessfulResponse(
           "OCSPGetCertTrustTest Signer", OCSPResponseContext::good,
           byKey, &OCSPSigningEKUDER, &signerCertDER));
     if (response.Init(createdResponse) != Success) {
       abort();
     }
 
-    if (response.GetLength() == 0 || signerCertDER.GetLength() == 0) {
+    if (response.GetLength() == 0 || signerCertDER.length() == 0) {
       abort();
     }
   }
 
   class TrustDomain : public OCSPTestTrustDomain
   {
   public:
     TrustDomain()
       : certTrustLevel(TrustLevel::InheritsTrust)
     {
     }
 
-    bool SetCertTrust(Input certDER, TrustLevel certTrustLevel)
+    bool SetCertTrust(const ByteString& certDER, TrustLevel certTrustLevel)
     {
-      EXPECT_EQ(Success, this->certDER.Init(certDER));
+      this->certDER = certDER;
       this->certTrustLevel = certTrustLevel;
       return true;
     }
   private:
     virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
                                 const CertPolicyId&,
                                 Input candidateCert,
                                 /*out*/ TrustLevel& trustLevel)
     {
       EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
-      EXPECT_NE(0, certDER.GetLength());
-      EXPECT_TRUE(InputsAreEqual(certDER, candidateCert));
+      EXPECT_FALSE(certDER.empty());
+      Input certDERInput;
+      EXPECT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
+      EXPECT_TRUE(InputsAreEqual(certDERInput, candidateCert));
       trustLevel = certTrustLevel;
       return Success;
     }
 
-    Input certDER;
+    ByteString certDER;
     TrustLevel certTrustLevel;
   };
 
   TrustDomain trustDomain;
-  Input signerCertDER; // owned by arena
+  ByteString signerCertDER;
   Input response; // owned by arena
 };
 
 TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, InheritTrust)
 {
   ASSERT_TRUE(trustDomain.SetCertTrust(signerCertDER,
                                        TrustLevel::InheritsTrust));
   bool expired;
--- a/lib/mozpkix/test/lib/pkixtestutil.cpp
+++ b/lib/mozpkix/test/lib/pkixtestutil.cpp
@@ -389,17 +389,17 @@ YMDHMS(int16_t year, int16_t month, int1
   totalSeconds += seconds;
   return TimeFromElapsedSecondsAD(totalSeconds);
 }
 
 static ByteString
 SignedData(const ByteString& tbsData,
            SECKEYPrivateKey* privKey,
            SignatureAlgorithm signatureAlgorithm,
-           bool corrupt, /*optional*/ SECItem const* const* certs)
+           bool corrupt, /*optional*/ const ByteString* certs)
 {
   assert(privKey);
   if (!privKey) {
     return ENCODING_FAILED;
   }
 
   SECOidTag signatureAlgorithmOidTag;
   ByteString signatureAlgorithmDER;
@@ -426,18 +426,18 @@ SignedData(const ByteString& tbsData,
   SECITEM_FreeItem(&signature, false);
   if (signatureNested == ENCODING_FAILED) {
     return ENCODING_FAILED;
   }
 
   ByteString certsNested;
   if (certs) {
     ByteString certsSequenceValue;
-    while (*certs) {
-      certsSequenceValue.append(ByteString((*certs)->data, (*certs)->len));
+    while (!(*certs).empty()) {
+      certsSequenceValue.append(*certs);
       ++certs;
     }
     ByteString certsSequence(TLV(der::SEQUENCE, certsSequenceValue));
     if (certsSequence == ENCODING_FAILED) {
       return ENCODING_FAILED;
     }
     certsNested = TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
                       certsSequence);
@@ -571,62 +571,57 @@ static ByteString TBSCertificate(long ve
                                  const ByteString& subject,
                                  const SECKEYPublicKey* subjectPublicKey,
                                  /*optional*/ const ByteString* extensions);
 
 // Certificate  ::=  SEQUENCE  {
 //         tbsCertificate       TBSCertificate,
 //         signatureAlgorithm   AlgorithmIdentifier,
 //         signatureValue       BIT STRING  }
-SECItem*
-CreateEncodedCertificate(PLArenaPool* arena, long version, Input signature,
+ByteString
+CreateEncodedCertificate(long version, Input signature,
                          const ByteString& serialNumber,
                          const ByteString& issuerNameDER,
                          time_t notBefore, time_t notAfter,
                          const ByteString& subjectNameDER,
                          /*optional*/ const ByteString* extensions,
                          /*optional*/ SECKEYPrivateKey* issuerPrivateKey,
                          SignatureAlgorithm signatureAlgorithm,
                          /*out*/ ScopedSECKEYPrivateKey& privateKeyResult)
 {
-  assert(arena);
-  if (!arena) {
-    return nullptr;
-  }
-
   // It may be the case that privateKeyResult refers to the
   // ScopedSECKEYPrivateKey that owns issuerPrivateKey; thus, we can't set
   // privateKeyResult until after we're done with issuerPrivateKey.
   ScopedSECKEYPublicKey publicKey;
   ScopedSECKEYPrivateKey privateKeyTemp;
   if (GenerateKeyPair(publicKey, privateKeyTemp) != Success) {
-    return nullptr;
+    return ENCODING_FAILED;
   }
 
   ByteString tbsCertificate(TBSCertificate(version, serialNumber,
                                            signature, issuerNameDER, notBefore,
                                            notAfter, subjectNameDER,
                                            publicKey.get(), extensions));
   if (tbsCertificate == ENCODING_FAILED) {
-    return nullptr;
+    return ENCODING_FAILED;
   }
 
   ByteString result(SignedData(tbsCertificate,
                                issuerPrivateKey ? issuerPrivateKey
                                                 : privateKeyTemp.get(),
                                signatureAlgorithm, false, nullptr));
   if (result == ENCODING_FAILED) {
-    return nullptr;
+    return ENCODING_FAILED;
   }
 
   MaybeLogOutput(result, "cert");
 
   privateKeyResult = privateKeyTemp.release();
 
-  return ArenaDupByteString(arena, result);
+  return result;
 }
 
 // TBSCertificate  ::=  SEQUENCE  {
 //      version         [0]  Version DEFAULT v1,
 //      serialNumber         CertificateSerialNumber,
 //      signature            AlgorithmIdentifier,
 //      issuer               Name,
 //      validity             Validity,
--- a/lib/mozpkix/test/lib/pkixtestutil.h
+++ b/lib/mozpkix/test/lib/pkixtestutil.h
@@ -123,29 +123,26 @@ enum Version { v1 = 0, v2 = 1, v3 = 2 };
 //
 // If extensions is null, then no extensions will be encoded. Otherwise,
 // extensions must point to a null-terminated array of SECItem*. If the first
 // item of the array is null then an empty Extensions sequence will be encoded.
 //
 // If issuerPrivateKey is null, then the certificate will be self-signed.
 // Parameter order is based on the order of the attributes of the certificate
 // in RFC 5280.
-//
-// The return value, if non-null, is owned by the arena in the context and
-// MUST NOT be freed.
-SECItem* CreateEncodedCertificate(PLArenaPool* arena, long version,
-                                  Input signature,
-                                  const ByteString& serialNumber,
-                                  const ByteString& issuerNameDER,
-                                  std::time_t notBefore, std::time_t notAfter,
-                                  const ByteString& subjectNameDER,
-                     /*optional*/ const ByteString* extensions,
-                     /*optional*/ SECKEYPrivateKey* issuerPrivateKey,
-                                  SignatureAlgorithm signatureAlgorithm,
-                          /*out*/ ScopedSECKEYPrivateKey& privateKey);
+ByteString CreateEncodedCertificate(long version,
+                                    Input signature,
+                                    const ByteString& serialNumber,
+                                    const ByteString& issuerNameDER,
+                                    std::time_t notBefore, std::time_t notAfter,
+                                    const ByteString& subjectNameDER,
+                       /*optional*/ const ByteString* extensions,
+                       /*optional*/ SECKEYPrivateKey* issuerPrivateKey,
+                                    SignatureAlgorithm signatureAlgorithm,
+                            /*out*/ ScopedSECKEYPrivateKey& privateKey);
 
 ByteString CreateEncodedSerialNumber(long value);
 
 MOZILLA_PKIX_ENUM_CLASS ExtensionCriticality { NotCritical = 0, Critical = 1 };
 
 ByteString CreateEncodedBasicConstraints(bool isCA,
                                          /*optional*/ long* pathLenConstraint,
                                          ExtensionCriticality criticality);
@@ -197,17 +194,17 @@ public:
   std::time_t producedAt;
 
   OCSPResponseExtension* extensions;
   bool includeEmptyExtensions; // If true, include the extension wrapper
                                // regardless of if there are any actual
                                // extensions.
   ScopedSECKEYPrivateKey signerPrivateKey;
   bool badSignature; // If true, alter the signature to fail verification
-  SECItem const* const* certs; // non-owning pointer to certs to embed
+  const ByteString* certs; // optional; array terminated by an empty string
 
   // The following fields are on a per-SingleResponse basis. In the future we
   // may support including multiple SingleResponses per response.
   enum CertStatus {
     good = 0,
     revoked = 1,
     unknown = 2,
   };