Backed out changeset d4a6f5cb9b3f (bug 1747320) for breaking connectivity with many https sites (bug 1750188) a=backout

This commit is contained in:
Norisz Fay 2022-01-14 15:15:26 +02:00
Родитель 71bbf38c5a
Коммит 4475b51bcb
19 изменённых файлов: 276 добавлений и 533 удалений

Просмотреть файл

@ -161,6 +161,10 @@ pref("security.xfocsp.errorReporting.automatic", false);
// 2: Enable and enforce revocations via CRLite
pref("security.pki.crlite_mode", 1);
// Represents the expected certificate transparency log merge delay (including
// the time to generate a CRLite filter). Currently 28 hours in seconds.
pref("security.pki.crlite_ct_merge_delay_seconds", 100800);
// Issuer we use to detect MitM proxies. Set to the issuer of the cert of the
// Firefox update service. The string format is whatever NSS uses to print a DN.
// This value is set and cleared automatically.

Просмотреть файл

@ -1,33 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CRLiteTimestamp_h
#define CRLiteTimestamp_h
#include "nsICertStorage.h"
#include "SignedCertificateTimestamp.h"
namespace mozilla::psm {
class CRLiteTimestamp final : public nsICRLiteTimestamp {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICRLITETIMESTAMP
CRLiteTimestamp() : mTimestamp(0) {}
explicit CRLiteTimestamp(const ct::SignedCertificateTimestamp& sct)
: mLogID(Span(sct.logId)), mTimestamp(sct.timestamp) {}
private:
~CRLiteTimestamp() = default;
nsTArray<uint8_t> mLogID;
uint64_t mTimestamp;
};
} // namespace mozilla::psm
#endif // CRLiteTimestamp_h

Просмотреть файл

@ -109,6 +109,7 @@ CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode,
CRLiteMode crliteMode,
uint64_t crliteCTMergeDelaySeconds,
const Vector<EnterpriseCert>& thirdPartyCerts)
: mOCSPDownloadConfig(odc),
mOCSPStrict(osc == ocspStrict),
@ -119,7 +120,8 @@ CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mNameMatchingMode(nameMatchingMode),
mNetscapeStepUpPolicy(netscapeStepUpPolicy),
mCTMode(ctMode),
mCRLiteMode(crliteMode) {
mCRLiteMode(crliteMode),
mCRLiteCTMergeDelaySeconds(crliteCTMergeDelaySeconds) {
LoadKnownCTLogs();
for (const auto& root : thirdPartyCerts) {
EnterpriseCert rootCopy;
@ -578,9 +580,10 @@ Result CertVerifier::VerifyCert(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
rv = BuildCertChain(
trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyPurposeId::id_kp_clientAuth,
@ -649,9 +652,10 @@ Result CertVerifier::VerifyCert(
trustSSL, evOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS,
ValidityCheckingMode::CheckForEV, sha1ModeConfigurations[i],
mNetscapeStepUpPolicy, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, pinningTelemetryInfo, hostname);
mNetscapeStepUpPolicy, mCRLiteMode, mCRLiteCTMergeDelaySeconds,
originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, // (EC)DHE
@ -729,9 +733,9 @@ Result CertVerifier::VerifyCert(
mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
keySizeOptions[i], ValidityCheckingMode::CheckingOff,
sha1ModeConfigurations[j], mNetscapeStepUpPolicy, mCRLiteMode,
originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
mCRLiteCTMergeDelaySeconds, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, //(EC)DHE
@ -796,9 +800,10 @@ Result CertVerifier::VerifyCert(
trustSSL, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
mNetscapeStepUpPolicy, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
mNetscapeStepUpPolicy, mCRLiteMode, mCRLiteCTMergeDelaySeconds,
originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeCA,
KeyUsage::keyCertSign, KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy, stapledOCSPResponse);
@ -810,9 +815,10 @@ Result CertVerifier::VerifyCert(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
rv = BuildCertChain(
trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyPurposeId::id_kp_emailProtection,
@ -834,9 +840,10 @@ Result CertVerifier::VerifyCert(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA

Просмотреть файл

@ -222,6 +222,7 @@ class CertVerifier {
BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode, CRLiteMode crliteMode,
uint64_t crliteCTMergeDelaySeconds,
const Vector<EnterpriseCert>& thirdPartyCerts);
~CertVerifier();
@ -237,6 +238,7 @@ class CertVerifier {
const NetscapeStepUpPolicy mNetscapeStepUpPolicy;
const CertificateTransparencyMode mCTMode;
const CRLiteMode mCRLiteMode;
const uint64_t mCRLiteCTMergeDelaySeconds;
private:
OCSPCache mOCSPCache;

Просмотреть файл

@ -9,7 +9,6 @@
#include <stdint.h>
#include <utility>
#include "CRLiteTimestamp.h"
#include "ExtendedValidation.h"
#include "MultiLogCTVerifier.h"
#include "NSSErrorsService.h"
@ -73,7 +72,8 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
TimeDuration ocspTimeoutHard, uint32_t certShortLifetimeInDays,
unsigned int minRSABits, ValidityCheckingMode validityCheckingMode,
CertVerifier::SHA1Mode sha1Mode, NetscapeStepUpPolicy netscapeStepUpPolicy,
CRLiteMode crliteMode, const OriginAttributes& originAttributes,
CRLiteMode crliteMode, uint64_t crliteCTMergeDelaySeconds,
const OriginAttributes& originAttributes,
const Vector<Input>& thirdPartyRootInputs,
const Vector<Input>& thirdPartyIntermediateInputs,
const Maybe<nsTArray<nsTArray<uint8_t>>>& extraCertificates,
@ -92,6 +92,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
mSHA1Mode(sha1Mode),
mNetscapeStepUpPolicy(netscapeStepUpPolicy),
mCRLiteMode(crliteMode),
mCRLiteCTMergeDelaySeconds(crliteCTMergeDelaySeconds),
mSawDistrustedCAByPolicyError(false),
mOriginAttributes(originAttributes),
mThirdPartyRootInputs(thirdPartyRootInputs),
@ -599,24 +600,10 @@ static Result GetOCSPAuthorityInfoAccessLocation(const UniquePLArenaPool& arena,
return Success;
}
NS_IMPL_ISUPPORTS(CRLiteTimestamp, nsICRLiteTimestamp)
Result GetEarliestSCTTimestamp(Input sctExtension,
Maybe<uint64_t>& earliestTimestamp) {
earliestTimestamp.reset();
NS_IMETHODIMP
CRLiteTimestamp::GetLogID(nsTArray<uint8_t>& aLogID) {
aLogID.Clear();
aLogID.AppendElements(mLogID);
return NS_OK;
}
NS_IMETHODIMP
CRLiteTimestamp::GetTimestamp(uint64_t* aTimestamp) {
*aTimestamp = mTimestamp;
return NS_OK;
}
Result BuildCRLiteTimestampArray(
Input sctExtension,
/*out*/ nsTArray<RefPtr<nsICRLiteTimestamp>>& timestamps) {
Input sctList;
Result rv =
ExtractSignedCertificateTimestampListFromExtension(sctExtension, sctList);
@ -627,9 +614,10 @@ Result BuildCRLiteTimestampArray(
size_t decodingErrors;
DecodeSCTs(sctList, decodedSCTs, decodingErrors);
Unused << decodingErrors;
for (const auto& sct : decodedSCTs) {
timestamps.AppendElement(new CRLiteTimestamp(sct));
for (const auto& scts : decodedSCTs) {
if (!earliestTimestamp.isSome() || scts.timestamp < *earliestTimestamp) {
earliestTimestamp = Some(scts.timestamp);
}
}
return Success;
}
@ -661,14 +649,14 @@ Result NSSCertDBTrustDomain::CheckCRLiteStash(
Result NSSCertDBTrustDomain::CheckCRLite(
const nsTArray<uint8_t>& issuerBytes,
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
const nsTArray<uint8_t>& serialNumberBytes,
const nsTArray<RefPtr<nsICRLiteTimestamp>>& timestamps,
/*out*/ bool& filterCoversCertificate) {
const nsTArray<uint8_t>& serialNumberBytes, uint64_t earliestSCTTimestamp,
bool& filterCoversCertificate) {
filterCoversCertificate = false;
uint64_t filterTimestamp;
int16_t crliteRevocationState;
nsresult rv = mCertStorage->GetCRLiteRevocationState(
issuerBytes, issuerSubjectPublicKeyInfoBytes, serialNumberBytes,
timestamps, &crliteRevocationState);
&filterTimestamp, &crliteRevocationState);
if (NS_FAILED(rv)) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain::CheckCRLite: CRLite call failed"));
@ -676,28 +664,50 @@ Result NSSCertDBTrustDomain::CheckCRLite(
}
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain::CheckCRLite: CRLite check returned "
"state=%hd",
crliteRevocationState));
switch (crliteRevocationState) {
case nsICertStorage::STATE_ENFORCE:
filterCoversCertificate = true;
return Result::ERROR_REVOKED_CERTIFICATE;
case nsICertStorage::STATE_UNSET:
filterCoversCertificate = true;
return Success;
case nsICertStorage::STATE_NOT_ENROLLED:
filterCoversCertificate = false;
return Success;
case nsICertStorage::STATE_NOT_COVERED:
filterCoversCertificate = false;
return Success;
default:
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain::CheckCRLite: Unknown CRLite revocation "
"state"));
return Result::FATAL_ERROR_LIBRARY_FAILURE;
"state=%hd filter timestamp=%llu",
crliteRevocationState,
// The cast is to silence warnings on compilers where uint64_t is
// an unsigned long as opposed to an unsigned long long.
static_cast<unsigned long long>(filterTimestamp)));
Time filterTimestampTime(TimeFromEpochInSeconds(filterTimestamp));
// 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));
Result result =
earliestCertificateTimestamp.AddSeconds(mCRLiteCTMergeDelaySeconds);
if (result != Success) {
// This shouldn't happen - the merge delay is at most a year in seconds,
// and the SCT timestamp is supposed to be in the past.
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain::CheckRevocation: integer overflow "
"calculating sct timestamp + merge delay (%llu + %llu)",
static_cast<unsigned long long>(earliestSCTTimestamp / 1000),
static_cast<unsigned long long>(mCRLiteCTMergeDelaySeconds)));
// While we do have control over the possible values of the CT merge
// delay parameter, we don't have control over the SCT timestamp.
// Thus, if we've reached this point, the CA has probably made a
// mistake and we should treat this certificate as revoked.
return Result::ERROR_REVOKED_CERTIFICATE;
}
if (filterTimestamp != 0 &&
earliestCertificateTimestamp <= filterTimestampTime &&
crliteRevocationState != nsICertStorage::STATE_NOT_ENROLLED) {
filterCoversCertificate = true;
}
if (filterCoversCertificate &&
crliteRevocationState == nsICertStorage::STATE_ENFORCE) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain::CheckRevocation: certificate revoked via "
"CRLite"));
return Result::ERROR_REVOKED_CERTIFICATE;
}
return Success;
}
Result NSSCertDBTrustDomain::CheckRevocation(
@ -715,10 +725,20 @@ Result NSSCertDBTrustDomain::CheckRevocation(
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain: Top of CheckRevocation\n"));
Maybe<uint64_t> 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"));
}
}
bool crliteFilterCoversCertificate = false;
Result crliteResult = Success;
if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
mCRLiteMode != CRLiteMode::Disabled && sctExtension) {
mCRLiteMode != CRLiteMode::Disabled && earliestSCTTimestamp.isSome()) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain::CheckRevocation: checking CRLite"));
nsTArray<uint8_t> issuerSubjectPublicKeyInfoBytes;
@ -735,32 +755,22 @@ Result NSSCertDBTrustDomain::CheckRevocation(
if (rv != Success) {
return rv;
}
nsTArray<uint8_t> issuerBytes;
issuerBytes.AppendElements(certID.issuer.UnsafeGetData(),
certID.issuer.GetLength());
nsTArray<RefPtr<nsICRLiteTimestamp>> timestamps;
rv = BuildCRLiteTimestampArray(*sctExtension, timestamps);
if (rv != Success) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("decoding SCT extension failed - CRLite will be not be "
"consulted"));
} else {
crliteResult = CheckCRLite(issuerBytes, issuerSubjectPublicKeyInfoBytes,
serialNumberBytes, timestamps,
crliteFilterCoversCertificate);
// If CheckCRLite returned an error other than "revoked certificate",
// propagate that error.
if (crliteResult != Success &&
crliteResult != Result::ERROR_REVOKED_CERTIFICATE) {
return crliteResult;
}
// Always return the result of CheckCRLite if CRLite is being enforced and
// the certificate is covered by the CRLite filter.
if (mCRLiteMode == CRLiteMode::Enforce && crliteFilterCoversCertificate) {
return crliteResult;
}
crliteResult = CheckCRLite(issuerBytes, issuerSubjectPublicKeyInfoBytes,
serialNumberBytes, *earliestSCTTimestamp,
crliteFilterCoversCertificate);
// If CheckCRLite returned an error other than "revoked certificate",
// propagate that error.
if (crliteResult != Success &&
crliteResult != Result::ERROR_REVOKED_CERTIFICATE) {
return crliteResult;
}
// Always return the result of CheckCRLite if CRLite is being enforced and
// the certificate is covered by the CRLite filter.
if (mCRLiteMode == CRLiteMode::Enforce && crliteFilterCoversCertificate) {
return crliteResult;
}
}

Просмотреть файл

@ -8,7 +8,6 @@
#define NSSCertDBTrustDomain_h
#include "CertVerifier.h"
#include "CRLiteTimestamp.h"
#include "ScopedNSSTypes.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/TimeStamp.h"
@ -144,6 +143,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
unsigned int minRSABits, ValidityCheckingMode validityCheckingMode,
CertVerifier::SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy, CRLiteMode crliteMode,
uint64_t crliteCTMergeDelaySeconds,
const OriginAttributes& originAttributes,
const Vector<mozilla::pkix::Input>& thirdPartyRootInputs,
const Vector<mozilla::pkix::Input>& thirdPartyIntermediateInputs,
@ -237,12 +237,11 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
Result CheckCRLiteStash(
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
const nsTArray<uint8_t>& serialNumberBytes);
Result CheckCRLite(
const nsTArray<uint8_t>& issuerBytes,
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
const nsTArray<uint8_t>& serialNumberBytes,
const nsTArray<RefPtr<nsICRLiteTimestamp>>& crliteTimestamps,
bool& filterCoversCertificate);
Result CheckCRLite(const nsTArray<uint8_t>& issuerBytes,
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
const nsTArray<uint8_t>& serialNumberBytes,
uint64_t earliestSCTTimestamp,
bool& filterCoversCertificate);
enum EncodedResponseSource {
ResponseIsFromNetwork = 1,
@ -275,6 +274,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
CertVerifier::SHA1Mode mSHA1Mode;
NetscapeStepUpPolicy mNetscapeStepUpPolicy;
CRLiteMode mCRLiteMode;
uint64_t mCRLiteCTMergeDelaySeconds;
bool mSawDistrustedCAByPolicyError;
const OriginAttributes& mOriginAttributes;
const Vector<mozilla::pkix::Input>& mThirdPartyRootInputs; // non-owning

Просмотреть файл

@ -91,17 +91,6 @@ CRLiteState.prototype.QueryInterface = ChromeUtils.generateQI([
"nsICRLiteState",
]);
class CRLiteCoverage {
constructor(b64LogID, minTimestamp, maxTimestamp) {
this.b64LogID = b64LogID;
this.minTimestamp = minTimestamp;
this.maxTimestamp = maxTimestamp;
}
}
CRLiteCoverage.prototype.QueryInterface = ChromeUtils.generateQI([
"nsICRLiteCoverage",
]);
class CertInfo {
constructor(cert, subject) {
this.cert = cert;
@ -674,22 +663,10 @@ class CRLiteFilters {
log.warn("trying to install more than one full CRLite filter?");
}
let filter = fullFiltersDownloaded[0];
let coverage = [];
if (filter.coverage) {
for (let entry of filter.coverage) {
coverage.push(
new CRLiteCoverage(
entry.LogID,
entry.MinTimestamp,
entry.MaxTimestamp
)
);
}
}
let timestamp = Math.floor(filter.effectiveTimestamp / 1000);
log.debug(`setting CRLite filter timestamp to ${timestamp}`);
await new Promise(resolve => {
certList.setFullCRLiteFilter(filter.bytes, coverage, rv => {
certList.setFullCRLiteFilter(filter.bytes, timestamp, rv => {
log.debug(`setFullCRLiteFilter: ${rv}`);
resolve();
});

Просмотреть файл

@ -27,11 +27,12 @@ class SharedCertVerifier : public mozilla::psm::CertVerifier {
BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode, CRLiteMode crliteMode,
uint64_t crliteCTMergeDelaySeconds,
const Vector<EnterpriseCert>& thirdPartyCerts)
: mozilla::psm::CertVerifier(odc, osc, ocspSoftTimeout, ocspHardTimeout,
certShortLifetimeInDays, sha1Mode,
nameMatchingMode, netscapeStepUpPolicy,
ctMode, crliteMode, thirdPartyCerts) {}
: mozilla::psm::CertVerifier(
odc, osc, ocspSoftTimeout, ocspHardTimeout, certShortLifetimeInDays,
sha1Mode, nameMatchingMode, netscapeStepUpPolicy, ctMode,
crliteMode, crliteCTMergeDelaySeconds, thirdPartyCerts) {}
};
} // namespace psm

Просмотреть файл

@ -59,10 +59,10 @@ use std::time::{Duration, SystemTime};
use storage_variant::VariantType;
use thin_vec::ThinVec;
use xpcom::interfaces::{
nsICRLiteCoverage, nsICRLiteState, nsICRLiteTimestamp, nsICertInfo, nsICertStorage,
nsICertStorageCallback, nsIFile, nsIHandleReportCallback, nsIIssuerAndSerialRevocationState,
nsIMemoryReporter, nsIMemoryReporterManager, nsIObserver, nsIPrefBranch, nsIRevocationState,
nsISerialEventTarget, nsISubjectAndPubKeyRevocationState, nsISupports,
nsICRLiteState, nsICertInfo, nsICertStorage, nsICertStorageCallback, nsIFile,
nsIHandleReportCallback, nsIIssuerAndSerialRevocationState, nsIMemoryReporter,
nsIMemoryReporterManager, nsIObserver, nsIPrefBranch, nsIRevocationState, nsISerialEventTarget,
nsISubjectAndPubKeyRevocationState, nsISupports,
};
use xpcom::{nsIID, GetterAddrefs, RefPtr, ThreadBoundRefPtr, XpCom};
@ -73,8 +73,6 @@ const PREFIX_SUBJECT: &str = "subject";
const PREFIX_CERT: &str = "cert";
const PREFIX_DATA_TYPE: &str = "datatype";
const COVERAGE_SERIALIZATION_VERSION: u8 = 1;
type Rkv = rkv::Rkv<SafeModeEnvironment>;
type SingleStore = rkv::SingleStore<SafeModeDatabase>;
@ -153,10 +151,8 @@ struct SecurityState {
int_prefs: HashMap<String, u32>,
#[ignore_malloc_size_of = "rental crate does not allow impls for rental structs"]
crlite_filter: Option<holding::CRLiteFilter>,
/// Maps issuer spki hashes to sets of serial numbers.
/// Maps issuer spki hashes to sets of seiral numbers.
crlite_stash: Option<HashMap<Vec<u8>, HashSet<Vec<u8>>>>,
/// Maps an RFC 6962 LogID to a pair of 64 bit unix timestamps
crlite_coverage: Option<HashMap<Vec<u8>, (u64, u64)>>,
/// Tracks the number of asynchronous operations which have been dispatched but not completed.
remaining_ops: i32,
}
@ -171,7 +167,6 @@ impl SecurityState {
int_prefs: HashMap::new(),
crlite_filter: None,
crlite_stash: None,
crlite_coverage: None,
remaining_ops: 0,
})
}
@ -302,7 +297,7 @@ impl SecurityState {
pub fn get_has_prior_data(&self, data_type: u8) -> Result<bool, SecurityStateError> {
if data_type == nsICertStorage::DATA_TYPE_CRLITE_FILTER_FULL {
return Ok(self.crlite_filter.is_some() && self.crlite_coverage.is_some());
return Ok(self.crlite_filter.is_some());
}
if data_type == nsICertStorage::DATA_TYPE_CRLITE_FILTER_INCREMENTAL {
return Ok(self.crlite_stash.is_some());
@ -418,31 +413,15 @@ impl SecurityState {
}
}
pub fn filter_covers_timestamp(
&self,
log_id: &[u8],
timestamp: u64,
) -> Result<bool, SecurityStateError> {
if let Some(crlite_coverage) = self.crlite_coverage.as_ref() {
match crlite_coverage.get(log_id) {
Some(&(low, high)) => Ok(low <= timestamp && timestamp <= high),
None => Ok(false),
}
} else {
Err(SecurityStateError::from("coverage not initialized"))
}
}
pub fn set_full_crlite_filter(
&mut self,
filter: Vec<u8>,
coverage_entries: &[(nsCString, u64, u64)],
timestamp: u64,
) -> Result<(), SecurityStateError> {
// First drop any existing crlite filter and clear the accumulated stash.
{
let _ = self.crlite_filter.take();
let _ = self.crlite_stash.take();
let _ = self.crlite_coverage.take();
let mut path = get_store_path(&self.profile_path)?;
path.push("crlite.stash");
// Truncate the stash file if it exists.
@ -459,45 +438,31 @@ impl SecurityState {
let mut filter_file = File::create(&path)?;
filter_file.write_all(&filter)?;
}
// Serialize the coverage metadata as a 1 byte version number followed by any number of 48
// byte entries. Each entry is a 32 byte (opaque) log id, followed by two 8 byte
// timestamps. Each timestamp is an 8 byte unsigned integer in little endian.
let mut coverage_bytes = Vec::with_capacity(
size_of::<u8>() + coverage_entries.len() * (32 + size_of::<u64>() + size_of::<u64>()),
);
coverage_bytes.push(COVERAGE_SERIALIZATION_VERSION);
for (b64_log_id, min_t, max_t) in coverage_entries {
let log_id = match base64::decode(&b64_log_id) {
Ok(log_id) if log_id.len() == 32 => log_id,
_ => {
warn!("malformed log ID - skipping: {}", b64_log_id);
continue;
}
};
coverage_bytes.extend_from_slice(&log_id);
coverage_bytes.extend_from_slice(&min_t.to_le_bytes());
coverage_bytes.extend_from_slice(&max_t.to_le_bytes());
}
// Write the coverage file for the new filter
let mut path = get_store_path(&self.profile_path)?;
path.push("crlite.coverage");
{
let mut coverage_file = File::create(&path)?;
coverage_file.write_all(&coverage_bytes)?;
}
self.load_crlite_filter()?;
let env_and_store = match self.env_and_store.as_mut() {
Some(env_and_store) => env_and_store,
None => return Err(SecurityStateError::from("env and store not initialized?")),
};
let mut writer = env_and_store.env.write()?;
// Make a note of the timestamp of the full filter.
env_and_store.store.put(
&mut writer,
&make_key!(
PREFIX_DATA_TYPE,
&[nsICertStorage::DATA_TYPE_CRLITE_FILTER_FULL]
),
&Value::U64(timestamp),
)?;
writer.commit()?;
Ok(())
}
fn load_crlite_filter(&mut self) -> Result<(), SecurityStateError> {
if self.crlite_filter.is_some() || self.crlite_coverage.is_some() {
if self.crlite_filter.is_some() {
return Err(SecurityStateError::from(
"Both crlite_filter and crlite_coverage should be None here",
"crlite_filter should be None here",
));
}
let mut path = get_store_path(&self.profile_path)?;
path.push("crlite.filter");
// Before we've downloaded any filters, this file won't exist.
@ -513,63 +478,8 @@ impl SecurityState {
}
})
.map_err(|_| SecurityStateError::from("unable to initialize CRLite filter"))?;
let mut path = get_store_path(&self.profile_path)?;
path.push("crlite.coverage");
if !path.exists() {
return Ok(());
}
// Deserialize the coverage metadata.
// The format is described in `set_full_crlite_filter`.
let coverage_file = File::open(path)?;
let mut coverage_reader = BufReader::new(coverage_file);
match coverage_reader.read_u8() {
Ok(COVERAGE_SERIALIZATION_VERSION) => (),
_ => {
return Err(SecurityStateError::from(
"unable to initialize CRLite coverage",
))
}
}
let mut crlite_coverage: HashMap<Vec<u8>, (u64, u64)> = HashMap::new();
loop {
let mut coverage_entry = [0u8; 48];
match coverage_reader.read(&mut coverage_entry) {
Ok(48) => (),
Ok(0) => break, // end of file
_ => {
return Err(SecurityStateError::from(
"unable to initialize CRLite coverage",
))
}
};
let log_id = &coverage_entry[0..32];
let min_timestamp: u64;
let max_timestamp: u64;
match (&coverage_entry[32..40]).read_u64::<LittleEndian>() {
Ok(value) => min_timestamp = value,
_ => {
return Err(SecurityStateError::from(
"unable to initialize CRLite coverage",
))
}
}
match (&coverage_entry[40..48]).read_u64::<LittleEndian>() {
Ok(value) => max_timestamp = value,
_ => {
return Err(SecurityStateError::from(
"unable to initialize CRLite coverage",
))
}
}
crlite_coverage.insert(log_id.to_vec(), (min_timestamp, max_timestamp));
}
let old_crlite_filter_should_be_none = self.crlite_filter.replace(crlite_filter);
assert!(old_crlite_filter_should_be_none.is_none());
let old_crlite_coverage_should_be_none = self.crlite_coverage.replace(crlite_coverage);
assert!(old_crlite_coverage_should_be_none.is_none());
Ok(())
}
@ -608,21 +518,35 @@ impl SecurityState {
issuer: &[u8],
issuer_spki: &[u8],
serial_number: &[u8],
timestamps: &[CRLiteTimestamp],
) -> Result<i16, SecurityStateError> {
) -> Result<(u64, i16), SecurityStateError> {
let timestamp = {
let env_and_store = match self.env_and_store.as_ref() {
Some(env_and_store) => env_and_store,
None => return Err(SecurityStateError::from("env and store not initialized?")),
};
let reader = env_and_store.env.read()?;
match env_and_store.store.get(
&reader,
&make_key!(
PREFIX_DATA_TYPE,
&[nsICertStorage::DATA_TYPE_CRLITE_FILTER_FULL]
),
) {
Ok(Some(Value::U64(timestamp))) => timestamp,
// If we don't have a timestamp yet, we won't have a filter. Return the earliest
// timestamp possible to indicate this to callers.
Ok(None) => return Ok((0, nsICertStorage::STATE_UNSET)),
Ok(_) => {
return Err(SecurityStateError::from(
"unexpected type when trying to get Value::U64",
))
}
Err(_) => return Err(SecurityStateError::from("error getting CRLite timestamp")),
}
};
let enrollment_state = self.get_crlite_state(issuer, issuer_spki)?;
if enrollment_state != nsICertStorage::STATE_ENFORCE {
return Ok(nsICertStorage::STATE_NOT_ENROLLED);
}
let mut covered = false;
for timestamp in timestamps {
if self.filter_covers_timestamp(&timestamp.log_id, timestamp.timestamp)? {
covered = true;
break;
}
}
if !covered {
return Ok(nsICertStorage::STATE_NOT_COVERED);
return Ok((timestamp, nsICertStorage::STATE_NOT_ENROLLED));
}
let mut digest = Sha256::default();
digest.input(issuer_spki);
@ -632,12 +556,13 @@ impl SecurityState {
let result = match &self.crlite_filter {
Some(crlite_filter) => crlite_filter.rent(|filter| filter.has(&lookup_key)),
// This can only happen if the backing file was deleted or if it or our database has
// become corrupted. In any case, we have no information.
None => return Ok(nsICertStorage::STATE_NOT_COVERED),
// become corrupted. In any case, we have no information, so again return the earliest
// timestamp to indicate this to the user.
None => return Ok((0, nsICertStorage::STATE_UNSET)),
};
match result {
true => Ok(nsICertStorage::STATE_ENFORCE),
false => Ok(nsICertStorage::STATE_UNSET),
true => Ok((timestamp, nsICertStorage::STATE_ENFORCE)),
false => Ok((timestamp, nsICertStorage::STATE_UNSET)),
}
}
@ -1002,12 +927,6 @@ impl<'a> IntoIterator for CertHashList<'a> {
}
}
// Helper struct for get_crlite_revocation_state.
struct CRLiteTimestamp {
log_id: ThinVec<u8>,
timestamp: u64,
}
// Helper struct for set_batch_state. Takes a prefix, two base64-encoded key
// parts, and a security state value.
struct EncodedSecurityState {
@ -1728,34 +1647,20 @@ impl CertStorage {
unsafe fn SetFullCRLiteFilter(
&self,
filter: *const ThinVec<u8>,
coverage: *const ThinVec<RefPtr<nsICRLiteCoverage>>,
timestamp: u64,
callback: *const nsICertStorageCallback,
) -> nserror::nsresult {
if !is_main_thread() {
return NS_ERROR_NOT_SAME_THREAD;
}
if filter.is_null() || coverage.is_null() || callback.is_null() {
if filter.is_null() || callback.is_null() {
return NS_ERROR_NULL_POINTER;
}
let filter_owned = (*filter).to_vec();
let coverage = &*coverage;
let mut coverage_entries = Vec::with_capacity(coverage.len());
for entry in coverage {
let mut b64_log_id = nsCString::new();
try_ns!((*entry).GetB64LogID(&mut *b64_log_id).to_result(), or continue);
let mut min_timestamp: u64 = 0;
try_ns!((*entry).GetMinTimestamp(&mut min_timestamp).to_result(), or continue);
let mut max_timestamp: u64 = 0;
try_ns!((*entry).GetMaxTimestamp(&mut max_timestamp).to_result(), or continue);
coverage_entries.push((b64_log_id, min_timestamp, max_timestamp));
}
let task = Box::new(try_ns!(SecurityStateTask::new(
&*callback,
&self.security_state,
move |ss| ss.set_full_crlite_filter(filter_owned, &coverage_entries),
move |ss| ss.set_full_crlite_filter(filter_owned, timestamp),
)));
let runnable = try_ns!(TaskRunnable::new("SetFullCRLiteFilter", task));
try_ns!(TaskRunnable::dispatch(runnable, self.queue.coerce()));
@ -1806,7 +1711,7 @@ impl CertStorage {
issuer: *const ThinVec<u8>,
issuerSPKI: *const ThinVec<u8>,
serialNumber: *const ThinVec<u8>,
timestamps: *const ThinVec<RefPtr<nsICRLiteTimestamp>>,
valid_before: *mut u64,
state: *mut i16,
) -> nserror::nsresult {
// TODO (bug 1541212): We really want to restrict this to non-main-threads only, but we
@ -1814,29 +1719,17 @@ impl CertStorage {
if issuer.is_null()
|| issuerSPKI.is_null()
|| serialNumber.is_null()
|| valid_before.is_null()
|| state.is_null()
|| timestamps.is_null()
{
return NS_ERROR_NULL_POINTER;
}
let timestamps = &*timestamps;
let mut timestamp_entries = Vec::with_capacity(timestamps.len());
for timestamp_entry in timestamps {
let mut log_id = ThinVec::with_capacity(32);
try_ns!(timestamp_entry.GetLogID(&mut log_id).to_result(), or continue);
let mut timestamp: u64 = 0;
try_ns!(timestamp_entry.GetTimestamp(&mut timestamp).to_result(), or continue);
timestamp_entries.push(CRLiteTimestamp { log_id, timestamp });
}
*valid_before = 0;
*state = nsICertStorage::STATE_UNSET;
let ss = get_security_state!(self);
match ss.get_crlite_revocation_state(
&*issuer,
&*issuerSPKI,
&*serialNumber,
&timestamp_entries,
) {
Ok(st) => {
match ss.get_crlite_revocation_state(&*issuer, &*issuerSPKI, &*serialNumber) {
Ok((crlite_timestamp, st)) => {
*valid_before = crlite_timestamp;
*state = st;
NS_OK
}

Просмотреть файл

@ -160,10 +160,4 @@ Classes = [
'type': 'nsCertTree',
'legacy_constructor': 'mozilla::psm::NSSConstructor<nsCertTree>',
},
{
'cid': '{9676cfc4-6e84-11ec-a30d-d3cd0af86e01}',
'contract_ids': ['@mozilla.org/security/CRLiteTimestamp;1'],
'type': 'mozilla::psm::CRLiteTimestamp',
'headers': ['/security/certverifier/CRLiteTimestamp.h'],
},
]

Просмотреть файл

@ -70,35 +70,6 @@ interface nsICRLiteState : nsISupports {
readonly attribute short state;
};
/**
* An interface representing a set of certificates that are covered by a CRLite
* filter. The set is represented by a certificate transparency log ID and a
* pair of timestamps. The timestamps are such that the CRLite aggregator has
* seen every certificate from the specified log with an SCT between the two
* timestamps.
* b64LogID is a base 64-encoded RFC 6962 LogID.
* minTimestamp is the smallest timestamp that the CRLite filter covers.
* maxTimestamp is the largest timestamp that the CRLite filter covers.
*/
[scriptable, uuid(416453f7-29bd-4820-a039-9c2e055d3715)]
interface nsICRLiteCoverage : nsISupports {
readonly attribute ACString b64LogID;
readonly attribute unsigned long long minTimestamp;
readonly attribute unsigned long long maxTimestamp;
};
/**
* An interface representing the id and timestamp fields from an RFC 6962
* SignedCertificateTimestamp struct.
* logID is the id field.
* timestamp is the timestamp field.
*/
[uuid(9676cfc4-6e84-11ec-a30d-d3cd0af86e01)]
interface nsICRLiteTimestamp: nsISupports {
readonly attribute Array<octet> logID;
readonly attribute unsigned long long timestamp;
};
/**
* An interface representing a certificate to add to storage. Consists of the
* base64-encoded DER bytes of the certificate (cert), the base64-encoded DER
@ -136,7 +107,6 @@ interface nsICertStorage : nsISupports {
const short STATE_UNSET = 0;
const short STATE_ENFORCE = 1;
const short STATE_NOT_ENROLLED = 2;
const short STATE_NOT_COVERED = 3;
/**
* Asynchronously set the revocation states of a set of certificates.
@ -192,33 +162,34 @@ interface nsICertStorage : nsISupports {
short getCRLiteState(in Array<octet> subject, in Array<octet> spki);
/**
* Given the contents of a new CRLite filter and a description of the new
* filter's coverage, replaces any existing filter with the new one. Also
* clears any previously-set incremental revocation updates ("stashes").
* Given the contents of a CRLite filter and its creation date as seconds since the epoch,
* replaces any existing filter with the new one. Also clears any previously-set incremental
* revocation updates ("stashes").
*/
[must_use]
void setFullCRLiteFilter(in Array<octet> filter,
in Array<nsICRLiteCoverage> coverage,
void setFullCRLiteFilter(in Array<octet> filter, in uint64_t timestamp,
in nsICertStorageCallback callback);
/**
* Given the DER-encoded issuer distinguished name, DER-encoded issuer subject public key info,
* the bytes of the value of the serial number (so, not including the DER tag and length) of a
* certificate, and the timestamps from that certificate's embedded SCTs, returns the result of
* looking up the corresponding entry in the currently-saved CRLite filter (if any).
* Returns
* - STATE_ENFORCE if the lookup indicates the certificate is revoked via CRLite,
* - STATE_UNSET if the lookup indicates the certificate is not revoked via CRLite,
* - STATE_NOT_ENROLLED if the issuer is not enrolled in CRLite, or
* - STATE_NOT_COVERED if the issuer is enrolled but the provided timestamps indicate
* that the serial number is not covered by the current CRLite filter.
* No lookup is performed in the STATE_NOT_ENROLLED and STATE_NOT_COVERED cases.
* and the bytes of the value of the serial number (so, not including the DER tag and length) of a
* certificate, returns the result of looking up the corresponding entry in the currently-saved
* CRLite filter (if any). Returns STATE_ENFORCE if the lookup indicates the corresponding
* certificate is revoked via CRLite. Returns STATE_UNSET if the lookup indicates the
* corresponding certificate is not revoked via CRLite. Returns STATE_NOT_ENROLLED if the issuer
* certificate is not enrolled in CRLite and thus no lookup was made. Also returns the timestamp
* before which lookups will be valid. That is, if a certificate has a notBefore value after the
* returned filter timestamp, the lookup is not trustworthy because the certificate may have been
* created after the filter, and thus it may cause a false negative or positive. If no filter is
* available (it may not have been downloaded yet), validBefore will be 0. The timestamp is
* represented as seconds since the epoch (i.e. it returns what was most recently set via
* setFullCRLiteFilter).
*/
[must_use]
short getCRLiteRevocationState(in Array<octet> issuer,
in Array<octet> issuerSPKI,
in Array<octet> serialNumber,
in Array<nsICRLiteTimestamp> timestamps);
out uint64_t validBefore);
/**
* Given the contents of a CRLite incremental revocation update ("stash"), adds the revocation

Просмотреть файл

@ -1546,6 +1546,16 @@ void nsNSSComponent::setValidationOptions(
break;
}
uint32_t defaultCRLiteCTMergeDelaySeconds =
60 * 60 * 28; // 28 hours in seconds
uint64_t maxCRLiteCTMergeDelaySeconds = 60 * 60 * 24 * 365;
uint64_t crliteCTMergeDelaySeconds =
Preferences::GetUint("security.pki.crlite_ct_merge_delay_seconds",
defaultCRLiteCTMergeDelaySeconds);
if (crliteCTMergeDelaySeconds > maxCRLiteCTMergeDelaySeconds) {
crliteCTMergeDelaySeconds = maxCRLiteCTMergeDelaySeconds;
}
CertVerifier::OcspDownloadConfig odc;
CertVerifier::OcspStrictConfig osc;
uint32_t certShortLifetimeInDays;
@ -1558,7 +1568,7 @@ void nsNSSComponent::setValidationOptions(
mDefaultCertVerifier = new SharedCertVerifier(
odc, osc, softTimeout, hardTimeout, certShortLifetimeInDays, sha1Mode,
PublicSSLState()->NameMatchingMode(), netscapeStepUpPolicy, ctMode,
crliteMode, mEnterpriseCerts);
crliteMode, crliteCTMergeDelaySeconds, mEnterpriseCerts);
}
void nsNSSComponent::UpdateCertVerifierWithEnterpriseRoots() {
@ -1577,7 +1587,8 @@ void nsNSSComponent::UpdateCertVerifierWithEnterpriseRoots() {
oldCertVerifier->mCertShortLifetimeInDays, oldCertVerifier->mSHA1Mode,
oldCertVerifier->mNameMatchingMode,
oldCertVerifier->mNetscapeStepUpPolicy, oldCertVerifier->mCTMode,
oldCertVerifier->mCRLiteMode, mEnterpriseCerts);
oldCertVerifier->mCRLiteMode, oldCertVerifier->mCRLiteCTMergeDelaySeconds,
mEnterpriseCerts);
}
// Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and
@ -2389,7 +2400,9 @@ nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
"security.OCSP.timeoutMilliseconds.soft") ||
prefName.EqualsLiteral(
"security.OCSP.timeoutMilliseconds.hard") ||
prefName.EqualsLiteral("security.pki.crlite_mode")) {
prefName.EqualsLiteral("security.pki.crlite_mode") ||
prefName.EqualsLiteral(
"security.pki.crlite_ct_merge_delay_seconds")) {
MutexAutoLock lock(mMutex);
setValidationOptions(false, lock);
#ifdef DEBUG

Просмотреть файл

@ -253,17 +253,6 @@ CRLiteState.prototype.QueryInterface = ChromeUtils.generateQI([
"nsICRLiteState",
]);
class CRLiteCoverage {
constructor(ctLogID, minTimestamp, maxTimestamp) {
this.b64LogID = ctLogID;
this.minTimestamp = minTimestamp;
this.maxTimestamp = maxTimestamp;
}
}
CRLiteCoverage.prototype.QueryInterface = ChromeUtils.generateQI([
"nsICRLiteCoverage",
]);
async function addCRLiteState(state) {
let result = await new Promise(resolve => {
certStorage.setCRLiteState(state, resolve);
@ -415,12 +404,15 @@ add_task(async function test_crlite_filter() {
false
);
ok(filterFile.exists(), "test filter file should exist");
let coverage = [];
let filterBytes = stringToArray(readFile(filterFile));
// First simualte a filter that does not cover any certificates. With CRLite
// enabled, none of the certificates should appear to be revoked.
// First simulate the filter being from before the certificates being tested are valid. With
// CRLite enabled, none of the certificates should appear to be revoked.
let setFullCRLiteFilterResult = await new Promise(resolve => {
certStorage.setFullCRLiteFilter(filterBytes, coverage, resolve);
certStorage.setFullCRLiteFilter(
filterBytes,
new Date("2017-10-28T00:00:00Z").getTime() / 1000,
resolve
);
});
Assert.equal(
setFullCRLiteFilterResult,
@ -453,18 +445,13 @@ add_task(async function test_crlite_filter() {
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
);
// Now replace the filter with one that covers the "valid" and "revoked"
// certificates. CRLite should flag the revoked certificate.
coverage.push(
new CRLiteCoverage(
"pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA=",
0,
1641612275000
)
);
// Now "replace" the filter with a more recent one. The revoked certificate should be revoked.
setFullCRLiteFilterResult = await new Promise(resolve => {
certStorage.setFullCRLiteFilter(filterBytes, coverage, resolve);
certStorage.setFullCRLiteFilter(
filterBytes,
new Date("2019-10-28T00:00:00Z").getTime() / 1000,
resolve
);
});
Assert.equal(
setFullCRLiteFilterResult,

Просмотреть файл

@ -27,10 +27,6 @@ add_task(async function() {
"test_cert_storage_preexisting_crlite/crlite.filter"
);
crliteFile.copyTo(dbDirectory, "crlite.filter");
let coverageFile = do_get_file(
"test_cert_storage_preexisting_crlite/crlite.coverage"
);
coverageFile.copyTo(dbDirectory, "crlite.coverage");
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
Ci.nsICertStorage

Двоичный файл не отображается.

Просмотреть файл

@ -8,6 +8,9 @@
"use strict";
do_get_profile(); // must be called before getting nsIX509CertDB
const { RemoteSettings } = ChromeUtils.import(
"resource://services-settings/remote-settings.js"
);
const { RemoteSecuritySettings } = ChromeUtils.import(
"resource://gre/modules/psm/RemoteSecuritySettings.jsm"
);
@ -97,7 +100,6 @@ async function syncAndDownload(filters, clear = true) {
effectiveTimestamp: new Date(filter.timestamp).getTime(),
parent: filter.type == "diff" ? filter.parent : undefined,
id: filter.id,
coverage: filter.type == "full" ? filter.coverage : undefined,
};
await localDB.create(record);
@ -116,18 +118,7 @@ add_task(async function test_crlite_filters_disabled() {
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, false);
let result = await syncAndDownload([
{
timestamp: "2019-01-01T00:00:00Z",
type: "full",
id: "0000",
coverage: [
{
LogID: "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
MinTimestamp: 0,
MaxTimestamp: 9999999999999,
},
],
},
{ timestamp: "2019-01-01T00:00:00Z", type: "full", id: "0000" },
]);
equal(result, "disabled", "CRLite filter download should not have run");
});
@ -397,23 +388,7 @@ add_task(async function test_crlite_filters_and_check_revocation() {
});
let result = await syncAndDownload([
{
timestamp: "2020-10-17T00:00:00Z",
type: "full",
id: "0000",
coverage: [
{
LogID: "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
MinTimestamp: 0,
MaxTimestamp: 9999999999999,
},
{
LogID: "pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA=",
MinTimestamp: 0,
MaxTimestamp: 9999999999999,
},
],
},
{ timestamp: "2020-10-17T00:00:00Z", type: "full", id: "0000" },
]);
equal(
result,
@ -598,36 +573,20 @@ add_task(async function test_crlite_filters_and_check_revocation() {
Services.prefs.clearUserPref("security.OCSP.require");
Services.prefs.clearUserPref("security.OCSP.enabled");
// The revoked certificate example has one SCT from the log with ID "9ly...="
// at time 1598140096613 and another from the log with ID "XNx...=" at time
// 1598140096917. The filter we construct here fails to cover it by one
// millisecond in each case. The implementation will fall back to OCSP
// fetching. Since this would result in a crash and test failure, the
// Ci.nsIX509CertDB.FLAG_LOCAL_ONLY is used.
result = await syncAndDownload([
{
timestamp: "2020-10-17T00:00:00Z",
type: "full",
id: "0000",
coverage: [
{
LogID: "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
MinTimestamp: 0,
MaxTimestamp: 1598140096612,
},
{
LogID: "XNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbHDso=",
MinTimestamp: 1598140096917,
MaxTimestamp: 9999999999999,
},
],
},
]);
equal(
result,
"finished;2020-10-17T00:00:00Z-full",
"CRLite filter download should have run"
// If the earliest certificate timestamp is within the merge delay of the
// logs for the filter we have, it won't be looked up, and thus won't be
// revoked.
// The earliest timestamp in this certificate is in August 2020, whereas
// the filter timestamp is in October 2020, so setting the merge delay to
// this large value simluates the situation being tested.
Services.prefs.setIntPref(
"security.pki.crlite_ct_merge_delay_seconds",
60 * 60 * 24 * 60
);
// Since setting the merge delay parameter this way effectively makes this
// certificate "too new" to be covered by the filter, the implementation
// would fall back to OCSP fetching. Since this would result in a crash and
// test failure, the Ci.nsIX509CertDB.FLAG_LOCAL_ONLY is used.
await checkCertErrorGenericAtTime(
certdb,
revokedCert,
@ -638,24 +597,14 @@ add_task(async function test_crlite_filters_and_check_revocation() {
"us-datarecovery.com",
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
);
Services.prefs.clearUserPref("security.pki.crlite_ct_merge_delay_seconds");
});
add_task(async function test_crlite_filters_avoid_reprocessing_filters() {
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
let result = await syncAndDownload([
{
timestamp: "2019-01-01T00:00:00Z",
type: "full",
id: "0000",
coverage: [
{
LogID: "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
MinTimestamp: 0,
MaxTimestamp: 9999999999999,
},
],
},
{ timestamp: "2019-01-01T00:00:00Z", type: "full", id: "0000" },
{
timestamp: "2019-01-01T06:00:00Z",
type: "diff",

Просмотреть файл

@ -1,38 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIGpzCCBY+gAwIBAgIIfLPIa/Mc/f4wDQYJKoZIhvcNAQELBQAwgbQxCzAJBgNV
BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRow
GAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UECxMkaHR0cDovL2NlcnRz
LmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQDEypHbyBEYWRkeSBTZWN1
cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwHhcNMjIwMTA2MDA1MTI5WhcN
MjMwMjA0MTUxNjQwWjAeMRwwGgYDVQQDExNwZWVrYWJvb3Bob25pY3MuY29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuCKkB+36Yd/mBwwlq/F+B2R/
ibNdUncADG1+xCB21TB6H0UWR1Aj92ZsIKXwXIyhj02VT58y0Oh4eycsMtEi/lLq
KXhpWjRAMZaxjdyIrSJxpQVXC3v8Taej6PG2RewGMA3uXj+oWfl7t25JnEes1l2n
JOnDXs5w4K0aDD1+r7wqCgZA7evmmdK3WJMWD/GSeF2hYcXFgb5dM2TiSRBGkv/9
jMAvOSuJO8/kxKHLtLfM4I3O0gugB5Uyxtn5a6+P4vOphozsYgHqnSapCV8eAEN2
SWRhFpfwsbt6/Dw/k38F2A5axSF0n+IQ49ejtWjs+f/GNTloieTsDbcpKkDSEwID
AQABo4IDUDCCA0wwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwDgYDVR0PAQH/BAQDAgWgMDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6
Ly9jcmwuZ29kYWRkeS5jb20vZ2RpZzJzMS0zNzEwLmNybDBdBgNVHSAEVjBUMEgG
C2CGSAGG/W0BBxcBMDkwNwYIKwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu
Z29kYWRkeS5jb20vcmVwb3NpdG9yeS8wCAYGZ4EMAQIBMHYGCCsGAQUFBwEBBGow
aDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMEAGCCsGAQUF
BzAChjRodHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv
Z2RpZzIuY3J0MB8GA1UdIwQYMBaAFEDCvSeOzDSDMKIz1/tss/C0LIDOMDcGA1Ud
EQQwMC6CE3BlZWthYm9vcGhvbmljcy5jb22CF3d3dy5wZWVrYWJvb3Bob25pY3Mu
Y29tMB0GA1UdDgQWBBRElZlefxDT9BFjvpeq7zP6TlVv+TCCAYEGCisGAQQB1nkC
BAIEggFxBIIBbQFrAHcA6D7Q2j71BjUy51covIlryQPTy9ERa+zraeF3fW0GvW4A
AAF+LN6rOQAABAMASDBGAiEAssjNEfjNFhpQmiFRCFZSr1zZk7ISWHqPIzoghyZ+
UbgCIQDB6iKxtMkpx1I9P9uL40M93xynsb/3DVl1OX8pSO1n9gB3ADXPGRu/sWxX
vw+tTG1Cy7u2JyAmUeo/4SrvqAPDO9ZMAAABfizerPwAAAQDAEgwRgIhANUhPyqm
inLVPy1zUqikc64dwi0P/nvCoNtC1gO2cDHgAiEAjv1Gw04htq5OyTP3XYQTHsZW
h35omGu+WCS68t8LnIEAdwB6MoxU2LcttiDqOOBSHumEFnAyE4VNO9IrwTpXo1Lr
UgAAAX4s3q2BAAAEAwBIMEYCIQDqxot9iMPghZbHZSegX98g1o5dvSsG1azMv290
Cp+sBgIhALiMl5lj1A3nWkHTQKF9bF3ops5/ZxxJYE7XwBxlkZYYMA0GCSqGSIb3
DQEBCwUAA4IBAQAOfIC7VLhn3oBYQKTzX4CN+249JN7l5tbSMqC2zjKRjOWOF3p/
yNb2gk/v6EW0xN024E2yo8K4XF+QJMfzlwpsed1yuziYHIpjeiad7JGUs/57jdCo
EUQrvwkuIeR5CZrGcXKG8nlVM5SaNhmId8XixnJz7XfEWiCxszlRkXIZ4Uhpwz2D
XhQ8RE1DhwX3x6oO5y9Eu6o6+bz2Y14E0lL4hCng09UmrOFEUzVcO4bK8qsSp9oe
1NNPlMQ3SD6RlGBy+2O5Iy8Kj4BRv2US2stuDeZWSvxp6N2RwLGBnDTyT08VAFD5
SkulqE2/r6AHWNMe649z1clhq14i1+kQjEq5
-----END CERTIFICATE-----

Просмотреть файл

@ -123,19 +123,31 @@ add_task(async function test_preexisting_crlite_data() {
Services.prefs.clearUserPref("security.OCSP.require");
Services.prefs.clearUserPref("security.OCSP.enabled");
let notCoveredCert = constructCertFromFile(
"test_crlite_filters/notcovered.pem"
// If the earliest certificate timestamp is within the merge delay of the
// logs for the filter we have, it won't be looked up, and thus won't be
// revoked.
// The earliest timestamp in this certificate is in August 2020, whereas
// the filter timestamp is in October 2020, so setting the merge delay to
// this large value simluates the situation being tested.
Services.prefs.setIntPref(
"security.pki.crlite_ct_merge_delay_seconds",
60 * 60 * 24 * 60
);
// Since setting the merge delay parameter this way effectively makes this
// certificate "too new" to be covered by the filter, the implementation
// would fall back to OCSP fetching. Since this would result in a crash and
// test failure, the Ci.nsIX509CertDB.FLAG_LOCAL_ONLY is used.
await checkCertErrorGenericAtTime(
certdb,
notCoveredCert,
revokedCert,
PRErrorCodeSuccess,
certificateUsageSSLServer,
new Date("2022-01-07T00:00:00Z").getTime() / 1000,
new Date("2020-10-20T00:00:00Z").getTime() / 1000,
false,
"peekaboophonics.com",
"us-datarecovery.com",
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
);
Services.prefs.clearUserPref("security.pki.crlite_ct_merge_delay_seconds");
});
function run_test() {
@ -151,8 +163,6 @@ function run_test() {
// profile directory.
let stashFile = do_get_file("test_crlite_preexisting/crlite.stash");
stashFile.copyTo(securityStateDirectory, "crlite.stash");
let coverageFile = do_get_file("test_crlite_preexisting/crlite.coverage");
coverageFile.copyTo(securityStateDirectory, "crlite.coverage");
let certStorageFile = do_get_file("test_crlite_preexisting/data.safe.bin");
certStorageFile.copyTo(securityStateDirectory, "data.safe.bin");

Двоичный файл не отображается.