Bug 307081 - Clean up nsIClientAuthDialogs.idl and implementations. r=kats,keeler draft
authorCykesiopka <cykesiopka.bmo@gmail.com>
Fri, 24 Jun 2016 00:12:11 -0700
changeset 381113 ab518fe6a325fe94e4d6583d282c055efb842e2d
parent 381112 1c09b2b5f4c4281ab2e5cf73758bb6578e6c9c6e
child 381114 52a86543ce4f32dc20f7b456f367e668ebd58d33
push id21395
push usercykesiopka.bmo@gmail.com
push dateFri, 24 Jun 2016 07:13:10 +0000
reviewerskats, keeler
bugs307081
milestone50.0a1
Bug 307081 - Clean up nsIClientAuthDialogs.idl and implementations. r=kats,keeler This fixes the following in the IDL: 1. Misleading or unclear parameter names in the IDL. |cn| in practice is the concatenation of the CN of the server cert and the port of the server, and |issuer| is the Organization of the issuer cert of the server cert. 2. Use of the |wstring| type. |AString| is generally preferred, and has the benefit of letting implementations skip null checks due to the use of references. 3. Using an explicit |canceled| outparam instead of just setting a return type. There is no need for the outparam if the return type can be used. 4. Using |long| (int32_t) for |selectedIndex|. |unsigned long| (uint32_t) is more logical, and paves the way for future changes. This fixes the following in the Android implementation: 1. Lack of checks to ensure the QueryInterface() call succeeded. In practice, the call will always succeed, but it's good practice to check anyways. 2. Setting a variable to an nsIPrefService instance initially, then later setting it to a pref branch instance later on. This is confusing and unnecessary. This fixes the following in the desktop implementation: 1. Lack of null pointer checking. 2. Trying to get a parent window ref off a context that doesn't actually support doing so. 3. Setting a variable to an nsIPrefService instance initially, then later setting it to a pref branch instance later on. This is confusing and unnecessary. 4. Abusal of the CAPS bundle. 5. Unnecessary variables. 6. Variables declared far away from where they are used. 7. Variable shadowing. 8. Style issues. 9. Lack of documentation. This also fixes the following: 1. Lack of localisation notes. MozReview-Commit-ID: FTc6XecJd6h
dom/locales/en-US/chrome/security/caps.properties
mobile/android/components/NSSDialogService.js
mobile/android/locales/en-US/chrome/pippki.properties
security/manager/locales/en-US/chrome/pippki/pippki.properties
security/manager/pki/nsNSSDialogs.cpp
security/manager/pki/resources/content/clientauthask.js
security/manager/pki/resources/content/clientauthask.xul
security/manager/ssl/nsIClientAuthDialogs.idl
security/manager/ssl/nsNSSIOLayer.cpp
--- a/dom/locales/en-US/chrome/security/caps.properties
+++ b/dom/locales/en-US/chrome/security/caps.properties
@@ -1,12 +1,11 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-CheckMessage = Remember this decision
 CheckLoadURIError = Security Error: Content at %S may not load or link to %S.
 CheckSameOriginError = Security Error: Content at %S may not load data from %S.
 ExternalDataError = Security Error: Content at %S attempted to load %S, but may not load external data when being used as an image. 
 
 # LOCALIZATION NOTE (GetPropertyDeniedOrigins):
 # %1$S is the origin of the script which was denied access.
 # %2$S is the type of object it was.
 # %3$S is the property of that object that access was denied for.
--- a/mobile/android/components/NSSDialogService.js
+++ b/mobile/android/components/NSSDialogService.js
@@ -146,65 +146,61 @@ NSSDialogs.prototype = {
   viewCertDetails: function(details) {
     let p = this.getPrompt(this.getString("clientAuthAsk.message3"),
                     '',
                     [ this.getString("nssdialogs.ok.label") ]);
     p.addLabel({ label: details });
     this.showPrompt(p);
   },
 
-  ChooseCertificate: function(aCtx, cn, organization, issuer, certNickList, certDetailsList, count, selectedIndex, canceled) {
-    let rememberSetting = true;
-    var pref = Cc['@mozilla.org/preferences-service;1']
-               .getService(Components.interfaces.nsIPrefService);
-    if (pref) {
-      pref = pref.getBranch(null);
-      try {
-        rememberSetting = pref.getBoolPref("security.remember_cert_checkbox_default_setting");
-      } catch (e) {
-        // pref is missing
-      }
-    }
+  chooseCertificate: function(ctx, cnAndPort, organization, issuerOrg,
+                              certNickList, certDetailsList, count,
+                              selectedIndex) {
+    let rememberSetting =
+      Services.prefs.getBoolPref("security.remember_cert_checkbox_default_setting");
 
-    let organizationString = this.formatString("clientAuthAsk.organization",
-                                               [organization]);
-    let issuerString = this.formatString("clientAuthAsk.issuer",
-                                         [issuer]);
-    let serverRequestedDetails = cn + '<br/>' + organizationString + '<br/>' + issuerString;
+    let serverRequestedDetails = [
+      cnAndPort,
+      this.formatString("clientAuthAsk.organization", [organization]),
+      this.formatString("clientAuthAsk.issuer", [issuerOrg]),
+    ].join("<br/>");
 
     selectedIndex.value = 0;
     while (true) {
+      let buttons = [
+        this.getString("nssdialogs.ok.label"),
+        this.getString("clientAuthAsk.viewCert.label"),
+        this.getString("nssdialogs.cancel.label"),
+      ];
       let prompt = this.getPrompt(this.getString("clientAuthAsk.title"),
-                                     this.getString("clientAuthAsk.message1"),
-                                     [ this.getString("nssdialogs.ok.label"),
-                                       this.getString("clientAuthAsk.viewCert.label"),
-                                       this.getString("nssdialogs.cancel.label")
-                                     ])
+                                  this.getString("clientAuthAsk.message1"),
+                                  buttons)
       .addLabel({ id: "requestedDetails", label: serverRequestedDetails } )
       .addMenulist({
         id: "nicknames",
         label: this.getString("clientAuthAsk.message2"),
         values: certNickList,
         selected: selectedIndex.value,
       }).addCheckbox({
         id: "rememberBox",
         label: this.getString("clientAuthAsk.remember.label"),
         checked: rememberSetting
       });
       let response = this.showPrompt(prompt);
       selectedIndex.value = response.nicknames;
-      if (response.button == 1) {
+      if (response.button == 1 /* buttons[1] */) {
         this.viewCertDetails(certDetailsList[selectedIndex.value]);
         continue;
-      } else if (response.button == 0) {
-        canceled.value = false;
+      } else if (response.button == 0 /* buttons[0] */) {
         if (response.rememberBox == true) {
-          aCtx.QueryInterface(Ci.nsIClientAuthUserDecision).rememberClientAuthCertificate = true;
+          let caud = ctx.QueryInterface(Ci.nsIClientAuthUserDecision);
+          if (caud) {
+            caud.rememberClientAuthCertificate = true;
+          }
         }
         return true;
       }
-      canceled.value = true;
       return false;
     }
   }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NSSDialogs]);
--- a/mobile/android/locales/en-US/chrome/pippki.properties
+++ b/mobile/android/locales/en-US/chrome/pippki.properties
@@ -14,17 +14,21 @@ downloadCert.trustEmail=Trust to identif
 downloadCert.trustObjSign=Trust to identify software developers.
 pkcs12.getpassword.title=Password Entry Dialog
 pkcs12.getpassword.message=Please enter the password that was used to encrypt this certificate backup.
 clientAuthAsk.title=User Identification Request
 clientAuthAsk.message1=This site has requested that you identify yourself with a certificate:
 clientAuthAsk.message2=Choose a certificate to present as identification:
 clientAuthAsk.message3=Details of selected certificate:
 clientAuthAsk.remember.label=Remember this decision
+# LOCALIZATION NOTE(clientAuthAsk.organization): %S is the Organization of the
+# server cert.
 clientAuthAsk.organization=Organization: "%S"
+# LOCALIZATION NOTE(clientAuthAsk.issuer): %S is the Organization of the
+# issuer cert of the server cert.
 clientAuthAsk.issuer=Issued Under: "%S"
 clientAuthAsk.viewCert.label=View
 
 certmgr.title=Certificate Details
 # These strings are stolen from security/manager/locales/en-US/chrome/pippki/certManager.dtd
 certmgr.subjectinfo.label=Issued To
 certmgr.issuerinfo.label=Issued By
 certmgr.periodofvalidity.label=Period of Validity
--- a/security/manager/locales/en-US/chrome/pippki/pippki.properties
+++ b/security/manager/locales/en-US/chrome/pippki/pippki.properties
@@ -47,17 +47,22 @@ certNotVerified_CertExpired=Could not ve
 certNotVerified_CertNotTrusted=Could not verify this certificate because it is not trusted.
 certNotVerified_IssuerNotTrusted=Could not verify this certificate because the issuer is not trusted.
 certNotVerified_IssuerUnknown=Could not verify this certificate because the issuer is unknown.
 certNotVerified_CAInvalid=Could not verify this certificate because the CA certificate is invalid.
 certNotVerified_AlgorithmDisabled=Could not verify this certificate because it was signed using a signature algorithm that was disabled because that algorithm is not secure.
 certNotVerified_Unknown=Could not verify this certificate for unknown reasons.
 
 #Client auth
+clientAuthRemember=Remember this decision
+# LOCALIZATION NOTE(clientAuthMessage1): %S is the Organization of the server
+# cert.
 clientAuthMessage1=Organization: ā€œ%Sā€
+# LOCALIZATION NOTE(clientAuthMessage2): %S is the Organization of the issuer
+# cert of the server cert.
 clientAuthMessage2=Issued Under: ā€œ%Sā€
 
 #Page Info
 pageInfo_NoEncryption=Connection Not Encrypted
 pageInfo_Privacy_None1=The website %S does not support encryption for the page you are viewing.
 pageInfo_Privacy_None2=Information sent over the Internet without encryption can be seen by other people while it is in transit. 
 pageInfo_Privacy_None4=The page you are viewing was not encrypted before being transmitted over the Internet.
 # LOCALIZATION NOTE (pageInfo_EncryptionWithBitsAndProtocol and pageInfo_BrokenEncryption):
--- a/security/manager/pki/nsNSSDialogs.cpp
+++ b/security/manager/pki/nsNSSDialogs.cpp
@@ -3,40 +3,39 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * Dialog services for PIP.
  */
 #include "mozIDOMWindow.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Casting.h"
 #include "nsArray.h"
-#include "nsCOMPtr.h"
 #include "nsDateTimeFormatCID.h"
 #include "nsEmbedCID.h"
 #include "nsIComponentManager.h"
 #include "nsIDateTimeFormat.h"
 #include "nsIDialogParamBlock.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIKeygenThread.h"
 #include "nsIPromptService.h"
 #include "nsIProtectedAuthThread.h"
 #include "nsIServiceManager.h"
-#include "nsIStringBundle.h"
 #include "nsIWindowWatcher.h"
 #include "nsIX509CertDB.h"
 #include "nsIX509Cert.h"
 #include "nsIX509CertValidity.h"
 #include "nsNSSDialogHelper.h"
 #include "nsNSSDialogs.h"
 #include "nsPromiseFlatString.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
-#include "nsXPIDLString.h"
 
 #define PIPSTRING_BUNDLE_URL "chrome://pippki/locale/pippki.properties"
 
 /* ==== */
 
 nsNSSDialogs::nsNSSDialogs()
 {
 }
@@ -153,44 +152,47 @@ nsNSSDialogs::ConfirmDownloadCACert(nsII
   *_trust |= (objsign) ? nsIX509CertDB::TRUSTED_OBJSIGN : 0;
 
   *_retval = (status != 0);
 
   return rv;
 }
 
 NS_IMETHODIMP
-nsNSSDialogs::ChooseCertificate(nsIInterfaceRequestor* ctx, const char16_t* cn,
-                                const char16_t* organization,
-                                const char16_t* issuer,
+nsNSSDialogs::ChooseCertificate(nsIInterfaceRequestor* ctx,
+                                const nsAString& cnAndPort,
+                                const nsAString& organization,
+                                const nsAString& issuerOrg,
                                 const char16_t** certNickList,
                                 const char16_t** certDetailsList, uint32_t count,
-                                int32_t* selectedIndex, bool* canceled)
+                        /*out*/ uint32_t* selectedIndex,
+                        /*out*/ bool* certificateChosen)
 {
+  NS_ENSURE_ARG_POINTER(ctx);
+  NS_ENSURE_ARG_POINTER(selectedIndex);
+  NS_ENSURE_ARG_POINTER(certificateChosen);
+
   nsresult rv;
   uint32_t i;
 
-  *canceled = false;
-
-  // Get the parent window for the dialog
-  nsCOMPtr<nsIDOMWindow> parent = do_GetInterface(ctx);
+  *certificateChosen = false;
 
   nsCOMPtr<nsIDialogParamBlock> block =
            do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
   if (!block) return NS_ERROR_FAILURE;
 
   block->SetNumberStrings(4+count*2);
 
-  rv = block->SetString(0, cn);
+  rv = block->SetString(0, PromiseFlatString(cnAndPort).get());
   if (NS_FAILED(rv)) return rv;
 
-  rv = block->SetString(1, organization);
+  rv = block->SetString(1, PromiseFlatString(organization).get());
   if (NS_FAILED(rv)) return rv;
 
-  rv = block->SetString(2, issuer);
+  rv = block->SetString(2, PromiseFlatString(issuerOrg).get());
   if (NS_FAILED(rv)) return rv;
 
   for (i = 0; i < count; i++) {
     rv = block->SetString(i+3, certNickList[i]);
     if (NS_FAILED(rv)) return rv;
   }
 
   for (i = 0; i < count; i++) {
@@ -214,22 +216,33 @@ nsNSSDialogs::ChooseCertificate(nsIInter
   if (extraResult) {
     int32_t rememberSelection;
     rv = block->GetInt(2, &rememberSelection);
     if (NS_SUCCEEDED(rv)) {
       extraResult->SetRememberClientAuthCertificate(rememberSelection!=0);
     }
   }
 
-  *canceled = (status == 0)?true:false;
-  if (!*canceled) {
-    // retrieve the nickname
-    rv = block->GetInt(1, selectedIndex);
+  *certificateChosen = (status != 0);
+  if (*certificateChosen) {
+    int32_t index = 0;
+    rv = block->GetInt(1, &index);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    if (index < 0) {
+      MOZ_ASSERT_UNREACHABLE("Selected index should never be negative");
+      return NS_ERROR_FAILURE;
+    }
+
+    *selectedIndex = mozilla::AssertedCast<uint32_t>(index);
   }
-  return rv;
+
+  return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNSSDialogs::PickCertificate(nsIInterfaceRequestor *ctx, 
                               const char16_t **certNickList, 
                               const char16_t **certDetailsList, 
                               uint32_t count, 
--- a/security/manager/pki/resources/content/clientauthask.js
+++ b/security/manager/pki/resources/content/clientauthask.js
@@ -1,104 +1,93 @@
 /* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 /* import-globals-from pippki.js */
 "use strict";
 
-const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
 
+/**
+ * The param block to get params from and set results on.
+ * @type nsIDialogParamBlock
+ */
 var dialogParams;
 var itemCount = 0;
+/**
+ * The checkbox storing whether the user wants to remember the selected cert.
+ * @type nsIDOMXULCheckboxElement
+ */
 var rememberBox;
 
-function onLoad()
-{
-    var cn;
-    var org;
-    var issuer;
+function onLoad() {
+  dialogParams = window.arguments[0].QueryInterface(Ci.nsIDialogParamBlock);
 
-    dialogParams = window.arguments[0].QueryInterface(nsIDialogParamBlock);
-    cn = dialogParams.GetString(0);
-    org = dialogParams.GetString(1);
-    issuer = dialogParams.GetString(2);
+  let bundle = document.getElementById("pippki_bundle");
+  let rememberSetting =
+    Services.prefs.getBoolPref("security.remember_cert_checkbox_default_setting");
+
+  rememberBox = document.getElementById("rememberBox");
+  rememberBox.label = bundle.getString("clientAuthRemember");
+  rememberBox.checked = rememberSetting;
 
-    // added with bug 431819. reuse string from caps in order to avoid string changes
-    var capsBundle = document.getElementById("caps_bundle");
-    var rememberString = capsBundle.getString("CheckMessage");
-    var rememberSetting = true;
+  let cnAndPort = dialogParams.GetString(0);
+  let org = dialogParams.GetString(1);
+  let issuerOrg = dialogParams.GetString(2);
+  let formattedOrg = bundle.getFormattedString("clientAuthMessage1", [org]);
+  let formattedIssuerOrg = bundle.getFormattedString("clientAuthMessage2",
+                                                     [issuerOrg]);
+  setText("hostname", cnAndPort);
+  setText("organization", formattedOrg);
+  setText("issuer", formattedIssuerOrg);
 
-    var pref = Components.classes['@mozilla.org/preferences-service;1']
-                         .getService(Components.interfaces.nsIPrefService);
-    if (pref) {
-      pref = pref.getBranch(null);
-      try {
-	rememberSetting =
-	  pref.getBoolPref("security.remember_cert_checkbox_default_setting");
-      } catch (e) {
-	// pref is missing
-      }
+  let selectElement = document.getElementById("nicknames");
+  itemCount = dialogParams.GetInt(0);
+  for (let i = 0; i < itemCount; i++) {
+    let menuItemNode = document.createElement("menuitem");
+    let nick = dialogParams.GetString(i + 3);
+    menuItemNode.setAttribute("value", i);
+    menuItemNode.setAttribute("label", nick); // this is displayed
+    selectElement.firstChild.appendChild(menuItemNode);
+    if (i == 0) {
+      selectElement.selectedItem = menuItemNode;
     }
-
-    rememberBox = document.getElementById("rememberBox");
-    rememberBox.label = rememberString;
-    rememberBox.checked = rememberSetting;
-
-    var bundle = document.getElementById("pippki_bundle");
-    var message1 = bundle.getFormattedString("clientAuthMessage1", [org]);
-    var message2 = bundle.getFormattedString("clientAuthMessage2", [issuer]);
-    setText("hostname", cn);
-    setText("organization", message1);
-    setText("issuer", message2);
+  }
 
-    var selectElement = document.getElementById("nicknames");
-    itemCount = dialogParams.GetInt(0);
-    for (let i = 0; i < itemCount; i++) {
-        var menuItemNode = document.createElement("menuitem");
-        let nick = dialogParams.GetString(i + 3);
-        menuItemNode.setAttribute("value", i);
-        menuItemNode.setAttribute("label", nick); // this is displayed
-        selectElement.firstChild.appendChild(menuItemNode);
-        if (i == 0) {
-            selectElement.selectedItem = menuItemNode;
-        }
-    }
-
-    setDetails();
+  setDetails();
 }
 
-function setDetails()
-{
+/**
+ * Populates the details section with information concerning the selected cert.
+ */
+function setDetails() {
   let index = parseInt(document.getElementById("nicknames").value);
   let details = dialogParams.GetString(index + itemCount + 3);
   document.getElementById("details").value = details;
 }
 
-function onCertSelected()
-{
+function onCertSelected() {
   setDetails();
 }
 
-function doOK()
-{
+function doOK() {
   // Signal that the user accepted.
   dialogParams.SetInt(0, 1);
   let index = parseInt(document.getElementById("nicknames").value);
   // Signal the index of the selected cert in the list of cert nicknames
   // provided.
   dialogParams.SetInt(1, index);
   // Signal whether the user wanted to remember the selection.
   dialogParams.SetInt(2, rememberBox.checked);
   return true;
 }
 
-function doCancel()
-{
+function doCancel() {
   // Signal that the user cancelled.
   dialogParams.SetInt(0, 0);
-  // Signal some invalid index value since a cert hasn't actually been chosen.
-  dialogParams.SetInt(1, -1); // invalid value
   // Signal whether the user wanted to remember the "selection".
   dialogParams.SetInt(2, rememberBox.checked);
   return true;
 }
--- a/security/manager/pki/resources/content/clientauthask.xul
+++ b/security/manager/pki/resources/content/clientauthask.xul
@@ -15,17 +15,16 @@
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"      
   buttons="accept,cancel"
   ondialogaccept="return doOK();"
   ondialogcancel="return doCancel();"
   onload="onLoad();">
 
 <stringbundleset id="stringbundleset">
   <stringbundle id="pippki_bundle" src="chrome://pippki/locale/pippki.properties"/>
-  <stringbundle id="caps_bundle" src="chrome://global/locale/security/caps.properties"/>
 </stringbundleset>
 
 <script type="application/javascript" src="chrome://pippki/content/pippki.js"/>
 <script type="application/javascript" src="chrome://pippki/content/clientauthask.js"/>
 
   <groupbox>
     <description style="font-weight: bold;">&clientAuthAsk.message1;</description>
     <description id="hostname"/>
--- a/security/manager/ssl/nsIClientAuthDialogs.idl
+++ b/security/manager/ssl/nsIClientAuthDialogs.idl
@@ -2,35 +2,39 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIInterfaceRequestor;
 
 /**
- * nsIClientAuthDialog
  * Provides UI for SSL client-auth dialogs.
  */
 [scriptable, uuid(fa4c7520-1433-11d5-ba24-00108303b117)]
 interface nsIClientAuthDialogs : nsISupports
 {
   /**
-   * display
-   *   UI shown when a user is asked to do SSL client auth.
+   * Called when a user is asked to choose a certificate for client auth.
+   *
+   * @param ctx Context that allows at least nsIClientAuthUserDecision to be
+   *            queried.
+   * @param cnAndPort Common Name of the server cert and the port of the server.
+   * @param organization Organization field of the server cert.
+   * @param issuerOrg Organization field of the issuer cert of the server cert.
+   * @return true if a certificate was chosen. false if the user canceled.
    */
-  void ChooseCertificate(in nsIInterfaceRequestor ctx, 
-                        in wstring cn,
-                        in wstring organization,
-                        in wstring issuer,
-                        [array, size_is(count)] in wstring certNickList,
-                        [array, size_is(count)] in wstring certDetailsList,
-                        in unsigned long count,
-                        out long selectedIndex,
-                        out boolean canceled);
+  boolean chooseCertificate(in nsIInterfaceRequestor ctx,
+                            in AString cnAndPort,
+                            in AString organization,
+                            in AString issuerOrg,
+                            [array, size_is(count)] in wstring certNickList,
+                            [array, size_is(count)] in wstring certDetailsList,
+                            in unsigned long count,
+                            out unsigned long selectedIndex);
 };
 
 [scriptable, uuid(95c4373e-bdd4-4a63-b431-f5b000367721)]
 interface nsIClientAuthUserDecision : nsISupports
 {
   attribute boolean rememberClientAuthCertificate;
 };
 
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -2094,20 +2094,17 @@ ClientAuthDataRunnable::RunOnTargetThrea
   // We check the value of a pref in this runnable, so this runnable should only
   // be run on the main thread.
   MOZ_ASSERT(NS_IsMainThread());
 
   UniquePLArenaPool arena;
   char** caNameStrings;
   UniqueCERTCertificate cert;
   UniqueSECKEYPrivateKey privKey;
-  UniqueCERTCertList certList;
-  CERTCertListNode* node;
   UniqueCERTCertNicknames nicknames;
-  int keyError = 0; // used for private key retrieval error
   int32_t NumberOfCerts = 0;
   void* wincx = mSocketInfo;
   nsresult rv;
 
   nsCOMPtr<nsIX509Cert> socketClientCert;
   mSocketInfo->GetClientCert(getter_AddRefs(socketClientCert));
 
   // If a client cert preference was set on the socket info, use that and skip
@@ -2147,72 +2144,70 @@ ClientAuthDataRunnable::RunOnTargetThrea
     goto loser;
   }
 
   // find valid user cert and key pair
   if (nsGetUserCertChoice() == UserCertChoice::Auto) {
     // automatically find the right cert
 
     // find all user certs that are valid and for SSL
-    certList.reset(CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
-                                             certUsageSSLClient, false, true,
-                                             wincx));
+    UniqueCERTCertList certList(
+      CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageSSLClient,
+                                false, true, wincx));
     if (!certList) {
-      goto noCert;
+      goto loser;
     }
 
     // filter the list to those issued by CAs supported by the server
     mRV = CERT_FilterCertListByCANames(certList.get(), mCANames->nnames,
                                        caNameStrings, certUsageSSLClient);
     if (mRV != SECSuccess) {
-      goto noCert;
+      goto loser;
     }
 
     // make sure the list is not empty
-    node = CERT_LIST_HEAD(certList);
-    if (CERT_LIST_END(node, certList)) {
-      goto noCert;
+    if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
+      goto loser;
     }
 
     UniqueCERTCertificate lowPrioNonrepCert;
 
     // loop through the list until we find a cert with a key
-    while (!CERT_LIST_END(node, certList)) {
+    for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
+         !CERT_LIST_END(node, certList);
+         node = CERT_LIST_NEXT(node)) {
       // if the certificate has restriction and we do not satisfy it we do not
       // use it
       privKey.reset(PK11_FindKeyByAnyCert(node->cert, wincx));
       if (privKey) {
         if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
           privKey = nullptr;
           // Not a preferred cert
           if (!lowPrioNonrepCert) { // did not yet find a low prio cert
             lowPrioNonrepCert.reset(CERT_DupCertificate(node->cert));
           }
         } else {
           // this is a good cert to present
           cert.reset(CERT_DupCertificate(node->cert));
           break;
         }
       }
-      keyError = PR_GetError();
-      if (keyError == SEC_ERROR_BAD_PASSWORD) {
+      if (PR_GetError() == SEC_ERROR_BAD_PASSWORD) {
         // problem with password: bail
         goto loser;
       }
-
-      node = CERT_LIST_NEXT(node);
     }
 
     if (!cert && lowPrioNonrepCert) {
       cert = Move(lowPrioNonrepCert);
       privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
     }
 
     if (!cert) {
-      goto noCert;
+      goto loser;
     }
   } else { // Not Auto => ask
     // Get the SSL Certificate
 
     nsXPIDLCString hostname;
     mSocketInfo->GetHostName(getter_Copies(hostname));
 
     RefPtr<nsClientAuthRememberService> cars =
@@ -2224,84 +2219,72 @@ ClientAuthDataRunnable::RunOnTargetThrea
       bool found;
       rv = cars->HasRememberedDecision(hostname, mServerCert,
         rememberedDBKey, &found);
       if (NS_SUCCEEDED(rv) && found) {
         hasRemembered = true;
       }
     }
 
-    bool canceled = false;
-
-    if (hasRemembered) {
-      if (rememberedDBKey.IsEmpty()) {
-        canceled = true;
-      } else {
-        nsCOMPtr<nsIX509CertDB> certdb;
-        certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
-        if (certdb) {
-          nsCOMPtr<nsIX509Cert> found_cert;
-          nsresult find_rv =
-            certdb->FindCertByDBKey(rememberedDBKey.get(),
-            getter_AddRefs(found_cert));
-          if (NS_SUCCEEDED(find_rv) && found_cert) {
-            nsNSSCertificate* obj_cert =
-              BitwiseCast<nsNSSCertificate*, nsIX509Cert*>(found_cert.get());
-            if (obj_cert) {
-              cert.reset(obj_cert->GetCert());
-            }
+    if (hasRemembered && !rememberedDBKey.IsEmpty()) {
+      nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
+      if (certdb) {
+        nsCOMPtr<nsIX509Cert> foundCert;
+        rv = certdb->FindCertByDBKey(rememberedDBKey.get(),
+                                     getter_AddRefs(foundCert));
+        if (NS_SUCCEEDED(rv) && foundCert) {
+          nsNSSCertificate* objCert =
+            BitwiseCast<nsNSSCertificate*, nsIX509Cert*>(foundCert.get());
+          if (objCert) {
+            cert.reset(objCert->GetCert());
           }
-
-          if (!cert) {
-            hasRemembered = false;
-          }
+        }
+
+        if (!cert) {
+          hasRemembered = false;
         }
       }
     }
 
     if (!hasRemembered) {
       // user selects a cert to present
       nsCOMPtr<nsIClientAuthDialogs> dialogs;
-      int32_t selectedIndex = -1;
       char16_t** certNicknameList = nullptr;
       char16_t** certDetailsList = nullptr;
 
       // find all user certs that are for SSL
       // note that we are allowing expired certs in this list
-      certList.reset(CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
-                                               certUsageSSLClient, false,
-                                               false, wincx));
+      UniqueCERTCertList certList(
+        CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageSSLClient,
+                                  false, false, wincx));
       if (!certList) {
-        goto noCert;
+        goto loser;
       }
 
       if (mCANames->nnames != 0) {
         // filter the list to those issued by CAs supported by the server
         mRV = CERT_FilterCertListByCANames(certList.get(),
                                            mCANames->nnames,
                                            caNameStrings,
                                            certUsageSSLClient);
         if (mRV != SECSuccess) {
           goto loser;
         }
       }
 
       if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
         // list is empty - no matching certs
-        goto noCert;
+        goto loser;
       }
 
       // filter it further for hostname restriction
-      node = CERT_LIST_HEAD(certList.get());
-      while (!CERT_LIST_END(node, certList.get())) {
+      for (CERTCertListNode* node = CERT_LIST_HEAD(certList.get());
+           !CERT_LIST_END(node, certList.get());
+           node = CERT_LIST_NEXT(node)) {
         ++NumberOfCerts;
-        node = CERT_LIST_NEXT(node);
-      }
-      if (CERT_LIST_END(CERT_LIST_HEAD(certList.get()), certList.get())) {
-        goto noCert;
       }
 
       nicknames.reset(getNSSCertNicknamesFromCertList(certList));
 
       if (!nicknames) {
         goto loser;
       }
 
@@ -2309,17 +2292,17 @@ ClientAuthDataRunnable::RunOnTargetThrea
 
       // Get CN and O of the subject and O of the issuer
       UniquePORTString ccn(CERT_GetCommonName(&mServerCert->subject));
       NS_ConvertUTF8toUTF16 cn(ccn.get());
 
       int32_t port;
       mSocketInfo->GetPort(&port);
 
-      nsString cn_host_port;
+      nsAutoString cn_host_port;
       if (ccn && strcmp(ccn.get(), hostname) == 0) {
         cn_host_port.Append(cn);
         cn_host_port.Append(':');
         cn_host_port.AppendInt(port);
       } else {
         cn_host_port.Append(cn);
         cn_host_port.AppendLiteral(" (");
         cn_host_port.Append(':');
@@ -2339,21 +2322,20 @@ ClientAuthDataRunnable::RunOnTargetThrea
         goto loser;
       certDetailsList =
         (char16_t**)moz_xmalloc(sizeof(char16_t*)* nicknames->numnicknames);
       if (!certDetailsList) {
         free(certNicknameList);
         goto loser;
       }
 
-      int32_t CertsToUse;
-      for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
-        !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
-        node = CERT_LIST_NEXT(node)
-        ) {
+      int32_t CertsToUse = 0;
+      for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
+           !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
+           node = CERT_LIST_NEXT(node)) {
         RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
 
         if (!tempCert)
           continue;
 
         NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
         nsAutoString nickWithSerial, details;
 
@@ -2368,80 +2350,74 @@ ClientAuthDataRunnable::RunOnTargetThrea
           free(certNicknameList[CertsToUse]);
           continue;
         }
 
         ++CertsToUse;
       }
 
       // Throw up the client auth dialog and get back the index of the selected cert
-      nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
-                                  NS_GET_IID(nsIClientAuthDialogs),
-                                  NS_CLIENTAUTHDIALOGS_CONTRACTID);
+      rv = getNSSDialogs(getter_AddRefs(dialogs),
+                         NS_GET_IID(nsIClientAuthDialogs),
+                         NS_CLIENTAUTHDIALOGS_CONTRACTID);
 
       if (NS_FAILED(rv)) {
         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
         goto loser;
       }
 
-      rv = dialogs->ChooseCertificate(mSocketInfo, cn_host_port.get(),
-                                      org.get(), issuer.get(),
+      uint32_t selectedIndex = 0;
+      bool certChosen = false;
+      rv = dialogs->ChooseCertificate(mSocketInfo, cn_host_port, org, issuer,
                                       (const char16_t**)certNicknameList,
                                       (const char16_t**)certDetailsList,
-                                      CertsToUse, &selectedIndex, &canceled);
+                                      CertsToUse, &selectedIndex, &certChosen);
 
       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
 
-      if (NS_FAILED(rv)) goto loser;
+      if (NS_FAILED(rv)) {
+        goto loser;
+      }
 
       // even if the user has canceled, we want to remember that, to avoid repeating prompts
       bool wantRemember = false;
       mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
 
-      int i;
-      if (!canceled)
-      for (i = 0, node = CERT_LIST_HEAD(certList);
-        !CERT_LIST_END(node, certList);
-        ++i, node = CERT_LIST_NEXT(node)) {
-
-        if (i == selectedIndex) {
-          cert.reset(CERT_DupCertificate(node->cert));
-          break;
+      if (certChosen) {
+        uint32_t i = 0;
+        for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
+             !CERT_LIST_END(node, certList);
+             ++i, node = CERT_LIST_NEXT(node)) {
+          if (i == selectedIndex) {
+            cert.reset(CERT_DupCertificate(node->cert));
+            break;
+          }
         }
       }
 
       if (cars && wantRemember) {
         cars->RememberDecision(hostname, mServerCert,
-          canceled ? nullptr : cert.get());
+                               certChosen ? cert.get() : nullptr);
       }
     }
 
-    if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
-
     if (!cert) {
       goto loser;
     }
 
     // go get the private key
     privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
     if (!privKey) {
-      keyError = PR_GetError();
-      if (keyError == SEC_ERROR_BAD_PASSWORD) {
-        // problem with password: bail
-        goto loser;
-      } else {
-        goto noCert;
-      }
+      goto loser;
     }
   }
   goto done;
 
-noCert:
 loser:
   if (mRV == SECSuccess) {
     mRV = SECFailure;
   }
 done:
   int error = PR_GetError();
 
   *mPRetCert = cert.release();