Backed out changeset 54267d9f3d78 (bug 1701192) for causing mochitest failures on test_hsts_upgrade_intercept.html. CLOSED TREE DONTBUILD

This commit is contained in:
Iulian Moraru 2021-05-27 03:17:12 +03:00
Родитель 0c2f477cee
Коммит 38414bfb41
23 изменённых файлов: 627 добавлений и 381 удалений

Просмотреть файл

@ -1740,43 +1740,59 @@ static void GetSTSConsoleErrorTag(uint32_t failureResult,
}
/**
* Process an HTTP Strict Transport Security (HSTS) header.
* Process a single security header. Only one type is supported: HSTS
*/
nsresult nsHttpChannel::ProcessHSTSHeader(nsITransportSecurityInfo* aSecInfo,
uint32_t aFlags) {
nsHttpAtom atom(nsHttp::ResolveAtom("Strict-Transport-Security"));
nsresult nsHttpChannel::ProcessSingleSecurityHeader(
uint32_t aType, nsITransportSecurityInfo* aSecInfo, uint32_t aFlags) {
nsHttpAtom atom;
switch (aType) {
case nsISiteSecurityService::HEADER_HSTS:
atom = nsHttp::ResolveAtom("Strict-Transport-Security");
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid security header type");
return NS_ERROR_FAILURE;
}
nsAutoCString securityHeader;
nsresult rv = mResponseHead->GetHeader(atom, securityHeader);
if (rv == NS_ERROR_NOT_AVAILABLE) {
if (NS_SUCCEEDED(rv)) {
nsISiteSecurityService* sss = gHttpHandler->GetSSService();
NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
// Process header will now discard the headers itself if the channel
// wasn't secure (whereas before it had to be checked manually)
OriginAttributes originAttributes;
if (NS_WARN_IF(!StoragePrincipalHelper::GetOriginAttributesForHSTS(
this, originAttributes))) {
return NS_ERROR_FAILURE;
}
uint32_t failureResult;
uint32_t headerSource = nsISiteSecurityService::SOURCE_ORGANIC_REQUEST;
rv = sss->ProcessHeader(aType, mURI, securityHeader, aSecInfo, aFlags,
headerSource, originAttributes, nullptr, nullptr,
&failureResult);
if (NS_FAILED(rv)) {
nsAutoString consoleErrorCategory;
nsAutoString consoleErrorTag;
switch (aType) {
case nsISiteSecurityService::HEADER_HSTS:
GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
consoleErrorCategory = u"Invalid HSTS Headers"_ns;
break;
default:
return NS_ERROR_FAILURE;
}
Unused << AddSecurityMessage(consoleErrorTag, consoleErrorCategory);
LOG(("nsHttpChannel: Failed to parse %s header, continuing load.\n",
atom.get()));
}
} else {
if (rv != NS_ERROR_NOT_AVAILABLE) {
// All other errors are fatal
NS_ENSURE_SUCCESS(rv, rv);
}
LOG(("nsHttpChannel: No %s header, continuing load.\n", atom.get()));
return NS_OK;
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsISiteSecurityService* sss = gHttpHandler->GetSSService();
NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
OriginAttributes originAttributes;
if (NS_WARN_IF(!StoragePrincipalHelper::GetOriginAttributesForHSTS(
this, originAttributes))) {
return NS_ERROR_FAILURE;
}
uint32_t failureResult;
uint32_t headerSource = nsISiteSecurityService::SOURCE_ORGANIC_REQUEST;
rv = sss->ProcessHeader(nsISiteSecurityService::HEADER_HSTS, mURI,
securityHeader, aSecInfo, aFlags, headerSource,
originAttributes, nullptr, nullptr, &failureResult);
if (NS_FAILED(rv)) {
nsAutoString consoleErrorCategory(u"Invalid HSTS Headers"_ns);
nsAutoString consoleErrorTag;
GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
Unused << AddSecurityMessage(consoleErrorTag, consoleErrorCategory);
LOG(("nsHttpChannel: Failed to parse %s header, continuing load.\n",
atom.get()));
}
return NS_OK;
}
@ -1823,12 +1839,9 @@ nsresult nsHttpChannel::ProcessSecurityHeaders() {
do_QueryInterface(mSecurityInfo);
NS_ENSURE_TRUE(transSecInfo, NS_ERROR_FAILURE);
// Only process HSTS headers for first-party loads. This prevents a
// proliferation of useless HSTS state for partitioned third parties.
if (!mLoadInfo->GetIsThirdPartyContextToTopWindow()) {
rv = ProcessHSTSHeader(transSecInfo, flags);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = ProcessSingleSecurityHeader(nsISiteSecurityService::HEADER_HSTS,
transSecInfo, flags);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

Просмотреть файл

@ -447,12 +447,12 @@ class nsHttpChannel final : public HttpBaseChannel,
nsHttpResponseHead* aResponseHead);
/**
* A function to process HTTP Strict Transport Security (HSTS) headers.
* Some basic consistency checks have been applied to the channel. Called
* A function to process a single security header (STS or PKP), assumes
* some basic sanity checks have been applied to the channel. Called
* from ProcessSecurityHeaders.
*/
[[nodiscard]] nsresult ProcessHSTSHeader(nsITransportSecurityInfo* aSecInfo,
uint32_t aFlags);
[[nodiscard]] nsresult ProcessSingleSecurityHeader(
uint32_t aType, nsITransportSecurityInfo* aSecInfo, uint32_t aFlags);
void InvalidateCacheEntryForLocation(const char* location);
void AssembleCacheKey(const char* spec, uint32_t postID, nsACString& key);

Просмотреть файл

@ -1,14 +1,9 @@
[DEFAULT]
tags = psm
support-files =
*.pem
head.js
hsts_headers.sjs
hsts_headers_framed.html
some_content.html
some_content_framed.html
*.pem
[browser_HSTS.js]
[browser_bug627234_perwindowpb.js]
[browser_certificateManager.js]
[browser_certViewer.js]

Просмотреть файл

@ -1,271 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that HTTP Strict Transport Security (HSTS) headers are noted as appropriate.
// Register a cleanup function to clear all accumulated HSTS state when this
// test is done.
add_task(async function register_cleanup() {
registerCleanupFunction(() => {
let sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
sss.clearAll();
});
});
// In the absense of HSTS information, no upgrade should happen.
add_task(async function test_no_hsts_information_no_upgrade() {
let httpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http");
gBrowser.removeCurrentTab();
});
// Visit a secure site that sends an HSTS header to set up the rest of the
// test.
add_task(async function see_hsts_header() {
let setHstsUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) + "hsts_headers.sjs";
await BrowserTestUtils.openNewForegroundTab(gBrowser, setHstsUrl);
gBrowser.removeCurrentTab();
});
// Given a known HSTS host, future http navigations to that domain will be
// upgraded.
add_task(async function test_http_upgrade() {
let httpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https");
gBrowser.removeCurrentTab();
});
// http navigations to unrelated hosts should not be upgraded.
add_task(async function test_unrelated_domain_no_upgrade() {
let differentHttpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.org"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, differentHttpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http");
gBrowser.removeCurrentTab();
});
// http navigations in private contexts shouldn't use information from
// non-private contexts, so no upgrade should occur.
add_task(async function test_private_window_no_upgrade() {
let privateWindow = OpenBrowserWindow({ private: true });
await BrowserTestUtils.firstBrowserLoaded(privateWindow, false);
let url =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(privateWindow.gBrowser, url);
Assert.equal(
privateWindow.gBrowser.selectedBrowser.currentURI.scheme,
"http"
);
privateWindow.gBrowser.removeCurrentTab();
privateWindow.close();
});
// Since the header didn't specify "includeSubdomains", visiting a subdomain
// should not result in an upgrade.
add_task(async function test_subdomain_no_upgrade() {
let subdomainHttpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://test1.example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http");
gBrowser.removeCurrentTab();
});
// Now visit a secure site that sends an HSTS header that also includes subdomains.
add_task(async function see_hsts_header_include_subdomains() {
let setHstsUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) + "hsts_headers.sjs?includeSubdomains";
await BrowserTestUtils.openNewForegroundTab(gBrowser, setHstsUrl);
gBrowser.removeCurrentTab();
});
// Now visiting a subdomain should result in an upgrade.
add_task(async function test_subdomain_upgrade() {
let subdomainHttpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://test1.example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https");
gBrowser.removeCurrentTab();
});
// Visiting a subdomain with https should result in an https URL (this isn't an
// upgrade - this test is essentially a consistency check).
add_task(async function test_already_https() {
let subdomainHttpsUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://test2.example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpsUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https");
gBrowser.removeCurrentTab();
});
// Test that subresources are upgraded.
add_task(async function test_iframe_upgrade() {
let framedUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) + "some_content_framed.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
await ContentTaskUtils.waitForCondition(() => {
let frame = content.document.getElementById("frame");
if (frame) {
return frame.baseURI.startsWith("https://");
}
return false;
});
});
gBrowser.removeCurrentTab();
});
// Clear state.
add_task(async function clear_hsts_state() {
let sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
sss.clearAll();
});
// Make sure this test is valid.
add_task(async function test_no_hsts_information_no_upgrade_again() {
let httpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http");
gBrowser.removeCurrentTab();
});
// Visit a site with an iframe that loads first-party content that sends an
// HSTS header. The header should be heeded because it's first-party.
add_task(async function see_hsts_header_in_framed_first_party_context() {
let framedUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) + "hsts_headers_framed.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
await ContentTaskUtils.waitForCondition(() => {
return content.document.getElementById("done");
});
});
gBrowser.removeCurrentTab();
});
// Check that the framed, first-party header was heeded.
add_task(async function test_http_upgrade_after_framed_first_party_header() {
let httpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https");
gBrowser.removeCurrentTab();
});
// Visit a site with an iframe that loads third-party content that sends an
// HSTS header. The header should be ignored because it's third-party.
add_task(async function see_hsts_header_in_third_party_context() {
let framedUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) + "hsts_headers_framed.html?third-party";
await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
await ContentTaskUtils.waitForCondition(() => {
return content.document.getElementById("done");
});
});
gBrowser.removeCurrentTab();
});
// Since the HSTS header was not received in a first-party context, no upgrade
// should occur.
add_task(async function test_no_upgrade_for_third_party_header() {
let url =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.org"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http");
gBrowser.removeCurrentTab();
});
// Clear state again.
add_task(async function clear_hsts_state_again() {
let sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
sss.clearAll();
});
// HSTS information encountered in private contexts should not be used in
// non-private contexts.
add_task(
async function test_no_upgrade_for_HSTS_information_from_private_window() {
let privateWindow = OpenBrowserWindow({ private: true });
await BrowserTestUtils.firstBrowserLoaded(privateWindow, false);
let setHstsUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"https://example.com"
) + "hsts_headers.sjs";
await BrowserTestUtils.openNewForegroundTab(
privateWindow.gBrowser,
setHstsUrl
);
privateWindow.gBrowser.removeCurrentTab();
let httpUrl =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
) + "some_content.html";
await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl);
Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http");
gBrowser.removeCurrentTab();
privateWindow.close();
}
);

Просмотреть файл

@ -1,15 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function handleRequest(request, response) {
let hstsHeader = "max-age=300";
if (request.queryString == "includeSubdomains") {
hstsHeader += "; includeSubdomains";
}
response.setHeader("Strict-Transport-Security", hstsHeader);
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/html", false);
response.setStatusLine(request.httpVersion, 200);
response.write("<!DOCTYPE html><html><body><h1>Ok!</h1></body></html>");
}

Просмотреть файл

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<script>
"use strict";
let src = document.location.href.replace("hsts_headers_framed.html", "hsts_headers.sjs");
if (document.location.search == "?third-party") {
src = src.replace("example.com", "example.org");
}
let frame = document.createElement("iframe");
frame.setAttribute("src", src);
frame.onload = () => {
let done = document.createElement("h1");
done.textContent = "done";
done.setAttribute("id", "done");
document.body.appendChild(done);
};
document.body.appendChild(frame);
</script>
</body>
</html>

Просмотреть файл

@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<h1>Some Content!</h1>
</body>
</html>

Просмотреть файл

@ -1,14 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<script>
"use strict";
let src = document.location.href.replace("https://", "http://");
let frame = document.createElement("iframe");
frame.setAttribute("id", "frame");
frame.setAttribute("src", src);
document.body.appendChild(frame);
</script>
</body>
</html>

Просмотреть файл

@ -7,4 +7,5 @@
TEST_DIRS += [
"browser",
"mixedcontent",
"stricttransportsecurity",
]

Просмотреть файл

@ -0,0 +1,6 @@
[DEFAULT]
tags = psm
skip-if = os == 'android'
support-files = page_blank.html
[test_sts_privatebrowsing_perwindowpb.html]

Просмотреть файл

@ -0,0 +1,12 @@
[DEFAULT]
tags = psm
support-files =
nosts_bootstrap.html
nosts_bootstrap.html^headers^
plain_bootstrap.html
plain_bootstrap.html^headers^
subdom_bootstrap.html
subdom_bootstrap.html^headers^
verify.sjs
[test_stricttransportsecurity.html]

Просмотреть файл

@ -0,0 +1,9 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
MOCHITEST_MANIFESTS += ["mochitest.ini"]
MOCHITEST_CHROME_MANIFESTS += ["chrome.ini"]

Просмотреть файл

@ -0,0 +1,28 @@
<!-- 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/. -->
<!DOCTYPE HTML>
<html>
<head>
<title>STS test iframe</title>
<script>
"use strict";
let windowRef = window;
window.addEventListener("load", function() {
windowRef.parent.postMessage("BOOTSTRAP plain",
"http://mochi.test:8888");
});
</script>
</head>
<body>
<!-- This frame should be loaded over HTTPS to set the STS header. -->
This frame was loaded using
<script>
"use strict";
// eslint-disable-next-line no-unsanitized/method
document.write(document.location.protocol);
</script>
and set the STS header to force this site and allow subdomain upgrading.
</body>
</html>

Просмотреть файл

@ -0,0 +1 @@
Cache-Control: no-cache

Просмотреть файл

@ -0,0 +1,5 @@
<html>
<body>
PAGE BLANK
</body>
</html>

Просмотреть файл

@ -0,0 +1,28 @@
<!-- 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/. -->
<!DOCTYPE HTML>
<html>
<head>
<title>STS test iframe</title>
<script>
"use strict";
let windowRef = window;
window.addEventListener("load", function() {
windowRef.parent.postMessage("BOOTSTRAP plain",
"http://mochi.test:8888");
});
</script>
</head>
<body>
<!-- This frame should be loaded over HTTPS to set the STS header. -->
This frame was loaded using
<script>
"use strict";
// eslint-disable-next-line no-unsanitized/method
document.write(document.location.protocol);
</script>
and set the STS header to force this site and allow subdomain upgrading.
</body>
</html>

Просмотреть файл

@ -0,0 +1,2 @@
Cache-Control: no-cache
Strict-Transport-Security: max-age=60

Просмотреть файл

@ -0,0 +1,28 @@
<!-- 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/. -->
<!DOCTYPE HTML>
<html>
<head>
<title>STS test iframe</title>
<script>
"use strict";
let windowRef = window;
window.addEventListener("load", function() {
windowRef.parent.postMessage("BOOTSTRAP subdom",
"http://mochi.test:8888");
});
</script>
</head>
<body>
<!-- This frame should be loaded over HTTPS to set the STS header. -->
This frame was loaded using
<script>
"use strict";
// eslint-disable-next-line no-unsanitized/method
document.write(document.location.protocol);
</script>
and set the STS header to force this site and allow subdomain upgrading.
</body>
</html>

Просмотреть файл

@ -0,0 +1,2 @@
Cache-Control: no-cache
Strict-Transport-Security: max-age=60; includeSubDomains

Просмотреть файл

@ -0,0 +1,126 @@
<!-- 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/. -->
<!DOCTYPE HTML>
<html>
<head>
<title>opens additional content that should be converted to https</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script class="testbody" type="text/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
const STSPATH =
"tests/security/manager/ssl/tests/mochitest/stricttransportsecurity";
// initialized manually here
var testsleft = {plain: 4, subdom: 4};
var roundsLeft = 2;
var testframes = {
samedom: {
url: `http://example.com/${STSPATH}/verify.sjs`,
expected: {plain: "SECURE", subdom: "SECURE"},
},
subdom: {
url: `http://test1.example.com/${STSPATH}/verify.sjs`,
expected: {plain: "INSECURE", subdom: "SECURE"},
},
otherdom: {
url: `http://example.org/${STSPATH}/verify.sjs`,
expected: {plain: "INSECURE", subdom: "INSECURE"},
},
alreadysecure: {
url: `https://test2.example.com/${STSPATH}/verify.sjs`,
expected: {plain: "SECURE", subdom: "SECURE"},
},
};
function startRound(round) {
let frame = document.createElement("iframe");
frame.setAttribute("id", "ifr_bootstrap");
frame.setAttribute("src",
`https://example.com/${STSPATH}/${round}_bootstrap.html`);
document.body.appendChild(frame);
}
function endRound(round) {
// remove all the iframes in the document
document.body.removeChild(document.getElementById("ifr_bootstrap"));
for (let test in testframes) {
document.body.removeChild(document.getElementById("ifr_" + test));
}
// clean up the STS state
SpecialPowers.cleanUpSTSData("http://example.com");
}
function loadVerifyFrames(round) {
for (let test in testframes) {
let frame = document.createElement("iframe");
frame.setAttribute("id", "ifr_" + test);
frame.setAttribute("src", testframes[test].url + "?id=" + test);
document.body.appendChild(frame);
}
}
/* Messages received are in this format:
* (BOOTSTRAP|SECURE|INSECURE) testid
* For example: "BOOTSTRAP plain"
* or: "INSECURE otherdom"
*/
function onMessageReceived(event) {
let result = event.data.split(/\s+/);
if (result.length != 2) {
SimpleTest.ok(false, event.data);
return;
}
// figure out which round of tests we're in
let round = (roundsLeft == 2) ? "plain" : "subdom";
if (result[0] === "BOOTSTRAP") {
loadVerifyFrames(round);
return;
}
// check if the result (SECURE/INSECURE) is expected for this round/test combo
SimpleTest.is(result[0], testframes[result[1]].expected[round],
"in ROUND " + round + ", test " + result[1]);
testsleft[round]--;
// check if there are more tests to run.
if (testsleft[round] < 1) {
// if not, advance to next round
endRound(round);
roundsLeft--;
// defer this so it doesn't muck with the stack too much.
if (roundsLeft == 1) {
setTimeout(function () {
startRound("subdom");
}, 0);
}
}
if (roundsLeft < 1) {
SimpleTest.finish();
}
}
// listen for calls back from the sts-setting iframe and then
// the verification frames.
window.addEventListener("message", onMessageReceived);
window.addEventListener("load", () => { startRound("plain"); });
</script>
</head>
<body>
This test will load some iframes and do some tests.
</body>
</html>

Просмотреть файл

@ -0,0 +1,268 @@
<!-- 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/. -->
<!DOCTYPE HTML>
<html>
<head>
<title>opens additional content that should be converted to https</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script class="testbody" type="text/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
const STSPATH =
"tests/security/manager/ssl/tests/mochitest/stricttransportsecurity";
const NUM_TEST_FRAMES = 4;
const CONTENT_PAGE =
"http://mochi.test:8888/chrome/security/manager/ssl/tests/mochitest/stricttransportsecurity/page_blank.html";
const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
// This is how many sub-tests (testframes) in each round.
// When the round begins, this will be initialized.
var testsleftinround = 0;
var currentround = "";
var mainWindow = window.browsingContext.topChromeWindow;
SpecialPowers.Services.prefs.setIntPref("browser.startup.page", 0);
SpecialPowers.Services.prefs.setBoolPref("privacy.partition.network_state", false);
var testframes = {
samedom: {
url: `http://example.com/${STSPATH}/verify.sjs`,
expected: {plain: "SECURE", subdom: "SECURE", nosts: "INSECURE"},
},
subdom: {
url: `http://test1.example.com/${STSPATH}/verify.sjs`,
expected: {plain: "INSECURE", subdom: "SECURE", nosts: "INSECURE"},
},
otherdom: {
url: `http://example.org/${STSPATH}/verify.sjs`,
expected: {plain: "INSECURE", subdom: "INSECURE", nosts: "INSECURE"},
},
alreadysecure: {
url: `https://test2.example.com/${STSPATH}/verify.sjs`,
expected: {plain: "SECURE", subdom: "SECURE", nosts: "SECURE"},
},
};
function whenDelayedStartupFinished(aWindow, aCallback) {
SpecialPowers.Services.obs.addObserver(function observer(aSubject, aTopic) {
if (aWindow == aSubject) {
SpecialPowers.Services.obs.removeObserver(observer, aTopic);
SimpleTest.executeSoon(aCallback);
}
}, "browser-delayed-startup-finished");
}
function testOnWindow(aIsPrivate, aCallback) {
let win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
(async function() {
await new Promise(resolve => whenDelayedStartupFinished(win, resolve));
let browser = win.gBrowser.selectedBrowser;
BrowserTestUtils.loadURI(browser, CONTENT_PAGE);
await BrowserTestUtils.browserLoaded(browser);
aCallback(win);
})();
}
function startRound(win, isPrivate, round) {
currentround = round;
testsleftinround = NUM_TEST_FRAMES;
SimpleTest.info("TESTS LEFT IN ROUND " + currentround + ": " + testsleftinround);
let browser = win.gBrowser.selectedBrowser;
let src = `https://example.com/${STSPATH}/${round}_bootstrap.html`;
SpecialPowers.spawn(browser, [src], async function(contentSrc) {
let frame = content.document.createElement("iframe");
frame.setAttribute("id", "ifr_bootstrap");
frame.setAttribute("src", contentSrc);
return new Promise(resolve => {
frame.addEventListener("load", () => resolve(), { once: true });
content.document.body.appendChild(frame);
});
}).then(() => {
onMessageReceived(win, isPrivate, "BOOTSTRAP " + round);
});
}
function loadVerifyFrames(win, isPrivate, round) {
loadVerifyFrame(win, isPrivate, testframes.samedom, "samedom", function() {
loadVerifyFrame(win, isPrivate, testframes.subdom, "subdom", function() {
loadVerifyFrame(win, isPrivate, testframes.otherdom, "otherdom", function() {
loadVerifyFrame(win, isPrivate, testframes.alreadysecure, "alreadysecure");
});
});
});
}
function loadVerifyFrame(win, isPrivate, test, testName, aCallback) {
let id = "ifr_" + testName;
let src = test.url + "?id=" + testName;
let browser = win.gBrowser.selectedBrowser;
SpecialPowers.spawn(browser, [[id, src]], async function([contentId, contentSrc]) {
let frame = content.document.createElement("iframe");
frame.setAttribute("id", contentId);
frame.setAttribute("src", contentSrc);
return new Promise(resolve => {
frame.addEventListener("load", () => {
resolve(frame.contentDocument.location.protocol);
});
content.document.body.appendChild(frame);
});
}).then(scheme => {
if (scheme == "https:") {
onMessageReceived(win, isPrivate, "SECURE " + testName);
} else {
onMessageReceived(win, isPrivate, "INSECURE " + testName);
}
if (aCallback) {
aCallback();
}
});
}
/**
* @param {DOMWindow} win
* Test window.
* @param {Boolean} isPrivate
* Whether the given window is in private browsing mode.
* @param {String} data
* A message that is expected to be in this format:
* (BOOTSTRAP|SECURE|INSECURE) testid
* For example: "BOOTSTRAP subdom"
* or: "INSECURE otherdom"
*/
function onMessageReceived(win, isPrivate, data) {
let result = data.split(/\s+/);
if (result.length != 2) {
SimpleTest.ok(false, data);
return;
}
if (result[0] === "BOOTSTRAP") {
loadVerifyFrames(win, isPrivate, currentround);
return;
}
// check if the result (SECURE/INSECURE) is expected for this round/test
// combo
dump_STSState(isPrivate);
SimpleTest.is(result[0], testframes[result[1]].expected[currentround],
"in ROUND " + currentround +
", test " + result[1]);
testsleftinround--;
// if this round is complete...
if (testsleftinround < 1) {
SimpleTest.info("DONE WITH ROUND " + currentround);
// remove all the iframes in the document
let browser = win.gBrowser.selectedBrowser;
SpecialPowers.spawn(browser, [testframes], async function(contentTestFrames) {
content.document.body.removeChild(
content.document.getElementById("ifr_bootstrap"));
for (let test in contentTestFrames) {
content.document.body.removeChild(
content.document.getElementById("ifr_" + test));
}
}).then(async () => {
currentround = "";
if (!isPrivate) {
await clean_up_sts_state(isPrivate);
}
// Close test window.
win.close();
// And advance to the next test.
// Defer this so it doesn't muck with the stack too much.
SimpleTest.executeSoon(nextTest);
});
}
}
function test_sts_before_private_mode() {
testOnWindow(false, function(win) {
SimpleTest.info("In public window");
dump_STSState(false);
startRound(win, false, "plain");
});
}
function test_sts_in_private_mode() {
testOnWindow(true, function(win) {
SimpleTest.info("In private window");
dump_STSState(true);
startRound(win, true, "subdom");
});
}
function test_sts_after_exiting_private_mode() {
testOnWindow(false, function(win) {
SimpleTest.info("In a new public window");
dump_STSState(false);
startRound(win, false, "nosts");
});
}
async function clean_up_sts_state(isPrivate) {
// erase all signs that this test ran.
SimpleTest.info("Cleaning up STS data");
let flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
await SpecialPowers.cleanUpSTSData("http://example.com", flags);
dump_STSState(isPrivate);
}
function dump_STSState(isPrivate) {
let sss = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
let flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
SimpleTest.info("State of example.com: " +
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
Services.io.newURI("https://example.com"), flags));
}
// These are executed in the order presented.
// 0. test that STS works before entering private browsing mode.
// (load sts-bootstrapped "plain" tests)
// ... clear any STS data ...
// 1. test that STS works in private browsing mode
// (load sts-bootstrapped "subdomain" tests)
// 2. test that after exiting private browsing, STS data is forgotten
// (verified with non-sts-bootstrapped pages)
// ... clear any STS data ...
var tests = [
test_sts_before_private_mode,
test_sts_in_private_mode,
test_sts_after_exiting_private_mode,
];
function finish() {
SpecialPowers.Services.prefs.clearUserPref("browser.startup.page");
SimpleTest.finish();
}
function nextTest() {
SimpleTest.executeSoon(tests.length ? tests.shift() : finish);
}
window.addEventListener("load", nextTest);
</script>
</head>
<body>
This test will load some iframes and do some tests.
</body>
</html>

Просмотреть файл

@ -0,0 +1,47 @@
/* 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/. */
// SJS file that serves un-cacheable responses for STS tests that postMessage
// to the parent saying whether or not they were loaded securely.
function handleRequest(request, response)
{
var query = {};
request.queryString.split('&').forEach(function (val) {
var [name, value] = val.split('=');
query[name] = unescape(value);
});
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/html", false);
if ('id' in query) {
var outstr = [
" <!DOCTYPE html>",
" <html> <head> <title>subframe for STS</title>",
" <script type='text/javascript'>",
" var self = window;",
" window.addEventListener('load', function() {",
" if (document.location.protocol === 'https:') {",
" self.parent.postMessage('SECURE " + query['id'] + "',",
" 'http://mochi.test:8888');",
" } else {",
" self.parent.postMessage('INSECURE " + query['id'] + "',",
" 'http://mochi.test:8888');",
" }",
" }, false);",
" </script>",
" </head>",
" <body>",
" STS state verification frame loaded via",
" <script>",
" document.write(document.location.protocol);",
" </script>",
" </body>",
" </html>"].join("\n");
response.write(outstr);
} else {
response.write("ERROR: no id provided");
}
}

Просмотреть файл

@ -140,8 +140,7 @@ add_task(async function test_subresource() {
Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE
);
// Load a secure subresource. HSTS won't be activated, since third
// parties can't set HSTS.
// Load a secure subresource to activate HSTS.
await SpecialPowers.spawn(
tab.linkedBrowser,
[secureImgURL],
@ -163,7 +162,7 @@ add_task(async function test_subresource() {
Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE
);
// Load an unsecure subresource. It should not be upgraded to https.
// Load a unsecure subresource, this should be upgraded to https.
await SpecialPowers.spawn(
tab.linkedBrowser,
[unsecureImgURL],
@ -174,7 +173,7 @@ add_task(async function test_subresource() {
}
);
is(await finalURL, unsecureImgURL, "HSTS isn't set for 3rd parties");
is(await finalURL, secureImgURL, "HSTS works for 3rd parties");
// Load the secure page with a different origin as first party.
await promiseTabLoadEvent(
@ -199,7 +198,11 @@ add_task(async function test_subresource() {
}
);
is(await finalURL, unsecureImgURL, "HSTS isn't set for 3rd parties");
if (networkIsolation) {
is(await finalURL, unsecureImgURL, "HSTS doesn't work for 3rd parties");
} else {
is(await finalURL, secureImgURL, "HSTS works for 3rd parties");
}
gBrowser.removeCurrentTab();
cleanupHSTS(networkIsolation, partitionPerSite);