From 553254501f35f7c231a0aeb6450abf08f4b17cea Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Fri, 30 May 2014 16:12:36 -0700 Subject: [PATCH] Bug 991815 - Part 1/2 - Allow intermediate OCSP responses up to 1 year old. r=keeler --HG-- extra : rebase_source : 28d5336da1dc44932b92ce2c59fca5fcb2b8a3d8 --- security/certverifier/NSSCertDBTrustDomain.cpp | 18 +++++++++++++++--- security/certverifier/NSSCertDBTrustDomain.h | 3 ++- security/pkix/include/pkix/pkix.h | 1 + security/pkix/lib/pkixocsp.cpp | 18 ++++++++++-------- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 911cc04adf1..23dd1dc8136 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -185,6 +185,15 @@ NSSCertDBTrustDomain::CheckRevocation( 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 + // old. + uint16_t maxOCSPLifetimeInDays = 10; + if (endEntityOrCA == EndEntityOrCA::MustBeCA) { + maxOCSPLifetimeInDays = 365; + } + // If we have a stapled OCSP response then the verification of that response // determines the result unless the OCSP response is expired. We make an // exception for expired responses because some servers, nginx in particular, @@ -193,6 +202,7 @@ NSSCertDBTrustDomain::CheckRevocation( PR_ASSERT(endEntityOrCA == EndEntityOrCA::MustBeEndEntity); SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(cert, issuerCert, time, + maxOCSPLifetimeInDays, stapledOCSPResponse, ResponseWasStapled); if (rv == SECSuccess) { @@ -376,6 +386,7 @@ NSSCertDBTrustDomain::CheckRevocation( } SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(cert, issuerCert, time, + maxOCSPLifetimeInDays, response, ResponseIsFromNetwork); if (rv == SECSuccess || mOCSPFetching != FetchOCSPForDVSoftFail) { @@ -399,13 +410,14 @@ NSSCertDBTrustDomain::CheckRevocation( SECStatus NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse( const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time, - const SECItem* encodedResponse, EncodedResponseSource responseSource) + uint16_t maxLifetimeInDays, const SECItem* encodedResponse, + EncodedResponseSource responseSource) { PRTime thisUpdate = 0; PRTime validThrough = 0; SECStatus rv = VerifyEncodedOCSPResponse(*this, cert, issuerCert, time, - encodedResponse, &thisUpdate, - &validThrough); + maxLifetimeInDays, encodedResponse, + &thisUpdate, &validThrough); PRErrorCode error = (rv == SECSuccess ? 0 : PR_GetError()); // validThrough is only trustworthy if the response successfully verifies // or it indicates a revoked or unknown certificate. diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index 1438f5ce051..e2f9ea9c01a 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -90,7 +90,8 @@ private: static const PRTime ServerFailureDelay = 5 * 60 * PR_USEC_PER_SEC; SECStatus VerifyAndMaybeCacheEncodedOCSPResponse( const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time, - const SECItem* encodedResponse, EncodedResponseSource responseSource); + uint16_t maxLifetimeInDays, const SECItem* encodedResponse, + EncodedResponseSource responseSource); const SECTrustType mCertDBTrustType; const OCSPFetching mOCSPFetching; diff --git a/security/pkix/include/pkix/pkix.h b/security/pkix/include/pkix/pkix.h index 264af02cb2c..1d7dce5c030 100644 --- a/security/pkix/include/pkix/pkix.h +++ b/security/pkix/include/pkix/pkix.h @@ -121,6 +121,7 @@ SECStatus VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time, + uint16_t maxLifetimeInDays, const SECItem* encodedResponse, /* optional out */ PRTime* thisUpdate, /* optional out */ PRTime* validThrough); diff --git a/security/pkix/lib/pkixocsp.cpp b/security/pkix/lib/pkixocsp.cpp index 4540f89ba54..a7a003c736e 100644 --- a/security/pkix/lib/pkixocsp.cpp +++ b/security/pkix/lib/pkixocsp.cpp @@ -56,12 +56,14 @@ public: const CERTCertificate& cert, CERTCertificate& issuerCert, PRTime time, + uint16_t maxLifetimeInDays, PRTime* thisUpdate, PRTime* validThrough) : trustDomain(trustDomain) , cert(cert) , issuerCert(issuerCert) , time(time) + , maxLifetimeInDays(maxLifetimeInDays) , certStatus(CertStatus::Unknown) , thisUpdate(thisUpdate) , validThrough(validThrough) @@ -78,6 +80,7 @@ public: const CERTCertificate& cert; CERTCertificate& issuerCert; const PRTime time; + const uint16_t maxLifetimeInDays; CertStatus certStatus; PRTime* thisUpdate; PRTime* validThrough; @@ -337,6 +340,7 @@ SECStatus VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time, + uint16_t maxOCSPLifetimeInDays, const SECItem* encodedResponse, PRTime* thisUpdate, PRTime* validThrough) @@ -355,9 +359,8 @@ VerifyEncodedOCSPResponse(TrustDomain& trustDomain, SetErrorToMalformedResponseOnBadDERError(); return SECFailure; } - - Context context(trustDomain, *cert, *issuerCert, time, thisUpdate, - validThrough); + Context context(trustDomain, *cert, *issuerCert, time, maxOCSPLifetimeInDays, + thisUpdate, validThrough); if (der::Nested(input, der::SEQUENCE, bind(OCSPResponse, _1, ref(context))) != der::Success) { @@ -672,9 +675,8 @@ SingleResponse(der::Input& input, Context& context) // be available about the status of the certificate (nextUpdate) is // greater than the current time. - // We won't accept any OCSP responses that are more than 10 days old, even if - // the nextUpdate time is further in the future. - static const PRTime OLDEST_ACCEPTABLE = INT64_C(10) * ONE_DAY; + const PRTime maxLifetime = + context.maxLifetimeInDays * ONE_DAY; PRTime thisUpdate; if (der::GeneralizedTime(input, thisUpdate) != der::Success) { @@ -699,10 +701,10 @@ SingleResponse(der::Input& input, Context& context) if (nextUpdate < thisUpdate) { return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE); } - if (nextUpdate - thisUpdate <= OLDEST_ACCEPTABLE) { + if (nextUpdate - thisUpdate <= maxLifetime) { notAfter = nextUpdate; } else { - notAfter = thisUpdate + OLDEST_ACCEPTABLE; + notAfter = thisUpdate + maxLifetime; } } else { // NSS requires all OCSP responses without a nextUpdate to be recent.