зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset d4a6f5cb9b3f (bug 1747320) for breaking connectivity with many https sites (bug 1750188) a=backout
This commit is contained in:
Родитель
71bbf38c5a
Коммит
4475b51bcb
|
@ -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(×tamp.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,
|
||||
×tamp_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");
|
||||
|
||||
|
|
Двоичный файл не отображается.
Загрузка…
Ссылка в новой задаче