summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/subresource-integrity
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/subresource-integrity')
-rw-r--r--testing/web-platform/tests/subresource-integrity/META.yml5
-rw-r--r--testing/web-platform/tests/subresource-integrity/alternate.css1
-rw-r--r--testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css1
-rw-r--r--testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css.headers1
-rw-r--r--testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css1
-rw-r--r--testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css.sub.headers2
-rw-r--r--testing/web-platform/tests/subresource-integrity/crossorigin-ineligible-style.css1
-rw-r--r--testing/web-platform/tests/subresource-integrity/image.pngbin0 -> 18299 bytes
-rw-r--r--testing/web-platform/tests/subresource-integrity/script.js1
-rw-r--r--testing/web-platform/tests/subresource-integrity/sri-test-helpers.sub.js43
-rw-r--r--testing/web-platform/tests/subresource-integrity/style.css1
-rw-r--r--testing/web-platform/tests/subresource-integrity/subresource-integrity.html468
-rw-r--r--testing/web-platform/tests/subresource-integrity/tools/generate_javascript.py52
-rw-r--r--testing/web-platform/tests/subresource-integrity/tools/list_hashes.py57
14 files changed, 634 insertions, 0 deletions
diff --git a/testing/web-platform/tests/subresource-integrity/META.yml b/testing/web-platform/tests/subresource-integrity/META.yml
new file mode 100644
index 0000000000..f6980682f1
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/META.yml
@@ -0,0 +1,5 @@
+spec: https://w3c.github.io/webappsec-subresource-integrity/
+suggested_reviewers:
+ - metromoxie
+ - mikewest
+ - hillbrad
diff --git a/testing/web-platform/tests/subresource-integrity/alternate.css b/testing/web-platform/tests/subresource-integrity/alternate.css
new file mode 100644
index 0000000000..0ea6d22ec7
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/alternate.css
@@ -0,0 +1 @@
+.testdiv{ background-color: red }
diff --git a/testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css b/testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css
new file mode 100644
index 0000000000..3cde4df12c
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css
@@ -0,0 +1 @@
+.testdiv{ background-color: yellow }
diff --git a/testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css.headers b/testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/crossorigin-anon-style.css.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css b/testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css
new file mode 100644
index 0000000000..3cde4df12c
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css
@@ -0,0 +1 @@
+.testdiv{ background-color: yellow }
diff --git a/testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css.sub.headers b/testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css.sub.headers
new file mode 100644
index 0000000000..d6af1f0dea
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/crossorigin-creds-style.css.sub.headers
@@ -0,0 +1,2 @@
+Access-Control-Allow-Origin: {{location[scheme]}}://{{domains[]}}{{GET[acao_port]}}
+Access-Control-Allow-Credentials: true
diff --git a/testing/web-platform/tests/subresource-integrity/crossorigin-ineligible-style.css b/testing/web-platform/tests/subresource-integrity/crossorigin-ineligible-style.css
new file mode 100644
index 0000000000..3cde4df12c
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/crossorigin-ineligible-style.css
@@ -0,0 +1 @@
+.testdiv{ background-color: yellow }
diff --git a/testing/web-platform/tests/subresource-integrity/image.png b/testing/web-platform/tests/subresource-integrity/image.png
new file mode 100644
index 0000000000..01c9666a8d
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/image.png
Binary files differ
diff --git a/testing/web-platform/tests/subresource-integrity/script.js b/testing/web-platform/tests/subresource-integrity/script.js
new file mode 100644
index 0000000000..bfca1efbf3
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/script.js
@@ -0,0 +1 @@
+// nothing important.
diff --git a/testing/web-platform/tests/subresource-integrity/sri-test-helpers.sub.js b/testing/web-platform/tests/subresource-integrity/sri-test-helpers.sub.js
new file mode 100644
index 0000000000..53102d4544
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/sri-test-helpers.sub.js
@@ -0,0 +1,43 @@
+// This horrible hack is needed for the 'use-credentials' tests because, on
+// response, if port 80 or 443 is the current port, it will not appear to
+// the browser as part of the origin string. Since the origin *string* is
+// used for CORS access control, instead of the origin itself, if there
+// isn't an exact string match, the check will fail. For example,
+// "http://example.com" would not match "http://example.com:80", because
+// they are not exact string matches, even though the origins are the same.
+//
+// Thus, we only want the Access-Control-Allow-Origin header to have
+// the port if it's not port 80 or 443, since the user agent will elide the
+// ports in those cases.
+const main_domain = '{{domains[]}}';
+const www_domain = '{{domains[www]}}';
+const default_port = (location.protocol === 'https:') ? '{{ports[https][0]}}' :
+ '{{ports[http][0]}}';
+
+const port_string = (default_port !== '80' && default_port !== '443') ?
+ `:${default_port}` : '';
+const www_host_and_port = www_domain + port_string;
+
+// General resource prefixes.
+const same_origin_prefix = '/subresource-integrity/';
+const xorigin_prefix = `${location.protocol}//${www_host_and_port}/subresource-integrity/`;
+
+// General resource suffixes, for piping CORS headers.
+const anonymous = '&pipe=header(Access-Control-Allow-Origin,*)';
+const use_credentials = "&pipe=header(Access-Control-Allow-Credentials,true)|" +
+ "header(Access-Control-Allow-Origin," + location.origin + ")";
+
+// Note that all of these style URLs have query parameters started, so any
+// additional parameters should be appended starting with '&'.
+const xorigin_anon_style = location.protocol
+ + '//' + www_host_and_port
+ + '/subresource-integrity/crossorigin-anon-style.css?';
+
+const xorigin_creds_style = location.protocol
+ + '//' + www_host_and_port
+ + '/subresource-integrity/crossorigin-creds-style.css?acao_port='
+ + port_string;
+
+const xorigin_ineligible_style = location.protocol
+ + '//' + www_host_and_port
+ + '/subresource-integrity/crossorigin-ineligible-style.css?';
diff --git a/testing/web-platform/tests/subresource-integrity/style.css b/testing/web-platform/tests/subresource-integrity/style.css
new file mode 100644
index 0000000000..3cde4df12c
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/style.css
@@ -0,0 +1 @@
+.testdiv{ background-color: yellow }
diff --git a/testing/web-platform/tests/subresource-integrity/subresource-integrity.html b/testing/web-platform/tests/subresource-integrity/subresource-integrity.html
new file mode 100644
index 0000000000..355e1da1d7
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/subresource-integrity.html
@@ -0,0 +1,468 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Subresource Integrity</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/sriharness.js"></script>
+<script src="/common/utils.js"></script>
+<script src="sri-test-helpers.sub.js"></script>
+
+<div id="log"></div>
+
+<div id="container"></div>
+<script>
+ var style_tests = [];
+ style_tests.execute = function() {
+ if (this.length > 0) {
+ this.shift().execute();
+ }
+ }
+ add_result_callback(function(res) {
+ if (res.name.startsWith("Style: ")) {
+ style_tests.execute();
+ }
+ });
+
+ // Script tests
+ new SRIScriptTest(
+ true,
+ "Same-origin with correct sha256 hash.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with correct sha384 hash.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha384-cINXh+nCzEHPWzXS7eoT+vYMBpyqczOybRLNU3XAButFWCRhHT5hLByIbPRqIm2f"
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with correct sha512 hash.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha512-KZdenhzBd7X7Q/vmaOSyvFz1CGdoVt26xzCZjlkU9lfBEK+V/ougGys7iYDi0+tOHIQSQa87bIqx95R7GU7I9Q=="
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with empty integrity.",
+ `${same_origin_prefix}script.js?${token()}`,
+ ""
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "Same-origin with incorrect hash.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ ).execute();
+
+ // Scripts with integrity attribute changed after #prepare-a-script.
+ new SRIScriptTest(
+ false,
+ "Same-origin with incorrect integrity => cleared after prepare.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead",
+ undefined,
+ undefined,
+ null
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "Same-origin with incorrect integrity => set to correct hash after prepare.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead",
+ undefined,
+ undefined,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with empty integrity => set to incorrect hash after prepare.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "",
+ undefined,
+ undefined,
+ "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with correct integrity => set to incorrect hash after prepare.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
+ undefined,
+ undefined,
+ "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with multiple sha256 hashes, including correct.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA= sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with multiple sha256 hashes, including unknown algorithm.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA= foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with sha256 mismatch, sha512 match",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha512-KZdenhzBd7X7Q/vmaOSyvFz1CGdoVt26xzCZjlkU9lfBEK+V/ougGys7iYDi0+tOHIQSQa87bIqx95R7GU7I9Q== sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "Same-origin with sha256 match, sha512 mismatch",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha512-deadbeefspbnUnwooKGNNCb39nvg+EW0O9hDScTXeo/9pVZztLSUYU3LNV6H0lZapo8bCJUpyPPLAzE9fDzpxg== sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "<crossorigin='anonymous'> with correct hash, ACAO: *",
+ `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
+ "anonymous"
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "<crossorigin='anonymous'> with incorrect hash, ACAO: *",
+ `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
+ "sha256-deadbeefcSLlbFZCj1OACLxTxVck2TOrBTEdUbwz1yU=",
+ "anonymous"
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "<crossorigin='use-credentials'> with correct hash, CORS-eligible",
+ `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Credentials,true)|header(Access-Control-Allow-Origin,${location.origin})`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
+ "use-credentials"
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "<crossorigin='use-credentials'> with incorrect hash CORS-eligible",
+ `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Credentials,true)|header(Access-Control-Allow-Origin,${location.origin})`,
+ "sha256-deadbeef2S+pTRZgiw3DWrhC6JLDlt2zRyGpwH7unU8=",
+ "use-credentials"
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "<crossorigin='anonymous'> with CORS-ineligible resource",
+ `${xorigin_prefix}script.js?${token()}`, /* no ACAO header makes this CORS-ineligible */
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=",
+ "anonymous"
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "Cross-origin, not CORS request, with correct hash",
+ `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="
+ ).execute();
+
+ new SRIScriptTest(
+ false,
+ "Cross-origin, not CORS request, with hash mismatch",
+ `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
+ "sha256-deadbeef01Y0yKSx3/UoIKtIY2UQ9+H8WGyyMuOWOC0="
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Cross-origin, empty integrity",
+ `${xorigin_prefix}script.js?${token()}&pipe=header(Access-Control-Allow-Origin,*)`,
+ ""
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with correct hash, options.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=?foo=bar?spam=eggs"
+ ).execute();
+
+ new SRIScriptTest(
+ true,
+ "Same-origin with unknown algorithm only.",
+ `${same_origin_prefix}script.js?${token()}`,
+ "foo666-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E="
+ ).execute();
+
+ // Style tests
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with correct sha256 hash",
+ {
+ href: "style.css?1",
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with correct sha384 hash",
+ {
+ href: "style.css?2",
+ integrity: "sha384-wDAWxH4tOWBwAwHfBn9B7XuNmFxHTMeigAMwn0iVQ0zq3FtmYMLxihcGnU64CwcX"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with correct sha512 hash",
+ {
+ href: "style.css?3",
+ integrity: "sha512-9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2HSZX4l6w=="
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with empty integrity",
+ {
+ href: "style.css?4",
+ integrity: ""
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "Same-origin with incorrect hash.",
+ {
+ href: "style.css?5",
+ integrity: "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with multiple sha256 hashes, including correct.",
+ {
+ href: "style.css?6",
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4= sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with multiple sha256 hashes, including unknown algorithm.",
+ {
+ href: "style.css?7",
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4= foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with sha256 mismatch, sha512 match",
+ {
+ href: "style.css?8",
+ integrity: "sha512-9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2HSZX4l6w== sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "Same-origin with sha256 match, sha512 mismatch",
+ {
+ href: "style.css?9",
+ integrity: "sha512-deadbeef9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2== sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "<crossorigin='anonymous'> with correct hash, ACAO: *",
+ {
+ href: xorigin_anon_style + '&1',
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
+ crossorigin: "anonymous"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "<crossorigin='anonymous'> with incorrect hash, ACAO: *",
+ {
+ href: xorigin_anon_style + '&2',
+ integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk=",
+ crossorigin: "anonymous"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "<crossorigin='use-credentials'> with correct hash, CORS-eligible",
+ {
+ href: xorigin_creds_style + '&1',
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
+ crossorigin: "use-credentials"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "<crossorigin='use-credentials'> with incorrect hash CORS-eligible",
+ {
+ href: xorigin_creds_style + '&2',
+ integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk=",
+ crossorigin: "use-credentials"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "<crossorigin='anonymous'> with CORS-ineligible resource",
+ {
+ href: xorigin_ineligible_style + '&1',
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
+ crossorigin: "anonymous"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "Cross-origin, not CORS request, with correct hash",
+ {
+ href: xorigin_anon_style + '&3',
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "Cross-origin, not CORS request, with hash mismatch",
+ {
+ href: xorigin_anon_style + '&4',
+ integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk="
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Cross-origin, empty integrity",
+ {
+ href: xorigin_anon_style + '&5',
+ integrity: ""
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with correct hash, options.",
+ {
+ href: "style.css?10",
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=?foo=bar?spam=eggs"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with unknown algorithm only.",
+ {
+ href: "style.css?11",
+ integrity: "foo666-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=?foo=bar?spam=eggs"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with correct sha256 hash, rel='stylesheet license'",
+ {
+ href: "style.css?12",
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
+ rel: "stylesheet license"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with correct sha256 hash, rel='license stylesheet'",
+ {
+ href: "style.css?13",
+ integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
+ rel: "license stylesheet"
+ }
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ true,
+ "Same-origin with correct sha256 and sha512 hash, rel='alternate stylesheet' enabled",
+ {
+ href: "alternate.css?1",
+ title: "alt",
+ type: "text/css",
+ class: "alternate",
+ disabled: "disabled",
+ rel: "alternate stylesheet",
+ integrity: "sha256-phbz83bWhnLig+d2VPKrRrTRyhqoDRo1ruGqZLZ0= sha512-8OYEB7ktnzcb6h+kB9CUIuc8qvKIyLpygRJdQSEEycRy74dUsB+Yu9rSjpOPjRUblle8WWX9Gn7v39LK2Oceig==",
+ },
+ function (link, container) {
+ var alternate = document.querySelector('link.alternate');
+ alternate.disabled = false;
+ },
+ "rgb(255, 0, 0)"
+ );
+
+ new SRIStyleTest(
+ style_tests,
+ false,
+ "Same-origin with incorrect sha256 and sha512 hash, rel='alternate stylesheet' enabled",
+ {
+ href: "alternate.css?2",
+ title: "alt",
+ type: "text/css",
+ class: "alternate",
+ disabled: "disabled",
+ rel: "alternate stylesheet",
+ integrity: "sha256-fail83bWhnLig+d2VPKrRrTRyhqoDRo1ruGqZLZ0= sha512-failB7ktnzcb6h+kB9CUIuc8qvKIyLpygRJdQSEEycRy74dUsB+Yu9rSjpOPjRUblle8WWX9Gn7v39LK2Oceig==",
+ },
+ function (link, container) {
+ var alternate = document.querySelector('link.alternate');
+ alternate.disabled = false;
+ }
+ );
+
+ style_tests.execute();
+
+</script>
+<!-- TODO check cache-poisoned resources, transfer-encoding, 3xx redirect
+ to resource with matching hash, and cross-origin leakage test as in sec5.3.
+ -->
diff --git a/testing/web-platform/tests/subresource-integrity/tools/generate_javascript.py b/testing/web-platform/tests/subresource-integrity/tools/generate_javascript.py
new file mode 100644
index 0000000000..fed3e5445f
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/tools/generate_javascript.py
@@ -0,0 +1,52 @@
+from os import path, listdir
+from hashlib import sha512, sha256, md5
+from base64 import b64encode
+import re
+
+JS_DIR = path.normpath(path.join(__file__, "..", ".."))
+
+'''
+Yield each file in the javascript directory
+'''
+def js_files():
+ for f in listdir(JS_DIR):
+ if path.isfile(f) and f.endswith(".js"):
+ yield f
+
+'''
+URL-safe base64 encode a binary digest and strip any padding.
+'''
+def format_digest(digest):
+ return b64encode(digest)
+
+'''
+Generate an encoded sha512 URI.
+'''
+def sha512_uri(content):
+ return "sha512-%s" % format_digest(sha512(content).digest())
+
+'''
+Generate an encoded sha256 URI.
+'''
+def sha256_uri(content):
+ return "sha256-%s" % format_digest(sha256(content).digest())
+
+'''
+Generate an encoded md5 digest URI.
+'''
+def md5_uri(content):
+ return "md5-%s" % format_digest(md5(content).digest())
+
+def main():
+ for file in js_files():
+ print("Generating content for %s" % file)
+ base = path.splitext(path.basename(file))[0]
+ var_name = re.sub(r"[^a-z0-9]", "_", base)
+ content = "%s=true;" % var_name
+ with open(file, "w") as f: f.write(content)
+ print("\tSHA512 integrity: %s" % sha512_uri(content))
+ print("\tSHA256 integrity: %s" % sha256_uri(content))
+ print("\tMD5 integrity: %s" % md5_uri(content))
+
+if __name__ == "__main__":
+ main()
diff --git a/testing/web-platform/tests/subresource-integrity/tools/list_hashes.py b/testing/web-platform/tests/subresource-integrity/tools/list_hashes.py
new file mode 100644
index 0000000000..52f46ffd74
--- /dev/null
+++ b/testing/web-platform/tests/subresource-integrity/tools/list_hashes.py
@@ -0,0 +1,57 @@
+from os import path, listdir
+from hashlib import sha512, sha384, sha256, md5
+from base64 import b64encode
+import re
+
+DIR = path.normpath(path.join(__file__, "..", ".."))
+
+'''
+Yield each javascript and css file in the directory
+'''
+def js_and_css_files():
+ for f in listdir(DIR):
+ if path.isfile(f) and (f.endswith(".js") or f.endswith(".css")):
+ yield f
+
+'''
+URL-safe base64 encode a binary digest and strip any padding.
+'''
+def format_digest(digest):
+ return b64encode(digest)
+
+'''
+Generate an encoded sha512 URI.
+'''
+def sha512_uri(content):
+ return "sha512-%s" % format_digest(sha512(content).digest())
+
+'''
+Generate an encoded sha384 URI.
+'''
+def sha384_uri(content):
+ return "sha384-%s" % format_digest(sha384(content).digest())
+
+'''
+Generate an encoded sha256 URI.
+'''
+def sha256_uri(content):
+ return "sha256-%s" % format_digest(sha256(content).digest())
+
+'''
+Generate an encoded md5 digest URI.
+'''
+def md5_uri(content):
+ return "md5-%s" % format_digest(md5(content).digest())
+
+def main():
+ for file in js_and_css_files():
+ print("Listing hash values for %s" % file)
+ with open(file, "r") as content_file:
+ content = content_file.read()
+ print("\tSHA512 integrity: %s" % sha512_uri(content))
+ print("\tSHA384 integrity: %s" % sha384_uri(content))
+ print("\tSHA256 integrity: %s" % sha256_uri(content))
+ print("\tMD5 integrity: %s" % md5_uri(content))
+
+if __name__ == "__main__":
+ main()