--- a/security/certverifier/OCSPCache.cpp
+++ b/security/certverifier/OCSPCache.cpp
@@ -33,29 +33,54 @@
#include "secerr.h"
extern mozilla::LazyLogModule gCertVerifierLog;
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) {
return SECFailure;
}
SECStatus rv = PK11_DigestBegin(context.get());
if (rv != SECSuccess) {
return rv;
@@ -69,33 +94,50 @@ CertIDHash(SHA384Buffer& buf, const Cert
UnsafeMapInputToSECItem(certID.issuerSubjectPublicKeyInfo);
rv = PK11_DigestOp(context.get(), certIDIssuerSubjectPublicKeyInfo.data,
certIDIssuerSubjectPublicKeyInfo.len);
if (rv != SECSuccess) {
return rv;
}
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<const unsigned char*>(firstPartyDomain),
+ firstPartyDomainLen);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
uint32_t outLen = 0;
rv = PK11_DigestFinal(context.get(), buf, &outLen, SHA384_LENGTH);
if (outLen != SHA384_LENGTH) {
return SECFailure;
}
return rv;
}
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());
}
return Success;
}
OCSPCache::OCSPCache()
: mMutex("OCSPCache-mutex")
@@ -105,25 +147,26 @@ OCSPCache::OCSPCache()
OCSPCache::~OCSPCache()
{
Clear();
}
// 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) {
return false;
}
SHA384Buffer idHash;
- SECStatus rv = CertIDHash(idHash, aCertID);
+ SECStatus rv = CertIDHash(idHash, aCertID, aFirstPartyDomain);
if (rv != SECSuccess) {
return false;
}
// mEntries is sorted with the most-recently-used entry at the end.
// Thus, searching from the end will often be fastest.
index = mEntries.length();
while (index > 0) {
@@ -131,98 +174,107 @@ OCSPCache::FindInternal(const CertID& aC
if (memcmp(mEntries[index]->mIDHash, idHash, SHA384_LENGTH) == 0) {
return true;
}
}
return false;
}
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
OCSPCache::MakeMostRecentlyUsed(size_t aIndex,
const MutexAutoLock& /* aProofOfLock */)
{
Entry* entry = mEntries[aIndex];
// Since mEntries is sorted with the most-recently-used entry at the end,
// aIndex is likely to be near the end, so this is likely to be fast.
mEntries.erase(mEntries.begin() + aIndex);
// erase() does not shrink or realloc memory, so the append below should
// always succeed.
MOZ_RELEASE_ASSERT(mEntries.append(entry));
}
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);
return true;
}
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;
}
// Never replace a newer entry with an older one unless the older entry
// 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;
}
// Only known good responses or responses indicating an unknown
// or revoked certificate should replace previously known responses.
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;
MakeMostRecentlyUsed(index, lock);
return Success;
}
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,
// because revoked responses are more security-critical to remember.
if ((*toEvict)->mResult != Result::ERROR_REVOKED_CERTIFICATE &&
(*toEvict)->mResult != Result::ERROR_OCSP_UNKNOWN_CERT) {
delete *toEvict;
mEntries.erase(toEvict);
@@ -244,26 +296,27 @@ OCSPCache::Put(const CertID& aCertID, Re
Entry* newEntry = new (std::nothrow) Entry(aResult, aThisUpdate,
aValidThrough);
// Normally we don't have to do this in Gecko, because OOM is fatal.
// However, if we want to embed this in another project, OOM might not
// be fatal, so handle this case.
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;
}
if (!mEntries.append(newEntry)) {
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;
}
void
OCSPCache::Clear()
{
MutexAutoLock lock(mMutex);
MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("OCSPCache::Clear: clearing cache"));
--- a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
+++ b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
@@ -42,29 +42,29 @@ protected:
}
const Time now;
mozilla::psm::OCSPCache cache;
};
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
// to be equal to the passed-in time. Since these values will
// 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);
}
Input fakeIssuer1(LiteralInput("CN=issuer1"));
Input fakeKey000(LiteralInput("key000"));
Input fakeKey001(LiteralInput("key001"));
Input fakeSerial0000(LiteralInput("0000"));
@@ -75,17 +75,17 @@ TEST_F(psm_OCSPCacheTest, TestPutAndGet)
Input fakeSerial001(LiteralInput("001"));
SCOPED_TRACE("");
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial001),
Success, now);
Result resultOut;
Time timeOut(Time::uninitialized);
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial000),
- resultOut, timeOut));
+ nullptr, resultOut, timeOut));
}
TEST_F(psm_OCSPCacheTest, TestVariousGets)
{
SCOPED_TRACE("");
for (int i = 0; i < MaxCacheEntries; i++) {
uint8_t serialBuf[8];
snprintf(mozilla::BitwiseCast<char*, uint8_t*>(serialBuf), sizeof(serialBuf),
@@ -99,41 +99,41 @@ TEST_F(psm_OCSPCacheTest, TestVariousGet
}
Time timeIn(now);
Result resultOut;
Time timeOut(Time::uninitialized);
// 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);
// This will be in the middle
Time timeInPlus512(now);
ASSERT_EQ(Success, timeInPlus512.AddSeconds(512));
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)
{
SCOPED_TRACE("");
// By putting more distinct entries in the cache than it can hold,
// we cause the least recently used entry to be evicted.
for (int i = 0; i < MaxCacheEntries + 1; i++) {
@@ -146,17 +146,17 @@ TEST_F(psm_OCSPCacheTest, TestEviction)
ASSERT_EQ(Success, timeIn.AddSeconds(i));
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
Success, timeIn);
}
Result resultOut;
Time timeOut(Time::uninitialized);
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial0000),
- resultOut, timeOut));
+ nullptr, resultOut, timeOut));
}
TEST_F(psm_OCSPCacheTest, TestNoEvictionForRevokedResponses)
{
SCOPED_TRACE("");
CertID notEvicted(fakeIssuer1, fakeKey000, fakeSerial0000);
Time timeIn(now);
PutAndGet(cache, notEvicted, Result::ERROR_REVOKED_CERTIFICATE, timeIn);
@@ -170,23 +170,23 @@ TEST_F(psm_OCSPCacheTest, TestNoEviction
ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
Time timeIn(now);
ASSERT_EQ(Success, timeIn.AddSeconds(i));
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
Success, timeIn);
}
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)
{
SCOPED_TRACE("");
Time timeIn(now);
// Fill up the cache with revoked responses.
for (int i = 0; i < MaxCacheEntries; i++) {
@@ -203,71 +203,71 @@ TEST_F(psm_OCSPCacheTest, TestEverything
static const Input fakeSerial1025(LiteralInput("1025"));
CertID good(fakeIssuer1, fakeKey000, fakeSerial1025);
// This will "succeed", allowing verification to continue. However,
// nothing was actually put in the cache.
Time timeInPlus1025(timeIn);
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);
// This will fail, causing verification to fail.
Time timeInPlus1026(timeIn);
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);
}
TEST_F(psm_OCSPCacheTest, VariousIssuers)
{
SCOPED_TRACE("");
Time timeIn(now);
static const Input fakeIssuer2(LiteralInput("CN=issuer2"));
static const Input fakeSerial001(LiteralInput("001"));
CertID subject(fakeIssuer1, fakeKey000, fakeSerial001);
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)
{
SCOPED_TRACE("");
CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
PutAndGet(cache, certID, Result::ERROR_OCSP_UNKNOWN_CERT,
TimeFromElapsedSecondsAD(100));
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);
// Result::ERROR_REVOKED_CERTIFICATE overrides everything
PutAndGet(cache, certID, Result::ERROR_REVOKED_CERTIFICATE,
TimeFromElapsedSecondsAD(50));
}
@@ -276,39 +276,51 @@ TEST_F(psm_OCSPCacheTest, NetworkFailure
{
SCOPED_TRACE("");
CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
PutAndGet(cache, certID, Result::ERROR_CONNECT_REFUSED,
TimeFromElapsedSecondsAD(100));
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);
PutAndGet(cache, certID, Result::ERROR_OCSP_UNKNOWN_CERT,
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);
PutAndGet(cache, certID, Result::ERROR_REVOKED_CERTIFICATE,
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));
+}