Bug 1242886 - Change learn more link for unknown issuers on about:certerror. r=gijs
authorJohann Hofmann <jhofmann@mozilla.com>
Fri, 08 Apr 2016 16:01:51 +0200
changeset 317000 82d61d3c98215265a4f07ca313ecfb9eeb2aa9a1
parent 316999 761a291f2255e6139dfef556149d6f7d3406ba42
child 317001 6f5f9b50fe67263bfac71eafb3672a5ca8c7ab72
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs
bugs1242886
milestone48.0a1
Bug 1242886 - Change learn more link for unknown issuers on about:certerror. r=gijs
browser/base/content/browser.js
browser/base/content/content.js
browser/base/content/test/general/browser_aboutCertError.js
netwerk/base/nsINSSErrorsService.idl
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2759,26 +2759,25 @@ var BrowserOnClick = {
     let errorReporter = Cc["@mozilla.org/securityreporter;1"]
                           .getService(Ci.nsISecurityReporter);
     errorReporter.reportTLSError(transportSecurityInfo,
                                  uri.host, uri.port);
   },
 
   onCertError: function (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);
         }
 
-        let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
-                           .getService(Ci.nsISerializationHelper);
-        let securityInfo = serhelper.deserializeObject(securityInfoAsString);
+        securityInfo = getSecurityInfo(securityInfoAsString);
         let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
                                     .SSLStatus;
         let params = { exceptionAdded : false,
                        sslStatus : sslStatus };
 
         try {
           switch (Services.prefs.getIntPref("browser.ssl_override_behavior")) {
             case 2 : // Pre-fetch & pre-populate
@@ -2806,27 +2805,31 @@ var BrowserOnClick = {
         goBackFromErrorPage();
         break;
 
       case "advancedButton":
         if (isTopFrame) {
           secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS);
         }
 
+        securityInfo = getSecurityInfo(securityInfoAsString);
         let errorInfo = getDetailedCertErrorInfo(location,
-                                                 securityInfoAsString);
-        browser.messageManager.sendAsyncMessage("CertErrorDetails",
-                                                { info: errorInfo });
+                                                 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,
-                                                    securityInfoAsString);
+                                                    securityInfo);
         gClipboardHelper.copyString(detailedInfo);
         break;
 
     }
   },
 
   onAboutBlocked: function (elementId, reason, isTopFrame, location) {
     // Depending on what page we are displaying here (malware/phishing/unwanted)
@@ -3078,34 +3081,41 @@ function BrowserReloadWithFlags(reloadFl
 
   gBrowser.selectedBrowser
           .messageManager
           .sendAsyncMessage("Browser:Reload",
                             { flags: reloadFlags,
                               handlingUserInput: windowUtils.isHandlingUserInput });
 }
 
-/**
- * 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, securityInfoAsString) {
+function getSecurityInfo(securityInfoAsString) {
   if (!securityInfoAsString)
-    return "";
-
-  let certErrorDetails = location;
+    return null;
 
   const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                        .getService(Ci.nsISerializationHelper);
   let securityInfo = serhelper.deserializeObject(securityInfoAsString);
   securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
 
+  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) {
+  if (!securityInfo)
+    return "";
+
+  let certErrorDetails = location;
+  let code = securityInfo.errorCode;
   let errors = Cc["@mozilla.org/nss_errors_service;1"]
                   .getService(Ci.nsINSSErrorsService);
-  let code = securityInfo.errorCode;
+
   certErrorDetails += "\r\n\r\n" + errors.getErrorMessage(errors.getXPCOMFromNSSError(code));
 
   const sss = Cc["@mozilla.org/ssservice;1"]
                  .getService(Ci.nsISiteSecurityService);
   // SiteSecurityService uses different storage if the channel is
   // private. Thus we must give isSecureHost correct flags or we
   // might get incorrect results.
   let flags = PrivateBrowsingUtils.isWindowPrivate(window) ?
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -207,16 +207,19 @@ Cc["@mozilla.org/eventlistenerservice;1"
   .addSystemEventListener(global, "contextmenu", handleContentContextMenu, false);
 
 // Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
 const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
 const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;
 const TLS_ERROR_REPORT_TELEMETRY_SUCCESS  = 6;
 const TLS_ERROR_REPORT_TELEMETRY_FAILURE  = 7;
 
+const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
+
+const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
 
 var AboutNetAndCertErrorListener = {
   init: function(chromeGlobal) {
     addMessageListener("CertErrorDetails", this);
     chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
     chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
     chromeGlobal.addEventListener('AboutNetErrorOverride', this, false, true);
   },
@@ -239,16 +242,23 @@ var AboutNetAndCertErrorListener = {
         this.onCertErrorDetails(msg);
         break;
     }
   },
 
   onCertErrorDetails(msg) {
     let div = content.document.getElementById("certificateErrorText");
     div.textContent = msg.data.info;
+
+    switch (msg.data.code) {
+      case SEC_ERROR_UNKNOWN_ISSUER:
+        let learnMoreLink = content.document.getElementById("learnMoreLink");
+        learnMoreLink.href = "https://support.mozilla.org/kb/troubleshoot-SEC_ERROR_UNKNOWN_ISSUER";
+        break;
+    }
   },
 
   handleEvent: function(aEvent) {
     if (!this.isAboutNetError && !this.isAboutCertError) {
       return;
     }
 
     switch (aEvent.type) {
--- a/browser/base/content/test/general/browser_aboutCertError.js
+++ b/browser/base/content/test/general/browser_aboutCertError.js
@@ -2,16 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // This is testing the aboutCertError page (Bug 1207107).
 
 const GOOD_PAGE = "https://example.com/";
 const BAD_CERT = "https://expired.example.com/";
+const UNKNOWN_ISSUER = "https://self-signed.example.com ";
 const BAD_STS_CERT = "https://badchain.include-subdomains.pinning.example.com:443";
 const {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
 const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
 
 add_task(function* checkReturnToAboutHome() {
   info("Loading a bad cert page directly and making sure 'return to previous page' goes to about:home");
   let browser;
   let certErrorLoaded;
@@ -41,17 +42,17 @@ add_task(function* checkReturnToAboutHom
     returnButton.click();
   });
   yield pageshowPromise;
 
   is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
   is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
   is(gBrowser.currentURI.spec, "about:home", "Went back");
 
-  gBrowser.removeCurrentTab();
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkReturnToPreviousPage() {
   info("Loading a bad cert page and making sure 'return to previous page' goes back");
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
   let browser = gBrowser.selectedBrowser;
 
   info("Loading and waiting for the cert error");
@@ -76,17 +77,17 @@ add_task(function* checkReturnToPrevious
     returnButton.click();
   });
   yield pageshowPromise;
 
   is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
   is(browser.webNavigation.canGoForward, true, "webNavigation.canGoForward");
   is(gBrowser.currentURI.spec, GOOD_PAGE, "Went back");
 
-  gBrowser.removeCurrentTab();
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkBadStsCert() {
   info("Loading a badStsCert and making sure exception button doesn't show up");
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
   let browser = gBrowser.selectedBrowser;
 
   info("Loading and waiting for the cert error");
@@ -96,17 +97,17 @@ add_task(function* checkBadStsCert() {
 
   let exceptionButtonHidden = yield ContentTask.spawn(browser, null, function* () {
     let doc = content.document;
     let exceptionButton = doc.getElementById("exceptionDialogButton");
     return exceptionButton.hidden;
   });
   ok(exceptionButtonHidden, "Exception button is hidden");
 
-  gBrowser.removeCurrentTab();
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkAdvancedDetails() {
   info("Loading a bad cert page and verifying the advanced details section");
   let browser;
   let certErrorLoaded;
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
     gBrowser.selectedTab = gBrowser.addTab(BAD_CERT);
@@ -156,17 +157,17 @@ add_task(function* checkAdvancedDetails(
      "Correct error message found");
   ok(message.text.includes("HTTP Strict Transport Security: false"),
      "Correct HSTS value found");
   ok(message.text.includes("HTTP Public Key Pinning: false"),
      "Correct HPKP value found");
   let certChain = getCertChain(message.securityInfoAsString);
   ok(message.text.includes(certChain), "Found certificate chain");
 
-  gBrowser.removeCurrentTab();
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(function* checkAdvancedDetailsForHSTS() {
   info("Loading a bad STS cert page and verifying the advanced details section");
   let browser;
   let certErrorLoaded;
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
     gBrowser.selectedTab = gBrowser.addTab(BAD_STS_CERT);
@@ -228,17 +229,39 @@ add_task(function* checkAdvancedDetailsF
      "Correct error message found");
   ok(message.text.includes("HTTP Strict Transport Security: false"),
      "Correct HSTS value found");
   ok(message.text.includes("HTTP Public Key Pinning: true"),
      "Correct HPKP value found");
   let certChain = getCertChain(message.securityInfoAsString);
   ok(message.text.includes(certChain), "Found certificate chain");
 
-  gBrowser.removeCurrentTab();
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(function* checkUnknownIssuerLearnMoreLink() {
+  info("Loading a cert error for self-signed pages and checking the correct link is shown");
+  let browser;
+  let certErrorLoaded;
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+    gBrowser.selectedTab = gBrowser.addTab(UNKNOWN_ISSUER);
+    browser = gBrowser.selectedBrowser;
+    certErrorLoaded = waitForCertErrorLoad(browser);
+  }, false);
+
+  info("Loading and waiting for the cert error");
+  yield certErrorLoaded;
+
+  let href = yield ContentTask.spawn(browser, null, function* () {
+    let learnMoreLink = content.document.getElementById("learnMoreLink");
+    return learnMoreLink.href;
+  });
+  is(href, "https://support.mozilla.org/kb/troubleshoot-SEC_ERROR_UNKNOWN_ISSUER");
+
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 function waitForCertErrorLoad(browser) {
   return new Promise(resolve => {
     info("Waiting for DOMContentLoaded event");
     browser.addEventListener("DOMContentLoaded", function load() {
       browser.removeEventListener("DOMContentLoaded", load, false, true);
       resolve();
--- a/netwerk/base/nsINSSErrorsService.idl
+++ b/netwerk/base/nsINSSErrorsService.idl
@@ -19,25 +19,26 @@ interface nsINSSErrorsService : nsISuppo
      *  Function will fail if aNSPRCode is not an NSS error code.
      *  @param aNSPRCode An error code obtained using PR_GetError()
      *  @return The result of the conversion, an XPCOM error code
      */
     nsresult getXPCOMFromNSSError(in int32_t aNSPRCode);
 
     /**
      *  Function will fail if aXPCOMErrorCode is not an NSS error code.
-     *  @param aXPCOMErrorCode An error code obtain using getXPCOMFromNSSError
+     *  @param aXPCOMErrorCode An error code obtained using getXPCOMFromNSSError
      *  return A localized human readable error explanation.
      */
     AString getErrorMessage(in nsresult aXPCOMErrorCode);
 
     /**
      *  Function will fail if aXPCOMErrorCode is not an NSS error code.
-     *  @param aXPCOMErrorCode An error code obtain using getXPCOMFromNSSError
-     *  return the 
+     *  @param aXPCOMErrorCode An error code obtained using getXPCOMFromNSSError
+     *  return the error class of the code, either ERROR_CLASS_BAD_CERT
+     *         or ERROR_CLASS_SSL_PROTOCOL
      */
     uint32_t getErrorClass(in nsresult aXPCOMErrorCode);
 
     const unsigned long ERROR_CLASS_SSL_PROTOCOL = 1;
     const unsigned long ERROR_CLASS_BAD_CERT     = 2;
 
     /**
      *  The following values define the range of NSPR error codes used by NSS.