Backed out changeset 8ef044a6a1fe (bug 1766687) for causing bustage in NSSCertDBTrustDomain.cpp

This commit is contained in:
Noemi Erli 2022-06-01 02:35:17 +03:00
Родитель 0785765372
Коммит aca984c8a8
19 изменённых файлов: 693 добавлений и 113 удалений

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

@ -12245,6 +12245,14 @@
value: 10
mirror: always
# NB: Changes to this pref affect CERT_CHAIN_SHA1_POLICY_STATUS telemetry.
# See the comment in CertVerifier.cpp.
# 1 = forbid sha1 in certificate signatures, even for imported roots
- name: security.pki.sha1_enforcement_level
type: RelaxedAtomicUint32
value: 1
mirror: always
# security.pki.netscape_step_up_policy controls how the platform handles the
# id-Netscape-stepUp OID in extended key usage extensions of CA certificates.
# 0: id-Netscape-stepUp is always considered equivalent to id-kp-serverAuth

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

@ -214,16 +214,10 @@ Result AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
return Success;
}
Result AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
Result AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm,
EndEntityOrCA, Time) {
switch (digestAlg) {
case DigestAlgorithm::sha256: // fall through
case DigestAlgorithm::sha384: // fall through
case DigestAlgorithm::sha512:
return Success;
case DigestAlgorithm::sha1:
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
}
// TODO: We should restrict signatures to SHA-256 or better.
return Success;
}
Result AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(

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

@ -104,7 +104,7 @@ void CertificateTransparencyInfo::Reset() {
CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays,
uint32_t certShortLifetimeInDays, SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode,
CRLiteMode crliteMode,
@ -114,6 +114,7 @@ CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mOCSPTimeoutSoft(ocspTimeoutSoft),
mOCSPTimeoutHard(ocspTimeoutHard),
mCertShortLifetimeInDays(certShortLifetimeInDays),
mSHA1Mode(sha1Mode),
mNetscapeStepUpPolicy(netscapeStepUpPolicy),
mCTMode(ctMode),
mCRLiteMode(crliteMode) {
@ -445,6 +446,24 @@ Result CertVerifier::VerifyCertificateTransparencyPolicy(
return Success;
}
bool CertVerifier::SHA1ModeMoreRestrictiveThanGivenMode(SHA1Mode mode) {
switch (mSHA1Mode) {
case SHA1Mode::Forbidden:
return mode != SHA1Mode::Forbidden;
case SHA1Mode::ImportedRoot:
return mode != SHA1Mode::Forbidden && mode != SHA1Mode::ImportedRoot;
case SHA1Mode::ImportedRootOrBefore2016:
return mode == SHA1Mode::Allowed;
case SHA1Mode::Allowed:
return false;
// MSVC warns unless we explicitly handle this now-unused option.
case SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
default:
MOZ_ASSERT(false, "unexpected SHA1Mode type");
return true;
}
}
Result CertVerifier::VerifyCert(
const nsTArray<uint8_t>& certBytes, SECCertificateUsage usage, Time time,
void* pinArg, const char* hostname,
@ -457,6 +476,7 @@ Result CertVerifier::VerifyCert(
/*optional out*/ EVStatus* evStatus,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
/*optional out*/ KeySizeStatus* keySizeStatus,
/*optional out*/ SHA1ModeResult* sha1ModeResult,
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
/*optional out*/ CertificateTransparencyInfo* ctInfo,
/*optional out*/ bool* isBuiltChainRootBuiltInRoot) {
@ -464,6 +484,7 @@ Result CertVerifier::VerifyCert(
MOZ_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
MOZ_ASSERT(usage == certificateUsageSSLServer || !keySizeStatus);
MOZ_ASSERT(usage == certificateUsageSSLServer || !sha1ModeResult);
if (NS_FAILED(BlockUntilLoadableCertsLoaded())) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
@ -489,6 +510,13 @@ Result CertVerifier::VerifyCert(
*keySizeStatus = KeySizeStatus::NeverChecked;
}
if (sha1ModeResult) {
if (usage != certificateUsageSSLServer) {
return Result::FATAL_ERROR_INVALID_ARGS;
}
*sha1ModeResult = SHA1ModeResult::NeverChecked;
}
if (usage != certificateUsageSSLServer && (flags & FLAG_MUST_BE_EV)) {
return Result::FATAL_ERROR_INVALID_ARGS;
}
@ -539,10 +567,10 @@ Result CertVerifier::VerifyCert(
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, NetscapeStepUpPolicy::NeverMatch,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
rv = BuildCertChain(
trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyPurposeId::id_kp_clientAuth,
@ -555,6 +583,30 @@ Result CertVerifier::VerifyCert(
// restrict the acceptable key usage based on the key exchange method
// chosen by the server.
// These configurations are in order of most restrictive to least
// restrictive. This enables us to gather telemetry on the expected
// results of setting the default policy to a particular configuration.
SHA1Mode sha1ModeConfigurations[] = {
SHA1Mode::Forbidden,
SHA1Mode::ImportedRoot,
SHA1Mode::ImportedRootOrBefore2016,
SHA1Mode::Allowed,
};
SHA1ModeResult sha1ModeResults[] = {
SHA1ModeResult::SucceededWithoutSHA1,
SHA1ModeResult::SucceededWithImportedRoot,
SHA1ModeResult::SucceededWithImportedRootOrSHA1Before2016,
SHA1ModeResult::SucceededWithSHA1,
};
size_t sha1ModeConfigurationsCount =
MOZ_ARRAY_LENGTH(sha1ModeConfigurations);
static_assert(MOZ_ARRAY_LENGTH(sha1ModeConfigurations) ==
MOZ_ARRAY_LENGTH(sha1ModeResults),
"digestAlgorithm array lengths differ");
// Try to validate for EV first.
NSSCertDBTrustDomain::OCSPFetching evOCSPFetching =
(mOCSPDownloadConfig == ocspOff) || (flags & FLAG_LOCAL_ONLY)
@ -564,14 +616,32 @@ Result CertVerifier::VerifyCert(
CertPolicyId evPolicy;
bool foundEVPolicy = GetFirstEVPolicy(certBytes, evPolicy);
rv = Result::ERROR_UNKNOWN_ERROR;
if (foundEVPolicy) {
for (size_t i = 0;
i < sha1ModeConfigurationsCount && rv != Success && foundEVPolicy;
i++) {
// Don't attempt verification if the SHA1 mode set by preferences
// (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
// (To put it another way, only attempt verification if the SHA1 mode
// option we're on is as restrictive or more restrictive than
// mSHA1Mode.) This allows us to gather telemetry information while
// still enforcing the mode set by preferences.
if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[i])) {
continue;
}
// Because of the try-strict and fallback approach, we have to clear any
// previously noted telemetry information.
if (pinningTelemetryInfo) {
pinningTelemetryInfo->Reset();
}
NSSCertDBTrustDomain trustDomain(
trustSSL, evOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS,
ValidityCheckingMode::CheckForEV, mNetscapeStepUpPolicy,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
ValidityCheckingMode::CheckForEV, sha1ModeConfigurations[i],
mNetscapeStepUpPolicy, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, // (EC)DHE
@ -579,21 +649,36 @@ Result CertVerifier::VerifyCert(
KeyUsage::keyAgreement, // (EC)DH
KeyPurposeId::id_kp_serverAuth, evPolicy, stapledOCSPResponse,
ocspStaplingStatus);
if (rv == Success) {
rv = VerifyCertificateTransparencyPolicy(
trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
if (rv == Success &&
sha1ModeConfigurations[i] == SHA1Mode::ImportedRoot &&
trustDomain.GetIsBuiltChainRootBuiltInRoot()) {
rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
}
if (rv == Success) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("cert is EV with status %i\n",
static_cast<int>(sha1ModeResults[i])));
if (evStatus) {
*evStatus = EVStatus::EV;
*evStatus = foundEVPolicy ? EVStatus::EV : EVStatus::NotEV;
}
if (sha1ModeResult) {
*sha1ModeResult = sha1ModeResults[i];
}
rv = VerifyCertificateTransparencyPolicy(
trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
if (rv != Success) {
break;
}
if (isBuiltChainRootBuiltInRoot) {
*isBuiltChainRootBuiltInRoot =
trustDomain.GetIsBuiltChainRootBuiltInRoot();
}
break;
}
}
if (rv == Success) {
break;
}
if (flags & FLAG_MUST_BE_EV) {
rv = Result::ERROR_POLICY_VALIDATION_FAILED;
break;
@ -612,53 +697,86 @@ Result CertVerifier::VerifyCert(
size_t keySizeOptionsCount = MOZ_ARRAY_LENGTH(keySizeStatuses);
for (size_t i = 0; i < keySizeOptionsCount && rv != Success; i++) {
// invalidate any telemetry info relating to failed chains
if (pinningTelemetryInfo) {
pinningTelemetryInfo->Reset();
}
for (size_t j = 0; j < sha1ModeConfigurationsCount && rv != Success;
j++) {
// Don't attempt verification if the SHA1 mode set by preferences
// (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
// (To put it another way, only attempt verification if the SHA1 mode
// option we're on is as restrictive or more restrictive than
// mSHA1Mode.) This allows us to gather telemetry information while
// still enforcing the mode set by preferences.
if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[j])) {
continue;
}
NSSCertDBTrustDomain trustDomain(
trustSSL, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, keySizeOptions[i],
ValidityCheckingMode::CheckingOff, mNetscapeStepUpPolicy,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, //(EC)DHE
KeyUsage::keyEncipherment, // RSA
KeyUsage::keyAgreement, //(EC)DH
KeyPurposeId::id_kp_serverAuth, CertPolicyId::anyPolicy,
stapledOCSPResponse, ocspStaplingStatus);
if (rv != Success && !IsFatalError(rv) &&
rv != Result::ERROR_REVOKED_CERTIFICATE &&
trustDomain.GetIsErrorDueToDistrustedCAPolicy()) {
// Bug 1444440 - If there are multiple paths, at least one to a CA
// distrusted-by-policy, and none of them ending in a trusted root,
// then we might show a different error (UNKNOWN_ISSUER) than we
// intend, confusing users.
rv = Result::ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED;
}
if (rv == Success) {
rv = VerifyCertificateTransparencyPolicy(
trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
}
if (rv == Success) {
if (keySizeStatus) {
*keySizeStatus = keySizeStatuses[i];
// invalidate any telemetry info relating to failed chains
if (pinningTelemetryInfo) {
pinningTelemetryInfo->Reset();
}
if (isBuiltChainRootBuiltInRoot) {
*isBuiltChainRootBuiltInRoot =
trustDomain.GetIsBuiltChainRootBuiltInRoot();
NSSCertDBTrustDomain trustDomain(
trustSSL, defaultOCSPFetching, mOCSPCache, pinArg,
mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
keySizeOptions[i], ValidityCheckingMode::CheckingOff,
sha1ModeConfigurations[j], mNetscapeStepUpPolicy, mCRLiteMode,
originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, //(EC)DHE
KeyUsage::keyEncipherment, // RSA
KeyUsage::keyAgreement, //(EC)DH
KeyPurposeId::id_kp_serverAuth, CertPolicyId::anyPolicy,
stapledOCSPResponse, ocspStaplingStatus);
if (rv != Success && !IsFatalError(rv) &&
rv != Result::ERROR_REVOKED_CERTIFICATE &&
trustDomain.GetIsErrorDueToDistrustedCAPolicy()) {
// Bug 1444440 - If there are multiple paths, at least one to a CA
// distrusted-by-policy, and none of them ending in a trusted root,
// then we might show a different error (UNKNOWN_ISSUER) than we
// intend, confusing users.
rv = Result::ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED;
}
if (rv == Success &&
sha1ModeConfigurations[j] == SHA1Mode::ImportedRoot &&
trustDomain.GetIsBuiltChainRootBuiltInRoot()) {
rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
}
if (rv == Success) {
if (keySizeStatus) {
*keySizeStatus = keySizeStatuses[i];
}
if (sha1ModeResult) {
*sha1ModeResult = sha1ModeResults[j];
}
rv = VerifyCertificateTransparencyPolicy(
trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
if (rv != Success) {
break;
}
if (isBuiltChainRootBuiltInRoot) {
*isBuiltChainRootBuiltInRoot =
trustDomain.GetIsBuiltChainRootBuiltInRoot();
}
}
break;
}
}
if (rv != Success && keySizeStatus) {
if (rv == Success) {
break;
}
if (keySizeStatus) {
*keySizeStatus = KeySizeStatus::AlreadyBad;
}
// The telemetry probe CERT_CHAIN_SHA1_POLICY_STATUS gives us feedback on
// the result of setting a specific policy. However, we don't want noise
// from users who have manually set the policy to something other than the
// default, so we only collect for Forbidden (which is the default).
if (sha1ModeResult && mSHA1Mode == SHA1Mode::Forbidden) {
*sha1ModeResult = SHA1ModeResult::Failed;
}
break;
}
@ -667,10 +785,10 @@ Result CertVerifier::VerifyCert(
NSSCertDBTrustDomain trustDomain(
trustSSL, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, mNetscapeStepUpPolicy, mCRLiteMode,
originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
mNetscapeStepUpPolicy, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeCA,
KeyUsage::keyCertSign, KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy, stapledOCSPResponse);
@ -681,10 +799,10 @@ Result CertVerifier::VerifyCert(
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, NetscapeStepUpPolicy::NeverMatch,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
rv = BuildCertChain(
trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyPurposeId::id_kp_emailProtection,
@ -705,10 +823,10 @@ Result CertVerifier::VerifyCert(
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, NetscapeStepUpPolicy::NeverMatch,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, nullptr, nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA
@ -761,6 +879,7 @@ Result CertVerifier::VerifySSLServerCert(
/*optional out*/ EVStatus* evStatus,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
/*optional out*/ KeySizeStatus* keySizeStatus,
/*optional out*/ SHA1ModeResult* sha1ModeResult,
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
/*optional out*/ CertificateTransparencyInfo* ctInfo,
/*optional out*/ bool* isBuiltChainRootBuiltInRoot) {
@ -792,7 +911,7 @@ Result CertVerifier::VerifySSLServerCert(
PromiseFlatCString(hostname).get(), builtChain, flags,
extraCertificates, stapledOCSPResponse, sctsFromTLS,
originAttributes, evStatus, ocspStaplingStatus, keySizeStatus,
pinningTelemetryInfo, ctInfo,
sha1ModeResult, pinningTelemetryInfo, ctInfo,
&isBuiltChainRootBuiltInRootLocal);
if (rv != Success) {
// we don't use the certificate for path building, so this parameter doesn't

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

@ -61,6 +61,16 @@ enum class KeySizeStatus {
AlreadyBad = 3,
};
// These values correspond to the CERT_CHAIN_SHA1_POLICY_STATUS telemetry.
enum class SHA1ModeResult {
NeverChecked = 0,
SucceededWithoutSHA1 = 1,
SucceededWithImportedRoot = 2,
SucceededWithImportedRootOrSHA1Before2016 = 3,
SucceededWithSHA1 = 4,
Failed = 5,
};
enum class CRLiteMode {
Disabled = 0,
TelemetryOnly = 1,
@ -160,6 +170,7 @@ class CertVerifier {
/*optional out*/ EVStatus* evStatus = nullptr,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
/*optional out*/ SHA1ModeResult* sha1ModeResult = nullptr,
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
/*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr);
@ -180,10 +191,22 @@ class CertVerifier {
/*optional out*/ EVStatus* evStatus = nullptr,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
/*optional out*/ SHA1ModeResult* sha1ModeResult = nullptr,
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
/*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr);
enum class SHA1Mode {
Allowed = 0,
Forbidden = 1,
// There used to be a policy that only allowed SHA1 for certificates issued
// before 2016. This is no longer available. If a user has selected this
// policy in about:config, it now maps to Forbidden.
UsedToBeBefore2016ButNowIsForbidden = 2,
ImportedRoot = 3,
ImportedRootOrBefore2016 = 4,
};
enum OcspDownloadConfig { ocspOff = 0, ocspOn = 1, ocspEVOnly = 2 };
enum OcspStrictConfig { ocspRelaxed = 0, ocspStrict };
@ -195,7 +218,7 @@ class CertVerifier {
CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays,
uint32_t certShortLifetimeInDays, SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode, CRLiteMode crliteMode,
const Vector<EnterpriseCert>& thirdPartyCerts);
@ -208,6 +231,7 @@ class CertVerifier {
const mozilla::TimeDuration mOCSPTimeoutSoft;
const mozilla::TimeDuration mOCSPTimeoutHard;
const uint32_t mCertShortLifetimeInDays;
const SHA1Mode mSHA1Mode;
const NetscapeStepUpPolicy mNetscapeStepUpPolicy;
const CertificateTransparencyMode mCTMode;
const CRLiteMode mCRLiteMode;
@ -233,6 +257,12 @@ class CertVerifier {
const nsTArray<nsTArray<uint8_t>>& builtChain,
mozilla::pkix::Input sctsFromTLS, mozilla::pkix::Time time,
/*optional out*/ CertificateTransparencyInfo* ctInfo);
// Returns true if the configured SHA1 mode is more restrictive than the given
// mode. SHA1Mode::Forbidden is more restrictive than any other mode except
// Forbidden. Next is ImportedRoot, then ImportedRootOrBefore2016, then
// Allowed. (A mode is never more restrictive than itself.)
bool SHA1ModeMoreRestrictiveThanGivenMode(SHA1Mode mode);
};
mozilla::pkix::Result IsCertBuiltInRoot(pkix::Input certInput, bool& result);

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

@ -13,6 +13,7 @@
#include "ExtendedValidation.h"
#include "MultiLogCTVerifier.h"
#include "NSSErrorsService.h"
#include "OCSPVerificationTrustDomain.h"
#include "PublicKeyPinningService.h"
#include "cert.h"
#include "cert_storage/src/cert_storage.h"
@ -71,8 +72,8 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
/*optional but shouldn't be*/ void* pinArg, TimeDuration ocspTimeoutSoft,
TimeDuration ocspTimeoutHard, uint32_t certShortLifetimeInDays,
unsigned int minRSABits, ValidityCheckingMode validityCheckingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy, CRLiteMode crliteMode,
const OriginAttributes& originAttributes,
CertVerifier::SHA1Mode sha1Mode, NetscapeStepUpPolicy netscapeStepUpPolicy,
CRLiteMode crliteMode, const OriginAttributes& originAttributes,
const Vector<Input>& thirdPartyRootInputs,
const Vector<Input>& thirdPartyIntermediateInputs,
const Maybe<nsTArray<nsTArray<uint8_t>>>& extraCertificates,
@ -88,6 +89,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
mCertShortLifetimeInDays(certShortLifetimeInDays),
mMinRSABits(minRSABits),
mValidityCheckingMode(validityCheckingMode),
mSHA1Mode(sha1Mode),
mNetscapeStepUpPolicy(netscapeStepUpPolicy),
mCRLiteMode(crliteMode),
mSawDistrustedCAByPolicyError(false),
@ -1120,9 +1122,18 @@ Result NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
Time thisUpdate(Time::uninitialized);
Time validThrough(Time::uninitialized);
Result rv = VerifyEncodedOCSPResponse(*this, certID, time, maxLifetimeInDays,
encodedResponse, expired, &thisUpdate,
&validThrough);
// We use a try and fallback approach which first mandates good signature
// digest algorithms, then falls back to SHA-1 if this fails. If a delegated
// OCSP response signing certificate was issued with a SHA-1 signature,
// verification initially fails. We cache the failure and then re-use that
// result even when doing fallback (i.e. when weak signature digest algorithms
// should succeed). To address this we use an OCSPVerificationTrustDomain
// here, rather than using *this, to ensure verification succeeds for all
// allowed signature digest algorithms.
OCSPVerificationTrustDomain trustDomain(*this);
Result rv = VerifyEncodedOCSPResponse(trustDomain, certID, time,
maxLifetimeInDays, encodedResponse,
expired, &thisUpdate, &validThrough);
// If a response was stapled and expired, we don't want to cache it. Return
// early to simplify the logic here.
if (responseSource == ResponseWasStapled && expired) {
@ -1370,15 +1381,39 @@ Result NSSCertDBTrustDomain::IsChainValid(const DERArray& reversedDERArray,
}
Result NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(
DigestAlgorithm aAlg, EndEntityOrCA /*endEntityOrCA*/, Time /*notBefore*/) {
switch (aAlg) {
case DigestAlgorithm::sha256: // fall through
case DigestAlgorithm::sha384: // fall through
case DigestAlgorithm::sha512:
return Success;
case DigestAlgorithm::sha1:
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
DigestAlgorithm aAlg, EndEntityOrCA endEntityOrCA, Time notBefore) {
// (new Date("2016-01-01T00:00:00Z")).getTime() / 1000
static const Time JANUARY_FIRST_2016 = TimeFromEpochInSeconds(1451606400);
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain: CheckSignatureDigestAlgorithm"));
if (aAlg == DigestAlgorithm::sha1) {
switch (mSHA1Mode) {
case CertVerifier::SHA1Mode::Forbidden:
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("SHA-1 certificate rejected"));
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
case CertVerifier::SHA1Mode::ImportedRootOrBefore2016:
if (JANUARY_FIRST_2016 <= notBefore) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("Post-2015 SHA-1 certificate rejected"));
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
}
break;
case CertVerifier::SHA1Mode::Allowed:
// Enforcing that the resulting chain uses an imported root is only
// possible at a higher level. This is done in CertVerifier::VerifyCert.
case CertVerifier::SHA1Mode::ImportedRoot:
default:
break;
// MSVC warns unless we explicitly handle this now-unused option.
case CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
MOZ_ASSERT_UNREACHABLE("unexpected SHA1Mode type");
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
}
return Success;
}
Result NSSCertDBTrustDomain::CheckRSAPublicKeyModulusSizeInBits(

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

@ -142,6 +142,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
OCSPCache& ocspCache, void* pinArg, mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard, uint32_t certShortLifetimeInDays,
unsigned int minRSABits, ValidityCheckingMode validityCheckingMode,
CertVerifier::SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy, CRLiteMode crliteMode,
const OriginAttributes& originAttributes,
const Vector<mozilla::pkix::Input>& thirdPartyRootInputs,
@ -278,6 +279,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
const uint32_t mCertShortLifetimeInDays;
const unsigned int mMinRSABits;
ValidityCheckingMode mValidityCheckingMode;
CertVerifier::SHA1Mode mSHA1Mode;
NetscapeStepUpPolicy mNetscapeStepUpPolicy;
CRLiteMode mCRLiteMode;
bool mSawDistrustedCAByPolicyError;

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

@ -0,0 +1,114 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "OCSPVerificationTrustDomain.h"
using namespace mozilla;
using namespace mozilla::pkix;
namespace mozilla {
namespace psm {
OCSPVerificationTrustDomain::OCSPVerificationTrustDomain(
NSSCertDBTrustDomain& certDBTrustDomain)
: mCertDBTrustDomain(certDBTrustDomain) {}
Result OCSPVerificationTrustDomain::GetCertTrust(
EndEntityOrCA endEntityOrCA, const CertPolicyId& policy,
Input candidateCertDER,
/*out*/ TrustLevel& trustLevel) {
return mCertDBTrustDomain.GetCertTrust(endEntityOrCA, policy,
candidateCertDER, trustLevel);
}
Result OCSPVerificationTrustDomain::FindIssuer(Input, IssuerChecker&, Time) {
// We do not expect this to be called for OCSP signers
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time,
const CertPolicyId&) {
// We do not expect this to be called for OCSP signers
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result OCSPVerificationTrustDomain::CheckRevocation(EndEntityOrCA,
const CertID&, Time,
Duration, const Input*,
const Input*,
const Input*) {
// We do not expect this to be called for OCSP signers
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result OCSPVerificationTrustDomain::CheckSignatureDigestAlgorithm(
DigestAlgorithm aAlg, EndEntityOrCA aEEOrCA, Time notBefore) {
// The reason for wrapping the NSSCertDBTrustDomain in an
// OCSPVerificationTrustDomain is to allow us to bypass the weaker signature
// algorithm check - thus all allowable signature digest algorithms should
// always be accepted. This is only needed while we gather telemetry on SHA-1.
return Success;
}
Result OCSPVerificationTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
EndEntityOrCA aEEOrCA, unsigned int aModulusSizeInBits) {
return mCertDBTrustDomain.CheckRSAPublicKeyModulusSizeInBits(
aEEOrCA, aModulusSizeInBits);
}
Result OCSPVerificationTrustDomain::VerifyRSAPKCS1SignedData(
Input data, DigestAlgorithm digestAlgorithm, Input signature,
Input subjectPublicKeyInfo) {
return mCertDBTrustDomain.VerifyRSAPKCS1SignedData(
data, digestAlgorithm, signature, subjectPublicKeyInfo);
}
Result OCSPVerificationTrustDomain::VerifyRSAPSSSignedData(
Input data, DigestAlgorithm digestAlgorithm, Input signature,
Input subjectPublicKeyInfo) {
return mCertDBTrustDomain.VerifyRSAPSSSignedData(
data, digestAlgorithm, signature, subjectPublicKeyInfo);
}
Result OCSPVerificationTrustDomain::CheckECDSACurveIsAcceptable(
EndEntityOrCA aEEOrCA, NamedCurve aCurve) {
return mCertDBTrustDomain.CheckECDSACurveIsAcceptable(aEEOrCA, aCurve);
}
Result OCSPVerificationTrustDomain::VerifyECDSASignedData(
Input data, DigestAlgorithm digestAlgorithm, Input signature,
Input subjectPublicKeyInfo) {
return mCertDBTrustDomain.VerifyECDSASignedData(
data, digestAlgorithm, signature, subjectPublicKeyInfo);
}
Result OCSPVerificationTrustDomain::CheckValidityIsAcceptable(
Time notBefore, Time notAfter, EndEntityOrCA endEntityOrCA,
KeyPurposeId keyPurpose) {
return mCertDBTrustDomain.CheckValidityIsAcceptable(
notBefore, notAfter, endEntityOrCA, keyPurpose);
}
Result OCSPVerificationTrustDomain::NetscapeStepUpMatchesServerAuth(
Time notBefore,
/*out*/ bool& matches) {
return mCertDBTrustDomain.NetscapeStepUpMatchesServerAuth(notBefore, matches);
}
void OCSPVerificationTrustDomain::NoteAuxiliaryExtension(
AuxiliaryExtension extension, Input extensionData) {
mCertDBTrustDomain.NoteAuxiliaryExtension(extension, extensionData);
}
Result OCSPVerificationTrustDomain::DigestBuf(Input item,
DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf,
size_t digestBufLen) {
return mCertDBTrustDomain.DigestBuf(item, digestAlg, digestBuf, digestBufLen);
}
} // namespace psm
} // namespace mozilla

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

@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_psm__OCSPVerificationTrustDomain_h
#define mozilla_psm__OCSPVerificationTrustDomain_h
#include "mozpkix/pkixtypes.h"
#include "NSSCertDBTrustDomain.h"
namespace mozilla {
namespace psm {
typedef mozilla::pkix::Result Result;
class OCSPVerificationTrustDomain : public mozilla::pkix::TrustDomain {
public:
explicit OCSPVerificationTrustDomain(NSSCertDBTrustDomain& certDBTrustDomain);
virtual Result FindIssuer(mozilla::pkix::Input encodedIssuerName,
IssuerChecker& checker,
mozilla::pkix::Time time) override;
virtual Result GetCertTrust(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
const mozilla::pkix::CertPolicyId& policy,
mozilla::pkix::Input candidateCertDER,
/*out*/ mozilla::pkix::TrustLevel& trustLevel) override;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg,
mozilla::pkix::EndEntityOrCA endEntityOrCA,
mozilla::pkix::Time notBefore) override;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits) override;
virtual Result VerifyRSAPKCS1SignedData(
mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm,
mozilla::pkix::Input signature,
mozilla::pkix::Input subjectPublicKeyInfo) override;
virtual Result VerifyRSAPSSSignedData(
mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm,
mozilla::pkix::Input signature,
mozilla::pkix::Input subjectPublicKeyInfo) override;
virtual Result CheckECDSACurveIsAcceptable(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
mozilla::pkix::NamedCurve curve) override;
virtual Result VerifyECDSASignedData(
mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm,
mozilla::pkix::Input signature,
mozilla::pkix::Input subjectPublicKeyInfo) override;
virtual Result DigestBuf(mozilla::pkix::Input item,
mozilla::pkix::DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf,
size_t digestBufLen) override;
virtual Result CheckValidityIsAcceptable(
mozilla::pkix::Time notBefore, mozilla::pkix::Time notAfter,
mozilla::pkix::EndEntityOrCA endEntityOrCA,
mozilla::pkix::KeyPurposeId keyPurpose) override;
virtual Result NetscapeStepUpMatchesServerAuth(
mozilla::pkix::Time notBefore,
/*out*/ bool& matches) override;
virtual Result CheckRevocation(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
const mozilla::pkix::CertID& certID, mozilla::pkix::Time time,
mozilla::pkix::Duration validityDuration,
/*optional*/ const mozilla::pkix::Input* stapledOCSPResponse,
/*optional*/ const mozilla::pkix::Input* aiaExtension,
/*optional*/ const mozilla::pkix::Input* sctExtension) override;
virtual Result IsChainValid(
const mozilla::pkix::DERArray& certChain, mozilla::pkix::Time time,
const mozilla::pkix::CertPolicyId& requiredPolicy) override;
virtual void NoteAuxiliaryExtension(
mozilla::pkix::AuxiliaryExtension extension,
mozilla::pkix::Input extensionData) override;
private:
NSSCertDBTrustDomain& mCertDBTrustDomain;
};
} // namespace psm
} // namespace mozilla
#endif // mozilla_psm__OCSPVerificationTrustDomain_h

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

@ -16,6 +16,7 @@ UNIFIED_SOURCES += [
"CertVerifier.cpp",
"NSSCertDBTrustDomain.cpp",
"OCSPCache.cpp",
"OCSPVerificationTrustDomain.cpp",
]
if not CONFIG["NSS_NO_EV_CERTS"]:

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

@ -131,14 +131,10 @@ Result CSTrustDomain::IsChainValid(const DERArray& certChain, Time time,
Result CSTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
EndEntityOrCA endEntityOrCA,
Time notBefore) {
switch (digestAlg) {
case DigestAlgorithm::sha256: // fall through
case DigestAlgorithm::sha384: // fall through
case DigestAlgorithm::sha512:
return Success;
case DigestAlgorithm::sha1:
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
if (digestAlg == DigestAlgorithm::sha1) {
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
}
return Success;
}
Result CSTrustDomain::CheckRSAPublicKeyModulusSizeInBits(

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

@ -638,7 +638,7 @@ void GatherCertificateTransparencyTelemetry(
static void CollectCertTelemetry(
mozilla::pkix::Result aCertVerificationResult, EVStatus aEVStatus,
CertVerifier::OCSPStaplingStatus aOcspStaplingStatus,
KeySizeStatus aKeySizeStatus,
KeySizeStatus aKeySizeStatus, SHA1ModeResult aSha1ModeResult,
const PinningTelemetryInfo& aPinningTelemetryInfo,
const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain,
const CertificateTransparencyInfo& aCertificateTransparencyInfo) {
@ -656,6 +656,11 @@ static void CollectCertTelemetry(
static_cast<uint32_t>(aKeySizeStatus));
}
if (aSha1ModeResult != SHA1ModeResult::NeverChecked) {
Telemetry::Accumulate(Telemetry::CERT_CHAIN_SHA1_POLICY_STATUS,
static_cast<uint32_t>(aSha1ModeResult));
}
if (aPinningTelemetryInfo.accumulateForRoot) {
Telemetry::Accumulate(Telemetry::CERT_PINNING_FAILURES_BY_CA,
aPinningTelemetryInfo.rootBucket);
@ -694,6 +699,7 @@ Result AuthCertificate(
CertVerifier::OCSPStaplingStatus ocspStaplingStatus =
CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked;
SHA1ModeResult sha1ModeResult = SHA1ModeResult::NeverChecked;
PinningTelemetryInfo pinningTelemetryInfo;
nsTArray<nsTArray<uint8_t>> peerCertsBytes;
@ -709,11 +715,12 @@ Result AuthCertificate(
certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags,
Some(std::move(peerCertsBytes)), stapledOCSPResponse,
sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus,
&ocspStaplingStatus, &keySizeStatus, &pinningTelemetryInfo,
&certificateTransparencyInfo, &aIsBuiltCertChainRootBuiltInRoot);
&ocspStaplingStatus, &keySizeStatus, &sha1ModeResult,
&pinningTelemetryInfo, &certificateTransparencyInfo,
&aIsBuiltCertChainRootBuiltInRoot);
CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus,
pinningTelemetryInfo, builtCertChain,
sha1ModeResult, pinningTelemetryInfo, builtCertChain,
certificateTransparencyInfo);
return rv;

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

@ -23,13 +23,14 @@ class SharedCertVerifier : public mozilla::psm::CertVerifier {
SharedCertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mozilla::TimeDuration ocspSoftTimeout,
mozilla::TimeDuration ocspHardTimeout,
uint32_t certShortLifetimeInDays,
uint32_t certShortLifetimeInDays, SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode, CRLiteMode crliteMode,
const Vector<EnterpriseCert>& thirdPartyCerts)
: mozilla::psm::CertVerifier(
odc, osc, ocspSoftTimeout, ocspHardTimeout, certShortLifetimeInDays,
netscapeStepUpPolicy, ctMode, crliteMode, thirdPartyCerts) {}
: mozilla::psm::CertVerifier(odc, osc, ocspSoftTimeout, ocspHardTimeout,
certShortLifetimeInDays, sha1Mode,
netscapeStepUpPolicy, ctMode, crliteMode,
thirdPartyCerts) {}
};
} // namespace psm

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

@ -1098,6 +1098,7 @@ static void RebuildVerifiedCertificateInformation(PRFileDesc* fd,
&evStatus,
nullptr, // OCSP stapling telemetry
nullptr, // key size telemetry
nullptr, // SHA-1 telemetry
nullptr, // pinning telemetry
&certificateTransparencyInfo, &isBuiltCertChainRootBuiltInRoot);

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

@ -1418,6 +1418,25 @@ void nsNSSComponent::setValidationOptions(
Telemetry::Accumulate(Telemetry::CERT_OCSP_REQUIRED, ocspRequired);
}
CertVerifier::SHA1Mode sha1Mode = static_cast<CertVerifier::SHA1Mode>(
StaticPrefs::security_pki_sha1_enforcement_level());
switch (sha1Mode) {
case CertVerifier::SHA1Mode::Allowed:
case CertVerifier::SHA1Mode::Forbidden:
case CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
case CertVerifier::SHA1Mode::ImportedRoot:
case CertVerifier::SHA1Mode::ImportedRootOrBefore2016:
break;
default:
sha1Mode = CertVerifier::SHA1Mode::Allowed;
break;
}
// Convert a previously-available setting to a safe one.
if (sha1Mode == CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden) {
sha1Mode = CertVerifier::SHA1Mode::Forbidden;
}
NetscapeStepUpPolicy netscapeStepUpPolicy = static_cast<NetscapeStepUpPolicy>(
StaticPrefs::security_pki_netscape_step_up_policy());
switch (netscapeStepUpPolicy) {
@ -1455,7 +1474,7 @@ void nsNSSComponent::setValidationOptions(
softTimeout, hardTimeout);
mDefaultCertVerifier = new SharedCertVerifier(
odc, osc, softTimeout, hardTimeout, certShortLifetimeInDays,
odc, osc, softTimeout, hardTimeout, certShortLifetimeInDays, sha1Mode,
netscapeStepUpPolicy, ctMode, crliteMode, mEnterpriseCerts);
}
@ -1472,7 +1491,7 @@ void nsNSSComponent::UpdateCertVerifierWithEnterpriseRoots() {
oldCertVerifier->mOCSPStrict ? CertVerifier::ocspStrict
: CertVerifier::ocspRelaxed,
oldCertVerifier->mOCSPTimeoutSoft, oldCertVerifier->mOCSPTimeoutHard,
oldCertVerifier->mCertShortLifetimeInDays,
oldCertVerifier->mCertShortLifetimeInDays, oldCertVerifier->mSHA1Mode,
oldCertVerifier->mNetscapeStepUpPolicy, oldCertVerifier->mCTMode,
oldCertVerifier->mCRLiteMode, mEnterpriseCerts);
}
@ -2273,6 +2292,7 @@ nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
prefName.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
prefName.EqualsLiteral(
"security.pki.certificate_transparency.mode") ||
prefName.EqualsLiteral("security.pki.sha1_enforcement_level") ||
prefName.EqualsLiteral("security.pki.netscape_step_up_policy") ||
prefName.EqualsLiteral(
"security.OCSP.timeoutMilliseconds.soft") ||

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

@ -3,7 +3,8 @@
// 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/.
// Tests the rejection of SHA-1 certificates.
// Tests the rejection of SHA-1 certificates based on the preference
// security.pki.sha1_enforcement_level.
"use strict";
@ -12,6 +13,9 @@ const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
Ci.nsIX509CertDB
);
// We need to test as if we are at a fixed time, so that we are testing the
// 2016 checks on SHA-1, not the notBefore checks.
//
// (new Date("2016-03-01")).getTime() / 1000
const VALIDATION_TIME = 1456790400;
@ -38,6 +42,63 @@ add_task(async function() {
loadCertWithTrust("int-pre", ",,");
loadCertWithTrust("int-post", ",,");
// Test cases per pref setting
//
// root intermed. end entity
// ===========================
// root
// |
// +--- pre-2016
// | |
// | +----- pre-2016 <--- (a)
// | +----- post-2016 <--- (b)
// |
// +--- post-2016
// |
// +----- post-2016 <--- (c)
//
// Expected outcomes (accept / reject):
//
// a b c
// Allowed (0) Accept Accept Accept
// Forbidden (1) Reject Reject Reject
// (2) is no longer available and is treated as Forbidden (1) internally.
// ImportedRoot (3) Reject Reject Reject (for built-in roots)
// ImportedRoot Accept Accept Accept (for non-built-in roots)
// ImportedRootOrBefore2016 (4) Accept Reject Reject (for built-in roots)
// ImportedRootOrBefore2016 Accept Accept Accept (for non-built-in roots)
//
// The pref setting of ImportedRoot accepts usage of SHA-1 only for
// certificates issued by non-built-in roots. By default, the testing
// certificates are all considered issued by a non-built-in root. However, we
// have the ability to treat a given non-built-in root as built-in. We test
// both of these situations below.
//
// As a historical note, a policy option (Before2016) was previously available
// that only allowed SHA-1 for certificates with a notBefore before 2016.
// However, to enable the policy of only allowing SHA-1 from non-built-in
// roots in the most straightforward way (while still having a time-based
// policy that users could enable if this new policy were problematic),
// Before2016 was shifted to also allow SHA-1 from non-built-in roots, hence
// ImportedRootOrBefore2016.
//
// A note about intermediate certificates: the certificate verifier has the
// ability to directly verify a given certificate for the purpose of issuing
// TLS web server certificates. However, when asked to do so, the certificate
// verifier does not take into account the currently configured SHA-1 policy.
// This is in part due to implementation complexity and because this isn't
// actually how TLS web server certificates are verified in the TLS handshake
// (which makes a full implementation that supports heeding the SHA-1 policy
// unnecessary).
// SHA-1 allowed
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 0);
await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
// SHA-1 forbidden
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 1);
await checkEndEntity(
certFromFile("ee-pre_int-pre"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
@ -50,4 +111,77 @@ add_task(async function() {
certFromFile("ee-post_int-post"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
// SHA-1 forbidden (test the case where the pref has been set to 2)
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 2);
await checkEndEntity(
certFromFile("ee-pre_int-pre"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
await checkEndEntity(
certFromFile("ee-post_int-pre"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
await checkEndEntity(
certFromFile("ee-post_int-post"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
// SHA-1 allowed only when issued by an imported root. First test with the
// test root considered a built-in (on debug only - this functionality is
// disabled on non-debug builds).
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 3);
if (isDebugBuild) {
let root = certFromFile("ca");
Services.prefs.setCharPref(
"security.test.built_in_root_hash",
root.sha256Fingerprint
);
await checkEndEntity(
certFromFile("ee-pre_int-pre"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
await checkEndEntity(
certFromFile("ee-post_int-pre"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
await checkEndEntity(
certFromFile("ee-post_int-post"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
Services.prefs.clearUserPref("security.test.built_in_root_hash");
}
// SHA-1 still allowed only when issued by an imported root.
// Now test with the test root considered a non-built-in.
await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
// SHA-1 allowed before 2016 or when issued by an imported root. First test
// with the test root considered a built-in.
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
if (isDebugBuild) {
let root = certFromFile("ca");
Services.prefs.setCharPref(
"security.test.built_in_root_hash",
root.sha256Fingerprint
);
await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
await checkEndEntity(
certFromFile("ee-post_int-pre"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
await checkEndEntity(
certFromFile("ee-post_int-post"),
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
);
Services.prefs.clearUserPref("security.test.built_in_root_hash");
}
// SHA-1 still only allowed before 2016 or when issued by an imported root.
// Now test with the test root considered a non-built-in.
await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
});

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

@ -78,6 +78,7 @@ function run_test() {
do_get_profile();
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
Services.prefs.setIntPref("security.OCSP.enabled", 1);
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
let ocspResponder = new HttpServer();
@ -162,7 +163,14 @@ function add_tests() {
add_ocsp_test(
"ocsp-stapling-none.example.com",
SEC_ERROR_OCSP_UNKNOWN_CERT,
[respondWithError, respondWithError],
[
respondWithError,
respondWithError,
respondWithError,
respondWithError,
respondWithError,
respondWithError,
],
"No stapled response -> a fetch should have been attempted"
);
@ -243,9 +251,9 @@ function add_tests() {
add_ocsp_test(
"ocsp-stapling-none.example.com",
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
PRErrorCodeSuccess,
[respondWithSHA1OCSP],
"OCSP signing cert was issued with sha1 - should fail"
"signing cert is good (though sha1) - should succeed"
);
add_test(function() {

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

@ -54,6 +54,7 @@ Services.prefs.setIntPref("security.OCSP.enabled", 1);
// That aspect of OCSP requests is not what we're testing here, so we can just
// bump the timeout and hopefully avoid these failures.
Services.prefs.setIntPref("security.OCSP.timeoutMilliseconds.soft", 5000);
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
var args = [
["good", "default-ee", "unused", 0],
["expiredresponse", "default-ee", "unused", 0],
@ -79,8 +80,9 @@ var ocspResponseGoodMustStaple = ocspResponses[5];
var willNotRetry = 1;
// but sometimes, since a bad response is in the cache, OCSP fetch will be
// attempted for each validation - in practice, for these test certs, this
// means 2 requests because various key sizes are tried.
var willRetry = 2;
// means 6 requests because various hash algorithm and key size combinations
// are tried.
var willRetry = 6;
function run_test() {
let ocspResponder = new HttpServer();

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

@ -12881,6 +12881,14 @@
"n_values": 4,
"description": "Does enforcing a larger minimum RSA key size cause verification failures? 1 = no, 2 = yes, 3 = another error prevented finding a verified chain"
},
"CERT_CHAIN_SHA1_POLICY_STATUS": {
"record_in_processes": ["main", "content"],
"products": ["firefox", "fennec"],
"expires_in_version": "default",
"kind": "enumerated",
"n_values": 6,
"description": "1 = No SHA1 signatures, 2 = SHA1 certificates issued by an imported root, 3 = SHA1 certificates issued before 2016, 4 = SHA1 certificates issued after 2015, 5 = another error prevented successful verification"
},
"WEAVE_START_COUNT": {
"record_in_processes": ["main", "content"],
"products": ["firefox", "fennec"],

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

@ -73,6 +73,7 @@
"CANVAS_2D_USED",
"CANVAS_WEBGL_USED",
"CERT_CHAIN_KEY_SIZE_STATUS",
"CERT_CHAIN_SHA1_POLICY_STATUS",
"CHANGES_OF_DETECTED_LANGUAGE",
"CHANGES_OF_TARGET_LANGUAGE",
"CHECK_ADDONS_MODIFIED_MS",
@ -414,6 +415,7 @@
"CANVAS_2D_USED",
"CANVAS_WEBGL_USED",
"CERT_CHAIN_KEY_SIZE_STATUS",
"CERT_CHAIN_SHA1_POLICY_STATUS",
"CERT_OCSP_ENABLED",
"CERT_OCSP_REQUIRED",
"CERT_PINNING_FAILURES_BY_CA",
@ -1058,6 +1060,7 @@
"FX_THUMBNAILS_BG_CAPTURE_PAGE_LOAD_TIME_MS",
"REQUESTS_OF_ORIGINAL_CONTENT",
"NEWTAB_PAGE_ENHANCED",
"CERT_CHAIN_SHA1_POLICY_STATUS",
"FX_THUMBNAILS_BG_CAPTURE_SERVICE_TIME_MS",
"PLACES_BACKUPS_TOJSON_MS",
"A11Y_ISIMPLEDOM_USAGE_FLAG",