From 8c7b033b68078dc952ce6d0f3c5310c7e799602f Mon Sep 17 00:00:00 2001 From: Jonathan Hao Date: Tue, 18 Oct 2016 17:08:39 +0800 Subject: [PATCH] Bug 1264562 - Part 5: Double key OCSP cache with firstPartyDomain (adapted from Tor Browser patch #13670) r=keeler --HG-- extra : rebase_source : cfca6f16dcd315c03704e75ed63181466a8eb5c4 --- .../certverifier/NSSCertDBTrustDomain.cpp | 7 +- security/certverifier/OCSPCache.cpp | 117 +++++++++++++----- security/certverifier/OCSPCache.h | 17 ++- .../manager/ssl/tests/gtest/OCSPCacheTest.cpp | 64 ++++++---- 4 files changed, 141 insertions(+), 64 deletions(-) diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index f78ad3ee2a87..6d308a12018e 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -421,7 +421,7 @@ NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA, Result cachedResponseResult = Success; Time cachedResponseValidThrough(Time::uninitialized); - bool cachedResponsePresent = mOCSPCache.Get(certID, + bool cachedResponsePresent = mOCSPCache.Get(certID, mFirstPartyDomain, cachedResponseResult, cachedResponseValidThrough); if (cachedResponsePresent) { @@ -588,7 +588,7 @@ NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA, if (timeout.AddSeconds(ServerFailureDelaySeconds) != Success) { return Result::FATAL_ERROR_LIBRARY_FAILURE; // integer overflow } - rv = mOCSPCache.Put(certID, error, time, timeout); + rv = mOCSPCache.Put(certID, mFirstPartyDomain, error, time, timeout); if (rv != Success) { return rv; } @@ -693,7 +693,8 @@ NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse( rv == Result::ERROR_OCSP_UNKNOWN_CERT) { MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("NSSCertDBTrustDomain: caching OCSP response")); - Result putRV = mOCSPCache.Put(certID, rv, thisUpdate, validThrough); + Result putRV = mOCSPCache.Put(certID, mFirstPartyDomain, rv, thisUpdate, + validThrough); if (putRV != Success) { return putRV; } diff --git a/security/certverifier/OCSPCache.cpp b/security/certverifier/OCSPCache.cpp index f1270fec129b..45ec589abe6d 100644 --- a/security/certverifier/OCSPCache.cpp +++ b/security/certverifier/OCSPCache.cpp @@ -38,19 +38,44 @@ using namespace mozilla::pkix; namespace mozilla { namespace psm { +static SECStatus +DigestLength(UniquePK11Context& context, uint32_t length) +{ + // Restrict length to 2 bytes because it should be big enough for all + // inputs this code will actually see and that it is well-defined and + // type-size-independent. + if (length >= 65536) { + return SECFailure; + } + unsigned char array[2]; + array[0] = length & 255; + array[1] = (length >> 8) & 255; + + return PK11_DigestOp(context.get(), array, MOZ_ARRAY_LENGTH(array)); +} + // Let derIssuer be the DER encoding of the issuer of aCert. // Let derPublicKey be the DER encoding of the public key of aIssuerCert. // Let serialNumber be the bytes of the serial number of aCert. -// The value calculated is SHA384(derIssuer || derPublicKey || serialNumber). -// Because the DER encodings include the length of the data encoded, -// there do not exist A(derIssuerA, derPublicKeyA, serialNumberA) and -// B(derIssuerB, derPublicKeyB, serialNumberB) such that the concatenation of -// each triplet results in the same string of bytes but where each part in A is -// not equal to its counterpart in B. This is important because as a result it -// is computationally infeasible to find collisions that would subvert this -// cache (given that SHA384 is a cryptographically-secure hash function). +// Let serialNumberLen be the number of bytes of serialNumber. +// The first party domain is only non-empty when "privacy.firstParty.isolate" +// is enabled, in order to isolate OCSP cache by first party. +// Let firstPartyDomainLen be the number of bytes of firstPartyDomain. +// The value calculated is SHA384(derIssuer || derPublicKey || serialNumberLen +// || serialNumber || firstPartyDomainLen || firstPartyDomain). +// Because the DER encodings include the length of the data encoded, and we also +// include the length of serialNumber and firstPartyDomain, there do not exist +// A(derIssuerA, derPublicKeyA, serialNumberLenA, serialNumberA, +// firstPartyDomainLenA, firstPartyDomainA) and B(derIssuerB, derPublicKeyB, +// serialNumberLenB, serialNumberB, firstPartyDomainLenB, firstPartyDomainB) +// such that the concatenation of each tuple results in the same string of +// bytes but where each part in A is not equal to its counterpart in B. This is +// important because as a result it is computationally infeasible to find +// collisions that would subvert this cache (given that SHA384 is a +// cryptographically-secure hash function). static SECStatus -CertIDHash(SHA384Buffer& buf, const CertID& certID) +CertIDHash(SHA384Buffer& buf, const CertID& certID, + const char* firstPartyDomain) { UniquePK11Context context(PK11_CreateDigestContext(SEC_OID_SHA384)); if (!context) { @@ -74,11 +99,28 @@ CertIDHash(SHA384Buffer& buf, const CertID& certID) } SECItem certIDSerialNumber = UnsafeMapInputToSECItem(certID.serialNumber); + rv = DigestLength(context, certIDSerialNumber.len); + if (rv != SECSuccess) { + return rv; + } rv = PK11_DigestOp(context.get(), certIDSerialNumber.data, certIDSerialNumber.len); if (rv != SECSuccess) { return rv; } + if (firstPartyDomain) { + uint32_t firstPartyDomainLen = strlen(firstPartyDomain); + rv = DigestLength(context, firstPartyDomainLen); + if (rv != SECSuccess) { + return rv; + } + rv = PK11_DigestOp(context.get(), + BitwiseCast(firstPartyDomain), + firstPartyDomainLen); + if (rv != SECSuccess) { + return rv; + } + } uint32_t outLen = 0; rv = PK11_DigestFinal(context.get(), buf, &outLen, SHA384_LENGTH); if (outLen != SHA384_LENGTH) { @@ -88,9 +130,9 @@ CertIDHash(SHA384Buffer& buf, const CertID& certID) } Result -OCSPCache::Entry::Init(const CertID& aCertID) +OCSPCache::Entry::Init(const CertID& aCertID, const char* aFirstPartyDomain) { - SECStatus srv = CertIDHash(mIDHash, aCertID); + SECStatus srv = CertIDHash(mIDHash, aCertID, aFirstPartyDomain); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } @@ -110,7 +152,8 @@ OCSPCache::~OCSPCache() // Returns false with index in an undefined state if no matching entry was // found. bool -OCSPCache::FindInternal(const CertID& aCertID, /*out*/ size_t& index, +OCSPCache::FindInternal(const CertID& aCertID, const char* aFirstPartyDomain, + /*out*/ size_t& index, const MutexAutoLock& /* aProofOfLock */) { if (mEntries.length() == 0) { @@ -118,7 +161,7 @@ OCSPCache::FindInternal(const CertID& aCertID, /*out*/ size_t& index, } SHA384Buffer idHash; - SECStatus rv = CertIDHash(idHash, aCertID); + SECStatus rv = CertIDHash(idHash, aCertID, aFirstPartyDomain); if (rv != SECSuccess) { return false; } @@ -136,9 +179,11 @@ OCSPCache::FindInternal(const CertID& aCertID, /*out*/ size_t& index, } static inline void -LogWithCertID(const char* aMessage, const CertID& aCertID) +LogWithCertID(const char* aMessage, const CertID& aCertID, + const char* aFirstPartyDomain) { - MOZ_LOG(gCertVerifierLog, LogLevel::Debug, (aMessage, &aCertID)); + MOZ_LOG(gCertVerifierLog, LogLevel::Debug, + (aMessage, &aCertID, aFirstPartyDomain)); } void @@ -155,16 +200,19 @@ OCSPCache::MakeMostRecentlyUsed(size_t aIndex, } bool -OCSPCache::Get(const CertID& aCertID, Result& aResult, Time& aValidThrough) +OCSPCache::Get(const CertID& aCertID, const char* aFirstPartyDomain, + Result& aResult, Time& aValidThrough) { MutexAutoLock lock(mMutex); size_t index; - if (!FindInternal(aCertID, index, lock)) { - LogWithCertID("OCSPCache::Get(%p) not in cache", aCertID); + if (!FindInternal(aCertID, aFirstPartyDomain, index, lock)) { + LogWithCertID("OCSPCache::Get(%p,\"%s\") not in cache", aCertID, + aFirstPartyDomain); return false; } - LogWithCertID("OCSPCache::Get(%p) in cache", aCertID); + LogWithCertID("OCSPCache::Get(%p,\"%s\") in cache", aCertID, + aFirstPartyDomain); aResult = mEntries[index]->mResult; aValidThrough = mEntries[index]->mValidThrough; MakeMostRecentlyUsed(index, lock); @@ -172,17 +220,17 @@ OCSPCache::Get(const CertID& aCertID, Result& aResult, Time& aValidThrough) } Result -OCSPCache::Put(const CertID& aCertID, Result aResult, - Time aThisUpdate, Time aValidThrough) +OCSPCache::Put(const CertID& aCertID, const char* aFirstPartyDomain, + Result aResult, Time aThisUpdate, Time aValidThrough) { MutexAutoLock lock(mMutex); size_t index; - if (FindInternal(aCertID, index, lock)) { + if (FindInternal(aCertID, aFirstPartyDomain, index, lock)) { // Never replace an entry indicating a revoked certificate. if (mEntries[index]->mResult == Result::ERROR_REVOKED_CERTIFICATE) { - LogWithCertID("OCSPCache::Put(%p) already in cache as revoked - " - "not replacing", aCertID); + LogWithCertID("OCSPCache::Put(%p, \"%s\") already in cache as revoked - " + "not replacing", aCertID, aFirstPartyDomain); MakeMostRecentlyUsed(index, lock); return Success; } @@ -191,8 +239,9 @@ OCSPCache::Put(const CertID& aCertID, Result aResult, // indicates a revoked certificate, which we want to remember. if (mEntries[index]->mThisUpdate > aThisUpdate && aResult != Result::ERROR_REVOKED_CERTIFICATE) { - LogWithCertID("OCSPCache::Put(%p) already in cache with more recent " - "validity - not replacing", aCertID); + LogWithCertID("OCSPCache::Put(%p, \"%s\") already in cache with more " + "recent validity - not replacing", aCertID, + aFirstPartyDomain); MakeMostRecentlyUsed(index, lock); return Success; } @@ -202,13 +251,15 @@ OCSPCache::Put(const CertID& aCertID, Result aResult, if (aResult != Success && aResult != Result::ERROR_OCSP_UNKNOWN_CERT && aResult != Result::ERROR_REVOKED_CERTIFICATE) { - LogWithCertID("OCSPCache::Put(%p) already in cache - not replacing " - "with less important status", aCertID); + LogWithCertID("OCSPCache::Put(%p, \"%s\") already in cache - not " + "replacing with less important status", aCertID, + aFirstPartyDomain); MakeMostRecentlyUsed(index, lock); return Success; } - LogWithCertID("OCSPCache::Put(%p) already in cache - replacing", aCertID); + LogWithCertID("OCSPCache::Put(%p, \"%s\") already in cache - replacing", + aCertID, aFirstPartyDomain); mEntries[index]->mResult = aResult; mEntries[index]->mThisUpdate = aThisUpdate; mEntries[index]->mValidThrough = aValidThrough; @@ -217,7 +268,8 @@ OCSPCache::Put(const CertID& aCertID, Result aResult, } if (mEntries.length() == MaxEntries) { - LogWithCertID("OCSPCache::Put(%p) too full - evicting an entry", aCertID); + LogWithCertID("OCSPCache::Put(%p, \"%s\") too full - evicting an entry", + aCertID, aFirstPartyDomain); for (Entry** toEvict = mEntries.begin(); toEvict != mEntries.end(); toEvict++) { // Never evict an entry that indicates a revoked or unknokwn certificate, @@ -249,7 +301,7 @@ OCSPCache::Put(const CertID& aCertID, Result aResult, if (!newEntry) { return Result::FATAL_ERROR_NO_MEMORY; } - Result rv = newEntry->Init(aCertID); + Result rv = newEntry->Init(aCertID, aFirstPartyDomain); if (rv != Success) { delete newEntry; return rv; @@ -258,7 +310,8 @@ OCSPCache::Put(const CertID& aCertID, Result aResult, delete newEntry; return Result::FATAL_ERROR_NO_MEMORY; } - LogWithCertID("OCSPCache::Put(%p) added to cache", aCertID); + LogWithCertID("OCSPCache::Put(%p, \"%s\") added to cache", aCertID, + aFirstPartyDomain); return Success; } diff --git a/security/certverifier/OCSPCache.h b/security/certverifier/OCSPCache.h index d0f374f20785..b4121a8f9107 100644 --- a/security/certverifier/OCSPCache.h +++ b/security/certverifier/OCSPCache.h @@ -56,13 +56,18 @@ public: // Returns true if the status of the given certificate (issued by the given // issuer) is in the cache, and false otherwise. + // The first party domain is only non-empty when "privacy.firstParty.isolate" + // is enabled, in order to isolate OCSP cache by first party. // If it is in the cache, returns by reference the error code of the cached // status and the time through which the status is considered trustworthy. bool Get(const mozilla::pkix::CertID& aCertID, + const char* aFirstPartyDomain, /*out*/ mozilla::pkix::Result& aResult, /*out*/ mozilla::pkix::Time& aValidThrough); // Caches the status of the given certificate (issued by the given issuer). + // The first party domain is only non-empty when "privacy.firstParty.isolate" + // is enabled, in order to isolate OCSP cache by first party. // The status is considered trustworthy through the given time. // A status with an error code of SEC_ERROR_REVOKED_CERTIFICATE will not // be replaced or evicted. @@ -72,6 +77,7 @@ public: // status with a less recent thisUpdate unless the less recent status // indicates the certificate is revoked. mozilla::pkix::Result Put(const mozilla::pkix::CertID& aCertID, + const char* aFirstPartyDomain, mozilla::pkix::Result aResult, mozilla::pkix::Time aThisUpdate, mozilla::pkix::Time aValidThrough); @@ -91,18 +97,23 @@ private: , mValidThrough(aValidThrough) { } - mozilla::pkix::Result Init(const mozilla::pkix::CertID& aCertID); + mozilla::pkix::Result Init(const mozilla::pkix::CertID& aCertID, + const char* aFirstPartyDomain); mozilla::pkix::Result mResult; mozilla::pkix::Time mThisUpdate; mozilla::pkix::Time mValidThrough; // The SHA-384 hash of the concatenation of the DER encodings of the - // issuer name and issuer key, followed by the serial number. + // issuer name and issuer key, followed by the length of the serial number, + // the serial number, the length of the first party domain, and the first + // party domain (if "privacy.firstparty.isolate" is enabled). // See the documentation for CertIDHash in OCSPCache.cpp. SHA384Buffer mIDHash; }; - bool FindInternal(const mozilla::pkix::CertID& aCertID, /*out*/ size_t& index, + bool FindInternal(const mozilla::pkix::CertID& aCertID, + const char* aFirstPartyDomain, + /*out*/ size_t& index, const MutexAutoLock& aProofOfLock); void MakeMostRecentlyUsed(size_t aIndex, const MutexAutoLock& aProofOfLock); diff --git a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp index faa4502baaaa..05076fe09d21 100644 --- a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp +++ b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp @@ -47,7 +47,7 @@ protected: static void PutAndGet(OCSPCache& cache, const CertID& certID, Result result, - Time time) + Time time, const char* firstPartyDomain = nullptr) { // The first time is thisUpdate. The second is validUntil. // The caller is expecting the validUntil returned with Get @@ -55,11 +55,11 @@ PutAndGet(OCSPCache& cache, const CertID& certID, Result result, // be different in practice, make thisUpdate less than validUntil. Time thisUpdate(time); ASSERT_EQ(Success, thisUpdate.SubtractSeconds(10)); - Result rv = cache.Put(certID, result, thisUpdate, time); + Result rv = cache.Put(certID, firstPartyDomain, result, thisUpdate, time); ASSERT_TRUE(rv == Success); Result resultOut; Time timeOut(Time::uninitialized); - ASSERT_TRUE(cache.Get(certID, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(certID, firstPartyDomain, resultOut, timeOut)); ASSERT_EQ(result, resultOut); ASSERT_EQ(time, timeOut); } @@ -80,7 +80,7 @@ TEST_F(psm_OCSPCacheTest, TestPutAndGet) Result resultOut; Time timeOut(Time::uninitialized); ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial000), - resultOut, timeOut)); + nullptr, resultOut, timeOut)); } TEST_F(psm_OCSPCacheTest, TestVariousGets) @@ -104,11 +104,11 @@ TEST_F(psm_OCSPCacheTest, TestVariousGets) // This will be at the end of the list in the cache CertID cert0000(fakeIssuer1, fakeKey000, fakeSerial0000); - ASSERT_TRUE(cache.Get(cert0000, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(cert0000, nullptr, resultOut, timeOut)); ASSERT_EQ(Success, resultOut); ASSERT_EQ(timeIn, timeOut); // Once we access it, it goes to the front - ASSERT_TRUE(cache.Get(cert0000, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(cert0000, nullptr, resultOut, timeOut)); ASSERT_EQ(Success, resultOut); ASSERT_EQ(timeIn, timeOut); @@ -118,17 +118,17 @@ TEST_F(psm_OCSPCacheTest, TestVariousGets) static const Input fakeSerial0512(LiteralInput("0512")); CertID cert0512(fakeIssuer1, fakeKey000, fakeSerial0512); - ASSERT_TRUE(cache.Get(cert0512, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(cert0512, nullptr, resultOut, timeOut)); ASSERT_EQ(Success, resultOut); ASSERT_EQ(timeInPlus512, timeOut); - ASSERT_TRUE(cache.Get(cert0512, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(cert0512, nullptr, resultOut, timeOut)); ASSERT_EQ(Success, resultOut); ASSERT_EQ(timeInPlus512, timeOut); // We've never seen this certificate static const Input fakeSerial1111(LiteralInput("1111")); ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey000, fakeSerial1111), - resultOut, timeOut)); + nullptr, resultOut, timeOut)); } TEST_F(psm_OCSPCacheTest, TestEviction) @@ -151,7 +151,7 @@ TEST_F(psm_OCSPCacheTest, TestEviction) Result resultOut; Time timeOut(Time::uninitialized); ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial0000), - resultOut, timeOut)); + nullptr, resultOut, timeOut)); } TEST_F(psm_OCSPCacheTest, TestNoEvictionForRevokedResponses) @@ -175,13 +175,13 @@ TEST_F(psm_OCSPCacheTest, TestNoEvictionForRevokedResponses) } Result resultOut; Time timeOut(Time::uninitialized); - ASSERT_TRUE(cache.Get(notEvicted, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(notEvicted, nullptr, resultOut, timeOut)); ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, resultOut); ASSERT_EQ(timeIn, timeOut); Input fakeSerial0001(LiteralInput("0001")); CertID evicted(fakeIssuer1, fakeKey000, fakeSerial0001); - ASSERT_FALSE(cache.Get(evicted, resultOut, timeOut)); + ASSERT_FALSE(cache.Get(evicted, nullptr, resultOut, timeOut)); } TEST_F(psm_OCSPCacheTest, TestEverythingIsRevoked) @@ -208,12 +208,12 @@ TEST_F(psm_OCSPCacheTest, TestEverythingIsRevoked) ASSERT_EQ(Success, timeInPlus1025.AddSeconds(1025)); Time timeInPlus1025Minus50(timeInPlus1025); ASSERT_EQ(Success, timeInPlus1025Minus50.SubtractSeconds(50)); - Result result = cache.Put(good, Success, timeInPlus1025Minus50, + Result result = cache.Put(good, nullptr, Success, timeInPlus1025Minus50, timeInPlus1025); ASSERT_EQ(Success, result); Result resultOut; Time timeOut(Time::uninitialized); - ASSERT_FALSE(cache.Get(good, resultOut, timeOut)); + ASSERT_FALSE(cache.Get(good, nullptr, resultOut, timeOut)); static const Input fakeSerial1026(LiteralInput("1026")); CertID revoked(fakeIssuer1, fakeKey000, fakeSerial1026); @@ -222,7 +222,7 @@ TEST_F(psm_OCSPCacheTest, TestEverythingIsRevoked) ASSERT_EQ(Success, timeInPlus1026.AddSeconds(1026)); Time timeInPlus1026Minus50(timeInPlus1026); ASSERT_EQ(Success, timeInPlus1026Minus50.SubtractSeconds(50)); - result = cache.Put(revoked, Result::ERROR_REVOKED_CERTIFICATE, + result = cache.Put(revoked, nullptr, Result::ERROR_REVOKED_CERTIFICATE, timeInPlus1026Minus50, timeInPlus1026); ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, result); } @@ -237,15 +237,15 @@ TEST_F(psm_OCSPCacheTest, VariousIssuers) PutAndGet(cache, subject, Success, now); Result resultOut; Time timeOut(Time::uninitialized); - ASSERT_TRUE(cache.Get(subject, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(subject, nullptr, resultOut, timeOut)); ASSERT_EQ(Success, resultOut); ASSERT_EQ(timeIn, timeOut); // Test that we don't match a different issuer DN ASSERT_FALSE(cache.Get(CertID(fakeIssuer2, fakeKey000, fakeSerial001), - resultOut, timeOut)); + nullptr, resultOut, timeOut)); // Test that we don't match a different issuer key ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial001), - resultOut, timeOut)); + nullptr, resultOut, timeOut)); } TEST_F(psm_OCSPCacheTest, Times) @@ -257,12 +257,12 @@ TEST_F(psm_OCSPCacheTest, Times) PutAndGet(cache, certID, Success, TimeFromElapsedSecondsAD(200)); // This should not override the more recent entry. ASSERT_EQ(Success, - cache.Put(certID, Result::ERROR_OCSP_UNKNOWN_CERT, + cache.Put(certID, nullptr, Result::ERROR_OCSP_UNKNOWN_CERT, TimeFromElapsedSecondsAD(100), TimeFromElapsedSecondsAD(100))); Result resultOut; Time timeOut(Time::uninitialized); - ASSERT_TRUE(cache.Get(certID, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(certID, nullptr, resultOut, timeOut)); // Here we see the more recent time. ASSERT_EQ(Success, resultOut); ASSERT_EQ(TimeFromElapsedSecondsAD(200), timeOut); @@ -281,12 +281,12 @@ TEST_F(psm_OCSPCacheTest, NetworkFailure) PutAndGet(cache, certID, Success, TimeFromElapsedSecondsAD(200)); // This should not override the already present entry. ASSERT_EQ(Success, - cache.Put(certID, Result::ERROR_CONNECT_REFUSED, + cache.Put(certID, nullptr, Result::ERROR_CONNECT_REFUSED, TimeFromElapsedSecondsAD(300), TimeFromElapsedSecondsAD(350))); Result resultOut; Time timeOut(Time::uninitialized); - ASSERT_TRUE(cache.Get(certID, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(certID, nullptr, resultOut, timeOut)); ASSERT_EQ(Success, resultOut); ASSERT_EQ(TimeFromElapsedSecondsAD(200), timeOut); @@ -294,10 +294,10 @@ TEST_F(psm_OCSPCacheTest, NetworkFailure) TimeFromElapsedSecondsAD(400)); // This should not override the already present entry. ASSERT_EQ(Success, - cache.Put(certID, Result::ERROR_CONNECT_REFUSED, + cache.Put(certID, nullptr, Result::ERROR_CONNECT_REFUSED, TimeFromElapsedSecondsAD(500), TimeFromElapsedSecondsAD(550))); - ASSERT_TRUE(cache.Get(certID, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(certID, nullptr, resultOut, timeOut)); ASSERT_EQ(Result::ERROR_OCSP_UNKNOWN_CERT, resultOut); ASSERT_EQ(TimeFromElapsedSecondsAD(400), timeOut); @@ -305,10 +305,22 @@ TEST_F(psm_OCSPCacheTest, NetworkFailure) TimeFromElapsedSecondsAD(600)); // This should not override the already present entry. ASSERT_EQ(Success, - cache.Put(certID, Result::ERROR_CONNECT_REFUSED, + cache.Put(certID, nullptr, Result::ERROR_CONNECT_REFUSED, TimeFromElapsedSecondsAD(700), TimeFromElapsedSecondsAD(750))); - ASSERT_TRUE(cache.Get(certID, resultOut, timeOut)); + ASSERT_TRUE(cache.Get(certID, nullptr, resultOut, timeOut)); ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, resultOut); ASSERT_EQ(TimeFromElapsedSecondsAD(600), timeOut); } + +TEST_F(psm_OCSPCacheTest, TestFirstPartyDomain) +{ + CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000); + + SCOPED_TRACE(""); + PutAndGet(cache, certID, Success, now, "foo.com"); + + Result resultOut; + Time timeOut(Time::uninitialized); + ASSERT_FALSE(cache.Get(certID, "bar.com", resultOut, timeOut)); +}