Bug 1036105: Delegate digest operations to the TrustDomain in mozilla::pkix, r=keeler
authorBrian Smith <brian@briansmith.org>
Sun, 06 Jul 2014 19:36:05 -0700
changeset 14624 354983173ff099cf87cddab96b98b0b5e9372671
parent 14623 154fdd34da308a779077a0e5bb110b41a7daeea1
child 14625 c1332f88b791f6285a8b0f106aa914e54d2d7a25
push id3202
push userfranziskuskiefer@gmail.com
push dateMon, 01 Oct 2018 08:30:12 +0000
reviewerskeeler
bugs1036105
Bug 1036105: Delegate digest operations to the TrustDomain in mozilla::pkix, r=keeler
lib/mozpkix/include/pkix/pkix.h
lib/mozpkix/include/pkix/pkixtypes.h
lib/mozpkix/lib/pkixkey.cpp
lib/mozpkix/lib/pkixocsp.cpp
lib/mozpkix/test/gtest/pkixbuild_tests.cpp
lib/mozpkix/test/gtest/pkixcert_extension_tests.cpp
lib/mozpkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp
--- a/lib/mozpkix/include/pkix/pkix.h
+++ b/lib/mozpkix/include/pkix/pkix.h
@@ -98,17 +98,18 @@ SECStatus BuildCertChain(TrustDomain& tr
             /*optional*/ const SECItem* stapledOCSPResponse);
 
 // Verify the given signed data using the given public key.
 SECStatus VerifySignedData(const SignedDataWithSignature& sd,
                            const SECItem& subjectPublicKeyInfo,
                            void* pkcs11PinArg);
 
 // The return value, if non-null, is owned by the arena and MUST NOT be freed.
-SECItem* CreateEncodedOCSPRequest(PLArenaPool* arena, const CertID& certID);
+SECItem* CreateEncodedOCSPRequest(TrustDomain& trustDomain, PLArenaPool* arena,
+                                  const CertID& certID);
 
 // The out parameter expired will be true if the response has expired. If the
 // response also indicates a revoked or unknown certificate, that error
 // will be returned by PR_GetError(). Otherwise, SEC_ERROR_OCSP_OLD_RESPONSE
 // will be returned by PR_GetError() for an expired response.
 // The optional parameter thisUpdate will be the thisUpdate value of
 // the encoded response if it is considered trustworthy. Only
 // good, unknown, or revoked responses that verify correctly are considered
@@ -119,11 +120,25 @@ SECItem* CreateEncodedOCSPRequest(PLAren
 SECStatus VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
                                     const CertID& certID, PRTime time,
                                     uint16_t maxLifetimeInDays,
                                     const SECItem& encodedResponse,
                           /* out */ bool& expired,
                  /* optional out */ PRTime* thisUpdate = nullptr,
                  /* optional out */ PRTime* validThrough = nullptr);
 
+// Computes the SHA-1 hash of the data in the current item.
+//
+// item contains the data to hash.
+// digestBuf must point to a buffer to where the SHA-1 hash will be written.
+// digestBufLen must be 20 (the length of a SHA-1 hash,
+//              TrustDomain::DIGEST_LENGTH).
+//
+// TODO(bug 966856): Add SHA-2 support
+// TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
+// other, extensive, memory safety efforts in mozilla::pkix, and we should find
+// a way to provide a more-obviously-safe interface.
+SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+                    size_t digestBufLen);
+
 } } // namespace mozilla::pkix
 
 #endif // mozilla_pkix__pkix_h
--- a/lib/mozpkix/include/pkix/pkixtypes.h
+++ b/lib/mozpkix/include/pkix/pkixtypes.h
@@ -299,16 +299,31 @@ public:
                        /*optional*/ const SECItem* aiaExtension) = 0;
 
   // Verify the given signature using the given public key.
   //
   // Most implementations of this function should probably forward the call
   // directly to mozilla::pkix::VerifySignedData.
   virtual SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
                                      const SECItem& subjectPublicKeyInfo) = 0;
+
+  // Compute the SHA-1 hash of the data in the current item.
+  //
+  // item contains the data to hash.
+  // digestBuf must point to a buffer to where the SHA-1 hash will be written.
+  // digestBufLen must be DIGEST_LENGTH (20, the length of a SHA-1 hash).
+  //
+  // TODO(bug 966856): Add SHA-2 support
+  // TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
+  // other, extensive, memory safety efforts in mozilla::pkix, and we should
+  // find a way to provide a more-obviously-safe interface.
+  static const size_t DIGEST_LENGTH = 20; // length of SHA-1 digest
+  virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+                              size_t digestBufLen) = 0;
+
 protected:
   TrustDomain() { }
 
 private:
   TrustDomain(const TrustDomain&) /* = delete */;
   void operator=(const TrustDomain&) /* = delete */;
 };
 
--- a/lib/mozpkix/lib/pkixkey.cpp
+++ b/lib/mozpkix/lib/pkixkey.cpp
@@ -23,16 +23,17 @@
  */
 
 #include <limits>
 #include <stdint.h>
 
 #include "cert.h"
 #include "cryptohi.h"
 #include "keyhi.h"
+#include "pk11pub.h"
 #include "pkix/pkix.h"
 #include "pkix/ScopedPtr.h"
 #include "prerror.h"
 #include "secerr.h"
 
 namespace mozilla { namespace pkix {
 
 SECStatus
@@ -113,9 +114,29 @@ VerifySignedData(const SignedDataWithSig
 
   // The static_cast is safe according to the check above that references
   // bug 921585.
   return VFY_VerifyDataDirect(sd.data.data, static_cast<int>(sd.data.len),
                               pubKey.get(), &sd.signature, pubKeyAlg,
                               digestAlg, nullptr, pkcs11PinArg);
 }
 
+SECStatus
+DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf, size_t digestBufLen)
+{
+  static_assert(TrustDomain::DIGEST_LENGTH == SHA1_LENGTH,
+                "TrustDomain::DIGEST_LENGTH must be 20 (SHA-1 digest length)");
+  if (digestBufLen != TrustDomain::DIGEST_LENGTH) {
+    PR_NOT_REACHED("invalid hash length");
+    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+    return SECFailure;
+  }
+  if (item.len >
+      static_cast<decltype(item.len)>(std::numeric_limits<int32_t>::max())) {
+    PR_NOT_REACHED("large OCSP responses should have already been rejected");
+    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+    return SECFailure;
+  }
+  return PK11_HashBuf(SEC_OID_SHA1, digestBuf, item.data,
+                      static_cast<int32_t>(item.len));
+}
+
 } } // namespace mozilla::pkix
--- a/lib/mozpkix/lib/pkixocsp.cpp
+++ b/lib/mozpkix/lib/pkixocsp.cpp
@@ -19,18 +19,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <limits>
 
-#include "hasht.h"
-#include "pk11pub.h"
 #include "pkix/bind.h"
 #include "pkix/pkix.h"
 #include "pkixcheck.h"
 #include "pkixder.h"
 
 // TODO: use typed/qualified typedefs everywhere?
 // TODO: When should we return SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE?
 
@@ -79,35 +77,16 @@ public:
   PRTime* validThrough;
   bool expired;
 
 private:
   Context(const Context&); // delete
   void operator=(const Context&); // delete
 };
 
-static der::Result
-HashBuf(const SECItem& item, /*out*/ uint8_t *hashBuf, size_t hashBufLen)
-{
-  if (hashBufLen != SHA1_LENGTH) {
-    PR_NOT_REACHED("invalid hash length");
-    return der::Fail(SEC_ERROR_INVALID_ARGS);
-  }
-  if (item.len >
-      static_cast<decltype(item.len)>(std::numeric_limits<int32_t>::max())) {
-    PR_NOT_REACHED("large OCSP responses should have already been rejected");
-    return der::Fail(SEC_ERROR_INVALID_ARGS);
-  }
-  if (PK11_HashBuf(SEC_OID_SHA1, hashBuf, item.data,
-                   static_cast<int32_t>(item.len)) != SECSuccess) {
-    return der::Fail(PR_GetError());
-  }
-  return der::Success;
-}
-
 // Verify that potentialSigner is a valid delegated OCSP response signing cert
 // according to RFC 6960 section 4.2.2.2.
 static Result
 CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
                             BackCert& potentialSigner,
                             const SECItem& issuerSubject,
                             const SECItem& issuerSubjectPublicKeyInfo,
                             PRTime time)
@@ -184,25 +163,28 @@ static inline der::Result ResponseData(
 static inline der::Result SingleResponse(der::Input& input,
                                           Context& context);
 static der::Result ExtensionNotUnderstood(der::Input& extnID,
                                           const SECItem& extnValue,
                                           /*out*/ bool& understood);
 static inline der::Result CertID(der::Input& input,
                                   const Context& context,
                                   /*out*/ bool& match);
-static Result MatchKeyHash(const SECItem& issuerKeyHash,
+static Result MatchKeyHash(TrustDomain& trustDomain,
+                           const SECItem& issuerKeyHash,
                            const SECItem& issuerSubjectPublicKeyInfo,
                            /*out*/ bool& match);
-static Result KeyHash(const SECItem& subjectPublicKeyInfo,
+static Result KeyHash(TrustDomain& trustDomain,
+                      const SECItem& subjectPublicKeyInfo,
                       /*out*/ uint8_t* hashBuf, size_t hashBufSize);
 
 
 static Result
-MatchResponderID(ResponderIDType responderIDType,
+MatchResponderID(TrustDomain& trustDomain,
+                 ResponderIDType responderIDType,
                  const SECItem& responderIDItem,
                  const SECItem& potentialSignerSubject,
                  const SECItem& potentialSignerSubjectPublicKeyInfo,
                  /*out*/ bool& match)
 {
   match = false;
 
   switch (responderIDType) {
@@ -219,17 +201,18 @@ MatchResponderID(ResponderIDType respond
             != der::Success) {
         return RecoverableError;
       }
       SECItem keyHash;
       if (der::ExpectTagAndGetValue(responderID, der::OCTET_STRING, keyHash)
             != der::Success) {
         return RecoverableError;
       }
-      return MatchKeyHash(keyHash, potentialSignerSubjectPublicKeyInfo, match);
+      return MatchKeyHash(trustDomain, keyHash,
+                          potentialSignerSubjectPublicKeyInfo, match);
     }
 
     default:
       return Fail(RecoverableError, SEC_ERROR_OCSP_MALFORMED_RESPONSE);
   }
 }
 
 static Result
@@ -254,35 +237,35 @@ VerifyOCSPSignedData(TrustDomain& trustD
 // *directly* to issuerCert.
 static Result
 VerifySignature(Context& context, ResponderIDType responderIDType,
                 const SECItem& responderID, const SECItem* certs,
                 size_t numCerts,
                 const SignedDataWithSignature& signedResponseData)
 {
   bool match;
-  Result rv = MatchResponderID(responderIDType, responderID,
-                               context.certID.issuer,
+  Result rv = MatchResponderID(context.trustDomain, responderIDType,
+                               responderID, context.certID.issuer,
                                context.certID.issuerSubjectPublicKeyInfo,
                                match);
   if (rv != Success) {
     return rv;
   }
   if (match) {
     return VerifyOCSPSignedData(context.trustDomain, signedResponseData,
                                 context.certID.issuerSubjectPublicKeyInfo);
   }
 
   for (size_t i = 0; i < numCerts; ++i) {
     BackCert cert(certs[i], EndEntityOrCA::MustBeEndEntity, nullptr);
     rv = cert.Init();
     if (rv != Success) {
       return rv;
     }
-    rv = MatchResponderID(responderIDType, responderID,
+    rv = MatchResponderID(context.trustDomain, responderIDType, responderID,
                           cert.GetSubject(), cert.GetSubjectPublicKeyInfo(),
                           match);
     if (rv == FatalError) {
       return rv;
     }
     if (rv == RecoverableError) {
       continue;
     }
@@ -717,36 +700,37 @@ CertID(der::Input& input, const Context&
   // TODO: support SHA-2 hashes.
 
   if (hashAlgorithm != DigestAlgorithm::sha1) {
     // Again, not interested in this response. Consume input, return success.
     input.SkipToEnd();
     return der::Success;
   }
 
-  if (issuerNameHash.len != SHA1_LENGTH) {
+  if (issuerNameHash.len != TrustDomain::DIGEST_LENGTH) {
     return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
   }
 
   // From http://tools.ietf.org/html/rfc6960#section-4.1.1:
   // "The hash shall be calculated over the DER encoding of the
   // issuer's name field in the certificate being checked."
-  uint8_t hashBuf[SHA1_LENGTH];
-  if (HashBuf(context.certID.issuer, hashBuf, sizeof(hashBuf))
-        != der::Success) {
+  uint8_t hashBuf[TrustDomain::DIGEST_LENGTH];
+  if (context.trustDomain.DigestBuf(context.certID.issuer, hashBuf,
+                                    sizeof(hashBuf)) != SECSuccess) {
     return der::Failure;
   }
   if (memcmp(hashBuf, issuerNameHash.data, issuerNameHash.len)) {
     // Again, not interested in this response. Consume input, return success.
     input.SkipToEnd();
     return der::Success;
   }
 
-  if (MatchKeyHash(issuerKeyHash, context.certID.issuerSubjectPublicKeyInfo,
-                   match) != Success) {
+  if (MatchKeyHash(context.trustDomain, issuerKeyHash,
+                   context.certID.issuerSubjectPublicKeyInfo, match)
+        != Success) {
     return der::Failure;
   }
 
   return der::Success;
 }
 
 // From http://tools.ietf.org/html/rfc6960#section-4.1.1:
 // "The hash shall be calculated over the value (excluding tag and length) of
@@ -754,37 +738,38 @@ CertID(der::Input& input, const Context&
 //
 // From http://tools.ietf.org/html/rfc6960#appendix-B.1:
 // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
 //                          -- (i.e., the SHA-1 hash of the value of the
 //                          -- BIT STRING subjectPublicKey [excluding
 //                          -- the tag, length, and number of unused
 //                          -- bits] in the responder's certificate)
 static Result
-MatchKeyHash(const SECItem& keyHash, const SECItem& subjectPublicKeyInfo,
-             /*out*/ bool& match)
+MatchKeyHash(TrustDomain& trustDomain, const SECItem& keyHash,
+             const SECItem& subjectPublicKeyInfo, /*out*/ bool& match)
 {
-  if (keyHash.len != SHA1_LENGTH)  {
+  if (keyHash.len != TrustDomain::DIGEST_LENGTH)  {
     return Fail(RecoverableError, SEC_ERROR_OCSP_MALFORMED_RESPONSE);
   }
-  static uint8_t hashBuf[SHA1_LENGTH];
-  Result rv = KeyHash(subjectPublicKeyInfo, hashBuf, sizeof hashBuf);
+  static uint8_t hashBuf[TrustDomain::DIGEST_LENGTH];
+  Result rv = KeyHash(trustDomain, subjectPublicKeyInfo, hashBuf,
+                      sizeof hashBuf);
   if (rv != Success) {
     return rv;
   }
   match = !memcmp(hashBuf, keyHash.data, keyHash.len);
   return Success;
 }
 
 // TODO(bug 966856): support SHA-2 hashes
 Result
-KeyHash(const SECItem& subjectPublicKeyInfo, /*out*/ uint8_t* hashBuf,
-        size_t hashBufSize)
+KeyHash(TrustDomain& trustDomain, const SECItem& subjectPublicKeyInfo,
+        /*out*/ uint8_t* hashBuf, size_t hashBufSize)
 {
-  if (!hashBuf || hashBufSize != SHA1_LENGTH) {
+  if (!hashBuf || hashBufSize != TrustDomain::DIGEST_LENGTH) {
     return Fail(FatalError, SEC_ERROR_LIBRARY_FAILURE);
   }
 
   // RFC 5280 Section 4.1
   //
   // SubjectPublicKeyInfo  ::=  SEQUENCE  {
   //    algorithm            AlgorithmIdentifier,
   //    subjectPublicKey     BIT STRING  }
@@ -825,17 +810,18 @@ KeyHash(const SECItem& subjectPublicKeyI
 
   // Assume/require that the number of unused bits in the public key is zero.
   if (subjectPublicKey.len == 0 || subjectPublicKey.data[0] != 0) {
     return Fail(RecoverableError, SEC_ERROR_BAD_DER);
   }
   ++subjectPublicKey.data;
   --subjectPublicKey.len;
 
-  if (HashBuf(subjectPublicKey, hashBuf, hashBufSize) != der::Success) {
+  if (trustDomain.DigestBuf(subjectPublicKey, hashBuf, hashBufSize)
+        != SECSuccess) {
     return MapSECStatus(SECFailure);
   }
   return Success;
 }
 
 der::Result
 ExtensionNotUnderstood(der::Input& /*extnID*/, const SECItem& /*extnValue*/,
                        /*out*/ bool& understood)
@@ -863,17 +849,18 @@ ExtensionNotUnderstood(der::Input& /*ext
 //   SHOULD be considered unreliable.
 //
 //   If nextUpdate is not set, the responder is indicating that newer
 //   revocation information is available all the time.
 //
 // http://tools.ietf.org/html/rfc5019#section-4
 
 SECItem*
-CreateEncodedOCSPRequest(PLArenaPool* arena, const struct CertID& certID)
+CreateEncodedOCSPRequest(TrustDomain& trustDomain, PLArenaPool* arena,
+                         const struct CertID& certID)
 {
   if (!arena) {
     PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
     return nullptr;
   }
 
   // We do not add any extensions to the request.
 
@@ -891,17 +878,17 @@ CreateEncodedOCSPRequest(PLArenaPool* ar
   // Since we don't know whether the OCSP responder supports anything other
   // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and
   // issuerKeyHash.
   static const uint8_t hashAlgorithm[11] = {
     0x30, 0x09,                               // SEQUENCE
     0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, //   OBJECT IDENTIFIER id-sha1
     0x05, 0x00,                               //   NULL
   };
-  static const uint8_t hashLen = SHA1_LENGTH;
+  static const uint8_t hashLen = TrustDomain::DIGEST_LENGTH;
 
   static const unsigned int totalLenWithoutSerialNumberData
     = 2                             // OCSPRequest
     + 2                             //   tbsRequest
     + 2                             //     requestList
     + 2                             //       Request
     + 2                             //         reqCert (CertID)
     + PR_ARRAY_SIZE(hashAlgorithm)  //           hashAlgorithm
@@ -938,25 +925,26 @@ CreateEncodedOCSPRequest(PLArenaPool* ar
   // reqCert.hashAlgorithm
   for (size_t i = 0; i < PR_ARRAY_SIZE(hashAlgorithm); ++i) {
     *d++ = hashAlgorithm[i];
   }
 
   // reqCert.issuerNameHash (OCTET STRING)
   *d++ = 0x04;
   *d++ = hashLen;
-  if (HashBuf(certID.issuer, d, hashLen) != der::Success) {
+  if (trustDomain.DigestBuf(certID.issuer, d, hashLen) != SECSuccess) {
     return nullptr;
   }
   d += hashLen;
 
   // reqCert.issuerKeyHash (OCTET STRING)
   *d++ = 0x04;
   *d++ = hashLen;
-  if (KeyHash(certID.issuerSubjectPublicKeyInfo, d, hashLen) != Success) {
+  if (KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen)
+        != Success) {
     return nullptr;
   }
   d += hashLen;
 
   // reqCert.serialNumber (INTEGER)
   *d++ = 0x02; // INTEGER
   *d++ = static_cast<uint8_t>(certID.serialNumber.len);
   for (size_t i = 0; i < certID.serialNumber.len; ++i) {
--- a/lib/mozpkix/test/gtest/pkixbuild_tests.cpp
+++ b/lib/mozpkix/test/gtest/pkixbuild_tests.cpp
@@ -145,35 +145,43 @@ private:
           break;
         }
       }
     }
 
     return SECSuccess;
   }
 
-  SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
-                             const SECItem& subjectPublicKeyInfo)
-  {
-    return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
-                                             nullptr);
-  }
-
   SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
                             /*optional*/ const SECItem*,
                             /*optional*/ const SECItem*)
   {
     return SECSuccess;
   }
 
   virtual SECStatus IsChainValid(const DERArray&)
   {
     return SECSuccess;
   }
 
+  SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
+                             const SECItem& subjectPublicKeyInfo)
+  {
+    return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
+                                             nullptr);
+  }
+
+  virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t *digestBuf,
+                              size_t digestBufLen)
+  {
+    ADD_FAILURE();
+    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+    return SECFailure;
+  }
+
   // We hold references to CERTCertificates in the cert chain tail so that we
   // CERT_CreateSubjectCertList can find them.
   ScopedCERTCertificate certChainTail[7];
 
 public:
   ScopedSECKEYPrivateKey leafCAKey;
   CERTCertificate* GetLeafCACert() const
   {
--- a/lib/mozpkix/test/gtest/pkixcert_extension_tests.cpp
+++ b/lib/mozpkix/test/gtest/pkixcert_extension_tests.cpp
@@ -80,39 +80,46 @@ private:
   {
     *trustLevel = TrustLevel::TrustAnchor;
     return SECSuccess;
   }
 
   SECStatus FindIssuer(const SECItem& /*encodedIssuerName*/,
                        IssuerChecker& /*checker*/, PRTime /*time*/)
   {
-    PR_NOT_REACHED("FindIssuer should not be called");
+    ADD_FAILURE();
     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
     return SECFailure;
   }
 
-  SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
-                             const SECItem& subjectPublicKeyInfo)
-  {
-    return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
-                                             nullptr);
-  }
-
   SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
                             /*optional*/ const SECItem*,
                             /*optional*/ const SECItem*)
   {
     return SECSuccess;
   }
 
   virtual SECStatus IsChainValid(const DERArray&)
   {
     return SECSuccess;
   }
+
+  SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
+                             const SECItem& subjectPublicKeyInfo)
+  {
+    return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
+                                             nullptr);
+  }
+
+  SECStatus DigestBuf(const SECItem&, /*out*/ uint8_t *, size_t)
+  {
+    ADD_FAILURE();
+    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+    return SECFailure;
+  }
 };
 
 class pkixcert_extension: public NSSTest
 {
 public:
   static void SetUpTestCase()
   {
     NSSTest::SetUpTestCase();
--- a/lib/mozpkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp
+++ b/lib/mozpkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp
@@ -26,16 +26,64 @@
 #include "pkix/pkix.h"
 #include "pkixder.h"
 #include "prerror.h"
 #include "secerr.h"
 
 using namespace mozilla::pkix;
 using namespace mozilla::pkix::test;
 
+class CreateEncodedOCSPRequestTrustDomain : public TrustDomain
+{
+private:
+  virtual SECStatus GetCertTrust(EndEntityOrCA, const CertPolicyId&,
+                                 const SECItem&, /*out*/ TrustLevel*)
+  {
+    ADD_FAILURE();
+    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+    return SECFailure;
+  }
+
+  virtual SECStatus FindIssuer(const SECItem&, IssuerChecker&, PRTime)
+  {
+    ADD_FAILURE();
+    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+    return SECFailure;
+  }
+
+  virtual SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
+                                    const SECItem*, const SECItem*)
+  {
+    ADD_FAILURE();
+    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+    return SECFailure;
+  }
+
+  virtual SECStatus IsChainValid(const DERArray&)
+  {
+    ADD_FAILURE();
+    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+    return SECFailure;
+  }
+
+  virtual SECStatus VerifySignedData(const SignedDataWithSignature&,
+                                     const SECItem&)
+  {
+    ADD_FAILURE();
+    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+    return SECFailure;
+  }
+
+  virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t *digestBuf,
+                              size_t digestBufLen)
+  {
+    return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
+  }
+};
+
 class pkixocsp_CreateEncodedOCSPRequest : public NSSTest
 {
 protected:
   // These SECItems are allocated in arena, and so will be auto-cleaned.
   SECItem* unsupportedLongSerialNumber;
   SECItem* longestRequiredSerialNumber;
 
   void SetUp()
@@ -81,36 +129,37 @@ protected:
     issuerSPKI = SECKEY_EncodeDERSubjectPublicKeyInfo(issuerPublicKey.get());
     if (!issuerSPKI) {
       return SECFailure;
     }
 
     return SECSuccess;
   }
 
+  CreateEncodedOCSPRequestTrustDomain trustDomain;
 };
 
 // Test that the large length of the child serial number causes
 // CreateEncodedOCSPRequest to fail.
 TEST_F(pkixocsp_CreateEncodedOCSPRequest, ChildCertLongSerialNumberTest)
 {
   const SECItem* issuerDER;
   ScopedSECItem issuerSPKI;
   ASSERT_EQ(SECSuccess,
             MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
-  ASSERT_FALSE(CreateEncodedOCSPRequest(arena.get(),
+  ASSERT_FALSE(CreateEncodedOCSPRequest(trustDomain, arena.get(),
                                         CertID(*issuerDER, *issuerSPKI,
                                                *unsupportedLongSerialNumber)));
   ASSERT_EQ(SEC_ERROR_BAD_DATA, PR_GetError());
 }
 
 // Test that CreateEncodedOCSPRequest handles the longest serial number that
 // it's required to support (i.e. 20 octets).
 TEST_F(pkixocsp_CreateEncodedOCSPRequest, LongestSupportedSerialNumberTest)
 {
   const SECItem* issuerDER;
   ScopedSECItem issuerSPKI;
   ASSERT_EQ(SECSuccess,
             MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
-  ASSERT_TRUE(CreateEncodedOCSPRequest(arena.get(),
+  ASSERT_TRUE(CreateEncodedOCSPRequest(trustDomain, arena.get(),
                                         CertID(*issuerDER, *issuerSPKI,
                                                *longestRequiredSerialNumber)));
 }