mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-11 10:08:41 +00:00
Bug 1026261: Remove CERTCertificate from mozilla::pkix revocation checking API, r=keeler
--HG-- extra : rebase_source : 6798f494bd351961ea02abba07b5860839bbc418
This commit is contained in:
parent
c751f855a6
commit
ca4f473450
@ -170,10 +170,8 @@ AppTrustDomain::VerifySignedData(const CERTSignedData* signedData,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
AppTrustDomain::CheckRevocation(EndEntityOrCA,
|
||||
const CERTCertificate*,
|
||||
/*const*/ CERTCertificate*,
|
||||
PRTime time,
|
||||
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
|
||||
|
@ -31,10 +31,9 @@ public:
|
||||
SECStatus VerifySignedData(const CERTSignedData* signedData,
|
||||
const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
|
||||
SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const CERTCertificate* cert,
|
||||
/*const*/ CERTCertificate* issuerCertToDup,
|
||||
PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPresponse);
|
||||
const mozilla::pkix::CertID& certID, PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPresponse,
|
||||
/*optional*/ const SECItem* aiaExtension);
|
||||
SECStatus IsChainValid(const CERTCertList* certChain) { return SECSuccess; }
|
||||
|
||||
private:
|
||||
|
@ -175,13 +175,67 @@ OCSPFetchingTypeToTimeoutTime(NSSCertDBTrustDomain::OCSPFetching ocspFetching)
|
||||
return PR_SecondsToInterval(2);
|
||||
}
|
||||
|
||||
// Copied and modified from CERT_GetOCSPAuthorityInfoAccessLocation and
|
||||
// CERT_GetGeneralNameByType. Returns SECFailure on error, SECSuccess
|
||||
// with url == nullptr when an OCSP URI was not found, and SECSuccess with
|
||||
// url != nullptr when an OCSP URI was found. The output url will be owned
|
||||
// by the arena.
|
||||
static SECStatus
|
||||
GetOCSPAuthorityInfoAccessLocation(PLArenaPool* arena,
|
||||
const SECItem& aiaExtension,
|
||||
/*out*/ char const*& url)
|
||||
{
|
||||
url = nullptr;
|
||||
|
||||
// TODO(bug 1028380): Remove the const_cast.
|
||||
CERTAuthInfoAccess** aia = CERT_DecodeAuthInfoAccessExtension(
|
||||
arena,
|
||||
const_cast<SECItem*>(&aiaExtension));
|
||||
if (!aia) {
|
||||
PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
for (size_t i = 0; aia[i]; ++i) {
|
||||
if (SECOID_FindOIDTag(&aia[i]->method) == SEC_OID_PKIX_OCSP) {
|
||||
// NSS chooses the **last** OCSP URL; we choose the **first**
|
||||
CERTGeneralName* current = aia[i]->location;
|
||||
if (!current) {
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
if (current->type == certURI) {
|
||||
const SECItem& location = current->name.other;
|
||||
// (location.len + 1) must be small enough to fit into a uint32_t,
|
||||
// but we limit it to a smaller bound to reduce OOM risk.
|
||||
if (location.len > 1024 || memchr(location.data, 0, location.len)) {
|
||||
// Reject embedded nulls. (NSS doesn't do this)
|
||||
PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
// Copy the non-null-terminated SECItem into a null-terminated string.
|
||||
char* nullTerminatedURL(static_cast<char*>(
|
||||
PORT_ArenaAlloc(arena, location.len + 1)));
|
||||
if (!nullTerminatedURL) {
|
||||
return SECFailure;
|
||||
}
|
||||
memcpy(nullTerminatedURL, location.data, location.len);
|
||||
nullTerminatedURL[location.len] = 0;
|
||||
url = nullTerminatedURL;
|
||||
return SECSuccess;
|
||||
}
|
||||
current = CERT_GetNextGeneralName(current);
|
||||
} while (current != aia[i]->location);
|
||||
}
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
NSSCertDBTrustDomain::CheckRevocation(
|
||||
mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const CERTCertificate* cert,
|
||||
/*const*/ CERTCertificate* issuerCert,
|
||||
PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse)
|
||||
NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
const CertID& certID, PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const SECItem* aiaExtension)
|
||||
{
|
||||
// Actively distrusted certificates will have already been blocked by
|
||||
// GetCertTrust.
|
||||
@ -192,13 +246,6 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("NSSCertDBTrustDomain: Top of CheckRevocation\n"));
|
||||
|
||||
PORT_Assert(cert);
|
||||
PORT_Assert(issuerCert);
|
||||
if (!cert || !issuerCert) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Bug 991815: The BR allow OCSP for intermediates to be up to one year old.
|
||||
// Since this affects EV there is no reason why DV should be more strict
|
||||
// so all intermediatates are allowed to have OCSP responses up to one year
|
||||
@ -218,10 +265,9 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
if (stapledOCSPResponse) {
|
||||
PR_ASSERT(endEntityOrCA == EndEntityOrCA::MustBeEndEntity);
|
||||
bool expired;
|
||||
SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(cert, issuerCert,
|
||||
time,
|
||||
SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
|
||||
maxOCSPLifetimeInDays,
|
||||
stapledOCSPResponse,
|
||||
*stapledOCSPResponse,
|
||||
ResponseWasStapled,
|
||||
expired);
|
||||
if (rv == SECSuccess) {
|
||||
@ -254,7 +300,7 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
|
||||
PRErrorCode cachedResponseErrorCode = 0;
|
||||
PRTime cachedResponseValidThrough = 0;
|
||||
bool cachedResponsePresent = mOCSPCache.Get(cert, issuerCert,
|
||||
bool cachedResponsePresent = mOCSPCache.Get(certID,
|
||||
cachedResponseErrorCode,
|
||||
cachedResponseValidThrough);
|
||||
if (cachedResponsePresent) {
|
||||
@ -332,8 +378,19 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ScopedPtr<char, PORT_Free_string>
|
||||
url(CERT_GetOCSPAuthorityInfoAccessLocation(cert));
|
||||
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
||||
if (!arena) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
const char* url = nullptr; // owned by the arena
|
||||
|
||||
if (aiaExtension) {
|
||||
if (GetOCSPAuthorityInfoAccessLocation(arena.get(), *aiaExtension, url)
|
||||
!= SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
if (mOCSPFetching == FetchOCSPForEV ||
|
||||
@ -357,24 +414,18 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
||||
if (!arena) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// 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(), cert,
|
||||
issuerCert));
|
||||
const SECItem* request(CreateEncodedOCSPRequest(arena.get(), certID));
|
||||
if (!request) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
response = DoOCSPRequest(arena.get(), url.get(), request,
|
||||
response = DoOCSPRequest(arena.get(), url, request,
|
||||
OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
|
||||
mOCSPGetConfig == CertVerifier::ocsp_get_enabled);
|
||||
}
|
||||
@ -385,7 +436,7 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
error = cachedResponseErrorCode;
|
||||
}
|
||||
PRTime timeout = time + ServerFailureDelay;
|
||||
if (mOCSPCache.Put(cert, issuerCert, error, time, timeout) != SECSuccess) {
|
||||
if (mOCSPCache.Put(certID, error, time, timeout) != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
PR_SetError(error, 0);
|
||||
@ -420,9 +471,9 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
// or unknown certificate, PR_GetError() will return the appropriate error.
|
||||
// We actually ignore expired here.
|
||||
bool expired;
|
||||
SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(cert, issuerCert, time,
|
||||
SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
|
||||
maxOCSPLifetimeInDays,
|
||||
response,
|
||||
*response,
|
||||
ResponseIsFromNetwork,
|
||||
expired);
|
||||
if (rv == SECSuccess || mOCSPFetching != FetchOCSPForDVSoftFail) {
|
||||
@ -453,13 +504,13 @@ NSSCertDBTrustDomain::CheckRevocation(
|
||||
|
||||
SECStatus
|
||||
NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
|
||||
const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time,
|
||||
uint16_t maxLifetimeInDays, const SECItem* encodedResponse,
|
||||
EncodedResponseSource responseSource, /*out*/ bool& expired)
|
||||
const CertID& certID, PRTime time, uint16_t maxLifetimeInDays,
|
||||
const SECItem& encodedResponse, EncodedResponseSource responseSource,
|
||||
/*out*/ bool& expired)
|
||||
{
|
||||
PRTime thisUpdate = 0;
|
||||
PRTime validThrough = 0;
|
||||
SECStatus rv = VerifyEncodedOCSPResponse(*this, cert, issuerCert, time,
|
||||
SECStatus rv = VerifyEncodedOCSPResponse(*this, certID, time,
|
||||
maxLifetimeInDays, encodedResponse,
|
||||
expired, &thisUpdate, &validThrough);
|
||||
PRErrorCode error = (rv == SECSuccess ? 0 : PR_GetError());
|
||||
@ -483,8 +534,7 @@ NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
|
||||
error == SEC_ERROR_OCSP_UNKNOWN_CERT) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("NSSCertDBTrustDomain: caching OCSP response"));
|
||||
if (mOCSPCache.Put(cert, issuerCert, error, thisUpdate, validThrough)
|
||||
!= SECSuccess) {
|
||||
if (mOCSPCache.Put(certID, error, thisUpdate, validThrough) != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
}
|
||||
|
@ -75,10 +75,10 @@ public:
|
||||
const SECItem& subjectPublicKeyInfo);
|
||||
|
||||
virtual SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const CERTCertificate* cert,
|
||||
/*const*/ CERTCertificate* issuerCert,
|
||||
const mozilla::pkix::CertID& certID,
|
||||
PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse);
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const SECItem* aiaExtension);
|
||||
|
||||
virtual SECStatus IsChainValid(const CERTCertList* certChain);
|
||||
|
||||
@ -89,8 +89,8 @@ private:
|
||||
};
|
||||
static const PRTime ServerFailureDelay = 5 * 60 * PR_USEC_PER_SEC;
|
||||
SECStatus VerifyAndMaybeCacheEncodedOCSPResponse(
|
||||
const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time,
|
||||
uint16_t maxLifetimeInDays, const SECItem* encodedResponse,
|
||||
const mozilla::pkix::CertID& certID, PRTime time,
|
||||
uint16_t maxLifetimeInDays, const SECItem& encodedResponse,
|
||||
EncodedResponseSource responseSource, /*out*/ bool& expired);
|
||||
|
||||
const SECTrustType mCertDBTrustType;
|
||||
|
@ -28,12 +28,15 @@
|
||||
|
||||
#include "NSSCertDBTrustDomain.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gCertVerifierLog;
|
||||
#endif
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
void
|
||||
@ -58,8 +61,7 @@ typedef mozilla::pkix::ScopedPtr<PK11Context,
|
||||
// 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 CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert)
|
||||
CertIDHash(SHA384Buffer& buf, const CertID& certID)
|
||||
{
|
||||
ScopedPK11Context context(PK11_CreateDigestContext(SEC_OID_SHA384));
|
||||
if (!context) {
|
||||
@ -69,18 +71,17 @@ CertIDHash(SHA384Buffer& buf, const CERTCertificate* aCert,
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
rv = PK11_DigestOp(context.get(), aCert->derIssuer.data,
|
||||
aCert->derIssuer.len);
|
||||
rv = PK11_DigestOp(context.get(), certID.issuer.data, certID.issuer.len);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
rv = PK11_DigestOp(context.get(), aIssuerCert->derPublicKey.data,
|
||||
aIssuerCert->derPublicKey.len);
|
||||
rv = PK11_DigestOp(context.get(), certID.issuerSubjectPublicKeyInfo.data,
|
||||
certID.issuerSubjectPublicKeyInfo.len);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
rv = PK11_DigestOp(context.get(), aCert->serialNumber.data,
|
||||
aCert->serialNumber.len);
|
||||
rv = PK11_DigestOp(context.get(), certID.serialNumber.data,
|
||||
certID.serialNumber.len);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
@ -93,16 +94,13 @@ CertIDHash(SHA384Buffer& buf, const CERTCertificate* aCert,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
OCSPCache::Entry::Init(const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert,
|
||||
PRErrorCode aErrorCode,
|
||||
PRTime aThisUpdate,
|
||||
PRTime aValidThrough)
|
||||
OCSPCache::Entry::Init(const CertID& aCertID, PRErrorCode aErrorCode,
|
||||
PRTime aThisUpdate, PRTime aValidThrough)
|
||||
{
|
||||
mErrorCode = aErrorCode;
|
||||
mThisUpdate = aThisUpdate;
|
||||
mValidThrough = aValidThrough;
|
||||
return CertIDHash(mIDHash, aCert, aIssuerCert);
|
||||
return CertIDHash(mIDHash, aCertID);
|
||||
}
|
||||
|
||||
OCSPCache::OCSPCache()
|
||||
@ -118,9 +116,7 @@ OCSPCache::~OCSPCache()
|
||||
// Returns false with index in an undefined state if no matching entry was
|
||||
// found.
|
||||
bool
|
||||
OCSPCache::FindInternal(const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert,
|
||||
/*out*/ size_t& index,
|
||||
OCSPCache::FindInternal(const CertID& aCertID, /*out*/ size_t& index,
|
||||
const MutexAutoLock& /* aProofOfLock */)
|
||||
{
|
||||
if (mEntries.length() == 0) {
|
||||
@ -128,7 +124,7 @@ OCSPCache::FindInternal(const CERTCertificate* aCert,
|
||||
}
|
||||
|
||||
SHA384Buffer idHash;
|
||||
SECStatus rv = CertIDHash(idHash, aCert, aIssuerCert);
|
||||
SECStatus rv = CertIDHash(idHash, aCertID);
|
||||
if (rv != SECSuccess) {
|
||||
return false;
|
||||
}
|
||||
@ -145,19 +141,10 @@ OCSPCache::FindInternal(const CERTCertificate* aCert,
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
OCSPCache::LogWithCerts(const char* aMessage, const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert)
|
||||
static inline void
|
||||
LogWithCertID(const char* aMessage, const CertID& aCertID)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gCertVerifierLog, PR_LOG_DEBUG)) {
|
||||
mozilla::pkix::ScopedPtr<char, mozilla::psm::PORT_Free_string>
|
||||
cn(CERT_GetCommonName(&aCert->subject));
|
||||
mozilla::pkix::ScopedPtr<char, mozilla::psm::PORT_Free_string>
|
||||
cnIssuer(CERT_GetCommonName(&aIssuerCert->subject));
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, (aMessage, cn.get(), cnIssuer.get()));
|
||||
}
|
||||
#endif
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, (aMessage, &aCertID));
|
||||
}
|
||||
|
||||
void
|
||||
@ -172,22 +159,17 @@ OCSPCache::MakeMostRecentlyUsed(size_t aIndex,
|
||||
}
|
||||
|
||||
bool
|
||||
OCSPCache::Get(const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert,
|
||||
PRErrorCode& aErrorCode,
|
||||
OCSPCache::Get(const CertID& aCertID, PRErrorCode& aErrorCode,
|
||||
PRTime& aValidThrough)
|
||||
{
|
||||
PR_ASSERT(aCert);
|
||||
PR_ASSERT(aIssuerCert);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
size_t index;
|
||||
if (!FindInternal(aCert, aIssuerCert, index, lock)) {
|
||||
LogWithCerts("OCSPCache::Get(%s, %s) not in cache", aCert, aIssuerCert);
|
||||
if (!FindInternal(aCertID, index, lock)) {
|
||||
LogWithCertID("OCSPCache::Get(%p) not in cache", aCertID);
|
||||
return false;
|
||||
}
|
||||
LogWithCerts("OCSPCache::Get(%s, %s) in cache", aCert, aIssuerCert);
|
||||
LogWithCertID("OCSPCache::Get(%p) in cache", aCertID);
|
||||
aErrorCode = mEntries[index]->mErrorCode;
|
||||
aValidThrough = mEntries[index]->mValidThrough;
|
||||
MakeMostRecentlyUsed(index, lock);
|
||||
@ -195,23 +177,17 @@ OCSPCache::Get(const CERTCertificate* aCert,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
OCSPCache::Put(const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert,
|
||||
PRErrorCode aErrorCode,
|
||||
PRTime aThisUpdate,
|
||||
PRTime aValidThrough)
|
||||
OCSPCache::Put(const CertID& aCertID, PRErrorCode aErrorCode,
|
||||
PRTime aThisUpdate, PRTime aValidThrough)
|
||||
{
|
||||
PR_ASSERT(aCert);
|
||||
PR_ASSERT(aIssuerCert);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
size_t index;
|
||||
if (FindInternal(aCert, aIssuerCert, index, lock)) {
|
||||
if (FindInternal(aCertID, index, lock)) {
|
||||
// Never replace an entry indicating a revoked certificate.
|
||||
if (mEntries[index]->mErrorCode == SEC_ERROR_REVOKED_CERTIFICATE) {
|
||||
LogWithCerts("OCSPCache::Put(%s, %s) already in cache as revoked - "
|
||||
"not replacing", aCert, aIssuerCert);
|
||||
LogWithCertID("OCSPCache::Put(%p) already in cache as revoked - "
|
||||
"not replacing", aCertID);
|
||||
MakeMostRecentlyUsed(index, lock);
|
||||
return SECSuccess;
|
||||
}
|
||||
@ -220,8 +196,8 @@ OCSPCache::Put(const CERTCertificate* aCert,
|
||||
// indicates a revoked certificate, which we want to remember.
|
||||
if (mEntries[index]->mThisUpdate > aThisUpdate &&
|
||||
aErrorCode != SEC_ERROR_REVOKED_CERTIFICATE) {
|
||||
LogWithCerts("OCSPCache::Put(%s, %s) already in cache with more recent "
|
||||
"validity - not replacing", aCert, aIssuerCert);
|
||||
LogWithCertID("OCSPCache::Put(%p) already in cache with more recent "
|
||||
"validity - not replacing", aCertID);
|
||||
MakeMostRecentlyUsed(index, lock);
|
||||
return SECSuccess;
|
||||
}
|
||||
@ -230,14 +206,13 @@ OCSPCache::Put(const CERTCertificate* aCert,
|
||||
// or revoked certificate should replace previously known responses.
|
||||
if (aErrorCode != 0 && aErrorCode != SEC_ERROR_OCSP_UNKNOWN_CERT &&
|
||||
aErrorCode != SEC_ERROR_REVOKED_CERTIFICATE) {
|
||||
LogWithCerts("OCSPCache::Put(%s, %s) already in cache - not replacing "
|
||||
"with less important status", aCert, aIssuerCert);
|
||||
LogWithCertID("OCSPCache::Put(%p) already in cache - not replacing "
|
||||
"with less important status", aCertID);
|
||||
MakeMostRecentlyUsed(index, lock);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
LogWithCerts("OCSPCache::Put(%s, %s) already in cache - replacing",
|
||||
aCert, aIssuerCert);
|
||||
LogWithCertID("OCSPCache::Put(%p) already in cache - replacing", aCertID);
|
||||
mEntries[index]->mErrorCode = aErrorCode;
|
||||
mEntries[index]->mThisUpdate = aThisUpdate;
|
||||
mEntries[index]->mValidThrough = aValidThrough;
|
||||
@ -246,8 +221,7 @@ OCSPCache::Put(const CERTCertificate* aCert,
|
||||
}
|
||||
|
||||
if (mEntries.length() == MaxEntries) {
|
||||
LogWithCerts("OCSPCache::Put(%s, %s) too full - evicting an entry", aCert,
|
||||
aIssuerCert);
|
||||
LogWithCertID("OCSPCache::Put(%p) too full - evicting an entry", aCertID);
|
||||
for (Entry** toEvict = mEntries.begin(); toEvict != mEntries.end();
|
||||
toEvict++) {
|
||||
// Never evict an entry that indicates a revoked or unknokwn certificate,
|
||||
@ -283,14 +257,14 @@ OCSPCache::Put(const CERTCertificate* aCert,
|
||||
PR_SetError(SEC_ERROR_NO_MEMORY, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
SECStatus rv = newEntry->Init(aCert, aIssuerCert, aErrorCode, aThisUpdate,
|
||||
SECStatus rv = newEntry->Init(aCertID, aErrorCode, aThisUpdate,
|
||||
aValidThrough);
|
||||
if (rv != SECSuccess) {
|
||||
delete newEntry;
|
||||
return rv;
|
||||
}
|
||||
mEntries.append(newEntry);
|
||||
LogWithCerts("OCSPCache::Put(%s, %s) added to cache", aCert, aIssuerCert);
|
||||
LogWithCertID("OCSPCache::Put(%p) added to cache", aCertID);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,17 @@
|
||||
#ifndef mozilla_psm_OCSPCache_h
|
||||
#define mozilla_psm_OCSPCache_h
|
||||
|
||||
#include "certt.h"
|
||||
#include "hasht.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "prerror.h"
|
||||
#include "prtime.h"
|
||||
#include "seccomon.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
struct CertID;
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
// make SHA384Buffer be of type "array of uint8_t of length SHA384_LENGTH"
|
||||
@ -54,7 +57,7 @@ public:
|
||||
// issuer) is in the cache, and false otherwise.
|
||||
// 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 CERTCertificate* aCert, const CERTCertificate* aIssuerCert,
|
||||
bool Get(const mozilla::pkix::CertID& aCertID,
|
||||
/* out */ PRErrorCode& aErrorCode, /* out */ PRTime& aValidThrough);
|
||||
|
||||
// Caches the status of the given certificate (issued by the given issuer).
|
||||
@ -66,11 +69,8 @@ public:
|
||||
// A status with a more recent thisUpdate will not be replaced with a
|
||||
// status with a less recent thisUpdate unless the less recent status
|
||||
// indicates the certificate is revoked.
|
||||
SECStatus Put(const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert,
|
||||
PRErrorCode aErrorCode,
|
||||
PRTime aThisUpdate,
|
||||
PRTime aValidThrough);
|
||||
SECStatus Put(const mozilla::pkix::CertID& aCertID, PRErrorCode aErrorCode,
|
||||
PRTime aThisUpdate, PRTime aValidThrough);
|
||||
|
||||
// Removes everything from the cache.
|
||||
void Clear();
|
||||
@ -79,10 +79,8 @@ private:
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
SECStatus Init(const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert,
|
||||
PRErrorCode aErrorCode, PRTime aThisUpdate,
|
||||
PRTime aValidThrough);
|
||||
SECStatus Init(const mozilla::pkix::CertID& aCertID, PRErrorCode aErrorCode,
|
||||
PRTime aThisUpdate, PRTime aValidThrough);
|
||||
|
||||
PRErrorCode mErrorCode;
|
||||
PRTime mThisUpdate;
|
||||
@ -93,13 +91,9 @@ private:
|
||||
SHA384Buffer mIDHash;
|
||||
};
|
||||
|
||||
bool FindInternal(const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert,
|
||||
/*out*/ size_t& index,
|
||||
bool FindInternal(const mozilla::pkix::CertID& aCertID, /*out*/ size_t& index,
|
||||
const MutexAutoLock& aProofOfLock);
|
||||
void MakeMostRecentlyUsed(size_t aIndex, const MutexAutoLock& aProofOfLock);
|
||||
void LogWithCerts(const char* aMessage, const CERTCertificate* aCert,
|
||||
const CERTCertificate* aIssuerCert);
|
||||
|
||||
Mutex mMutex;
|
||||
static const size_t MaxEntries = 1024;
|
||||
|
@ -6,12 +6,15 @@
|
||||
|
||||
#include "CertVerifier.h"
|
||||
#include "OCSPCache.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "nss.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "prerr.h"
|
||||
#include "prprf.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::psm;
|
||||
|
||||
const int MaxCacheEntries = 1024;
|
||||
|
||||
@ -27,179 +30,207 @@ class OCSPCacheTest : public ::testing::Test
|
||||
mozilla::psm::OCSPCache cache;
|
||||
};
|
||||
|
||||
// Makes a fake certificate with just the fields we need for testing here.
|
||||
// (And those values are almost entirely bogus.)
|
||||
// stackCert should be stack-allocated memory.
|
||||
static void
|
||||
MakeFakeCert(CERTCertificate* stackCert, const char* subjectValue,
|
||||
const char* issuerValue, const char* serialNumberValue,
|
||||
const char* publicKeyValue)
|
||||
{
|
||||
stackCert->derSubject.data = (unsigned char*)subjectValue;
|
||||
stackCert->derSubject.len = strlen(subjectValue);
|
||||
stackCert->derIssuer.data = (unsigned char*)issuerValue;
|
||||
stackCert->derIssuer.len = strlen(issuerValue);
|
||||
stackCert->serialNumber.data = (unsigned char*)serialNumberValue;
|
||||
stackCert->serialNumber.len = strlen(serialNumberValue);
|
||||
stackCert->derPublicKey.data = (unsigned char*)publicKeyValue;
|
||||
stackCert->derPublicKey.len = strlen(publicKeyValue);
|
||||
CERTName *subject = CERT_AsciiToName(subjectValue); // TODO: this will leak...
|
||||
ASSERT_TRUE(subject);
|
||||
stackCert->subject.arena = subject->arena;
|
||||
stackCert->subject.rdns = subject->rdns;
|
||||
}
|
||||
|
||||
static void
|
||||
PutAndGet(mozilla::psm::OCSPCache& cache, CERTCertificate* subject,
|
||||
CERTCertificate* issuer,
|
||||
PRErrorCode error, PRTime time)
|
||||
PutAndGet(OCSPCache& cache, const CertID& certID, PRErrorCode error,
|
||||
PRTime time)
|
||||
{
|
||||
// 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.
|
||||
ASSERT_TRUE(time >= 10);
|
||||
SECStatus rv = cache.Put(subject, issuer, error, time - 10, time);
|
||||
SECStatus rv = cache.Put(certID, error, time - 10, time);
|
||||
ASSERT_TRUE(rv == SECSuccess);
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_TRUE(cache.Get(subject, issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
|
||||
ASSERT_TRUE(error == errorOut && time == timeOut);
|
||||
}
|
||||
|
||||
static const SECItem fakeIssuer1 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("CN=issuer1")),
|
||||
10
|
||||
};
|
||||
static const SECItem fakeKey000 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("key000")),
|
||||
6
|
||||
};
|
||||
static const SECItem fakeKey001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("key001")),
|
||||
6
|
||||
};
|
||||
static const SECItem fakeSerial0000 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("0000")),
|
||||
4
|
||||
};
|
||||
|
||||
TEST_F(OCSPCacheTest, TestPutAndGet)
|
||||
{
|
||||
static const SECItem fakeSerial000 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("000")),
|
||||
3
|
||||
};
|
||||
static const SECItem fakeSerial001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("001")),
|
||||
3
|
||||
};
|
||||
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate subject;
|
||||
MakeFakeCert(&subject, "CN=subject1", "CN=issuer1", "001", "key001");
|
||||
CERTCertificate issuer;
|
||||
MakeFakeCert(&issuer, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
PutAndGet(cache, &subject, &issuer, 0, PR_Now());
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial001), 0, PR_Now());
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_FALSE(cache.Get(&issuer, &issuer, errorOut, timeOut));
|
||||
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial000),
|
||||
errorOut, timeOut));
|
||||
}
|
||||
|
||||
TEST_F(OCSPCacheTest, TestVariousGets)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate issuer;
|
||||
MakeFakeCert(&issuer, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
PRTime timeIn = PR_Now();
|
||||
for (int i = 0; i < MaxCacheEntries; i++) {
|
||||
CERTCertificate subject;
|
||||
char subjectBuf[64];
|
||||
PR_snprintf(subjectBuf, sizeof(subjectBuf), "CN=subject%04d", i);
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
MakeFakeCert(&subject, subjectBuf, "CN=issuer1", serialBuf, "key000");
|
||||
PutAndGet(cache, &subject, &issuer, 0, timeIn + i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(serialBuf)),
|
||||
4
|
||||
};
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial), 0, timeIn + i);
|
||||
}
|
||||
CERTCertificate subject;
|
||||
// This will be at the end of the list in the cache
|
||||
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
MakeFakeCert(&subject, "CN=subject0000", "CN=issuer1", "0000", "key000");
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
|
||||
// This will be at the end of the list in the cache
|
||||
CertID cert0000(fakeIssuer1, fakeKey000, fakeSerial0000);
|
||||
ASSERT_TRUE(cache.Get(cert0000, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == 0 && timeOut == timeIn);
|
||||
// Once we access it, it goes to the front
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(cert0000, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == 0 && timeOut == timeIn);
|
||||
MakeFakeCert(&subject, "CN=subject0512", "CN=issuer1", "0512", "key000");
|
||||
|
||||
// This will be in the middle
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
static const SECItem fakeSerial0512 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("0512")),
|
||||
4
|
||||
};
|
||||
CertID cert0512(fakeIssuer1, fakeKey000, fakeSerial0512);
|
||||
ASSERT_TRUE(cache.Get(cert0512, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == 0 && timeOut == timeIn + 512);
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(cert0512, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == 0 && timeOut == timeIn + 512);
|
||||
|
||||
// We've never seen this certificate
|
||||
MakeFakeCert(&subject, "CN=subject1111", "CN=issuer1", "1111", "key000");
|
||||
ASSERT_FALSE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
static const SECItem fakeSerial1111 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1111")),
|
||||
4
|
||||
};
|
||||
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey000, fakeSerial1111),
|
||||
errorOut, timeOut));
|
||||
}
|
||||
|
||||
TEST_F(OCSPCacheTest, TestEviction)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate issuer;
|
||||
PRTime timeIn = PR_Now();
|
||||
MakeFakeCert(&issuer, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
|
||||
// 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++) {
|
||||
CERTCertificate subject;
|
||||
char subjectBuf[64];
|
||||
PR_snprintf(subjectBuf, sizeof(subjectBuf), "CN=subject%04d", i);
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
MakeFakeCert(&subject, subjectBuf, "CN=issuer1", serialBuf, "key000");
|
||||
PutAndGet(cache, &subject, &issuer, 0, timeIn + i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(serialBuf)),
|
||||
4
|
||||
};
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial), 0, timeIn + i);
|
||||
}
|
||||
CERTCertificate evictedSubject;
|
||||
MakeFakeCert(&evictedSubject, "CN=subject0000", "CN=issuer1", "0000", "key000");
|
||||
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_FALSE(cache.Get(&evictedSubject, &issuer, errorOut, timeOut));
|
||||
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial0000),
|
||||
errorOut, timeOut));
|
||||
}
|
||||
|
||||
TEST_F(OCSPCacheTest, TestNoEvictionForRevokedResponses)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate issuer;
|
||||
MakeFakeCert(&issuer, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
CERTCertificate notEvictedSubject;
|
||||
MakeFakeCert(¬EvictedSubject, "CN=subject0000", "CN=issuer1", "0000", "key000");
|
||||
PRTime timeIn = PR_Now();
|
||||
PutAndGet(cache, ¬EvictedSubject, &issuer, SEC_ERROR_REVOKED_CERTIFICATE, timeIn);
|
||||
CertID notEvicted(fakeIssuer1, fakeKey000, fakeSerial0000);
|
||||
PutAndGet(cache, notEvicted, SEC_ERROR_REVOKED_CERTIFICATE, timeIn);
|
||||
// By putting more distinct entries in the cache than it can hold,
|
||||
// we cause the least recently used entry that isn't revoked to be evicted.
|
||||
for (int i = 1; i < MaxCacheEntries + 1; i++) {
|
||||
CERTCertificate subject;
|
||||
char subjectBuf[64];
|
||||
PR_snprintf(subjectBuf, sizeof(subjectBuf), "CN=subject%04d", i);
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
MakeFakeCert(&subject, subjectBuf, "CN=issuer1", serialBuf, "key000");
|
||||
PutAndGet(cache, &subject, &issuer, 0, timeIn + i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
reinterpret_cast<uint8_t*>(serialBuf),
|
||||
4
|
||||
};
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial), 0, timeIn + i);
|
||||
}
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_TRUE(cache.Get(¬EvictedSubject, &issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(notEvicted, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == SEC_ERROR_REVOKED_CERTIFICATE && timeOut == timeIn);
|
||||
CERTCertificate evictedSubject;
|
||||
MakeFakeCert(&evictedSubject, "CN=subject0001", "CN=issuer1", "0001", "key000");
|
||||
ASSERT_FALSE(cache.Get(&evictedSubject, &issuer, errorOut, timeOut));
|
||||
|
||||
const SECItem fakeSerial0001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("0001")),
|
||||
4
|
||||
};
|
||||
CertID evicted(fakeIssuer1, fakeKey000, fakeSerial0001);
|
||||
ASSERT_FALSE(cache.Get(evicted, errorOut, timeOut));
|
||||
}
|
||||
|
||||
TEST_F(OCSPCacheTest, TestEverythingIsRevoked)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate issuer;
|
||||
MakeFakeCert(&issuer, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
PRTime timeIn = PR_Now();
|
||||
// Fill up the cache with revoked responses.
|
||||
for (int i = 0; i < MaxCacheEntries; i++) {
|
||||
CERTCertificate subject;
|
||||
char subjectBuf[64];
|
||||
PR_snprintf(subjectBuf, sizeof(subjectBuf), "CN=subject%04d", i);
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
MakeFakeCert(&subject, subjectBuf, "CN=issuer1", serialBuf, "key000");
|
||||
PutAndGet(cache, &subject, &issuer, SEC_ERROR_REVOKED_CERTIFICATE, timeIn + i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
reinterpret_cast<uint8_t*>(serialBuf),
|
||||
4
|
||||
};
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
|
||||
SEC_ERROR_REVOKED_CERTIFICATE, timeIn + i);
|
||||
}
|
||||
CERTCertificate goodSubject;
|
||||
MakeFakeCert(&goodSubject, "CN=subject1025", "CN=issuer1", "1025", "key000");
|
||||
const SECItem fakeSerial1025 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1025")),
|
||||
4
|
||||
};
|
||||
CertID good(fakeIssuer1, fakeKey000, fakeSerial1025);
|
||||
// This will "succeed", allowing verification to continue. However,
|
||||
// nothing was actually put in the cache.
|
||||
SECStatus result = cache.Put(&goodSubject, &issuer, 0, timeIn + 1025 - 50,
|
||||
timeIn + 1025);
|
||||
SECStatus result = cache.Put(good, 0, timeIn + 1025 - 50, timeIn + 1025);
|
||||
ASSERT_TRUE(result == SECSuccess);
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_FALSE(cache.Get(&goodSubject, &issuer, errorOut, timeOut));
|
||||
ASSERT_FALSE(cache.Get(good, errorOut, timeOut));
|
||||
|
||||
CERTCertificate revokedSubject;
|
||||
MakeFakeCert(&revokedSubject, "CN=subject1026", "CN=issuer1", "1026", "key000");
|
||||
const SECItem fakeSerial1026 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1026")),
|
||||
4
|
||||
};
|
||||
CertID revoked(fakeIssuer1, fakeKey000, fakeSerial1026);
|
||||
// This will fail, causing verification to fail.
|
||||
result = cache.Put(&revokedSubject, &issuer, SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
result = cache.Put(revoked, SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
timeIn + 1026 - 50, timeIn + 1026);
|
||||
PRErrorCode error = PR_GetError();
|
||||
ASSERT_TRUE(result == SECFailure);
|
||||
@ -209,75 +240,76 @@ TEST_F(OCSPCacheTest, TestEverythingIsRevoked)
|
||||
TEST_F(OCSPCacheTest, VariousIssuers)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate issuer1;
|
||||
MakeFakeCert(&issuer1, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
CERTCertificate issuer2;
|
||||
MakeFakeCert(&issuer2, "CN=issuer2", "CN=issuer2", "000", "key001");
|
||||
CERTCertificate issuer3;
|
||||
// Note: same CN as issuer1
|
||||
MakeFakeCert(&issuer3, "CN=issuer1", "CN=issuer3", "000", "key003");
|
||||
CERTCertificate subject;
|
||||
MakeFakeCert(&subject, "CN=subject", "CN=issuer1", "001", "key002");
|
||||
static const SECItem fakeIssuer2 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("CN=issuer2")),
|
||||
10
|
||||
};
|
||||
static const SECItem fakeSerial001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("001")),
|
||||
3
|
||||
};
|
||||
|
||||
PRTime timeIn = PR_Now();
|
||||
PutAndGet(cache, &subject, &issuer1, 0, timeIn);
|
||||
CertID subject(fakeIssuer1, fakeKey000, fakeSerial001);
|
||||
PutAndGet(cache, subject, 0, timeIn);
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer1, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(subject, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == 0 && timeOut == timeIn);
|
||||
ASSERT_FALSE(cache.Get(&subject, &issuer2, errorOut, timeOut));
|
||||
ASSERT_FALSE(cache.Get(&subject, &issuer3, errorOut, timeOut));
|
||||
// Test that we don't match a different issuer DN
|
||||
ASSERT_FALSE(cache.Get(CertID(fakeIssuer2, fakeKey000, fakeSerial001),
|
||||
errorOut, timeOut));
|
||||
// Test that we don't match a different issuer key
|
||||
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial001),
|
||||
errorOut, timeOut));
|
||||
}
|
||||
|
||||
TEST_F(OCSPCacheTest, Times)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate subject;
|
||||
MakeFakeCert(&subject, "CN=subject1", "CN=issuer1", "001", "key001");
|
||||
CERTCertificate issuer;
|
||||
MakeFakeCert(&issuer, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
PutAndGet(cache, &subject, &issuer, SEC_ERROR_OCSP_UNKNOWN_CERT, 100);
|
||||
PutAndGet(cache, &subject, &issuer, 0, 200);
|
||||
CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
|
||||
PutAndGet(cache, certID, SEC_ERROR_OCSP_UNKNOWN_CERT, 100);
|
||||
PutAndGet(cache, certID, 0, 200);
|
||||
// This should not override the more recent entry.
|
||||
SECStatus rv = cache.Put(&subject, &issuer, SEC_ERROR_OCSP_UNKNOWN_CERT, 100, 100);
|
||||
ASSERT_TRUE(rv == SECSuccess);
|
||||
ASSERT_EQ(SECSuccess, cache.Put(certID, SEC_ERROR_OCSP_UNKNOWN_CERT, 100,
|
||||
100));
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
|
||||
// Here we see the more recent time.
|
||||
ASSERT_TRUE(errorOut == 0 && timeOut == 200);
|
||||
|
||||
// SEC_ERROR_REVOKED_CERTIFICATE overrides everything
|
||||
PutAndGet(cache, &subject, &issuer, SEC_ERROR_REVOKED_CERTIFICATE, 50);
|
||||
PutAndGet(cache, certID, SEC_ERROR_REVOKED_CERTIFICATE, 50);
|
||||
}
|
||||
|
||||
TEST_F(OCSPCacheTest, NetworkFailure)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
CERTCertificate subject;
|
||||
MakeFakeCert(&subject, "CN=subject1", "CN=issuer1", "001", "key001");
|
||||
CERTCertificate issuer;
|
||||
MakeFakeCert(&issuer, "CN=issuer1", "CN=issuer1", "000", "key000");
|
||||
PutAndGet(cache, &subject, &issuer, PR_CONNECT_REFUSED_ERROR, 100);
|
||||
PutAndGet(cache, &subject, &issuer, 0, 200);
|
||||
CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
|
||||
PutAndGet(cache, certID, PR_CONNECT_REFUSED_ERROR, 100);
|
||||
PutAndGet(cache, certID, 0, 200);
|
||||
// This should not override the already present entry.
|
||||
SECStatus rv = cache.Put(&subject, &issuer, PR_CONNECT_REFUSED_ERROR, 300, 350);
|
||||
SECStatus rv = cache.Put(certID, PR_CONNECT_REFUSED_ERROR, 300, 350);
|
||||
ASSERT_TRUE(rv == SECSuccess);
|
||||
PRErrorCode errorOut;
|
||||
PRTime timeOut;
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == 0 && timeOut == 200);
|
||||
|
||||
PutAndGet(cache, &subject, &issuer, SEC_ERROR_OCSP_UNKNOWN_CERT, 400);
|
||||
PutAndGet(cache, certID, SEC_ERROR_OCSP_UNKNOWN_CERT, 400);
|
||||
// This should not override the already present entry.
|
||||
rv = cache.Put(&subject, &issuer, PR_CONNECT_REFUSED_ERROR, 500, 550);
|
||||
rv = cache.Put(certID, PR_CONNECT_REFUSED_ERROR, 500, 550);
|
||||
ASSERT_TRUE(rv == SECSuccess);
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == SEC_ERROR_OCSP_UNKNOWN_CERT && timeOut == 400);
|
||||
|
||||
PutAndGet(cache, &subject, &issuer, SEC_ERROR_REVOKED_CERTIFICATE, 600);
|
||||
PutAndGet(cache, certID, SEC_ERROR_REVOKED_CERTIFICATE, 600);
|
||||
// This should not override the already present entry.
|
||||
rv = cache.Put(&subject, &issuer, PR_CONNECT_REFUSED_ERROR, 700, 750);
|
||||
rv = cache.Put(certID, PR_CONNECT_REFUSED_ERROR, 700, 750);
|
||||
ASSERT_TRUE(rv == SECSuccess);
|
||||
ASSERT_TRUE(cache.Get(&subject, &issuer, errorOut, timeOut));
|
||||
ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
|
||||
ASSERT_TRUE(errorOut == SEC_ERROR_REVOKED_CERTIFICATE && timeOut == 600);
|
||||
}
|
||||
|
@ -6,16 +6,16 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pkixtestutil.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "TLSServer.h"
|
||||
#include "pkixtestutil.h"
|
||||
#include "secder.h"
|
||||
#include "secerr.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::test;
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
using namespace mozilla::test;
|
||||
|
||||
SECItemArray *
|
||||
GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert,
|
||||
@ -40,25 +40,26 @@ GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert,
|
||||
PRTime oneDay = 60*60*24 * (PRTime)PR_USEC_PER_SEC;
|
||||
PRTime oldNow = now - (8 * oneDay);
|
||||
|
||||
OCSPResponseContext context(aArena, aCert, now);
|
||||
mozilla::ScopedCERTCertificate cert(CERT_DupCertificate(aCert));
|
||||
|
||||
if (aORT == ORTGoodOtherCert) {
|
||||
context.cert = PK11_FindCertFromNickname(aAdditionalCertName, nullptr);
|
||||
if (!context.cert) {
|
||||
cert = PK11_FindCertFromNickname(aAdditionalCertName, nullptr);
|
||||
if (!cert) {
|
||||
PrintPRError("PK11_FindCertFromNickname failed");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// XXX CERT_FindCertIssuer uses the old, deprecated path-building logic
|
||||
ScopedCERTCertificate issuerCert(CERT_FindCertIssuer(aCert, now,
|
||||
certUsageSSLCA));
|
||||
mozilla::ScopedCERTCertificate
|
||||
issuerCert(CERT_FindCertIssuer(aCert, now, certUsageSSLCA));
|
||||
if (!issuerCert) {
|
||||
PrintPRError("CERT_FindCertIssuer failed");
|
||||
return nullptr;
|
||||
}
|
||||
context.issuerNameDER = &issuerCert->derSubject;
|
||||
context.issuerSPKI = &issuerCert->subjectPublicKeyInfo;
|
||||
ScopedCERTCertificate signerCert;
|
||||
CertID certID(cert->derIssuer, issuerCert->derPublicKey, cert->serialNumber);
|
||||
OCSPResponseContext context(aArena, certID, now);
|
||||
|
||||
mozilla::ScopedCERTCertificate signerCert;
|
||||
if (aORT == ORTGoodOtherCA || aORT == ORTDelegatedIncluded ||
|
||||
aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissing ||
|
||||
aORT == ORTDelegatedMissingMultiple) {
|
||||
@ -77,7 +78,7 @@ GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert,
|
||||
}
|
||||
if (aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissingMultiple) {
|
||||
certs[0] = &issuerCert->derCert;
|
||||
certs[1] = &context.cert->derCert;
|
||||
certs[1] = &cert->derCert;
|
||||
certs[2] = &issuerCert->derCert;
|
||||
if (aORT != ORTDelegatedMissingMultiple) {
|
||||
certs[3] = &signerCert->derCert;
|
||||
|
@ -105,9 +105,7 @@ SECStatus VerifySignedData(const CERTSignedData* sd,
|
||||
void* pkcs11PinArg);
|
||||
|
||||
// The return value, if non-null, is owned by the arena and MUST NOT be freed.
|
||||
SECItem* CreateEncodedOCSPRequest(PLArenaPool* arena,
|
||||
const CERTCertificate* cert,
|
||||
const CERTCertificate* issuerCert);
|
||||
SECItem* CreateEncodedOCSPRequest(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
|
||||
@ -121,14 +119,12 @@ SECItem* CreateEncodedOCSPRequest(PLArenaPool* arena,
|
||||
// which the encoded response is considered trustworthy (that is, if a response had a
|
||||
// thisUpdate time of validThrough, it would be considered trustworthy).
|
||||
SECStatus VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
|
||||
const CERTCertificate* cert,
|
||||
CERTCertificate* issuerCert,
|
||||
PRTime time,
|
||||
const CertID& certID, PRTime time,
|
||||
uint16_t maxLifetimeInDays,
|
||||
const SECItem* encodedResponse,
|
||||
const SECItem& encodedResponse,
|
||||
/* out */ bool& expired,
|
||||
/* optional out */ PRTime* thisUpdate,
|
||||
/* optional out */ PRTime* validThrough);
|
||||
/* optional out */ PRTime* thisUpdate = nullptr,
|
||||
/* optional out */ PRTime* validThrough = nullptr);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
|
@ -25,11 +25,11 @@
|
||||
#ifndef mozilla_pkix__pkixtypes_h
|
||||
#define mozilla_pkix__pkixtypes_h
|
||||
|
||||
#include "cert.h"
|
||||
#include "pkix/enumclass.h"
|
||||
#include "pkix/ScopedPtr.h"
|
||||
#include "plarena.h"
|
||||
#include "cert.h"
|
||||
#include "keyhi.h"
|
||||
#include "seccomon.h"
|
||||
#include "secport.h"
|
||||
#include "stdint.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
@ -88,6 +88,34 @@ MOZILLA_PKIX_ENUM_CLASS TrustLevel {
|
||||
InheritsTrust = 3 // certificate must chain to a trust anchor
|
||||
};
|
||||
|
||||
// CertID references the information needed to do revocation checking for the
|
||||
// certificate issued by the given issuer with the given serial number.
|
||||
//
|
||||
// issuer must be the DER-encoded issuer field from the certificate for which
|
||||
// revocation checking is being done, **NOT** the subject field of the issuer
|
||||
// certificate. (Those two fields must be equal to each other, but they may not
|
||||
// be encoded exactly the same, and the encoding matters for OCSP.)
|
||||
// issuerSubjectPublicKeyInfo is the entire DER-encoded subjectPublicKeyInfo
|
||||
// field from the issuer's certificate. serialNumber is the entire DER-encoded
|
||||
// serial number from the subject certificate (the certificate for which we are
|
||||
// checking the revocation status).
|
||||
struct CertID
|
||||
{
|
||||
public:
|
||||
CertID(const SECItem& issuer, const SECItem& issuerSubjectPublicKeyInfo,
|
||||
const SECItem& serialNumber)
|
||||
: issuer(issuer)
|
||||
, issuerSubjectPublicKeyInfo(issuerSubjectPublicKeyInfo)
|
||||
, serialNumber(serialNumber)
|
||||
{
|
||||
}
|
||||
const SECItem& issuer;
|
||||
const SECItem& issuerSubjectPublicKeyInfo;
|
||||
const SECItem& serialNumber;
|
||||
private:
|
||||
void operator=(const CertID&) /*= delete*/;
|
||||
};
|
||||
|
||||
// Applications control the behavior of path building and verification by
|
||||
// implementing the TrustDomain interface. The TrustDomain is used for all
|
||||
// cryptography and for determining which certificates are trusted or
|
||||
@ -136,10 +164,9 @@ public:
|
||||
// issuerCertToDup is only non-const so CERT_DupCertificate can be called on
|
||||
// it.
|
||||
virtual SECStatus CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
const CERTCertificate* cert,
|
||||
/*const*/ CERTCertificate* issuerCertToDup,
|
||||
PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPresponse) = 0;
|
||||
const CertID& certID, PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPresponse,
|
||||
/*optional*/ const SECItem* aiaExtension) = 0;
|
||||
|
||||
// Called as soon as we think we have a valid chain but before revocation
|
||||
// checks are done. Called to compute additional chain level checks, by the
|
||||
|
@ -69,7 +69,6 @@ BackCert::Init(const SECItem& certDER)
|
||||
|
||||
const SECItem* dummyEncodedSubjectKeyIdentifier = nullptr;
|
||||
const SECItem* dummyEncodedAuthorityKeyIdentifier = nullptr;
|
||||
const SECItem* dummyEncodedAuthorityInfoAccess = nullptr;
|
||||
const SECItem* dummyEncodedSubjectAltName = nullptr;
|
||||
|
||||
for (const CERTCertExtension* ext = *exts; ext; ext = *++exts) {
|
||||
@ -104,7 +103,7 @@ BackCert::Init(const SECItem& certDER)
|
||||
// We should remember the value of the encoded AIA extension here, but
|
||||
// since our TrustDomain implementations get the OCSP URI using
|
||||
// CERT_GetOCSPAuthorityInfoAccessLocation, we currently don't need to.
|
||||
out = &dummyEncodedAuthorityInfoAccess;
|
||||
out = &encodedAuthorityInfoAccess;
|
||||
}
|
||||
|
||||
// If this is an extension we don't understand and it's marked critical,
|
||||
@ -283,7 +282,7 @@ BuildForward(TrustDomain& trustDomain,
|
||||
// Find a trusted issuer.
|
||||
// TODO(bug 965136): Add SKI/AKI matching optimizations
|
||||
ScopedCERTCertList candidates;
|
||||
if (trustDomain.FindPotentialIssuers(&subject.GetNSSCert()->derIssuer, time,
|
||||
if (trustDomain.FindPotentialIssuers(&subject.GetIssuer(), time,
|
||||
candidates) != SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
@ -305,10 +304,12 @@ BuildForward(TrustDomain& trustDomain,
|
||||
return Fail(FatalError, deferredEndEntityError);
|
||||
}
|
||||
|
||||
SECStatus srv = trustDomain.CheckRevocation(endEntityOrCA,
|
||||
subject.GetNSSCert(),
|
||||
n->cert, time,
|
||||
stapledOCSPResponse);
|
||||
CertID certID(subject.GetIssuer(), n->cert->derPublicKey,
|
||||
subject.GetSerialNumber());
|
||||
SECStatus srv = trustDomain.CheckRevocation(
|
||||
endEntityOrCA, certID, time,
|
||||
stapledOCSPResponse,
|
||||
subject.encodedAuthorityInfoAccess);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
@ -22,13 +22,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "pkix/pkix.h"
|
||||
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cert.h"
|
||||
#include "cryptohi.h"
|
||||
#include "keyhi.h"
|
||||
#include "pkix/pkix.h"
|
||||
#include "prerror.h"
|
||||
#include "secerr.h"
|
||||
|
||||
|
@ -24,15 +24,13 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "hasht.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pkix/bind.h"
|
||||
#include "pkix/pkix.h"
|
||||
#include "pkixcheck.h"
|
||||
#include "pkixder.h"
|
||||
|
||||
#include "hasht.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secder.h"
|
||||
|
||||
// TODO: use typed/qualified typedefs everywhere?
|
||||
// TODO: When should we return SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE?
|
||||
|
||||
@ -52,18 +50,11 @@ MOZILLA_PKIX_ENUM_CLASS CertStatus : uint8_t {
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
Context(TrustDomain& trustDomain,
|
||||
const SECItem& certSerialNumber,
|
||||
const SECItem& issuerSubject,
|
||||
const SECItem& issuerSubjectPublicKeyInfo,
|
||||
PRTime time,
|
||||
uint16_t maxLifetimeInDays,
|
||||
PRTime* thisUpdate,
|
||||
PRTime* validThrough)
|
||||
Context(TrustDomain& trustDomain, const CertID& certID, PRTime time,
|
||||
uint16_t maxLifetimeInDays, /*optional out*/ PRTime* thisUpdate,
|
||||
/*optional out*/ PRTime* validThrough)
|
||||
: trustDomain(trustDomain)
|
||||
, certSerialNumber(certSerialNumber)
|
||||
, issuerSubject(issuerSubject)
|
||||
, issuerSubjectPublicKeyInfo(issuerSubjectPublicKeyInfo)
|
||||
, certID(certID)
|
||||
, time(time)
|
||||
, maxLifetimeInDays(maxLifetimeInDays)
|
||||
, certStatus(CertStatus::Unknown)
|
||||
@ -80,9 +71,7 @@ public:
|
||||
}
|
||||
|
||||
TrustDomain& trustDomain;
|
||||
const SECItem& certSerialNumber;
|
||||
const SECItem& issuerSubject;
|
||||
const SECItem& issuerSubjectPublicKeyInfo;
|
||||
const CertID& certID;
|
||||
const PRTime time;
|
||||
const uint16_t maxLifetimeInDays;
|
||||
CertStatus certStatus;
|
||||
@ -197,6 +186,9 @@ static inline der::Result CertID(der::Input& input,
|
||||
static Result MatchKeyHash(const SECItem& issuerKeyHash,
|
||||
const SECItem& issuerSubjectPublicKeyInfo,
|
||||
/*out*/ bool& match);
|
||||
static Result KeyHash(const SECItem& subjectPublicKeyInfo,
|
||||
/*out*/ uint8_t* hashBuf, size_t hashBufSize);
|
||||
|
||||
|
||||
static Result
|
||||
MatchResponderID(ResponderIDType responderIDType,
|
||||
@ -261,14 +253,15 @@ VerifySignature(Context& context, ResponderIDType responderIDType,
|
||||
{
|
||||
bool match;
|
||||
Result rv = MatchResponderID(responderIDType, responderID,
|
||||
context.issuerSubject,
|
||||
context.issuerSubjectPublicKeyInfo, match);
|
||||
context.certID.issuer,
|
||||
context.certID.issuerSubjectPublicKeyInfo,
|
||||
match);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (match) {
|
||||
return VerifyOCSPSignedData(context.trustDomain, signedResponseData,
|
||||
context.issuerSubjectPublicKeyInfo);
|
||||
context.certID.issuerSubjectPublicKeyInfo);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < numCerts; ++i) {
|
||||
@ -289,8 +282,8 @@ VerifySignature(Context& context, ResponderIDType responderIDType,
|
||||
|
||||
if (match) {
|
||||
rv = CheckOCSPResponseSignerCert(context.trustDomain, cert,
|
||||
context.issuerSubject,
|
||||
context.issuerSubjectPublicKeyInfo,
|
||||
context.certID.issuer,
|
||||
context.certID.issuerSubjectPublicKeyInfo,
|
||||
context.time);
|
||||
if (rv == FatalError) {
|
||||
return rv;
|
||||
@ -316,34 +309,22 @@ SetErrorToMalformedResponseOnBadDERError()
|
||||
}
|
||||
|
||||
SECStatus
|
||||
VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
|
||||
const CERTCertificate* cert,
|
||||
CERTCertificate* issuerCert, PRTime time,
|
||||
uint16_t maxOCSPLifetimeInDays,
|
||||
const SECItem* encodedResponse,
|
||||
VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
PRTime time, uint16_t maxOCSPLifetimeInDays,
|
||||
const SECItem& encodedResponse,
|
||||
bool& expired,
|
||||
PRTime* thisUpdate,
|
||||
PRTime* validThrough)
|
||||
/*optional out*/ PRTime* thisUpdate,
|
||||
/*optional out*/ PRTime* validThrough)
|
||||
{
|
||||
PR_ASSERT(cert);
|
||||
PR_ASSERT(issuerCert);
|
||||
// TODO: PR_Assert(pinArg)
|
||||
PR_ASSERT(encodedResponse);
|
||||
if (!cert || !issuerCert || !encodedResponse || !encodedResponse->data) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Always initialize this to something reasonable.
|
||||
expired = false;
|
||||
|
||||
der::Input input;
|
||||
if (input.Init(encodedResponse->data, encodedResponse->len) != der::Success) {
|
||||
if (input.Init(encodedResponse.data, encodedResponse.len) != der::Success) {
|
||||
SetErrorToMalformedResponseOnBadDERError();
|
||||
return SECFailure;
|
||||
}
|
||||
Context context(trustDomain, cert->serialNumber, issuerCert->derSubject,
|
||||
issuerCert->derPublicKey, time, maxOCSPLifetimeInDays,
|
||||
Context context(trustDomain, certID, time, maxOCSPLifetimeInDays,
|
||||
thisUpdate, validThrough);
|
||||
|
||||
if (der::Nested(input, der::SEQUENCE,
|
||||
@ -726,7 +707,7 @@ CertID(der::Input& input, const Context& context, /*out*/ bool& match)
|
||||
return der::Failure;
|
||||
}
|
||||
|
||||
if (!SECITEM_ItemsAreEqual(&serialNumber, &context.certSerialNumber)) {
|
||||
if (!SECITEM_ItemsAreEqual(&serialNumber, &context.certID.serialNumber)) {
|
||||
// This does not reference the certificate we're interested in.
|
||||
// Consume the rest of the input and return successfully to
|
||||
// potentially continue processing other responses.
|
||||
@ -751,7 +732,7 @@ CertID(der::Input& input, const Context& context, /*out*/ bool& match)
|
||||
// "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.issuerSubject, hashBuf, sizeof(hashBuf))
|
||||
if (HashBuf(context.certID.issuer, hashBuf, sizeof(hashBuf))
|
||||
!= der::Success) {
|
||||
return der::Failure;
|
||||
}
|
||||
@ -761,7 +742,7 @@ CertID(der::Input& input, const Context& context, /*out*/ bool& match)
|
||||
return der::Success;
|
||||
}
|
||||
|
||||
if (MatchKeyHash(issuerKeyHash, context.issuerSubjectPublicKeyInfo,
|
||||
if (MatchKeyHash(issuerKeyHash, context.certID.issuerSubjectPublicKeyInfo,
|
||||
match) != Success) {
|
||||
return der::Failure;
|
||||
}
|
||||
@ -786,8 +767,23 @@ MatchKeyHash(const SECItem& keyHash, const SECItem& subjectPublicKeyInfo,
|
||||
if (keyHash.len != SHA1_LENGTH) {
|
||||
return Fail(RecoverableError, SEC_ERROR_OCSP_MALFORMED_RESPONSE);
|
||||
}
|
||||
static uint8_t hashBuf[SHA1_LENGTH];
|
||||
Result rv = KeyHash(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
|
||||
// TODO(bug 966856): support SHA-2 hashes
|
||||
Result
|
||||
KeyHash(const SECItem& subjectPublicKeyInfo, /*out*/ uint8_t* hashBuf,
|
||||
size_t hashBufSize)
|
||||
{
|
||||
if (!hashBuf || hashBufSize != SHA1_LENGTH) {
|
||||
return Fail(FatalError, SEC_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
// RFC 5280 Section 4.1
|
||||
//
|
||||
@ -836,11 +832,9 @@ MatchKeyHash(const SECItem& keyHash, const SECItem& subjectPublicKeyInfo,
|
||||
++subjectPublicKey.data;
|
||||
--subjectPublicKey.len;
|
||||
|
||||
static uint8_t hashBuf[SHA1_LENGTH];
|
||||
if (HashBuf(subjectPublicKey, hashBuf, sizeof(hashBuf)) != der::Success) {
|
||||
if (HashBuf(subjectPublicKey, hashBuf, hashBufSize) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
match = !memcmp(hashBuf, keyHash.data, keyHash.len);
|
||||
return Success;
|
||||
}
|
||||
|
||||
@ -903,11 +897,9 @@ CheckExtensionsForCriticality(der::Input& input)
|
||||
// http://tools.ietf.org/html/rfc5019#section-4
|
||||
|
||||
SECItem*
|
||||
CreateEncodedOCSPRequest(PLArenaPool* arena,
|
||||
const CERTCertificate* cert,
|
||||
const CERTCertificate* issuerCert)
|
||||
CreateEncodedOCSPRequest(PLArenaPool* arena, const struct CertID& certID)
|
||||
{
|
||||
if (!arena || !cert || !issuerCert) {
|
||||
if (!arena) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return nullptr;
|
||||
}
|
||||
@ -952,13 +944,13 @@ CreateEncodedOCSPRequest(PLArenaPool* arena,
|
||||
// we allow for some amount of non-conformance with that requirement while
|
||||
// still ensuring we can encode the length values in the ASN.1 TLV structures
|
||||
// in a single byte.
|
||||
if (cert->serialNumber.len > 127u - totalLenWithoutSerialNumberData) {
|
||||
if (certID.serialNumber.len > 127u - totalLenWithoutSerialNumberData) {
|
||||
PR_SetError(SEC_ERROR_BAD_DATA, 0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t totalLen = static_cast<uint8_t>(totalLenWithoutSerialNumberData +
|
||||
cert->serialNumber.len);
|
||||
certID.serialNumber.len);
|
||||
|
||||
SECItem* encodedRequest = SECITEM_AllocItem(arena, nullptr, totalLen);
|
||||
if (!encodedRequest) {
|
||||
@ -980,7 +972,7 @@ CreateEncodedOCSPRequest(PLArenaPool* arena,
|
||||
// reqCert.issuerNameHash (OCTET STRING)
|
||||
*d++ = 0x04;
|
||||
*d++ = hashLen;
|
||||
if (HashBuf(issuerCert->derSubject, d, hashLen) != der::Success) {
|
||||
if (HashBuf(certID.issuer, d, hashLen) != der::Success) {
|
||||
return nullptr;
|
||||
}
|
||||
d += hashLen;
|
||||
@ -988,18 +980,16 @@ CreateEncodedOCSPRequest(PLArenaPool* arena,
|
||||
// reqCert.issuerKeyHash (OCTET STRING)
|
||||
*d++ = 0x04;
|
||||
*d++ = hashLen;
|
||||
SECItem key = issuerCert->subjectPublicKeyInfo.subjectPublicKey;
|
||||
DER_ConvertBitString(&key);
|
||||
if (HashBuf(key, d, hashLen) != der::Success) {
|
||||
if (KeyHash(certID.issuerSubjectPublicKeyInfo, d, hashLen) != Success) {
|
||||
return nullptr;
|
||||
}
|
||||
d += hashLen;
|
||||
|
||||
// reqCert.serialNumber (INTEGER)
|
||||
*d++ = 0x02; // INTEGER
|
||||
*d++ = static_cast<uint8_t>(cert->serialNumber.len);
|
||||
for (size_t i = 0; i < cert->serialNumber.len; ++i) {
|
||||
*d++ = cert->serialNumber.data[i];
|
||||
*d++ = static_cast<uint8_t>(certID.serialNumber.len);
|
||||
for (size_t i = 0; i < certID.serialNumber.len; ++i) {
|
||||
*d++ = certID.serialNumber.data[i];
|
||||
}
|
||||
|
||||
PR_ASSERT(d == encodedRequest->data + totalLen);
|
||||
|
@ -96,7 +96,8 @@ public:
|
||||
|
||||
// nssCert and childCert must be valid for the lifetime of BackCert
|
||||
BackCert(BackCert* childCert, IncludeCN includeCN)
|
||||
: encodedBasicConstraints(nullptr)
|
||||
: encodedAuthorityInfoAccess(nullptr)
|
||||
, encodedBasicConstraints(nullptr)
|
||||
, encodedCertificatePolicies(nullptr)
|
||||
, encodedExtendedKeyUsage(nullptr)
|
||||
, encodedKeyUsage(nullptr)
|
||||
@ -112,6 +113,7 @@ public:
|
||||
|
||||
const SECItem& GetDER() const { return nssCert->derCert; }
|
||||
const SECItem& GetIssuer() const { return nssCert->derIssuer; }
|
||||
const SECItem& GetSerialNumber() const { return nssCert->serialNumber; }
|
||||
const SECItem& GetSubject() const { return nssCert->derSubject; }
|
||||
const SECItem& GetSubjectPublicKeyInfo() const
|
||||
{
|
||||
@ -121,6 +123,7 @@ public:
|
||||
Result VerifyOwnSignatureWithKey(TrustDomain& trustDomain,
|
||||
const SECItem& subjectPublicKeyInfo) const;
|
||||
|
||||
const SECItem* encodedAuthorityInfoAccess;
|
||||
const SECItem* encodedBasicConstraints;
|
||||
const SECItem* encodedCertificatePolicies;
|
||||
const SECItem* encodedExtendedKeyUsage;
|
||||
|
@ -142,8 +142,8 @@ private:
|
||||
nullptr);
|
||||
}
|
||||
|
||||
SECStatus CheckRevocation(EndEntityOrCA, const CERTCertificate*,
|
||||
/*const*/ CERTCertificate*, PRTime,
|
||||
SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
|
||||
/*optional*/ const SECItem*,
|
||||
/*optional*/ const SECItem*)
|
||||
{
|
||||
return SECSuccess;
|
||||
|
@ -95,8 +95,8 @@ private:
|
||||
nullptr);
|
||||
}
|
||||
|
||||
SECStatus CheckRevocation(EndEntityOrCA, const CERTCertificate*,
|
||||
/*const*/ CERTCertificate*, PRTime,
|
||||
SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
|
||||
/*optional*/ const SECItem*,
|
||||
/*optional*/ const SECItem*)
|
||||
{
|
||||
return SECSuccess;
|
||||
|
@ -36,7 +36,6 @@ class pkix_ocsp_request_tests : public NSSTest
|
||||
protected:
|
||||
// These SECItems are allocated in arena, and so will be auto-cleaned.
|
||||
SECItem* unsupportedLongSerialNumber;
|
||||
SECItem* shortSerialNumber;
|
||||
SECItem* longestRequiredSerialNumber;
|
||||
|
||||
void SetUp()
|
||||
@ -54,12 +53,6 @@ protected:
|
||||
unsupportedLongSerialNumber->data[2] = UNSUPPORTED_LEN;
|
||||
unsupportedLongSerialNumber->data[3] = 0x01; // value is 0x010000...00
|
||||
|
||||
// Each of tag, length, and value here are 1 byte: the total length is 3.
|
||||
shortSerialNumber = SECITEM_AllocItem(arena.get(), nullptr, 3);
|
||||
shortSerialNumber->data[0] = der::INTEGER;
|
||||
shortSerialNumber->data[1] = 0x01; // length of value is 1
|
||||
shortSerialNumber->data[2] = 0x01; // value is 1
|
||||
|
||||
static const uint8_t LONGEST_REQUIRED_LEN = 20;
|
||||
// tag + length + value is 1 + 1 + LONGEST_REQUIRED_LEN
|
||||
longestRequiredSerialNumber = SECITEM_AllocItem(arena.get(), nullptr,
|
||||
@ -71,74 +64,41 @@ protected:
|
||||
longestRequiredSerialNumber->data[2] = 0x01; // value is 0x010000...00
|
||||
}
|
||||
|
||||
void MakeTwoCerts(const char* issuerCN, SECItem* issuerSerial,
|
||||
/*out*/ ScopedCERTCertificate& issuer,
|
||||
const char* childCN, SECItem* childSerial,
|
||||
/*out*/ ScopedCERTCertificate& child)
|
||||
// The resultant issuerDER is owned by the arena.
|
||||
SECStatus MakeIssuerCertIDComponents(const char* issuerASCII,
|
||||
/*out*/ const SECItem*& issuerDER,
|
||||
/*out*/ ScopedSECItem& issuerSPKI)
|
||||
{
|
||||
const SECItem* issuerNameDer = ASCIIToDERName(arena.get(), issuerCN);
|
||||
ASSERT_TRUE(issuerNameDer);
|
||||
ScopedSECKEYPrivateKey issuerKey;
|
||||
SECItem* issuerCertDer(CreateEncodedCertificate(arena.get(), v3,
|
||||
SEC_OID_SHA256, issuerSerial, issuerNameDer,
|
||||
oneDayBeforeNow, oneDayAfterNow, issuerNameDer,
|
||||
nullptr, nullptr, SEC_OID_SHA256, issuerKey));
|
||||
ASSERT_TRUE(issuerCertDer);
|
||||
const SECItem* childNameDer = ASCIIToDERName(arena.get(), childCN);
|
||||
ASSERT_TRUE(childNameDer);
|
||||
ScopedSECKEYPrivateKey childKey;
|
||||
SECItem* childDer(CreateEncodedCertificate(arena.get(), v3,
|
||||
SEC_OID_SHA256, childSerial, issuerNameDer,
|
||||
oneDayBeforeNow, oneDayAfterNow, childNameDer, nullptr,
|
||||
issuerKey.get(), SEC_OID_SHA256, childKey));
|
||||
ASSERT_TRUE(childDer);
|
||||
issuer = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), issuerCertDer,
|
||||
nullptr, false, true);
|
||||
ASSERT_TRUE(issuer);
|
||||
child = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), childDer, nullptr,
|
||||
false, true);
|
||||
ASSERT_TRUE(child);
|
||||
issuerDER = ASCIIToDERName(arena.get(), issuerASCII);
|
||||
if (!issuerDER) {
|
||||
return SECFailure;
|
||||
}
|
||||
ScopedSECKEYPublicKey issuerPublicKey;
|
||||
ScopedSECKEYPrivateKey issuerPrivateKey;
|
||||
if (GenerateKeyPair(issuerPublicKey, issuerPrivateKey) != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
issuerSPKI = SECKEY_EncodeDERSubjectPublicKeyInfo(issuerPublicKey.get());
|
||||
if (!issuerSPKI) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Test that the large length of the issuer serial number doesn't cause
|
||||
// CreateEncodedOCSPRequest to fail when called for the child certificate.
|
||||
TEST_F(pkix_ocsp_request_tests, IssuerCertLongSerialNumberTest)
|
||||
{
|
||||
const char* issuerCN = "CN=Long Serial Number CA";
|
||||
const char* childCN = "CN=Short Serial Number EE";
|
||||
ScopedCERTCertificate issuer;
|
||||
ScopedCERTCertificate child;
|
||||
{
|
||||
SCOPED_TRACE("IssuerCertLongSerialNumberTest");
|
||||
MakeTwoCerts(issuerCN, unsupportedLongSerialNumber, issuer,
|
||||
childCN, shortSerialNumber, child);
|
||||
}
|
||||
ASSERT_TRUE(issuer);
|
||||
ASSERT_TRUE(child);
|
||||
ASSERT_TRUE(CreateEncodedOCSPRequest(arena.get(), child.get(),
|
||||
issuer.get()));
|
||||
ASSERT_EQ(0, PR_GetError());
|
||||
}
|
||||
|
||||
// Test that the large length of the child serial number causes
|
||||
// CreateEncodedOCSPRequest to fail.
|
||||
TEST_F(pkix_ocsp_request_tests, ChildCertLongSerialNumberTest)
|
||||
{
|
||||
const char* issuerCN = "CN=Short Serial Number CA";
|
||||
const char* childCN = "CN=Long Serial Number EE";
|
||||
ScopedCERTCertificate issuer;
|
||||
ScopedCERTCertificate child;
|
||||
{
|
||||
SCOPED_TRACE("ChildCertLongSerialNumberTest");
|
||||
MakeTwoCerts(issuerCN, shortSerialNumber, issuer,
|
||||
childCN, unsupportedLongSerialNumber, child);
|
||||
}
|
||||
ASSERT_TRUE(issuer);
|
||||
ASSERT_TRUE(child);
|
||||
ASSERT_FALSE(CreateEncodedOCSPRequest(arena.get(), child.get(),
|
||||
issuer.get()));
|
||||
const SECItem* issuerDER;
|
||||
ScopedSECItem issuerSPKI;
|
||||
ASSERT_EQ(SECSuccess,
|
||||
MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
|
||||
ASSERT_FALSE(CreateEncodedOCSPRequest(arena.get(),
|
||||
CertID(*issuerDER, *issuerSPKI,
|
||||
*unsupportedLongSerialNumber)));
|
||||
ASSERT_EQ(SEC_ERROR_BAD_DATA, PR_GetError());
|
||||
}
|
||||
|
||||
@ -146,18 +106,11 @@ TEST_F(pkix_ocsp_request_tests, ChildCertLongSerialNumberTest)
|
||||
// it's required to support (i.e. 20 octets).
|
||||
TEST_F(pkix_ocsp_request_tests, LongestSupportedSerialNumberTest)
|
||||
{
|
||||
const char* issuerCN = "CN=Short Serial Number CA";
|
||||
const char* childCN = "CN=Longest Serial Number Supported EE";
|
||||
ScopedCERTCertificate issuer;
|
||||
ScopedCERTCertificate child;
|
||||
{
|
||||
SCOPED_TRACE("LongestSupportedSerialNumberTest");
|
||||
MakeTwoCerts(issuerCN, shortSerialNumber, issuer,
|
||||
childCN, longestRequiredSerialNumber, child);
|
||||
}
|
||||
ASSERT_TRUE(issuer);
|
||||
ASSERT_TRUE(child);
|
||||
ASSERT_TRUE(CreateEncodedOCSPRequest(arena.get(), child.get(),
|
||||
issuer.get()));
|
||||
ASSERT_EQ(0, PR_GetError());
|
||||
const SECItem* issuerDER;
|
||||
ScopedSECItem issuerSPKI;
|
||||
ASSERT_EQ(SECSuccess,
|
||||
MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
|
||||
ASSERT_TRUE(CreateEncodedOCSPRequest(arena.get(),
|
||||
CertID(*issuerDER, *issuerSPKI,
|
||||
*longestRequiredSerialNumber)));
|
||||
}
|
||||
|
@ -178,14 +178,11 @@ private:
|
||||
};
|
||||
|
||||
OCSPResponseContext::OCSPResponseContext(PLArenaPool* arena,
|
||||
CERTCertificate* cert,
|
||||
PRTime time)
|
||||
const CertID& certID, PRTime time)
|
||||
: arena(arena)
|
||||
, cert(CERT_DupCertificate(cert))
|
||||
, certID(certID)
|
||||
, responseStatus(successful)
|
||||
, skipResponseBytes(false)
|
||||
, issuerNameDER(nullptr)
|
||||
, issuerSPKI(nullptr)
|
||||
, signerNameDER(nullptr)
|
||||
, producedAt(time)
|
||||
, extensions(nullptr)
|
||||
@ -243,7 +240,7 @@ HashAlgorithmToLength(SECOidTag hashAlg)
|
||||
}
|
||||
|
||||
static SECItem*
|
||||
HashedOctetString(PLArenaPool* arena, const SECItem* bytes, SECOidTag hashAlg)
|
||||
HashedOctetString(PLArenaPool* arena, const SECItem& bytes, SECOidTag hashAlg)
|
||||
{
|
||||
size_t hashLen = HashAlgorithmToLength(hashAlg);
|
||||
if (hashLen == 0) {
|
||||
@ -253,7 +250,7 @@ HashedOctetString(PLArenaPool* arena, const SECItem* bytes, SECOidTag hashAlg)
|
||||
if (!hashBuf) {
|
||||
return nullptr;
|
||||
}
|
||||
if (PK11_HashBuf(hashAlg, hashBuf->data, bytes->data, bytes->len)
|
||||
if (PK11_HashBuf(hashAlg, hashBuf->data, bytes.data, bytes.len)
|
||||
!= SECSuccess) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -267,7 +264,7 @@ KeyHashHelper(PLArenaPool* arena, const CERTSubjectPublicKeyInfo* spki)
|
||||
// We only need a shallow copy here.
|
||||
SECItem spk = spki->subjectPublicKey;
|
||||
DER_ConvertBitString(&spk); // bits to bytes
|
||||
return HashedOctetString(arena, &spk, SEC_OID_SHA1);
|
||||
return HashedOctetString(arena, spk, SEC_OID_SHA1);
|
||||
}
|
||||
|
||||
static SECItem*
|
||||
@ -919,8 +916,7 @@ CreateEncodedOCSPResponse(OCSPResponseContext& context)
|
||||
}
|
||||
|
||||
if (!context.skipResponseBytes) {
|
||||
if (!context.cert || !context.issuerNameDER || !context.issuerSPKI ||
|
||||
!context.signerPrivateKey) {
|
||||
if (!context.signerPrivateKey) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return nullptr;
|
||||
}
|
||||
@ -1260,21 +1256,29 @@ CertID(OCSPResponseContext& context)
|
||||
return nullptr;
|
||||
}
|
||||
SECItem* issuerNameHash = HashedOctetString(context.arena,
|
||||
context.issuerNameDER,
|
||||
context.certID.issuer,
|
||||
context.certIDHashAlg);
|
||||
if (!issuerNameHash) {
|
||||
return nullptr;
|
||||
}
|
||||
SECItem* issuerKeyHash = KeyHashHelper(context.arena, context.issuerSPKI);
|
||||
|
||||
ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
|
||||
spki(SECKEY_DecodeDERSubjectPublicKeyInfo(
|
||||
&context.certID.issuerSubjectPublicKeyInfo));
|
||||
if (!spki) {
|
||||
return nullptr;
|
||||
}
|
||||
SECItem* issuerKeyHash(KeyHashHelper(context.arena, spki.get()));
|
||||
if (!issuerKeyHash) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const SEC_ASN1Template serialTemplate[] = {
|
||||
{ SEC_ASN1_INTEGER, offsetof(CERTCertificate, serialNumber) },
|
||||
{ SEC_ASN1_INTEGER, 0 },
|
||||
{ 0 }
|
||||
};
|
||||
SECItem* serialNumber = SEC_ASN1EncodeItem(context.arena, nullptr,
|
||||
context.cert.get(),
|
||||
&context.certID.serialNumber,
|
||||
serialTemplate);
|
||||
if (!serialNumber) {
|
||||
return nullptr;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "keyhi.h"
|
||||
#include "pkix/enumclass.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "pkix/ScopedPtr.h"
|
||||
@ -128,11 +129,11 @@ public:
|
||||
class OCSPResponseContext
|
||||
{
|
||||
public:
|
||||
OCSPResponseContext(PLArenaPool* arena, CERTCertificate* cert, PRTime time);
|
||||
OCSPResponseContext(PLArenaPool* arena, const CertID& certID, PRTime time);
|
||||
|
||||
PLArenaPool* arena;
|
||||
const CertID& certID;
|
||||
// TODO(bug 980538): add a way to specify what certificates are included.
|
||||
pkix::ScopedCERTCertificate cert; // The subject of the OCSP response
|
||||
|
||||
// The fields below are in the order that they appear in an OCSP response.
|
||||
|
||||
@ -160,8 +161,6 @@ public:
|
||||
bool skipResponseBytes; // If true, don't include responseBytes
|
||||
|
||||
// responderID
|
||||
const SECItem* issuerNameDER; // non-owning
|
||||
const CERTSubjectPublicKeyInfo* issuerSPKI; // non-owning pointer
|
||||
const SECItem* signerNameDER; // If set, responderID will use the byName
|
||||
// form; otherwise responderID will use the
|
||||
// byKeyHash form.
|
||||
|
Loading…
x
Reference in New Issue
Block a user