summaryrefslogtreecommitdiff
path: root/dom/security/test/contentverifier/head.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/security/test/contentverifier/head.js')
-rw-r--r--dom/security/test/contentverifier/head.js210
1 files changed, 210 insertions, 0 deletions
diff --git a/dom/security/test/contentverifier/head.js b/dom/security/test/contentverifier/head.js
new file mode 100644
index 0000000000..d9637d18b7
--- /dev/null
+++ b/dom/security/test/contentverifier/head.js
@@ -0,0 +1,210 @@
+/*
+ * Test Content-Signature for remote about:newtab
+ * - Bug 1226928 - allow about:newtab to load remote content
+ *
+ * This tests content-signature verification on remote about:newtab in the
+ * following cases (see TESTS, all failed loads display about:blank fallback):
+ * - good case (signature should verify and correct page is displayed)
+ * - reload of newtab when the siganture was invalidated after the last correct
+ * load
+ * - malformed content-signature header
+ * - malformed keyid directive
+ * - malformed p384ecdsa directive
+ * - wrong signature (this is not a siganture for the delivered document)
+ * - invalid signature (this is not even a signature)
+ * - loading a file that doesn't fit the key or signature
+ * - cache poisoning (load a malicious remote page not in newtab, subsequent
+ * newtab load has to load the fallback)
+ */
+
+const ABOUT_NEWTAB_URI = "about:newtab";
+
+const BASE = "https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?";
+const URI_GOOD = BASE + "sig=good&x5u=good&file=good&header=good";
+
+const INVALIDATE_FILE = BASE + "invalidateFile=yep";
+const VALIDATE_FILE = BASE + "validateFile=yep";
+
+const URI_HEADER_BASE = BASE + "sig=good&x5u=good&file=good&header=";
+const URI_ERROR_HEADER = URI_HEADER_BASE + "error";
+const URI_KEYERROR_HEADER = URI_HEADER_BASE + "errorInX5U";
+const URI_SIGERROR_HEADER = URI_HEADER_BASE + "errorInSignature";
+const URI_NO_HEADER = URI_HEADER_BASE + "noHeader";
+
+const URI_BAD_SIG = BASE + "sig=bad&x5u=good&file=good&header=good";
+const URI_BROKEN_SIG = BASE + "sig=broken&x5u=good&file=good&header=good";
+const URI_BAD_X5U = BASE + "sig=good&x5u=bad&file=good&header=good";
+const URI_HTTP_X5U = BASE + "sig=good&x5u=http&file=good&header=good";
+const URI_BAD_FILE = BASE + "sig=good&x5u=good&file=bad&header=good";
+const URI_BAD_ALL = BASE + "sig=bad&x5u=bad&file=bad&header=bad";
+const URI_BAD_CSP = BASE + "sig=bad-csp&x5u=good&file=bad-csp&header=good";
+
+const URI_BAD_FILE_CACHED = BASE + "sig=good&x5u=good&file=bad&header=good&cached=true";
+
+const GOOD_ABOUT_STRING = "Just a fully good testpage for Bug 1226928";
+const BAD_ABOUT_STRING = "Just a bad testpage for Bug 1226928";
+const ABOUT_BLANK = "<head></head><body></body>";
+
+const URI_CLEANUP = BASE + "cleanup=true";
+const CLEANUP_DONE = "Done";
+
+const URI_SRI = BASE + "sig=sri&x5u=good&file=sri&header=good";
+const STYLESHEET_WITHOUT_SRI_BLOCKED = "Stylesheet without SRI blocked";
+const STYLESHEET_WITH_SRI_BLOCKED = "Stylesheet with SRI blocked";
+const STYLESHEET_WITH_SRI_LOADED = "Stylesheet with SRI loaded";
+const SCRIPT_WITHOUT_SRI_BLOCKED = "Script without SRI blocked";
+const SCRIPT_WITH_SRI_BLOCKED = "Script with SRI blocked";
+const SCRIPT_WITH_SRI_LOADED = "Script with SRI loaded";
+
+const CSP_TEST_SUCCESS_STRING = "CSP violation test succeeded.";
+
+// Needs to sync with pref "security.signed_content.CSP.default".
+const SIGNED_CONTENT_CSP = `{"csp-policies":[{"report-only":false,"script-src":["https://example.com","'unsafe-inline'"],"style-src":["https://example.com"]}]}`;
+
+var browser = null;
+var aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"]
+ .getService(Ci.nsIAboutNewTabService);
+
+function pushPrefs(...aPrefs) {
+ return new Promise((resolve) => {
+ SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve);
+ });
+}
+
+/*
+ * run tests with input from TESTS
+ */
+function doTest(aExpectedStrings, reload, aUrl, aNewTabPref) {
+ // set about:newtab location for this test if it's a newtab test
+ if (aNewTabPref) {
+ aboutNewTabService.newTabURL = aNewTabPref;
+ }
+
+ // set prefs
+ yield pushPrefs(
+ ["browser.newtabpage.remote.content-signing-test", true],
+ ["browser.newtabpage.remote", true],
+ ["security.content.signature.root_hash",
+ "CC:BE:04:87:74:B2:98:24:4A:C6:7A:71:BC:6F:DB:D6:C0:48:17:29:57:51:96:47:38:CC:24:C8:E4:F9:DD:CB"]);
+
+ if (aNewTabPref === URI_BAD_CSP) {
+ // Use stricter CSP to test CSP violation.
+ yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self'; style-src 'self'"]);
+ } else {
+ // Use weaker CSP to test normal content.
+ yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self' 'unsafe-inline'; style-src 'self'"]);
+ }
+
+ // start the test
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: aUrl,
+ },
+ function * (browser) {
+ // check if everything's set correct for testing
+ ok(Services.prefs.getBoolPref(
+ "browser.newtabpage.remote.content-signing-test"),
+ "sanity check: remote newtab signing test should be used");
+ ok(Services.prefs.getBoolPref("browser.newtabpage.remote"),
+ "sanity check: remote newtab should be used");
+ // we only check this if we really do a newtab test
+ if (aNewTabPref) {
+ ok(aboutNewTabService.overridden,
+ "sanity check: default URL for about:newtab should be overriden");
+ is(aboutNewTabService.newTabURL, aNewTabPref,
+ "sanity check: default URL for about:newtab should return the new URL");
+ }
+
+ // Every valid remote newtab page must have built-in CSP.
+ let shouldHaveCSP = ((aUrl === ABOUT_NEWTAB_URI) &&
+ (aNewTabPref === URI_GOOD || aNewTabPref === URI_SRI));
+
+ if (shouldHaveCSP) {
+ is(browser.contentDocument.nodePrincipal.cspJSON, SIGNED_CONTENT_CSP,
+ "Valid remote newtab page must have built-in CSP.");
+ }
+
+ yield ContentTask.spawn(
+ browser, aExpectedStrings, function * (aExpectedStrings) {
+ for (let expectedString of aExpectedStrings) {
+ ok(content.document.documentElement.innerHTML.includes(expectedString),
+ "Expect the following value in the result\n" + expectedString +
+ "\nand got " + content.document.documentElement.innerHTML);
+ }
+ });
+
+ // for good test cases we check if a reload fails if the remote page
+ // changed from valid to invalid in the meantime
+ if (reload) {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: INVALIDATE_FILE,
+ },
+ function * (browser2) {
+ yield ContentTask.spawn(browser2, null, function * () {
+ ok(content.document.documentElement.innerHTML.includes("Done"),
+ "Expect the following value in the result\n" + "Done" +
+ "\nand got " + content.document.documentElement.innerHTML);
+ });
+ }
+ );
+
+ browser.reload();
+ yield BrowserTestUtils.browserLoaded(browser);
+
+ let expectedStrings = [ABOUT_BLANK];
+ if (aNewTabPref == URI_SRI) {
+ expectedStrings = [
+ STYLESHEET_WITHOUT_SRI_BLOCKED,
+ STYLESHEET_WITH_SRI_BLOCKED,
+ SCRIPT_WITHOUT_SRI_BLOCKED,
+ SCRIPT_WITH_SRI_BLOCKED
+ ];
+ }
+ yield ContentTask.spawn(browser, expectedStrings,
+ function * (expectedStrings) {
+ for (let expectedString of expectedStrings) {
+ ok(content.document.documentElement.innerHTML.includes(expectedString),
+ "Expect the following value in the result\n" + expectedString +
+ "\nand got " + content.document.documentElement.innerHTML);
+ }
+ }
+ );
+
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: VALIDATE_FILE,
+ },
+ function * (browser2) {
+ yield ContentTask.spawn(browser2, null, function * () {
+ ok(content.document.documentElement.innerHTML.includes("Done"),
+ "Expect the following value in the result\n" + "Done" +
+ "\nand got " + content.document.documentElement.innerHTML);
+ });
+ }
+ );
+ }
+ }
+ );
+}
+
+function runTests() {
+ // run tests from TESTS
+ for (let i = 0; i < TESTS.length; i++) {
+ let testCase = TESTS[i];
+ let url = "", aNewTabPref = "";
+ let reload = false;
+ var aExpectedStrings = testCase.testStrings;
+ if (testCase.aboutURI) {
+ url = ABOUT_NEWTAB_URI;
+ aNewTabPref = testCase.aboutURI;
+ if (aNewTabPref == URI_GOOD || aNewTabPref == URI_SRI) {
+ reload = true;
+ }
+ } else {
+ url = testCase.url;
+ }
+
+ yield doTest(aExpectedStrings, reload, url, aNewTabPref);
+ }
+}