bug 1473573 - import intermediate certificates as well as roots r=jcj

Differential Revision: https://phabricator.services.mozilla.com/D18630

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dana Keeler 2019-02-12 18:23:25 +00:00
parent 7f2cafcb86
commit 86b72ab902
11 changed files with 207 additions and 109 deletions

View File

@ -89,7 +89,7 @@ CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode,
DistrustedCAPolicy distrustedCAPolicy,
const Vector<Vector<uint8_t>>& thirdPartyRoots)
const Vector<EnterpriseCert>& thirdPartyCerts)
: mOCSPDownloadConfig(odc),
mOCSPStrict(osc == ocspStrict),
mOCSPTimeoutSoft(ocspTimeoutSoft),
@ -102,19 +102,24 @@ CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mCTMode(ctMode),
mDistrustedCAPolicy(distrustedCAPolicy) {
LoadKnownCTLogs();
for (const auto& root : thirdPartyRoots) {
Vector<uint8_t> rootCopy;
if (rootCopy.append(root.begin(), root.end())) {
// Best-effort. If we run out of memory, users might see untrusted issuer
// errors, but the browser will probably crash before then.
Unused << mThirdPartyRoots.append(std::move(rootCopy));
for (const auto& root : thirdPartyCerts) {
EnterpriseCert rootCopy;
// Best-effort. If we run out of memory, users might see untrusted issuer
// errors, but the browser will probably crash before then.
if (NS_SUCCEEDED(rootCopy.Init(root))) {
Unused << mThirdPartyCerts.append(std::move(rootCopy));
}
}
for (const auto& root : mThirdPartyRoots) {
Input rootInput;
if (rootInput.Init(root.begin(), root.length()) == Success) {
// Best effort again.
Unused << mThirdPartyRootInputs.append(rootInput);
for (const auto& root : mThirdPartyCerts) {
Input input;
if (root.GetInput(input) == Success) {
// mThirdPartyCerts consists of roots and intermediates.
if (root.GetIsRoot()) {
// Best effort again.
Unused << mThirdPartyRootInputs.append(input);
} else {
Unused << mThirdPartyIntermediateInputs.append(input);
}
}
}
}
@ -528,7 +533,7 @@ Result CertVerifier::VerifyCert(
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch,
mDistrustedCAPolicy, originAttributes, mThirdPartyRootInputs,
builtChain, nullptr, nullptr);
mThirdPartyIntermediateInputs, builtChain, nullptr, nullptr);
rv = BuildCertChain(
trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyPurposeId::id_kp_clientAuth,
@ -601,7 +606,8 @@ Result CertVerifier::VerifyCert(
MIN_RSA_BITS, ValidityCheckingMode::CheckForEV,
sha1ModeConfigurations[i], mNetscapeStepUpPolicy,
mDistrustedCAPolicy, originAttributes, mThirdPartyRootInputs,
builtChain, pinningTelemetryInfo, hostname);
mThirdPartyIntermediateInputs, builtChain, pinningTelemetryInfo,
hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, // (EC)DHE
@ -682,8 +688,8 @@ Result CertVerifier::VerifyCert(
mPinningMode, keySizeOptions[i],
ValidityCheckingMode::CheckingOff, sha1ModeConfigurations[j],
mNetscapeStepUpPolicy, mDistrustedCAPolicy, originAttributes,
mThirdPartyRootInputs, builtChain, pinningTelemetryInfo,
hostname);
mThirdPartyRootInputs, mThirdPartyIntermediateInputs, builtChain,
pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, //(EC)DHE
@ -751,8 +757,8 @@ Result CertVerifier::VerifyCert(
mOCSPTimeoutHard, mCertShortLifetimeInDays, pinningDisabled,
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, mNetscapeStepUpPolicy, mDistrustedCAPolicy,
originAttributes, mThirdPartyRootInputs, builtChain, nullptr,
nullptr);
originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeCA,
KeyUsage::keyCertSign, KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy, stapledOCSPResponse);
@ -766,7 +772,7 @@ Result CertVerifier::VerifyCert(
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch,
mDistrustedCAPolicy, originAttributes, mThirdPartyRootInputs,
builtChain, nullptr, nullptr);
mThirdPartyIntermediateInputs, builtChain, nullptr, nullptr);
rv = BuildCertChain(
trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyPurposeId::id_kp_emailProtection,
@ -790,7 +796,7 @@ Result CertVerifier::VerifyCert(
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch,
mDistrustedCAPolicy, originAttributes, mThirdPartyRootInputs,
builtChain, nullptr, nullptr);
mThirdPartyIntermediateInputs, builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA

View File

@ -10,6 +10,7 @@
#include "BRNameMatchingPolicy.h"
#include "CTPolicyEnforcer.h"
#include "CTVerifyResult.h"
#include "EnterpriseRoots.h"
#include "OCSPCache.h"
#include "RootCertificateTelemetryUtils.h"
#include "ScopedNSSTypes.h"
@ -207,7 +208,7 @@ class CertVerifier {
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode,
DistrustedCAPolicy distrustedCAPolicy,
const Vector<Vector<uint8_t>>& thirdPartyRoots);
const Vector<EnterpriseCert>& thirdPartyCerts);
~CertVerifier();
void ClearOCSPCache() { mOCSPCache.Clear(); }
@ -227,10 +228,12 @@ class CertVerifier {
private:
OCSPCache mOCSPCache;
// We keep a copy of the bytes of each third party root to own.
Vector<Vector<uint8_t>> mThirdPartyRoots;
Vector<EnterpriseCert> mThirdPartyCerts;
// This is a reusable, precomputed list of Inputs corresponding to each root
// in mThirdPartyRoots that wasn't too long to make an Input out of.
// in mThirdPartyCerts that wasn't too long to make an Input out of.
Vector<mozilla::pkix::Input> mThirdPartyRootInputs;
// Similarly, but with intermediates.
Vector<mozilla::pkix::Input> mThirdPartyIntermediateInputs;
// We only have a forward declarations of these classes (see above)
// so we must allocate dynamically.

View File

@ -61,6 +61,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
DistrustedCAPolicy distrustedCAPolicy,
const OriginAttributes& originAttributes,
const Vector<Input>& thirdPartyRootInputs,
const Vector<Input>& thirdPartyIntermediateInputs,
/*out*/ UniqueCERTCertList& builtChain,
/*optional*/ PinningTelemetryInfo* pinningTelemetryInfo,
/*optional*/ const char* hostname)
@ -80,6 +81,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
mSawDistrustedCAByPolicyError(false),
mOriginAttributes(originAttributes),
mThirdPartyRootInputs(thirdPartyRootInputs),
mThirdPartyIntermediateInputs(thirdPartyIntermediateInputs),
mBuiltChain(builtChain),
mPinningTelemetryInfo(pinningTelemetryInfo),
mHostname(hostname),
@ -126,6 +128,13 @@ Result NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
}
}
for (const auto& thirdPartyIntermediateInput :
mThirdPartyIntermediateInputs) {
if (!intermediateCandidates.append(thirdPartyIntermediateInput)) {
return Result::FATAL_ERROR_NO_MEMORY;
}
}
// Handle imposed name constraints, if any.
ScopedAutoSECItem nameConstraints;
Input nameConstraintsInput;

View File

@ -108,6 +108,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
DistrustedCAPolicy distrustedCAPolicy,
const OriginAttributes& originAttributes,
const Vector<mozilla::pkix::Input>& thirdPartyRootInputs,
const Vector<mozilla::pkix::Input>& thirdPartyIntermediateInputs,
/*out*/ UniqueCERTCertList& builtChain,
/*optional*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
/*optional*/ const char* hostname = nullptr);
@ -217,6 +218,8 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
bool mSawDistrustedCAByPolicyError;
const OriginAttributes& mOriginAttributes;
const Vector<mozilla::pkix::Input>& mThirdPartyRootInputs; // non-owning
const Vector<mozilla::pkix::Input>&
mThirdPartyIntermediateInputs; // non-owning
UniqueCERTCertList& mBuiltChain; // non-owning
PinningTelemetryInfo* mPinningTelemetryInfo;
const char* mHostname; // non-owning - only used for pinning checks

View File

@ -9,6 +9,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/Unused.h"
#include "mozpkix/Result.h"
#ifdef XP_MACOSX
# include <Security/Security.h>
@ -19,8 +20,36 @@ extern LazyLogModule gPIPNSSLog;
using namespace mozilla;
nsresult EnterpriseCert::Init(const uint8_t* data, size_t len, bool isRoot) {
mDER.clear();
if (!mDER.append(data, len)) {
return NS_ERROR_OUT_OF_MEMORY;
}
mIsRoot = isRoot;
return NS_OK;
}
nsresult EnterpriseCert::Init(const EnterpriseCert& orig) {
return Init(orig.mDER.begin(), orig.mDER.length(), orig.mIsRoot);
}
nsresult EnterpriseCert::CopyBytes(nsTArray<uint8_t>& dest) const {
dest.Clear();
if (!dest.AppendElements(mDER.begin(), mDER.length())) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
pkix::Result EnterpriseCert::GetInput(pkix::Input& input) const {
return input.Init(mDER.begin(), mDER.length());
}
bool EnterpriseCert::GetIsRoot() const { return mIsRoot; }
#ifdef XP_WIN
const wchar_t* kWindowsDefaultRootStoreName = L"ROOT";
const wchar_t* kWindowsDefaultRootStoreNames[] = {L"ROOT", L"CA"};
// Helper function to determine if the OS considers the given certificate to be
// a trust anchor for TLS server auth certificates. This is to be used in the
@ -29,10 +58,13 @@ const wchar_t* kWindowsDefaultRootStoreName = L"ROOT";
// in some way unsuitable to issue certificates, mozilla::pkix will never build
// a valid chain that includes the certificate, so importing it even if it
// isn't a valid CA poses no risk.
static bool CertIsTrustAnchorForTLSServerAuth(PCCERT_CONTEXT certificate) {
static void CertIsTrustAnchorForTLSServerAuth(PCCERT_CONTEXT certificate,
bool& isTrusted, bool& isRoot) {
isTrusted = false;
isRoot = false;
MOZ_ASSERT(certificate);
if (!certificate) {
return false;
return;
}
PCCERT_CHAIN_CONTEXT pChainContext = nullptr;
@ -56,20 +88,19 @@ static bool CertIsTrustAnchorForTLSServerAuth(PCCERT_CONTEXT certificate) {
if (!CertGetCertificateChain(nullptr, certificate, nullptr, nullptr,
&chainPara, 0, nullptr, &pChainContext)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CertGetCertificateChain failed"));
return false;
return;
}
isTrusted = pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR;
if (isTrusted && pChainContext->cChain > 0) {
// The so-called "final chain" is what we're after:
// https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/ns-wincrypt-_cert_chain_context
CERT_SIMPLE_CHAIN* finalChain =
pChainContext->rgpChain[pChainContext->cChain - 1];
// This is a root if the final chain consists of only one certificate (i.e.
// this one).
isRoot = finalChain->cElement == 1;
}
bool trusted =
pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR;
bool isRoot = pChainContext->cChain == 1;
CertFreeCertificateChain(pChainContext);
if (trusted && isRoot) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("certificate is trust anchor for TLS server auth"));
return true;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("certificate not trust anchor for TLS server auth"));
return false;
}
// Because HCERTSTORE is just a typedef void*, we can't use any of the nice
@ -100,8 +131,8 @@ class ScopedCertStore final {
// HKLM\SOFTWARE\Policies\Microsoft\SystemCertificates\Root\Certificates)
// CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
// (for HKLM\SOFTWARE\Microsoft\EnterpriseCertificates\Root\Certificates)
static void GatherEnterpriseRootsForLocation(DWORD locationFlag,
Vector<Vector<uint8_t>>& roots) {
static void GatherEnterpriseCertsForLocation(DWORD locationFlag,
Vector<EnterpriseCert>& certs) {
MOZ_ASSERT(locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ||
locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY ||
locationFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
@ -119,52 +150,55 @@ static void GatherEnterpriseRootsForLocation(DWORD locationFlag,
// of Microsoft's root store program.
// The 3rd parameter to CertOpenStore should be NULL according to
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa376559%28v=vs.85%29.aspx
ScopedCertStore enterpriseRootStore(
CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, NULL, flags,
kWindowsDefaultRootStoreName));
if (!enterpriseRootStore.get()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to open enterprise root store"));
return;
}
PCCERT_CONTEXT certificate = nullptr;
uint32_t numImported = 0;
while ((certificate = CertFindCertificateInStore(
enterpriseRootStore.get(), X509_ASN_ENCODING, 0, CERT_FIND_ANY,
nullptr, certificate))) {
if (!CertIsTrustAnchorForTLSServerAuth(certificate)) {
for (auto name : kWindowsDefaultRootStoreNames) {
ScopedCertStore enterpriseRootStore(
CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, NULL, flags, name));
if (!enterpriseRootStore.get()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("skipping cert not trust anchor for TLS server auth"));
("failed to open enterprise root store"));
continue;
}
Vector<uint8_t> certBytes;
if (!certBytes.append(certificate->pbCertEncoded,
certificate->cbCertEncoded)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
("couldn't copy cert bytes (out of memory?)"));
continue;
PCCERT_CONTEXT certificate = nullptr;
uint32_t numImported = 0;
while ((certificate = CertFindCertificateInStore(
enterpriseRootStore.get(), X509_ASN_ENCODING, 0, CERT_FIND_ANY,
nullptr, certificate))) {
bool isTrusted;
bool isRoot;
CertIsTrustAnchorForTLSServerAuth(certificate, isTrusted, isRoot);
if (!isTrusted) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("skipping cert not trusted for TLS server auth"));
continue;
}
EnterpriseCert enterpriseCert;
if (NS_FAILED(enterpriseCert.Init(certificate->pbCertEncoded,
certificate->cbCertEncoded, isRoot))) {
// Best-effort. We probably ran out of memory.
continue;
}
if (!certs.append(std::move(enterpriseCert))) {
// Best-effort again.
continue;
}
numImported++;
}
if (!roots.append(std::move(certBytes))) {
MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
("couldn't append cert bytes to roots list (out of memory?)"));
continue;
}
numImported++;
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("imported %u certs from %S", numImported, name));
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("imported %u roots", numImported));
}
static void GatherEnterpriseRootsWindows(Vector<Vector<uint8_t>>& roots) {
GatherEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE, roots);
GatherEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY,
roots);
GatherEnterpriseRootsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
roots);
static void GatherEnterpriseCertsWindows(Vector<EnterpriseCert>& certs) {
GatherEnterpriseCertsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE, certs);
GatherEnterpriseCertsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY,
certs);
GatherEnterpriseCertsForLocation(CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
certs);
}
#endif // XP_WIN
#ifdef XP_MACOSX
OSStatus GatherEnterpriseRootsOSX(Vector<Vector<uint8_t>>& roots) {
OSStatus GatherEnterpriseCertsMacOS(Vector<EnterpriseCert>& certs) {
// The following builds a search dictionary corresponding to:
// { class: "certificate",
// match limit: "match all",
@ -204,33 +238,32 @@ OSStatus GatherEnterpriseRootsOSX(Vector<Vector<uint8_t>>& roots) {
// a SecCertificateRef.
const SecCertificateRef s = (const SecCertificateRef)c;
ScopedCFType<CFDataRef> der(SecCertificateCopyData(s));
const unsigned char* ptr = CFDataGetBytePtr(der.get());
unsigned int len = CFDataGetLength(der.get());
Vector<uint8_t> certBytes;
if (!certBytes.append(ptr, len)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
("couldn't copy cert bytes (out of memory?)"));
EnterpriseCert enterpriseCert;
// TODO(BUG 1526004) currently we treat all 3rd party certificates as trust
// anchors on MacOS. This will be addressed in a follow-up bug.
if (NS_FAILED(enterpriseCert.Init(CFDataGetBytePtr(der.get()),
CFDataGetLength(der.get()), true))) {
// Best-effort. We probably ran out of memory.
continue;
}
if (!roots.append(std::move(certBytes))) {
MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
("couldn't append cert bytes to roots list (out of memory?)"));
if (!certs.append(std::move(enterpriseCert))) {
// Best-effort again.
continue;
}
numImported++;
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("imported %u roots", numImported));
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("imported %u certs", numImported));
return errSecSuccess;
}
#endif // XP_MACOSX
nsresult GatherEnterpriseRoots(Vector<Vector<uint8_t>>& roots) {
roots.clear();
nsresult GatherEnterpriseCerts(Vector<EnterpriseCert>& certs) {
certs.clear();
#ifdef XP_WIN
GatherEnterpriseRootsWindows(roots);
GatherEnterpriseCertsWindows(certs);
#endif // XP_WIN
#ifdef XP_MACOSX
OSStatus rv = GatherEnterpriseRootsOSX(roots);
OSStatus rv = GatherEnterpriseCertsMacOS(certs);
if (rv != errSecSuccess) {
return NS_ERROR_FAILURE;
}

View File

@ -8,8 +8,27 @@
#define EnterpriseRoots_h
#include "mozilla/Vector.h"
#include "mozpkix/Input.h"
#include "mozpkix/Result.h"
#include "nsTArray.h"
nsresult GatherEnterpriseRoots(
mozilla::Vector<mozilla::Vector<uint8_t>>& roots);
class EnterpriseCert {
public:
EnterpriseCert() : mIsRoot(false) {}
nsresult Init(const uint8_t* data, size_t len, bool isRoot);
// Like a copy constructor but able to return a result.
nsresult Init(const EnterpriseCert& orig);
nsresult CopyBytes(nsTArray<uint8_t>& dest) const;
mozilla::pkix::Result GetInput(mozilla::pkix::Input& input) const;
bool GetIsRoot() const;
private:
mozilla::Vector<uint8_t> mDER;
bool mIsRoot;
};
nsresult GatherEnterpriseCerts(mozilla::Vector<EnterpriseCert>& certs);
#endif // EnterpriseRoots_h

View File

@ -6,6 +6,7 @@
#define SharedCertVerifier_h
#include "CertVerifier.h"
#include "EnterpriseRoots.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
@ -28,11 +29,11 @@ class SharedCertVerifier : public mozilla::psm::CertVerifier {
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode,
DistrustedCAPolicy distrustedCAPolicy,
const Vector<Vector<uint8_t>>& thirdPartyRoots)
const Vector<EnterpriseCert>& thirdPartyCerts)
: mozilla::psm::CertVerifier(
odc, osc, ocspSoftTimeout, ocspHardTimeout, certShortLifetimeInDays,
pinningMode, sha1Mode, nameMatchingMode, netscapeStepUpPolicy,
ctMode, distrustedCAPolicy, thirdPartyRoots) {}
ctMode, distrustedCAPolicy, thirdPartyCerts) {}
};
} // namespace psm

View File

@ -68,6 +68,7 @@ EXTRA_JS_MODULES.psm += [
EXPORTS += [
'CryptoTask.h',
'EnterpriseRoots.h',
'nsClientAuthRemember.h',
'nsNSSCallbacks.h',
'nsNSSCertificate.h',

View File

@ -54,6 +54,11 @@ interface nsINSSComponent : nsISupports {
*/
Array<Array<octet> > getEnterpriseRoots();
/**
* Similarly, but for intermediate certificates.
*/
Array<Array<octet> > getEnterpriseIntermediates();
/**
* For performance reasons, the builtin roots module is loaded on a background
* thread. When any code that depends on the builtin roots module runs, it

View File

@ -482,7 +482,7 @@ void nsNSSComponent::UnloadEnterpriseRoots() {
}
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadEnterpriseRoots"));
MutexAutoLock lock(mMutex);
mEnterpriseRoots.clear();
mEnterpriseCerts.clear();
setValidationOptions(false, lock);
}
@ -510,34 +510,49 @@ void nsNSSComponent::MaybeImportEnterpriseRoots() {
void nsNSSComponent::ImportEnterpriseRoots() {
MutexAutoLock lock(mMutex);
nsresult rv = GatherEnterpriseRoots(mEnterpriseRoots);
nsresult rv = GatherEnterpriseCerts(mEnterpriseCerts);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed gathering enterprise roots"));
}
}
NS_IMETHODIMP
nsNSSComponent::GetEnterpriseRoots(
nsTArray<nsTArray<uint8_t>>& enterpriseRoots) {
nsresult nsNSSComponent::CommonGetEnterpriseCerts(
nsTArray<nsTArray<uint8_t>>& enterpriseCerts, bool getRoots) {
MutexAutoLock nsNSSComponentLock(mMutex);
MOZ_ASSERT(NS_IsMainThread());
if (!NS_IsMainThread()) {
return NS_ERROR_NOT_SAME_THREAD;
}
enterpriseRoots.Clear();
for (const auto& root : mEnterpriseRoots) {
nsTArray<uint8_t> rootCopy;
if (!rootCopy.AppendElements(root.begin(), root.length())) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (!enterpriseRoots.AppendElement(std::move(rootCopy))) {
return NS_ERROR_OUT_OF_MEMORY;
enterpriseCerts.Clear();
for (const auto& cert : mEnterpriseCerts) {
nsTArray<uint8_t> certCopy;
// mEnterpriseCerts includes both roots and intermediates.
if (cert.GetIsRoot() == getRoots) {
nsresult rv = cert.CopyBytes(certCopy);
if (NS_FAILED(rv)) {
return rv;
}
if (!enterpriseCerts.AppendElement(std::move(certCopy))) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsNSSComponent::GetEnterpriseRoots(
nsTArray<nsTArray<uint8_t>>& enterpriseRoots) {
return CommonGetEnterpriseCerts(enterpriseRoots, true);
}
NS_IMETHODIMP
nsNSSComponent::GetEnterpriseIntermediates(
nsTArray<nsTArray<uint8_t>>& enterpriseIntermediates) {
return CommonGetEnterpriseCerts(enterpriseIntermediates, false);
}
class LoadLoadableRootsTask final : public Runnable {
public:
LoadLoadableRootsTask(nsNSSComponent* nssComponent,
@ -1199,7 +1214,7 @@ void nsNSSComponent::setValidationOptions(
mDefaultCertVerifier = new SharedCertVerifier(
odc, osc, softTimeout, hardTimeout, certShortLifetimeInDays, pinningMode,
sha1Mode, nameMatchingMode, netscapeStepUpPolicy, ctMode,
distrustedCAPolicy, mEnterpriseRoots);
distrustedCAPolicy, mEnterpriseCerts);
}
void nsNSSComponent::UpdateCertVerifierWithEnterpriseRoots() {
@ -1218,7 +1233,7 @@ void nsNSSComponent::UpdateCertVerifierWithEnterpriseRoots() {
oldCertVerifier->mCertShortLifetimeInDays, oldCertVerifier->mPinningMode,
oldCertVerifier->mSHA1Mode, oldCertVerifier->mNameMatchingMode,
oldCertVerifier->mNetscapeStepUpPolicy, oldCertVerifier->mCTMode,
oldCertVerifier->mDistrustedCAPolicy, mEnterpriseRoots);
oldCertVerifier->mDistrustedCAPolicy, mEnterpriseCerts);
}
// Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and

View File

@ -9,6 +9,7 @@
#include "nsINSSComponent.h"
#include "EnterpriseRoots.h"
#include "ScopedNSSTypes.h"
#include "SharedCertVerifier.h"
#include "mozilla/Attributes.h"
@ -86,6 +87,8 @@ class nsNSSComponent final : public nsINSSComponent, public nsIObserver {
void MaybeImportEnterpriseRoots();
void ImportEnterpriseRoots();
void UnloadEnterpriseRoots();
nsresult CommonGetEnterpriseCerts(
nsTArray<nsTArray<uint8_t>>& enterpriseCerts, bool getRoots);
bool ShouldEnableEnterpriseRootsForFamilySafety(uint32_t familySafetyMode);
@ -106,7 +109,7 @@ class nsNSSComponent final : public nsINSSComponent, public nsIObserver {
RefPtr<mozilla::psm::SharedCertVerifier> mDefaultCertVerifier;
nsString mMitmCanaryIssuer;
bool mMitmDetecionEnabled;
mozilla::Vector<mozilla::Vector<uint8_t>> mEnterpriseRoots;
mozilla::Vector<EnterpriseCert> mEnterpriseCerts;
// The following members are accessed only on the main thread:
static int mInstanceCount;