diff options
Diffstat (limited to 'dom/security/test/hsts/head.js')
-rw-r--r-- | dom/security/test/hsts/head.js | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/dom/security/test/hsts/head.js b/dom/security/test/hsts/head.js new file mode 100644 index 000000000..362b36444 --- /dev/null +++ b/dom/security/test/hsts/head.js @@ -0,0 +1,308 @@ +/* + * Description of the tests: + * Check that HSTS priming occurs correctly with mixed content + * + * This test uses three hostnames, each of which treats an HSTS priming + * request differently. + * * no-ssl never returns an ssl response + * * reject-upgrade returns an ssl response, but with no STS header + * * prime-hsts returns an ssl response with the appropriate STS header + * + * For each server, test that it response appropriately when the we allow + * or block active or display content, as well as when we send an hsts priming + * request, but do not change the order of mixed-content and HSTS. + * + * Test use http-on-examine-response, so must be run in browser context. + */ +'use strict'; + +var TOP_URI = "https://example.com/browser/dom/security/test/hsts/file_priming-top.html"; + +var test_servers = { + // a test server that does not support TLS + 'no-ssl': { + host: 'example.co.jp', + response: false, + id: 'no-ssl', + }, + // a test server which does not support STS upgrade + 'reject-upgrade': { + host: 'example.org', + response: true, + id: 'reject-upgrade', + }, + // a test server when sends an STS header when priming + 'prime-hsts': { + host: 'test1.example.com', + response: true, + id: 'prime-hsts' + }, +}; + +var test_settings = { + // mixed active content is allowed, priming will upgrade + allow_active: { + block_active: false, + block_display: false, + use_hsts: true, + send_hsts_priming: true, + type: 'script', + result: { + 'no-ssl': 'insecure', + 'reject-upgrade': 'insecure', + 'prime-hsts': 'secure', + }, + }, + // mixed active content is blocked, priming will upgrade + block_active: { + block_active: true, + block_display: false, + use_hsts: true, + send_hsts_priming: true, + type: 'script', + result: { + 'no-ssl': 'blocked', + 'reject-upgrade': 'blocked', + 'prime-hsts': 'secure', + }, + }, + // keep the original order of mixed-content and HSTS, but send + // priming requests + hsts_after_mixed: { + block_active: true, + block_display: false, + use_hsts: false, + send_hsts_priming: true, + type: 'script', + result: { + 'no-ssl': 'blocked', + 'reject-upgrade': 'blocked', + 'prime-hsts': 'blocked', + }, + }, + // mixed display content is allowed, priming will upgrade + allow_display: { + block_active: true, + block_display: false, + use_hsts: true, + send_hsts_priming: true, + type: 'img', + result: { + 'no-ssl': 'insecure', + 'reject-upgrade': 'insecure', + 'prime-hsts': 'secure', + }, + }, + // mixed display content is blocked, priming will upgrade + block_display: { + block_active: true, + block_display: true, + use_hsts: true, + send_hsts_priming: true, + type: 'img', + result: { + 'no-ssl': 'blocked', + 'reject-upgrade': 'blocked', + 'prime-hsts': 'secure', + }, + }, + // mixed active content is blocked, priming will upgrade (css) + block_active_css: { + block_active: true, + block_display: false, + use_hsts: true, + send_hsts_priming: true, + type: 'css', + result: { + 'no-ssl': 'blocked', + 'reject-upgrade': 'blocked', + 'prime-hsts': 'secure', + }, + }, + // mixed active content is blocked, priming will upgrade + // redirect to the same host + block_active_with_redir_same: { + block_active: true, + block_display: false, + use_hsts: true, + send_hsts_priming: true, + type: 'script', + redir: 'same', + result: { + 'no-ssl': 'blocked', + 'reject-upgrade': 'blocked', + 'prime-hsts': 'secure', + }, + }, +} +// track which test we are on +var which_test = ""; + +const Observer = { + observe: function (subject, topic, data) { + switch (topic) { + case 'console-api-log-event': + return Observer.console_api_log_event(subject, topic, data); + case 'http-on-examine-response': + return Observer.http_on_examine_response(subject, topic, data); + case 'http-on-modify-request': + return Observer.http_on_modify_request(subject, topic, data); + } + throw "Can't handle topic "+topic; + }, + add_observers: function (services) { + services.obs.addObserver(Observer, "console-api-log-event", false); + services.obs.addObserver(Observer, "http-on-examine-response", false); + services.obs.addObserver(Observer, "http-on-modify-request", false); + }, + // When a load is blocked which results in an error event within a page, the + // test logs to the console. + console_api_log_event: function (subject, topic, data) { + var message = subject.wrappedJSObject.arguments[0]; + // when we are blocked, this will match the message we sent to the console, + // ignore everything else. + var re = RegExp(/^HSTS_PRIMING: Blocked ([-\w]+).*$/); + if (!re.test(message)) { + return; + } + + let id = message.replace(re, '$1'); + let curTest =test_servers[id]; + + if (!curTest) { + ok(false, "HSTS priming got a console message blocked, "+ + "but doesn't match expectations "+id+" (msg="+message); + return; + } + + is("blocked", test_settings[which_test].result[curTest.id], "HSTS priming "+ + which_test+":"+curTest.id+" expected "+ + test_settings[which_test].result[curTest.id]+", got blocked"); + test_settings[which_test].finished[curTest.id] = "blocked"; + }, + get_current_test: function(uri) { + for (let item in test_servers) { + let re = RegExp('https?://'+test_servers[item].host); + if (re.test(uri)) { + return test_servers[item]; + } + } + return null; + }, + http_on_modify_request: function (subject, topic, data) { + let channel = subject.QueryInterface(Ci.nsIHttpChannel); + if (channel.requestMethod != 'HEAD') { + return; + } + + let curTest = this.get_current_test(channel.URI.asciiSpec); + + if (!curTest) { + return; + } + + ok(!(curTest.id in test_settings[which_test].priming), "Already saw a priming request for " + curTest.id); + test_settings[which_test].priming[curTest.id] = true; + }, + // When we see a response come back, peek at the response and test it is secure + // or insecure as needed. Addtionally, watch the response for priming requests. + http_on_examine_response: function (subject, topic, data) { + let channel = subject.QueryInterface(Ci.nsIHttpChannel); + let curTest = this.get_current_test(channel.URI.asciiSpec); + + if (!curTest) { + return; + } + + let result = (channel.URI.asciiSpec.startsWith('https:')) ? "secure" : "insecure"; + + // This is a priming request, go ahead and validate we were supposed to see + // a response from the server + if (channel.requestMethod == 'HEAD') { + is(true, curTest.response, "HSTS priming response found " + curTest.id); + return; + } + + // This is the response to our query, make sure it matches + is(result, test_settings[which_test].result[curTest.id], + "HSTS priming result " + which_test + ":" + curTest.id); + test_settings[which_test].finished[curTest.id] = result; + }, +}; + +// opens `uri' in a new tab and focuses it. +// returns the newly opened tab +function openTab(uri) { + let tab = gBrowser.addTab(uri); + + // select tab and make sure its browser is focused + gBrowser.selectedTab = tab; + tab.ownerDocument.defaultView.focus(); + + return tab; +} + +function clear_sts_data() { + for (let test in test_servers) { + SpecialPowers.cleanUpSTSData('http://'+test_servers[test].host); + } +} + +function do_cleanup() { + clear_sts_data(); + + Services.obs.removeObserver(Observer, "console-api-log-event"); + Services.obs.removeObserver(Observer, "http-on-examine-response"); +} + +function SetupPrefTestEnvironment(which, additional_prefs) { + which_test = which; + clear_sts_data(); + + var settings = test_settings[which]; + // priming counts how many priming requests we saw + settings.priming = {}; + // priming counts how many tests were finished + settings.finished= {}; + + var prefs = [["security.mixed_content.block_active_content", + settings.block_active], + ["security.mixed_content.block_display_content", + settings.block_display], + ["security.mixed_content.use_hsts", + settings.use_hsts], + ["security.mixed_content.send_hsts_priming", + settings.send_hsts_priming]]; + + if (additional_prefs) { + for (let idx in additional_prefs) { + prefs.push(additional_prefs[idx]); + } + } + + console.log("prefs=%s", prefs); + + SpecialPowers.pushPrefEnv({'set': prefs}); +} + +// make the top-level test uri +function build_test_uri(base_uri, host, test_id, type) { + return base_uri + + "?host=" + escape(host) + + "&id=" + escape(test_id) + + "&type=" + escape(type); +} + +// open a new tab, load the test, and wait for it to finish +function execute_test(test, mimetype) { + var src = build_test_uri(TOP_URI, test_servers[test].host, + test, test_settings[which_test].type); + + let tab = openTab(src); + test_servers[test]['tab'] = tab; + + let browser = gBrowser.getBrowserForTab(tab); + yield BrowserTestUtils.browserLoaded(browser); + + yield BrowserTestUtils.removeTab(tab); +} |