зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1876435 - gather telemetry on the sources of issuer certificates r=jschanck
Differential Revision: https://phabricator.services.mozilla.com/D199599
This commit is contained in:
Родитель
2694839f3b
Коммит
61cba1c84d
|
@ -452,7 +452,8 @@ Result CertVerifier::VerifyCert(
|
||||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
|
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
|
||||||
/*optional out*/ CertificateTransparencyInfo* ctInfo,
|
/*optional out*/ CertificateTransparencyInfo* ctInfo,
|
||||||
/*optional out*/ bool* isBuiltChainRootBuiltInRoot,
|
/*optional out*/ bool* isBuiltChainRootBuiltInRoot,
|
||||||
/*optional out*/ bool* madeOCSPRequests) {
|
/*optional out*/ bool* madeOCSPRequests,
|
||||||
|
/*optional out*/ IssuerSources* issuerSources) {
|
||||||
MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Top of VerifyCert\n"));
|
MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Top of VerifyCert\n"));
|
||||||
|
|
||||||
MOZ_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
|
MOZ_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
|
||||||
|
@ -494,6 +495,10 @@ Result CertVerifier::VerifyCert(
|
||||||
*madeOCSPRequests = false;
|
*madeOCSPRequests = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (issuerSources) {
|
||||||
|
issuerSources->clear();
|
||||||
|
}
|
||||||
|
|
||||||
Input certDER;
|
Input certDER;
|
||||||
Result rv = certDER.Init(certBytes.Elements(), certBytes.Length());
|
Result rv = certDER.Init(certBytes.Elements(), certBytes.Length());
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
|
@ -584,6 +589,9 @@ Result CertVerifier::VerifyCert(
|
||||||
*madeOCSPRequests |=
|
*madeOCSPRequests |=
|
||||||
trustDomain.GetOCSPFetchStatus() == OCSPFetchStatus::Fetched;
|
trustDomain.GetOCSPFetchStatus() == OCSPFetchStatus::Fetched;
|
||||||
}
|
}
|
||||||
|
if (issuerSources) {
|
||||||
|
*issuerSources = trustDomain.GetIssuerSources();
|
||||||
|
}
|
||||||
if (rv == Success) {
|
if (rv == Success) {
|
||||||
rv = VerifyCertificateTransparencyPolicy(
|
rv = VerifyCertificateTransparencyPolicy(
|
||||||
trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
|
trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
|
||||||
|
@ -643,6 +651,9 @@ Result CertVerifier::VerifyCert(
|
||||||
*madeOCSPRequests |=
|
*madeOCSPRequests |=
|
||||||
trustDomain.GetOCSPFetchStatus() == OCSPFetchStatus::Fetched;
|
trustDomain.GetOCSPFetchStatus() == OCSPFetchStatus::Fetched;
|
||||||
}
|
}
|
||||||
|
if (issuerSources) {
|
||||||
|
*issuerSources = trustDomain.GetIssuerSources();
|
||||||
|
}
|
||||||
if (rv != Success && !IsFatalError(rv) &&
|
if (rv != Success && !IsFatalError(rv) &&
|
||||||
rv != Result::ERROR_REVOKED_CERTIFICATE &&
|
rv != Result::ERROR_REVOKED_CERTIFICATE &&
|
||||||
trustDomain.GetIsErrorDueToDistrustedCAPolicy()) {
|
trustDomain.GetIsErrorDueToDistrustedCAPolicy()) {
|
||||||
|
@ -807,7 +818,8 @@ Result CertVerifier::VerifySSLServerCert(
|
||||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
|
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
|
||||||
/*optional out*/ CertificateTransparencyInfo* ctInfo,
|
/*optional out*/ CertificateTransparencyInfo* ctInfo,
|
||||||
/*optional out*/ bool* isBuiltChainRootBuiltInRoot,
|
/*optional out*/ bool* isBuiltChainRootBuiltInRoot,
|
||||||
/*optional out*/ bool* madeOCSPRequests) {
|
/*optional out*/ bool* madeOCSPRequests,
|
||||||
|
/*optional out*/ IssuerSources* issuerSources) {
|
||||||
// XXX: MOZ_ASSERT(pinarg);
|
// XXX: MOZ_ASSERT(pinarg);
|
||||||
MOZ_ASSERT(!hostname.IsEmpty());
|
MOZ_ASSERT(!hostname.IsEmpty());
|
||||||
|
|
||||||
|
@ -832,12 +844,12 @@ Result CertVerifier::VerifySSLServerCert(
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
bool isBuiltChainRootBuiltInRootLocal;
|
bool isBuiltChainRootBuiltInRootLocal;
|
||||||
rv = VerifyCert(peerCertBytes, certificateUsageSSLServer, time, pinarg,
|
rv = VerifyCert(
|
||||||
PromiseFlatCString(hostname).get(), builtChain, flags,
|
peerCertBytes, certificateUsageSSLServer, time, pinarg,
|
||||||
extraCertificates, stapledOCSPResponse, sctsFromTLS,
|
PromiseFlatCString(hostname).get(), builtChain, flags, extraCertificates,
|
||||||
originAttributes, evStatus, ocspStaplingStatus, keySizeStatus,
|
stapledOCSPResponse, sctsFromTLS, originAttributes, evStatus,
|
||||||
pinningTelemetryInfo, ctInfo,
|
ocspStaplingStatus, keySizeStatus, pinningTelemetryInfo, ctInfo,
|
||||||
&isBuiltChainRootBuiltInRootLocal, madeOCSPRequests);
|
&isBuiltChainRootBuiltInRootLocal, madeOCSPRequests, issuerSources);
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
// we don't use the certificate for path building, so this parameter doesn't
|
// we don't use the certificate for path building, so this parameter doesn't
|
||||||
// matter
|
// matter
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "OCSPCache.h"
|
#include "OCSPCache.h"
|
||||||
#include "RootCertificateTelemetryUtils.h"
|
#include "RootCertificateTelemetryUtils.h"
|
||||||
#include "ScopedNSSTypes.h"
|
#include "ScopedNSSTypes.h"
|
||||||
|
#include "mozilla/EnumSet.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "mozilla/TimeStamp.h"
|
#include "mozilla/TimeStamp.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
|
@ -70,6 +71,17 @@ enum class CRLiteMode {
|
||||||
|
|
||||||
enum class NetscapeStepUpPolicy : uint32_t;
|
enum class NetscapeStepUpPolicy : uint32_t;
|
||||||
|
|
||||||
|
// Describes the source of the associated issuer.
|
||||||
|
enum class IssuerSource {
|
||||||
|
TLSHandshake, // included by the peer in the TLS handshake
|
||||||
|
PreloadedIntermediates, // a preloaded intermediate (via remote settings)
|
||||||
|
ThirdPartyCertificates, // a third-party certificate gleaned from the OS
|
||||||
|
NSSCertDB, // a certificate found in the profile's NSS certificate DB
|
||||||
|
BuiltInRootsModule, // a root from the built-in roots module
|
||||||
|
};
|
||||||
|
|
||||||
|
using IssuerSources = EnumSet<IssuerSource>;
|
||||||
|
|
||||||
class PinningTelemetryInfo {
|
class PinningTelemetryInfo {
|
||||||
public:
|
public:
|
||||||
PinningTelemetryInfo()
|
PinningTelemetryInfo()
|
||||||
|
@ -163,7 +175,8 @@ class CertVerifier {
|
||||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
|
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
|
||||||
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
|
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
|
||||||
/*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr,
|
/*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr,
|
||||||
/*optional out*/ bool* madeOCSPRequests = nullptr);
|
/*optional out*/ bool* madeOCSPRequests = nullptr,
|
||||||
|
/*optional out*/ IssuerSources* = nullptr);
|
||||||
|
|
||||||
mozilla::pkix::Result VerifySSLServerCert(
|
mozilla::pkix::Result VerifySSLServerCert(
|
||||||
const nsTArray<uint8_t>& peerCert, mozilla::pkix::Time time, void* pinarg,
|
const nsTArray<uint8_t>& peerCert, mozilla::pkix::Time time, void* pinarg,
|
||||||
|
@ -184,7 +197,8 @@ class CertVerifier {
|
||||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
|
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
|
||||||
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
|
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
|
||||||
/*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr,
|
/*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr,
|
||||||
/*optional out*/ bool* madeOCSPRequests = nullptr);
|
/*optional out*/ bool* madeOCSPRequests = nullptr,
|
||||||
|
/*optional out*/ IssuerSources* = nullptr);
|
||||||
|
|
||||||
enum OcspDownloadConfig { ocspOff = 0, ocspOn = 1, ocspEVOnly = 2 };
|
enum OcspDownloadConfig { ocspOff = 0, ocspOn = 1, ocspEVOnly = 2 };
|
||||||
enum OcspStrictConfig { ocspRelaxed = 0, ocspStrict };
|
enum OcspStrictConfig { ocspRelaxed = 0, ocspStrict };
|
||||||
|
|
|
@ -137,8 +137,7 @@ static void FindRootsWithSubject(UniqueSECMODModule& rootsModule,
|
||||||
// certificate extensions we support are restrictive rather than additive in
|
// certificate extensions we support are restrictive rather than additive in
|
||||||
// terms of the rest of the chain (for example, we don't support policy mapping
|
// terms of the rest of the chain (for example, we don't support policy mapping
|
||||||
// and we ignore any SCT information in intermediates).
|
// and we ignore any SCT information in intermediates).
|
||||||
static bool ShouldSkipSelfSignedNonTrustAnchor(TrustDomain& trustDomain,
|
bool NSSCertDBTrustDomain::ShouldSkipSelfSignedNonTrustAnchor(Input certDER) {
|
||||||
Input certDER) {
|
|
||||||
BackCert cert(certDER, EndEntityOrCA::MustBeCA, nullptr);
|
BackCert cert(certDER, EndEntityOrCA::MustBeCA, nullptr);
|
||||||
if (cert.Init() != Success) {
|
if (cert.Init() != Success) {
|
||||||
return false; // turn any failures into "don't skip trying this cert"
|
return false; // turn any failures into "don't skip trying this cert"
|
||||||
|
@ -148,8 +147,8 @@ static bool ShouldSkipSelfSignedNonTrustAnchor(TrustDomain& trustDomain,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TrustLevel trust;
|
TrustLevel trust;
|
||||||
if (trustDomain.GetCertTrust(EndEntityOrCA::MustBeCA, CertPolicyId::anyPolicy,
|
if (GetCertTrust(EndEntityOrCA::MustBeCA, CertPolicyId::anyPolicy, certDER,
|
||||||
certDER, trust) != Success) {
|
trust) != Success) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// If the trust for this certificate is anything other than "inherit", we want
|
// If the trust for this certificate is anything other than "inherit", we want
|
||||||
|
@ -157,7 +156,7 @@ static bool ShouldSkipSelfSignedNonTrustAnchor(TrustDomain& trustDomain,
|
||||||
if (trust != TrustLevel::InheritsTrust) {
|
if (trust != TrustLevel::InheritsTrust) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (VerifySignedData(trustDomain, cert.GetSignedData(),
|
if (VerifySignedData(*this, cert.GetSignedData(),
|
||||||
cert.GetSubjectPublicKeyInfo()) != Success) {
|
cert.GetSubjectPublicKeyInfo()) != Success) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -166,24 +165,25 @@ static bool ShouldSkipSelfSignedNonTrustAnchor(TrustDomain& trustDomain,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result CheckCandidates(TrustDomain& trustDomain,
|
Result NSSCertDBTrustDomain::CheckCandidates(
|
||||||
TrustDomain::IssuerChecker& checker,
|
IssuerChecker& checker, nsTArray<IssuerCandidateWithSource>& candidates,
|
||||||
nsTArray<Input>& candidates,
|
|
||||||
Input* nameConstraintsInputPtr, bool& keepGoing) {
|
Input* nameConstraintsInputPtr, bool& keepGoing) {
|
||||||
for (Input candidate : candidates) {
|
for (const auto& candidate : candidates) {
|
||||||
// Stop path building if the program is shutting down.
|
// Stop path building if the program is shutting down.
|
||||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
|
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
|
||||||
keepGoing = false;
|
keepGoing = false;
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
if (ShouldSkipSelfSignedNonTrustAnchor(trustDomain, candidate)) {
|
if (ShouldSkipSelfSignedNonTrustAnchor(candidate.mDER)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Result rv = checker.Check(candidate, nameConstraintsInputPtr, keepGoing);
|
Result rv =
|
||||||
|
checker.Check(candidate.mDER, nameConstraintsInputPtr, keepGoing);
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
if (!keepGoing) {
|
if (!keepGoing) {
|
||||||
|
mIssuerSources += candidate.mIssuerSource;
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,29 +212,8 @@ Result NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
|
||||||
|
|
||||||
// First try all relevant certificates known to Gecko, which avoids calling
|
// First try all relevant certificates known to Gecko, which avoids calling
|
||||||
// CERT_CreateSubjectCertList, because that can be expensive.
|
// CERT_CreateSubjectCertList, because that can be expensive.
|
||||||
nsTArray<Input> geckoRootCandidates;
|
nsTArray<IssuerCandidateWithSource> geckoRootCandidates;
|
||||||
nsTArray<Input> geckoIntermediateCandidates;
|
nsTArray<IssuerCandidateWithSource> geckoIntermediateCandidates;
|
||||||
|
|
||||||
if (!mCertStorage) {
|
|
||||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
|
||||||
}
|
|
||||||
nsTArray<uint8_t> subject;
|
|
||||||
subject.AppendElements(encodedIssuerName.UnsafeGetData(),
|
|
||||||
encodedIssuerName.GetLength());
|
|
||||||
nsTArray<nsTArray<uint8_t>> certs;
|
|
||||||
nsresult rv = mCertStorage->FindCertsBySubject(subject, certs);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
|
||||||
}
|
|
||||||
for (auto& cert : certs) {
|
|
||||||
Input certDER;
|
|
||||||
Result rv = certDER.Init(cert.Elements(), cert.Length());
|
|
||||||
if (rv != Success) {
|
|
||||||
continue; // probably too big
|
|
||||||
}
|
|
||||||
// Currently we're only expecting intermediate certificates in cert storage.
|
|
||||||
geckoIntermediateCandidates.AppendElement(std::move(certDER));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We might not have this module if e.g. we're on a Linux distribution that
|
// We might not have this module if e.g. we're on a Linux distribution that
|
||||||
// does something unexpected.
|
// does something unexpected.
|
||||||
|
@ -248,45 +227,14 @@ Result NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
continue; // probably too big
|
continue; // probably too big
|
||||||
}
|
}
|
||||||
geckoRootCandidates.AppendElement(rootInput);
|
geckoRootCandidates.AppendElement(IssuerCandidateWithSource{
|
||||||
|
rootInput, IssuerSource::BuiltInRootsModule});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
||||||
("NSSCertDBTrustDomain::FindIssuer: no built-in roots module"));
|
("NSSCertDBTrustDomain::FindIssuer: no built-in roots module"));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& thirdPartyRootInput : mThirdPartyRootInputs) {
|
|
||||||
BackCert root(thirdPartyRootInput, EndEntityOrCA::MustBeCA, nullptr);
|
|
||||||
Result rv = root.Init();
|
|
||||||
if (rv != Success) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Filter out 3rd party roots that can't be issuers we're looking for
|
|
||||||
// because the subject distinguished name doesn't match. This prevents
|
|
||||||
// mozilla::pkix from accumulating spurious errors during path building.
|
|
||||||
if (!InputsAreEqual(encodedIssuerName, root.GetSubject())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
geckoRootCandidates.AppendElement(thirdPartyRootInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& thirdPartyIntermediateInput :
|
|
||||||
mThirdPartyIntermediateInputs) {
|
|
||||||
BackCert intermediate(thirdPartyIntermediateInput, EndEntityOrCA::MustBeCA,
|
|
||||||
nullptr);
|
|
||||||
Result rv = intermediate.Init();
|
|
||||||
if (rv != Success) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Filter out 3rd party intermediates that can't be issuers we're looking
|
|
||||||
// for because the subject distinguished name doesn't match. This prevents
|
|
||||||
// mozilla::pkix from accumulating spurious errors during path building.
|
|
||||||
if (!InputsAreEqual(encodedIssuerName, intermediate.GetSubject())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
geckoIntermediateCandidates.AppendElement(thirdPartyIntermediateInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mExtraCertificates.isSome()) {
|
if (mExtraCertificates.isSome()) {
|
||||||
for (const auto& extraCert : *mExtraCertificates) {
|
for (const auto& extraCert : *mExtraCertificates) {
|
||||||
Input certInput;
|
Input certInput;
|
||||||
|
@ -307,15 +255,72 @@ Result NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
|
||||||
}
|
}
|
||||||
// We assume that extra certificates (presumably from the TLS handshake)
|
// We assume that extra certificates (presumably from the TLS handshake)
|
||||||
// are intermediates, since sending trust anchors would be superfluous.
|
// are intermediates, since sending trust anchors would be superfluous.
|
||||||
geckoIntermediateCandidates.AppendElement(certInput);
|
geckoIntermediateCandidates.AppendElement(
|
||||||
|
IssuerCandidateWithSource{certInput, IssuerSource::TLSHandshake});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& thirdPartyRootInput : mThirdPartyRootInputs) {
|
||||||
|
BackCert root(thirdPartyRootInput, EndEntityOrCA::MustBeCA, nullptr);
|
||||||
|
Result rv = root.Init();
|
||||||
|
if (rv != Success) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Filter out 3rd party roots that can't be issuers we're looking for
|
||||||
|
// because the subject distinguished name doesn't match. This prevents
|
||||||
|
// mozilla::pkix from accumulating spurious errors during path building.
|
||||||
|
if (!InputsAreEqual(encodedIssuerName, root.GetSubject())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
geckoRootCandidates.AppendElement(IssuerCandidateWithSource{
|
||||||
|
thirdPartyRootInput, IssuerSource::ThirdPartyCertificates});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& thirdPartyIntermediateInput :
|
||||||
|
mThirdPartyIntermediateInputs) {
|
||||||
|
BackCert intermediate(thirdPartyIntermediateInput, EndEntityOrCA::MustBeCA,
|
||||||
|
nullptr);
|
||||||
|
Result rv = intermediate.Init();
|
||||||
|
if (rv != Success) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Filter out 3rd party intermediates that can't be issuers we're looking
|
||||||
|
// for because the subject distinguished name doesn't match. This prevents
|
||||||
|
// mozilla::pkix from accumulating spurious errors during path building.
|
||||||
|
if (!InputsAreEqual(encodedIssuerName, intermediate.GetSubject())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
geckoIntermediateCandidates.AppendElement(IssuerCandidateWithSource{
|
||||||
|
thirdPartyIntermediateInput, IssuerSource::ThirdPartyCertificates});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mCertStorage) {
|
||||||
|
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||||
|
}
|
||||||
|
nsTArray<uint8_t> subject;
|
||||||
|
subject.AppendElements(encodedIssuerName.UnsafeGetData(),
|
||||||
|
encodedIssuerName.GetLength());
|
||||||
|
nsTArray<nsTArray<uint8_t>> certs;
|
||||||
|
nsresult rv = mCertStorage->FindCertsBySubject(subject, certs);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||||
|
}
|
||||||
|
for (auto& cert : certs) {
|
||||||
|
Input certDER;
|
||||||
|
Result rv = certDER.Init(cert.Elements(), cert.Length());
|
||||||
|
if (rv != Success) {
|
||||||
|
continue; // probably too big
|
||||||
|
}
|
||||||
|
// Currently we're only expecting intermediate certificates in cert storage.
|
||||||
|
geckoIntermediateCandidates.AppendElement(IssuerCandidateWithSource{
|
||||||
|
std::move(certDER), IssuerSource::PreloadedIntermediates});
|
||||||
|
}
|
||||||
|
|
||||||
// Try all root certs first and then all (presumably) intermediates.
|
// Try all root certs first and then all (presumably) intermediates.
|
||||||
geckoRootCandidates.AppendElements(std::move(geckoIntermediateCandidates));
|
geckoRootCandidates.AppendElements(std::move(geckoIntermediateCandidates));
|
||||||
|
|
||||||
bool keepGoing = true;
|
bool keepGoing = true;
|
||||||
Result result = CheckCandidates(*this, checker, geckoRootCandidates,
|
Result result = CheckCandidates(checker, geckoRootCandidates,
|
||||||
nameConstraintsInputPtr, keepGoing);
|
nameConstraintsInputPtr, keepGoing);
|
||||||
if (result != Success) {
|
if (result != Success) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -365,14 +370,15 @@ Result NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
|
||||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<Input> nssCandidates;
|
nsTArray<IssuerCandidateWithSource> nssCandidates;
|
||||||
for (const auto& rootCandidate : nssRootCandidates) {
|
for (const auto& rootCandidate : nssRootCandidates) {
|
||||||
Input certDER;
|
Input certDER;
|
||||||
Result rv = certDER.Init(rootCandidate.Elements(), rootCandidate.Length());
|
Result rv = certDER.Init(rootCandidate.Elements(), rootCandidate.Length());
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
continue; // probably too big
|
continue; // probably too big
|
||||||
}
|
}
|
||||||
nssCandidates.AppendElement(std::move(certDER));
|
nssCandidates.AppendElement(
|
||||||
|
IssuerCandidateWithSource{std::move(certDER), IssuerSource::NSSCertDB});
|
||||||
}
|
}
|
||||||
for (const auto& intermediateCandidate : nssIntermediateCandidates) {
|
for (const auto& intermediateCandidate : nssIntermediateCandidates) {
|
||||||
Input certDER;
|
Input certDER;
|
||||||
|
@ -381,10 +387,11 @@ Result NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
continue; // probably too big
|
continue; // probably too big
|
||||||
}
|
}
|
||||||
nssCandidates.AppendElement(std::move(certDER));
|
nssCandidates.AppendElement(
|
||||||
|
IssuerCandidateWithSource{std::move(certDER), IssuerSource::NSSCertDB});
|
||||||
}
|
}
|
||||||
|
|
||||||
return CheckCandidates(*this, checker, nssCandidates, nameConstraintsInputPtr,
|
return CheckCandidates(checker, nssCandidates, nameConstraintsInputPtr,
|
||||||
keepGoing);
|
keepGoing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1606,6 +1613,7 @@ void NSSCertDBTrustDomain::ResetAccumulatedState() {
|
||||||
mSCTListFromCertificate = nullptr;
|
mSCTListFromCertificate = nullptr;
|
||||||
mSawDistrustedCAByPolicyError = false;
|
mSawDistrustedCAByPolicyError = false;
|
||||||
mIsBuiltChainRootBuiltInRoot = false;
|
mIsBuiltChainRootBuiltInRoot = false;
|
||||||
|
mIssuerSources.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Input SECItemToInput(const UniqueSECItem& item) {
|
static Input SECItemToInput(const UniqueSECItem& item) {
|
||||||
|
|
|
@ -54,6 +54,13 @@ enum class OCSPFetchStatus : uint16_t {
|
||||||
Fetched = 1,
|
Fetched = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper struct to associate the DER bytes of a potential issuer certificate
|
||||||
|
// with its source (i.e. where it came from).
|
||||||
|
struct IssuerCandidateWithSource {
|
||||||
|
mozilla::pkix::Input mDER; // non-owning
|
||||||
|
IssuerSource mIssuerSource;
|
||||||
|
};
|
||||||
|
|
||||||
SECStatus InitializeNSS(const nsACString& dir, NSSDBConfig nssDbConfig,
|
SECStatus InitializeNSS(const nsACString& dir, NSSDBConfig nssDbConfig,
|
||||||
PKCS11DBConfig pkcs11DbConfig);
|
PKCS11DBConfig pkcs11DbConfig);
|
||||||
|
|
||||||
|
@ -245,6 +252,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
|
||||||
bool GetIsErrorDueToDistrustedCAPolicy() const;
|
bool GetIsErrorDueToDistrustedCAPolicy() const;
|
||||||
|
|
||||||
OCSPFetchStatus GetOCSPFetchStatus() { return mOCSPFetchStatus; }
|
OCSPFetchStatus GetOCSPFetchStatus() { return mOCSPFetchStatus; }
|
||||||
|
IssuerSources GetIssuerSources() { return mIssuerSources; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result CheckCRLiteStash(
|
Result CheckCRLiteStash(
|
||||||
|
@ -290,6 +298,12 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
|
||||||
const Result error,
|
const Result error,
|
||||||
/*out*/ bool& softFailure);
|
/*out*/ bool& softFailure);
|
||||||
|
|
||||||
|
bool ShouldSkipSelfSignedNonTrustAnchor(mozilla::pkix::Input certDER);
|
||||||
|
Result CheckCandidates(IssuerChecker& checker,
|
||||||
|
nsTArray<IssuerCandidateWithSource>& candidates,
|
||||||
|
mozilla::pkix::Input* nameConstraintsInputPtr,
|
||||||
|
bool& keepGoing);
|
||||||
|
|
||||||
const SECTrustType mCertDBTrustType;
|
const SECTrustType mCertDBTrustType;
|
||||||
const OCSPFetching mOCSPFetching;
|
const OCSPFetching mOCSPFetching;
|
||||||
OCSPCache& mOCSPCache; // non-owning!
|
OCSPCache& mOCSPCache; // non-owning!
|
||||||
|
@ -321,6 +335,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
|
||||||
UniqueSECMODModule mBuiltInRootsModule;
|
UniqueSECMODModule mBuiltInRootsModule;
|
||||||
|
|
||||||
OCSPFetchStatus mOCSPFetchStatus;
|
OCSPFetchStatus mOCSPFetchStatus;
|
||||||
|
IssuerSources mIssuerSources;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace psm
|
} // namespace psm
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
#include "mozilla/glean/GleanMetrics.h"
|
||||||
#include "nsComponentManagerUtils.h"
|
#include "nsComponentManagerUtils.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsICertOverrideService.h"
|
#include "nsICertOverrideService.h"
|
||||||
|
@ -529,7 +530,8 @@ static void CollectCertTelemetry(
|
||||||
KeySizeStatus aKeySizeStatus,
|
KeySizeStatus aKeySizeStatus,
|
||||||
const PinningTelemetryInfo& aPinningTelemetryInfo,
|
const PinningTelemetryInfo& aPinningTelemetryInfo,
|
||||||
const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain,
|
const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain,
|
||||||
const CertificateTransparencyInfo& aCertificateTransparencyInfo) {
|
const CertificateTransparencyInfo& aCertificateTransparencyInfo,
|
||||||
|
const IssuerSources& issuerSources) {
|
||||||
uint32_t evStatus = (aCertVerificationResult != Success) ? 0 // 0 = Failure
|
uint32_t evStatus = (aCertVerificationResult != Success) ? 0 // 0 = Failure
|
||||||
: (aEVStatus != EVStatus::EV) ? 1 // 1 = DV
|
: (aEVStatus != EVStatus::EV) ? 1 // 1 = DV
|
||||||
: 2; // 2 = EV
|
: 2; // 2 = EV
|
||||||
|
@ -562,6 +564,28 @@ static void CollectCertTelemetry(
|
||||||
rootCert);
|
rootCert);
|
||||||
GatherCertificateTransparencyTelemetry(rootCert, aEVStatus == EVStatus::EV,
|
GatherCertificateTransparencyTelemetry(rootCert, aEVStatus == EVStatus::EV,
|
||||||
aCertificateTransparencyInfo);
|
aCertificateTransparencyInfo);
|
||||||
|
|
||||||
|
mozilla::glean::tls::certificate_verifications.Add(1);
|
||||||
|
if (issuerSources.contains(IssuerSource::TLSHandshake)) {
|
||||||
|
mozilla::glean::verification_used_cert_from::tls_handshake.AddToNumerator(
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
if (issuerSources.contains(IssuerSource::PreloadedIntermediates)) {
|
||||||
|
mozilla::glean::verification_used_cert_from::preloaded_intermediates
|
||||||
|
.AddToNumerator(1);
|
||||||
|
}
|
||||||
|
if (issuerSources.contains(IssuerSource::ThirdPartyCertificates)) {
|
||||||
|
mozilla::glean::verification_used_cert_from::third_party_certificates
|
||||||
|
.AddToNumerator(1);
|
||||||
|
}
|
||||||
|
if (issuerSources.contains(IssuerSource::NSSCertDB)) {
|
||||||
|
mozilla::glean::verification_used_cert_from::nss_cert_db.AddToNumerator(
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
if (issuerSources.contains(IssuerSource::BuiltInRootsModule)) {
|
||||||
|
mozilla::glean::verification_used_cert_from::built_in_roots_module
|
||||||
|
.AddToNumerator(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,17 +618,18 @@ Result AuthCertificate(
|
||||||
[](const auto& elementArray) { return elementArray.Clone(); });
|
[](const auto& elementArray) { return elementArray.Clone(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IssuerSources issuerSources;
|
||||||
Result rv = certVerifier.VerifySSLServerCert(
|
Result rv = certVerifier.VerifySSLServerCert(
|
||||||
certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags,
|
certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags,
|
||||||
Some(std::move(peerCertsBytes)), stapledOCSPResponse,
|
Some(std::move(peerCertsBytes)), stapledOCSPResponse,
|
||||||
sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus,
|
sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus,
|
||||||
&ocspStaplingStatus, &keySizeStatus, &pinningTelemetryInfo,
|
&ocspStaplingStatus, &keySizeStatus, &pinningTelemetryInfo,
|
||||||
&certificateTransparencyInfo, &aIsBuiltCertChainRootBuiltInRoot,
|
&certificateTransparencyInfo, &aIsBuiltCertChainRootBuiltInRoot,
|
||||||
&aMadeOCSPRequests);
|
&aMadeOCSPRequests, &issuerSources);
|
||||||
|
|
||||||
CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus,
|
CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus,
|
||||||
pinningTelemetryInfo, builtCertChain,
|
pinningTelemetryInfo, builtCertChain,
|
||||||
certificateTransparencyInfo);
|
certificateTransparencyInfo, issuerSources);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
# 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
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
# Adding a new metric? We have docs for that!
|
# Adding a new metric? We have docs for that!
|
||||||
# https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/new_definitions_file.html
|
# https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/new_definitions_file.html
|
||||||
|
|
||||||
|
@ -73,3 +72,78 @@ oskeystore:
|
||||||
- available
|
- available
|
||||||
- encrypt
|
- encrypt
|
||||||
- decrypt
|
- decrypt
|
||||||
|
|
||||||
|
tls:
|
||||||
|
certificate_verifications:
|
||||||
|
type: counter
|
||||||
|
description: >
|
||||||
|
The total number of successful TLS server certificate verifications.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
notification_emails:
|
||||||
|
- dkeeler@mozilla.com
|
||||||
|
expires: never
|
||||||
|
|
||||||
|
verification_used_cert_from:
|
||||||
|
tls_handshake:
|
||||||
|
type: rate
|
||||||
|
description: >
|
||||||
|
How many successfully-built certificate chains used a certificate from the TLS handshake.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
notification_emails:
|
||||||
|
- dkeeler@mozilla.com
|
||||||
|
expires: never
|
||||||
|
denominator_metric: tls.certificate_verifications
|
||||||
|
preloaded_intermediates:
|
||||||
|
type: rate
|
||||||
|
description: >
|
||||||
|
How many successfully-built certificate chains used a certificate from preloaded intermediates.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
notification_emails:
|
||||||
|
- dkeeler@mozilla.com
|
||||||
|
expires: never
|
||||||
|
denominator_metric: tls.certificate_verifications
|
||||||
|
third_party_certificates:
|
||||||
|
type: rate
|
||||||
|
description: >
|
||||||
|
How many successfully-built certificate chains used a third-party certificate from the OS.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
notification_emails:
|
||||||
|
- dkeeler@mozilla.com
|
||||||
|
expires: never
|
||||||
|
denominator_metric: tls.certificate_verifications
|
||||||
|
nss_cert_db:
|
||||||
|
type: rate
|
||||||
|
description: >
|
||||||
|
How many successfully-built certificate chains used a certificate from the NSS cert DB.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
notification_emails:
|
||||||
|
- dkeeler@mozilla.com
|
||||||
|
expires: never
|
||||||
|
denominator_metric: tls.certificate_verifications
|
||||||
|
built_in_roots_module:
|
||||||
|
type: rate
|
||||||
|
description: >
|
||||||
|
How many successfully-built certificate chains used a certificate from the built-in roots module.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1876435
|
||||||
|
notification_emails:
|
||||||
|
- dkeeler@mozilla.com
|
||||||
|
expires: never
|
||||||
|
denominator_metric: tls.certificate_verifications
|
||||||
|
|
Загрузка…
Ссылка в новой задаче