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 215881 2ea91aa53633847fb32c280a079d9a958534f215
parent 215880 96d7c79707e590b91a38020bb5a11aec8070e447
child 215882 a6389627c3a4d841462b60223357bedc5494ebca
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs1036105
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1036105: Delegate digest operations to the TrustDomain in mozilla::pkix, r=keeler
security/apps/AppTrustDomain.cpp
security/apps/AppTrustDomain.h
security/certverifier/NSSCertDBTrustDomain.cpp
security/certverifier/NSSCertDBTrustDomain.h
security/pkix/include/pkix/pkix.h
security/pkix/include/pkix/pkixtypes.h
security/pkix/lib/pkixkey.cpp
security/pkix/lib/pkixocsp.cpp
security/pkix/test/gtest/pkixbuild_tests.cpp
security/pkix/test/gtest/pkixcert_extension_tests.cpp
security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp
--- a/security/apps/AppTrustDomain.cpp
+++ b/security/apps/AppTrustDomain.cpp
@@ -192,16 +192,23 @@ SECStatus
 AppTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
                                  const SECItem& subjectPublicKeyInfo)
 {
   return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
                                            mPinArg);
 }
 
 SECStatus
+AppTrustDomain::DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+                          size_t digestBufLen)
+{
+  return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
+}
+
+SECStatus
 AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, PRTime time,
                                 /*optional*/ const SECItem*,
                                 /*optional*/ const SECItem*)
 {
   // We don't currently do revocation checking. If we need to distrust an Apps
   // certificate, we will use the active distrust mechanism.
   return SECSuccess;
 }
--- a/security/apps/AppTrustDomain.h
+++ b/security/apps/AppTrustDomain.h
@@ -22,25 +22,28 @@ public:
   SECStatus SetTrustedRoot(AppTrustedRoot trustedRoot);
 
   SECStatus GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
                          const mozilla::pkix::CertPolicyId& policy,
                          const SECItem& candidateCertDER,
                  /*out*/ mozilla::pkix::TrustLevel* trustLevel) MOZ_OVERRIDE;
   SECStatus FindIssuer(const SECItem& encodedIssuerName,
                        IssuerChecker& checker, PRTime time) MOZ_OVERRIDE;
-  SECStatus VerifySignedData(
-              const mozilla::pkix::SignedDataWithSignature& signedData,
-              const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
   SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
                             const mozilla::pkix::CertID& certID, PRTime time,
                             /*optional*/ const SECItem* stapledOCSPresponse,
                             /*optional*/ const SECItem* aiaExtension);
   SECStatus IsChainValid(const mozilla::pkix::DERArray& certChain);
 
+  SECStatus VerifySignedData(
+              const mozilla::pkix::SignedDataWithSignature& signedData,
+              const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
+  SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+                      size_t digestBufLen) MOZ_OVERRIDE;
+
 private:
   /*out*/ ScopedCERTCertList& mCertChain;
   void* mPinArg; // non-owning!
   ScopedCERTCertificate mTrustedRoot;
 };
 
 } } // namespace mozilla::psm
 
--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -219,16 +219,24 @@ NSSCertDBTrustDomain::GetCertTrust(EndEn
 SECStatus
 NSSCertDBTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
                                        const SECItem& subjectPublicKeyInfo)
 {
   return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
                                            mPinArg);
 }
 
+SECStatus
+NSSCertDBTrustDomain::DigestBuf(const SECItem& item,
+                                /*out*/ uint8_t* digestBuf, size_t digestBufLen)
+{
+  return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
+}
+
+
 static PRIntervalTime
 OCSPFetchingTypeToTimeoutTime(NSSCertDBTrustDomain::OCSPFetching ocspFetching)
 {
   switch (ocspFetching) {
     case NSSCertDBTrustDomain::FetchOCSPForDVSoftFail:
       return PR_SecondsToInterval(2);
     case NSSCertDBTrustDomain::FetchOCSPForEV:
     case NSSCertDBTrustDomain::FetchOCSPForDVHardFail:
@@ -484,17 +492,18 @@ NSSCertDBTrustDomain::CheckRevocation(En
   }
 
   // Only request a response if we didn't have a cached indication of failure
   // (don't keep requesting responses from a failing server).
   const SECItem* response = nullptr;
   if (cachedResponseErrorCode == 0 ||
       cachedResponseErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT ||
       cachedResponseErrorCode == SEC_ERROR_OCSP_OLD_RESPONSE) {
-    const SECItem* request(CreateEncodedOCSPRequest(arena.get(), certID));
+    const SECItem* request(CreateEncodedOCSPRequest(*this, arena.get(),
+                                                    certID));
     if (!request) {
       return SECFailure;
     }
 
     response = DoOCSPRequest(arena.get(), url, request,
                              OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
                              mOCSPGetConfig == CertVerifier::ocsp_get_enabled);
   }
--- a/security/certverifier/NSSCertDBTrustDomain.h
+++ b/security/certverifier/NSSCertDBTrustDomain.h
@@ -61,16 +61,19 @@ public:
                                  const mozilla::pkix::CertPolicyId& policy,
                                  const SECItem& candidateCertDER,
                          /*out*/ mozilla::pkix::TrustLevel* trustLevel);
 
   virtual SECStatus VerifySignedData(
                       const mozilla::pkix::SignedDataWithSignature& signedData,
                       const SECItem& subjectPublicKeyInfo);
 
+  virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+                              size_t digestBufLen);
+
   virtual SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
                                     const mozilla::pkix::CertID& certID,
                                     PRTime time,
                        /*optional*/ const SECItem* stapledOCSPResponse,
                        /*optional*/ const SECItem* aiaExtension);
 
   virtual SECStatus IsChainValid(const mozilla::pkix::DERArray& certChain);
 
--- a/security/pkix/include/pkix/pkix.h
+++ b/security/pkix/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/security/pkix/include/pkix/pkixtypes.h
+++ b/security/pkix/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/security/pkix/lib/pkixkey.cpp
+++ b/security/pkix/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/security/pkix/lib/pkixocsp.cpp
+++ b/security/pkix/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/security/pkix/test/gtest/pkixbuild_tests.cpp
+++ b/security/pkix/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/security/pkix/test/gtest/pkixcert_extension_tests.cpp
+++ b/security/pkix/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/security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp
+++ b/security/pkix/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)));
 }