--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -174,34 +174,24 @@ NSSCertDBTrustDomain::CheckRevocation(
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
- // 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,
// are known to serve expired responses due to bugs.
if (stapledOCSPResponse) {
PR_ASSERT(endEntityOrCA == MustBeEndEntity);
SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(cert, issuerCert,
time,
- maxOCSPLifetimeInDays,
stapledOCSPResponse,
ResponseWasStapled);
if (rv == SECSuccess) {
// stapled OCSP response present and good
Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 1);
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: stapled OCSP response: good"));
return rv;
@@ -373,17 +363,16 @@ NSSCertDBTrustDomain::CheckRevocation(
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning SECSuccess after "
"OCSP request failure"));
return SECSuccess; // Soft fail -> success :(
}
SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(cert, issuerCert, time,
- maxOCSPLifetimeInDays,
response,
ResponseIsFromNetwork);
if (rv == SECSuccess || mOCSPFetching != FetchOCSPForDVSoftFail) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning after VerifyEncodedOCSPResponse"));
return rv;
}
@@ -397,24 +386,23 @@ NSSCertDBTrustDomain::CheckRevocation(
("NSSCertDBTrustDomain: end of CheckRevocation"));
return SECSuccess;
}
SECStatus
NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time,
- uint16_t maxLifetimeInDays, const SECItem* encodedResponse,
- EncodedResponseSource responseSource)
+ const SECItem* encodedResponse, EncodedResponseSource responseSource)
{
PRTime thisUpdate = 0;
PRTime validThrough = 0;
SECStatus rv = VerifyEncodedOCSPResponse(*this, cert, issuerCert, time,
- maxLifetimeInDays, encodedResponse,
- &thisUpdate, &validThrough);
+ 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.
// If this isn't the case, store an indication of failure (to prevent
// repeatedly requesting a response from a failing server).
if (rv != SECSuccess && error != SEC_ERROR_REVOKED_CERTIFICATE &&
error != SEC_ERROR_OCSP_UNKNOWN_CERT) {
validThrough = time + ServerFailureDelay;
--- a/security/certverifier/NSSCertDBTrustDomain.h
+++ b/security/certverifier/NSSCertDBTrustDomain.h
@@ -81,18 +81,17 @@ public:
private:
enum EncodedResponseSource {
ResponseIsFromNetwork = 1,
ResponseWasStapled = 2
};
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,
- EncodedResponseSource responseSource);
+ const SECItem* encodedResponse, EncodedResponseSource responseSource);
const SECTrustType mCertDBTrustType;
const OCSPFetching mOCSPFetching;
OCSPCache& mOCSPCache; // non-owning!
void* mPinArg; // non-owning!
};
} } // namespace mozilla::psm
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -428,58 +428,42 @@ function getFailingHttpServer(serverPort
// will cause a test failure
// nssDBlocaion is the location of the NSS database from where the OCSP
// responses will be generated (assumes appropiate keys are present)
// expectedCertNames is an array of nicks of the certs to be responsed
// expectedBasePaths is an optional array that is used to indicate
// what is the expected base path of the OCSP request.
function startOCSPResponder(serverPort, identity, invalidIdentities,
nssDBLocation, expectedCertNames,
- expectedBasePaths, expectedMethods,
- expectedResponseTypes) {
+ expectedBasePaths) {
let httpServer = new HttpServer();
httpServer.registerPrefixHandler("/",
function handleServerCallback(aRequest, aResponse) {
invalidIdentities.forEach(function(identity) {
do_check_neq(aRequest.host, identity)
});
- do_print("got request for: " + aRequest.path);
let basePath = aRequest.path.slice(1).split("/")[0];
if (expectedBasePaths.length >= 1) {
do_check_eq(basePath, expectedBasePaths.shift());
}
do_check_true(expectedCertNames.length >= 1);
- if (expectedMethods && expectedMethods.length >= 1) {
- do_check_eq(aRequest.method, expectedMethods.shift());
- }
- let responseType = "good";
- if (expectedResponseTypes && expectedResponseTypes.length >= 1) {
- responseType = expectedResponseTypes.shift();
- }
- do_check_true(expectedCertNames.length >= 1);
let expectedNick = expectedCertNames.shift();
- do_print("Generating ocsp response(" + responseType + ") for '" +
- expectedNick + "(" + basePath + ")'");
+ do_print("Generating ocsp response for '" + expectedNick + "(" +
+ basePath + ")'");
aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
aResponse.setHeader("Content-Type", "application/ocsp-response");
- let args = [ [responseType, expectedNick, "unused" ] ];
+ let args = [ ["good", expectedNick, "unused" ] ];
let retArray = generateOCSPResponses(args, nssDBLocation);
let responseBody = retArray[0];
aResponse.bodyOutputStream.write(responseBody, responseBody.length);
});
httpServer.identity.setPrimary("http", identity, serverPort);
invalidIdentities.forEach(function(identity) {
httpServer.identity.add("http", identity, serverPort);
});
httpServer.start(serverPort);
return {
stop: function(callback) {
do_check_eq(expectedCertNames.length, 0);
- if (expectedBasePaths) {
- do_check_eq(expectedBasePaths.length, 0);
- }
- if (expectedResponseTypes) {
- do_check_eq(expectedResponseTypes.length, 0);
- }
httpServer.stop(callback);
}
};
}
--- a/security/manager/ssl/tests/unit/test_ev_certs.js
+++ b/security/manager/ssl/tests/unit/test_ev_certs.js
@@ -205,75 +205,16 @@ function add_tests_in_mode(useMozillaPKI
do_check_eq(error,
isDebugBuild ? 0
: (useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED
: SEC_ERROR_EXTENSION_NOT_FOUND));
failingOcspResponder.stop(run_next_test);
});
});
- // Bug 991815 old but valid intermediates are OK
- add_test(function () {
- clearOCSPCache();
- let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [],
- "test_ev_certs",
- isDebugBuild ? ["int-ev-valid", "ev-valid"]
- : ["ev-valid"],
- [], [],
- isDebugBuild ? ["longvalidityalmostold", "good"]
- : ["good"]);
- check_ee_for_ev("ev-valid", isDebugBuild);
- ocspResponder.stop(run_next_test);
- });
-
- // Bug 991815 old but valid end-entities are NOT OK for EV
- // Unfortunatelly because of soft-fail we consider these OK for DV
- // libpkix does not enforce the age restriction and thus EV is valid
- add_test(function () {
- clearOCSPCache();
- // Since Mozilla::pkix does not consider the old amost invalid OCSP
- // response valid, it does not cache the old response and thus
- // makes a separate request for DV
- let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"];
- let debugResponseArray = ["good", "longvalidityalmostold",
- "longvalidityalmostold"];
- if (!useMozillaPKIX) {
- debugCertNickArray = ["int-ev-valid", "ev-valid"];
- debugResponseArray = ["good", "longvalidityalmostold"];
- }
- let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [],
- "test_ev_certs",
- isDebugBuild ? debugCertNickArray : ["ev-valid"],
- [], [],
- isDebugBuild ? debugResponseArray
- : ["longvalidityalmostold"]);
- check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild);
- ocspResponder.stop(run_next_test);
- });
-
- // Bug 991815 Valid but Ancient (almost two year old) responses are Not OK for
- // EV (still OK for soft fail DV)
- add_test(function () {
- clearOCSPCache();
- let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"];
- let debugResponseArray = ["good", "ancientstillvalid",
- "ancientstillvalid"];
- if (!useMozillaPKIX) {
- debugCertNickArray = ["int-ev-valid", "ev-valid"];
- debugResponseArray = ["good", "ancientstillvalid"];
- }
- let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [],
- "test_ev_certs",
- isDebugBuild ? debugCertNickArray : ["ev-valid"],
- [], [],
- isDebugBuild ? debugResponseArray
- : ["ancientstillvalid"]);
- check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild);
- ocspResponder.stop(run_next_test);
- });
}
// bug 950240: add FLAG_MUST_BE_EV to CertVerifier::VerifyCert
// to prevent spurious OCSP requests that race with OCSP stapling.
// This has the side-effect of saying an EV certificate is not EV if
// it hasn't already been verified (e.g. on the verification thread when
// connecting to a site).
// This flag is mostly a hack that should be removed once FLAG_LOCAL_ONLY
--- a/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
@@ -95,40 +95,22 @@ function add_tests_in_mode(useMozillaPKI
getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
ocspResponseRevoked);
add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
ocspResponseRevoked);
add_ocsp_test("ocsp-stapling-expired.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT),
ocspResponseUnknown);
-
- if (useMozillaPKIX) {
- // These tests are verifying that an valid but very old response
- // is rejected as a valid stapled response, requiring a fetch
- // from the ocsp responder.
- add_ocsp_test("ocsp-stapling-ancient-valid.example.com", Cr.NS_OK,
- ocspResponseGood);
- add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
- getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
- ocspResponseRevoked);
- add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
- getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT),
- ocspResponseUnknown);
- }
}
function check_ocsp_stapling_telemetry() {
let histogram = Cc["@mozilla.org/base/telemetry;1"]
.getService(Ci.nsITelemetry)
.getHistogramById("SSL_OCSP_STAPLING")
.snapshot();
do_check_eq(histogram.counts[0], 2 * 0); // histogram bucket 0 is unused
do_check_eq(histogram.counts[1], 2 * 0); // 0 connections with a good response
do_check_eq(histogram.counts[2], 2 * 0); // 0 connections with no stapled resp.
- do_check_eq(histogram.counts[3], 2 * 9 + 3); // 9 connections with an expired response
- // 3 connection with a response
- // considered expired due to being
- // old but having an overly-long
- // validity period
+ do_check_eq(histogram.counts[3], 2 * 9); // 9 connections with an expired response
do_check_eq(histogram.counts[4], 2 * 0); // 0 connections with bad responses
run_next_test();
}
--- a/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp
@@ -51,22 +51,16 @@ const static OCSPResponseName kOCSPRespo
{ "serverr", ORTSrverr}, // the response indicates there was a
// server error
{ "trylater", ORTTryLater}, // the responder replied with
// "try again later"
{ "resp-unsigned", ORTNeedsSig}, // the response needs a signature
{ "unauthorized", ORTUnauthorized}, // the responder does not know about
// the cert
{ "bad-signature", ORTBadSignature}, // the response has a bad signature
- { "longvalidityalmostold", ORTLongValidityAlmostExpired}, // the response is
- // still valid, but the generation
- // is almost a year old
- { "ancientstillvalid", ORTAncientAlmostExpired}, // The response is still
- // valid but the generation is almost
- // two years old
};
bool
stringToOCSPResponseType(const char* respText,
/*out*/ OCSPResponseType* OCSPType)
{
if (!OCSPType) {
--- a/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp
@@ -44,17 +44,16 @@ const OCSPHost sOCSPHosts[] =
{ "ocsp-stapling-delegated-included.example.com", ORTDelegatedIncluded, "delegatedSigner" },
{ "ocsp-stapling-delegated-included-last.example.com", ORTDelegatedIncludedLast, "delegatedSigner" },
{ "ocsp-stapling-delegated-missing.example.com", ORTDelegatedMissing, "delegatedSigner" },
{ "ocsp-stapling-delegated-missing-multiple.example.com", ORTDelegatedMissingMultiple, "delegatedSigner" },
{ "ocsp-stapling-delegated-no-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerNoExtKeyUsage" },
{ "ocsp-stapling-delegated-from-intermediate.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerFromIntermediate" },
{ "ocsp-stapling-delegated-keyUsage-crlSigning.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerKeyUsageCrlSigning" },
{ "ocsp-stapling-delegated-wrong-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage" },
- { "ocsp-stapling-ancient-valid.example.com", ORTAncientAlmostExpired, nullptr},
{ nullptr, ORTNull, nullptr }
};
int32_t
DoSNISocketConfig(PRFileDesc *aFd, const SECItem *aSrvNameArr,
uint32_t aSrvNameArrSize, void *aArg)
{
const OCSPHost *host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
--- a/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp
@@ -103,22 +103,16 @@ GetOCSPResponseForType(OCSPResponseType
}
if (aORT == ORTSkipResponseBytes) {
context.skipResponseBytes = true;
}
if (aORT == ORTExpired || aORT == ORTExpiredFreshCA) {
context.thisUpdate = oldNow;
context.nextUpdate = oldNow + 10 * PR_USEC_PER_SEC;
}
- if (aORT == ORTLongValidityAlmostExpired) {
- context.thisUpdate = now - (320 * oneDay);
- }
- if (aORT == ORTAncientAlmostExpired) {
- context.thisUpdate = now - (640 * oneDay);
- }
if (aORT == ORTRevoked) {
context.certStatus = 1;
}
if (aORT == ORTUnknown) {
context.certStatus = 2;
}
if (aORT == ORTBadSignature) {
context.badSignature = true;
--- a/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.h
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.h
@@ -32,18 +32,16 @@ enum OCSPResponseType
ORTSkipResponseBytes, // the response does not include responseBytes
ORTCriticalExtension, // the response includes a critical extension
ORTNoncriticalExtension, // the response includes an extension that is not critical
ORTEmptyExtensions, // the response includes a SEQUENCE OF Extension that is empty
ORTDelegatedIncluded, // the response is signed by an included delegated responder
ORTDelegatedIncludedLast, // same, but multiple other certificates are included
ORTDelegatedMissing, // the response is signed by a not included delegated responder
ORTDelegatedMissingMultiple, // same, but multiple other certificates are included
- ORTLongValidityAlmostExpired, // a good response, but that was generated a almost a year ago
- ORTAncientAlmostExpired, // a good response, with a validity of almost two years almost expiring
};
struct OCSPHost
{
const char *mHostName;
OCSPResponseType mORT;
const char *mAdditionalCertName; // useful for ORTGoodOtherCert, etc.
};
--- a/security/pkix/include/pkix/pkix.h
+++ b/security/pkix/include/pkix/pkix.h
@@ -109,16 +109,15 @@ SECItem* CreateEncodedOCSPRequest(PLAren
// trustworthy. If the response is not trustworthy, thisUpdate will be 0.
// Similarly, the optional parameter validThrough will be the time through
// 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,
- uint16_t maxLifetimeInDays,
const SECItem* encodedResponse,
/* optional out */ PRTime* thisUpdate,
/* optional out */ PRTime* validThrough);
} } // namespace mozilla::pkix
#endif // mozilla_pkix__pkix_h
--- a/security/pkix/lib/pkixocsp.cpp
+++ b/security/pkix/lib/pkixocsp.cpp
@@ -51,41 +51,38 @@ ENUM_CLASS CertStatus : uint8_t {
class Context
{
public:
Context(TrustDomain& trustDomain,
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)
{
if (thisUpdate) {
*thisUpdate = 0;
}
if (validThrough) {
*validThrough = 0;
}
}
TrustDomain& trustDomain;
const CERTCertificate& cert;
CERTCertificate& issuerCert;
const PRTime time;
- const uint16_t maxLifetimeInDays;
CertStatus certStatus;
PRTime* thisUpdate;
PRTime* validThrough;
private:
Context(const Context&); // delete
void operator=(const Context&); // delete
};
@@ -321,17 +318,16 @@ SetErrorToMalformedResponseOnBadDERError
PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0);
}
}
SECStatus
VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
const CERTCertificate* cert,
CERTCertificate* issuerCert, PRTime time,
- uint16_t maxOCSPLifetimeInDays,
const SECItem* encodedResponse,
PRTime* thisUpdate,
PRTime* validThrough)
{
PR_ASSERT(cert);
PR_ASSERT(issuerCert);
// TODO: PR_Assert(pinArg)
PR_ASSERT(encodedResponse);
@@ -340,18 +336,19 @@ VerifyEncodedOCSPResponse(TrustDomain& t
return SECFailure;
}
der::Input input;
if (input.Init(encodedResponse->data, encodedResponse->len) != der::Success) {
SetErrorToMalformedResponseOnBadDERError();
return SECFailure;
}
- Context context(trustDomain, *cert, *issuerCert, time, maxOCSPLifetimeInDays,
- thisUpdate, validThrough);
+
+ Context context(trustDomain, *cert, *issuerCert, time, thisUpdate,
+ validThrough);
if (der::Nested(input, der::SEQUENCE,
bind(OCSPResponse, _1, ref(context))) != der::Success) {
SetErrorToMalformedResponseOnBadDERError();
return SECFailure;
}
if (der::End(input) != der::Success) {
@@ -662,18 +659,19 @@ SingleResponse(der::Input& input, Contex
// http://tools.ietf.org/html/rfc6960#section-3.2
// 5. The time at which the status being indicated is known to be
// correct (thisUpdate) is sufficiently recent;
// 6. When available, the time at or before which newer information will
// be available about the status of the certificate (nextUpdate) is
// greater than the current time.
- const PRTime maxLifetime =
- context.maxLifetimeInDays * ONE_DAY;
+ // 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;
PRTime thisUpdate;
if (der::GeneralizedTime(input, thisUpdate) != der::Success) {
return der::Failure;
}
if (thisUpdate > context.time + SLOP) {
return der::Fail(SEC_ERROR_OCSP_FUTURE_RESPONSE);
@@ -688,20 +686,20 @@ SingleResponse(der::Input& input, Contex
bind(der::GeneralizedTime, _1, ref(nextUpdate)))
!= der::Success) {
return der::Failure;
}
if (nextUpdate < thisUpdate) {
return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
}
- if (nextUpdate - thisUpdate <= maxLifetime) {
+ if (nextUpdate - thisUpdate <= OLDEST_ACCEPTABLE) {
notAfter = nextUpdate;
} else {
- notAfter = thisUpdate + maxLifetime;
+ notAfter = thisUpdate + OLDEST_ACCEPTABLE;
}
} else {
// NSS requires all OCSP responses without a nextUpdate to be recent.
// Match that stricter behavior.
notAfter = thisUpdate + ONE_DAY;
}
if (context.time < SLOP) { // prevent underflow