Bug 307081 - Make nsIClientAuthDialogs::ChooseCertificate() pass an nsIArray of nsIX509Certs, not strings. r=kats,keeler
This provides implementations of ChooseCertificate() with more flexibility, and
allows callers of ChooseCertificate() to be less complex.
A portion of this work involves reimplementing
nsNSSCertificate::FormatUIStrings() in JS and improving UI strings for l10n.
MozReview-Commit-ID: CE7Uc2ntwmZ
--- a/mobile/android/components/NSSDialogService.js
+++ b/mobile/android/components/NSSDialogService.js
@@ -138,36 +138,78 @@ NSSDialogs.prototype = {
["certmgr.begins", aCert.validity.notBeforeLocalDay,
"certmgr.expires", aCert.validity.notAfterLocalDay])})
.addLabel({ label: this.certInfoSection("certmgr.fingerprints.label",
["certmgr.certdetail.sha256fingerprint", aCert.sha256Fingerprint,
"certmgr.certdetail.sha1fingerprint", aCert.sha1Fingerprint], false) });
this.showPrompt(p);
},
+ /**
+ * Returns a list of details of the given cert relevant for TLS client
+ * authentication.
+ *
+ * @param {nsIX509Cert} cert Cert to get the details of.
+ * @returns {String} <br/> delimited list of details.
+ */
+ getCertDetails: function(cert) {
+ let detailLines = [
+ this.formatString("clientAuthAsk.issuedTo", [cert.subjectName]),
+ this.formatString("clientAuthAsk.serial", [cert.serialNumber]),
+ this.formatString("clientAuthAsk.validityPeriod",
+ [cert.validity.notBeforeLocalTime,
+ cert.validity.notAfterLocalTime]),
+ ];
+ let keyUsages = cert.keyUsages;
+ if (keyUsages) {
+ detailLines.push(this.formatString("clientAuthAsk.keyUsages",
+ [keyUsages]));
+ }
+ let emailAddresses = cert.getEmailAddresses({});
+ if (emailAddresses.length > 0) {
+ let joinedAddresses = emailAddresses.join(", ");
+ detailLines.push(this.formatString("clientAuthAsk.emailAddresses",
+ [joinedAddresses]));
+ }
+ detailLines.push(this.formatString("clientAuthAsk.issuedBy",
+ [cert.issuerName]));
+ detailLines.push(this.formatString("clientAuthAsk.storedOn",
+ [cert.tokenName]));
+
+ return detailLines.join("<br/>");
+ },
+
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(ctx, cnAndPort, organization, issuerOrg,
- certNickList, certDetailsList, count,
+ chooseCertificate: function(ctx, cnAndPort, organization, issuerOrg, certList,
selectedIndex) {
let rememberSetting =
Services.prefs.getBoolPref("security.remember_cert_checkbox_default_setting");
let serverRequestedDetails = [
cnAndPort,
this.formatString("clientAuthAsk.organization", [organization]),
this.formatString("clientAuthAsk.issuer", [issuerOrg]),
].join("<br/>");
+ let certNickList = [];
+ let certDetailsList = [];
+ for (let i = 0; i < certList.length; i++) {
+ let cert = certList.queryElementAt(i, Ci.nsIX509Cert);
+ certNickList.push(this.formatString("clientAuthAsk.nickAndSerial",
+ [cert.nickname, cert.serialNumber]));
+ certDetailsList.push(this.getCertDetails(cert));
+ }
+
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"),
--- a/mobile/android/locales/en-US/chrome/pippki.properties
+++ b/mobile/android/locales/en-US/chrome/pippki.properties
@@ -14,22 +14,50 @@ 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.nickAndSerial): Represents a single cert when
+# the user is choosing from a list of certificates.
+# %1$S is the nickname of the cert.
+# %2$S is the serial number of the cert in AA:BB:CC hex format.
+clientAuthAsk.nickAndSerial=%1$S [%2$S]
# 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"
+# LOCALIZATION NOTE(clientAuthAsk.issuedTo): %1$S is the Distinguished Name of
+# the currently selected client cert, such as "CN=John Doe,OU=Example" (without
+# quotes).
+clientAuthAsk.issuedTo=Issued to: %1$S
+# LOCALIZATION NOTE(clientAuthAsk.serial): %1$S is the serial number of the
+# selected cert in AA:BB:CC hex format.
+clientAuthAsk.serial=Serial number: %1$S
+# LOCALIZATION NOTE(clientAuthAsk.validityPeriod):
+# %1$S is the already localized notBefore date of the selected cert.
+# %2$S is the already localized notAfter date of the selected cert.
+clientAuthAsk.validityPeriod=Valid from %1$S to %2$S
+# LOCALIZATION NOTE(clientAuthAsk.keyUsages): %1$S is a comma separated list of
+# already localized key usages the selected cert is valid for.
+clientAuthAsk.keyUsages=Key Usages: %1$S
+# LOCALIZATION NOTE(clientAuthAsk.emailAddresses): %1$S is a comma separated
+# list of e-mail addresses the selected cert is valid for.
+clientAuthAsk.emailAddresses=Email addresses: %1$S
+# LOCALIZATION NOTE(clientAuthAsk.issuedBy): %1$S is the Distinguished Name of
+# the cert which issued the selected cert.
+clientAuthAsk.issuedBy=Issued by: %1$S
+# LOCALIZATION NOTE(clientAuthAsk.storedOn): %1$S is the name of the PKCS #11
+# token the selected cert is stored on.
+clientAuthAsk.storedOn=Stored on: %1$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
certmgr.fingerprints.label=Fingerprints
--- a/security/manager/locales/en-US/chrome/pippki/pippki.properties
+++ b/security/manager/locales/en-US/chrome/pippki/pippki.properties
@@ -48,22 +48,50 @@ certNotVerified_CertNotTrusted=Could not
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(clientAuthNickAndSerial): Represents a single cert when the
+# user is choosing from a list of certificates.
+# %1$S is the nickname of the cert.
+# %2$S is the serial number of the cert in AA:BB:CC hex format.
+clientAuthNickAndSerial=%1$S [%2$S]
# 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ā
+# LOCALIZATION NOTE(clientAuthIssuedTo): %1$S is the Distinguished Name of the
+# currently selected client cert, such as "CN=John Doe,OU=Example" (without
+# quotes).
+clientAuthIssuedTo=Issued to: %1$S
+# LOCALIZATION NOTE(clientAuthSerial): %1$S is the serial number of the selected
+# cert in AA:BB:CC hex format.
+clientAuthSerial=Serial number: %1$S
+# LOCALIZATION NOTE(clientAuthValidityPeriod):
+# %1$S is the already localized notBefore date of the selected cert.
+# %2$S is the already localized notAfter date of the selected cert.
+clientAuthValidityPeriod=Valid from %1$S to %2$S
+# LOCALIZATION NOTE(clientAuthKeyUsages): %1$S is a comma separated list of
+# already localized key usages the selected cert is valid for.
+clientAuthKeyUsages=Key Usages: %1$S
+# LOCALIZATION NOTE(clientAuthEmailAddresses): %1$S is a comma separated list of
+# e-mail addresses the selected cert is valid for.
+clientAuthEmailAddresses=Email addresses: %1$S
+# LOCALIZATION NOTE(clientAuthIssuedBy): %1$S is the Distinguished Name of the
+# cert which issued the selected cert.
+clientAuthIssuedBy=Issued by: %1$S
+# LOCALIZATION NOTE(clientAuthStoredOn): %1$S is the name of the PKCS #11 token
+# the selected cert is stored on.
+clientAuthStoredOn=Stored on: %1$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):
# %1$S is the name of the encryption standard,
--- a/security/manager/pki/nsNSSDialogs.cpp
+++ b/security/manager/pki/nsNSSDialogs.cpp
@@ -156,66 +156,76 @@ nsNSSDialogs::ConfirmDownloadCACert(nsII
return rv;
}
NS_IMETHODIMP
nsNSSDialogs::ChooseCertificate(nsIInterfaceRequestor* ctx,
const nsAString& cnAndPort,
const nsAString& organization,
const nsAString& issuerOrg,
- const char16_t** certNickList,
- const char16_t** certDetailsList, uint32_t count,
+ nsIArray* certList,
/*out*/ uint32_t* selectedIndex,
/*out*/ bool* certificateChosen)
{
NS_ENSURE_ARG_POINTER(ctx);
+ NS_ENSURE_ARG_POINTER(certList);
NS_ENSURE_ARG_POINTER(selectedIndex);
NS_ENSURE_ARG_POINTER(certificateChosen);
- nsresult rv;
- uint32_t i;
-
*certificateChosen = false;
nsCOMPtr<nsIDialogParamBlock> block =
- do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
- if (!block) return NS_ERROR_FAILURE;
+ do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID);
+ if (!block) {
+ return NS_ERROR_FAILURE;
+ }
- block->SetNumberStrings(4+count*2);
+ nsCOMPtr<nsIMutableArray> paramBlockArray = nsArrayBase::Create();
+ if (!paramBlockArray) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = paramBlockArray->AppendElement(certList, false);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = block->SetObjects(paramBlockArray);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = block->SetNumberStrings(3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
rv = block->SetString(0, PromiseFlatString(cnAndPort).get());
- if (NS_FAILED(rv)) return rv;
-
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
rv = block->SetString(1, PromiseFlatString(organization).get());
- if (NS_FAILED(rv)) return rv;
-
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
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;
+ if (NS_FAILED(rv)) {
+ return rv;
}
- for (i = 0; i < count; i++) {
- rv = block->SetString(i+count+3, certDetailsList[i]);
- if (NS_FAILED(rv)) return rv;
+ rv = nsNSSDialogHelper::openDialog(nullptr,
+ "chrome://pippki/content/clientauthask.xul",
+ block);
+ if (NS_FAILED(rv)) {
+ return rv;
}
- rv = block->SetInt(0, count);
- if (NS_FAILED(rv)) return rv;
-
- rv = nsNSSDialogHelper::openDialog(nullptr,
- "chrome://pippki/content/clientauthask.xul",
- block);
- if (NS_FAILED(rv)) return rv;
-
int32_t status;
rv = block->GetInt(0, &status);
- if (NS_FAILED(rv)) return rv;
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
nsCOMPtr<nsIClientAuthUserDecision> extraResult = do_QueryInterface(ctx);
if (extraResult) {
int32_t rememberSelection;
rv = block->GetInt(2, &rememberSelection);
if (NS_SUCCEEDED(rv)) {
extraResult->SetRememberClientAuthCertificate(rememberSelection!=0);
}
--- a/security/manager/pki/resources/content/clientauthask.js
+++ b/security/manager/pki/resources/content/clientauthask.js
@@ -6,31 +6,40 @@
/* import-globals-from pippki.js */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
/**
+ * The pippki <stringbundle> element.
+ * @type <stringbundle>
+ */
+var bundle;
+/**
+ * The array of certs the user can choose from.
+ * @type nsIArray<nsIX509Cert>
+ */
+var certArray;
+/**
* 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() {
dialogParams = window.arguments[0].QueryInterface(Ci.nsIDialogParamBlock);
- let bundle = document.getElementById("pippki_bundle");
+ 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;
let cnAndPort = dialogParams.GetString(0);
@@ -39,38 +48,65 @@ function onLoad() {
let formattedOrg = bundle.getFormattedString("clientAuthMessage1", [org]);
let formattedIssuerOrg = bundle.getFormattedString("clientAuthMessage2",
[issuerOrg]);
setText("hostname", cnAndPort);
setText("organization", formattedOrg);
setText("issuer", formattedIssuerOrg);
let selectElement = document.getElementById("nicknames");
- itemCount = dialogParams.GetInt(0);
- for (let i = 0; i < itemCount; i++) {
+ certArray = dialogParams.objects.queryElementAt(0, Ci.nsIArray);
+ for (let i = 0; i < certArray.length; i++) {
let menuItemNode = document.createElement("menuitem");
- let nick = dialogParams.GetString(i + 3);
+ let cert = certArray.queryElementAt(i, Ci.nsIX509Cert);
+ let nickAndSerial =
+ bundle.getFormattedString("clientAuthNickAndSerial",
+ [cert.nickname, cert.serialNumber]);
menuItemNode.setAttribute("value", i);
- menuItemNode.setAttribute("label", nick); // this is displayed
+ menuItemNode.setAttribute("label", nickAndSerial); // This is displayed.
selectElement.firstChild.appendChild(menuItemNode);
if (i == 0) {
selectElement.selectedItem = menuItemNode;
}
}
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;
+ let cert = certArray.queryElementAt(index, Ci.nsIX509Cert);
+
+ let detailLines = [
+ bundle.getFormattedString("clientAuthIssuedTo", [cert.subjectName]),
+ bundle.getFormattedString("clientAuthSerial", [cert.serialNumber]),
+ bundle.getFormattedString("clientAuthValidityPeriod",
+ [cert.validity.notBeforeLocalTime,
+ cert.validity.notAfterLocalTime]),
+ ];
+ let keyUsages = cert.keyUsages;
+ if (keyUsages) {
+ detailLines.push(bundle.getFormattedString("clientAuthKeyUsages",
+ [keyUsages]));
+ }
+ let emailAddresses = cert.getEmailAddresses({});
+ if (emailAddresses.length > 0) {
+ let joinedAddresses = emailAddresses.join(", ");
+ detailLines.push(bundle.getFormattedString("clientAuthEmailAddresses",
+ [joinedAddresses]));
+ }
+ detailLines.push(bundle.getFormattedString("clientAuthIssuedBy",
+ [cert.issuerName]));
+ detailLines.push(bundle.getFormattedString("clientAuthStoredOn",
+ [cert.tokenName]));
+
+ document.getElementById("details").value = detailLines.join("\n");
}
function onCertSelected() {
setDetails();
}
function doOK() {
// Signal that the user accepted.
--- a/security/manager/ssl/nsIClientAuthDialogs.idl
+++ b/security/manager/ssl/nsIClientAuthDialogs.idl
@@ -1,39 +1,41 @@
/* 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/. */
#include "nsISupports.idl"
+interface nsIArray;
interface nsIInterfaceRequestor;
/**
* Provides UI for SSL client-auth dialogs.
*/
[scriptable, uuid(fa4c7520-1433-11d5-ba24-00108303b117)]
interface nsIClientAuthDialogs : nsISupports
{
/**
* 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.
+ * @param certList List of certificates the user can choose from.
+ * @param selectedIndex Index of the cert in |certList| that the user chose.
+ * Ignored if the return value is false.
* @return true if a certificate was chosen. false if the user 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,
+ in nsIArray certList,
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
@@ -16,16 +16,17 @@
#include "SharedSSLState.h"
#include "keyhi.h"
#include "mozilla/Casting.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Logging.h"
#include "mozilla/Move.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
+#include "nsArrayUtils.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsClientAuthRemember.h"
#include "nsContentUtils.h"
#include "nsIClientAuthDialogs.h"
#include "nsIConsoleService.h"
#include "nsIPrefService.h"
#include "nsISocketProvider.h"
#include "nsIWebProgressListener.h"
@@ -2094,18 +2095,16 @@ 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;
- UniqueCERTCertNicknames nicknames;
- 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
// the client cert UI and/or search of the user's past cert decisions.
@@ -2242,18 +2241,16 @@ ClientAuthDataRunnable::RunOnTargetThrea
hasRemembered = false;
}
}
}
if (!hasRemembered) {
// user selects a cert to present
nsCOMPtr<nsIClientAuthDialogs> dialogs;
- 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
UniqueCERTCertList certList(
CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageSSLClient,
false, false, wincx));
if (!certList) {
goto loser;
@@ -2270,31 +2267,16 @@ ClientAuthDataRunnable::RunOnTargetThrea
}
}
if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
// list is empty - no matching certs
goto loser;
}
- // filter it further for hostname restriction
- for (CERTCertListNode* node = CERT_LIST_HEAD(certList.get());
- !CERT_LIST_END(node, certList.get());
- node = CERT_LIST_NEXT(node)) {
- ++NumberOfCerts;
- }
-
- nicknames.reset(getNSSCertNicknamesFromCertList(certList));
-
- if (!nicknames) {
- goto loser;
- }
-
- NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");
-
// 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);
nsAutoString cn_host_port;
@@ -2311,93 +2293,63 @@ ClientAuthDataRunnable::RunOnTargetThrea
}
UniquePORTString corg(CERT_GetOrgName(&mServerCert->subject));
NS_ConvertUTF8toUTF16 org(corg.get());
UniquePORTString cissuer(CERT_GetOrgName(&mServerCert->issuer));
NS_ConvertUTF8toUTF16 issuer(cissuer.get());
- certNicknameList =
- (char16_t**)moz_xmalloc(sizeof(char16_t*)* nicknames->numnicknames);
- if (!certNicknameList)
- goto loser;
- certDetailsList =
- (char16_t**)moz_xmalloc(sizeof(char16_t*)* nicknames->numnicknames);
- if (!certDetailsList) {
- free(certNicknameList);
+ nsCOMPtr<nsIMutableArray> certArray = nsArrayBase::Create();
+ if (!certArray) {
goto loser;
}
- int32_t CertsToUse = 0;
for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
- !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
+ !CERT_LIST_END(node, certList);
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;
-
- if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
- continue;
-
- certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
- if (!certNicknameList[CertsToUse])
- continue;
- certDetailsList[CertsToUse] = ToNewUnicode(details);
- if (!certDetailsList[CertsToUse]) {
- free(certNicknameList[CertsToUse]);
- continue;
+ nsCOMPtr<nsIX509Cert> tempCert = nsNSSCertificate::Create(node->cert);
+ if (!tempCert) {
+ goto loser;
}
- ++CertsToUse;
+ rv = certArray->AppendElement(tempCert, false);
+ if (NS_FAILED(rv)) {
+ goto loser;
+ }
}
// Throw up the client auth dialog and get back the index of the selected cert
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;
}
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, &certChosen);
-
- NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
- NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
-
+ certArray, &selectedIndex, &certChosen);
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);
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;
- }
+ nsCOMPtr<nsIX509Cert> selectedCert = do_QueryElementAt(certArray,
+ selectedIndex);
+ if (!selectedCert) {
+ goto loser;
}
+ cert.reset(selectedCert->GetCert());
}
if (cars && wantRemember) {
cars->RememberDecision(hostname, mServerCert,
certChosen ? cert.get() : nullptr);
}
}