summaryrefslogtreecommitdiffstats
path: root/dom/security/test/contentverifier
diff options
context:
space:
mode:
Diffstat (limited to 'dom/security/test/contentverifier')
-rw-r--r--dom/security/test/contentverifier/browser.ini19
-rw-r--r--dom/security/test/contentverifier/browser_verify_content_about_newtab.js20
-rw-r--r--dom/security/test/contentverifier/browser_verify_content_about_newtab2.js19
-rw-r--r--dom/security/test/contentverifier/file_about_newtab.html11
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_bad.html11
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_bad_csp.html14
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_bad_csp_signature1
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_bad_signature1
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_broken_signature1
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_good_signature1
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_sri.html36
-rw-r--r--dom/security/test/contentverifier/file_about_newtab_sri_signature1
-rw-r--r--dom/security/test/contentverifier/file_contentserver.sjs261
-rw-r--r--dom/security/test/contentverifier/goodChain.pem51
-rw-r--r--dom/security/test/contentverifier/head.js210
-rw-r--r--dom/security/test/contentverifier/script.js1
-rw-r--r--dom/security/test/contentverifier/signature.derbin0 -> 103 bytes
-rw-r--r--dom/security/test/contentverifier/sk.pem9
-rw-r--r--dom/security/test/contentverifier/style.css3
19 files changed, 670 insertions, 0 deletions
diff --git a/dom/security/test/contentverifier/browser.ini b/dom/security/test/contentverifier/browser.ini
new file mode 100644
index 000000000..c41c2e8e8
--- /dev/null
+++ b/dom/security/test/contentverifier/browser.ini
@@ -0,0 +1,19 @@
+[DEFAULT]
+support-files =
+ file_contentserver.sjs
+ file_about_newtab.html
+ file_about_newtab_bad.html
+ file_about_newtab_bad_csp.html
+ file_about_newtab_bad_csp_signature
+ file_about_newtab_good_signature
+ file_about_newtab_bad_signature
+ file_about_newtab_broken_signature
+ file_about_newtab_sri.html
+ file_about_newtab_sri_signature
+ goodChain.pem
+ head.js
+ script.js
+ style.css
+
+[browser_verify_content_about_newtab.js]
+[browser_verify_content_about_newtab2.js]
diff --git a/dom/security/test/contentverifier/browser_verify_content_about_newtab.js b/dom/security/test/contentverifier/browser_verify_content_about_newtab.js
new file mode 100644
index 000000000..f63726ef8
--- /dev/null
+++ b/dom/security/test/contentverifier/browser_verify_content_about_newtab.js
@@ -0,0 +1,20 @@
+
+const TESTS = [
+ // { newtab (aboutURI) or regular load (url) : url,
+ // testStrings : expected strings in the loaded page }
+ { "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
+ { "aboutURI" : URI_ERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
+ { "url" : URI_BAD_FILE_CACHED, "testStrings" : [BAD_ABOUT_STRING] },
+ { "aboutURI" : URI_BAD_FILE_CACHED, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
+ { "aboutURI" : URI_SRI, "testStrings" : [
+ STYLESHEET_WITHOUT_SRI_BLOCKED,
+ STYLESHEET_WITH_SRI_LOADED,
+ SCRIPT_WITHOUT_SRI_BLOCKED,
+ SCRIPT_WITH_SRI_LOADED,
+ ]},
+ { "aboutURI" : URI_BAD_CSP, "testStrings" : [CSP_TEST_SUCCESS_STRING] },
+ { "url" : URI_CLEANUP, "testStrings" : [CLEANUP_DONE] },
+];
+
+add_task(runTests);
diff --git a/dom/security/test/contentverifier/browser_verify_content_about_newtab2.js b/dom/security/test/contentverifier/browser_verify_content_about_newtab2.js
new file mode 100644
index 000000000..a35ff6660
--- /dev/null
+++ b/dom/security/test/contentverifier/browser_verify_content_about_newtab2.js
@@ -0,0 +1,19 @@
+
+const TESTS = [
+ // { newtab (aboutURI) or regular load (url) : url,
+ // testStrings : expected strings in the loaded page }
+ { "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
+ { "aboutURI" : URI_ERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_KEYERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_SIGERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_NO_HEADER, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_BAD_SIG, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_BROKEN_SIG, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_BAD_X5U, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_HTTP_X5U, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_BAD_FILE, "testStrings" : [ABOUT_BLANK] },
+ { "aboutURI" : URI_BAD_ALL, "testStrings" : [ABOUT_BLANK] },
+ { "url" : URI_CLEANUP, "testStrings" : [CLEANUP_DONE] },
+];
+
+add_task(runTests);
diff --git a/dom/security/test/contentverifier/file_about_newtab.html b/dom/security/test/contentverifier/file_about_newtab.html
new file mode 100644
index 000000000..f274743b9
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1226928 -->
+<head>
+ <meta charset="utf-8">
+ <title>Testpage for bug 1226928</title>
+</head>
+<body>
+ Just a fully good testpage for Bug 1226928<br/>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_about_newtab_bad.html b/dom/security/test/contentverifier/file_about_newtab_bad.html
new file mode 100644
index 000000000..45899f4f4
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_bad.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1226928 -->
+<head>
+ <meta charset="utf-8">
+ <title>Testpage for bug 1226928</title>
+</head>
+<body>
+ Just a bad testpage for Bug 1226928<br/>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_about_newtab_bad_csp.html b/dom/security/test/contentverifier/file_about_newtab_bad_csp.html
new file mode 100644
index 000000000..f8044b73f
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_bad_csp.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Testpage for CSP violation (inline script)</title>
+</head>
+<body>
+ CSP violation test succeeded.
+ <script>
+ // This inline script would override the success string if loaded.
+ document.body.innerHTML = "CSP violation test failed.";
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_about_newtab_bad_csp_signature b/dom/security/test/contentverifier/file_about_newtab_bad_csp_signature
new file mode 100644
index 000000000..ded42dc9f
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_bad_csp_signature
@@ -0,0 +1 @@
+oiypz3lb-IyJsmKNsnlp2zDrqncste8yONn9WUE6ksgJWMhSEQ9lp8vRqN0W3JPwJb6uSk16RI-tDv7uy0jxon5jL1BZpqlqIpvimg7FCQEedMKoHZwtE9an-e95sOTd \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_about_newtab_bad_signature b/dom/security/test/contentverifier/file_about_newtab_bad_signature
new file mode 100644
index 000000000..73a3c1e34
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_bad_signature
@@ -0,0 +1 @@
+KirX94omQL7lKfWGhc777t8U29enDg0O0UcJLH3PRXcvWGO8KA6mmLS3yNCFnGiTjP3vNnVtm-sUkXr4ix8WTkKABkU4fEAi77sNOkLCKw40M9sDJOesmYInS_J2AuXX \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_about_newtab_broken_signature b/dom/security/test/contentverifier/file_about_newtab_broken_signature
new file mode 100644
index 000000000..468a167ff
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_broken_signature
@@ -0,0 +1 @@
+MGUCMFwSs3o95ukwBWXN1WbLgnpJ_uHWFiQROPm9zjrSqzlfiSMyLwJwIZzldWo_pBJtOwIxAJIfhXIiMVfl5NkFEJUUMxzu6FuxOJl5DCpG2wHLy9AhayLUzm4X4SpwZ6QBPapdTg \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_about_newtab_good_signature b/dom/security/test/contentverifier/file_about_newtab_good_signature
new file mode 100644
index 000000000..d826d49c3
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_good_signature
@@ -0,0 +1 @@
+HUndgHvxHNMiAe1SXoeyOOraUJCdxHqWkAYTu0Cq1KpAHcWZEVelNTvyXGbTLWj8btsmqNLAm08UlyK43q_2oO9DQfez3Fo8DhsKvm7TqgSXCkhUoxsYNanxWXhqw-Jw \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_about_newtab_sri.html b/dom/security/test/contentverifier/file_about_newtab_sri.html
new file mode 100644
index 000000000..4415c533a
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_sri.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1235572 -->
+<head>
+ <meta charset="utf-8">
+ <title>Testpage for bug 1235572</title>
+ <script>
+ function loaded(resource) {
+ document.getElementById("result").innerHTML += resource + " loaded\n";
+ }
+ function blocked(resource) {
+ document.getElementById("result").innerHTML += resource + " blocked\n";
+ }
+ </script>
+</head>
+<body>
+ Testing script loading without SRI for Bug 1235572<br/>
+ <div id="result"></div>
+
+ <!-- use css1 and css2 to make urls different to avoid the resource being cached-->
+ <link rel="stylesheet" href="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=css1"
+ onload="loaded('Stylesheet without SRI')"
+ onerror="blocked('Stylesheet without SRI')">
+ <link rel="stylesheet" href="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=css2"
+ integrity="sha384-/6Tvxh7SX39y62qePcvYoi5Vrf0lK8Ix3wJFLCYKI5KNJ5wIlCR8UsFC1OXwmwgd"
+ onload="loaded('Stylesheet with SRI')"
+ onerror="blocked('Stylesheet with SRI')">
+ <script src="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=script"
+ onload="loaded('Script without SRI')"
+ onerror="blocked('Script without SRI')"></script>
+ <script src="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=script"
+ integrity="sha384-zDCkvKOHXk8mM6Nk07oOGXGME17PA4+ydFw+hq0r9kgF6ZDYFWK3fLGPEy7FoOAo"
+ onload="loaded('Script with SRI')"
+ onerror="blocked('Script with SRI')"></script>
+</body>
+</html>
diff --git a/dom/security/test/contentverifier/file_about_newtab_sri_signature b/dom/security/test/contentverifier/file_about_newtab_sri_signature
new file mode 100644
index 000000000..b7ac17944
--- /dev/null
+++ b/dom/security/test/contentverifier/file_about_newtab_sri_signature
@@ -0,0 +1 @@
+yoIyAYiiEzdP1zpkRy3KaqdsjUy62Notku89cytwVwcH0x6fKsMCdM-df1wbk9N28CSTaIOW5kcSenFy5K3nU-zPIoqZDjQo6aSjF8hF6lrw1a1xbhfl9K3g4YJsuWsO \ No newline at end of file
diff --git a/dom/security/test/contentverifier/file_contentserver.sjs b/dom/security/test/contentverifier/file_contentserver.sjs
new file mode 100644
index 000000000..3ea49cdde
--- /dev/null
+++ b/dom/security/test/contentverifier/file_contentserver.sjs
@@ -0,0 +1,261 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* 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 for remote about:newtab (bug 1226928)
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.importGlobalProperties(["URLSearchParams"]);
+
+const path = "browser/dom/security/test/contentverifier/";
+
+const goodFileName = "file_about_newtab.html";
+const goodFileBase = path + goodFileName;
+const goodFile = FileUtils.getDir("TmpD", [], true);
+goodFile.append(goodFileName);
+const goodSignature = path + "file_about_newtab_good_signature";
+const goodX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\"";
+
+const scriptFileName = "script.js";
+const cssFileName = "style.css";
+const badFile = path + "file_about_newtab_bad.html";
+const brokenSignature = path + "file_about_newtab_broken_signature";
+const badSignature = path + "file_about_newtab_bad_signature";
+const badX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=bad\"";
+const httpX5UString = "\"http://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\"";
+
+const sriFile = path + "file_about_newtab_sri.html";
+const sriSignature = path + "file_about_newtab_sri_signature";
+
+const badCspFile = path + "file_about_newtab_bad_csp.html";
+const badCspSignature = path + "file_about_newtab_bad_csp_signature";
+
+// This cert chain is copied from
+// security/manager/ssl/tests/unit/test_content_signing/
+// using the certificates
+// * content_signing_remote_newtab_ee.pem
+// * content_signing_int.pem
+// * content_signing_root.pem
+const goodCertChainPath = path + "goodChain.pem";
+
+const tempFileNames = [goodFileName, scriptFileName, cssFileName];
+
+// we copy the file to serve as newtab to a temp directory because
+// we modify it during tests.
+setupTestFiles();
+
+function setupTestFiles() {
+ for (let fileName of tempFileNames) {
+ let tempFile = FileUtils.getDir("TmpD", [], true);
+ tempFile.append(fileName);
+ if (!tempFile.exists()) {
+ let fileIn = getFileName(path + fileName, "CurWorkD");
+ fileIn.copyTo(FileUtils.getDir("TmpD", [], true), "");
+ }
+ }
+}
+
+function getFileName(filePath, dir) {
+ // Since it's relative to the cwd of the test runner, we start there and
+ // append to get to the actual path of the file.
+ let testFile =
+ Cc["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get(dir, Components.interfaces.nsILocalFile);
+ let dirs = filePath.split("/");
+ for (let i = 0; i < dirs.length; i++) {
+ testFile.append(dirs[i]);
+ }
+ return testFile;
+}
+
+function loadFile(file) {
+ // Load a file to return it.
+ let testFileStream =
+ Cc["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Components.interfaces.nsIFileInputStream);
+ testFileStream.init(file, -1, 0, 0);
+ return NetUtil.readInputStreamToString(testFileStream,
+ testFileStream.available());
+}
+
+function appendToFile(aFile, content) {
+ try {
+ let file = FileUtils.openFileOutputStream(aFile, FileUtils.MODE_APPEND |
+ FileUtils.MODE_WRONLY);
+ file.write(content, content.length);
+ file.close();
+ } catch (e) {
+ dump(">>> Error in appendToFile "+e);
+ return "Error";
+ }
+ return "Done";
+}
+
+function truncateFile(aFile, length) {
+ let fileIn = loadFile(aFile);
+ fileIn = fileIn.slice(0, -length);
+
+ try {
+ let file = FileUtils.openFileOutputStream(aFile, FileUtils.MODE_WRONLY |
+ FileUtils.MODE_TRUNCATE);
+ file.write(fileIn, fileIn.length);
+ file.close();
+ } catch (e) {
+ dump(">>> Error in truncateFile "+e);
+ return "Error";
+ }
+ return "Done";
+}
+
+function cleanupTestFiles() {
+ for (let fileName of tempFileNames) {
+ let tempFile = FileUtils.getDir("TmpD", [], true);
+ tempFile.append(fileName);
+ tempFile.remove(true);
+ }
+}
+
+/*
+ * handle requests of the following form:
+ * sig=good&key=good&file=good&header=good&cached=no to serve pages with
+ * content signatures
+ *
+ * it further handles invalidateFile=yep and validateFile=yep to change the
+ * served file
+ */
+function handleRequest(request, response) {
+ let params = new URLSearchParams(request.queryString);
+ let x5uType = params.get("x5u");
+ let signatureType = params.get("sig");
+ let fileType = params.get("file");
+ let headerType = params.get("header");
+ let cached = params.get("cached");
+ let invalidateFile = params.get("invalidateFile");
+ let validateFile = params.get("validateFile");
+ let resource = params.get("resource");
+ let x5uParam = params.get("x5u");
+
+ if (params.get("cleanup")) {
+ cleanupTestFiles();
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("Done");
+ return;
+ }
+
+ if (resource) {
+ if (resource == "script") {
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write(loadFile(getFileName(scriptFileName, "TmpD")));
+ } else { // resource == "css1" || resource == "css2"
+ response.setHeader("Content-Type", "text/css", false);
+ response.write(loadFile(getFileName(cssFileName, "TmpD")));
+ }
+ return;
+ }
+
+ // if invalidateFile is set, this doesn't actually return a newtab page
+ // but changes the served file to invalidate the signature
+ // NOTE: make sure to make the file valid again afterwards!
+ if (invalidateFile) {
+ let r = "Done";
+ for (let fileName of tempFileNames) {
+ if (appendToFile(getFileName(fileName, "TmpD"), "!") != "Done") {
+ r = "Error";
+ }
+ }
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(r);
+ return;
+ }
+
+ // if validateFile is set, this doesn't actually return a newtab page
+ // but changes the served file to make the signature valid again
+ if (validateFile) {
+ let r = "Done";
+ for (let fileName of tempFileNames) {
+ if (truncateFile(getFileName(fileName, "TmpD"), 1) != "Done") {
+ r = "Error";
+ }
+ }
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(r);
+ return;
+ }
+
+ // we have to return the certificate chain on request for the x5u parameter
+ if (x5uParam && x5uParam == "default") {
+ response.setHeader("Cache-Control", "max-age=216000", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(loadFile(getFileName(goodCertChainPath, "CurWorkD")));
+ return;
+ }
+
+ // avoid confusing cache behaviours
+ if (!cached) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ } else {
+ response.setHeader("Cache-Control", "max-age=3600", false);
+ }
+
+ // send HTML to test allowed/blocked behaviours
+ response.setHeader("Content-Type", "text/html", false);
+
+ // set signature header and key for Content-Signature header
+ /* By default a good content-signature header is returned. Any broken return
+ * value has to be indicated in the url.
+ */
+ let csHeader = "";
+ let x5uString = goodX5UString;
+ let signature = goodSignature;
+ let file = goodFile;
+ if (x5uType == "bad") {
+ x5uString = badX5UString;
+ } else if (x5uType == "http") {
+ x5uString = httpX5UString;
+ }
+ if (signatureType == "bad") {
+ signature = badSignature;
+ } else if (signatureType == "broken") {
+ signature = brokenSignature;
+ } else if (signatureType == "sri") {
+ signature = sriSignature;
+ } else if (signatureType == "bad-csp") {
+ signature = badCspSignature;
+ }
+ if (fileType == "bad") {
+ file = getFileName(badFile, "CurWorkD");
+ } else if (fileType == "sri") {
+ file = getFileName(sriFile, "CurWorkD");
+ } else if (fileType == "bad-csp") {
+ file = getFileName(badCspFile, "CurWorkD");
+ }
+
+ if (headerType == "good") {
+ // a valid content-signature header
+ csHeader = "x5u=" + x5uString + ";p384ecdsa=" +
+ loadFile(getFileName(signature, "CurWorkD"));
+ } else if (headerType == "error") {
+ // this content-signature header is missing ; before p384ecdsa
+ csHeader = "x5u=" + x5uString + "p384ecdsa=" +
+ loadFile(getFileName(signature, "CurWorkD"));
+ } else if (headerType == "errorInX5U") {
+ // this content-signature header is missing the keyid directive
+ csHeader = "x6u=" + x5uString + ";p384ecdsa=" +
+ loadFile(getFileName(signature, "CurWorkD"));
+ } else if (headerType == "errorInSignature") {
+ // this content-signature header is missing the p384ecdsa directive
+ csHeader = "x5u=" + x5uString + ";p385ecdsa=" +
+ loadFile(getFileName(signature, "CurWorkD"));
+ }
+
+ if (csHeader) {
+ response.setHeader("Content-Signature", csHeader, false);
+ }
+ let result = loadFile(file);
+
+ response.write(result);
+}
diff --git a/dom/security/test/contentverifier/goodChain.pem b/dom/security/test/contentverifier/goodChain.pem
new file mode 100644
index 000000000..d5047cfc2
--- /dev/null
+++ b/dom/security/test/contentverifier/goodChain.pem
@@ -0,0 +1,51 @@
+-----BEGIN CERTIFICATE-----
+MIICUzCCAT2gAwIBAgIUJ1BtYqWRwUsVaZCGPp9eTHIC04QwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcTLajOmOgxU05q
+nAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/wAvBa9xof3cyD
+dKpuqc6jTjBMMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDUGA1UdEQQuMCyCKnJlbW90
+ZW5ld3RhYi5jb250ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzALBgkqhkiG9w0B
+AQsDggEBALiLck6k50ok9ahVq45P3feY1PeUXcIYZkJd8aPDYM+0kfg5+JyJBykA
+mtHWPE1QQjs7VRMfaLfu04E4UJMI2V1AON1qtgR9BQLctW85KFACg2omfiCKwJh0
+5Q8cxBFx9BpNMayqLJwHttB6oluxZFTB8CL/hfpbYpHz1bMEDCVSRP588YBrc8mV
+OLqzQK+k3ewwGvfD6SvXmTny37MxqwxdTPFJNnpqzKAsQIvz8Skic9BkA1NFk0Oq
+lsKKoiibbOCmwS9XY/laAkBaC3winuhciYAC0ImAopZ4PBCU0AOHGrNbhZXWYQxt
+uHBj34FqvIRCqgM06JCEwN0ULgix4kI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC0TCCAbugAwIBAgIUPcKbBQpKwTzrrlqzM+d3z5DWiNUwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBmludC1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMlMCMwDAYDVR0TBAUwAwEB/zAT
+BgNVHSUEDDAKBggrBgEFBQcDAzALBgkqhkiG9w0BAQsDggEBADDPjITgz8joxLRW
+wpLxELKSgO/KQ6iAXztjMHq9ovT7Fy0fqBnQ1mMVFr+sBXLgtUCM45aip6PjhUXc
+zs5Dq5STg+kz7qtmAjEQvOPcyictbgdu/K7+uMhXQhlzhOgyW88Uk5vrAezNTc/e
+TvSmWp1FcgVAfaeMN/90nzD1KIHoUt7zqZIz9ub8jXPVzQNZq4vh33smZhmbdTdV
+DaHUyef5cR1VTEGB+L1qzUIQqpHmD4UkMNP1nYedWfauiQhRt6Ql3rJSCRuEvsOA
+iBTJlwai/EFwfyfHkOV2GNgv+A5wHHEjBtF5c4PCxQEL5Vw+mfZHLsDVqF3279ZY
+lQ6jQ9g=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUKRLJoCmk0A6PHrNc8CxFn//4BYcwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyUwIzAMBgNVHRMEBTADAQH/MBMGA1Ud
+JQQMMAoGCCsGAQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAABgMK6EyVIXTjD5qaxPO
+DWz6yREACmAQBcowKWvfhwgi27DPSXyFGDbzTPEo+7RrIcXJkVAhLouGT51fCwTZ
+zb6Sgf6ztX7VSppY9AT4utvlZKP1xQ5WhIYsMtdHCHLHIkRjeWyoBEfUx50UXNLK
+Snl+A02GKYWiX+TLLg2DPN2s7v/mm8NLMQNgUlL7KakB2FHFyPa8otPpL4llg7UJ
+iBTVQ0c3JoiVbwZaY1Z8QinfMXUrTK9egUC4BAcId1dE8glzA5RRlw1fTLWpGApt
+hUmbDnl9N2a9NhGX323ypNzIATexafipzWe7bc4u/+bFdrUqnKUoEka73pZBdHdA
+FQ==
+-----END CERTIFICATE-----
diff --git a/dom/security/test/contentverifier/head.js b/dom/security/test/contentverifier/head.js
new file mode 100644
index 000000000..d9637d18b
--- /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);
+ }
+}
diff --git a/dom/security/test/contentverifier/script.js b/dom/security/test/contentverifier/script.js
new file mode 100644
index 000000000..8fd8f96b2
--- /dev/null
+++ b/dom/security/test/contentverifier/script.js
@@ -0,0 +1 @@
+var load=true;
diff --git a/dom/security/test/contentverifier/signature.der b/dom/security/test/contentverifier/signature.der
new file mode 100644
index 000000000..011b94142
--- /dev/null
+++ b/dom/security/test/contentverifier/signature.der
Binary files differ
diff --git a/dom/security/test/contentverifier/sk.pem b/dom/security/test/contentverifier/sk.pem
new file mode 100644
index 000000000..2ed514b9f
--- /dev/null
+++ b/dom/security/test/contentverifier/sk.pem
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDAzX2TrGOr0WE92AbAl+nqnpqh25pKCLYNMTV2hJHztrkVPWOp8w0mh
+scIodK8RMpagBwYFK4EEACKhZANiAATiTcWYbt0Wg63dO7OXvpptNG0ryxv+v+Js
+JJ5Upr3pFus5fZyKxzP9NPzB+oFhL/xw3jMx7X5/vBGaQ2sJSiNlHVkqZgzYF6JQ
+4yUyiqTY7v67CyfUPA1BJg/nxOS9m3o=
+-----END EC PRIVATE KEY-----
diff --git a/dom/security/test/contentverifier/style.css b/dom/security/test/contentverifier/style.css
new file mode 100644
index 000000000..c7ab9ecff
--- /dev/null
+++ b/dom/security/test/contentverifier/style.css
@@ -0,0 +1,3 @@
+#red-text {
+ color: red;
+}