Bug 1342178 - Pass origin attributes to isSecureURI in devtools and browser. r=keeler,past
☠☠ backed out by 3210020c5e49 ☠ ☠
authorJonathan Hao <jhao@mozilla.com>
Tue, 11 Apr 2017 10:14:10 +0800
changeset 560274 bc87945ba833e6004b877cf8507defff4ceee46f
parent 560273 db96edf786de1c5a776c4e2a277a2a327d88ff1f
child 560275 d30fe280e201f85aed8ba381c43b7e41fafc1bc9
push id53365
push userjichen@mozilla.com
push dateTue, 11 Apr 2017 08:35:12 +0000
reviewerskeeler, past
bugs1342178
milestone55.0a1
Bug 1342178 - Pass origin attributes to isSecureURI in devtools and browser. r=keeler,past MozReview-Commit-ID: HIOYH8iUUkO
browser/base/content/browser.js
browser/base/content/content.js
browser/base/content/test/general/browser_aboutCertError.js
devtools/client/debugger/new/debugger.js
devtools/shared/webconsole/network-helper.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3019,17 +3019,18 @@ 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.securityInfoAsString,
+                         msg.data.originAttributesAsString);
       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);
@@ -3083,17 +3084,18 @@ 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) {
+  onCertError(browser, elementId, isTopFrame, location, securityInfoAsString,
+              originAttributesAsString) {
     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);
         }
@@ -3133,29 +3135,31 @@ var BrowserOnClick = {
 
       case "advancedButton":
         if (isTopFrame) {
           secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS);
         }
 
         securityInfo = getSecurityInfo(securityInfoAsString);
         let errorInfo = getDetailedCertErrorInfo(location,
-                                                 securityInfo);
+                                                 securityInfo,
+                                                 JSON.parse(originAttributesAsString));
         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);
+                                                    securityInfo,
+                                                    JSON.parse(originAttributesAsString));
         gClipboardHelper.copyString(detailedInfo);
         break;
 
     }
   },
 
   onAboutBlocked(elementId, reason, isTopFrame, location, blockedInfo) {
     // Depending on what page we are displaying here (malware/phishing/unwanted)
@@ -3410,17 +3414,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) {
+function getDetailedCertErrorInfo(location, securityInfo, originAttributes) {
   if (!securityInfo)
     return "";
 
   let certErrorDetails = location;
   let code = securityInfo.errorCode;
   let errors = Cc["@mozilla.org/nss_errors_service;1"]
                   .getService(Ci.nsINSSErrorsService);
 
@@ -3431,18 +3435,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);
-  let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags);
+  let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags, originAttributes);
+  let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags, originAttributes);
   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,16 +288,24 @@ 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);
@@ -596,16 +604,17 @@ 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,20 +254,23 @@ 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
+      securityInfoAsString: serializedSecurityInfo,
+      originAttributesAsString: serializedOriginAttributes,
     };
   });
   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");
@@ -323,20 +326,23 @@ 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
+      securityInfoAsString: serializedSecurityInfo,
+      originAttributesAsString: serializedOriginAttributes,
     };
   });
   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,20 +8935,30 @@ 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;
 
-	        let host = httpActivity.hostname;
-
-	        info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
-	        info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
+	        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);
 	      } 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,18 +639,24 @@ 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);
         }
 
-        info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags);
-        info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags);
+        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);
       } 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.