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:
Dana Keeler 2024-01-29 18:28:00 +00:00
Родитель 2694839f3b
Коммит 61cba1c84d
6 изменённых файлов: 236 добавлений и 88 удалений

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

@ -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