Properly implement various HSTS states.

This commit is contained in:
Fedor 2019-09-20 13:14:00 +03:00
parent bb33363faf
commit 34eb8aadc5
2 changed files with 27 additions and 16 deletions

View File

@ -23,7 +23,7 @@ namespace mozilla
[ref] native nsCStringTArrayRef(nsTArray<nsCString>); [ref] native nsCStringTArrayRef(nsTArray<nsCString>);
[ref] native mozillaPkixTime(mozilla::pkix::Time); [ref] native mozillaPkixTime(mozilla::pkix::Time);
[scriptable, uuid(275127f8-dbd7-4681-afbf-6df0c6587a01)] [scriptable, uuid(233908bd-6741-4474-a6e1-f298c6ce9eaf)]
interface nsISiteSecurityService : nsISupports interface nsISiteSecurityService : nsISupports
{ {
const uint32_t HEADER_HSTS = 0; const uint32_t HEADER_HSTS = 0;
@ -98,15 +98,21 @@ interface nsISiteSecurityService : nsISupports
* Given a header type, removes state relating to that header of a host, * Given a header type, removes state relating to that header of a host,
* including the includeSubdomains state that would affect subdomains. * including the includeSubdomains state that would affect subdomains.
* This essentially removes the state for the domain tree rooted at this * This essentially removes the state for the domain tree rooted at this
* host. * host. If any preloaded information is present for that host, that
* information will then be used instead of any other previously existing
* state, unless the force parameter is set.
*
* @param aType the type of security state in question * @param aType the type of security state in question
* @param aURI the URI of the target host * @param aURI the URI of the target host
* @param aFlags options for this request as defined in nsISocketProvider: * @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE * NO_PERMANENT_STORAGE
* @param force if set, forces no-HSTS state by writing a knockout value,
* overriding any preload list state
*/ */
void removeState(in uint32_t aType, void removeState(in uint32_t aType,
in nsIURI aURI, in nsIURI aURI,
in uint32_t aFlags); in uint32_t aFlags,
[optional] in boolean force);
/** /**
* See isSecureURI * See isSecureURI

View File

@ -330,21 +330,22 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
uint32_t flags, uint32_t flags,
SecurityPropertyState aHSTSState) SecurityPropertyState aHSTSState)
{ {
// If max-age is zero, that's an indication to immediately remove the // Exit early if STS not enabled
// security state, so here's a shortcut. if (!mUseStsService) {
if (!maxage) { return NS_OK;
return RemoveState(aType, aSourceURI, flags); }
// 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 RemoveState(aType, aSourceURI, flags, true);
} }
MOZ_ASSERT((aHSTSState == SecurityPropertySet || MOZ_ASSERT((aHSTSState == SecurityPropertySet ||
aHSTSState == SecurityPropertyNegative), aHSTSState == SecurityPropertyNegative),
"HSTS State must be SecurityPropertySet or SecurityPropertyNegative"); "HSTS State must be SecurityPropertySet or SecurityPropertyNegative");
// Exit early if STS not enabled
if (!mUseStsService) {
return NS_OK;
}
int64_t expiretime = ExpireTimeFromMaxAge(maxage); int64_t expiretime = ExpireTimeFromMaxAge(maxage);
SiteHSTSState siteState(expiretime, aHSTSState, includeSubdomains); SiteHSTSState siteState(expiretime, aHSTSState, includeSubdomains);
nsAutoCString stateString; nsAutoCString stateString;
@ -367,7 +368,7 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
NS_IMETHODIMP NS_IMETHODIMP
nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
uint32_t aFlags) uint32_t aFlags, bool force = false)
{ {
// Child processes are not allowed direct access to this. // Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) { if (!XRE_IsParentProcess()) {
@ -387,8 +388,9 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
mozilla::DataStorageType storageType = isPrivate mozilla::DataStorageType storageType = isPrivate
? mozilla::DataStorage_Private ? mozilla::DataStorage_Private
: mozilla::DataStorage_Persistent; : mozilla::DataStorage_Persistent;
// If this host is in the preload list, we have to store a knockout entry. // If this host is in the preload list, we have to store a knockout entry
if (GetPreloadListEntry(hostname.get())) { // if it's explicitly forced to not be HSTS anymore
if (force && GetPreloadListEntry(hostname.get())) {
SSSLOG(("SSS: storing knockout entry for %s", hostname.get())); SSSLOG(("SSS: storing knockout entry for %s", hostname.get()));
SiteHSTSState siteState(0, SecurityPropertyKnockout, false); SiteHSTSState siteState(0, SecurityPropertyKnockout, false);
nsAutoCString stateString; nsAutoCString stateString;
@ -769,7 +771,10 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
// if maxAge == 0 we must delete all state, for now no hole-punching // If maxAge == 0, we remove dynamic HPKP state for this host. Due to
// architectural constraints, if this host was preloaded, any future lookups
// will use the preloaded state (i.e. we can't store a "this host is not HPKP"
// entry like we can for HSTS).
if (maxAge == 0) { if (maxAge == 0) {
return RemoveState(aType, aSourceURI, aFlags); return RemoveState(aType, aSourceURI, aFlags);
} }