1 /* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* import-globals-from pippki.js */
9 const { parse, pemToDER } = ChromeUtils.importESModule(
10 "chrome://global/content/certviewer/certDecoder.mjs"
14 * @file Implements the functionality of clientauthask.xhtml: a dialog that allows
15 * a user pick a client certificate for TLS client authentication.
16 * @param {object} window.arguments.0
17 * An Object with the properties:
19 * The hostname of the server requesting client authentication.
20 * {Array<nsIX509Cert>} certArray
21 * Array of certificates the user can choose from
23 * Object to set the return values of calling the dialog on.
24 * See ClientAuthAskReturnValues.
28 * @typedef ClientAuthAskReturnValues
30 * @property {nsIX509Cert} cert
31 * The certificate, if chosen. null otherwise.
32 * @property {boolean} rememberDecision
33 * Set to true if the user wanted their cert selection to be
34 * remembered, false otherwise.
38 * The array of certs the user can choose from.
40 * @type {Array<nsIX509Cert>}
45 * The checkbox storing whether the user wants to remember the selected cert.
47 * @type {HTMLInputElement} Element checkbox, has to have |checked| property.
49 var rememberBox, args;
51 async function onLoad() {
52 let rememberSetting = Services.prefs.getBoolPref(
53 "security.remember_cert_checkbox_default_setting"
55 rememberBox = document.getElementById("rememberBox");
56 rememberBox.checked = rememberSetting;
58 let propBag = window.arguments[0]
59 .QueryInterface(Ci.nsIWritablePropertyBag2)
60 .QueryInterface(Ci.nsIWritablePropertyBag);
62 for (let prop of propBag.enumerator) {
63 args[prop.name] = prop.value;
66 certArray = args.certArray;
68 document.l10n.setAttributes(
69 document.getElementById("clientAuthSiteIdentification"),
70 "client-auth-site-identification",
71 { hostname: args.hostname }
74 let selectElement = document.getElementById("nicknames");
75 for (let i = 0; i < certArray.length; i++) {
76 let menuItemNode = document.createXULElement("menuitem");
77 let cert = certArray[i];
78 let nickAndSerial = `${cert.displayName} [${cert.serialNumber}]`;
79 menuItemNode.setAttribute("value", i);
80 menuItemNode.setAttribute("label", nickAndSerial); // This is displayed.
81 selectElement.menupopup.appendChild(menuItemNode);
83 selectElement.selectedItem = menuItemNode;
88 document.addEventListener("dialogaccept", doOK);
89 document.addEventListener("dialogcancel", doCancel);
91 Services.obs.notifyObservers(
92 document.getElementById("certAuthAsk"),
98 * Populates the details section with information concerning the selected cert.
100 async function setDetails() {
101 let index = parseInt(document.getElementById("nicknames").value);
102 let cert = certArray[index];
103 document.l10n.setAttributes(
104 document.getElementById("clientAuthCertDetailsIssuedTo"),
105 "client-auth-cert-details-issued-to",
106 { issuedTo: cert.subjectName }
108 document.l10n.setAttributes(
109 document.getElementById("clientAuthCertDetailsSerialNumber"),
110 "client-auth-cert-details-serial-number",
111 { serialNumber: cert.serialNumber }
113 const formatter = new Intl.DateTimeFormat(undefined, {
117 document.l10n.setAttributes(
118 document.getElementById("clientAuthCertDetailsValidityPeriod"),
119 "client-auth-cert-details-validity-period",
121 notBefore: formatter.format(new Date(cert.validity.notBefore / 1000)),
122 notAfter: formatter.format(new Date(cert.validity.notAfter / 1000)),
125 let parsedCert = await parse(pemToDER(cert.getBase64DERString()));
126 let keyUsages = parsedCert.ext.keyUsages;
127 let keyUsagesJoined =
128 keyUsages && keyUsages.purposes.length ? keyUsages.purposes.join(", ") : "";
129 document.l10n.setAttributes(
130 document.getElementById("clientAuthCertDetailsKeyUsages"),
131 "client-auth-cert-details-key-usages",
132 { keyUsages: keyUsagesJoined }
134 let emailAddresses = cert.getEmailAddresses();
135 let emailAddressesJoined = emailAddresses.length
136 ? emailAddresses.join(", ")
138 document.l10n.setAttributes(
139 document.getElementById("clientAuthCertDetailsEmailAddresses"),
140 "client-auth-cert-details-email-addresses",
141 { emailAddresses: emailAddressesJoined }
143 document.l10n.setAttributes(
144 document.getElementById("clientAuthCertDetailsIssuedBy"),
145 "client-auth-cert-details-issued-by",
146 { issuedBy: cert.issuerName }
148 document.l10n.setAttributes(
149 document.getElementById("clientAuthCertDetailsStoredOn"),
150 "client-auth-cert-details-stored-on",
151 { storedOn: cert.tokenName }
155 async function onCertSelected() {
160 let { retVals } = args;
161 let index = parseInt(document.getElementById("nicknames").value);
162 let cert = certArray[index];
164 retVals.rememberDecision = rememberBox.checked;
167 function doCancel() {
168 let { retVals } = args;
170 retVals.rememberDecision = rememberBox.checked;