Bug 1382001 - Part 2: Use a DAFSA for kSTSPreloadList. r=keeler

This switches the STS preload list over to a more compact representation by
using a DAFSA. `getHSTSPreloadList.js` is updated to output data in the gperf
format expected by `make_dafsa.py`. We then add a generated file that gets
created by pumping `nsSTSPreloadList.inc` through `make_dafsa.py`.

`nsSiteSecurityService` is updated to use the DAFSA which either returns -1
(kNotFound) if an entry is not present or (0, 1) indicating whether or not to
use subdomains.

`nsSTSPreloadList.inc` is an automated conversion to the new gperf-like format.
This commit is contained in:
Eric Rahm
2017-08-10 17:29:11 -07:00
parent dda60070a4
commit 7c42f46fb4
5 changed files with 21808 additions and 43597 deletions

View File

@@ -41,7 +41,7 @@
// influence its HSTS status via include subdomains, however).
// This prevents the preload list from overriding the site's current
// desired HSTS status.
#include "nsSTSPreloadList.inc"
#include "nsSTSPreloadList.h"
using namespace mozilla;
using namespace mozilla::psm;
@@ -495,6 +495,7 @@ nsSiteSecurityService::nsSiteSecurityService()
: mMaxMaxAge(kSixtyDaysInSeconds)
, mUsePreloadList(true)
, mPreloadListTimeOffset(0)
, mDafsa(kDafsa)
{
}
@@ -730,7 +731,7 @@ nsSiteSecurityService::RemoveStateInternal(
mozilla::DataStorage_Persistent);
RefPtr<SiteHSTSState> dynamicState =
new SiteHSTSState(aHost, aOriginAttributes, value);
if (GetPreloadListEntry(aHost.get()) ||
if (GetPreloadStatus(aHost) ||
dynamicState->mHSTSState != SecurityPropertyUnset) {
SSSLOG(("SSS: storing knockout entry for %s", aHost.get()));
RefPtr<SiteHSTSState> siteState = new SiteHSTSState(
@@ -1370,29 +1371,31 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
source, aResult);
}
int STSPreloadCompare(const void *key, const void *entry)
// Checks if the given host is in the preload list.
//
// @param aHost The host to match. Only does exact host matching.
// @param aIncludeSubdomains Out, optional. Indicates whether or not to include
// subdomains. Only set if the host is matched and this function returns
// true.
//
// @return True if the host is matched, false otherwise.
bool
nsSiteSecurityService::GetPreloadStatus(const nsACString& aHost,
bool* aIncludeSubdomains) const
{
const char *keyStr = (const char *)key;
const nsSTSPreload *preloadEntry = (const nsSTSPreload *)entry;
return strcmp(keyStr, &kSTSHostTable[preloadEntry->mHostIndex]);
}
const int kIncludeSubdomains = 1;
bool found = false;
// Returns the preload list entry for the given host, if it exists.
// Only does exact host matching - the user must decide how to use the returned
// data. May return null.
const nsSTSPreload *
nsSiteSecurityService::GetPreloadListEntry(const char *aHost)
{
PRTime currentTime = PR_Now() + (mPreloadListTimeOffset * PR_USEC_PER_SEC);
if (mUsePreloadList && currentTime < gPreloadListExpirationTime) {
return (const nsSTSPreload *) bsearch(aHost,
kSTSPreloadList,
mozilla::ArrayLength(kSTSPreloadList),
sizeof(nsSTSPreload),
STSPreloadCompare);
int result = mDafsa.Lookup(aHost);
found = (result != mozilla::Dafsa::kKeyNotFound);
if (found && aIncludeSubdomains) {
*aIncludeSubdomains = (result == kIncludeSubdomains);
}
}
return nullptr;
return found;
}
// Allows us to determine if we have an HSTS entry for a given host (and, if
@@ -1476,7 +1479,7 @@ nsSiteSecurityService::HostHasHSTSEntry(
if (dynamicState->mHSTSState == SecurityPropertyUnset) {
SSSLOG(("No dynamic preload - checking for static preload"));
// Now check the static preload list.
if (!GetPreloadListEntry(aHost.get())) {
if (!GetPreloadStatus(aHost)) {
SSSLOG(("No static preload - removing expired entry"));
mSiteStateStorage->Remove(storageKey, storageType);
}
@@ -1520,7 +1523,7 @@ nsSiteSecurityService::HostHasHSTSEntry(
} else {
// if a dynamic preload has expired and is not in the static preload
// list, we can remove it.
if (!GetPreloadListEntry(aHost.get())) {
if (!GetPreloadStatus(aHost)) {
mPreloadStateStorage->Remove(preloadKey,
mozilla::DataStorage_Persistent);
}
@@ -1528,18 +1531,18 @@ nsSiteSecurityService::HostHasHSTSEntry(
return false;
}
const nsSTSPreload* preload = nullptr;
bool includeSubdomains = false;
// Finally look in the static preload list.
if (siteState->mHSTSState == SecurityPropertyUnset &&
dynamicState->mHSTSState == SecurityPropertyUnset &&
(preload = GetPreloadListEntry(aHost.get())) != nullptr) {
GetPreloadStatus(aHost, &includeSubdomains)) {
SSSLOG(("%s is a preloaded HSTS host", aHost.get()));
*aResult = aRequireIncludeSubdomains ? preload->mIncludeSubdomains
*aResult = aRequireIncludeSubdomains ? includeSubdomains
: true;
if (aCached) {
// Only set cached if this includes subdomains
*aCached = aRequireIncludeSubdomains ? preload->mIncludeSubdomains
*aCached = aRequireIncludeSubdomains ? includeSubdomains
: true;
}
if (aSource) {