bug 887052 - refactor nsISiteSecurityService for multiple headers r=cviecco r=mcmanus r=jst sr=jst

This commit is contained in:
David Keeler 2013-07-01 10:49:40 -07:00
parent 503e645f01
commit a746ca39ba
14 changed files with 155 additions and 129 deletions

View File

@ -1237,7 +1237,7 @@ function test41()
var flags = 0;
if (loadContext.usePrivateBrowsing)
flags |= Ci.nsISocketProvider.NO_PERMANENT_STORAGE;
sss.removeStsState(thehost, flags);
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, thehost, flags);
doTest(42);
}
}

View File

@ -4273,7 +4273,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
mInPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
bool isStsHost = false;
rv = sss->IsStsURI(aURI, flags, &isStsHost);
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
aURI, flags, &isStsHost);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t bucketId;

View File

@ -8,9 +8,13 @@ interface nsIURI;
interface nsIObserver;
interface nsIHttpChannel;
[scriptable, uuid(1ca9de3d-26b8-4e0c-9641-62c380bdd9c7)]
[scriptable, uuid(b20a9242-5732-45bc-9fa0-a178154f2721)]
interface nsISiteSecurityService : nsISupports
{
const uint32_t HEADER_HSTS = 0;
const uint32_t HEADER_HKPK = 1;
const uint32_t HEADER_OMS = 2;
/**
* Parses a given HTTP header and records the results internally.
* The format of the STS header is defined by the STS specification:
@ -29,11 +33,12 @@ interface nsISiteSecurityService : nsISupports
* NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
* if there are unrecognized tokens in the header.
*/
void processStsHeader(in nsIURI aSourceURI,
in string aHeader,
in uint32_t aFlags,
[optional] out unsigned long long aMaxAge,
[optional] out boolean aIncludeSubdomains);
void processHeader(in uint32_t aType,
in nsIURI aSourceURI,
in string aHeader,
in uint32_t aFlags,
[optional] out unsigned long long aMaxAge,
[optional] out boolean aIncludeSubdomains);
/**
* Removes the STS state of a host, including the includeSubdomains state
@ -43,25 +48,15 @@ interface nsISiteSecurityService : nsISupports
* @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE
*/
void removeStsState(in nsIURI aURI,
in uint32_t aFlags);
void removeState(in uint32_t aType,
in nsIURI aURI,
in uint32_t aFlags);
/**
* Checks if the given security info is for an STS host with a broken
* transport layer (certificate errors like invalid CN).
*/
boolean shouldIgnoreStsHeader(in nsISupports aSecurityInfo);
/**
* Checks whether or not the given hostname has STS state set.
* The host is an STS host if either it has the STS permission, or one of
* its super-domains has an STS "includeSubdomains" permission set.
*
* @param aHost the hostname (punycode) to query for STS state.
* @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE
*/
boolean isStsHost(in string aHost, in uint32_t aFlags);
boolean shouldIgnoreHeader(in nsISupports aSecurityInfo);
/**
* Checks whether or not the URI's hostname has STS state set.
@ -75,7 +70,7 @@ interface nsISiteSecurityService : nsISupports
* @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE
*/
boolean isStsURI(in nsIURI aURI, in uint32_t aFlags);
boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags);
};

View File

@ -383,12 +383,13 @@ nsHttpChannel::Connect()
bool isStsHost = false;
uint32_t flags = mPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
rv = sss->IsStsURI(mURI, flags, &isStsHost);
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, mURI, flags,
&isStsHost);
// if STS fails, there's no reason to cancel the load, but it's
// if SSS fails, there's no reason to cancel the load, but it's
// worrisome.
NS_ASSERTION(NS_SUCCEEDED(rv),
"Something is wrong with STS: IsStsURI failed.");
"Something is wrong with SSS: IsSecureURI failed.");
if (NS_SUCCEEDED(rv) && isStsHost) {
LOG(("nsHttpChannel::Connect() STS permissions found\n"));
@ -1155,7 +1156,7 @@ nsHttpChannel::ProcessSTSHeader()
// If there are certificate errors, we still load the data, we just ignore
// any STS headers that are present.
bool tlsIsBroken = false;
rv = sss->ShouldIgnoreStsHeader(mSecurityInfo, &tlsIsBroken);
rv = sss->ShouldIgnoreHeader(mSecurityInfo, &tlsIsBroken);
NS_ENSURE_SUCCESS(rv, NS_OK);
// If this was already an STS host, the connection should have been aborted
@ -1166,7 +1167,8 @@ nsHttpChannel::ProcessSTSHeader()
bool wasAlreadySTSHost;
uint32_t flags =
NS_UsePrivateBrowsing(this) ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
rv = sss->IsStsURI(mURI, flags, &wasAlreadySTSHost);
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, mURI, flags,
&wasAlreadySTSHost);
// Failure here means STS is broken. Don't prevent the load, but this
// shouldn't fail.
NS_ENSURE_SUCCESS(rv, NS_OK);
@ -1194,7 +1196,8 @@ nsHttpChannel::ProcessSTSHeader()
// All other failures are fatal.
NS_ENSURE_SUCCESS(rv, rv);
rv = sss->ProcessStsHeader(mURI, stsHeader.get(), flags, NULL, NULL);
rv = sss->ProcessHeader(nsISiteSecurityService::HEADER_HSTS, mURI,
stsHeader.get(), flags, NULL, NULL);
if (NS_FAILED(rv)) {
AddSecurityMessage(NS_LITERAL_STRING("InvalidSTSHeaders"),
NS_LITERAL_STRING("Invalid HSTS Headers"));

View File

@ -1840,7 +1840,8 @@ nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
if (loadContext && loadContext->UsePrivateBrowsing())
flags |= nsISocketProvider::NO_PERMANENT_STORAGE;
nsCOMPtr<nsIURI> clone;
if (NS_SUCCEEDED(sss->IsStsURI(aURI, flags, &isStsHost)) && isStsHost) {
if (NS_SUCCEEDED(sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
aURI, flags, &isStsHost)) && isStsHost) {
if (NS_SUCCEEDED(aURI->Clone(getter_AddRefs(clone)))) {
clone->SetScheme(NS_LITERAL_CSTRING("https"));
aURI = clone.get();

View File

@ -49,7 +49,8 @@ TestSuccess(const char* hdr, bool extraTokens,
uint64_t maxAge = 0;
bool includeSubdomains = false;
rv = sss->ProcessStsHeader(dummyUri, hdr, 0, &maxAge, &includeSubdomains);
rv = sss->ProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri, hdr,
0, &maxAge, &includeSubdomains);
EXPECT_SUCCESS(rv, "Failed to process valid header: %s", hdr);
REQUIRE_EQUAL(maxAge, expectedMaxAge, "Did not correctly parse maxAge");
@ -74,7 +75,8 @@ bool TestFailure(const char* hdr,
nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
EXPECT_SUCCESS(rv, "Failed to create URI");
rv = sss->ProcessStsHeader(dummyUri, hdr, 0, NULL, NULL);
rv = sss->ProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri, hdr,
0, NULL, NULL);
EXPECT_FAILURE(rv, "Parsed invalid header: %s", hdr);
passed(hdr);
return true;

View File

@ -140,15 +140,16 @@ nsSiteSecurityService::GetPrincipalForURI(nsIURI* aURI,
}
nsresult
nsSiteSecurityService::SetStsState(nsIURI* aSourceURI,
int64_t maxage,
bool includeSubdomains,
uint32_t flags)
nsSiteSecurityService::SetState(uint32_t aType,
nsIURI* aSourceURI,
int64_t maxage,
bool includeSubdomains,
uint32_t flags)
{
// If max-age is zero, that's an indication to immediately remove the
// permissions, so here's a shortcut.
if (!maxage) {
return RemoveStsState(aSourceURI, flags);
return RemoveState(aType, aSourceURI, flags);
}
// Expire time is millis from now. Since STS max-age is in seconds, and
@ -191,11 +192,14 @@ nsSiteSecurityService::SetStsState(nsIURI* aSourceURI,
}
NS_IMETHODIMP
nsSiteSecurityService::RemoveStsState(nsIURI* aURI, uint32_t aFlags)
nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, uint32_t aFlags)
{
// Should be called on the main thread (or via proxy) since the permission
// manager is used and it's not threadsafe.
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
nsAutoCString hostname;
nsresult rv = GetHost(aURI, hostname);
@ -215,15 +219,19 @@ nsSiteSecurityService::RemoveStsState(nsIURI* aURI, uint32_t aFlags)
}
NS_IMETHODIMP
nsSiteSecurityService::ProcessStsHeader(nsIURI* aSourceURI,
const char* aHeader,
uint32_t aFlags,
uint64_t *aMaxAge,
bool *aIncludeSubdomains)
nsSiteSecurityService::ProcessHeader(uint32_t aType,
nsIURI* aSourceURI,
const char* aHeader,
uint32_t aFlags,
uint64_t *aMaxAge,
bool *aIncludeSubdomains)
{
// Should be called on the main thread (or via proxy) since the permission
// manager is used and it's not threadsafe.
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
if (aMaxAge != nullptr) {
*aMaxAge = 0;
@ -235,18 +243,19 @@ nsSiteSecurityService::ProcessStsHeader(nsIURI* aSourceURI,
char * header = NS_strdup(aHeader);
if (!header) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = ProcessStsHeaderMutating(aSourceURI, header, aFlags,
aMaxAge, aIncludeSubdomains);
nsresult rv = ProcessHeaderMutating(aType, aSourceURI, header, aFlags,
aMaxAge, aIncludeSubdomains);
NS_Free(header);
return rv;
}
nsresult
nsSiteSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI,
char* aHeader,
uint32_t aFlags,
uint64_t *aMaxAge,
bool *aIncludeSubdomains)
nsSiteSecurityService::ProcessHeaderMutating(uint32_t aType,
nsIURI* aSourceURI,
char* aHeader,
uint32_t aFlags,
uint64_t *aMaxAge,
bool *aIncludeSubdomains)
{
STSLOG(("STS: processing header '%s'", aHeader));
@ -342,7 +351,7 @@ nsSiteSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI,
}
// record the successfully parsed header data.
SetStsState(aSourceURI, maxAge, foundIncludeSubdomains, aFlags);
SetState(aType, aSourceURI, maxAge, foundIncludeSubdomains, aFlags);
if (aMaxAge != nullptr) {
*aMaxAge = (uint64_t)maxAge;
@ -357,21 +366,6 @@ nsSiteSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI,
NS_OK;
}
NS_IMETHODIMP
nsSiteSecurityService::IsStsHost(const char* aHost, uint32_t aFlags, bool* aResult)
{
// Should be called on the main thread (or via proxy) since the permission
// manager is used and it's not threadsafe.
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIURI> uri;
nsDependentCString hostString(aHost);
nsresult rv = NS_NewURI(getter_AddRefs(uri),
NS_LITERAL_CSTRING("https://") + hostString);
NS_ENSURE_SUCCESS(rv, rv);
return IsStsURI(uri, aFlags, aResult);
}
int STSPreloadCompare(const void *key, const void *entry)
{
const char *keyStr = (const char *)key;
@ -405,11 +399,15 @@ nsSiteSecurityService::GetPreloadListEntry(const char *aHost)
}
NS_IMETHODIMP
nsSiteSecurityService::IsStsURI(nsIURI* aURI, uint32_t aFlags, bool* aResult)
nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
uint32_t aFlags, bool* aResult)
{
// Should be called on the main thread (or via proxy) since the permission
// manager is used and it's not threadsafe.
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
// set default in case if we can't find any STS information
*aResult = false;
@ -546,8 +544,8 @@ nsSiteSecurityService::IsStsURI(nsIURI* aURI, uint32_t aFlags, bool* aResult)
// Verify the trustworthiness of the security info (are there any cert errors?)
NS_IMETHODIMP
nsSiteSecurityService::ShouldIgnoreStsHeader(nsISupports* aSecurityInfo,
bool* aResult)
nsSiteSecurityService::ShouldIgnoreHeader(nsISupports* aSecurityInfo,
bool* aResult)
{
nsresult rv;
bool tlsIsBroken = false;

View File

@ -136,9 +136,11 @@ public:
private:
nsresult GetHost(nsIURI *aURI, nsACString &aResult);
nsresult GetPrincipalForURI(nsIURI *aURI, nsIPrincipal **aPrincipal);
nsresult SetStsState(nsIURI* aSourceURI, int64_t maxage, bool includeSubdomains, uint32_t flags);
nsresult ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader, uint32_t flags,
uint64_t *aMaxAge, bool *aIncludeSubdomains);
nsresult SetState(uint32_t aType, nsIURI* aSourceURI, int64_t maxage,
bool includeSubdomains, uint32_t flags);
nsresult ProcessHeaderMutating(uint32_t aType, nsIURI* aSourceURI,
char* aHeader, uint32_t flags,
uint64_t *aMaxAge, bool *aIncludeSubdomains);
const nsSTSPreload *GetPreloadListEntry(const char *aHost);
// private-mode-preserving permission manager overlay functions

View File

@ -310,6 +310,7 @@ CertErrorRunnable::CheckCertOverrides()
uint32_t remaining_display_errors = mCollectedErrors;
nsresult nsrv;
nsCString hostString(mInfoObject->GetHostName());
// Enforce Strict-Transport-Security for hosts that are "STS" hosts:
// connections must be dropped when there are any certificate errors
@ -320,9 +321,15 @@ CertErrorRunnable::CheckCertOverrides()
if (NS_SUCCEEDED(nsrv)) {
nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
nsrv = sss->IsStsHost(mInfoObject->GetHostName(),
mProviderFlags,
&strictTransportSecurityEnabled);
nsCOMPtr<nsIURI> uri;
nsrv = NS_NewURI(getter_AddRefs(uri),
NS_LITERAL_CSTRING("https://") + hostString);
if (NS_SUCCEEDED(nsrv)) {
nsrv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
uri,
mProviderFlags,
&strictTransportSecurityEnabled);
}
}
if (NS_FAILED(nsrv)) {
return new SSLServerCertVerificationResult(mInfoObject,
@ -340,7 +347,6 @@ CertErrorRunnable::CheckCertOverrides()
{
bool haveOverride;
bool isTemporaryOverride; // we don't care
nsCString hostString(mInfoObject->GetHostName());
nsrv = overrideService->HasMatchingOverride(hostString, port,
mCert,
&overrideBits,

View File

@ -22,8 +22,9 @@ function test() {
aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
uri = aWindow.Services.io.newURI("https://localhost/img.png", null, null);
gSSService.processStsHeader(uri, "max-age=1000", privacyFlags(aIsPrivateMode));
ok(gSSService.isStsHost("localhost", privacyFlags(aIsPrivateMode)), "checking sts host");
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTA, uri,
"max-age=1000", privacyFlags(aIsPrivateMode));
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, privacyFlags(aIsPrivateMode)), "checking sts host");
aCallback();
}, true);
@ -47,7 +48,8 @@ function test() {
aWin.close();
});
uri = Services.io.newURI("http://localhost", null, null);
gSSService.removeStsState(uri, privacyFlags(true));
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
privacyFlags(true));
});
// test first when on private mode

View File

@ -54,7 +54,7 @@
var thehost = ios.newURI("http://example.com", null, null);
var sss = Cc["@mozilla.org/ssservice;1"].getService(Ci.nsISiteSecurityService);
sss.removeStsState(thehost, 0);
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, thehost, 0);
}
function loadVerifyFrames(round) {

View File

@ -191,7 +191,7 @@
Cc["@mozilla.org/ssservice;1"].
getService(Ci.nsISiteSecurityService);
var flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0
sss.removeStsState(thehost, flags);
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, thehost, flags);
dump_STSState(isPrivate);
}
@ -200,7 +200,8 @@
Cc["@mozilla.org/ssservice;1"].
getService(Ci.nsISiteSecurityService);
var flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0
SimpleTest.info("State of example.com: " + sss.isStsHost("example.com", flags));
var uri = SpecialPowers.Services.io.newURI("https://example.com", null, null);
SimpleTest.info("State of example.com: " + sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags));
}
// These are executed in the order presented.

View File

@ -25,7 +25,7 @@ var gObserver = new Observer();
function clearStsState() {
var permissionManager = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
// This is a list of every host we call processStsHeader with
// This is a list of every host we call processHeader with
// (so we can remove any state added to the sts service)
var hosts = ["bugzilla.mozilla.org", "login.persona.org",
"subdomain.www.torproject.org",
@ -52,54 +52,63 @@ function run_test() {
run_next_test();
}
function is_sts_host(aHost, aFlags) {
var uri = Services.io.newURI("http://" + aHost, null, null);
return gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, aFlags);
}
function test_part1() {
// check that a host not in the list is not identified as an sts host
do_check_false(gSSService.isStsHost("nonexistent.mozilla.com", 0));
do_check_false(is_sts_host("nonexistent.mozilla.com", 0));
// check that an ancestor domain is not identified as an sts host
do_check_false(gSSService.isStsHost("com", 0));
do_check_false(is_sts_host("com", 0));
// check that the pref to toggle using the preload list works
Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", false);
do_check_false(gSSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_false(is_sts_host("bugzilla.mozilla.org", 0));
Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", true);
do_check_true(gSSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("bugzilla.mozilla.org", 0));
// check that a subdomain is an sts host (includeSubdomains is set)
do_check_true(gSSService.isStsHost("subdomain.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("subdomain.bugzilla.mozilla.org", 0));
// check that another subdomain is an sts host (includeSubdomains is set)
do_check_true(gSSService.isStsHost("a.b.c.def.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("a.b.c.def.bugzilla.mozilla.org", 0));
// check that a subdomain is not an sts host (includeSubdomains is not set)
do_check_false(gSSService.isStsHost("subdomain.www.torproject.org", 0));
do_check_false(is_sts_host("subdomain.www.torproject.org", 0));
// check that a host with a dot on the end won't break anything
do_check_false(gSSService.isStsHost("notsts.nonexistent.mozilla.com.", 0));
do_check_false(is_sts_host("notsts.nonexistent.mozilla.com.", 0));
// check that processing a header with max-age: 0 will remove a preloaded
// site from the list
var uri = Services.io.newURI("http://bugzilla.mozilla.org", null, null);
gSSService.processStsHeader(uri, "max-age=0", 0);
do_check_false(gSSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_false(gSSService.isStsHost("subdomain.bugzilla.mozilla.org", 0));
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=0", 0);
do_check_false(is_sts_host("bugzilla.mozilla.org", 0));
do_check_false(is_sts_host("subdomain.bugzilla.mozilla.org", 0));
// check that processing another header (with max-age non-zero) will
// re-enable a site's sts status
gSSService.processStsHeader(uri, "max-age=1000", 0);
do_check_true(gSSService.isStsHost("bugzilla.mozilla.org", 0));
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=1000", 0);
do_check_true(is_sts_host("bugzilla.mozilla.org", 0));
// but this time include subdomains was not set, so test for that
do_check_false(gSSService.isStsHost("subdomain.bugzilla.mozilla.org", 0));
do_check_false(is_sts_host("subdomain.bugzilla.mozilla.org", 0));
clearStsState();
// check that processing a header with max-age: 0 from a subdomain of a site
// will not remove that (ancestor) site from the list
var uri = Services.io.newURI("http://subdomain.www.torproject.org", null, null);
gSSService.processStsHeader(uri, "max-age=0", 0);
do_check_true(gSSService.isStsHost("www.torproject.org", 0));
do_check_false(gSSService.isStsHost("subdomain.www.torproject.org", 0));
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=0", 0);
do_check_true(is_sts_host("www.torproject.org", 0));
do_check_false(is_sts_host("subdomain.www.torproject.org", 0));
var uri = Services.io.newURI("http://subdomain.bugzilla.mozilla.org", null, null);
gSSService.processStsHeader(uri, "max-age=0", 0);
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=0", 0);
// we received a header with "max-age=0", so we have "no information"
// regarding the sts state of subdomain.bugzilla.mozilla.org specifically,
// but it is actually still an STS host, because of the preloaded
@ -109,20 +118,21 @@ function test_part1() {
// |-- subdomain.bugzilla.mozilla.org IS sts host
// | `-- another.subdomain.bugzilla.mozilla.org IS sts host
// `-- sibling.bugzilla.mozilla.org IS sts host
do_check_true(gSSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_true(gSSService.isStsHost("subdomain.bugzilla.mozilla.org", 0));
do_check_true(gSSService.isStsHost("sibling.bugzilla.mozilla.org", 0));
do_check_true(gSSService.isStsHost("another.subdomain.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("subdomain.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("sibling.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("another.subdomain.bugzilla.mozilla.org", 0));
gSSService.processStsHeader(uri, "max-age=1000", 0);
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=1000", 0);
// Here's what we have now:
// |-- bugzilla.mozilla.org (in preload list, includes subdomains) IS sts host
// |-- subdomain.bugzilla.mozilla.org (include subdomains is false) IS sts host
// | `-- another.subdomain.bugzilla.mozilla.org IS NOT sts host
// `-- sibling.bugzilla.mozilla.org IS sts host
do_check_true(gSSService.isStsHost("subdomain.bugzilla.mozilla.org", 0));
do_check_true(gSSService.isStsHost("sibling.bugzilla.mozilla.org", 0));
do_check_false(gSSService.isStsHost("another.subdomain.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("subdomain.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("sibling.bugzilla.mozilla.org", 0));
do_check_false(is_sts_host("another.subdomain.bugzilla.mozilla.org", 0));
// Simulate leaving private browsing mode
Services.obs.notifyObservers(null, "last-pb-context-exited", null);
@ -133,24 +143,27 @@ const IS_PRIVATE = Ci.nsISocketProvider.NO_PERMANENT_STORAGE;
function test_private_browsing1() {
clearStsState();
// sanity - bugzilla.mozilla.org is preloaded, includeSubdomains set
do_check_true(gSSService.isStsHost("bugzilla.mozilla.org", IS_PRIVATE));
do_check_true(gSSService.isStsHost("a.b.c.subdomain.bugzilla.mozilla.org", IS_PRIVATE));
do_check_true(is_sts_host("bugzilla.mozilla.org", IS_PRIVATE));
do_check_true(is_sts_host("a.b.c.subdomain.bugzilla.mozilla.org", IS_PRIVATE));
var uri = Services.io.newURI("http://bugzilla.mozilla.org", null, null);
gSSService.processStsHeader(uri, "max-age=0", IS_PRIVATE);
do_check_false(gSSService.isStsHost("bugzilla.mozilla.org", IS_PRIVATE));
do_check_false(gSSService.isStsHost("a.b.subdomain.bugzilla.mozilla.org", IS_PRIVATE));
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=0", IS_PRIVATE);
do_check_false(is_sts_host("bugzilla.mozilla.org", IS_PRIVATE));
do_check_false(is_sts_host("a.b.subdomain.bugzilla.mozilla.org", IS_PRIVATE));
// check adding it back in
gSSService.processStsHeader(uri, "max-age=1000", IS_PRIVATE);
do_check_true(gSSService.isStsHost("bugzilla.mozilla.org", IS_PRIVATE));
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=1000", IS_PRIVATE);
do_check_true(is_sts_host("bugzilla.mozilla.org", IS_PRIVATE));
// but no includeSubdomains this time
do_check_false(gSSService.isStsHost("b.subdomain.bugzilla.mozilla.org", IS_PRIVATE));
do_check_false(is_sts_host("b.subdomain.bugzilla.mozilla.org", IS_PRIVATE));
// do the hokey-pokey...
gSSService.processStsHeader(uri, "max-age=0", IS_PRIVATE);
do_check_false(gSSService.isStsHost("bugzilla.mozilla.org", IS_PRIVATE));
do_check_false(gSSService.isStsHost("subdomain.bugzilla.mozilla.org", IS_PRIVATE));
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=0", IS_PRIVATE);
do_check_false(is_sts_host("bugzilla.mozilla.org", IS_PRIVATE));
do_check_false(is_sts_host("subdomain.bugzilla.mozilla.org", IS_PRIVATE));
// TODO unfortunately we don't have a good way to know when an entry
// has expired in the permission manager, so we can't yet extend this test
@ -161,11 +174,12 @@ function test_private_browsing1() {
// a site on the preload list, and that header later expires. We need to
// then treat that host as no longer an sts host.)
// (sanity check first - this should be in the preload list)
do_check_true(gSSService.isStsHost("login.persona.org", IS_PRIVATE));
do_check_true(is_sts_host("login.persona.org", IS_PRIVATE));
var uri = Services.io.newURI("http://login.persona.org", null, null);
gSSService.processStsHeader(uri, "max-age=1", IS_PRIVATE);
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
"max-age=1", IS_PRIVATE);
do_timeout(1250, function() {
do_check_false(gSSService.isStsHost("login.persona.org", IS_PRIVATE));
do_check_false(is_sts_host("login.persona.org", IS_PRIVATE));
// Simulate leaving private browsing mode
Services.obs.notifyObservers(null, "last-pb-context-exited", null);
});
@ -173,13 +187,13 @@ function test_private_browsing1() {
function test_private_browsing2() {
// if this test gets this far, it means there's a private browsing service
do_check_true(gSSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("bugzilla.mozilla.org", 0));
// the bugzilla.mozilla.org entry has includeSubdomains set
do_check_true(gSSService.isStsHost("subdomain.bugzilla.mozilla.org", 0));
do_check_true(is_sts_host("subdomain.bugzilla.mozilla.org", 0));
// Now that we're out of private browsing mode, we need to make sure
// we've "forgotten" that we "forgot" this site's sts status.
do_check_true(gSSService.isStsHost("login.persona.org", 0));
do_check_true(is_sts_host("login.persona.org", 0));
run_next_test();
}

View File

@ -5,17 +5,18 @@ function run_test() {
let SSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
let uri = Services.io.newURI("https://bugzilla.mozilla.org", null, null);
// check that a host on the preload list is identified as an sts host
do_check_true(SSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_true(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
do_check_false(SSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_false(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
// just make sure we can get everything back to normal
Services.prefs.clearUserPref("test.currentTimeOffsetSeconds");
do_check_true(SSService.isStsHost("bugzilla.mozilla.org", 0));
do_check_true(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
}