зеркало из https://github.com/mozilla/gecko-dev.git
bug 1227638 - deterministically load EV information r=Cykesiopka,mgoodwin
Previously PSM would load EV information on-demand (i.e. just before verifying a certificate). This simplifies this operation, removes a dubious optimization (loading the EV information on another thread while opening a network connection), and relocates the loading operation to when we are likely to have good disk locality (i.e. when we've just loaded the built-in roots module). This also removes the now-unused MOZ_NO_EV_CERTS build flag. MozReview-Commit-ID: 8Rnl4ozF95V --HG-- extra : rebase_source : 344b68c81af1ed3fb038e4e96c3c50e939d32c3d
This commit is contained in:
Родитель
439863da4e
Коммит
ec181af1f7
|
@ -19,7 +19,6 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
|
|||
|
||||
MOZ_NO_SMART_CARDS=1
|
||||
MOZ_APP_STATIC_INI=1
|
||||
MOZ_NO_EV_CERTS=1
|
||||
|
||||
if test "$OS_TARGET" = "Android"; then
|
||||
MOZ_CAPTURE=1
|
||||
|
|
|
@ -3993,14 +3993,6 @@ if test -n "$MOZ_NO_SMART_CARDS"; then
|
|||
fi
|
||||
AC_SUBST(MOZ_NO_SMART_CARDS)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable EV certificate verification
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_NO_EV_CERTS"; then
|
||||
AC_DEFINE(MOZ_NO_EV_CERTS)
|
||||
fi
|
||||
AC_SUBST(MOZ_NO_EV_CERTS)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Sandboxing support
|
||||
dnl ========================================================
|
||||
|
|
|
@ -460,7 +460,6 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
|
||||
rv = Result::ERROR_UNKNOWN_ERROR;
|
||||
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
// Try to validate for EV first.
|
||||
NSSCertDBTrustDomain::OCSPFetching evOCSPFetching
|
||||
= (mOCSPDownloadConfig == ocspOff) ||
|
||||
|
@ -534,7 +533,6 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
if (rv == Success) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (flags & FLAG_MUST_BE_EV) {
|
||||
rv = Result::ERROR_POLICY_VALIDATION_FAILED;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "certdb.h"
|
||||
#include "hasht.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "pk11pub.h"
|
||||
|
@ -1249,8 +1250,8 @@ CertIsAuthoritativeForEVPolicy(const UniqueCERTCertificate& cert,
|
|||
return false;
|
||||
}
|
||||
|
||||
static PRStatus
|
||||
IdentityInfoInit()
|
||||
nsresult
|
||||
LoadExtendedValidationInfo()
|
||||
{
|
||||
static const char* sCABForumOIDString = "2.23.140.1.1";
|
||||
static const char* sCABForumOIDDescription = "CA/Browser Forum EV OID";
|
||||
|
@ -1258,28 +1259,35 @@ IdentityInfoInit()
|
|||
mozilla::ScopedAutoSECItem cabforumOIDItem;
|
||||
if (SEC_StringToOID(nullptr, &cabforumOIDItem, sCABForumOIDString, 0)
|
||||
!= SECSuccess) {
|
||||
return PR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
sCABForumEVOIDTag = RegisterOID(cabforumOIDItem, sCABForumOIDDescription);
|
||||
if (sCABForumEVOIDTag == SEC_OID_UNKNOWN) {
|
||||
return PR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
for (size_t iEV = 0; iEV < mozilla::ArrayLength(myTrustedEVInfos); ++iEV) {
|
||||
nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
|
||||
|
||||
SECStatus srv;
|
||||
#ifdef DEBUG
|
||||
// This section of code double-checks that we calculated the correct
|
||||
// certificate hash given the issuer and serial number and that it is
|
||||
// actually present in our loaded root certificates module. It is
|
||||
// unnecessary to check this in non-debug builds since we will safely fall
|
||||
// back to DV if the EV information is incorrect.
|
||||
mozilla::ScopedAutoSECItem derIssuer;
|
||||
SECStatus rv = ATOB_ConvertAsciiToItem(&derIssuer, entry.issuer_base64);
|
||||
PR_ASSERT(rv == SECSuccess);
|
||||
if (rv != SECSuccess) {
|
||||
return PR_FAILURE;
|
||||
srv = ATOB_ConvertAsciiToItem(&derIssuer, entry.issuer_base64);
|
||||
MOZ_ASSERT(srv == SECSuccess, "Could not base64-decode built-in EV issuer");
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mozilla::ScopedAutoSECItem serialNumber;
|
||||
rv = ATOB_ConvertAsciiToItem(&serialNumber, entry.serial_base64);
|
||||
PR_ASSERT(rv == SECSuccess);
|
||||
if (rv != SECSuccess) {
|
||||
return PR_FAILURE;
|
||||
srv = ATOB_ConvertAsciiToItem(&serialNumber, entry.serial_base64);
|
||||
MOZ_ASSERT(srv == SECSuccess, "Could not base64-decode built-in EV serial");
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CERTIssuerAndSN ias;
|
||||
|
@ -1293,66 +1301,41 @@ IdentityInfoInit()
|
|||
|
||||
// If an entry is missing in the NSS root database, it may be because the
|
||||
// root database is out of sync with what we expect (e.g. a different
|
||||
// version of system NSS is installed). We assert on debug builds, but
|
||||
// silently continue on release builds. In both cases, the root cert does
|
||||
// not get EV treatment.
|
||||
// version of system NSS is installed).
|
||||
if (!cert) {
|
||||
#ifdef DEBUG
|
||||
// The debug CA structs are at positions 0 to NUM_TEST_EV_ROOTS - 1, and
|
||||
// are NOT in the NSS root DB.
|
||||
if (iEV < NUM_TEST_EV_ROOTS) {
|
||||
continue;
|
||||
// The entries for the debug EV roots are at indices 0 through
|
||||
// NUM_TEST_EV_ROOTS - 1. Since they're not built-in, they probably
|
||||
// haven't been loaded yet.
|
||||
MOZ_ASSERT(iEV < NUM_TEST_EV_ROOTS, "Could not find built-in EV root");
|
||||
} else {
|
||||
unsigned char certFingerprint[SHA256_LENGTH];
|
||||
srv = PK11_HashBuf(SEC_OID_SHA256, certFingerprint, cert->derCert.data,
|
||||
AssertedCast<int32_t>(cert->derCert.len));
|
||||
MOZ_ASSERT(srv == SECSuccess, "Could not hash EV root");
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
bool same = PodEqual(certFingerprint, entry.ev_root_sha256_fingerprint);
|
||||
MOZ_ASSERT(same, "EV root fingerprint mismatch");
|
||||
if (!same) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
PR_NOT_REACHED("Could not find EV root in NSS storage");
|
||||
continue;
|
||||
// This is the code that actually enables these roots for EV.
|
||||
mozilla::ScopedAutoSECItem evOIDItem;
|
||||
srv = SEC_StringToOID(nullptr, &evOIDItem, entry.dotted_oid, 0);
|
||||
MOZ_ASSERT(srv == SECSuccess, "SEC_StringToOID failed");
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
unsigned char certFingerprint[SHA256_LENGTH];
|
||||
rv = PK11_HashBuf(SEC_OID_SHA256, certFingerprint, cert->derCert.data,
|
||||
AssertedCast<int32_t>(cert->derCert.len));
|
||||
PR_ASSERT(rv == SECSuccess);
|
||||
if (rv == SECSuccess) {
|
||||
bool same = !memcmp(certFingerprint, entry.ev_root_sha256_fingerprint,
|
||||
sizeof(certFingerprint));
|
||||
PR_ASSERT(same);
|
||||
if (same) {
|
||||
mozilla::ScopedAutoSECItem evOIDItem;
|
||||
rv = SEC_StringToOID(nullptr, &evOIDItem, entry.dotted_oid, 0);
|
||||
PR_ASSERT(rv == SECSuccess);
|
||||
if (rv == SECSuccess) {
|
||||
entry.oid_tag = RegisterOID(evOIDItem, entry.oid_name);
|
||||
if (entry.oid_tag == SEC_OID_UNKNOWN) {
|
||||
rv = SECFailure;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PR_SetError(SEC_ERROR_BAD_DATA, 0);
|
||||
rv = SECFailure;
|
||||
}
|
||||
}
|
||||
|
||||
if (rv != SECSuccess) {
|
||||
entry.oid_tag = SEC_OID_UNKNOWN;
|
||||
return PR_FAILURE;
|
||||
entry.oid_tag = RegisterOID(evOIDItem, entry.oid_name);
|
||||
if (entry.oid_tag == SEC_OID_UNKNOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
static PRCallOnceType sIdentityInfoCallOnce;
|
||||
|
||||
void
|
||||
EnsureIdentityInfoLoaded()
|
||||
{
|
||||
(void) PR_CallOnce(&sIdentityInfoCallOnce, IdentityInfoInit);
|
||||
}
|
||||
|
||||
void
|
||||
CleanupIdentityInfo()
|
||||
{
|
||||
memset(&sIdentityInfoCallOnce, 0, sizeof(PRCallOnceType));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Find the first policy OID that is known to be an EV policy OID.
|
||||
|
|
|
@ -14,9 +14,7 @@ namespace mozilla { namespace pkix { struct CertPolicyId; } }
|
|||
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
void EnsureIdentityInfoLoaded();
|
||||
void CleanupIdentityInfo();
|
||||
nsresult LoadExtendedValidationInfo();
|
||||
SECStatus GetFirstEVPolicy(CERTCertificate* cert,
|
||||
/*out*/ mozilla::pkix::CertPolicyId& policy,
|
||||
/*out*/ SECOidTag& policyOidTag);
|
||||
|
@ -25,7 +23,6 @@ SECStatus GetFirstEVPolicy(CERTCertificate* cert,
|
|||
// or distrusted.
|
||||
bool CertIsAuthoritativeForEVPolicy(const UniqueCERTCertificate& cert,
|
||||
const mozilla::pkix::CertPolicyId& policy);
|
||||
#endif
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
||||
|
|
|
@ -171,12 +171,6 @@ NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
|||
Input candidateCertDER,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
#ifdef MOZ_NO_EV_CERTS
|
||||
if (!policy.IsAnyPolicy()) {
|
||||
return Result::ERROR_POLICY_VALIDATION_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
// XXX: This would be cleaner and more efficient if we could get the trust
|
||||
// information without constructing a CERTCertificate here, but NSS doesn't
|
||||
// expose it in any other easy-to-use fashion. The use of
|
||||
|
@ -248,12 +242,10 @@ NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
|||
trustLevel = TrustLevel::TrustAnchor;
|
||||
return Success;
|
||||
}
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
if (CertIsAuthoritativeForEVPolicy(candidateCert, policy)) {
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
return Success;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1756,37 +1756,6 @@ AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
class InitializeIdentityInfo : public CryptoTask
|
||||
{
|
||||
virtual nsresult CalculateResult() override
|
||||
{
|
||||
EnsureIdentityInfoLoaded();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual void ReleaseNSSResources() override { } // no-op
|
||||
virtual void CallCallback(nsresult rv) override { } // no-op
|
||||
};
|
||||
#endif
|
||||
|
||||
void EnsureServerVerificationInitialized()
|
||||
{
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
// Should only be called from socket transport thread due to the static
|
||||
// variable and the reference to gCertVerificationThreadPool
|
||||
|
||||
static bool triggeredCertVerifierInit = false;
|
||||
if (triggeredCertVerifierInit)
|
||||
return;
|
||||
triggeredCertVerifierInit = true;
|
||||
|
||||
RefPtr<InitializeIdentityInfo> initJob = new InitializeIdentityInfo();
|
||||
if (gCertVerificationThreadPool)
|
||||
gCertVerificationThreadPool->Dispatch(initJob, NS_DISPATCH_NORMAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
SSLServerCertVerificationResult::SSLServerCertVerificationResult(
|
||||
nsNSSSocketInfo* infoObject, PRErrorCode errorCode,
|
||||
Telemetry::ID telemetryID, uint32_t telemetryValue,
|
||||
|
|
|
@ -14,11 +14,6 @@ namespace mozilla { namespace psm {
|
|||
SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd,
|
||||
PRBool checkSig, PRBool isServer);
|
||||
|
||||
// EnsureServerVerificationInitialized() posts an event to a cert
|
||||
// verification thread to run nsINSSComponent::EnsureIdentityInfoLoaded()
|
||||
// exactly once. It must be called from socket thread.
|
||||
void EnsureServerVerificationInitialized();
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1968,15 +1968,15 @@ nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence,
|
|||
if (mCert->extensions) {
|
||||
SECOidTag ev_oid_tag = SEC_OID_UNKNOWN;
|
||||
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
bool validEV;
|
||||
rv = hasValidEVOidTag(ev_oid_tag, validEV);
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!validEV)
|
||||
if (!validEV) {
|
||||
ev_oid_tag = SEC_OID_UNKNOWN;
|
||||
#endif
|
||||
}
|
||||
|
||||
rv = ProcessExtensions(mCert->extensions, sequence, ev_oid_tag, nssComponent);
|
||||
if (NS_FAILED(rv))
|
||||
|
|
|
@ -1134,16 +1134,13 @@ nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
|
||||
nsresult
|
||||
nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown())
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
EnsureIdentityInfoLoaded();
|
||||
}
|
||||
|
||||
RefPtr<mozilla::psm::SharedCertVerifier>
|
||||
certVerifier(mozilla::psm::GetDefaultCertVerifier());
|
||||
|
@ -1195,15 +1192,9 @@ nsNSSCertificate::getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
|
|||
return rv;
|
||||
}
|
||||
|
||||
#endif // MOZ_NO_EV_CERTS
|
||||
|
||||
nsresult
|
||||
nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV)
|
||||
{
|
||||
#ifdef MOZ_NO_EV_CERTS
|
||||
*aIsEV = false;
|
||||
return NS_OK;
|
||||
#else
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -1219,7 +1210,6 @@ nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV)
|
|||
|
||||
SECOidTag oid_tag;
|
||||
return getValidEVOidTag(oid_tag, *aIsEV);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -1475,10 +1475,6 @@ VerifyCertAtTime(nsIX509Cert* aCert,
|
|||
*aHasEVPolicy = false;
|
||||
*_retval = PR_UNKNOWN_ERROR;
|
||||
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
EnsureIdentityInfoLoaded();
|
||||
#endif
|
||||
|
||||
UniqueCERTCertificate nssCert(aCert->GetCert());
|
||||
if (!nssCert) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
|
|
@ -1816,6 +1816,12 @@ nsNSSComponent::InitializeNSS()
|
|||
DisableMD5();
|
||||
LoadLoadableRoots();
|
||||
|
||||
rv = LoadExtendedValidationInfo();
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("failed to load EV info"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
MaybeEnableFamilySafetyCompatibility();
|
||||
MaybeImportEnterpriseRoots();
|
||||
|
||||
|
@ -1933,9 +1939,7 @@ nsNSSComponent::ShutdownNSS()
|
|||
// TLSServerSocket may be run with the session cache enabled. This ensures
|
||||
// those resources are cleaned up.
|
||||
Unused << SSL_ShutdownServerSessionIDCache();
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
CleanupIdentityInfo();
|
||||
#endif
|
||||
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("evaporating psm resources"));
|
||||
if (NS_FAILED(nsNSSShutDownList::evaporateAllNSSResources())) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("failed to evaporate resources"));
|
||||
|
|
|
@ -2437,10 +2437,6 @@ nsSSLIOLayerImportFD(PRFileDesc* fd,
|
|||
goto loser;
|
||||
}
|
||||
|
||||
// This is an optimization to make sure the identity info dataset is parsed
|
||||
// and loaded on a separate thread and can be overlapped with network latency.
|
||||
EnsureServerVerificationInitialized();
|
||||
|
||||
return sslSock;
|
||||
loser:
|
||||
if (sslSock) {
|
||||
|
|
|
@ -129,11 +129,7 @@ nsSSLStatus::GetIsExtendedValidation(bool* aIsEV)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_NO_EV_CERTS
|
||||
return NS_OK;
|
||||
#else
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -290,7 +286,6 @@ nsSSLStatus::SetServerCert(nsNSSCertificate* aServerCert,
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef MOZ_NO_EV_CERTS
|
||||
if (aServerCert) {
|
||||
nsresult rv = aServerCert->GetIsExtendedValidation(&mIsEV);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -298,5 +293,4 @@ nsSSLStatus::SetServerCert(nsNSSCertificate* aServerCert,
|
|||
}
|
||||
mHasIsEVStatus = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче