зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1323644
- Isolate the HSTS and HPKP storage by first party domain (PSM) r=Cykesiopka,keeler
MozReview-Commit-ID: HhFFqtpBNjO --HG-- extra : rebase_source : 980dfd035efc4886a7ca393923c2c2783cc76a7d
This commit is contained in:
Родитель
10e0910cef
Коммит
4489e44dc2
|
@ -867,8 +867,8 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
|
|||
(mPinningMode == CertVerifier::pinningEnforceTestMode);
|
||||
bool chainHasValidPins;
|
||||
nsresult nsrv = PublicKeyPinningService::ChainHasValidPins(
|
||||
certList, mHostname, time, enforceTestMode, chainHasValidPins,
|
||||
mPinningTelemetryInfo);
|
||||
certList, mHostname, time, enforceTestMode, mOriginAttributes,
|
||||
chainHasValidPins, mPinningTelemetryInfo);
|
||||
if (NS_FAILED(nsrv)) {
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ PublicKeyPinningService::ChainMatchesPinset(const UniqueCERTCertList& certList,
|
|||
// Dynamic pins are prioritized over static pins.
|
||||
static nsresult
|
||||
FindPinningInformation(const char* hostname, mozilla::pkix::Time time,
|
||||
const OriginAttributes& originAttributes,
|
||||
/*out*/ nsTArray<nsCString>& dynamicFingerprints,
|
||||
/*out*/ const TransportSecurityPreload*& staticFingerprints)
|
||||
{
|
||||
|
@ -190,7 +191,8 @@ FindPinningInformation(const char* hostname, mozilla::pkix::Time time,
|
|||
bool includeSubdomains;
|
||||
nsTArray<nsCString> pinArray;
|
||||
rv = sssService->GetKeyPinsForHostname(nsDependentCString(evalHost), time,
|
||||
pinArray, &includeSubdomains, &found);
|
||||
originAttributes, pinArray,
|
||||
&includeSubdomains, &found);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -241,6 +243,7 @@ FindPinningInformation(const char* hostname, mozilla::pkix::Time time,
|
|||
static nsresult
|
||||
CheckPinsForHostname(const UniqueCERTCertList& certList, const char* hostname,
|
||||
bool enforceTestMode, mozilla::pkix::Time time,
|
||||
const OriginAttributes& originAttributes,
|
||||
/*out*/ bool& chainHasValidPins,
|
||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo)
|
||||
{
|
||||
|
@ -254,8 +257,8 @@ CheckPinsForHostname(const UniqueCERTCertList& certList, const char* hostname,
|
|||
|
||||
nsTArray<nsCString> dynamicFingerprints;
|
||||
const TransportSecurityPreload* staticFingerprints = nullptr;
|
||||
nsresult rv = FindPinningInformation(hostname, time, dynamicFingerprints,
|
||||
staticFingerprints);
|
||||
nsresult rv = FindPinningInformation(hostname, time, originAttributes,
|
||||
dynamicFingerprints, staticFingerprints);
|
||||
// If we have no pinning information, the certificate chain trivially
|
||||
// validates with respect to pinning.
|
||||
if (dynamicFingerprints.Length() == 0 && !staticFingerprints) {
|
||||
|
@ -326,12 +329,14 @@ CheckPinsForHostname(const UniqueCERTCertList& certList, const char* hostname,
|
|||
}
|
||||
|
||||
nsresult
|
||||
PublicKeyPinningService::ChainHasValidPins(const UniqueCERTCertList& certList,
|
||||
const char* hostname,
|
||||
mozilla::pkix::Time time,
|
||||
bool enforceTestMode,
|
||||
/*out*/ bool& chainHasValidPins,
|
||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo)
|
||||
PublicKeyPinningService::ChainHasValidPins(
|
||||
const UniqueCERTCertList& certList,
|
||||
const char* hostname,
|
||||
mozilla::pkix::Time time,
|
||||
bool enforceTestMode,
|
||||
const OriginAttributes& originAttributes,
|
||||
/*out*/ bool& chainHasValidPins,
|
||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo)
|
||||
{
|
||||
chainHasValidPins = false;
|
||||
if (!certList) {
|
||||
|
@ -342,14 +347,15 @@ PublicKeyPinningService::ChainHasValidPins(const UniqueCERTCertList& certList,
|
|||
}
|
||||
nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
|
||||
return CheckPinsForHostname(certList, canonicalizedHostname.get(),
|
||||
enforceTestMode, time, chainHasValidPins,
|
||||
pinningTelemetryInfo);
|
||||
enforceTestMode, time, originAttributes,
|
||||
chainHasValidPins, pinningTelemetryInfo);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PublicKeyPinningService::HostHasPins(const char* hostname,
|
||||
mozilla::pkix::Time time,
|
||||
bool enforceTestMode,
|
||||
const OriginAttributes& originAttributes,
|
||||
/*out*/ bool& hostHasPins)
|
||||
{
|
||||
hostHasPins = false;
|
||||
|
@ -357,7 +363,8 @@ PublicKeyPinningService::HostHasPins(const char* hostname,
|
|||
nsTArray<nsCString> dynamicFingerprints;
|
||||
const TransportSecurityPreload* staticFingerprints = nullptr;
|
||||
nsresult rv = FindPinningInformation(canonicalizedHostname.get(), time,
|
||||
dynamicFingerprints, staticFingerprints);
|
||||
originAttributes, dynamicFingerprints,
|
||||
staticFingerprints);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
#include "nsTArray.h"
|
||||
#include "pkix/Time.h"
|
||||
|
||||
namespace mozilla {
|
||||
class OriginAttributes;
|
||||
}
|
||||
|
||||
using mozilla::OriginAttributes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace psm {
|
||||
|
||||
|
@ -31,6 +37,7 @@ public:
|
|||
const char* hostname,
|
||||
mozilla::pkix::Time time,
|
||||
bool enforceTestMode,
|
||||
const OriginAttributes& originAttributes,
|
||||
/*out*/ bool& chainHasValidPins,
|
||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo);
|
||||
/**
|
||||
|
@ -50,6 +57,7 @@ public:
|
|||
static nsresult HostHasPins(const char* hostname,
|
||||
mozilla::pkix::Time time,
|
||||
bool enforceTestMode,
|
||||
const OriginAttributes& originAttributes,
|
||||
/*out*/ bool& hostHasPins);
|
||||
|
||||
/**
|
||||
|
|
|
@ -524,6 +524,7 @@ CertErrorRunnable::CheckCertOverrides()
|
|||
nsrv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
|
||||
uri,
|
||||
mProviderFlags,
|
||||
mInfoObject->GetOriginAttributes(),
|
||||
nullptr,
|
||||
&strictTransportSecurityEnabled);
|
||||
if (NS_FAILED(nsrv)) {
|
||||
|
@ -535,6 +536,7 @@ CertErrorRunnable::CheckCertOverrides()
|
|||
nsrv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP,
|
||||
uri,
|
||||
mProviderFlags,
|
||||
mInfoObject->GetOriginAttributes(),
|
||||
nullptr,
|
||||
&hasPinningInformation);
|
||||
if (NS_FAILED(nsrv)) {
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace mozilla
|
|||
%}
|
||||
[ref] native nsCStringTArrayRef(nsTArray<nsCString>);
|
||||
[ref] native mozillaPkixTime(mozilla::pkix::Time);
|
||||
[ref] native const_OriginAttributesRef(const mozilla::OriginAttributes);
|
||||
|
||||
// [infallible] attributes are only allowed on [builtinclass]
|
||||
[scriptable, uuid(31313372-842c-4110-bdf1-6aea17c845ad), builtinclass]
|
||||
|
@ -33,6 +34,9 @@ interface nsISiteSecurityState : nsISupports
|
|||
[infallible] readonly attribute short securityPropertyState;
|
||||
[infallible] readonly attribute boolean includeSubdomains;
|
||||
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval originAttributes;
|
||||
|
||||
/*
|
||||
* SECURITY_PROPERTY_SET and SECURITY_PROPERTY_UNSET correspond to indicating
|
||||
* a site has or does not have the security property in question,
|
||||
|
@ -103,6 +107,11 @@ interface nsISiteSecurityService : nsISupports
|
|||
* @param aSSLStatus the SSLStatus of the current channel.
|
||||
* @param aFlags options for this request as defined in nsISocketProvider:
|
||||
* NO_PERMANENT_STORAGE
|
||||
* @param aOriginAttributes the origin attributes that isolate this origin,
|
||||
* (note that this implementation does not isolate
|
||||
* by userContextId because of the risk of man-in-
|
||||
* the-middle attacks before trust-on-second-use
|
||||
* happens).
|
||||
* @param aMaxAge the parsed max-age directive of the header.
|
||||
* @param aIncludeSubdomains the parsed includeSubdomains directive.
|
||||
* @param aFailureResult a more specific failure result if NS_ERROR_FAILURE
|
||||
|
@ -112,11 +121,24 @@ interface nsISiteSecurityService : nsISupports
|
|||
* NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
|
||||
* if there are unrecognized tokens in the header.
|
||||
*/
|
||||
[binaryname(ProcessHeader), noscript]
|
||||
void processHeaderNative(in uint32_t aType,
|
||||
in nsIURI aSourceURI,
|
||||
in ACString aHeader,
|
||||
in nsISSLStatus aSSLStatus,
|
||||
in uint32_t aFlags,
|
||||
in const_OriginAttributesRef aOriginAttributes,
|
||||
[optional] out unsigned long long aMaxAge,
|
||||
[optional] out boolean aIncludeSubdomains,
|
||||
[optional] out uint32_t aFailureResult);
|
||||
|
||||
[binaryname(ProcessHeaderScriptable), implicit_jscontext, optional_argc]
|
||||
void processHeader(in uint32_t aType,
|
||||
in nsIURI aSourceURI,
|
||||
in ACString aHeader,
|
||||
in nsISSLStatus aSSLStatus,
|
||||
in uint32_t aFlags,
|
||||
[optional] in jsval aOriginAttributes,
|
||||
[optional] out unsigned long long aMaxAge,
|
||||
[optional] out boolean aIncludeSubdomains,
|
||||
[optional] out uint32_t aFailureResult);
|
||||
|
@ -130,10 +152,17 @@ interface nsISiteSecurityService : nsISupports
|
|||
* @param aURI the URI of the target host
|
||||
* @param aFlags options for this request as defined in nsISocketProvider:
|
||||
* NO_PERMANENT_STORAGE
|
||||
* @param aOriginAttributes the origin attributes that isolate this origin,
|
||||
* (note that this implementation does not isolate
|
||||
* by userContextId because of the risk of man-in-
|
||||
* the-middle attacks before trust-on-second-use
|
||||
* happens).
|
||||
*/
|
||||
[implicit_jscontext, optional_argc]
|
||||
void removeState(in uint32_t aType,
|
||||
in nsIURI aURI,
|
||||
in uint32_t aFlags);
|
||||
in uint32_t aFlags,
|
||||
[optional] in jsval aOriginAttributes);
|
||||
|
||||
/**
|
||||
* Checks whether or not the URI's hostname has a given security state set.
|
||||
|
@ -148,10 +177,23 @@ interface nsISiteSecurityService : nsISupports
|
|||
* @param aURI the URI to query for STS state.
|
||||
* @param aFlags options for this request as defined in nsISocketProvider:
|
||||
* NO_PERMANENT_STORAGE
|
||||
* @param aOriginAttributes the origin attributes that isolate this origin,
|
||||
* (note that this implementation does not isolate
|
||||
* by userContextId because of the risk of man-in-
|
||||
* the-middle attacks before trust-on-second-use
|
||||
* happens).
|
||||
* @param aCached true if we have cached information regarding whether or not
|
||||
* the host is HSTS, false otherwise.
|
||||
*/
|
||||
[binaryname(IsSecureURI), noscript]
|
||||
boolean isSecureURINative(in uint32_t aType, in nsIURI aURI,
|
||||
in uint32_t aFlags,
|
||||
in const_OriginAttributesRef aOriginAttributes,
|
||||
[optional] out boolean aCached);
|
||||
|
||||
[binaryname(IsSecureURIScriptable), implicit_jscontext, optional_argc]
|
||||
boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags,
|
||||
[optional] in jsval aOriginAttributes,
|
||||
[optional] out boolean aCached);
|
||||
|
||||
/**
|
||||
|
@ -174,14 +216,21 @@ interface nsISiteSecurityService : nsISupports
|
|||
* @param aHostname the hostname (punycode) to be queried about
|
||||
* @param evalTime the time at which the pins should be valid. This is in
|
||||
mozilla::pkix::Time which uses internally seconds since 0 AD.
|
||||
* @param aOriginAttributes the origin attributes that isolate this origin,
|
||||
* (note that this implementation does not isolate
|
||||
* by userContextId because of the risk of man-in-
|
||||
* the-middle attacks before trust-on-second-use
|
||||
* happens).
|
||||
* @param aPinArray the set of sha256-hashed key pins for the given domain
|
||||
* @param aIncludeSubdomains true if the pins apply to subdomains of the
|
||||
* given domain
|
||||
*/
|
||||
[noscript] boolean getKeyPinsForHostname(in ACString aHostname,
|
||||
in mozillaPkixTime evalTime,
|
||||
out nsCStringTArrayRef aPinArray,
|
||||
out boolean aIncludeSubdomains);
|
||||
[noscript] boolean getKeyPinsForHostname(
|
||||
in ACString aHostname,
|
||||
in mozillaPkixTime evalTime,
|
||||
in const_OriginAttributesRef aOriginAttributes,
|
||||
out nsCStringTArrayRef aPinArray,
|
||||
out boolean aIncludeSubdomains);
|
||||
|
||||
/**
|
||||
* Set public-key pins for a host. The resulting pins will be permanent
|
||||
|
@ -195,11 +244,18 @@ interface nsISiteSecurityService : nsISupports
|
|||
* @param aSha256Pins array of hashed key fingerprints (SHA-256, base64)
|
||||
* @param aIsPreload are these key pins for a preload entry? (false by
|
||||
* default)
|
||||
* @param aOriginAttributes the origin attributes that isolate this origin,
|
||||
* (note that this implementation does not isolate
|
||||
* by userContextId because of the risk of man-in-
|
||||
* the-middle attacks before trust-on-second-use
|
||||
* happens).
|
||||
*/
|
||||
boolean setKeyPins(in ACString aHost, in boolean aIncludeSubdomains,
|
||||
in int64_t aExpires, in unsigned long aPinCount,
|
||||
[array, size_is(aPinCount)] in string aSha256Pins,
|
||||
[optional] in boolean aIsPreload);
|
||||
[implicit_jscontext, optional_argc]
|
||||
boolean setKeyPins(in ACString aHost, in boolean aIncludeSubdomains,
|
||||
in int64_t aExpires, in unsigned long aPinCount,
|
||||
[array, size_is(aPinCount)] in string aSha256Pins,
|
||||
[optional] in boolean aIsPreload,
|
||||
[optional] in jsval aOriginAttributes);
|
||||
|
||||
/**
|
||||
* Set an HSTS preload entry for a host. The resulting entries will be
|
||||
|
@ -211,8 +267,9 @@ interface nsISiteSecurityService : nsISupports
|
|||
* @param aIncludeSubdomains whether this entry also applies to subdomains
|
||||
* @param aExpires the time this entry should expire (millis since epoch)
|
||||
*/
|
||||
boolean setHSTSPreload(in ACString aHost, in boolean aIncludesSubdomains,
|
||||
in int64_t aExpires);
|
||||
boolean setHSTSPreload(in ACString aHost,
|
||||
in boolean aIncludesSubdomains,
|
||||
in int64_t aExpires);
|
||||
|
||||
/**
|
||||
* Mark a host as declining to provide a given security state so that features
|
||||
|
@ -220,8 +277,15 @@ interface nsISiteSecurityService : nsISupports
|
|||
*
|
||||
* @param aURI the nsIURI that this applies to
|
||||
* @param aMaxAge lifetime (in seconds) of this negative cache
|
||||
* @param aOriginAttributes the origin attributes that isolate this origin,
|
||||
* (note that this implementation does not isolate
|
||||
* by userContextId because of the risk of man-in-
|
||||
* the-middle attacks before trust-on-second-use
|
||||
* happens).
|
||||
*/
|
||||
[noscript] void cacheNegativeHSTSResult(in nsIURI aURI, in unsigned long long aMaxAge);
|
||||
[noscript] void cacheNegativeHSTSResult(
|
||||
in nsIURI aURI, in unsigned long long aMaxAge,
|
||||
in const_OriginAttributesRef aOriginAttributes);
|
||||
|
||||
/**
|
||||
* Returns an enumerator of the nsISiteSecurityService storage. Each item in
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include "nsCOMArray.h"
|
||||
#include "nsCRTGlue.h"
|
||||
#include "nsISSLStatus.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsISocketProvider.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIX509Cert.h"
|
||||
|
@ -58,8 +60,10 @@ const char kHPKPKeySuffix[] = ":HPKP";
|
|||
NS_IMPL_ISUPPORTS(SiteHSTSState, nsISiteSecurityState, nsISiteHSTSState)
|
||||
|
||||
SiteHSTSState::SiteHSTSState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
const nsCString& aStateString)
|
||||
: mHostname(aHost)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
, mHSTSExpireTime(0)
|
||||
, mHSTSState(SecurityPropertyUnset)
|
||||
, mHSTSIncludeSubdomains(false)
|
||||
|
@ -87,11 +91,13 @@ SiteHSTSState::SiteHSTSState(const nsCString& aHost,
|
|||
}
|
||||
|
||||
SiteHSTSState::SiteHSTSState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
PRTime aHSTSExpireTime,
|
||||
SecurityPropertyState aHSTSState,
|
||||
bool aHSTSIncludeSubdomains)
|
||||
|
||||
: mHostname(aHost)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
, mHSTSExpireTime(aHSTSExpireTime)
|
||||
, mHSTSState(aHSTSState)
|
||||
, mHSTSIncludeSubdomains(aHSTSIncludeSubdomains)
|
||||
|
@ -140,6 +146,16 @@ SiteHSTSState::GetIncludeSubdomains(bool* aIncludeSubdomains)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SiteHSTSState::GetOriginAttributes(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
if (!ToJSValue(aCx, mOriginAttributes, aOriginAttributes)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMPL_ISUPPORTS(SiteHPKPState, nsISiteSecurityState, nsISiteHPKPState)
|
||||
|
@ -165,8 +181,10 @@ SiteHPKPState::SiteHPKPState()
|
|||
}
|
||||
|
||||
SiteHPKPState::SiteHPKPState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
const nsCString& aStateString)
|
||||
: mHostname(aHost)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
, mExpireTime(0)
|
||||
, mState(SecurityPropertyUnset)
|
||||
, mIncludeSubdomains(false)
|
||||
|
@ -228,11 +246,13 @@ SiteHPKPState::SiteHPKPState(const nsCString& aHost,
|
|||
}
|
||||
|
||||
SiteHPKPState::SiteHPKPState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
PRTime aExpireTime,
|
||||
SecurityPropertyState aState,
|
||||
bool aIncludeSubdomains,
|
||||
nsTArray<nsCString>& aSHA256keys)
|
||||
: mHostname(aHost)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
, mExpireTime(aExpireTime)
|
||||
, mState(aState)
|
||||
, mIncludeSubdomains(aIncludeSubdomains)
|
||||
|
@ -305,6 +325,16 @@ SiteHPKPState::GetSha256Keys(nsISimpleEnumerator** aSha256Keys)
|
|||
return NS_NewArrayEnumerator(aSha256Keys, keys);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SiteHPKPState::GetOriginAttributes(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
if (!ToJSValue(aCx, mOriginAttributes, aOriginAttributes)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60;
|
||||
|
@ -396,9 +426,19 @@ nsSiteSecurityService::GetHost(nsIURI* aURI, nsACString& aResult)
|
|||
}
|
||||
|
||||
static void
|
||||
SetStorageKey(nsAutoCString& storageKey, const nsACString& hostname, uint32_t aType)
|
||||
SetStorageKey(const nsACString& hostname, uint32_t aType,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
/*out*/ nsAutoCString& storageKey)
|
||||
{
|
||||
storageKey = hostname;
|
||||
|
||||
// Don't isolate by userContextId.
|
||||
OriginAttributes originAttributesNoUserContext = aOriginAttributes;
|
||||
originAttributesNoUserContext.mUserContextId =
|
||||
nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID;
|
||||
nsAutoCString originAttributesSuffix;
|
||||
originAttributesNoUserContext.CreateSuffix(originAttributesSuffix);
|
||||
storageKey.Append(originAttributesSuffix);
|
||||
switch (aType) {
|
||||
case nsISiteSecurityService::HEADER_HSTS:
|
||||
storageKey.AppendASCII(kHSTSKeySuffix);
|
||||
|
@ -426,22 +466,27 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
|
|||
bool includeSubdomains,
|
||||
uint32_t flags,
|
||||
SecurityPropertyState aHSTSState,
|
||||
bool aIsPreload)
|
||||
bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
nsAutoCString hostname(aHost);
|
||||
// If max-age is zero, that's an indication to immediately remove the
|
||||
// security state, so here's a shortcut.
|
||||
if (!maxage) {
|
||||
return RemoveStateInternal(aType, hostname, flags, aIsPreload);
|
||||
return RemoveStateInternal(aType, hostname, flags, aIsPreload,
|
||||
aOriginAttributes);
|
||||
}
|
||||
|
||||
MOZ_ASSERT((aHSTSState == SecurityPropertySet ||
|
||||
aHSTSState == SecurityPropertyNegative),
|
||||
"HSTS State must be SecurityPropertySet or SecurityPropertyNegative");
|
||||
if (aIsPreload && aOriginAttributes != OriginAttributes()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
int64_t expiretime = ExpireTimeFromMaxAge(maxage);
|
||||
RefPtr<SiteHSTSState> siteState =
|
||||
new SiteHSTSState(hostname, expiretime, aHSTSState, includeSubdomains);
|
||||
RefPtr<SiteHSTSState> siteState = new SiteHSTSState(
|
||||
hostname, aOriginAttributes, expiretime, aHSTSState, includeSubdomains);
|
||||
nsAutoCString stateString;
|
||||
siteState->ToString(stateString);
|
||||
SSSLOG(("SSS: setting state for %s", hostname.get()));
|
||||
|
@ -450,7 +495,7 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
|
|||
? mozilla::DataStorage_Private
|
||||
: mozilla::DataStorage_Persistent;
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(storageKey, hostname, aType);
|
||||
SetStorageKey(hostname, aType, aOriginAttributes, storageKey);
|
||||
nsresult rv;
|
||||
if (aIsPreload) {
|
||||
SSSLOG(("SSS: storing entry for %s in dynamic preloads", hostname.get()));
|
||||
|
@ -466,20 +511,35 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::CacheNegativeHSTSResult(nsIURI* aSourceURI,
|
||||
uint64_t aMaxAge)
|
||||
nsSiteSecurityService::CacheNegativeHSTSResult(
|
||||
nsIURI* aSourceURI,
|
||||
uint64_t aMaxAge,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
nsAutoCString hostname;
|
||||
nsresult rv = GetHost(aSourceURI, hostname);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, hostname.get(),
|
||||
aMaxAge, false, 0, SecurityPropertyNegative, false);
|
||||
aMaxAge, false, 0, SecurityPropertyNegative, false,
|
||||
aOriginAttributes);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::RemoveStateInternal(uint32_t aType,
|
||||
const nsAutoCString& aHost,
|
||||
uint32_t aFlags, bool aIsPreload)
|
||||
nsSiteSecurityService::RemoveStateInternal(
|
||||
uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
nsAutoCString hostname;
|
||||
GetHost(aURI, hostname);
|
||||
return RemoveStateInternal(aType, hostname, aFlags, false, aOriginAttributes);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::RemoveStateInternal(
|
||||
uint32_t aType,
|
||||
const nsAutoCString& aHost,
|
||||
uint32_t aFlags, bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
|
@ -490,6 +550,9 @@ nsSiteSecurityService::RemoveStateInternal(uint32_t aType,
|
|||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
if (aIsPreload && aOriginAttributes != OriginAttributes()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
|
||||
mozilla::DataStorageType storageType = isPrivate
|
||||
|
@ -497,16 +560,17 @@ nsSiteSecurityService::RemoveStateInternal(uint32_t aType,
|
|||
: mozilla::DataStorage_Persistent;
|
||||
// If this host is in the preload list, we have to store a knockout entry.
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(storageKey, aHost, aType);
|
||||
SetStorageKey(aHost, aType, aOriginAttributes, storageKey);
|
||||
|
||||
nsCString value = mPreloadStateStorage->Get(storageKey,
|
||||
mozilla::DataStorage_Persistent);
|
||||
RefPtr<SiteHSTSState> dynamicState = new SiteHSTSState(aHost, value);
|
||||
RefPtr<SiteHSTSState> dynamicState =
|
||||
new SiteHSTSState(aHost, aOriginAttributes, value);
|
||||
if (GetPreloadListEntry(aHost.get()) ||
|
||||
dynamicState->mHSTSState != SecurityPropertyUnset) {
|
||||
SSSLOG(("SSS: storing knockout entry for %s", aHost.get()));
|
||||
RefPtr<SiteHSTSState> siteState =
|
||||
new SiteHSTSState(aHost, 0, SecurityPropertyKnockout, false);
|
||||
RefPtr<SiteHSTSState> siteState = new SiteHSTSState(
|
||||
aHost, aOriginAttributes, 0, SecurityPropertyKnockout, false);
|
||||
nsAutoCString stateString;
|
||||
siteState->ToString(stateString);
|
||||
nsresult rv;
|
||||
|
@ -531,11 +595,19 @@ nsSiteSecurityService::RemoveStateInternal(uint32_t aType,
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
|
||||
uint32_t aFlags)
|
||||
uint32_t aFlags,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
JSContext* aCx, uint8_t aArgc)
|
||||
{
|
||||
nsAutoCString hostname;
|
||||
GetHost(aURI, hostname);
|
||||
return RemoveStateInternal(aType, hostname, aFlags, false);
|
||||
OriginAttributes originAttributes;
|
||||
if (aArgc > 0) {
|
||||
// OriginAttributes were passed in.
|
||||
if (!aOriginAttributes.isObject() ||
|
||||
!originAttributes.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
return RemoveStateInternal(aType, aURI, aFlags, originAttributes);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -546,12 +618,39 @@ HostIsIPAddress(const nsCString& hostname)
|
|||
return (prv == PR_SUCCESS);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::ProcessHeaderScriptable(
|
||||
uint32_t aType,
|
||||
nsIURI* aSourceURI,
|
||||
const nsACString& aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult,
|
||||
JSContext* aCx,
|
||||
uint8_t aArgc)
|
||||
{
|
||||
OriginAttributes originAttributes;
|
||||
if (aArgc > 0) {
|
||||
if (!aOriginAttributes.isObject() ||
|
||||
!originAttributes.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
return ProcessHeader(aType, aSourceURI, aHeader, aSSLStatus, aFlags,
|
||||
originAttributes, aMaxAge, aIncludeSubdomains,
|
||||
aFailureResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::ProcessHeader(uint32_t aType,
|
||||
nsIURI* aSourceURI,
|
||||
const nsACString& aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
|
@ -571,19 +670,21 @@ nsSiteSecurityService::ProcessHeader(uint32_t aType,
|
|||
|
||||
NS_ENSURE_ARG(aSSLStatus);
|
||||
return ProcessHeaderInternal(aType, aSourceURI, PromiseFlatCString(aHeader),
|
||||
aSSLStatus, aFlags, aMaxAge, aIncludeSubdomains,
|
||||
aFailureResult);
|
||||
aSSLStatus, aFlags, aOriginAttributes, aMaxAge,
|
||||
aIncludeSubdomains, aFailureResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
||||
nsIURI* aSourceURI,
|
||||
const nsCString& aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
nsSiteSecurityService::ProcessHeaderInternal(
|
||||
uint32_t aType,
|
||||
nsIURI* aSourceURI,
|
||||
const nsCString& aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
|
@ -635,12 +736,13 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
|
|||
|
||||
switch (aType) {
|
||||
case nsISiteSecurityService::HEADER_HSTS:
|
||||
rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aMaxAge,
|
||||
rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aOriginAttributes, aMaxAge,
|
||||
aIncludeSubdomains, aFailureResult);
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags, aMaxAge,
|
||||
aIncludeSubdomains, aFailureResult);
|
||||
rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags,
|
||||
aOriginAttributes, aMaxAge, aIncludeSubdomains,
|
||||
aFailureResult);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected header type");
|
||||
|
@ -790,13 +892,15 @@ ParseSSSHeaders(uint32_t aType,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
const nsCString& aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
nsSiteSecurityService::ProcessPKPHeader(
|
||||
nsIURI* aSourceURI,
|
||||
const nsCString& aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
|
@ -863,7 +967,8 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
|||
host.get(), // hostname
|
||||
certList,
|
||||
false, // don't store intermediates
|
||||
flags)
|
||||
flags,
|
||||
aOriginAttributes)
|
||||
!= mozilla::pkix::Success) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -887,7 +992,7 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
|||
|
||||
// if maxAge == 0 we must delete all state, for now no hole-punching
|
||||
if (maxAge == 0) {
|
||||
return RemoveState(aType, aSourceURI, aFlags);
|
||||
return RemoveStateInternal(aType, aSourceURI, aFlags, aOriginAttributes);
|
||||
}
|
||||
|
||||
// clamp maxAge to the maximum set by pref
|
||||
|
@ -937,12 +1042,12 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
|||
|
||||
int64_t expireTime = ExpireTimeFromMaxAge(maxAge);
|
||||
RefPtr<SiteHPKPState> dynamicEntry =
|
||||
new SiteHPKPState(host, expireTime, SecurityPropertySet,
|
||||
new SiteHPKPState(host, aOriginAttributes, expireTime, SecurityPropertySet,
|
||||
foundIncludeSubdomains, sha256keys);
|
||||
SSSLOG(("SSS: about to set pins for %s, expires=%" PRId64 " now=%" PRId64 " maxAge=%" PRIu64 "\n",
|
||||
host.get(), expireTime, PR_Now() / PR_USEC_PER_MSEC, maxAge));
|
||||
|
||||
rv = SetHPKPState(host.get(), *dynamicEntry, aFlags, false);
|
||||
rv = SetHPKPState(host.get(), *dynamicEntry, aFlags, false, aOriginAttributes);
|
||||
if (NS_FAILED(rv)) {
|
||||
SSSLOG(("SSS: failed to set pins for %s\n", host.get()));
|
||||
if (aFailureResult) {
|
||||
|
@ -965,12 +1070,14 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
|
||||
const nsCString& aHeader,
|
||||
uint32_t aFlags,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
nsSiteSecurityService::ProcessSTSHeader(
|
||||
nsIURI* aSourceURI,
|
||||
const nsCString& aHeader,
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult)
|
||||
{
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
|
@ -1010,7 +1117,7 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
|
|||
|
||||
// record the successfully parsed header data.
|
||||
rv = SetHSTSState(aType, hostname.get(), maxAge, foundIncludeSubdomains,
|
||||
aFlags, SecurityPropertySet, false);
|
||||
aFlags, SecurityPropertySet, false, aOriginAttributes);
|
||||
if (NS_FAILED(rv)) {
|
||||
SSSLOG(("SSS: failed to set STS state"));
|
||||
if (aFailureResult) {
|
||||
|
@ -1032,10 +1139,28 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
|
|||
: NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::IsSecureURIScriptable(uint32_t aType, nsIURI* aURI,
|
||||
uint32_t aFlags,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
bool* aCached, JSContext* aCx,
|
||||
uint8_t aArgc, bool* aResult)
|
||||
{
|
||||
OriginAttributes originAttributes;
|
||||
if (aArgc > 0) {
|
||||
if (!aOriginAttributes.isObject() ||
|
||||
!originAttributes.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
return IsSecureURI(aType, aURI, aFlags, originAttributes, aCached, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
|
||||
uint32_t aFlags, bool* aCached,
|
||||
bool* aResult)
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
bool* aCached, bool* aResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
|
||||
|
@ -1059,7 +1184,8 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
return IsSecureHost(aType, hostname, aFlags, aCached, aResult);
|
||||
return IsSecureHost(aType, hostname, aFlags, aOriginAttributes, aCached,
|
||||
aResult);
|
||||
}
|
||||
|
||||
int STSPreloadCompare(const void *key, const void *entry)
|
||||
|
@ -1094,10 +1220,9 @@ nsSiteSecurityService::GetPreloadListEntry(const char *aHost)
|
|||
// aRequireIncludeSubdomains specifies whether we require includeSubdomains
|
||||
// to be set on the entry (with the other parameters being as per IsSecureHost).
|
||||
bool
|
||||
nsSiteSecurityService::HostHasHSTSEntry(const nsAutoCString& aHost,
|
||||
bool aRequireIncludeSubdomains,
|
||||
uint32_t aFlags, bool* aResult,
|
||||
bool* aCached)
|
||||
nsSiteSecurityService::HostHasHSTSEntry(
|
||||
const nsAutoCString& aHost, bool aRequireIncludeSubdomains, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes, bool* aResult, bool* aCached)
|
||||
{
|
||||
// First we check for an entry in site security storage. If that entry exists,
|
||||
// we don't want to check in the preload lists. We only want to use the
|
||||
|
@ -1111,9 +1236,14 @@ nsSiteSecurityService::HostHasHSTSEntry(const nsAutoCString& aHost,
|
|||
: mozilla::DataStorage_Persistent;
|
||||
nsAutoCString storageKey;
|
||||
SSSLOG(("Seeking HSTS entry for %s", aHost.get()));
|
||||
SetStorageKey(storageKey, aHost, nsISiteSecurityService::HEADER_HSTS);
|
||||
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, value);
|
||||
RefPtr<SiteHSTSState> siteState =
|
||||
new SiteHSTSState(aHost, aOriginAttributes, value);
|
||||
if (siteState->mHSTSState != SecurityPropertyUnset) {
|
||||
SSSLOG(("Found HSTS entry for %s", aHost.get()));
|
||||
bool expired = siteState->IsExpired(nsISiteSecurityService::HEADER_HSTS);
|
||||
|
@ -1137,9 +1267,10 @@ nsSiteSecurityService::HostHasHSTSEntry(const nsAutoCString& aHost,
|
|||
// If the entry is expired and is not in either the static or dynamic
|
||||
// preload lists, we can remove it.
|
||||
// First, check the dynamic preload list.
|
||||
value = mPreloadStateStorage->Get(storageKey,
|
||||
value = mPreloadStateStorage->Get(preloadKey,
|
||||
mozilla::DataStorage_Persistent);
|
||||
RefPtr<SiteHSTSState> dynamicState = new SiteHSTSState(aHost, value);
|
||||
RefPtr<SiteHSTSState> dynamicState =
|
||||
new SiteHSTSState(aHost, aOriginAttributes, value);
|
||||
if (dynamicState->mHSTSState == SecurityPropertyUnset) {
|
||||
SSSLOG(("No dynamic preload - checking for static preload"));
|
||||
// Now check the static preload list.
|
||||
|
@ -1153,9 +1284,10 @@ nsSiteSecurityService::HostHasHSTSEntry(const nsAutoCString& aHost,
|
|||
}
|
||||
|
||||
// Next, look in the dynamic preload list.
|
||||
value = mPreloadStateStorage->Get(storageKey,
|
||||
value = mPreloadStateStorage->Get(preloadKey,
|
||||
mozilla::DataStorage_Persistent);
|
||||
RefPtr<SiteHSTSState> dynamicState = new SiteHSTSState(aHost, value);
|
||||
RefPtr<SiteHSTSState> dynamicState =
|
||||
new SiteHSTSState(aHost, aOriginAttributes, value);
|
||||
if (dynamicState->mHSTSState != SecurityPropertyUnset) {
|
||||
SSSLOG(("Found dynamic preload entry for %s", aHost.get()));
|
||||
bool expired = dynamicState->IsExpired(nsISiteSecurityService::HEADER_HSTS);
|
||||
|
@ -1172,7 +1304,7 @@ nsSiteSecurityService::HostHasHSTSEntry(const nsAutoCString& aHost,
|
|||
// if a dynamic preload has expired and is not in the static preload
|
||||
// list, we can remove it.
|
||||
if (!GetPreloadListEntry(aHost.get())) {
|
||||
mPreloadStateStorage->Remove(storageKey,
|
||||
mPreloadStateStorage->Remove(preloadKey,
|
||||
mozilla::DataStorage_Persistent);
|
||||
}
|
||||
}
|
||||
|
@ -1199,8 +1331,9 @@ nsSiteSecurityService::HostHasHSTSEntry(const nsAutoCString& aHost,
|
|||
|
||||
nsresult
|
||||
nsSiteSecurityService::IsSecureHost(uint32_t aType, const nsACString& aHost,
|
||||
uint32_t aFlags, bool* aCached,
|
||||
bool* aResult)
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
bool* aCached, bool* aResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
|
||||
|
@ -1240,7 +1373,8 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const nsACString& aHost,
|
|||
CertVerifier::PinningMode::pinningEnforceTestMode;
|
||||
return PublicKeyPinningService::HostHasPins(flatHost.get(),
|
||||
mozilla::pkix::Now(),
|
||||
enforceTestMode, *aResult);
|
||||
enforceTestMode, aOriginAttributes,
|
||||
*aResult);
|
||||
}
|
||||
|
||||
// Holepunch chart.apis.google.com and subdomains.
|
||||
|
@ -1255,7 +1389,7 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const nsACString& aHost,
|
|||
}
|
||||
|
||||
// First check the exact host.
|
||||
if (HostHasHSTSEntry(host, false, aFlags, aResult, aCached)) {
|
||||
if (HostHasHSTSEntry(host, false, aFlags, aOriginAttributes, aResult, aCached)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1280,7 +1414,8 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const nsACString& aHost,
|
|||
// that the entry includes subdomains.
|
||||
nsAutoCString subdomainString(subdomain);
|
||||
|
||||
if (HostHasHSTSEntry(subdomainString, true, aFlags, aResult, aCached)) {
|
||||
if (HostHasHSTSEntry(subdomainString, true, aFlags, aOriginAttributes, aResult,
|
||||
aCached)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1319,11 +1454,13 @@ bool entryStateNotOK(SiteHPKPState& state, mozilla::pkix::Time& aEvalTime) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::GetKeyPinsForHostname(const nsACString& aHostname,
|
||||
mozilla::pkix::Time& aEvalTime,
|
||||
/*out*/ nsTArray<nsCString>& pinArray,
|
||||
/*out*/ bool* aIncludeSubdomains,
|
||||
/*out*/ bool* afound)
|
||||
nsSiteSecurityService::GetKeyPinsForHostname(
|
||||
const nsACString& aHostname,
|
||||
mozilla::pkix::Time& aEvalTime,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
/*out*/ nsTArray<nsCString>& pinArray,
|
||||
/*out*/ bool* aIncludeSubdomains,
|
||||
/*out*/ bool* afound)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
|
@ -1342,23 +1479,30 @@ nsSiteSecurityService::GetKeyPinsForHostname(const nsACString& aHostname,
|
|||
nsAutoCString host(
|
||||
PublicKeyPinningService::CanonicalizeHostname(flatHostname.get()));
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
|
||||
SetStorageKey(host, nsISiteSecurityService::HEADER_HPKP, aOriginAttributes,
|
||||
storageKey);
|
||||
|
||||
SSSLOG(("storagekey '%s'\n", storageKey.get()));
|
||||
mozilla::DataStorageType storageType = mozilla::DataStorage_Persistent;
|
||||
nsCString value = mSiteStateStorage->Get(storageKey, storageType);
|
||||
|
||||
// decode now
|
||||
RefPtr<SiteHPKPState> foundEntry = new SiteHPKPState(host, value);
|
||||
RefPtr<SiteHPKPState> foundEntry =
|
||||
new SiteHPKPState(host, aOriginAttributes, value);
|
||||
if (entryStateNotOK(*foundEntry, aEvalTime)) {
|
||||
// not in permanent storage, try now private
|
||||
value = mSiteStateStorage->Get(storageKey, mozilla::DataStorage_Private);
|
||||
RefPtr<SiteHPKPState> privateEntry = new SiteHPKPState(host, value);
|
||||
RefPtr<SiteHPKPState> privateEntry =
|
||||
new SiteHPKPState(host, aOriginAttributes, value);
|
||||
if (entryStateNotOK(*privateEntry, aEvalTime)) {
|
||||
// not in private storage, try dynamic preload
|
||||
value = mPreloadStateStorage->Get(storageKey,
|
||||
nsAutoCString preloadKey;
|
||||
SetStorageKey(host, nsISiteSecurityService::HEADER_HPKP,
|
||||
OriginAttributes(), preloadKey);
|
||||
value = mPreloadStateStorage->Get(preloadKey,
|
||||
mozilla::DataStorage_Persistent);
|
||||
RefPtr<SiteHPKPState> preloadEntry = new SiteHPKPState(host, value);
|
||||
RefPtr<SiteHPKPState> preloadEntry =
|
||||
new SiteHPKPState(host, aOriginAttributes, value);
|
||||
if (entryStateNotOK(*preloadEntry, aEvalTime)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1379,6 +1523,9 @@ nsSiteSecurityService::SetKeyPins(const nsACString& aHost,
|
|||
int64_t aExpires, uint32_t aPinCount,
|
||||
const char** aSha256Pins,
|
||||
bool aIsPreload,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
JSContext* aCx,
|
||||
uint8_t aArgc,
|
||||
/*out*/ bool* aResult)
|
||||
{
|
||||
// Child processes are not allowed direct access to this.
|
||||
|
@ -1389,6 +1536,17 @@ nsSiteSecurityService::SetKeyPins(const nsACString& aHost,
|
|||
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
NS_ENSURE_ARG_POINTER(aSha256Pins);
|
||||
OriginAttributes originAttributes;
|
||||
if (aArgc > 1) {
|
||||
// OriginAttributes were passed in.
|
||||
if (!aOriginAttributes.isObject() ||
|
||||
!originAttributes.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
if (aIsPreload && originAttributes != OriginAttributes()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
SSSLOG(("Top of SetKeyPins"));
|
||||
|
||||
|
@ -1405,10 +1563,9 @@ nsSiteSecurityService::SetKeyPins(const nsACString& aHost,
|
|||
const nsCString& flatHost = PromiseFlatCString(aHost);
|
||||
nsAutoCString host(
|
||||
PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
|
||||
RefPtr<SiteHPKPState> dynamicEntry =
|
||||
new SiteHPKPState(host, aExpires, SecurityPropertySet, aIncludeSubdomains,
|
||||
sha256keys);
|
||||
return SetHPKPState(host.get(), *dynamicEntry, 0, aIsPreload);
|
||||
RefPtr<SiteHPKPState> dynamicEntry = new SiteHPKPState(host, originAttributes,
|
||||
aExpires, SecurityPropertySet, aIncludeSubdomains, sha256keys);
|
||||
return SetHPKPState(host.get(), *dynamicEntry, 0, aIsPreload, originAttributes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1431,17 +1588,23 @@ nsSiteSecurityService::SetHSTSPreload(const nsACString& aHost,
|
|||
nsAutoCString host(
|
||||
PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
|
||||
return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, host.get(), aExpires,
|
||||
aIncludeSubdomains, 0, SecurityPropertySet, true);
|
||||
aIncludeSubdomains, 0, SecurityPropertySet, true,
|
||||
OriginAttributes());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::SetHPKPState(const char* aHost, SiteHPKPState& entry,
|
||||
uint32_t aFlags, bool aIsPreload)
|
||||
uint32_t aFlags, bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
if (aIsPreload && aOriginAttributes != OriginAttributes()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
SSSLOG(("Top of SetPKPState"));
|
||||
nsAutoCString host(aHost);
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
|
||||
SetStorageKey(host, nsISiteSecurityService::HEADER_HPKP, aOriginAttributes,
|
||||
storageKey);
|
||||
bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
|
||||
mozilla::DataStorageType storageType = isPrivate
|
||||
? mozilla::DataStorage_Private
|
||||
|
@ -1488,15 +1651,21 @@ nsSiteSecurityService::Enumerate(uint32_t aType,
|
|||
continue;
|
||||
}
|
||||
|
||||
nsCString hostname(
|
||||
nsCString origin(
|
||||
StringHead(item.key(), item.key().Length() - keySuffix.Length()));
|
||||
nsAutoCString hostname;
|
||||
OriginAttributes originAttributes;
|
||||
if (!originAttributes.PopulateFromOrigin(origin, hostname)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISiteSecurityState> state;
|
||||
switch(aType) {
|
||||
case nsISiteSecurityService::HEADER_HSTS:
|
||||
state = new SiteHSTSState(hostname, item.value());
|
||||
state = new SiteHSTSState(hostname, originAttributes, item.value());
|
||||
break;
|
||||
case nsISiteSecurityService::HEADER_HPKP:
|
||||
state = new SiteHPKPState(hostname, item.value());
|
||||
state = new SiteHPKPState(hostname, originAttributes, item.value());
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("SSS:Enumerate got invalid type");
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef __nsSiteSecurityService_h__
|
||||
#define __nsSiteSecurityService_h__
|
||||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/DataStorage.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -18,6 +19,8 @@
|
|||
class nsIURI;
|
||||
class nsISSLStatus;
|
||||
|
||||
using mozilla::OriginAttributes;
|
||||
|
||||
// {16955eee-6c48-4152-9309-c42a465138a1}
|
||||
#define NS_SITE_SECURITY_SERVICE_CID \
|
||||
{0x16955eee, 0x6c48, 0x4152, \
|
||||
|
@ -44,6 +47,7 @@ enum SecurityPropertyState {
|
|||
* the public key pins of a site.
|
||||
* HPKP state consists of:
|
||||
* - Hostname (nsCString)
|
||||
* - Origin attributes (OriginAttributes)
|
||||
* - Expiry time (PRTime (aka int64_t) in milliseconds)
|
||||
* - A state flag (SecurityPropertyState, default SecurityPropertyUnset)
|
||||
* - An include subdomains flag (bool, default false)
|
||||
|
@ -57,12 +61,16 @@ public:
|
|||
NS_DECL_NSISITESECURITYSTATE
|
||||
|
||||
SiteHPKPState();
|
||||
SiteHPKPState(const nsCString& aHost, const nsCString& aStateString);
|
||||
SiteHPKPState(const nsCString& aHost, PRTime aExpireTime,
|
||||
SecurityPropertyState aState, bool aIncludeSubdomains,
|
||||
nsTArray<nsCString>& SHA256keys);
|
||||
SiteHPKPState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
const nsCString& aStateString);
|
||||
SiteHPKPState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
PRTime aExpireTime, SecurityPropertyState aState,
|
||||
bool aIncludeSubdomains, nsTArray<nsCString>& SHA256keys);
|
||||
|
||||
nsCString mHostname;
|
||||
OriginAttributes mOriginAttributes;
|
||||
PRTime mExpireTime;
|
||||
SecurityPropertyState mState;
|
||||
bool mIncludeSubdomains;
|
||||
|
@ -88,6 +96,7 @@ protected:
|
|||
* the security state of a site. Currently only handles HSTS.
|
||||
* HSTS state consists of:
|
||||
* - Hostname (nsCString)
|
||||
* - Origin attributes (OriginAttributes)
|
||||
* - Expiry time (PRTime (aka int64_t) in milliseconds)
|
||||
* - A state flag (SecurityPropertyState, default SecurityPropertyUnset)
|
||||
* - An include subdomains flag (bool, default false)
|
||||
|
@ -99,11 +108,16 @@ public:
|
|||
NS_DECL_NSISITEHSTSSTATE
|
||||
NS_DECL_NSISITESECURITYSTATE
|
||||
|
||||
SiteHSTSState(const nsCString& aHost, const nsCString& aStateString);
|
||||
SiteHSTSState(const nsCString& aHost, PRTime aHSTSExpireTime,
|
||||
SecurityPropertyState aHSTSState, bool aHSTSIncludeSubdomains);
|
||||
SiteHSTSState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
const nsCString& aStateString);
|
||||
SiteHSTSState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
PRTime aHSTSExpireTime, SecurityPropertyState aHSTSState,
|
||||
bool aHSTSIncludeSubdomains);
|
||||
|
||||
nsCString mHostname;
|
||||
OriginAttributes mOriginAttributes;
|
||||
PRTime mHSTSExpireTime;
|
||||
SecurityPropertyState mHSTSState;
|
||||
bool mHSTSIncludeSubdomains;
|
||||
|
@ -150,30 +164,42 @@ private:
|
|||
nsresult GetHost(nsIURI *aURI, nsACString &aResult);
|
||||
nsresult SetHSTSState(uint32_t aType, const char* aHost, int64_t maxage,
|
||||
bool includeSubdomains, uint32_t flags,
|
||||
SecurityPropertyState aHSTSState, bool aIsPreload);
|
||||
SecurityPropertyState aHSTSState, bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
nsresult ProcessHeaderInternal(uint32_t aType, nsIURI* aSourceURI,
|
||||
const nsCString& aHeader,
|
||||
nsISSLStatus* aSSLStatus,
|
||||
uint32_t aFlags, uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains,
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t* aMaxAge, bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult);
|
||||
nsresult ProcessSTSHeader(nsIURI* aSourceURI, const nsCString& aHeader,
|
||||
uint32_t flags, uint64_t* aMaxAge,
|
||||
bool* aIncludeSubdomains, uint32_t* aFailureResult);
|
||||
uint32_t flags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t* aMaxAge, bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult);
|
||||
nsresult ProcessPKPHeader(nsIURI* aSourceURI, const nsCString& aHeader,
|
||||
nsISSLStatus* aSSLStatus, uint32_t flags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t* aMaxAge, bool* aIncludeSubdomains,
|
||||
uint32_t* aFailureResult);
|
||||
nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags,
|
||||
bool aIsPreload);
|
||||
bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
nsresult RemoveStateInternal(uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
nsresult RemoveStateInternal(uint32_t aType, const nsAutoCString& aHost,
|
||||
uint32_t aFlags, bool aIsPreload);
|
||||
uint32_t aFlags, bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
bool HostHasHSTSEntry(const nsAutoCString& aHost,
|
||||
bool aRequireIncludeSubdomains, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
bool* aResult, bool* aCached);
|
||||
const nsSTSPreload *GetPreloadListEntry(const char *aHost);
|
||||
nsresult IsSecureHost(uint32_t aType, const nsACString& aHost,
|
||||
uint32_t aFlags, bool* aCached, bool* aResult);
|
||||
uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
bool* aCached, bool* aResult);
|
||||
|
||||
uint64_t mMaxMaxAge;
|
||||
bool mUsePreloadList;
|
||||
|
|
|
@ -50,7 +50,7 @@ function checkPassValidPin(pinValue, settingPin, expectedMaxAge) {
|
|||
}
|
||||
try {
|
||||
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
pinValue, sslStatus, 0, maxAge);
|
||||
pinValue, sslStatus, 0, {}, maxAge);
|
||||
ok(true, "Valid pin should be accepted");
|
||||
} catch (e) {
|
||||
ok(false, "Valid pin should have been accepted");
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2
|
||||
* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Ensures nsISiteSecurityService APIs respects origin attributes.
|
||||
|
||||
do_register_cleanup(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots");
|
||||
});
|
||||
|
||||
const GOOD_MAX_AGE_SECONDS = 69403;
|
||||
const NON_ISSUED_KEY_HASH = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
||||
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
const VALID_PIN = `pin-sha256="${PINNING_ROOT_KEY_HASH}";`;
|
||||
const BACKUP_PIN = `pin-sha256="${NON_ISSUED_KEY_HASH}";`;
|
||||
const GOOD_MAX_AGE = `max-age=${GOOD_MAX_AGE_SECONDS};`;
|
||||
|
||||
do_get_profile(); // must be done before instantiating nsIX509CertDB
|
||||
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots", true);
|
||||
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
addCertFromFile(certdb, "test_pinning_dynamic/pinningroot.pem", "CTu,CTu,CTu");
|
||||
|
||||
let sss = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
let host = "a.pinning2.example.com";
|
||||
let uri = Services.io.newURI("https://" + host);
|
||||
|
||||
// This test re-uses certificates from pinning tests because that's easier and
|
||||
// simpler than recreating new certificates, hence the slightly longer than
|
||||
// necessary domain name.
|
||||
let sslStatus = new FakeSSLStatus(constructCertFromFile(
|
||||
"test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem"));
|
||||
|
||||
// Check if originAttributes1 and originAttributes2 are isolated with respect
|
||||
// to HSTS/HPKP storage.
|
||||
function doTest(originAttributes1, originAttributes2, shouldShare) {
|
||||
sss.clearAll();
|
||||
for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP]) {
|
||||
let header = GOOD_MAX_AGE;
|
||||
if (type == Ci.nsISiteSecurityService.HEADER_HPKP) {
|
||||
header += VALID_PIN + BACKUP_PIN;
|
||||
}
|
||||
// Set HSTS or HPKP for originAttributes1.
|
||||
sss.processHeader(type, uri, header, sslStatus, 0, originAttributes1);
|
||||
ok(sss.isSecureURI(type, uri, 0, originAttributes1),
|
||||
"URI should be secure given original origin attributes");
|
||||
equal(sss.isSecureURI(type, uri, 0, originAttributes2), shouldShare,
|
||||
"URI should be secure given different origin attributes if and " +
|
||||
"only if shouldShare is true");
|
||||
|
||||
if (!shouldShare) {
|
||||
// Remove originAttributes2 from the storage.
|
||||
sss.removeState(type, uri, 0, originAttributes2);
|
||||
ok(sss.isSecureURI(type, uri, 0, originAttributes1),
|
||||
"URI should still be secure given original origin attributes");
|
||||
}
|
||||
|
||||
// Remove originAttributes1 from the storage.
|
||||
sss.removeState(type, uri, 0, originAttributes1);
|
||||
ok(!sss.isSecureURI(type, uri, 0, originAttributes1),
|
||||
"URI should be not be secure after removeState");
|
||||
}
|
||||
// Set HPKP for originAttributes1.
|
||||
sss.setKeyPins(host, false, Date.now() + 1234567890, 2,
|
||||
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH], false,
|
||||
originAttributes1);
|
||||
ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0,
|
||||
originAttributes1),
|
||||
"URI should be secure after setKeyPins given original origin attributes");
|
||||
equal(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0,
|
||||
originAttributes2),
|
||||
shouldShare, "URI should be secure after setKeyPins given different " +
|
||||
"origin attributes if and only if shouldShare is true");
|
||||
|
||||
sss.clearAll();
|
||||
ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0,
|
||||
originAttributes1),
|
||||
"URI should not be secure after clearAll");
|
||||
}
|
||||
|
||||
function testInvalidOriginAttributes(originAttributes) {
|
||||
for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP]) {
|
||||
let header = GOOD_MAX_AGE;
|
||||
if (type == Ci.nsISiteSecurityService.HEADER_HPKP) {
|
||||
header += VALID_PIN + BACKUP_PIN;
|
||||
}
|
||||
|
||||
let callbacks = [
|
||||
() => sss.processHeader(type, uri, header, sslStatus, 0,
|
||||
originAttributes),
|
||||
() => sss.isSecureURI(type, uri, 0, originAttributes),
|
||||
() => sss.removeState(type, uri, 0, originAttributes),
|
||||
];
|
||||
|
||||
for (let callback of callbacks) {
|
||||
throws(callback, /NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Should get an error with invalid origin attributes");
|
||||
}
|
||||
}
|
||||
|
||||
throws(() => sss.setKeyPins(host, false, Date.now() + 1234567890, 2,
|
||||
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH],
|
||||
false, originAttributes),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Should get an error with invalid origin attributes");
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
sss.clearAll();
|
||||
let originAttributesList = [];
|
||||
for (let userContextId of [0, 1, 2]) {
|
||||
for (let firstPartyDomain of ["", "foo.com", "bar.com"]) {
|
||||
originAttributesList.push({ userContextId, firstPartyDomain });
|
||||
}
|
||||
}
|
||||
for (let attrs1 of originAttributesList) {
|
||||
for (let attrs2 of originAttributesList) {
|
||||
// SSS storage is not isolated by userContext
|
||||
doTest(attrs1, attrs2,
|
||||
attrs1.firstPartyDomain == attrs2.firstPartyDomain);
|
||||
}
|
||||
}
|
||||
|
||||
testInvalidOriginAttributes(undefined);
|
||||
testInvalidOriginAttributes(null);
|
||||
testInvalidOriginAttributes(1);
|
||||
testInvalidOriginAttributes("foo");
|
||||
}
|
|
@ -19,7 +19,7 @@ function check_ip(s, v, ip) {
|
|||
let parsedMaxAge = {};
|
||||
let parsedIncludeSubdomains = {};
|
||||
s.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
|
||||
"max-age=1000;includeSubdomains", sslStatus, 0,
|
||||
"max-age=1000;includeSubdomains", sslStatus, 0, {},
|
||||
parsedMaxAge, parsedIncludeSubdomains);
|
||||
ok(!s.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"URI should not be secure if it contains an IP address");
|
||||
|
|
|
@ -17,7 +17,7 @@ function testSuccess(header, expectedMaxAge, expectedIncludeSubdomains) {
|
|||
let includeSubdomains = {};
|
||||
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, dummyUri, header,
|
||||
sslStatus, 0, maxAge, includeSubdomains);
|
||||
sslStatus, 0, {}, maxAge, includeSubdomains);
|
||||
|
||||
equal(maxAge.value, expectedMaxAge, "Did not correctly parse maxAge");
|
||||
equal(includeSubdomains.value, expectedIncludeSubdomains,
|
||||
|
@ -31,7 +31,7 @@ function testFailure(header) {
|
|||
|
||||
throws(() => {
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, dummyUri, header,
|
||||
sslStatus, 0, maxAge, includeSubdomains);
|
||||
sslStatus, 0, {}, maxAge, includeSubdomains);
|
||||
}, "Parsed invalid header: " + header);
|
||||
}
|
||||
|
||||
|
|
|
@ -127,6 +127,7 @@ run-sequentially = hardcoded ports
|
|||
tags = addons psm
|
||||
[test_sss_enumerate.js]
|
||||
[test_sss_eviction.js]
|
||||
[test_sss_originAttributes.js]
|
||||
[test_sss_readstate.js]
|
||||
[test_sss_readstate_child.js]
|
||||
support-files = sss_readstate_child_worker.js
|
||||
|
|
|
@ -119,7 +119,7 @@ function processStsHeader(host, header, status, securityInfo) {
|
|||
var sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
|
||||
.SSLStatus;
|
||||
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri, header, sslStatus, 0, maxAge,
|
||||
uri, header, sslStatus, 0, {}, maxAge,
|
||||
includeSubdomains);
|
||||
}
|
||||
catch (e) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче