tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

clientauthask.js (6063B)


      1 /* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
      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 
      7 "use strict";
      8 
      9 const { parse, pemToDER } = ChromeUtils.importESModule(
     10  "chrome://global/content/certviewer/certDecoder.mjs"
     11 );
     12 
     13 /**
     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:
     18 *              {String} hostname
     19 *                 The hostname of the server requesting client authentication.
     20 *              {Array<nsIX509Cert>} certArray
     21 *                 Array of certificates the user can choose from
     22 *              {Object} retVal
     23 *                 Object to set the return values of calling the dialog on.
     24 *                 See ClientAuthAskReturnValues.
     25 */
     26 
     27 /**
     28 * @typedef ClientAuthAskReturnValues
     29 * @type {object}
     30 * @property {nsIX509Cert} cert
     31 *           The certificate, if chosen. null otherwise.
     32 * @property {number} rememberDuration
     33 *           Set to Ci.nsIClientAuthRememberService.Once if the decision should
     34 *           be remembered once, Ci.nsIClientAuthRememberService.Session if the
     35 *           decision should be remembered for this session, or
     36 *           Ci.nsIClientAuthRememberService.Permanent if the decision should
     37 *           be remembered permanently.
     38 */
     39 
     40 /**
     41 * The array of certs the user can choose from.
     42 *
     43 * @type {Array<nsIX509Cert>}
     44 */
     45 var certArray;
     46 
     47 /**
     48 * The checkbox storing whether the user wants to remember the selected cert.
     49 *
     50 * @type {HTMLInputElement} Element checkbox, has to have |checked| property.
     51 */
     52 var args;
     53 
     54 async function onLoad() {
     55  let rememberSetting = Services.prefs.getIntPref(
     56    "security.client_auth_certificate_default_remember_setting"
     57  );
     58  document.getElementById("rememberSetting").value =
     59    rememberSetting >= 0 && rememberSetting <= 2 ? rememberSetting : 2;
     60 
     61  let propBag = window.arguments[0]
     62    .QueryInterface(Ci.nsIWritablePropertyBag2)
     63    .QueryInterface(Ci.nsIWritablePropertyBag);
     64  args = {};
     65  for (let prop of propBag.enumerator) {
     66    args[prop.name] = prop.value;
     67  }
     68 
     69  certArray = args.certArray;
     70 
     71  document.l10n.setAttributes(
     72    document.getElementById("clientAuthSiteIdentification"),
     73    "client-auth-site-identification",
     74    { hostname: args.hostname }
     75  );
     76 
     77  let selectElement = document.getElementById("nicknames");
     78  for (let i = 0; i < certArray.length; i++) {
     79    let menuItemNode = document.createXULElement("menuitem");
     80    let cert = certArray[i];
     81    let nickAndSerial = `${cert.displayName} [${cert.serialNumber}]`;
     82    menuItemNode.setAttribute("value", i);
     83    menuItemNode.setAttribute("label", nickAndSerial); // This is displayed.
     84    selectElement.menupopup.appendChild(menuItemNode);
     85    if (i == 0) {
     86      selectElement.selectedItem = menuItemNode;
     87    }
     88  }
     89 
     90  await setDetails();
     91  document.addEventListener("dialogaccept", doOK);
     92  document.addEventListener("dialogcancel", doCancel);
     93  document
     94    .getElementById("nicknames")
     95    .addEventListener("command", () => onCertSelected());
     96 
     97  Services.obs.notifyObservers(
     98    document.getElementById("certAuthAsk"),
     99    "cert-dialog-loaded"
    100  );
    101 }
    102 
    103 /**
    104 * Populates the details section with information concerning the selected cert.
    105 */
    106 async function setDetails() {
    107  let index = parseInt(document.getElementById("nicknames").value);
    108  let cert = certArray[index];
    109  document.l10n.setAttributes(
    110    document.getElementById("clientAuthCertDetailsIssuedTo"),
    111    "client-auth-cert-details-issued-to",
    112    { issuedTo: cert.subjectName }
    113  );
    114  document.l10n.setAttributes(
    115    document.getElementById("clientAuthCertDetailsSerialNumber"),
    116    "client-auth-cert-details-serial-number",
    117    { serialNumber: cert.serialNumber }
    118  );
    119  const formatter = new Intl.DateTimeFormat(undefined, {
    120    dateStyle: "medium",
    121    timeStyle: "long",
    122  });
    123  document.l10n.setAttributes(
    124    document.getElementById("clientAuthCertDetailsValidityPeriod"),
    125    "client-auth-cert-details-validity-period",
    126    {
    127      notBefore: formatter.format(new Date(cert.validity.notBefore / 1000)),
    128      notAfter: formatter.format(new Date(cert.validity.notAfter / 1000)),
    129    }
    130  );
    131  let parsedCert = await parse(pemToDER(cert.getBase64DERString()));
    132  let keyUsages = parsedCert.ext.keyUsages;
    133  let keyUsagesJoined =
    134    keyUsages && keyUsages.purposes.length ? keyUsages.purposes.join(", ") : "";
    135  document.l10n.setAttributes(
    136    document.getElementById("clientAuthCertDetailsKeyUsages"),
    137    "client-auth-cert-details-key-usages",
    138    { keyUsages: keyUsagesJoined }
    139  );
    140  let emailAddresses = cert.getEmailAddresses();
    141  let emailAddressesJoined = emailAddresses.length
    142    ? emailAddresses.join(", ")
    143    : "";
    144  document.l10n.setAttributes(
    145    document.getElementById("clientAuthCertDetailsEmailAddresses"),
    146    "client-auth-cert-details-email-addresses",
    147    { emailAddresses: emailAddressesJoined }
    148  );
    149  document.l10n.setAttributes(
    150    document.getElementById("clientAuthCertDetailsIssuedBy"),
    151    "client-auth-cert-details-issued-by",
    152    { issuedBy: cert.issuerName }
    153  );
    154  document.l10n.setAttributes(
    155    document.getElementById("clientAuthCertDetailsStoredOn"),
    156    "client-auth-cert-details-stored-on",
    157    { storedOn: cert.tokenName }
    158  );
    159 }
    160 
    161 async function onCertSelected() {
    162  await setDetails();
    163 }
    164 
    165 function getRememberSetting() {
    166  return parseInt(document.getElementById("rememberSetting").value);
    167 }
    168 
    169 function doOK() {
    170  let { retVals } = args;
    171  let index = parseInt(document.getElementById("nicknames").value);
    172  let cert = certArray[index];
    173  retVals.cert = cert;
    174  retVals.rememberDuration = getRememberSetting();
    175 }
    176 
    177 function doCancel() {
    178  let { retVals } = args;
    179  retVals.cert = null;
    180  retVals.rememberDuration = getRememberSetting();
    181 }
    182 
    183 window.addEventListener("load", () => onLoad());