author | Wes Kocher <wkocher@mozilla.com> |
Mon, 10 Apr 2017 12:34:10 -0700 | |
changeset 560233 | 167230c49025646595e659ae92eb13ae442dcb71 |
parent 560232 | 4feb5533f54ac748cd335d2bdcad01811b95c6cf |
child 560234 | a21a26ea6947fe80775fda3a671381ae13342001 |
push id | 53365 |
push user | jichen@mozilla.com |
push date | Tue, 11 Apr 2017 08:35:12 +0000 |
reviewers | backout |
bugs | 1342178 |
milestone | 55.0a1 |
backs out | 7f9114ffbcae47f2870f542d62bb95dd6a0166aa f19289f0cfefc116efeb99cf02164c41238d2353 4afce44bc2b9f0793d81e868dafc73ffd0ddd3be db9b64a440120c4e259397b203cf11f82c6f1859 |
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3019,18 +3019,17 @@ var BrowserOnClick = { } }, receiveMessage(msg) { switch (msg.name) { case "Browser:CertExceptionError": this.onCertError(msg.target, msg.data.elementId, msg.data.isTopFrame, msg.data.location, - msg.data.securityInfoAsString, - msg.data.originAttributesAsString); + msg.data.securityInfoAsString); break; case "Browser:OpenCaptivePortalPage": CaptivePortalWatcher.ensureCaptivePortalTab(); break; case "Browser:SiteBlockedError": this.onAboutBlocked(msg.data.elementId, msg.data.reason, msg.data.isTopFrame, msg.data.location, msg.data.blockedInfo); @@ -3084,18 +3083,17 @@ var BrowserOnClick = { transportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo) let errorReporter = Cc["@mozilla.org/securityreporter;1"] .getService(Ci.nsISecurityReporter); errorReporter.reportTLSError(transportSecurityInfo, uri.host, uri.port); }, - onCertError(browser, elementId, isTopFrame, location, securityInfoAsString, - originAttributesAsString) { + onCertError(browser, elementId, isTopFrame, location, securityInfoAsString) { let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI"); let securityInfo; switch (elementId) { case "exceptionDialogButton": if (isTopFrame) { secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CLICK_ADD_EXCEPTION); } @@ -3135,31 +3133,29 @@ var BrowserOnClick = { case "advancedButton": if (isTopFrame) { secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS); } securityInfo = getSecurityInfo(securityInfoAsString); let errorInfo = getDetailedCertErrorInfo(location, - securityInfo, - JSON.parse(originAttributesAsString)); + securityInfo); browser.messageManager.sendAsyncMessage( "CertErrorDetails", { code: securityInfo.errorCode, info: errorInfo }); break; case "copyToClipboard": const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"] .getService(Ci.nsIClipboardHelper); securityInfo = getSecurityInfo(securityInfoAsString); let detailedInfo = getDetailedCertErrorInfo(location, - securityInfo, - JSON.parse(originAttributesAsString)); + securityInfo); gClipboardHelper.copyString(detailedInfo); break; } }, onAboutBlocked(elementId, reason, isTopFrame, location, blockedInfo) { // Depending on what page we are displaying here (malware/phishing/unwanted) @@ -3414,17 +3410,17 @@ function getSecurityInfo(securityInfoAsS return securityInfo; } /** * Returns a string with detailed information about the certificate validation * failure from the specified URI that can be used to send a report. */ -function getDetailedCertErrorInfo(location, securityInfo, originAttributes) { +function getDetailedCertErrorInfo(location, securityInfo) { if (!securityInfo) return ""; let certErrorDetails = location; let code = securityInfo.errorCode; let errors = Cc["@mozilla.org/nss_errors_service;1"] .getService(Ci.nsINSSErrorsService); @@ -3435,18 +3431,18 @@ function getDetailedCertErrorInfo(locati // SiteSecurityService uses different storage if the channel is // private. Thus we must give isSecureURI correct flags or we // might get incorrect results. let flags = PrivateBrowsingUtils.isWindowPrivate(window) ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0; let uri = Services.io.newURI(location); - let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags, originAttributes); - let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags, originAttributes); + let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags); + let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags); certErrorDetails += "\r\n\r\n" + gNavigatorBundle.getFormattedString("certErrorDetailsHSTS.label", [hasHSTS]); certErrorDetails += "\r\n" + gNavigatorBundle.getFormattedString("certErrorDetailsKeyPinning.label", [hasHPKP]); let certChain = "";
--- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -288,24 +288,16 @@ function getSiteBlockedErrorDetails(docS } addMessageListener("DeceptiveBlockedDetails", (message) => { sendAsyncMessage("DeceptiveBlockedDetails:Result", { blockedInfo: getSiteBlockedErrorDetails(docShell), }); }); -function getSerializedOriginAttributes(docShell) { - let originAttributes = {}; - if (docShell.failedChannel) { - originAttributes = docShell.failedChannel.loadInfo.originAttributes; - } - return JSON.stringify(originAttributes); -} - var AboutNetAndCertErrorListener = { init(chromeGlobal) { addMessageListener("CertErrorDetails", this); addMessageListener("Browser:CaptivePortalFreed", this); chromeGlobal.addEventListener("AboutNetErrorLoad", this, false, true); chromeGlobal.addEventListener("AboutNetErrorOpenCaptivePortal", this, false, true); chromeGlobal.addEventListener("AboutNetErrorSetAutomatic", this, false, true); chromeGlobal.addEventListener("AboutNetErrorResetPreferences", this, false, true); @@ -604,17 +596,16 @@ var ClickEventHandler = { let docShell = ownerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); sendAsyncMessage("Browser:CertExceptionError", { location: ownerDoc.location.href, elementId: targetElement.getAttribute("id"), isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView), securityInfoAsString: getSerializedSecurityInfo(docShell), - originAttributesAsString: getSerializedOriginAttributes(docShell), }); }, onAboutBlocked(targetElement, ownerDoc) { var reason = "phishing"; if (/e=malwareBlocked/.test(ownerDoc.documentURI)) { reason = "malware"; } else if (/e=unwantedBlocked/.test(ownerDoc.documentURI)) {
--- a/browser/base/content/test/general/browser_aboutCertError.js +++ b/browser/base/content/test/general/browser_aboutCertError.js @@ -254,23 +254,20 @@ add_task(function* checkAdvancedDetails( let text = doc.getElementById("certificateErrorText"); let serhelper = Cc["@mozilla.org/network/serialization-helper;1"] .getService(Ci.nsISerializationHelper); let serializable = docShell.failedChannel.securityInfo .QueryInterface(Ci.nsITransportSecurityInfo) .QueryInterface(Ci.nsISerializable); let serializedSecurityInfo = serhelper.serializeToString(serializable); - let originAttributes = docShell.failedChannel.loadInfo.originAttributes; - let serializedOriginAttributes = JSON.stringify(originAttributes); return { divDisplay: content.getComputedStyle(div).display, text: text.textContent, - securityInfoAsString: serializedSecurityInfo, - originAttributesAsString: serializedOriginAttributes, + securityInfoAsString: serializedSecurityInfo }; }); isnot(message.divDisplay, "none", "Debug information is visible"); ok(message.text.includes(BAD_CERT), "Correct URL found"); ok(message.text.includes("Certificate has expired"), "Correct error message found"); ok(message.text.includes("HTTP Strict Transport Security: false"), "Correct HSTS value found"); @@ -326,23 +323,20 @@ add_task(function* checkAdvancedDetailsF let text = doc.getElementById("certificateErrorText"); let serhelper = Cc["@mozilla.org/network/serialization-helper;1"] .getService(Ci.nsISerializationHelper); let serializable = docShell.failedChannel.securityInfo .QueryInterface(Ci.nsITransportSecurityInfo) .QueryInterface(Ci.nsISerializable); let serializedSecurityInfo = serhelper.serializeToString(serializable); - let originAttributes = docShell.failedChannel.loadInfo.originAttributes; - let serializedOriginAttributes = JSON.stringify(originAttributes); return { divDisplay: content.getComputedStyle(div).display, text: text.textContent, - securityInfoAsString: serializedSecurityInfo, - originAttributesAsString: serializedOriginAttributes, + securityInfoAsString: serializedSecurityInfo }; }); isnot(message.divDisplay, "none", "Debug information is visible"); ok(message.text.includes(badStsUri.spec), "Correct URL found"); ok(message.text.includes("requested domain name does not match the server\u2019s certificate"), "Correct error message found"); ok(message.text.includes("HTTP Strict Transport Security: false"), "Correct HSTS value found");
--- a/devtools/client/debugger/new/debugger.js +++ b/devtools/client/debugger/new/debugger.js @@ -8935,30 +8935,20 @@ return /******/ (function(modules) { // // SiteSecurityService uses different storage if the channel is // private. Thus we must give isSecureHost correct flags or we // might get incorrect results. let flags = (httpActivity.private) ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0; - if (!uri) { - // isSecureURI only cares about the host, not the scheme. - let host = httpActivity.hostname; - uri = Services.io.newURI("https://" + host); - } - - let originAttributes = {}; - if (httpActivity.channel) { - originAttributes = httpActivity.channel.loadInfo.originAttributes; - } - info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags, - originAttributes); - info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags, - originAttributes); + let host = httpActivity.hostname; + + info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags); + info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags); } else { DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo", "Could not get HSTS/HPKP status as hostname is not available."); info.hsts = false; info.hpkp = false; } } else {
--- a/devtools/shared/webconsole/network-helper.js +++ b/devtools/shared/webconsole/network-helper.js @@ -639,24 +639,18 @@ var NetworkHelper = { Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0; if (!uri) { // isSecureURI only cares about the host, not the scheme. let host = httpActivity.hostname; uri = Services.io.newURI("https://" + host); } - let originAttributes = {}; - if (httpActivity.channel) { - originAttributes = httpActivity.channel.loadInfo.originAttributes; - } - info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags, - originAttributes); - info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags, - originAttributes); + info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags); + info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags); } else { DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo", "Could not get HSTS/HPKP status as hostname is not available."); info.hsts = false; info.hpkp = false; } } else { // The connection failed.
--- a/devtools/shared/webconsole/test/chrome.ini +++ b/devtools/shared/webconsole/test/chrome.ini @@ -27,15 +27,16 @@ support-files = [test_jsterm.html] [test_jsterm_autocomplete.html] [test_jsterm_cd_iframe.html] [test_jsterm_last_result.html] [test_jsterm_queryselector.html] [test_network_get.html] [test_network_longstring.html] [test_network_post.html] -[test_network_security.html] +[test_network_security-hpkp.html] +[test_network_security-hsts.html] [test_nsiconsolemessage.html] [test_object_actor.html] [test_object_actor_native_getters.html] [test_object_actor_native_getters_lenient_this.html] [test_page_errors.html] [test_throw.html]
rename from devtools/shared/webconsole/test/test_network_security.html rename to devtools/shared/webconsole/test/test_network_security-hpkp.html --- a/devtools/shared/webconsole/test/test_network_security.html +++ b/devtools/shared/webconsole/test/test_network_security-hpkp.html @@ -9,187 +9,97 @@ - http://creativecommons.org/publicdomain/zero/1.0/ --> </head> <body> <p>Test for the network actor (HPKP detection)</p> <iframe src="https://example.com/chrome/devtools/shared/webconsole/test/network_requests_iframe.html"></iframe> <script class="testbody" type="text/javascript"> -Cu.import("resource://testing-common/BrowserTestUtils.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); - SimpleTest.waitForExplicitFinish(); let gCurrentTestCase = -1; const HPKP_PREF = "security.cert_pinning.process_headers_from_non_builtin_roots"; // Static pins tested by unit/test_security-info-static-hpkp.js. const TEST_CASES = [ { - desc: "no HSTS or HPKP", + desc: "no Public Key Pinning", url: "https://example.com", - usesHSTS: false, - usesPinning: false, - }, - { - desc: "HSTS from this response, no Public Key Pinning", - url: "https://example.com/" + - "browser/browser/base/content/test/general/browser_star_hsts.sjs", - usesHSTS: true, - usesPinning: false, - }, - { - desc: "stored HSTS from previous response, no Public Key Pinning", - url: "https://example.com/", - usesHSTS: true, usesPinning: false, }, { - desc: "no Public Key Pinning or HSTS", - url: "https://include-subdomains.pinning-dynamic.example.com/", - usesHSTS: false, - usesPinning: false, - }, - { - desc: "dynamic Public Key Pinning with this request, no HSTS", + desc: "dynamic Public Key Pinning with this request", url: "https://include-subdomains.pinning-dynamic.example.com/" + "browser/browser/base/content/test/general/pinning_headers.sjs", - usesHSTS: false, usesPinning: true, }, { - desc: "dynamic Public Key Pinning with previous request, no HSTS", + desc: "dynamic Public Key Pinning with previous request", url: "https://include-subdomains.pinning-dynamic.example.com/", - usesHSTS: false, usesPinning: true, } ]; -const TEST_MODES = [ "public", "private" ]; -let ALL_TESTS = []; - function startTest() { // Need to enable this pref or pinning headers are rejected due test // certificate. Services.prefs.setBoolPref(HPKP_PREF, true); SimpleTest.registerCleanupFunction(() => { Services.prefs.setBoolPref(HPKP_PREF, false); // Reset pinning state. let gSSService = Cc["@mozilla.org/ssservice;1"] .getService(Ci.nsISiteSecurityService); let gIOService = Cc["@mozilla.org/network/io-service;1"] .getService(Ci.nsIIOService); for (let {url} of TEST_CASES) { let uri = gIOService.newURI(url); - gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0); - gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, - Ci.nsISocketProvider.NO_PERMANENT_STORAGE, - { privateBrowsingId: 1 }); gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0); - gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, - Ci.nsISocketProvider.NO_PERMANENT_STORAGE, - { privateBrowsingId: 1 }); } }); - info("Test detection of HTTP Strict Transport Security" + - " and Public Key Pinning."); - for (let mode of TEST_MODES) { - for (let testCase of TEST_CASES) { - let test = { mode }; - for (let attr in testCase) { - test[attr] = testCase[attr]; - } - ALL_TESTS.push(test); - } - } - + info("Test detection of Public Key Pinning."); removeEventListener("load", startTest); attachConsoleToTab(["NetworkActivity"], onAttach); } function onAttach(state, response) { - let callback = onNetworkEventUpdate.bind(null, state); - state.dbgClient.addListener("networkEventUpdate", callback); + onNetworkEventUpdate = onNetworkEventUpdate.bind(null, state); + state.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate); runNextCase(state); } function runNextCase(state) { gCurrentTestCase++; - if (gCurrentTestCase === ALL_TESTS.length) { + if (gCurrentTestCase === TEST_CASES.length) { info("Tests ran. Cleaning up."); closeDebugger(state, SimpleTest.finish); return; } - let { desc, url, mode } = ALL_TESTS[gCurrentTestCase]; + let { desc, url } = TEST_CASES[gCurrentTestCase]; info("Testing site with " + desc); - if (mode == "private") { - info("Cleaning up the previous window."); - closeDebugger(state, runInPrivateWindow); - } else { - let iframe = document.querySelector("iframe").contentWindow; - iframe.wrappedJSObject.makeXhrCallback("GET", url); - } + let iframe = document.querySelector("iframe").contentWindow; + iframe.wrappedJSObject.makeXhrCallback("GET", url); } function onNetworkEventUpdate(state, type, packet) { function onSecurityInfo(received) { - let data = ALL_TESTS[gCurrentTestCase]; - is(received.securityInfo.hsts, data.usesHSTS, - "Strict Transport Security detected correctly."); + let data = TEST_CASES[gCurrentTestCase]; is(received.securityInfo.hpkp, data.usesPinning, "Public Key Pinning detected correctly."); runNextCase(state); } if (packet.updateType === "securityInfo") { state.client.getSecurityInfo(packet.from, onSecurityInfo); } } -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", false); -} - -let mainWindow = - window.QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem). - rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIDOMWindow); - -function runInPrivateWindow() { - let win = mainWindow.OpenBrowserWindow({private: true}); - - Task.spawn(function* () { - yield new Promise(resolve => whenDelayedStartupFinished(win, resolve)); - let browser = win.gBrowser.selectedBrowser; - let url = ALL_TESTS[gCurrentTestCase].url; - win.gBrowser.selectedTab = win.gBrowser.getTabForBrowser(browser); - - yield new Promise(function(resolve) { - attachConsoleToTab(["NetworkActivity"], function(state) { - let callback = onNetworkEventUpdate.bind(null, state); - state.dbgClient.addListener("networkEventUpdate", callback); - - resolve(); - }); - }); - - yield BrowserTestUtils.loadURI(browser, url); - }); -} - addEventListener("load", startTest); </script> </body> </html>
new file mode 100644 --- /dev/null +++ b/devtools/shared/webconsole/test/test_network_security-hsts.html @@ -0,0 +1,100 @@ +<!DOCTYPE HTML> +<html lang="en"> +<head> + <meta charset="utf8"> + <title>Test for the network actor (HSTS detection)</title> + <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="common.js"></script> + <!-- Any copyright is dedicated to the Public Domain. + - http://creativecommons.org/publicdomain/zero/1.0/ --> +</head> +<body> +<p>Test for the network actor (HSTS detection)</p> + +<iframe src="https://example.com/chrome/devtools/shared/webconsole/test/network_requests_iframe.html"></iframe> + +<script class="testbody" type="text/javascript"> +SimpleTest.waitForExplicitFinish(); + +let gCurrentTestCase = -1; +const TEST_CASES = [ + { + desc: "no HSTS", + url: "https://example.com", + usesHSTS: false, + }, + { + desc: "HSTS from this response", + url: "https://example.com/"+ + "browser/browser/base/content/test/general/browser_star_hsts.sjs", + usesHSTS: true, + }, + { + desc: "stored HSTS from previous response", + url: "https://example.com/", + usesHSTS: true, + } +]; + +function startTest() +{ + + SimpleTest.registerCleanupFunction(() => { + // Reset HSTS state. + let gSSService = Cc["@mozilla.org/ssservice;1"] + .getService(Ci.nsISiteSecurityService); + + let gIOService = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService); + + let uri = gIOService.newURI(TEST_CASES[0].url); + gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0); + }); + + info("Test detection of HTTP Strict Transport Security."); + removeEventListener("load", startTest); + attachConsoleToTab(["NetworkActivity"], onAttach); +} + +function onAttach(aState, aResponse) +{ + onNetworkEventUpdate = onNetworkEventUpdate.bind(null, aState); + aState.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate); + + runNextCase(aState); +} + +function runNextCase(aState) { + gCurrentTestCase++; + if (gCurrentTestCase === TEST_CASES.length) { + info("Tests ran. Cleaning up."); + closeDebugger(aState, SimpleTest.finish); + return; + } + + let { desc, url } = TEST_CASES[gCurrentTestCase]; + info("Testing site with " + desc); + + let iframe = document.querySelector("iframe").contentWindow; + iframe.wrappedJSObject.makeXhrCallback("GET", url); +} + +function onNetworkEventUpdate(aState, aType, aPacket) +{ + function onSecurityInfo(packet) { + let data = TEST_CASES[gCurrentTestCase]; + is(packet.securityInfo.hsts, data.usesHSTS, + "Strict Transport Security detected correctly."); + + runNextCase(aState); + } + + if (aPacket.updateType === "securityInfo") { + aState.client.getSecurityInfo(aPacket.from, onSecurityInfo); + } +} + +addEventListener("load", startTest); +</script> +</body> +</html>