Backed out 3 changesets (bug 1715142) for causing build bustages. CLOSED TREE

Backed out changeset 7e67994f6a65 (bug 1715142)
Backed out changeset f58d5156f332 (bug 1715142)
Backed out changeset f8a7bd4519c6 (bug 1715142)
This commit is contained in:
Butkovits Atila 2021-06-11 21:20:02 +03:00
parent 5b30ebbe89
commit e4394b27a2
58 changed files with 756 additions and 402 deletions

View File

@ -15,6 +15,7 @@ add_task(async function test_star_redirect() {
Ci.nsISiteSecurityService
);
sss.resetState(
Ci.nsISiteSecurityService.HEADER_HSTS,
NetUtil.newURI("http://example.com/"),
0,
Services.prefs.getBoolPref("privacy.partition.network_state")

View File

@ -685,9 +685,6 @@ var NetworkHelper = {
const sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
const pkps = Cc[
"@mozilla.org/security/publickeypinningservice;1"
].getService(Ci.nsIPublicKeyPinningService);
// SiteSecurityService uses different storage if the channel is
// private. Thus we must give isSecureURI correct flags or we
@ -702,8 +699,8 @@ var NetworkHelper = {
uri = Services.io.newURI("https://" + host);
}
info.hsts = sss.isSecureURI(uri, flags);
info.hpkp = pkps.hostHasPins(uri);
info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags);
info.hpkp = sss.isSecureURI(sss.STATIC_PINNING, uri, flags);
} else {
DevToolsUtils.reportException(
"NetworkHelper.parseSecurityInfo",

View File

@ -47,7 +47,7 @@ async function startTest()
// Reset HSTS state.
const gSSService = Cc["@mozilla.org/ssservice;1"].getService(Ci.nsISiteSecurityService);
const uri = Services.io.newURI(TEST_CASES[0].url);
gSSService.resetState(uri, 0);
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
SimpleTest.finish();
}

View File

@ -139,7 +139,6 @@
#include "nsIPrompt.h"
#include "nsIPromptCollection.h"
#include "nsIPromptFactory.h"
#include "nsIPublicKeyPinningService.h"
#include "nsIReflowObserver.h"
#include "nsIScriptChannel.h"
#include "nsIScriptObjectPrincipal.h"
@ -3715,18 +3714,21 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
nsCOMPtr<nsISiteSecurityService> sss =
do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = sss->IsSecureURI(aURI, flags, attrsForHSTS, nullptr, nullptr,
&isStsHost);
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
attrsForHSTS, nullptr, nullptr, &isStsHost);
NS_ENSURE_SUCCESS(rv, rv);
rv = sss->IsSecureURI(nsISiteSecurityService::STATIC_PINNING, aURI,
flags, GetOriginAttributes(), nullptr, nullptr,
&isPinnedHost);
NS_ENSURE_SUCCESS(rv, rv);
} else {
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
cc->SendIsSecureURI(aURI, flags, attrsForHSTS, &isStsHost);
cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
attrsForHSTS, &isStsHost);
cc->SendIsSecureURI(nsISiteSecurityService::STATIC_PINNING, aURI, flags,
GetOriginAttributes(), &isPinnedHost);
}
nsCOMPtr<nsIPublicKeyPinningService> pkps =
do_GetService(NS_PKPSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = pkps->HostHasPins(aURI, &isPinnedHost);
if (Preferences::GetBool("browser.xul.error_pages.expert_bad_cert",
false)) {

View File

@ -341,7 +341,6 @@
#include "nsIPermission.h"
#include "nsIPrompt.h"
#include "nsIPropertyBag2.h"
#include "nsIPublicKeyPinningService.h"
#include "nsIReferrerInfo.h"
#include "nsIRefreshURI.h"
#include "nsIRequest.h"
@ -1891,22 +1890,23 @@ void Document::GetFailedCertSecurityInfo(FailedCertSecurityInfo& aInfo,
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
MOZ_ASSERT(cc);
cc->SendIsSecureURI(aURI, flags, attrs, &aInfo.mHasHSTS);
cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags, attrs,
&aInfo.mHasHSTS);
cc->SendIsSecureURI(nsISiteSecurityService::STATIC_PINNING, aURI, flags,
attrs, &aInfo.mHasHPKP);
} else {
nsCOMPtr<nsISiteSecurityService> sss =
do_GetService(NS_SSSERVICE_CONTRACTID);
if (NS_WARN_IF(!sss)) {
return;
}
Unused << NS_WARN_IF(NS_FAILED(sss->IsSecureURI(aURI, flags, attrs, nullptr,
nullptr, &aInfo.mHasHSTS)));
Unused << NS_WARN_IF(NS_FAILED(
sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
attrs, nullptr, nullptr, &aInfo.mHasHSTS)));
Unused << NS_WARN_IF(NS_FAILED(
sss->IsSecureURI(nsISiteSecurityService::STATIC_PINNING, aURI, flags,
attrs, nullptr, nullptr, &aInfo.mHasHPKP)));
}
nsCOMPtr<nsIPublicKeyPinningService> pkps =
do_GetService(NS_PKPSERVICE_CONTRACTID);
if (NS_WARN_IF(!pkps)) {
return;
}
Unused << NS_WARN_IF(NS_FAILED(pkps->HostHasPins(aURI, &aInfo.mHasHPKP)));
}
bool Document::AllowDeprecatedTls() {

View File

@ -4399,7 +4399,7 @@ mozilla::ipc::IPCResult ContentParent::RecvSetURITitle(nsIURI* uri,
}
mozilla::ipc::IPCResult ContentParent::RecvIsSecureURI(
nsIURI* aURI, const uint32_t& aFlags,
const uint32_t& aType, nsIURI* aURI, const uint32_t& aFlags,
const OriginAttributes& aOriginAttributes, bool* aIsSecureURI) {
nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
if (!sss) {
@ -4408,8 +4408,8 @@ mozilla::ipc::IPCResult ContentParent::RecvIsSecureURI(
if (!aURI) {
return IPC_FAIL_NO_REASON(this);
}
nsresult rv = sss->IsSecureURI(aURI, aFlags, aOriginAttributes, nullptr,
nullptr, aIsSecureURI);
nsresult rv = sss->IsSecureURI(aType, aURI, aFlags, aOriginAttributes,
nullptr, nullptr, aIsSecureURI);
if (NS_FAILED(rv)) {
return IPC_FAIL_NO_REASON(this);
}

View File

@ -941,7 +941,7 @@ class ContentParent final
const uint32_t& chromeFlags);
mozilla::ipc::IPCResult RecvIsSecureURI(
nsIURI* aURI, const uint32_t& aFlags,
const uint32_t& aType, nsIURI* aURI, const uint32_t& aFlags,
const OriginAttributes& aOriginAttributes, bool* aIsSecureURI);
mozilla::ipc::IPCResult RecvAccumulateMixedContentHSTS(

View File

@ -998,7 +998,7 @@ parent:
async InitCrashReporter(NativeThreadId tid);
sync IsSecureURI(nsIURI aURI, uint32_t aFlags,
sync IsSecureURI(uint32_t aType, nsIURI aURI, uint32_t aFlags,
OriginAttributes aOriginAttributes)
returns (bool isSecureURI);

View File

@ -979,7 +979,8 @@ void nsMixedContentBlocker::AccumulateMixedContentHSTS(
if (NS_FAILED(rv)) {
return;
}
rv = sss->IsSecureURI(aURI, 0, aOriginAttributes, nullptr, nullptr, &hsts);
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0,
aOriginAttributes, nullptr, nullptr, &hsts);
if (NS_FAILED(rv)) {
return;
}

View File

@ -10596,13 +10596,6 @@
value: true
mirror: always
# Disable preloaded static key pins by default.
- name: security.cert_pinning.enforcement_level
type: ReleaseAcquireAtomicUint32
value: 0
mirror: always
do_not_use_directly: true
#---------------------------------------------------------------------------
# Prefs starting with "slider."
#---------------------------------------------------------------------------

View File

@ -156,6 +156,11 @@ pref("security.webauth.webauthn_enable_softtoken", false);
pref("security.xfocsp.errorReporting.enabled", true);
pref("security.xfocsp.errorReporting.automatic", false);
// Impose a maximum age on HPKP headers, to avoid sites getting permanently
// blacking themselves out by setting a bad pin. (60 days by default)
// https://tools.ietf.org/html/rfc7469#section-4.1
pref("security.cert_pinning.max_max_age_seconds", 5184000);
// 0: Disable CRLite entirely
// 1: Enable and check revocations via CRLite, but only collect telemetry
// 2: Enable and enforce revocations via CRLite
@ -2163,6 +2168,22 @@ pref("security.ssl.enable_ocsp_must_staple", true);
pref("security.insecure_field_warning.contextual.enabled", false);
pref("security.insecure_field_warning.ignore_local_ip_address", true);
// Disable pinning checks by default.
pref("security.cert_pinning.enforcement_level", 0);
// Do not process hpkp headers rooted by not built in roots by default.
// This is to prevent accidental pinning from MITM devices and is used
// for tests.
pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
// Controls whether or not HPKP (the HTTP Public Key Pinning header) is enabled.
// If true, the header is processed and collected HPKP information is consulted
// when looking for pinning information.
// If false, the header is not processed and collected HPKP information is not
// consulted when looking for pinning information. Preloaded pins are not
// affected by this preference.
// Default: false
pref("security.cert_pinning.hpkp.enabled", false);
// Remote settings preferences
// Note: if you change this, make sure to also review security.onecrl.maximum_staleness_in_seconds
pref("services.settings.poll_interval", 86400); // 24H

View File

@ -243,6 +243,7 @@ static const char* gCallbackSecurityPrefs[] = {
"security.ssl.enable_ocsp_stapling",
"security.ssl.enable_ocsp_must_staple",
"security.pki.certificate_transparency.mode",
"security.cert_pinning.enforcement_level",
"security.pki.name_matching_mode",
nullptr,
};
@ -389,6 +390,7 @@ void nsIOService::OnTLSPrefChange(const char* aPref, void* aSelf) {
} else if (pref.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
pref.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
pref.EqualsLiteral("security.pki.certificate_transparency.mode") ||
pref.EqualsLiteral("security.cert_pinning.enforcement_level") ||
pref.EqualsLiteral("security.pki.name_matching_mode")) {
SetValidationOptionsCommon();
}

View File

@ -2964,9 +2964,9 @@ nsresult NS_ShouldSecureUpgrade(
resultCallback{std::move(aResultCallback)}]() mutable {
uint32_t hstsSource = 0;
bool isStsHost = false;
nsresult rv =
service->IsSecureURI(uri, flags, originAttributes, nullptr,
&hstsSource, &isStsHost);
nsresult rv = service->IsSecureURI(
nsISiteSecurityService::HEADER_HSTS, uri, flags,
originAttributes, nullptr, &hstsSource, &isStsHost);
// Successfully get the result from |IsSecureURI| implies that
// the storage is ready to read.
@ -2985,8 +2985,9 @@ nsresult NS_ShouldSecureUpgrade(
return rv;
}
nsresult rv = sss->IsSecureURI(aURI, flags, aOriginAttributes, nullptr,
&hstsSource, &isStsHost);
nsresult rv =
sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
aOriginAttributes, nullptr, &hstsSource, &isStsHost);
// if the SSS check fails, it's likely because this load is on a
// malformed URI or something else in the setup is wrong, so any error

View File

@ -1785,7 +1785,8 @@ nsresult nsHttpChannel::ProcessHSTSHeader(nsITransportSecurityInfo* aSecInfo,
uint32_t failureResult;
uint32_t headerSource = nsISiteSecurityService::SOURCE_ORGANIC_REQUEST;
rv = sss->ProcessHeader(mURI, securityHeader, aSecInfo, aFlags, headerSource,
rv = sss->ProcessHeader(nsISiteSecurityService::HEADER_HSTS, mURI,
securityHeader, aSecInfo, aFlags, headerSource,
originAttributes, nullptr, nullptr, &failureResult);
if (NS_FAILED(rv)) {
nsAutoString consoleErrorCategory(u"Invalid HSTS Headers"_ns);

View File

@ -2436,8 +2436,9 @@ nsresult nsHttpHandler::SpeculativeConnectInternal(
aURI, originAttributes);
nsCOMPtr<nsIURI> clone;
if (NS_SUCCEEDED(sss->IsSecureURI(aURI, flags, originAttributes, nullptr,
nullptr, &isStsHost)) &&
if (NS_SUCCEEDED(sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
flags, originAttributes, nullptr, nullptr,
&isStsHost)) &&
isStsHost) {
if (NS_SUCCEEDED(NS_GetSecureUpgradedURI(aURI, getter_AddRefs(clone)))) {
aURI = clone.get();

View File

@ -88,7 +88,8 @@ void CertificateTransparencyInfo::Reset() {
CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays, SHA1Mode sha1Mode,
uint32_t certShortLifetimeInDays,
PinningMode pinningMode, SHA1Mode sha1Mode,
BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode,
@ -100,6 +101,7 @@ CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mOCSPTimeoutSoft(ocspTimeoutSoft),
mOCSPTimeoutHard(ocspTimeoutHard),
mCertShortLifetimeInDays(certShortLifetimeInDays),
mPinningMode(pinningMode),
mSHA1Mode(sha1Mode),
mNameMatchingMode(nameMatchingMode),
mNetscapeStepUpPolicy(netscapeStepUpPolicy),
@ -562,9 +564,9 @@ Result CertVerifier::VerifyCert(
// just use trustEmail as it is the closest alternative.
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mOCSPTimeoutHard, mCertShortLifetimeInDays, pinningDisabled,
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
@ -635,10 +637,10 @@ Result CertVerifier::VerifyCert(
NSSCertDBTrustDomain trustDomain(
trustSSL, evOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS,
ValidityCheckingMode::CheckForEV, sha1ModeConfigurations[i],
mNetscapeStepUpPolicy, mCRLiteMode, mCRLiteCTMergeDelaySeconds,
originAttributes, mThirdPartyRootInputs,
mOCSPTimeoutHard, mCertShortLifetimeInDays, mPinningMode,
MIN_RSA_BITS, ValidityCheckingMode::CheckForEV,
sha1ModeConfigurations[i], mNetscapeStepUpPolicy, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
@ -718,11 +720,12 @@ Result CertVerifier::VerifyCert(
NSSCertDBTrustDomain trustDomain(
trustSSL, defaultOCSPFetching, mOCSPCache, pinArg,
mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
keySizeOptions[i], ValidityCheckingMode::CheckingOff,
sha1ModeConfigurations[j], mNetscapeStepUpPolicy, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes,
mThirdPartyRootInputs, mThirdPartyIntermediateInputs,
extraCertificates, builtChain, pinningTelemetryInfo, hostname);
mPinningMode, keySizeOptions[i],
ValidityCheckingMode::CheckingOff, sha1ModeConfigurations[j],
mNetscapeStepUpPolicy, mCRLiteMode, mCRLiteCTMergeDelaySeconds,
originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, //(EC)DHE
@ -787,10 +790,10 @@ Result CertVerifier::VerifyCert(
case certificateUsageSSLCA: {
NSSCertDBTrustDomain trustDomain(
trustSSL, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
mNetscapeStepUpPolicy, mCRLiteMode, mCRLiteCTMergeDelaySeconds,
originAttributes, mThirdPartyRootInputs,
mOCSPTimeoutHard, mCertShortLifetimeInDays, pinningDisabled,
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, mNetscapeStepUpPolicy, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeCA,
@ -802,9 +805,9 @@ Result CertVerifier::VerifyCert(
case certificateUsageEmailSigner: {
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mOCSPTimeoutHard, mCertShortLifetimeInDays, pinningDisabled,
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
@ -827,9 +830,9 @@ Result CertVerifier::VerifyCert(
// based on the result of the verification(s).
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, mOCSPTimeoutSoft,
mOCSPTimeoutHard, mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, SHA1Mode::Allowed,
NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mOCSPTimeoutHard, mCertShortLifetimeInDays, pinningDisabled,
MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch, mCRLiteMode,
mCRLiteCTMergeDelaySeconds, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);

View File

@ -195,6 +195,13 @@ class CertVerifier {
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
/*optional out*/ bool* isBuiltCertChainRootBuiltInRoot = nullptr);
enum PinningMode {
pinningDisabled = 0,
pinningAllowUserCAMITM = 1,
pinningStrict = 2,
pinningEnforceTestMode = 3
};
enum class SHA1Mode {
Allowed = 0,
Forbidden = 1,
@ -217,8 +224,8 @@ class CertVerifier {
CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard,
uint32_t certShortLifetimeInDays, SHA1Mode sha1Mode,
BRNameMatchingPolicy::Mode nameMatchingMode,
uint32_t certShortLifetimeInDays, PinningMode pinningMode,
SHA1Mode sha1Mode, BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode, CRLiteMode crliteMode,
uint64_t crliteCTMergeDelaySeconds,
@ -232,6 +239,7 @@ class CertVerifier {
const mozilla::TimeDuration mOCSPTimeoutSoft;
const mozilla::TimeDuration mOCSPTimeoutHard;
const uint32_t mCertShortLifetimeInDays;
const PinningMode mPinningMode;
const SHA1Mode mSHA1Mode;
const BRNameMatchingPolicy::Mode mNameMatchingMode;
const NetscapeStepUpPolicy mNetscapeStepUpPolicy;
@ -268,9 +276,9 @@ class CertVerifier {
};
mozilla::pkix::Result IsCertBuiltInRoot(CERTCertificate* cert, bool& result);
mozilla::pkix::Result CertListContainsExpectedKeys(const CERTCertList* certList,
const char* hostname,
mozilla::pkix::Time time);
mozilla::pkix::Result CertListContainsExpectedKeys(
const CERTCertList* certList, const char* hostname,
mozilla::pkix::Time time, CertVerifier::PinningMode pinningMode);
} // namespace psm
} // namespace mozilla

View File

@ -66,9 +66,10 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
OCSPCache& ocspCache,
/*optional but shouldn't be*/ void* pinArg, TimeDuration ocspTimeoutSoft,
TimeDuration ocspTimeoutHard, uint32_t certShortLifetimeInDays,
unsigned int minRSABits, ValidityCheckingMode validityCheckingMode,
CertVerifier::SHA1Mode sha1Mode, NetscapeStepUpPolicy netscapeStepUpPolicy,
CRLiteMode crliteMode, uint64_t crliteCTMergeDelaySeconds,
CertVerifier::PinningMode pinningMode, unsigned int minRSABits,
ValidityCheckingMode validityCheckingMode, CertVerifier::SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy, CRLiteMode crliteMode,
uint64_t crliteCTMergeDelaySeconds,
const OriginAttributes& originAttributes,
const Vector<Input>& thirdPartyRootInputs,
const Vector<Input>& thirdPartyIntermediateInputs,
@ -83,6 +84,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(
mOCSPTimeoutSoft(ocspTimeoutSoft),
mOCSPTimeoutHard(ocspTimeoutHard),
mCertShortLifetimeInDays(certShortLifetimeInDays),
mPinningMode(pinningMode),
mMinRSABits(minRSABits),
mValidityCheckingMode(validityCheckingMode),
mSHA1Mode(sha1Mode),
@ -1184,9 +1186,16 @@ Result NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time,
if (NS_FAILED(nsrv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
bool skipPinningChecksBecauseOfMITMMode =
(!isBuiltInRoot && mPinningMode == CertVerifier::pinningAllowUserCAMITM);
// If mHostname isn't set, we're not verifying in the context of a TLS
// handshake, so don't verify key pinning in those cases.
if (mHostname) {
// handshake, so don't verify HPKP in those cases.
if (mHostname && (mPinningMode != CertVerifier::pinningDisabled) &&
!skipPinningChecksBecauseOfMITMMode) {
bool enforceTestMode =
(mPinningMode == CertVerifier::pinningEnforceTestMode);
bool chainHasValidPins;
nsTArray<Span<const uint8_t>> derCertSpanList;
size_t numCerts = certArray.GetLength();
for (size_t i = numCerts; i > 0; --i) {
@ -1197,10 +1206,9 @@ Result NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time,
derCertSpanList.EmplaceBack(der->UnsafeGetData(), der->GetLength());
}
bool chainHasValidPins;
nsrv = PublicKeyPinningService::ChainHasValidPins(
derCertSpanList, mHostname, time, isBuiltInRoot, chainHasValidPins,
mPinningTelemetryInfo);
derCertSpanList, mHostname, time, enforceTestMode, mOriginAttributes,
chainHasValidPins, mPinningTelemetryInfo);
if (NS_FAILED(nsrv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}

View File

@ -128,7 +128,8 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
SECTrustType certDBTrustType, OCSPFetching ocspFetching,
OCSPCache& ocspCache, void* pinArg, mozilla::TimeDuration ocspTimeoutSoft,
mozilla::TimeDuration ocspTimeoutHard, uint32_t certShortLifetimeInDays,
unsigned int minRSABits, ValidityCheckingMode validityCheckingMode,
CertVerifier::PinningMode pinningMode, unsigned int minRSABits,
ValidityCheckingMode validityCheckingMode,
CertVerifier::SHA1Mode sha1Mode,
NetscapeStepUpPolicy netscapeStepUpPolicy, CRLiteMode crliteMode,
uint64_t crliteCTMergeDelaySeconds,
@ -246,6 +247,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
const mozilla::TimeDuration mOCSPTimeoutSoft;
const mozilla::TimeDuration mOCSPTimeoutHard;
const uint32_t mCertShortLifetimeInDays;
CertVerifier::PinningMode mPinningMode;
const unsigned int mMinRSABits;
ValidityCheckingMode mValidityCheckingMode;
CertVerifier::SHA1Mode mSHA1Mode;

View File

@ -202,26 +202,34 @@ CommonSocketControl::IsAcceptableForHost(const nsACString& hostname,
return NS_OK;
}
nsTArray<nsTArray<uint8_t>> rawDerCertList;
nsTArray<Span<const uint8_t>> derCertSpanList;
for (const auto& cert : mSucceededCertChain) {
rawDerCertList.EmplaceBack();
nsresult nsrv = cert->GetRawDER(rawDerCertList.LastElement());
if (NS_FAILED(nsrv)) {
return nsrv;
}
derCertSpanList.EmplaceBack(rawDerCertList.LastElement());
}
bool chainHasValidPins;
nsresult nsrv = mozilla::psm::PublicKeyPinningService::ChainHasValidPins(
derCertSpanList, PromiseFlatCString(hostname).BeginReading(), Now(),
mIsBuiltCertChainRootBuiltInRoot, chainHasValidPins, nullptr);
if (NS_FAILED(nsrv)) {
return NS_OK;
}
mozilla::psm::CertVerifier::PinningMode pinningMode =
mozilla::psm::PublicSSLState()->PinningMode();
if (pinningMode != mozilla::psm::CertVerifier::pinningDisabled) {
bool chainHasValidPins;
bool enforceTestMode =
(pinningMode == mozilla::psm::CertVerifier::pinningEnforceTestMode);
if (!chainHasValidPins) {
return NS_OK;
nsTArray<nsTArray<uint8_t>> rawDerCertList;
nsTArray<Span<const uint8_t>> derCertSpanList;
for (const auto& cert : mSucceededCertChain) {
rawDerCertList.EmplaceBack();
nsresult nsrv = cert->GetRawDER(rawDerCertList.LastElement());
if (NS_FAILED(nsrv)) {
return nsrv;
}
derCertSpanList.EmplaceBack(rawDerCertList.LastElement());
}
nsresult nsrv = mozilla::psm::PublicKeyPinningService::ChainHasValidPins(
derCertSpanList, PromiseFlatCString(hostname).BeginReading(), Now(),
enforceTestMode, GetOriginAttributes(lock), chainHasValidPins, nullptr);
if (NS_FAILED(nsrv)) {
return NS_OK;
}
if (!chainHasValidPins) {
return NS_OK;
}
}
// All tests pass

View File

@ -11,11 +11,9 @@
#include "mozilla/Casting.h"
#include "mozilla/Logging.h"
#include "mozilla/Span.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/Telemetry.h"
#include "nsDependentString.h"
#include "nsServiceManagerUtils.h"
#include "nsSiteSecurityService.h"
#include "mozpkix/pkixtypes.h"
#include "mozpkix/pkixutil.h"
#include "seccomon.h"
@ -29,32 +27,6 @@ using namespace mozilla::psm;
LazyLogModule gPublicKeyPinningLog("PublicKeyPinningService");
NS_IMPL_ISUPPORTS(PublicKeyPinningService, nsIPublicKeyPinningService)
enum class PinningMode : uint32_t {
Disabled = 0,
AllowUserCAMITM = 1,
Strict = 2,
EnforceTestMode = 3
};
PinningMode GetPinningMode() {
PinningMode pinningMode = static_cast<PinningMode>(
StaticPrefs::security_cert_pinning_enforcement_level_DoNotUseDirectly());
switch (pinningMode) {
case PinningMode::Disabled:
return PinningMode::Disabled;
case PinningMode::AllowUserCAMITM:
return PinningMode::AllowUserCAMITM;
case PinningMode::Strict:
return PinningMode::Strict;
case PinningMode::EnforceTestMode:
return PinningMode::EnforceTestMode;
default:
return PinningMode::Disabled;
}
}
/**
Computes in the location specified by base64Out the SHA256 digest
of the DER Encoded subject Public Key Info for the given cert
@ -189,6 +161,7 @@ static void ValidatePinningPreloadList() {
// information that is valid for the given host at the given time.
static nsresult FindPinningInformation(
const char* hostname, mozilla::pkix::Time time,
const OriginAttributes& originAttributes,
/*out*/ const TransportSecurityPreload*& staticFingerprints) {
#ifdef DEBUG
ValidatePinningPreloadList();
@ -244,6 +217,7 @@ static nsresult FindPinningInformation(
static nsresult CheckPinsForHostname(
const nsTArray<Span<const uint8_t>>& certList, const char* hostname,
bool enforceTestMode, mozilla::pkix::Time time,
const OriginAttributes& originAttributes,
/*out*/ bool& chainHasValidPins,
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) {
chainHasValidPins = false;
@ -255,10 +229,8 @@ static nsresult CheckPinsForHostname(
}
const TransportSecurityPreload* staticFingerprints = nullptr;
nsresult rv = FindPinningInformation(hostname, time, staticFingerprints);
if (NS_FAILED(rv)) {
return rv;
}
nsresult rv = FindPinningInformation(hostname, time, originAttributes,
staticFingerprints);
// If we have no pinning information, the certificate chain trivially
// validates with respect to pinning.
if (!staticFingerprints) {
@ -327,16 +299,10 @@ static nsresult CheckPinsForHostname(
nsresult PublicKeyPinningService::ChainHasValidPins(
const nsTArray<Span<const uint8_t>>& certList, const char* hostname,
mozilla::pkix::Time time, bool isBuiltInRoot,
mozilla::pkix::Time time, bool enforceTestMode,
const OriginAttributes& originAttributes,
/*out*/ bool& chainHasValidPins,
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) {
PinningMode pinningMode(GetPinningMode());
if (pinningMode == PinningMode::Disabled ||
(!isBuiltInRoot && pinningMode == PinningMode::AllowUserCAMITM)) {
chainHasValidPins = true;
return NS_OK;
}
chainHasValidPins = false;
if (certList.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
@ -345,38 +311,25 @@ nsresult PublicKeyPinningService::ChainHasValidPins(
return NS_ERROR_INVALID_ARG;
}
nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
bool enforceTestMode = pinningMode == PinningMode::EnforceTestMode;
return CheckPinsForHostname(certList, canonicalizedHostname.get(),
enforceTestMode, time, chainHasValidPins,
pinningTelemetryInfo);
enforceTestMode, time, originAttributes,
chainHasValidPins, pinningTelemetryInfo);
}
NS_IMETHODIMP
PublicKeyPinningService::HostHasPins(nsIURI* aURI, bool* hostHasPins) {
NS_ENSURE_ARG(aURI);
NS_ENSURE_ARG(hostHasPins);
*hostHasPins = false;
PinningMode pinningMode(GetPinningMode());
if (pinningMode == PinningMode::Disabled) {
return NS_OK;
}
nsAutoCString hostname;
nsresult rv = nsSiteSecurityService::GetHost(aURI, hostname);
if (NS_FAILED(rv)) {
return rv;
}
if (nsSiteSecurityService::HostIsIPAddress(hostname)) {
return NS_OK;
}
nsresult PublicKeyPinningService::HostHasPins(
const char* hostname, mozilla::pkix::Time time, bool enforceTestMode,
const OriginAttributes& originAttributes,
/*out*/ bool& hostHasPins) {
hostHasPins = false;
nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
const TransportSecurityPreload* staticFingerprints = nullptr;
rv = FindPinningInformation(hostname.get(), Now(), staticFingerprints);
nsresult rv = FindPinningInformation(canonicalizedHostname.get(), time,
originAttributes, staticFingerprints);
if (NS_FAILED(rv)) {
return rv;
}
if (staticFingerprints) {
*hostHasPins = !staticFingerprints->mTestMode ||
pinningMode == PinningMode::EnforceTestMode;
hostHasPins = !staticFingerprints->mTestMode || enforceTestMode;
}
return NS_OK;
}

View File

@ -6,22 +6,25 @@
#define PublicKeyPinningService_h
#include "CertVerifier.h"
#include "nsIPublicKeyPinningService.h"
#include "ScopedNSSTypes.h"
#include "cert.h"
#include "nsNSSCertificate.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/Span.h"
#include "mozpkix/Time.h"
namespace mozilla {
class OriginAttributes;
}
using mozilla::OriginAttributes;
namespace mozilla {
namespace psm {
class PublicKeyPinningService final : public nsIPublicKeyPinningService {
class PublicKeyPinningService {
public:
PublicKeyPinningService() = default;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIPUBLICKEYPINNINGSERVICE
/**
* Sets chainHasValidPins to true if the given (host, certList) passes pinning
* checks, or to false otherwise. If the host is pinned, returns true via
@ -33,19 +36,27 @@ class PublicKeyPinningService final : public nsIPublicKeyPinningService {
*/
static nsresult ChainHasValidPins(
const nsTArray<Span<const uint8_t>>& certList, const char* hostname,
mozilla::pkix::Time time, bool isBuiltInRoot,
mozilla::pkix::Time time, bool enforceTestMode,
const OriginAttributes& originAttributes,
/*out*/ bool& chainHasValidPins,
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo);
/**
* Returns true via the output parameter hostHasPins if there is pinning
* information for the given host that is valid at the given time, and false
* otherwise.
*/
static nsresult HostHasPins(const char* hostname, mozilla::pkix::Time time,
bool enforceTestMode,
const OriginAttributes& originAttributes,
/*out*/ bool& hostHasPins);
/**
* Given a hostname of potentially mixed case with potentially multiple
* trailing '.' (see bug 1118522), canonicalizes it to lowercase with no
* trailing '.'.
*/
static nsAutoCString CanonicalizeHostname(const char* hostname);
private:
~PublicKeyPinningService() = default;
};
} // namespace psm

View File

@ -117,7 +117,6 @@
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsICertOverrideService.h"
#include "nsIPublicKeyPinningService.h"
#include "nsISiteSecurityService.h"
#include "nsISocketProvider.h"
#include "nsThreadPool.h"
@ -429,24 +428,18 @@ static nsresult OverrideAllowedForHost(
return rv;
}
rv = sss->IsSecureURI(uri, aProviderFlags, aOriginAttributes, nullptr,
nullptr, &strictTransportSecurityEnabled);
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri,
aProviderFlags, aOriginAttributes, nullptr, nullptr,
&strictTransportSecurityEnabled);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[0x%" PRIx64 "] checking for HSTS failed", aPtrForLog));
return rv;
}
nsCOMPtr<nsIPublicKeyPinningService> pkps =
do_GetService(NS_PKPSERVICE_CONTRACTID, &rv);
if (!pkps) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[0x%" PRIx64
"] Couldn't get nsIPublicKeyPinningService to check pinning",
aPtrForLog));
return NS_ERROR_FAILURE;
}
rv = pkps->HostHasPins(uri, &isStaticallyPinned);
rv = sss->IsSecureURI(nsISiteSecurityService::STATIC_PINNING, uri,
aProviderFlags, aOriginAttributes, nullptr, nullptr,
&isStaticallyPinned);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[0x%" PRIx64 "] checking for static pin failed", aPtrForLog));

View File

@ -23,7 +23,8 @@ class SharedCertVerifier : public mozilla::psm::CertVerifier {
SharedCertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
mozilla::TimeDuration ocspSoftTimeout,
mozilla::TimeDuration ocspHardTimeout,
uint32_t certShortLifetimeInDays, SHA1Mode sha1Mode,
uint32_t certShortLifetimeInDays, PinningMode pinningMode,
SHA1Mode sha1Mode,
BRNameMatchingPolicy::Mode nameMatchingMode,
NetscapeStepUpPolicy netscapeStepUpPolicy,
CertificateTransparencyMode ctMode, CRLiteMode crliteMode,
@ -31,8 +32,8 @@ class SharedCertVerifier : public mozilla::psm::CertVerifier {
const Vector<EnterpriseCert>& thirdPartyCerts)
: mozilla::psm::CertVerifier(
odc, osc, ocspSoftTimeout, ocspHardTimeout, certShortLifetimeInDays,
sha1Mode, nameMatchingMode, netscapeStepUpPolicy, ctMode,
crliteMode, crliteCTMergeDelaySeconds, thirdPartyCerts) {}
pinningMode, sha1Mode, nameMatchingMode, netscapeStepUpPolicy,
ctMode, crliteMode, crliteCTMergeDelaySeconds, thirdPartyCerts) {}
};
} // namespace psm

View File

@ -36,6 +36,9 @@ class SharedSSLState {
void SetSignedCertTimestampsEnabled(bool signedCertTimestampsEnabled) {
mSignedCertTimestampsEnabled = signedCertTimestampsEnabled;
}
void SetPinningMode(CertVerifier::PinningMode aPinningMode) {
mPinningMode = aPinningMode;
}
void SetNameMatchingMode(BRNameMatchingPolicy::Mode aMode) {
mNameMatchingMode = aMode;
}
@ -49,6 +52,7 @@ class SharedSSLState {
bool IsSignedCertTimestampsEnabled() const {
return mSignedCertTimestampsEnabled;
}
CertVerifier::PinningMode PinningMode() { return mPinningMode; }
BRNameMatchingPolicy::Mode NameMatchingMode() { return mNameMatchingMode; }
private:
@ -67,6 +71,7 @@ class SharedSSLState {
bool mOCSPStaplingEnabled;
bool mOCSPMustStapleEnabled;
bool mSignedCertTimestampsEnabled;
CertVerifier::PinningMode mPinningMode;
BRNameMatchingPolicy::Mode mNameMatchingMode;
};

View File

@ -147,12 +147,6 @@ Classes = [
'headers': ['/security/manager/ssl/cert_storage/src/cert_storage.h'],
'legacy_constructor': 'cert_storage_constructor',
},
{
'cid': '{f64432b9-e8c6-41b4-b2da-8eb004344bba}',
'contract_ids': ['@mozilla.org/security/publickeypinningservice;1'],
'type': 'psm::PublicKeyPinningService',
'headers': ['/security/manager/ssl/PublicKeyPinningService.h'],
},
]
if defined('MOZ_XUL'):

View File

@ -36,7 +36,6 @@ XPIDL_SOURCES += [
"nsIPKCS11ModuleDB.idl",
"nsIPKCS11Slot.idl",
"nsIProtectedAuthThread.idl",
"nsIPublicKeyPinningService.idl",
"nsISecretDecoderRing.idl",
"nsISecurityUITelemetry.idl",
"nsISiteSecurityService.idl",

View File

@ -827,18 +827,8 @@ nsCertOverrideService::
return NS_ERROR_NOT_AVAILABLE;
}
{
MutexAutoLock lock(mMutex);
mDisableAllSecurityCheck = aDisable;
}
nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
if (nss) {
nss->ClearSSLExternalAndInternalSessionCache();
} else {
return NS_ERROR_NOT_AVAILABLE;
}
MutexAutoLock lock(mMutex);
mDisableAllSecurityCheck = aDisable;
return NS_OK;
}

View File

@ -1,22 +0,0 @@
/* 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 "nsISupports.idl"
interface nsIURI;
[scriptable, uuid(f64432b9-e8c6-41b4-b2da-8eb004344bba), builtinclass]
interface nsIPublicKeyPinningService : nsISupports
{
/**
* Returns true if the host of the given URI has pinning information, and
* false otherwise.
*/
[must_use]
bool hostHasPins(in nsIURI aURI);
};
%{C++
#define NS_PKPSERVICE_CONTRACTID "@mozilla.org/security/publickeypinningservice;1"
%}

View File

@ -45,6 +45,10 @@ interface nsISiteHSTSState : nsISiteSecurityState
[scriptable, uuid(275127f8-dbd7-4681-afbf-6df0c6587a01)]
interface nsISiteSecurityService : nsISupports
{
const uint32_t HEADER_HSTS = 0;
const uint32_t STATIC_PINNING = 1; // was HEADER_HPKP
// HEADER_OMS was 2 (but was never implemented)
const uint32_t Success = 0;
const uint32_t ERROR_UNKNOWN = 1;
const uint32_t ERROR_UNTRUSTWORTHY_CONNECTION = 2;
@ -80,6 +84,7 @@ interface nsISiteSecurityService : nsISupports
* and allows a host to specify that future HTTP requests should be
* upgraded to HTTPS.
*
* @param aType the type of security header in question.
* @param aSourceURI the URI of the resource with the HTTP header.
* @param aHeader the HTTP response header specifying security data.
* @param aSecInfo the TransportSecurityInfo of the current channel.
@ -102,7 +107,8 @@ interface nsISiteSecurityService : nsISupports
* if there are unrecognized tokens in the header.
*/
[binaryname(ProcessHeader), noscript, must_use]
void processHeaderNative(in nsIURI aSourceURI,
void processHeaderNative(in uint32_t aType,
in nsIURI aSourceURI,
in ACString aHeader,
in nsITransportSecurityInfo aSecInfo,
in uint32_t aFlags,
@ -114,7 +120,8 @@ interface nsISiteSecurityService : nsISupports
[binaryname(ProcessHeaderScriptable), implicit_jscontext, optional_argc,
must_use]
void processHeader(in nsIURI aSourceURI,
void processHeader(in uint32_t aType,
in nsIURI aSourceURI,
in ACString aHeader,
in nsITransportSecurityInfo aSecInfo,
in uint32_t aFlags,
@ -125,12 +132,14 @@ interface nsISiteSecurityService : nsISupports
[optional] out uint32_t aFailureResult);
/**
* Resets HSTS state a host, including the includeSubdomains state that
* would affect subdomains. This essentially removes the state for the
* domain tree rooted at this host. If any preloaded information is present
* for that host, that information will then be used instead of any other
* previously existing state.
* Given a header type, resets state relating to that header of a host,
* including the includeSubdomains state that would affect subdomains.
* This essentially removes the state for the domain tree rooted at this
* host. If any preloaded information is present for that host, that
* information will then be used instead of any other previously existing
* state.
*
* @param aType the type of security state in question
* @param aURI the URI of the target host
* @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE
@ -141,19 +150,21 @@ interface nsISiteSecurityService : nsISupports
* happens).
*/
[implicit_jscontext, optional_argc, must_use]
void resetState(in nsIURI aURI,
void resetState(in uint32_t aType,
in nsIURI aURI,
in uint32_t aFlags,
[optional] in jsval aOriginAttributes);
/**
* Checks whether or not the URI's hostname has HSTS set.
* For example:
* Checks whether or not the URI's hostname has a given security state set.
* For example, for HSTS:
* The URI is an HSTS URI if either the host has the HSTS state set, or one
* of its super-domains has the HSTS "includeSubdomains" flag set.
* NOTE: this function makes decisions based only on the
* host contained in the URI, and disregards other portions of the URI
* such as path and port.
*
* @param aType the type of security state in question.
* @param aURI the URI to query for STS state.
* @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE
@ -168,20 +179,21 @@ interface nsISiteSecurityService : nsISupports
* SOURCE_ORGANIC_REQUEST, or SOURCE_UNKNOWN.
*/
[binaryname(IsSecureURI), noscript, must_use]
boolean isSecureURINative(in nsIURI aURI, in uint32_t aFlags,
boolean isSecureURINative(in uint32_t aType, in nsIURI aURI,
in uint32_t aFlags,
in const_OriginAttributesRef aOriginAttributes,
[optional] out boolean aCached,
[optional] out uint32_t aSource);
[binaryname(IsSecureURIScriptable), implicit_jscontext, optional_argc,
must_use]
boolean isSecureURI(in nsIURI aURI, in uint32_t aFlags,
boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags,
[optional] in jsval aOriginAttributes,
[optional] out boolean aCached,
[optional] out uint32_t aSource);
/**
* Removes all non-preloaded HSTS state by resetting to factory-original
* Removes all non-preloaded security state by resetting to factory-original
* settings.
*/
[must_use]
@ -192,9 +204,11 @@ interface nsISiteSecurityService : nsISupports
* the enumeration is a nsISiteSecurityState that can be QueryInterfaced to
* nsISiteHSTSState.
* Doesn't include hard-coded preloaded entries.
*
* @param aType the type of security state in question.
*/
[must_use]
nsISimpleEnumerator enumerate();
nsISimpleEnumerator enumerate(in uint32_t aType);
};
%{C++

View File

@ -1292,6 +1292,16 @@ void SetValidationOptionsCommon() {
PublicSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);
PrivateSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);
CertVerifier::PinningMode pinningMode =
static_cast<CertVerifier::PinningMode>(
Preferences::GetInt("security.cert_pinning.enforcement_level",
CertVerifier::pinningDisabled));
if (pinningMode > CertVerifier::pinningEnforceTestMode) {
pinningMode = CertVerifier::pinningDisabled;
}
PublicSSLState()->SetPinningMode(pinningMode);
PrivateSSLState()->SetPinningMode(pinningMode);
BRNameMatchingPolicy::Mode nameMatchingMode =
static_cast<BRNameMatchingPolicy::Mode>(Preferences::GetInt(
"security.pki.name_matching_mode",
@ -1498,7 +1508,8 @@ void nsNSSComponent::setValidationOptions(
softTimeout, hardTimeout, proofOfLock);
mDefaultCertVerifier = new SharedCertVerifier(
odc, osc, softTimeout, hardTimeout, certShortLifetimeInDays, sha1Mode,
odc, osc, softTimeout, hardTimeout, certShortLifetimeInDays,
PublicSSLState()->PinningMode(), sha1Mode,
PublicSSLState()->NameMatchingMode(), netscapeStepUpPolicy, ctMode,
crliteMode, crliteCTMergeDelaySeconds, mEnterpriseCerts);
}
@ -1516,8 +1527,8 @@ void nsNSSComponent::UpdateCertVerifierWithEnterpriseRoots() {
oldCertVerifier->mOCSPStrict ? CertVerifier::ocspStrict
: CertVerifier::ocspRelaxed,
oldCertVerifier->mOCSPTimeoutSoft, oldCertVerifier->mOCSPTimeoutHard,
oldCertVerifier->mCertShortLifetimeInDays, oldCertVerifier->mSHA1Mode,
oldCertVerifier->mNameMatchingMode,
oldCertVerifier->mCertShortLifetimeInDays, oldCertVerifier->mPinningMode,
oldCertVerifier->mSHA1Mode, oldCertVerifier->mNameMatchingMode,
oldCertVerifier->mNetscapeStepUpPolicy, oldCertVerifier->mCTMode,
oldCertVerifier->mCRLiteMode, oldCertVerifier->mCRLiteCTMergeDelaySeconds,
mEnterpriseCerts);
@ -2273,6 +2284,8 @@ 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.cert_pinning.enforcement_level") ||
prefName.EqualsLiteral("security.pki.sha1_enforcement_level") ||
prefName.EqualsLiteral("security.pki.name_matching_mode") ||
prefName.EqualsLiteral("security.pki.netscape_step_up_policy") ||

View File

@ -45,7 +45,7 @@ static LazyLogModule gSSSLog("nsSSService");
#define SSSLOG(args) MOZ_LOG(gSSSLog, mozilla::LogLevel::Debug, args)
static const nsLiteralCString kHSTSKeySuffix = ":HSTS"_ns;
const char kHSTSKeySuffix[] = ":HSTS";
////////////////////////////////////////////////////////////////////////////////
@ -286,7 +286,7 @@ nsresult nsSiteSecurityService::GetHost(nsIURI* aURI, nsACString& aResult) {
return NS_OK;
}
static void SetStorageKey(const nsACString& hostname,
static void SetStorageKey(const nsACString& hostname, uint32_t aType,
const OriginAttributes& aOriginAttributes,
/*out*/ nsAutoCString& storageKey) {
storageKey = hostname;
@ -298,7 +298,13 @@ static void SetStorageKey(const nsACString& hostname,
nsAutoCString originAttributesSuffix;
originAttributesNoUserContext.CreateSuffix(originAttributesSuffix);
storageKey.Append(originAttributesSuffix);
storageKey.Append(kHSTSKeySuffix);
switch (aType) {
case nsISiteSecurityService::HEADER_HSTS:
storageKey.AppendASCII(kHSTSKeySuffix);
break;
default:
MOZ_ASSERT_UNREACHABLE("SSS:SetStorageKey got invalid type");
}
}
// Expire times are in millis. Since Headers max-age is in seconds, and
@ -308,16 +314,17 @@ static int64_t ExpireTimeFromMaxAge(uint64_t maxAge) {
}
nsresult nsSiteSecurityService::SetHSTSState(
const char* aHost, int64_t maxage, bool includeSubdomains, uint32_t flags,
SecurityPropertyState aHSTSState, SecurityPropertySource aSource,
const OriginAttributes& aOriginAttributes) {
uint32_t aType, const char* aHost, int64_t maxage, bool includeSubdomains,
uint32_t flags, SecurityPropertyState aHSTSState,
SecurityPropertySource aSource, const OriginAttributes& aOriginAttributes) {
nsAutoCString hostname(aHost);
bool isPreload = (aSource == SourcePreload);
// If max-age is zero, the host is no longer considered HSTS. If the host was
// preloaded, we store an entry indicating that this host is not HSTS, causing
// the preloaded information to be ignored.
if (maxage == 0) {
return MarkHostAsNotHSTS(hostname, flags, isPreload, aOriginAttributes);
return MarkHostAsNotHSTS(aType, hostname, flags, isPreload,
aOriginAttributes);
}
MOZ_ASSERT(aHSTSState == SecurityPropertySet,
@ -338,7 +345,7 @@ nsresult nsSiteSecurityService::SetHSTSState(
? mozilla::DataStorage_Private
: mozilla::DataStorage_Persistent;
nsAutoCString storageKey;
SetStorageKey(hostname, aOriginAttributes, storageKey);
SetStorageKey(hostname, aType, aOriginAttributes, storageKey);
SSSLOG(("SSS: storing HSTS site entry for %s", hostname.get()));
nsCString value = mSiteStateStorage->Get(storageKey, storageType);
RefPtr<SiteHSTSState> curSiteState =
@ -360,8 +367,12 @@ nsresult nsSiteSecurityService::SetHSTSState(
// entry that indicates this host is not HSTS to prevent the implementation
// using the preloaded information.
nsresult nsSiteSecurityService::MarkHostAsNotHSTS(
const nsAutoCString& aHost, uint32_t aFlags, bool aIsPreload,
const OriginAttributes& aOriginAttributes) {
uint32_t aType, const nsAutoCString& aHost, uint32_t aFlags,
bool aIsPreload, const OriginAttributes& aOriginAttributes) {
// This only applies to HSTS.
if (aType != nsISiteSecurityService::HEADER_HSTS) {
return NS_ERROR_INVALID_ARG;
}
if (aIsPreload && aOriginAttributes != OriginAttributes()) {
return NS_ERROR_INVALID_ARG;
}
@ -371,7 +382,7 @@ nsresult nsSiteSecurityService::MarkHostAsNotHSTS(
? mozilla::DataStorage_Private
: mozilla::DataStorage_Persistent;
nsAutoCString storageKey;
SetStorageKey(aHost, aOriginAttributes, storageKey);
SetStorageKey(aHost, aType, aOriginAttributes, storageKey);
if (GetPreloadStatus(aHost)) {
SSSLOG(("SSS: storing knockout entry for %s", aHost.get()));
@ -391,7 +402,7 @@ nsresult nsSiteSecurityService::MarkHostAsNotHSTS(
}
NS_IMETHODIMP
nsSiteSecurityService::ResetState(nsIURI* aURI, uint32_t aFlags,
nsSiteSecurityService::ResetState(uint32_t aType, nsIURI* aURI, uint32_t aFlags,
JS::HandleValue aOriginAttributes,
JSContext* aCx, uint8_t aArgc) {
if (!XRE_IsParentProcess()) {
@ -412,7 +423,7 @@ nsSiteSecurityService::ResetState(nsIURI* aURI, uint32_t aFlags,
}
}
return ResetStateInternal(aURI, aFlags, originAttributes);
return ResetStateInternal(aType, aURI, aFlags, originAttributes);
}
// Helper function to reset stored state of the given type for the host
@ -422,17 +433,21 @@ nsSiteSecurityService::ResetState(nsIURI* aURI, uint32_t aFlags,
// header with max-age=0 (meaning preloaded information will then not be used
// for that host).
nsresult nsSiteSecurityService::ResetStateInternal(
nsIURI* aURI, uint32_t aFlags, const OriginAttributes& aOriginAttributes) {
uint32_t aType, nsIURI* aURI, uint32_t aFlags,
const OriginAttributes& aOriginAttributes) {
if (!aURI) {
return NS_ERROR_INVALID_ARG;
}
if (aType != nsISiteSecurityService::HEADER_HSTS) {
return NS_ERROR_INVALID_ARG;
}
nsAutoCString hostname;
nsresult rv = GetHost(aURI, hostname);
if (NS_FAILED(rv)) {
return rv;
}
nsAutoCString storageKey;
SetStorageKey(hostname, aOriginAttributes, storageKey);
SetStorageKey(hostname, aType, aOriginAttributes, storageKey);
bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
mozilla::DataStorageType storageType = isPrivate
? mozilla::DataStorage_Private
@ -441,7 +456,7 @@ nsresult nsSiteSecurityService::ResetStateInternal(
return NS_OK;
}
bool nsSiteSecurityService::HostIsIPAddress(const nsCString& hostname) {
static bool HostIsIPAddress(const nsCString& hostname) {
PRNetAddr hostAddr;
PRErrorCode prv = PR_StringToNetAddr(hostname.get(), &hostAddr);
return (prv == PR_SUCCESS);
@ -449,7 +464,7 @@ bool nsSiteSecurityService::HostIsIPAddress(const nsCString& hostname) {
NS_IMETHODIMP
nsSiteSecurityService::ProcessHeaderScriptable(
nsIURI* aSourceURI, const nsACString& aHeader,
uint32_t aType, nsIURI* aSourceURI, const nsACString& aHeader,
nsITransportSecurityInfo* aSecInfo, uint32_t aFlags, uint32_t aSource,
JS::HandleValue aOriginAttributes, uint64_t* aMaxAge,
bool* aIncludeSubdomains, uint32_t* aFailureResult, JSContext* aCx,
@ -461,14 +476,14 @@ nsSiteSecurityService::ProcessHeaderScriptable(
return NS_ERROR_INVALID_ARG;
}
}
return ProcessHeader(aSourceURI, aHeader, aSecInfo, aFlags, aSource,
return ProcessHeader(aType, aSourceURI, aHeader, aSecInfo, aFlags, aSource,
originAttributes, aMaxAge, aIncludeSubdomains,
aFailureResult);
}
NS_IMETHODIMP
nsSiteSecurityService::ProcessHeader(
nsIURI* aSourceURI, const nsACString& aHeader,
uint32_t aType, nsIURI* aSourceURI, const nsACString& aHeader,
nsITransportSecurityInfo* aSecInfo, uint32_t aFlags, uint32_t aHeaderSource,
const OriginAttributes& aOriginAttributes, uint64_t* aMaxAge,
bool* aIncludeSubdomains, uint32_t* aFailureResult) {
@ -482,6 +497,8 @@ nsSiteSecurityService::ProcessHeader(
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
SecurityPropertySource source =
static_cast<SecurityPropertySource>(aHeaderSource);
switch (source) {
@ -494,19 +511,23 @@ nsSiteSecurityService::ProcessHeader(
}
NS_ENSURE_ARG(aSecInfo);
return ProcessHeaderInternal(aSourceURI, PromiseFlatCString(aHeader),
return ProcessHeaderInternal(aType, aSourceURI, PromiseFlatCString(aHeader),
aSecInfo, aFlags, source, aOriginAttributes,
aMaxAge, aIncludeSubdomains, aFailureResult);
}
nsresult nsSiteSecurityService::ProcessHeaderInternal(
nsIURI* aSourceURI, const nsCString& aHeader,
uint32_t aType, nsIURI* aSourceURI, const nsCString& aHeader,
nsITransportSecurityInfo* aSecInfo, uint32_t aFlags,
SecurityPropertySource aSource, const OriginAttributes& aOriginAttributes,
uint64_t* aMaxAge, bool* aIncludeSubdomains, uint32_t* aFailureResult) {
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
if (aMaxAge != nullptr) {
*aMaxAge = 0;
}
@ -548,12 +569,19 @@ nsresult nsSiteSecurityService::ProcessHeaderInternal(
return NS_OK;
}
return ProcessSTSHeader(aSourceURI, aHeader, aFlags, aSource,
aOriginAttributes, aMaxAge, aIncludeSubdomains,
aFailureResult);
switch (aType) {
case nsISiteSecurityService::HEADER_HSTS:
rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aSource,
aOriginAttributes, aMaxAge, aIncludeSubdomains,
aFailureResult);
break;
default:
MOZ_CRASH("unexpected header type");
}
return rv;
}
static uint32_t ParseSSSHeaders(const nsCString& aHeader,
static uint32_t ParseSSSHeaders(uint32_t aType, const nsCString& aHeader,
bool& foundIncludeSubdomains, bool& foundMaxAge,
bool& foundUnrecognizedDirective,
uint64_t& maxAge) {
@ -647,13 +675,16 @@ nsresult nsSiteSecurityService::ProcessSTSHeader(
}
SSSLOG(("SSS: processing HSTS header '%s'", aHeader.get()));
const uint32_t aType = nsISiteSecurityService::HEADER_HSTS;
bool foundMaxAge = false;
bool foundIncludeSubdomains = false;
bool foundUnrecognizedDirective = false;
uint64_t maxAge = 0;
nsTArray<nsCString> unusedSHA256keys; // Required for sane internal interface
uint32_t sssrv = ParseSSSHeaders(aHeader, foundIncludeSubdomains, foundMaxAge,
foundUnrecognizedDirective, maxAge);
uint32_t sssrv =
ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains, foundMaxAge,
foundUnrecognizedDirective, maxAge);
if (sssrv != nsISiteSecurityService::Success) {
if (aFailureResult) {
*aFailureResult = sssrv;
@ -676,8 +707,8 @@ nsresult nsSiteSecurityService::ProcessSTSHeader(
NS_ENSURE_SUCCESS(rv, rv);
// record the successfully parsed header data.
rv = SetHSTSState(hostname.get(), maxAge, foundIncludeSubdomains, aFlags,
SecurityPropertySet, aSource, aOriginAttributes);
rv = SetHSTSState(aType, hostname.get(), maxAge, foundIncludeSubdomains,
aFlags, SecurityPropertySet, aSource, aOriginAttributes);
if (NS_FAILED(rv)) {
SSSLOG(("SSS: failed to set STS state"));
if (aFailureResult) {
@ -699,7 +730,8 @@ nsresult nsSiteSecurityService::ProcessSTSHeader(
}
NS_IMETHODIMP
nsSiteSecurityService::IsSecureURIScriptable(nsIURI* aURI, uint32_t aFlags,
nsSiteSecurityService::IsSecureURIScriptable(uint32_t aType, nsIURI* aURI,
uint32_t aFlags,
JS::HandleValue aOriginAttributes,
bool* aCached, uint32_t* aSource,
JSContext* aCx, uint8_t aArgc,
@ -711,17 +743,31 @@ nsSiteSecurityService::IsSecureURIScriptable(nsIURI* aURI, uint32_t aFlags,
return NS_ERROR_INVALID_ARG;
}
}
return IsSecureURI(aURI, aFlags, originAttributes, aCached, aSource, aResult);
return IsSecureURI(aType, aURI, aFlags, originAttributes, aCached, aSource,
aResult);
}
NS_IMETHODIMP
nsSiteSecurityService::IsSecureURI(nsIURI* aURI, uint32_t aFlags,
nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
uint32_t aFlags,
const OriginAttributes& aOriginAttributes,
bool* aCached, uint32_t* aSource,
bool* aResult) {
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
MOZ_CRASH(
"Child process: no direct access to "
"nsISiteSecurityService::IsSecureURI for non-HSTS entries");
}
NS_ENSURE_ARG(aURI);
NS_ENSURE_ARG(aResult);
// Only HSTS and static pinning are supported.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::STATIC_PINNING,
NS_ERROR_NOT_IMPLEMENTED);
nsAutoCString hostname;
nsresult rv = GetHost(aURI, hostname);
NS_ENSURE_SUCCESS(rv, rv);
@ -734,8 +780,8 @@ nsSiteSecurityService::IsSecureURI(nsIURI* aURI, uint32_t aFlags,
SecurityPropertySource* source =
BitwiseCast<SecurityPropertySource*>(aSource);
return IsSecureHost(hostname, aFlags, aOriginAttributes, aCached, source,
aResult);
return IsSecureHost(aType, hostname, aFlags, aOriginAttributes, aCached,
source, aResult);
}
// Checks if the given host is in the preload list.
@ -791,13 +837,17 @@ bool nsSiteSecurityService::HostHasHSTSEntry(
: mozilla::DataStorage_Persistent;
nsAutoCString storageKey;
SSSLOG(("Seeking HSTS entry for %s", aHost.get()));
SetStorageKey(aHost, aOriginAttributes, storageKey);
SetStorageKey(aHost, nsISiteSecurityService::HEADER_HSTS, aOriginAttributes,
storageKey);
nsAutoCString preloadKey;
SetStorageKey(aHost, nsISiteSecurityService::HEADER_HSTS, OriginAttributes(),
preloadKey);
nsCString value = mSiteStateStorage->Get(storageKey, storageType);
RefPtr<SiteHSTSState> siteState =
new SiteHSTSState(aHost, aOriginAttributes, value);
if (siteState->mHSTSState != SecurityPropertyUnset) {
SSSLOG(("Found HSTS entry for %s", aHost.get()));
bool expired = siteState->IsExpired();
bool expired = siteState->IsExpired(nsISiteSecurityService::HEADER_HSTS);
if (!expired) {
SSSLOG(("Entry for %s is not expired", aHost.get()));
if (siteState->mHSTSState == SecurityPropertySet) {
@ -847,11 +897,23 @@ bool nsSiteSecurityService::HostHasHSTSEntry(
}
nsresult nsSiteSecurityService::IsSecureHost(
const nsACString& aHost, uint32_t aFlags,
uint32_t aType, const nsACString& aHost, uint32_t aFlags,
const OriginAttributes& aOriginAttributes, bool* aCached,
SecurityPropertySource* aSource, bool* aResult) {
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
MOZ_CRASH(
"Child process: no direct access to "
"nsISiteSecurityService::IsSecureHost for non-HSTS entries");
}
NS_ENSURE_ARG(aResult);
// Only HSTS and static pinning are supported.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::STATIC_PINNING,
NS_ERROR_NOT_IMPLEMENTED);
// set default in case if we can't find any STS information
*aResult = false;
@ -861,6 +923,22 @@ nsresult nsSiteSecurityService::IsSecureHost(
return NS_OK;
}
if (aType == nsISiteSecurityService::STATIC_PINNING) {
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
if (!certVerifier) {
return NS_ERROR_FAILURE;
}
if (certVerifier->mPinningMode ==
CertVerifier::PinningMode::pinningDisabled) {
return NS_OK;
}
bool enforceTestMode = certVerifier->mPinningMode ==
CertVerifier::PinningMode::pinningEnforceTestMode;
return PublicKeyPinningService::HostHasPins(
flatHost.get(), mozilla::pkix::Now(), enforceTestMode,
aOriginAttributes, *aResult);
}
nsAutoCString host(
PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
@ -912,28 +990,46 @@ nsSiteSecurityService::ClearAll() {
}
NS_IMETHODIMP
nsSiteSecurityService::Enumerate(nsISimpleEnumerator** aEnumerator) {
nsSiteSecurityService::Enumerate(uint32_t aType,
nsISimpleEnumerator** aEnumerator) {
NS_ENSURE_ARG(aEnumerator);
nsAutoCString keySuffix;
switch (aType) {
case nsISiteSecurityService::HEADER_HSTS:
keySuffix.AssignASCII(kHSTSKeySuffix);
break;
default:
return NS_ERROR_INVALID_ARG;
}
nsTArray<mozilla::psm::DataStorageItem> items;
mSiteStateStorage->GetAll(&items);
nsCOMArray<nsISiteSecurityState> states;
for (const mozilla::psm::DataStorageItem& item : items) {
if (!StringEndsWith(item.key(), kHSTSKeySuffix)) {
if (!StringEndsWith(item.key(), keySuffix)) {
// The key does not end with correct suffix, so is not the type we want.
continue;
}
nsCString origin(
StringHead(item.key(), item.key().Length() - kHSTSKeySuffix.Length()));
StringHead(item.key(), item.key().Length() - keySuffix.Length()));
nsAutoCString hostname;
OriginAttributes originAttributes;
if (!originAttributes.PopulateFromOrigin(origin, hostname)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISiteSecurityState> state(
new SiteHSTSState(hostname, originAttributes, item.value()));
nsCOMPtr<nsISiteSecurityState> state;
switch (aType) {
case nsISiteSecurityService::HEADER_HSTS:
state = new SiteHSTSState(hostname, originAttributes, item.value());
break;
default:
MOZ_ASSERT_UNREACHABLE("SSS:Enumerate got invalid type");
}
states.AppendObject(state);
}

View File

@ -82,7 +82,7 @@ class SiteHSTSState : public nsISiteHSTSState {
bool mHSTSIncludeSubdomains;
SecurityPropertySource mHSTSSource;
bool IsExpired() {
bool IsExpired(uint32_t aType) {
// If mHSTSExpireTime is 0, this entry never expires (this is the case for
// knockout entries).
if (mHSTSExpireTime == 0) {
@ -115,34 +115,30 @@ class nsSiteSecurityService : public nsISiteSecurityService,
nsSiteSecurityService();
nsresult Init();
static nsresult GetHost(nsIURI* aURI, nsACString& aResult);
static bool HostIsIPAddress(const nsCString& hostname);
protected:
virtual ~nsSiteSecurityService();
private:
nsresult SetHSTSState(const char* aHost, int64_t maxage,
nsresult GetHost(nsIURI* aURI, nsACString& aResult);
nsresult SetHSTSState(uint32_t aType, const char* aHost, int64_t maxage,
bool includeSubdomains, uint32_t flags,
SecurityPropertyState aHSTSState,
SecurityPropertySource aSource,
const OriginAttributes& aOriginAttributes);
nsresult ProcessHeaderInternal(nsIURI* aSourceURI, const nsCString& aHeader,
nsITransportSecurityInfo* aSecInfo,
uint32_t aFlags,
SecurityPropertySource aSource,
const OriginAttributes& aOriginAttributes,
uint64_t* aMaxAge, bool* aIncludeSubdomains,
uint32_t* aFailureResult);
nsresult ProcessHeaderInternal(
uint32_t aType, nsIURI* aSourceURI, const nsCString& aHeader,
nsITransportSecurityInfo* aSecInfo, uint32_t aFlags,
SecurityPropertySource aSource, const OriginAttributes& aOriginAttributes,
uint64_t* aMaxAge, bool* aIncludeSubdomains, uint32_t* aFailureResult);
nsresult ProcessSTSHeader(nsIURI* aSourceURI, const nsCString& aHeader,
uint32_t flags, SecurityPropertySource aSource,
const OriginAttributes& aOriginAttributes,
uint64_t* aMaxAge, bool* aIncludeSubdomains,
uint32_t* aFailureResult);
nsresult MarkHostAsNotHSTS(const nsAutoCString& aHost, uint32_t aFlags,
bool aIsPreload,
nsresult MarkHostAsNotHSTS(uint32_t aType, const nsAutoCString& aHost,
uint32_t aFlags, bool aIsPreload,
const OriginAttributes& aOriginAttributes);
nsresult ResetStateInternal(nsIURI* aURI, uint32_t aFlags,
nsresult ResetStateInternal(uint32_t aType, nsIURI* aURI, uint32_t aFlags,
const OriginAttributes& aOriginAttributes);
bool HostHasHSTSEntry(const nsAutoCString& aHost,
bool aRequireIncludeSubdomains, uint32_t aFlags,
@ -152,7 +148,8 @@ class nsSiteSecurityService : public nsISiteSecurityService,
bool GetPreloadStatus(
const nsACString& aHost,
/*optional out*/ bool* aIncludeSubdomains = nullptr) const;
nsresult IsSecureHost(const nsACString& aHost, uint32_t aFlags,
nsresult IsSecureHost(uint32_t aType, const nsACString& aHost,
uint32_t aFlags,
const OriginAttributes& aOriginAttributes,
bool* aCached, SecurityPropertySource* aSource,
bool* aResult);

View File

@ -38,6 +38,7 @@ function test() {
].createInstance(Ci.nsITransportSecurityInfo);
uri = aWindow.Services.io.newURI("https://localhost/img.png");
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000",
secInfo,
@ -45,7 +46,11 @@ function test() {
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(
gSSService.isSecureURI(uri, privacyFlags(aIsPrivateMode)),
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
privacyFlags(aIsPrivateMode)
),
"checking sts host"
);
@ -74,7 +79,7 @@ function test() {
aWin.close();
});
uri = Services.io.newURI("http://localhost");
gSSService.resetState(uri, 0);
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
});
// test first when on private mode

View File

@ -7,46 +7,57 @@ function run_test() {
);
ok(
!SSService.isSecureURI(Services.io.newURI("https://expired.example.com"), 0)
!SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://expired.example.com"),
0
)
);
ok(
SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://notexpired.example.com"),
0
)
);
ok(
SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
);
ok(
!SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.includesubdomains.preloaded.test"),
0
)
);
ok(
SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://incsubdomain.example.com"),
0
)
);
ok(
SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.incsubdomain.example.com"),
0
)
);
ok(
!SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains2.preloaded.test"),
0
)
);
ok(
!SSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.includesubdomains2.preloaded.test"),
0
)

View File

@ -45,6 +45,7 @@ function add_tests() {
// longer.
add_task(async function() {
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
GOOD_MAX_AGE,
secInfo,
@ -52,12 +53,15 @@ function add_tests() {
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
Assert.ok(sss.isSecureURI(uri, 0), "a.pinning.example.com should be HSTS");
Assert.ok(
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
"a.pinning.example.com should be HSTS"
);
await ForgetAboutSite.removeDataFromDomain("a.pinning.example.com");
Assert.ok(
!sss.isSecureURI(uri, 0),
!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
"a.pinning.example.com should not be HSTS now"
);
});
@ -68,6 +72,7 @@ function add_tests() {
// unrelated sites don't also get removed.
add_task(async function() {
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
GOOD_MAX_AGE,
secInfo,
@ -76,30 +81,34 @@ function add_tests() {
);
Assert.ok(
sss.isSecureURI(uri, 0),
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
"a.pinning.example.com should be HSTS (subdomain case)"
);
// Add an unrelated site to HSTS.
let unrelatedURI = Services.io.newURI("https://example.org");
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
unrelatedURI,
GOOD_MAX_AGE,
secInfo,
0,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
Assert.ok(sss.isSecureURI(unrelatedURI, 0), "example.org should be HSTS");
Assert.ok(
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, unrelatedURI, 0),
"example.org should be HSTS"
);
await ForgetAboutSite.removeDataFromDomain("example.com");
Assert.ok(
!sss.isSecureURI(uri, 0),
!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
"a.pinning.example.com should not be HSTS now (subdomain case)"
);
Assert.ok(
sss.isSecureURI(unrelatedURI, 0),
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, unrelatedURI, 0),
"example.org should still be HSTS"
);
});
@ -121,6 +130,7 @@ function add_tests() {
for (let originAttributes of originAttributesList) {
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
GOOD_MAX_AGE,
secInfo,
@ -130,12 +140,18 @@ function add_tests() {
);
Assert.ok(
sss.isSecureURI(uri, 0, originAttributes),
sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes
),
"a.pinning.example.com should be HSTS (originAttributes case)"
);
// Add an unrelated site to HSTS.
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
unrelatedURI,
GOOD_MAX_AGE,
secInfo,
@ -144,7 +160,12 @@ function add_tests() {
originAttributes
);
Assert.ok(
sss.isSecureURI(unrelatedURI, 0, originAttributes),
sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
unrelatedURI,
0,
originAttributes
),
"example.org should be HSTS (originAttributes case)"
);
}
@ -153,13 +174,23 @@ function add_tests() {
for (let originAttributes of originAttributesList) {
Assert.ok(
!sss.isSecureURI(uri, 0, originAttributes),
!sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes
),
"a.pinning.example.com should not be HSTS now " +
"(originAttributes case)"
);
Assert.ok(
sss.isSecureURI(unrelatedURI, 0, originAttributes),
sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
unrelatedURI,
0,
originAttributes
),
"example.org should still be HSTS (originAttributes case)"
);
}

View File

@ -51,6 +51,7 @@ function run_test() {
"@mozilla.org/security/transportsecurityinfo;1"
].createInstance(Ci.nsITransportSecurityInfo);
SSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=10000",
secInfo,
@ -58,7 +59,7 @@ function run_test() {
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(
SSService.isSecureURI(uri, 0),
SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
"Domain for the OCSP AIA URI should be considered a HSTS host, otherwise" +
" we wouldn't be testing what we think we're testing"
);

View File

@ -21,8 +21,8 @@ const TESTCASES = [
let sss = Cc["@mozilla.org/ssservice;1"].getService(Ci.nsISiteSecurityService);
function getEntries() {
return Array.from(sss.enumerate());
function getEntries(type) {
return Array.from(sss.enumerate(type));
}
function checkSiteSecurityStateAttrs(entries) {
@ -71,6 +71,7 @@ function add_tests() {
header += "; includeSubdomains";
}
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
header,
secInfo,
@ -82,12 +83,12 @@ function add_tests() {
}
add_task(() => {
let hstsEntries = getEntries();
let hstsEntries = getEntries(Ci.nsISiteSecurityService.HEADER_HSTS);
checkSiteSecurityStateAttrs(hstsEntries);
sss.clearAll();
hstsEntries = getEntries();
hstsEntries = getEntries(Ci.nsISiteSecurityService.HEADER_HSTS);
equal(hstsEntries.length, 0, "Should clear all HSTS entries");
});

View File

@ -53,6 +53,7 @@ function do_state_read(aSubject, aTopic, aData) {
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://frequentlyused.example.com"),
0
)
@ -63,6 +64,7 @@ function do_state_read(aSubject, aTopic, aData) {
for (let i = 0; i < 2000; i++) {
let uri = Services.io.newURI("http://bad" + i + ".example.com");
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000",
secInfo,

View File

@ -24,6 +24,7 @@ function doTest(secInfo, originAttributes1, originAttributes2, shouldShare) {
let header = GOOD_MAX_AGE;
// Set HSTS for originAttributes1.
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
header,
secInfo,
@ -32,11 +33,21 @@ function doTest(secInfo, originAttributes1, originAttributes2, shouldShare) {
originAttributes1
);
ok(
sss.isSecureURI(uri, 0, originAttributes1),
sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes1
),
"URI should be secure given original origin attributes"
);
equal(
sss.isSecureURI(uri, 0, originAttributes2),
sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes2
),
shouldShare,
"URI should be secure given different origin attributes if and " +
"only if shouldShare is true"
@ -44,17 +55,37 @@ function doTest(secInfo, originAttributes1, originAttributes2, shouldShare) {
if (!shouldShare) {
// Remove originAttributes2 from the storage.
sss.resetState(uri, 0, originAttributes2);
sss.resetState(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes2
);
ok(
sss.isSecureURI(uri, 0, originAttributes1),
sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes1
),
"URI should still be secure given original origin attributes"
);
}
// Remove originAttributes1 from the storage.
sss.resetState(uri, 0, originAttributes1);
sss.resetState(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes1
);
ok(
!sss.isSecureURI(uri, 0, originAttributes1),
!sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes1
),
"URI should not be secure after removeState"
);
@ -67,6 +98,7 @@ function testInvalidOriginAttributes(secInfo, originAttributes) {
let callbacks = [
() =>
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
header,
secInfo,
@ -74,8 +106,20 @@ function testInvalidOriginAttributes(secInfo, originAttributes) {
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST,
originAttributes
),
() => sss.isSecureURI(uri, 0, originAttributes),
() => sss.resetState(uri, 0, originAttributes),
() =>
sss.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes
),
() =>
sss.resetState(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes
),
];
for (let callback of callbacks) {

View File

@ -17,48 +17,56 @@ function checkStateRead(aSubject, aTopic, aData) {
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://expired.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://notexpired.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.includesubdomains.preloaded.test"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://incsubdomain.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.incsubdomain.example.com"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains2.preloaded.test"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.includesubdomains2.preloaded.test"),
0
)
@ -68,48 +76,56 @@ function checkStateRead(aSubject, aTopic, aData) {
gSSService.clearAll();
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://expired.example.com"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://notexpired.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.includesubdomains.preloaded.test"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://incsubdomain.example.com"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.incsubdomain.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains2.preloaded.test"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sub.includesubdomains2.preloaded.test"),
0
)

View File

@ -12,12 +12,14 @@ function checkStateRead(aSubject, aTopic, aData) {
// nonexistent.example.com should never be an HSTS host
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://nonexistent.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
@ -26,6 +28,7 @@ function checkStateRead(aSubject, aTopic, aData) {
// want to make sure that test hasn't interfered with this one.
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://notexpired.example.com"),
0
)

View File

@ -21,7 +21,11 @@ function checkStateRead(aSubject, aTopic, aData) {
];
for (let host of HSTS_HOSTS) {
ok(
gSSService.isSecureURI(Services.io.newURI(host), 0),
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI(host),
0
),
`${host} should be HSTS enabled`
);
}
@ -41,7 +45,11 @@ function checkStateRead(aSubject, aTopic, aData) {
];
for (let host of NOT_HSTS_HOSTS) {
ok(
!gSSService.isSecureURI(Services.io.newURI(host), 0),
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI(host),
0
),
`${host} should not be HSTS enabled`
);
}

View File

@ -18,42 +18,49 @@ function checkStateRead(aSubject, aTopic, aData) {
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example0.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example423.example.com"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example1023.example.com"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example1024.example.com"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example1025.example.com"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example9000.example.com"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example99999.example.com"),
0
)

View File

@ -14,70 +14,74 @@ var gSSService = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
function test_removeState(secInfo, flags) {
info(`running test_removeState(flags=${flags})`);
function test_removeState(secInfo, type, flags) {
info(`running test_removeState(type=${type}, flags=${flags})`);
// Simulate visiting a non-preloaded site by processing an HSTS header check
// that the HSTS bit gets set, simulate "forget about this site" (call
// removeState), and then check that the HSTS bit isn't set.
let notPreloadedURI = Services.io.newURI("https://not-preloaded.example.com");
ok(!gSSService.isSecureURI(notPreloadedURI, flags));
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
gSSService.processHeader(
type,
notPreloadedURI,
"max-age=1000;",
secInfo,
flags,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(gSSService.isSecureURI(notPreloadedURI, flags));
gSSService.resetState(notPreloadedURI, flags);
ok(!gSSService.isSecureURI(notPreloadedURI, flags));
ok(gSSService.isSecureURI(type, notPreloadedURI, flags));
gSSService.resetState(type, notPreloadedURI, flags);
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
// Simulate visiting a non-preloaded site that unsets HSTS by processing
// an HSTS header with "max-age=0", check that the HSTS bit isn't
// set, simulate "forget about this site" (call removeState), and then check
// that the HSTS bit isn't set.
gSSService.processHeader(
type,
notPreloadedURI,
"max-age=0;",
secInfo,
flags,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(!gSSService.isSecureURI(notPreloadedURI, flags));
gSSService.resetState(notPreloadedURI, flags);
ok(!gSSService.isSecureURI(notPreloadedURI, flags));
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
gSSService.resetState(type, notPreloadedURI, flags);
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
// Simulate visiting a preloaded site by processing an HSTS header, check
// that the HSTS bit is still set, simulate "forget about this site"
// (call removeState), and then check that the HSTS bit is still set.
let preloadedHost = "includesubdomains.preloaded.test";
let preloadedURI = Services.io.newURI(`https://${preloadedHost}`);
ok(gSSService.isSecureURI(preloadedURI, flags));
ok(gSSService.isSecureURI(type, preloadedURI, flags));
gSSService.processHeader(
type,
preloadedURI,
"max-age=1000;",
secInfo,
flags,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(gSSService.isSecureURI(preloadedURI, flags));
gSSService.resetState(preloadedURI, flags);
ok(gSSService.isSecureURI(preloadedURI, flags));
ok(gSSService.isSecureURI(type, preloadedURI, flags));
gSSService.resetState(type, preloadedURI, flags);
ok(gSSService.isSecureURI(type, preloadedURI, flags));
// Simulate visiting a preloaded site that unsets HSTS by processing an
// HSTS header with "max-age=0", check that the HSTS bit is what we
// expect (see below), simulate "forget about this site" (call removeState),
// and then check that the HSTS bit is set.
gSSService.processHeader(
type,
preloadedURI,
"max-age=0;",
secInfo,
flags,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(!gSSService.isSecureURI(preloadedURI, flags));
gSSService.resetState(preloadedURI, flags);
ok(gSSService.isSecureURI(preloadedURI, flags));
ok(!gSSService.isSecureURI(type, preloadedURI, flags));
gSSService.resetState(type, preloadedURI, flags);
ok(gSSService.isSecureURI(type, preloadedURI, flags));
}
function add_tests() {
@ -92,8 +96,12 @@ function add_tests() {
);
add_task(() => {
test_removeState(secInfo, 0);
test_removeState(secInfo, Ci.nsISocketProvider.NO_PERMANENT_STORAGE);
test_removeState(secInfo, Ci.nsISiteSecurityService.HEADER_HSTS, 0);
test_removeState(
secInfo,
Ci.nsISiteSecurityService.HEADER_HSTS,
Ci.nsISocketProvider.NO_PERMANENT_STORAGE
);
});
}

View File

@ -40,6 +40,7 @@ add_task(async function run_test() {
].createInstance(Ci.nsITransportSecurityInfo);
let header = "max-age=50000";
SSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("http://example.com"),
header,
secInfo,

View File

@ -108,6 +108,7 @@ function run_test() {
"@mozilla.org/security/transportsecurityinfo;1"
].createInstance(Ci.nsITransportSecurityInfo);
SSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uris[uriIndex],
maxAge + includeSubdomains,
secInfo,

View File

@ -11,29 +11,30 @@ function run_test() {
let uri = Services.io.newURI("https://example.com");
let uri1 = Services.io.newURI("https://example.com.");
let uri2 = Services.io.newURI("https://example.com..");
ok(!SSService.isSecureURI(uri, 0));
ok(!SSService.isSecureURI(uri1, 0));
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri1, 0));
// These cases are only relevant as long as bug 1118522 hasn't been fixed.
ok(!SSService.isSecureURI(uri2, 0));
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri2, 0));
let secInfo = Cc[
"@mozilla.org/security/transportsecurityinfo;1"
].createInstance(Ci.nsITransportSecurityInfo);
SSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000;includeSubdomains",
secInfo,
0,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(SSService.isSecureURI(uri, 0));
ok(SSService.isSecureURI(uri1, 0));
ok(SSService.isSecureURI(uri2, 0));
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri1, 0));
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri2, 0));
SSService.resetState(uri, 0);
ok(!SSService.isSecureURI(uri, 0));
ok(!SSService.isSecureURI(uri1, 0));
ok(!SSService.isSecureURI(uri2, 0));
SSService.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri1, 0));
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri2, 0));
// Somehow creating this malformed URI succeeds - we need to handle it
// gracefully.
@ -41,7 +42,7 @@ function run_test() {
equal(uri.host, "..");
throws(
() => {
SSService.isSecureURI(uri, 0);
SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
},
/NS_ERROR_UNEXPECTED/,
"Malformed URI should be rejected"

View File

@ -16,11 +16,12 @@ function check_ip(s, v, ip) {
str += "/";
let uri = Services.io.newURI(str);
ok(!s.isSecureURI(uri, 0));
ok(!s.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
let parsedMaxAge = {};
let parsedIncludeSubdomains = {};
s.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000;includeSubdomains",
secInfo,
@ -31,7 +32,7 @@ function check_ip(s, v, ip) {
parsedIncludeSubdomains
);
ok(
!s.isSecureURI(uri, 0),
!s.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
"URI should not be secure if it contains an IP address"
);

View File

@ -19,6 +19,7 @@ function testSuccess(header, expectedMaxAge, expectedIncludeSubdomains) {
let includeSubdomains = {};
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
dummyUri,
header,
secInfo,
@ -45,6 +46,7 @@ function testFailure(header) {
throws(
() => {
sss.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
dummyUri,
header,
secInfo,

View File

@ -40,13 +40,20 @@ function test_part1() {
// check that a host not in the list is not identified as an sts host
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://nonexistent.example.com"),
0
)
);
// check that an ancestor domain is not identified as an sts host
ok(!gSSService.isSecureURI(Services.io.newURI("https://com"), 0));
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://com"),
0
)
);
// check that the pref to toggle using the preload list works
Services.prefs.setBoolPref(
@ -55,6 +62,7 @@ function test_part1() {
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
@ -65,6 +73,7 @@ function test_part1() {
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
@ -73,6 +82,7 @@ function test_part1() {
// check that a subdomain is an sts host (includeSubdomains is set)
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://subdomain.includesubdomains.preloaded.test"),
0
)
@ -81,6 +91,7 @@ function test_part1() {
// check that another subdomain is an sts host (includeSubdomains is set)
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://a.b.c.def.includesubdomains.preloaded.test"),
0
)
@ -89,6 +100,7 @@ function test_part1() {
// check that a subdomain is not an sts host (includeSubdomains is not set)
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI(
"https://subdomain.noincludesubdomains.preloaded.test"
),
@ -99,6 +111,7 @@ function test_part1() {
// check that a host with a dot on the end won't break anything
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://notsts.nonexistent.example.com."),
0
)
@ -111,26 +124,40 @@ function test_part1() {
"https://subdomain.includesubdomains.preloaded.test"
);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=0",
secInfo,
0,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(!gSSService.isSecureURI(uri, 0));
ok(!gSSService.isSecureURI(subDomainUri, 0));
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
subDomainUri,
0
)
);
// check that processing another header (with max-age non-zero) will
// re-enable a site's sts status
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000",
secInfo,
0,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(gSSService.isSecureURI(uri, 0));
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
// but this time include subdomains was not set, so test for that
ok(!gSSService.isSecureURI(subDomainUri, 0));
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
subDomainUri,
0
)
);
gSSService.clearAll();
// check that processing a header with max-age: 0 from a subdomain of a site
@ -139,6 +166,7 @@ function test_part1() {
"https://subdomain.noincludesubdomains.preloaded.test"
);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=0",
secInfo,
@ -147,16 +175,18 @@ function test_part1() {
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://noincludesubdomains.preloaded.test"),
0
)
);
ok(!gSSService.isSecureURI(uri, 0));
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
uri = Services.io.newURI(
"https://subdomain.includesubdomains.preloaded.test"
);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=0",
secInfo,
@ -174,24 +204,28 @@ function test_part1() {
// `-- sibling.includesubdomains.preloaded.test IS sts host
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://subdomain.includesubdomains.preloaded.test"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sibling.includesubdomains.preloaded.test"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI(
"https://another.subdomain.includesubdomains.preloaded.test"
),
@ -200,6 +234,7 @@ function test_part1() {
);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000",
secInfo,
@ -213,18 +248,21 @@ function test_part1() {
// `-- sibling.includesubdomains.preloaded.test IS sts host
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://subdomain.includesubdomains.preloaded.test"),
0
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://sibling.includesubdomains.preloaded.test"),
0
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI(
"https://another.subdomain.includesubdomains.preloaded.test"
),
@ -239,8 +277,9 @@ function test_part1() {
// then treat that host as no longer an sts host.)
// (sanity check first - this should be in the preload list)
uri = Services.io.newURI("https://includesubdomains2.preloaded.test");
ok(gSSService.isSecureURI(uri, 0));
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1",
secInfo,
@ -248,7 +287,7 @@ function test_part1() {
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
do_timeout(1250, function() {
ok(!gSSService.isSecureURI(uri, 0));
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
run_next_test();
});
}
@ -262,41 +301,92 @@ function test_private_browsing1() {
"https://a.b.c.subdomain.includesubdomains.preloaded.test"
);
// sanity - includesubdomains.preloaded.test is preloaded, includeSubdomains set
ok(gSSService.isSecureURI(uri, IS_PRIVATE));
ok(gSSService.isSecureURI(subDomainUri, IS_PRIVATE));
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
IS_PRIVATE
)
);
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
subDomainUri,
IS_PRIVATE
)
);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=0",
secInfo,
IS_PRIVATE,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(!gSSService.isSecureURI(uri, IS_PRIVATE));
ok(!gSSService.isSecureURI(subDomainUri, IS_PRIVATE));
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
IS_PRIVATE
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
subDomainUri,
IS_PRIVATE
)
);
// check adding it back in
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000",
secInfo,
IS_PRIVATE,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(gSSService.isSecureURI(uri, IS_PRIVATE));
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
IS_PRIVATE
)
);
// but no includeSubdomains this time
ok(!gSSService.isSecureURI(subDomainUri, IS_PRIVATE));
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
subDomainUri,
IS_PRIVATE
)
);
// do the hokey-pokey...
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=0",
secInfo,
IS_PRIVATE,
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
ok(!gSSService.isSecureURI(uri, IS_PRIVATE));
ok(!gSSService.isSecureURI(subDomainUri, IS_PRIVATE));
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
IS_PRIVATE
)
);
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
subDomainUri,
IS_PRIVATE
)
);
// Test that an expired private browsing entry results in correctly
// identifying a host that is on the preload list as no longer sts.
@ -305,8 +395,15 @@ function test_private_browsing1() {
// then treat that host as no longer an sts host.)
// (sanity check first - this should be in the preload list)
uri = Services.io.newURI("https://includesubdomains2.preloaded.test");
ok(gSSService.isSecureURI(uri, IS_PRIVATE));
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
IS_PRIVATE
)
);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1",
secInfo,
@ -314,7 +411,13 @@ function test_private_browsing1() {
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
);
do_timeout(1250, function() {
ok(!gSSService.isSecureURI(uri, IS_PRIVATE));
ok(
!gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
IS_PRIVATE
)
);
// Simulate leaving private browsing mode
Services.obs.notifyObservers(null, "last-pb-context-exited");
});
@ -324,6 +427,7 @@ function test_private_browsing2() {
// if this test gets this far, it means there's a private browsing service
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains.preloaded.test"),
0
)
@ -331,6 +435,7 @@ function test_private_browsing2() {
// the includesubdomains.preloaded.test entry has includeSubdomains set
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://subdomain.includesubdomains.preloaded.test"),
0
)
@ -340,6 +445,7 @@ function test_private_browsing2() {
// we've "forgotten" that we "forgot" this site's sts status.
ok(
gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://includesubdomains2.preloaded.test"),
0
)

View File

@ -7,16 +7,16 @@ function run_test() {
let uri = Services.io.newURI("https://includesubdomains.preloaded.test");
// check that a host on the preload list is identified as an sts host
ok(SSService.isSecureURI(uri, 0));
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
// now simulate that it's 19 weeks later than it actually is
let offsetSeconds = 19 * 7 * 24 * 60 * 60;
Services.prefs.setIntPref("test.currentTimeOffsetSeconds", offsetSeconds);
// check that the preloaded host is no longer considered sts
ok(!SSService.isSecureURI(uri, 0));
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
// just make sure we can get everything back to normal
Services.prefs.clearUserPref("test.currentTimeOffsetSeconds");
ok(SSService.isSecureURI(uri, 0));
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
}

View File

@ -120,6 +120,7 @@ function processStsHeader(host, header, status, securityInfo) {
let uri = Services.io.newURI("https://" + host.name);
let secInfo = securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
header,
secInfo,

View File

@ -1039,7 +1039,7 @@ class SpecialPowersParent extends JSWindowActorParent {
let sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
sss.resetState(uri, flags);
sss.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
return undefined;
}

View File

@ -42,7 +42,12 @@ function cleanupHSTS(aPartitionEnabled, aUseSite) {
}
}
sss.resetState(NetUtil.newURI("http://example.com/"), 0, originAttributes);
sss.resetState(
Ci.nsISiteSecurityService.HEADER_HSTS,
NetUtil.newURI("http://example.com/"),
0,
originAttributes
);
}
}

View File

@ -1055,12 +1055,17 @@ const SecuritySettingsCleaner = {
);
// Also remove HSTS information for subdomains by enumerating
// the information in the site security service.
for (let entry of sss.enumerate()) {
for (let entry of sss.enumerate(Ci.nsISiteSecurityService.HEADER_HSTS)) {
let hostname = entry.hostname;
if (Services.eTLD.hasRootDomain(hostname, aHost)) {
// This uri is used as a key to reset the state.
let uri = Services.io.newURI("https://" + hostname);
sss.resetState(uri, 0, entry.originAttributes);
sss.resetState(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
entry.originAttributes
);
}
}
let cars = Cc[
@ -1081,14 +1086,19 @@ const SecuritySettingsCleaner = {
// Remove HSTS information by enumerating entries of the site security
// service.
Array.from(sss.enumerate())
Array.from(sss.enumerate(Ci.nsISiteSecurityService.HEADER_HSTS))
.filter(({ hostname, originAttributes }) =>
hasBaseDomain({ host: hostname, originAttributes }, aDomain)
)
.forEach(({ hostname, originAttributes }) => {
// This uri is used as a key to reset the state.
let uri = Services.io.newURI("https://" + hostname);
sss.resetState(uri, 0, originAttributes);
sss.resetState(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
originAttributes
);
});
let cars = Cc[

View File

@ -19,6 +19,7 @@ function addSecurityInfo({ host, topLevelBaseDomain, originAttributes = {} }) {
].createInstance(Ci.nsITransportSecurityInfo);
gSSService.processHeader(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
"max-age=1000;",
secInfo,
@ -62,6 +63,7 @@ function testSecurityInfo({
}) {
let uri = Services.io.newURI(`https://${host}`);
let isSecure = gSSService.isSecureURI(
Ci.nsISiteSecurityService.HEADER_HSTS,
uri,
0,
getOAWithPartitionKey(topLevelBaseDomain, originAttributes)

View File

@ -23,12 +23,6 @@ XPCOMUtils.defineLazyServiceGetter(
"@mozilla.org/ssservice;1",
"nsISiteSecurityService"
);
XPCOMUtils.defineLazyServiceGetter(
this,
"pkps",
"@mozilla.org/security/publickeypinningservice;1",
"nsIPublicKeyPinningService"
);
// NOTE: SecurityInfo is largely reworked from the devtools NetworkHelper with changes
// to better support the WebRequest api. The objects returned are formatted specifically
@ -199,8 +193,8 @@ const SecurityInfo = {
flags = Ci.nsISocketProvider.NO_PERMANENT_STORAGE;
}
info.hsts = sss.isSecureURI(uri, flags);
info.hpkp = pkps.hostHasPins(uri);
info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags);
info.hpkp = sss.isSecureURI(sss.STATIC_PINNING, uri, flags);
} else {
info.hsts = false;
info.hpkp = false;