tor-browser

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

head.js (6510B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 let exports = this;
      8 
      9 const scripts = [
     10  "pkijs/common.js",
     11  "pkijs/asn1.js",
     12  "pkijs/x509_schema.js",
     13  "pkijs/x509_simpl.js",
     14  "browser/cbor.js",
     15  "browser/u2futil.js",
     16 ];
     17 
     18 for (let script of scripts) {
     19  Services.scriptloader.loadSubScript(
     20    `chrome://mochitests/content/browser/dom/webauthn/tests/${script}`,
     21    this
     22  );
     23 }
     24 
     25 function add_virtual_authenticator(autoremove = true) {
     26  let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
     27    Ci.nsIWebAuthnService
     28  );
     29  let id = webauthnService.addVirtualAuthenticator(
     30    "ctap2_1",
     31    "internal",
     32    true,
     33    true,
     34    true,
     35    true
     36  );
     37  if (autoremove) {
     38    registerCleanupFunction(() => {
     39      webauthnService.removeVirtualAuthenticator(id);
     40    });
     41  }
     42  return id;
     43 }
     44 
     45 function remove_virtual_authenticator(authenticatorId) {
     46  let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
     47    Ci.nsIWebAuthnService
     48  );
     49  webauthnService.removeVirtualAuthenticator(authenticatorId);
     50 }
     51 
     52 async function addCredential(authenticatorId, rpId) {
     53  let keyPair = await crypto.subtle.generateKey(
     54    {
     55      name: "ECDSA",
     56      namedCurve: "P-256",
     57    },
     58    true,
     59    ["sign"]
     60  );
     61 
     62  let credId = new Uint8Array(32);
     63  crypto.getRandomValues(credId);
     64  credId = bytesToBase64UrlSafe(credId);
     65 
     66  let privateKey = await crypto.subtle
     67    .exportKey("pkcs8", keyPair.privateKey)
     68    .then(privateKey => bytesToBase64UrlSafe(privateKey));
     69 
     70  let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
     71    Ci.nsIWebAuthnService
     72  );
     73 
     74  webauthnService.addCredential(
     75    authenticatorId,
     76    credId,
     77    true, // resident key
     78    rpId,
     79    privateKey,
     80    "VGVzdCBVc2Vy", // "Test User"
     81    0 // sign count
     82  );
     83 
     84  return credId;
     85 }
     86 
     87 async function removeCredential(authenticatorId, credId) {
     88  let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
     89    Ci.nsIWebAuthnService
     90  );
     91 
     92  webauthnService.removeCredential(authenticatorId, credId);
     93 }
     94 
     95 function memcmp(x, y) {
     96  let xb = new Uint8Array(x);
     97  let yb = new Uint8Array(y);
     98 
     99  if (x.byteLength != y.byteLength) {
    100    return false;
    101  }
    102 
    103  for (let i = 0; i < xb.byteLength; ++i) {
    104    if (xb[i] != yb[i]) {
    105      return false;
    106    }
    107  }
    108 
    109  return true;
    110 }
    111 
    112 function arrivingHereIsBad(aResult) {
    113  ok(false, "Bad result! Received a: " + aResult);
    114 }
    115 
    116 function expectError(aType) {
    117  let expected = `${aType}Error`;
    118  return function (aResult) {
    119    is(
    120      aResult.slice(0, expected.length),
    121      expected,
    122      `Expecting a ${aType}Error`
    123    );
    124  };
    125 }
    126 
    127 /* eslint-disable no-shadow */
    128 function promiseWebAuthnMakeCredential(
    129  tab,
    130  attestation = "none",
    131  residentKey = "discouraged",
    132  extensions = {}
    133 ) {
    134  return ContentTask.spawn(
    135    tab.linkedBrowser,
    136    [attestation, residentKey, extensions],
    137    ([attestation, residentKey, extensions]) => {
    138      const cose_alg_ECDSA_w_SHA256 = -7;
    139 
    140      let challenge = content.crypto.getRandomValues(new Uint8Array(16));
    141 
    142      let pubKeyCredParams = [
    143        {
    144          type: "public-key",
    145          alg: cose_alg_ECDSA_w_SHA256,
    146        },
    147      ];
    148 
    149      let publicKey = {
    150        rp: { id: content.document.domain, name: "none" },
    151        user: {
    152          id: new Uint8Array(),
    153          name: "none",
    154          displayName: "none",
    155        },
    156        pubKeyCredParams,
    157        authenticatorSelection: {
    158          authenticatorAttachment: "cross-platform",
    159          residentKey,
    160        },
    161        extensions,
    162        attestation,
    163        challenge,
    164      };
    165 
    166      return content.navigator.credentials
    167        .create({ publicKey })
    168        .then(credential => {
    169          return {
    170            clientDataJSON: credential.response.clientDataJSON,
    171            attObj: credential.response.attestationObject,
    172            rawId: credential.rawId,
    173          };
    174        });
    175    }
    176  );
    177 }
    178 
    179 function promiseWebAuthnGetAssertion(tab, key_handle = null, extensions = {}) {
    180  return ContentTask.spawn(
    181    tab.linkedBrowser,
    182    [key_handle, extensions],
    183    ([key_handle, extensions]) => {
    184      let challenge = content.crypto.getRandomValues(new Uint8Array(16));
    185      if (key_handle == null) {
    186        key_handle = content.crypto.getRandomValues(new Uint8Array(16));
    187      }
    188 
    189      let credential = {
    190        id: key_handle,
    191        type: "public-key",
    192        transports: ["usb"],
    193      };
    194 
    195      let publicKey = {
    196        challenge,
    197        extensions,
    198        rpId: content.document.domain,
    199        allowCredentials: [credential],
    200      };
    201 
    202      return content.navigator.credentials
    203        .get({ publicKey })
    204        .then(assertion => {
    205          return {
    206            authenticatorData: assertion.response.authenticatorData,
    207            clientDataJSON: assertion.response.clientDataJSON,
    208            extensions: assertion.getClientExtensionResults(),
    209            signature: assertion.response.signature,
    210          };
    211        });
    212    }
    213  );
    214 }
    215 
    216 function promiseWebAuthnGetAssertionDiscoverable(
    217  tab,
    218  mediation = "optional",
    219  extensions = {}
    220 ) {
    221  return ContentTask.spawn(
    222    tab.linkedBrowser,
    223    [extensions, mediation],
    224    ([extensions, mediation]) => {
    225      let challenge = content.crypto.getRandomValues(new Uint8Array(16));
    226 
    227      let publicKey = {
    228        challenge,
    229        extensions,
    230        rpId: content.document.domain,
    231        allowCredentials: [],
    232      };
    233 
    234      return content.navigator.credentials.get({ publicKey, mediation });
    235    }
    236  );
    237 }
    238 
    239 function checkRpIdHash(rpIdHash, hostname) {
    240  return crypto.subtle
    241    .digest("SHA-256", string2buffer(hostname))
    242    .then(calculatedRpIdHash => {
    243      let calcHashStr = bytesToBase64UrlSafe(
    244        new Uint8Array(calculatedRpIdHash)
    245      );
    246      let providedHashStr = bytesToBase64UrlSafe(new Uint8Array(rpIdHash));
    247 
    248      if (calcHashStr != providedHashStr) {
    249        throw new Error("Calculated RP ID hash doesn't match.");
    250      }
    251    });
    252 }
    253 
    254 function promiseNotification(id) {
    255  return new Promise(resolve => {
    256    PopupNotifications.panel.addEventListener("popupshown", function shown() {
    257      let notification = PopupNotifications.getNotification(id);
    258      if (notification) {
    259        ok(true, `${id} prompt visible`);
    260        PopupNotifications.panel.removeEventListener("popupshown", shown);
    261        resolve();
    262      }
    263    });
    264  });
    265 }
    266 /* eslint-enable no-shadow */