From 3d9ab91ab0acff256c285d62bde3ef6efae07e73 Mon Sep 17 00:00:00 2001 From: Dana Keeler Date: Thu, 24 Sep 2020 18:10:05 +0000 Subject: [PATCH] Bug 1605273 - only run CRLite on certificates with a CT SCT available r=jcj Because CAs can back-date a certificate (i.e. set the "notBefore" field to earlier than when a certificate actually existed), the "notBefore" field can't be relied on when determining when CRLite information is recent enough to check a certificate with. To that end, this patch instead uses the earliest timestamp from the embedded SCTs in the certificate being checked. Differential Revision: https://phabricator.services.mozilla.com/D90599 --- security/apps/AppTrustDomain.cpp | 3 +- security/apps/AppTrustDomain.h | 4 +- .../certverifier/NSSCertDBTrustDomain.cpp | 58 +++++++++++++++---- security/certverifier/NSSCertDBTrustDomain.h | 4 +- .../OCSPVerificationTrustDomain.cpp | 3 +- .../OCSPVerificationTrustDomain.h | 4 +- security/ct/CTLogVerifier.cpp | 4 +- security/ct/MultiLogCTVerifier.cpp | 32 ++++++---- security/ct/MultiLogCTVerifier.h | 4 ++ security/ct/tests/gtest/CTTestUtils.cpp | 5 +- security/manager/ssl/CSTrustDomain.cpp | 5 +- security/manager/ssl/CSTrustDomain.h | 4 +- security/manager/ssl/nsNSSIOLayer.cpp | 5 +- .../no-sct-issuer.pem | 27 +++++++++ .../unit/test_cert_storage_direct/no-sct.pem | 33 +++++++++++ .../ssl/tests/unit/test_crlite_filters.js | 34 +++++++++++ 16 files changed, 191 insertions(+), 38 deletions(-) create mode 100644 security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct-issuer.pem create mode 100644 security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct.pem diff --git a/security/apps/AppTrustDomain.cpp b/security/apps/AppTrustDomain.cpp index 515b94bb6288..ea7b8cbb5150 100644 --- a/security/apps/AppTrustDomain.cpp +++ b/security/apps/AppTrustDomain.cpp @@ -227,9 +227,10 @@ Result AppTrustDomain::DigestBuf(Input item, DigestAlgorithm digestAlg, return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen); } -Result AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, +Result AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, /*optional*/ const Input*, + /*optional*/ const Input*, /*optional*/ const Input*) { // We don't currently do revocation checking. If we need to distrust an Apps // certificate, we will use the active distrust mechanism. diff --git a/security/apps/AppTrustDomain.h b/security/apps/AppTrustDomain.h index e298abe991f9..baa5b200f8fb 100644 --- a/security/apps/AppTrustDomain.h +++ b/security/apps/AppTrustDomain.h @@ -39,10 +39,10 @@ class AppTrustDomain final : public mozilla::pkix::TrustDomain { virtual Result CheckRevocation( mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, - mozilla::pkix::Time validityPeriodBeginning, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPresponse, - /*optional*/ const mozilla::pkix::Input* aiaExtension) override; + /*optional*/ const mozilla::pkix::Input* aiaExtension, + /*optional*/ const mozilla::pkix::Input* sctExtension) override; virtual Result IsChainValid( const mozilla::pkix::DERArray& certChain, mozilla::pkix::Time time, const mozilla::pkix::CertPolicyId& requiredPolicy) override; diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index c18b8939f709..ac49d657b19e 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -9,6 +9,7 @@ #include #include "ExtendedValidation.h" +#include "MultiLogCTVerifier.h" #include "NSSErrorsService.h" #include "OCSPVerificationTrustDomain.h" #include "PublicKeyPinningService.h" @@ -54,6 +55,7 @@ #include "TrustOverride-SymantecData.inc" using namespace mozilla; +using namespace mozilla::ct; using namespace mozilla::pkix; extern LazyLogModule gCertVerifierLog; @@ -605,11 +607,34 @@ static Result GetOCSPAuthorityInfoAccessLocation(const UniquePLArenaPool& arena, return Success; } +Result GetEarliestSCTTimestamp(Input sctExtension, + Maybe& earliestTimestamp) { + earliestTimestamp.reset(); + + Input sctList; + Result rv = + ExtractSignedCertificateTimestampListFromExtension(sctExtension, sctList); + if (rv != Success) { + return rv; + } + std::vector decodedSCTs; + size_t decodingErrors; + DecodeSCTs(sctList, decodedSCTs, decodingErrors); + Unused << decodingErrors; + for (const auto& scts : decodedSCTs) { + if (!earliestTimestamp.isSome() || scts.timestamp < *earliestTimestamp) { + earliestTimestamp = Some(scts.timestamp); + } + } + return Success; +} + Result NSSCertDBTrustDomain::CheckRevocation( EndEntityOrCA endEntityOrCA, const CertID& certID, Time time, - Time certValidityPeriodBeginning, Duration validityDuration, + Duration validityDuration, /*optional*/ const Input* stapledOCSPResponse, - /*optional*/ const Input* aiaExtension) { + /*optional*/ const Input* aiaExtension, + /*optional*/ const Input* sctExtension) { // Actively distrusted certificates will have already been blocked by // GetCertTrust. @@ -619,10 +644,20 @@ Result NSSCertDBTrustDomain::CheckRevocation( MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("NSSCertDBTrustDomain: Top of CheckRevocation\n")); + Maybe earliestSCTTimestamp = Nothing(); + if (sctExtension) { + Result rv = GetEarliestSCTTimestamp(*sctExtension, earliestSCTTimestamp); + if (rv != Success) { + MOZ_LOG( + gCertVerifierLog, LogLevel::Debug, + ("decoding SCT extension failed - CRLite will be not be consulted")); + } + } + Maybe crliteLookupDuration; #ifdef MOZ_NEW_CERT_STORAGE if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity && - mCRLiteMode != CRLiteMode::Disabled) { + mCRLiteMode != CRLiteMode::Disabled && earliestSCTTimestamp.isSome()) { MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("NSSCertDBTrustDomain::CheckRevocation: checking CRLite")); nsTArray issuerBytes; @@ -668,12 +703,15 @@ Result NSSCertDBTrustDomain::CheckRevocation( crliteLookupDuration.emplace(crliteLookupAfter - crliteLookupBefore); } Time filterTimestampTime(TimeFromEpochInSeconds(filterTimestamp)); - // We can only use this result if this certificate's `notBefore` time - // (i.e. the beginning of its validity period) is older than what cert - // storage returned for its CRLite timestamp. Otherwise, the CRLite filter - // cascade may have been created before this certificate existed, and if - // it would create a false positive, it hasn't been accounted for. - if (certValidityPeriodBeginning <= filterTimestampTime && + // We can only use this result if the earliest embedded signed + // certificate timestamp from the certificate is older than what cert + // storage returned for its CRLite timestamp. Otherwise, the CRLite + // filter cascade may have been created before this certificate existed, + // and if it would create a false positive, it hasn't been accounted for. + // SCT timestamps are milliseconds since the epoch. + Time earliestCertificateTimestamp( + TimeFromEpochInSeconds(*earliestSCTTimestamp / 1000)); + if (earliestCertificateTimestamp <= filterTimestampTime && crliteRevocationState == nsICertStorage::STATE_ENFORCE) { if (mCRLiteTelemetryInfo) { mCRLiteTelemetryInfo->mLookupResult = @@ -707,7 +745,7 @@ Result NSSCertDBTrustDomain::CheckRevocation( mCRLiteTelemetryInfo->mLookupResult = CRLiteLookupResult::FilterNotAvailable; } - } else if (certValidityPeriodBeginning > filterTimestampTime) { + } else if (earliestCertificateTimestamp > filterTimestampTime) { MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("NSSCertDBTrustDomain::CheckRevocation: cert too new")); if (mCRLiteTelemetryInfo) { diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index 02c7262de9d8..f42811493c82 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -223,10 +223,10 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain { virtual Result CheckRevocation( mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, - mozilla::pkix::Time validityPeriodBeginning, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, - /*optional*/ const mozilla::pkix::Input* aiaExtension) override; + /*optional*/ const mozilla::pkix::Input* aiaExtension, + /*optional*/ const mozilla::pkix::Input* sctExtension) override; virtual Result IsChainValid( const mozilla::pkix::DERArray& certChain, mozilla::pkix::Time time, diff --git a/security/certverifier/OCSPVerificationTrustDomain.cpp b/security/certverifier/OCSPVerificationTrustDomain.cpp index b80b9c0bba43..0a23821e4ca3 100644 --- a/security/certverifier/OCSPVerificationTrustDomain.cpp +++ b/security/certverifier/OCSPVerificationTrustDomain.cpp @@ -36,8 +36,9 @@ Result OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time, } Result OCSPVerificationTrustDomain::CheckRevocation(EndEntityOrCA, - const CertID&, Time, Time, + const CertID&, Time, Duration, const Input*, + const Input*, const Input*) { // We do not expect this to be called for OCSP signers return Result::FATAL_ERROR_LIBRARY_FAILURE; diff --git a/security/certverifier/OCSPVerificationTrustDomain.h b/security/certverifier/OCSPVerificationTrustDomain.h index 7c2dad10456f..be16a581cc28 100644 --- a/security/certverifier/OCSPVerificationTrustDomain.h +++ b/security/certverifier/OCSPVerificationTrustDomain.h @@ -67,10 +67,10 @@ class OCSPVerificationTrustDomain : public mozilla::pkix::TrustDomain { virtual Result CheckRevocation( mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, - mozilla::pkix::Time validityPeriodBeginning, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, - /*optional*/ const mozilla::pkix::Input* aiaExtension) override; + /*optional*/ const mozilla::pkix::Input* aiaExtension, + /*optional*/ const mozilla::pkix::Input* sctExtension) override; virtual Result IsChainValid( const mozilla::pkix::DERArray& certChain, mozilla::pkix::Time time, diff --git a/security/ct/CTLogVerifier.cpp b/security/ct/CTLogVerifier.cpp index 3b411de20a28..d704e876e596 100644 --- a/security/ct/CTLogVerifier.cpp +++ b/security/ct/CTLogVerifier.cpp @@ -38,8 +38,8 @@ class SignatureParamsTrustDomain final : public TrustDomain { return Result::FATAL_ERROR_LIBRARY_FAILURE; } - Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration, - const Input*, const Input*) override { + Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, + const Input*, const Input*, const Input*) override { return Result::FATAL_ERROR_LIBRARY_FAILURE; } diff --git a/security/ct/MultiLogCTVerifier.cpp b/security/ct/MultiLogCTVerifier.cpp index 37a2d1ad8851..78f7abb7a578 100644 --- a/security/ct/MultiLogCTVerifier.cpp +++ b/security/ct/MultiLogCTVerifier.cpp @@ -73,34 +73,46 @@ Result MultiLogCTVerifier::Verify(Input cert, Input issuerSubjectPublicKeyInfo, return Success; } -Result MultiLogCTVerifier::VerifySCTs(Input encodedSctList, - const LogEntry& expectedEntry, - VerifiedSCT::Origin origin, Time time, - CTVerifyResult& result) { +void DecodeSCTs(Input encodedSctList, + std::vector& decodedSCTs, + size_t& decodingErrors) { + decodedSCTs.clear(); + Reader listReader; Result rv = DecodeSCTList(encodedSctList, listReader); if (rv != Success) { - result.decodingErrors++; - return Success; + decodingErrors++; + return; } while (!listReader.AtEnd()) { Input encodedSct; rv = ReadSCTListItem(listReader, encodedSct); if (rv != Success) { - result.decodingErrors++; - return Success; + decodingErrors++; + return; } Reader encodedSctReader(encodedSct); SignedCertificateTimestamp sct; rv = DecodeSignedCertificateTimestamp(encodedSctReader, sct); if (rv != Success) { - result.decodingErrors++; + decodingErrors++; continue; } + decodedSCTs.push_back(std::move(sct)); + } +} - rv = VerifySingleSCT(std::move(sct), expectedEntry, origin, time, result); +Result MultiLogCTVerifier::VerifySCTs(Input encodedSctList, + const LogEntry& expectedEntry, + VerifiedSCT::Origin origin, Time time, + CTVerifyResult& result) { + std::vector decodedSCTs; + DecodeSCTs(encodedSctList, decodedSCTs, result.decodingErrors); + for (auto sct : decodedSCTs) { + Result rv = + VerifySingleSCT(std::move(sct), expectedEntry, origin, time, result); if (rv != Success) { return rv; } diff --git a/security/ct/MultiLogCTVerifier.h b/security/ct/MultiLogCTVerifier.h index d3c540bf747a..8f3047df7f7f 100644 --- a/security/ct/MultiLogCTVerifier.h +++ b/security/ct/MultiLogCTVerifier.h @@ -19,6 +19,10 @@ namespace mozilla { namespace ct { +void DecodeSCTs(Input encodedSctList, + std::vector& decodedSCTs, + size_t& decodingErrors); + // A Certificate Transparency verifier that can verify Signed Certificate // Timestamps from multiple logs. class MultiLogCTVerifier { diff --git a/security/ct/tests/gtest/CTTestUtils.cpp b/security/ct/tests/gtest/CTTestUtils.cpp index 667dab1cafa8..3dc40182e408 100644 --- a/security/ct/tests/gtest/CTTestUtils.cpp +++ b/security/ct/tests/gtest/CTTestUtils.cpp @@ -675,8 +675,9 @@ class OCSPExtensionTrustDomain : public TrustDomain { return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; } - pkix::Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, - Duration, const Input*, const Input*) override { + pkix::Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, + const Input*, const Input*, + const Input*) override { ADD_FAILURE(); return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; } diff --git a/security/manager/ssl/CSTrustDomain.cpp b/security/manager/ssl/CSTrustDomain.cpp index 99c4e4ec5f09..ac2e46dbfcdb 100644 --- a/security/manager/ssl/CSTrustDomain.cpp +++ b/security/manager/ssl/CSTrustDomain.cpp @@ -138,9 +138,10 @@ Result CSTrustDomain::FindIssuer(Input encodedIssuerName, Result CSTrustDomain::CheckRevocation( EndEntityOrCA endEntityOrCA, const CertID& certID, Time time, - Time validityPeriodBeginning, Duration validityDuration, + Duration validityDuration, /*optional*/ const Input* stapledOCSPresponse, - /*optional*/ const Input* aiaExtension) { + /*optional*/ const Input* aiaExtension, + /*optional*/ const Input* sctExtension) { // We're relying solely on the CertBlocklist for revocation - and we're // performing checks on this in GetCertTrust (as per nsNSSCertDBTrustDomain) return Success; diff --git a/security/manager/ssl/CSTrustDomain.h b/security/manager/ssl/CSTrustDomain.h index 7c86f2b0287e..949eb500acf7 100644 --- a/security/manager/ssl/CSTrustDomain.h +++ b/security/manager/ssl/CSTrustDomain.h @@ -35,10 +35,10 @@ class CSTrustDomain final : public mozilla::pkix::TrustDomain { virtual Result CheckRevocation( mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, - mozilla::pkix::Time validityPeriodBeginning, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPresponse, - /*optional*/ const mozilla::pkix::Input* aiaExtension) override; + /*optional*/ const mozilla::pkix::Input* aiaExtension, + /*optional*/ const mozilla::pkix::Input* sctExtension) override; virtual Result IsChainValid( const mozilla::pkix::DERArray& certChain, mozilla::pkix::Time time, const mozilla::pkix::CertPolicyId& requiredPolicy) override; diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp index 55cb43d7a1a3..681ca17855d5 100644 --- a/security/manager/ssl/nsNSSIOLayer.cpp +++ b/security/manager/ssl/nsNSSIOLayer.cpp @@ -1984,9 +1984,10 @@ class ClientAuthCertNonverifyingTrustDomain final : public TrustDomain { virtual mozilla::pkix::Result CheckRevocation( EndEntityOrCA endEntityOrCA, const CertID& certID, Time time, - Time validityPeriodBeginning, Duration validityDuration, + Duration validityDuration, /*optional*/ const Input* stapledOCSPresponse, - /*optional*/ const Input* aiaExtension) override { + /*optional*/ const Input* aiaExtension, + /*optional*/ const Input* sctExtension) override { return Success; } diff --git a/security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct-issuer.pem b/security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct-issuer.pem new file mode 100644 index 000000000000..70b86dfd71b9 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct-issuer.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg +U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83 +nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd +KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f +/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX +kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0 +/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C +AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY +aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6 +Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1 +oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD +QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v +d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh +xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB +CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl +5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA +8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC +2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit +c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0 +j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz +-----END CERTIFICATE----- diff --git a/security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct.pem b/security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct.pem new file mode 100644 index 000000000000..a690a0ad0d47 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_storage_direct/no-sct.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFpDCCBIygAwIBAgIQDVHBpbd6yyk2LgPoPr9QyjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E +aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTkxMTE4MDAwMDAwWhcN +MjExMTE4MTIwMDAwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju +aWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHTAbBgNVBAoTFFN5bWFudGVjIENv +cnBvcmF0aW9uMRcwFQYDVQQLEw5TeW1hbnRlYy5jbG91ZDEgMB4GA1UEAxMXbWFp +bDIzMy5tZXNzYWdlbGFicy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCyM1Fy9hAlahRqqeEnPKDWgUmsxofivWEWKNeSMEKcnXX3TCQOGbLQTthN +xfNU7IWY8ViTPwQ8JBWWDxNhd6dTYLNnytKrNRG8qDQ3rFMKJY4p0dZImMp55X3W +1xcKMxSOkPv0YUCGp7qlAHq6+N3YY1ILw6MRdJ75Njh4Kw8qe5F3rHLwD+AyYQmx +3WsMCRp5NZtWUcU5Vbc9ca/osrh9xBF7U3ZYR6GoPXQlizrNjXv7/BaKWWO5ChbD +iRI4Nj8d3HhWUHsJoGvYDof5Iudgtbubz3c5cwp6+VNNMas7izpvbixqW8zXdUug +8v5v47IkRNYnlma/zvv2IDC1dVlxAgMBAAGjggI2MIICMjAfBgNVHSMEGDAWgBQP +gGEcgjFh1S8o541GOLQs4cbZ4jAdBgNVHQ4EFgQUZnBdWwGQjkPX/+A2ZEYdUdnw +lN8wfQYDVR0RBHYwdIIbY2x1c3RlcjguZXUubWVzc2FnZWxhYnMuY29tgh5jbHVz +dGVyOG91dC5ldS5tZXNzYWdlbGFicy5jb22CHGNsdXN0ZXI4YS5ldS5tZXNzYWdl +bGFicy5jb22CF21haWwyMzMubWVzc2FnZWxhYnMuY29tMA4GA1UdDwEB/wQEAwIF +oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwawYDVR0fBGQwYjAvoC2g +K4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwL6At +oCuGKWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zc2NhLXNoYTItZzYuY3JsMEwG +A1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 +LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMHwGCCsGAQUFBwEBBHAwbjAkBggr +BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEYGCCsGAQUFBzAChjpo +dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyU2VjdXJlU2Vy +dmVyQ0EuY3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBAK7vS/qDcGKb +QYu26+jGtBemopT3+2YJjtALeR62eNhF9LoHu+mnmNLvPI0M0NMhz56Ss/6sUHOz +hJgB98SLAQ5ElSWXrnZThLIjsiH5X5MYTD0Y8MqzoJSi2Lf2Muy/UpyrD3wB14E1 +kUYhvUnaWDDPIN81DCFzEosBmnsRqr5zlcZSKs0e1LVQ8cNkt8svVkiwFgeOIhwo +QF22GJAZPtRceSGlbRTFBYKh+u3KN8eNS/X+C935y+F4J/grufDCzRSGtRRseTcd +1QW49+QME/rx1mBb7id4iXNKxvGuJTivBlxaHWBQLh/RGk39DSdHfjAhYvt2gmxh +C3gxXMNrymE= +-----END CERTIFICATE----- diff --git a/security/manager/ssl/tests/unit/test_crlite_filters.js b/security/manager/ssl/tests/unit/test_crlite_filters.js index 3e94dba982b3..1d06338f0217 100644 --- a/security/manager/ssl/tests/unit/test_crlite_filters.js +++ b/security/manager/ssl/tests/unit/test_crlite_filters.js @@ -402,11 +402,15 @@ add_task( let revokedInStashIssuer = constructCertFromFile( "test_cert_storage_direct/revoked-in-stash-issuer.pem" ); + let noSCTCertIssuer = constructCertFromFile( + "test_cert_storage_direct/no-sct-issuer.pem" + ); let crliteEnrollmentRecords = [ getCRLiteEnrollmentRecordFor(validCertIssuer), getCRLiteEnrollmentRecordFor(revokedCertIssuer), getCRLiteEnrollmentRecordFor(revokedInStashIssuer), + getCRLiteEnrollmentRecordFor(noSCTCertIssuer), ]; await IntermediatePreloadsClient.onSync({ @@ -521,6 +525,36 @@ add_task( "schunk-group.com", Ci.nsIX509CertDB.FLAG_LOCAL_ONLY ); + + // This certificate has no embedded SCTs, so it is not guaranteed to be in + // CT, so CRLite can't be guaranteed to give the correct answer, so it is + // not consulted. + let noSCTCert = constructCertFromFile( + "test_cert_storage_direct/no-sct.pem" + ); + // Currently OCSP will always be consulted for certificates that are not + // revoked in CRLite, but if/when OCSP gets skipped for all certificates + // covered by CRLite, this test will ensure that certificates without + // embedded SCTs will cause OCSP to be consulted. + // NB: this will cause an OCSP request to be sent to localhost:80, but + // since an OCSP responder shouldn't be running on that port, this should + // fail safely. + Services.prefs.setCharPref("network.dns.localDomains", "ocsp.digicert.com"); + Services.prefs.setBoolPref("security.OCSP.require", true); + Services.prefs.setIntPref("security.OCSP.enabled", 1); + await checkCertErrorGenericAtTime( + certdb, + noSCTCert, + SEC_ERROR_OCSP_SERVER_ERROR, + certificateUsageSSLServer, + new Date("2020-11-20T00:00:00Z").getTime() / 1000, + false, + "mail233.messagelabs.com", + 0 + ); + Services.prefs.clearUserPref("network.dns.localDomains"); + Services.prefs.clearUserPref("security.OCSP.require"); + Services.prefs.clearUserPref("security.OCSP.enabled"); } );