Bug 439722, Make the "bad cert error dialog" more helpful
authorKai Engert <kaie@kuix.de>
Tue, 26 Aug 2008 00:26:08 +0200
changeset 18398 5b74dbcd42f577f538166b0c58734ab137033a04
parent 18397 d22aca9bfcfe369ef347ed3066dc3c9b2cd2f190
child 18399 442ac72e88f16fd04db823baa2a5897de8f41999
push idunknown
push userunknown
push dateunknown
bugs439722
milestone1.9.1a2pre
Bug 439722, Make the "bad cert error dialog" more helpful r=rrelyea, sr=dveditz
security/manager/locales/en-US/chrome/pippki/pippki.dtd
security/manager/pki/resources/content/certerror.js
security/manager/pki/resources/content/certerror.xul
security/manager/pki/resources/jar.mn
security/manager/pki/src/nsNSSDialogs.cpp
security/manager/pki/src/nsNSSDialogs.h
security/manager/pki/src/nsPKIModule.cpp
security/manager/ssl/public/Makefile.in
security/manager/ssl/public/nsISSLCertErrorDialog.idl
security/manager/ssl/src/nsNSSIOLayer.cpp
--- a/security/manager/locales/en-US/chrome/pippki/pippki.dtd
+++ b/security/manager/locales/en-US/chrome/pippki/pippki.dtd
@@ -124,8 +124,12 @@
 <!ENTITY formSigning.title "Text Signing Request">
 <!ENTITY formSigning.cert "Signing Certificate">
 <!ENTITY formSigning.confirmPassword "To confirm you agree to sign this text message using your selected certificate, please confirm by entering the master password:">
 
 <!-- Strings for protectedAuth dialog -->
 <!ENTITY protectedAuth.title "Protected Token Authentication">
 <!ENTITY protectedAuth.msg "Please authenticate to the token. Authentication method depends on the type of your token.">
 <!ENTITY protectedAuth.tokenName.label "Token:">
+
+<!ENTITY certErrorDlg.title "Secure Connection Failed">
+<!ENTITY certErrorDlg.info1 "This could be a problem with the server's configuration or it could be someone trying to impersonate the server.">
+<!ENTITY certErrorDlg.info2 "If you have connected to this server successfully in the past the error may be temporary and you can try again later.">
new file mode 100644
--- /dev/null
+++ b/security/manager/pki/resources/content/certerror.js
@@ -0,0 +1,29 @@
+const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
+const nsIPKIParamBlock    = Components.interfaces.nsIPKIParamBlock;
+const nsIX509Cert         = Components.interfaces.nsIX509Cert;
+
+var dialogParams;
+var pkiParams;
+var cert;
+var hostport;
+
+function initCertErrorDialog()
+{
+  pkiParams    = window.arguments[0].QueryInterface(nsIPKIParamBlock);
+  dialogParams = pkiParams.QueryInterface(nsIDialogParamBlock);
+
+  var isupport = pkiParams.getISupportAtIndex(1);
+  cert = isupport.QueryInterface(nsIX509Cert);
+
+  var portNumber = dialogParams.GetInt(1);
+  var hostName = dialogParams.GetString(1);
+  var msg = dialogParams.GetString(2);
+
+  hostport = hostName + ":" + portNumber;
+  setText("warningText", msg);
+}
+
+function viewCert()
+{
+  viewCertHelper(window, cert);
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/pki/resources/content/certerror.xul
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is mozilla.org code.
+   -
+   - The Initial Developer of the Original Code is
+   - Red Hat, Inc.
+   - Portions created by the Initial Developer are Copyright (C) 2007
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Kai Engert <kaie@netscape.com>
+   -   Johnathan Nightingale <johnath@mozilla.com>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % pippkiDTD SYSTEM "chrome://pippki/locale/pippki.dtd" >
+%pippkiDTD;
+]>
+
+<dialog id="certErrorDialog" title="&certErrorDlg.title;"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  style="width: 47em;"
+  onload="initCertErrorDialog();"
+  buttons="cancel,extra1"
+  defaultButton="cancel"
+  buttonlabelextra1="&examineCert.label;"
+  buttonaccesskeyextra1="&examineCert.accesskey;"
+  ondialogextra1="viewCert();">
+
+<script type="application/x-javascript" src="chrome://global/content/strres.js"/>
+<script type="application/x-javascript" src="chrome://pippki/content/pippki.js"/>
+<script type="application/x-javascript" src="chrome://pippki/content/certerror.js"/>
+
+<hbox>
+  <vbox>
+#ifdef MOZ_WIDGET_GTK2
+    <image src="moz-icon://stock/gtk-dialog-warning?size=dialog"/>
+#else
+    <image src="chrome://global/skin/icons/warning-large.png"/>
+#endif
+    <spacer flex="1"/>
+  </vbox>
+  <vbox flex="1">
+    <description id="warningText"
+                 style="white-space: pre-wrap"/>
+    <separator/>
+    <description id="info1">&certErrorDlg.info1;</description>
+    <description id="info2">&certErrorDlg.info2;</description>
+  </vbox>
+</hbox>
+</dialog>
--- a/security/manager/pki/resources/jar.mn
+++ b/security/manager/pki/resources/jar.mn
@@ -11,16 +11,18 @@ pippki.jar:
     content/pippki/resetpassword.js          (content/resetpassword.js)
     content/pippki/PrefOverlay.xul           (content/PrefOverlay.xul)
     content/pippki/pref-security.js          (content/pref-security.js)
     content/pippki/pref-ssl.xul              (content/pref-ssl.xul)
     content/pippki/pref-certs.xul            (content/pref-certs.xul)
 #ifndef MOZ_PHOENIX
     content/pippki/PageInfoOverlay.xul       (content/PageInfoOverlay.xul)
 #endif
+    content/pippki/certerror.js              (content/certerror.js)
+*   content/pippki/certerror.xul             (content/certerror.xul)
     content/pippki/downloadcert.js           (content/downloadcert.js)
     content/pippki/downloadcert.xul          (content/downloadcert.xul)
     content/pippki/cacertexists.xul          (content/cacertexists.xul)
     content/pippki/certManager.js            (content/certManager.js)
     content/pippki/certManager.xul           (content/certManager.xul)
     content/pippki/CAOverlay.xul             (content/CAOverlay.xul)
     content/pippki/WebSitesOverlay.xul       (content/WebSitesOverlay.xul)
     content/pippki/OthersOverlay.xul         (content/OthersOverlay.xul)
--- a/security/manager/pki/src/nsNSSDialogs.cpp
+++ b/security/manager/pki/src/nsNSSDialogs.cpp
@@ -54,16 +54,17 @@
 #include "nsIStringBundle.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIX509Cert.h"
 #include "nsIX509CertDB.h"
 #include "nsILocaleService.h"
 #include "nsIDateTimeFormat.h"
 #include "nsDateTimeFormatCID.h"
+#include "nsPromiseFlatString.h"
 
 #include "nsNSSDialogs.h"
 #include "nsPKIParamBlock.h"
 #include "nsIKeygenThread.h"
 #include "nsIProtectedAuthThread.h"
 #include "nsNSSDialogHelper.h"
 #include "nsIWindowWatcher.h"
 #include "nsIX509CertValidity.h"
@@ -76,23 +77,24 @@
 nsNSSDialogs::nsNSSDialogs()
 {
 }
 
 nsNSSDialogs::~nsNSSDialogs()
 {
 }
 
-NS_IMPL_THREADSAFE_ISUPPORTS7(nsNSSDialogs, nsITokenPasswordDialogs,
+NS_IMPL_THREADSAFE_ISUPPORTS8(nsNSSDialogs, nsITokenPasswordDialogs,
                                             nsICertificateDialogs,
                                             nsIClientAuthDialogs,
                                             nsICertPickDialogs,
                                             nsITokenDialogs,
                                             nsIDOMCryptoDialogs,
-                                            nsIGeneratingKeypairInfoDialogs)
+                                            nsIGeneratingKeypairInfoDialogs,
+                                            nsISSLCertErrorDialog)
 
 nsresult
 nsNSSDialogs::Init()
 {
   nsresult rv;
 
   nsCOMPtr<nsIStringBundleService> service =
            do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
@@ -605,8 +607,51 @@ nsNSSDialogs::DisplayProtectedAuth(nsIIn
         "chrome://pippki/content/protectedAuth.xul",
         "_blank",
         "centerscreen,chrome,modal,titlebar,close=no",
         runnable,
         getter_AddRefs(newWindow));
     
     return rv;
 }
+
+NS_IMETHODIMP
+nsNSSDialogs::ShowCertError(nsIInterfaceRequestor *ctx, 
+                            nsISSLStatus *status, 
+                            nsIX509Cert *cert, 
+                            const nsAString & textErrorMessage, 
+                            const nsAString & htmlErrorMessage, 
+                            const nsACString & hostName, 
+                            PRUint32 portNumber)
+{
+  nsCOMPtr<nsIPKIParamBlock> block =
+           do_CreateInstance(NS_PKIPARAMBLOCK_CONTRACTID);
+  if (!block)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  nsCOMPtr<nsIDialogParamBlock> dialogBlock = do_QueryInterface(block);
+
+  nsresult rv;
+  rv = dialogBlock->SetInt(1, portNumber);
+  if (NS_FAILED(rv))
+    return rv; 
+
+  NS_ConvertUTF8toUTF16 host16(hostName);
+  nsPromiseFlatString flatHostName(host16);
+  nsPromiseFlatString flatMessage(textErrorMessage);
+
+  rv = dialogBlock->SetString(1, flatHostName.get());
+  if (NS_FAILED(rv))
+    return rv;
+  
+  rv = dialogBlock->SetString(2, flatMessage.get());
+  if (NS_FAILED(rv))
+    return rv;
+  
+  rv = block->SetISupportAtIndex(1, cert);
+  if (NS_FAILED(rv))
+    return rv;
+
+  rv = nsNSSDialogHelper::openDialog(nsnull, 
+                                     "chrome://pippki/content/certerror.xul",
+                                     block);
+  return rv;
+}
--- a/security/manager/pki/src/nsNSSDialogs.h
+++ b/security/manager/pki/src/nsNSSDialogs.h
@@ -42,42 +42,45 @@
 
 #include "nsITokenPasswordDialogs.h"
 #include "nsICertificateDialogs.h"
 #include "nsIClientAuthDialogs.h"
 #include "nsICertPickDialogs.h"
 #include "nsITokenDialogs.h"
 #include "nsIDOMCryptoDialogs.h"
 #include "nsIGenKeypairInfoDlg.h"
+#include "nsISSLCertErrorDialog.h"
 
 #include "nsCOMPtr.h"
 #include "nsIStringBundle.h"
 
 #define NS_NSSDIALOGS_CID \
   { 0x518e071f, 0x1dd2, 0x11b2, \
     { 0x93, 0x7e, 0xc4, 0x5f, 0x14, 0xde, 0xf7, 0x78 }}
 
 class nsNSSDialogs
 : public nsITokenPasswordDialogs,
   public nsICertificateDialogs,
   public nsIClientAuthDialogs,
   public nsICertPickDialogs,
   public nsITokenDialogs,
   public nsIDOMCryptoDialogs,
-  public nsIGeneratingKeypairInfoDialogs
+  public nsIGeneratingKeypairInfoDialogs,
+  public nsISSLCertErrorDialog
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITOKENPASSWORDDIALOGS
   NS_DECL_NSICERTIFICATEDIALOGS
   NS_DECL_NSICLIENTAUTHDIALOGS
   NS_DECL_NSICERTPICKDIALOGS
   NS_DECL_NSITOKENDIALOGS
   NS_DECL_NSIDOMCRYPTODIALOGS
   NS_DECL_NSIGENERATINGKEYPAIRINFODIALOGS
+  NS_DECL_NSISSLCERTERRORDIALOG
   nsNSSDialogs();
   virtual ~nsNSSDialogs();
 
   nsresult Init();
 
 protected:
   nsCOMPtr<nsIStringBundle> mPIPStringBundle;
 };
--- a/security/manager/pki/src/nsPKIModule.cpp
+++ b/security/manager/pki/src/nsPKIModule.cpp
@@ -39,29 +39,37 @@
 
 #include "nsIModule.h"
 #include "nsIGenericFactory.h"
 
 #include "nsNSSDialogs.h"
 #include "nsPKIParamBlock.h"
 #include "nsASN1Tree.h"
 #include "nsFormSigningDialog.h"
+#include "nsISSLCertErrorDialog.h"
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNSSDialogs, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPKIParamBlock, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSASN1Tree)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormSigningDialog)
 
 #define NSS_DIALOGS_DESCRIPTION "PSM Dialog Impl"
 
 static const nsModuleComponentInfo components[] =
 {
   {
     NSS_DIALOGS_DESCRIPTION,
     NS_NSSDIALOGS_CID,
+    NS_SSLCERTERRORDIALOG_CONTRACTID,
+    nsNSSDialogsConstructor
+  },
+
+  {
+    NSS_DIALOGS_DESCRIPTION,
+    NS_NSSDIALOGS_CID,
     NS_TOKENPASSWORDSDIALOG_CONTRACTID,
     nsNSSDialogsConstructor
   },
 
   {
     NSS_DIALOGS_DESCRIPTION,
     NS_NSSDIALOGS_CID,
     NS_CERTIFICATEDIALOGS_CONTRACTID,
--- a/security/manager/ssl/public/Makefile.in
+++ b/security/manager/ssl/public/Makefile.in
@@ -54,16 +54,17 @@ SDK_XPIDLSRCS = \
     nsICertificateDialogs.idl \
     nsICRLInfo.idl \
     nsIX509Cert.idl \
     nsIX509CertDB.idl \
     nsIX509CertValidity.idl \
     $(NULL)
 
 XPIDLSRCS = \
+    nsISSLCertErrorDialog.idl \
     nsIBadCertListener2.idl \
     nsISSLErrorListener.idl \
     nsIIdentityInfo.idl \
     nsIAssociatedContentSecurity.idl \
     nsICertOverrideService.idl \
     nsIRecentBadCertsService.idl \
     nsIFormSigningDialog.idl \
     nsIX509Cert2.idl \
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/public/nsISSLCertErrorDialog.idl
@@ -0,0 +1,72 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kai Engert <kaie@redhat.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIInterfaceRequestor;
+interface nsIX509Cert;
+interface nsISSLStatus;
+
+[scriptable, uuid(0729ce8e-8935-4989-ba72-a2d6307f2365)]
+interface nsISSLCertErrorDialog : nsISupports
+{
+  /**
+   *  Called when an SSL connection aborts because of a bad certificate,
+   *  and no other code is in place for reporting the problem.
+   *  Should bring up a dialog to inform the user and display the certificate.
+   *
+   *  @param status Might be used to query additional information
+   *  @param cert The certificate that this error is about
+   *  @param textErrorMessage An error message with whitespace formatting
+   *  @param htmlErrorMessage Optional, might either be empty,
+                              or might contain the same message as in
+                              textErrorMessage plus some html formatting.
+   *  @param hostName The error occurred when connecting to this hostName.
+   *  @param portNumber The error occurred when connecting to this portNumber.
+   */
+  void showCertError(in nsIInterfaceRequestor ctx, 
+                     in nsISSLStatus status,
+                     in nsIX509Cert cert,
+                     in AString textErrorMessage,
+                     in AString htmlErrorMessage,
+                     in ACString hostName,
+                     in PRUint32 portNumber);
+};
+
+%{C++
+#define NS_SSLCERTERRORDIALOG_CONTRACTID "@mozilla.org/nsSSLCertErrorDialog;1"
+%}
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -60,16 +60,17 @@
 #include "nsIClientAuthDialogs.h"
 #include "nsClientAuthRemember.h"
 #include "nsICertOverrideService.h"
 #include "nsIBadCertListener2.h"
 #include "nsISSLErrorListener.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsRecentBadCerts.h"
+#include "nsISSLCertErrorDialog.h"
 
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsHashSets.h"
 #include "nsCRT.h"
 #include "nsAutoPtr.h"
 #include "nsPrintfCString.h"
 #include "nsAutoLock.h"
@@ -1387,23 +1388,44 @@ nsHandleInvalidCertError(nsNSSSocketInfo
   }
   else
   {
     nsPSMUITracker tracker;
     if (tracker.isUIForbidden()) {
       rv = NS_ERROR_NOT_AVAILABLE;
     }
     else {
-      rv = displayAlert(formattedString, socketInfo);
+      nsISSLCertErrorDialog *dialogs = nsnull;
+      rv = getNSSDialogs((void**)&dialogs, 
+        NS_GET_IID(nsISSLCertErrorDialog), 
+        NS_SSLCERTERRORDIALOG_CONTRACTID);
+  
+      if (NS_SUCCEEDED(rv)) {
+        nsPSMUITracker tracker;
+        if (tracker.isUIForbidden()) {
+          rv = NS_ERROR_NOT_AVAILABLE;
+        }
+        else {
+          nsCOMPtr<nsISSLStatus> status;
+          socketInfo->GetSSLStatus(getter_AddRefs(status));
+
+          nsString empty;
+
+          rv = dialogs->ShowCertError(nsnull, status, ix509, 
+                                      formattedString, 
+                                      empty, host, port);
+        }
+  
+        NS_RELEASE(dialogs);
+      }
     }
   }
   return rv;
 }
 
-
 static PRStatus PR_CALLBACK
 nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
                     PRIntervalTime timeout)
 {
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n", (void*)fd));
   nsNSSShutDownPreventionLock locker;
   if (!fd || !fd->lower)
     return PR_FAILURE;