tor-browser

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

browser_clientAuth_ui.js (6582B)


      1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
      2 // Any copyright is dedicated to the Public Domain.
      3 // http://creativecommons.org/publicdomain/zero/1.0/
      4 "use strict";
      5 
      6 // Tests that the client authentication certificate chooser correctly displays
      7 // provided information and correctly returns user input.
      8 
      9 const TEST_HOSTNAME = "Test Hostname";
     10 const TEST_ORG = "Test Org";
     11 const TEST_ISSUER_ORG = "Test Issuer Org";
     12 const TEST_PORT = 123;
     13 
     14 var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
     15  Ci.nsIX509CertDB
     16 );
     17 
     18 ChromeUtils.defineESModuleGetters(this, {
     19  PromptUtils: "resource://gre/modules/PromptUtils.sys.mjs",
     20 });
     21 
     22 /**
     23 * Test certificate (i.e. build/pgo/certs/mochitest.client).
     24 *
     25 * @type {nsIX509Cert}
     26 */
     27 var cert;
     28 
     29 /**
     30 * Opens the client auth cert chooser dialog.
     31 *
     32 * @param {nsIX509Cert} cert The cert to pass to the dialog for display.
     33 * @returns {Promise}
     34 *          A promise that resolves when the dialog has finished loading, with
     35 *          an array consisting of:
     36 *            1. The window of the opened dialog.
     37 *            2. The return value nsIWritablePropertyBag2 passed to the dialog.
     38 */
     39 function openClientAuthDialog(cert) {
     40  let certArray = [cert];
     41  let retVals = { cert: undefined, rememberDuration: undefined };
     42  let args = PromptUtils.objectToPropBag({
     43    hostname: TEST_HOSTNAME,
     44    certArray,
     45    retVals,
     46  });
     47  let win = window.openDialog(
     48    "chrome://pippki/content/clientauthask.xhtml",
     49    "",
     50    "",
     51    args
     52  );
     53  return TestUtils.topicObserved("cert-dialog-loaded").then(() => {
     54    return { win, retVals };
     55  });
     56 }
     57 
     58 /**
     59 * Checks that the contents of the given cert chooser dialog match the details
     60 * of build/pgo/certs/mochitest.client.
     61 *
     62 * @param {window} win The cert chooser window.
     63 * @param {string} notBefore
     64 *        The formatted notBefore date of mochitest.client.
     65 * @param {string} notAfter
     66 *        The formatted notAfter date of mochitest.client.
     67 */
     68 async function checkDialogContents(win, notBefore, notAfter) {
     69  await TestUtils.waitForCondition(() => {
     70    return win.document
     71      .getElementById("clientAuthSiteIdentification")
     72      .textContent.includes(`${TEST_HOSTNAME}`);
     73  });
     74  let nicknames = win.document.getElementById("nicknames");
     75  await TestUtils.waitForCondition(() => {
     76    return nicknames.label == "Mochitest client [03]";
     77  });
     78  await TestUtils.waitForCondition(() => {
     79    return nicknames.itemCount == 1;
     80  });
     81  let subject = win.document.getElementById("clientAuthCertDetailsIssuedTo");
     82  await TestUtils.waitForCondition(() => {
     83    return subject.textContent == "Issued to: CN=Mochitest client";
     84  });
     85  let serialNum = win.document.getElementById(
     86    "clientAuthCertDetailsSerialNumber"
     87  );
     88  await TestUtils.waitForCondition(() => {
     89    return serialNum.textContent == "Serial number: 03";
     90  });
     91  let validity = win.document.getElementById(
     92    "clientAuthCertDetailsValidityPeriod"
     93  );
     94  await TestUtils.waitForCondition(() => {
     95    return validity.textContent == `Valid from ${notBefore} to ${notAfter}`;
     96  });
     97  let issuer = win.document.getElementById("clientAuthCertDetailsIssuedBy");
     98  await TestUtils.waitForCondition(() => {
     99    return (
    100      issuer.textContent ==
    101      "Issued by: OU=Profile Guided Optimization,O=Mozilla Testing,CN=Temporary Certificate Authority"
    102    );
    103  });
    104  let tokenName = win.document.getElementById("clientAuthCertDetailsStoredOn");
    105  await TestUtils.waitForCondition(() => {
    106    return tokenName.textContent == "Stored on: Software Security Device";
    107  });
    108 }
    109 
    110 function findCertByCommonName(commonName) {
    111  for (let cert of certDB.getCerts()) {
    112    if (cert.commonName == commonName) {
    113      return cert;
    114    }
    115  }
    116  return null;
    117 }
    118 
    119 add_setup(async function () {
    120  cert = findCertByCommonName("Mochitest client");
    121  isnot(cert, null, "Should be able to find the test client cert");
    122 });
    123 
    124 // Test that the contents of the dialog correspond to the details of the
    125 // provided cert.
    126 add_task(async function testContents() {
    127  const formatter = new Intl.DateTimeFormat(undefined, {
    128    dateStyle: "medium",
    129    timeStyle: "long",
    130  });
    131  let { win } = await openClientAuthDialog(cert);
    132  await checkDialogContents(
    133    win,
    134    formatter.format(new Date(cert.validity.notBefore / 1000)),
    135    formatter.format(new Date(cert.validity.notAfter / 1000))
    136  );
    137  await BrowserTestUtils.closeWindow(win);
    138 });
    139 
    140 // Test that the right values are returned when the dialog is accepted.
    141 add_task(async function testAcceptDialogReturnValues() {
    142  let { win, retVals } = await openClientAuthDialog(cert);
    143  win.document.getElementById("rememberSetting").value = 1;
    144  info("Accepting dialog");
    145  win.document.getElementById("certAuthAsk").acceptDialog();
    146  await BrowserTestUtils.windowClosed(win);
    147 
    148  is(retVals.cert, cert, "cert should be returned as chosen cert");
    149  is(
    150    retVals.rememberDuration,
    151    1,
    152    "Return value should signal 'Remember persistently' option was selected"
    153  );
    154 });
    155 
    156 // Test that the right values are returned when the dialog is canceled.
    157 add_task(async function testCancelDialogReturnValues() {
    158  let { win, retVals } = await openClientAuthDialog(cert);
    159  win.document.getElementById("rememberSetting").value = 0;
    160  info("Canceling dialog");
    161  win.document.getElementById("certAuthAsk").cancelDialog();
    162  await BrowserTestUtils.windowClosed(win);
    163 
    164  ok(
    165    !retVals.cert,
    166    "Return value should signal user did not choose a certificate"
    167  );
    168  is(
    169    retVals.rememberDuration,
    170    0,
    171    "Return value should signal 'Remember once' was selected"
    172  );
    173 });
    174 
    175 async function testDefaultRememberSettingFromPreference(
    176  preferenceValue,
    177  expectedSetting
    178 ) {
    179  Services.prefs.setIntPref(
    180    "security.client_auth_certificate_default_remember_setting",
    181    preferenceValue
    182  );
    183  let { win } = await openClientAuthDialog(cert);
    184  is(
    185    win.document.getElementById("rememberSetting").value,
    186    expectedSetting,
    187    "remember setting should default to value specified by preference"
    188  );
    189  info("Canceling dialog");
    190  win.document.getElementById("certAuthAsk").cancelDialog();
    191  await BrowserTestUtils.windowClosed(win);
    192 }
    193 
    194 // Test that the preference to set the default remember duration works.
    195 add_task(async function testDefaultRememberSettingFromAllPreferenceValues() {
    196  await testDefaultRememberSettingFromPreference(0, "0");
    197  await testDefaultRememberSettingFromPreference(1, "1");
    198  await testDefaultRememberSettingFromPreference(2, "2");
    199  // Setting the preference to an invalid value will result in the default of "2".
    200  await testDefaultRememberSettingFromPreference(3, "2");
    201 });