tor-browser

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

ext-pkcs11.js (7366B)


      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 ChromeUtils.defineESModuleGetters(this, {
      8  NativeManifests: "resource://gre/modules/NativeManifests.sys.mjs",
      9  ctypes: "resource://gre/modules/ctypes.sys.mjs",
     10 });
     11 
     12 XPCOMUtils.defineLazyServiceGetter(
     13  this,
     14  "pkcs11db",
     15  "@mozilla.org/security/pkcs11moduledb;1",
     16  Ci.nsIPKCS11ModuleDB
     17 );
     18 
     19 // eslint-disable-next-line mozilla/reject-importGlobalProperties
     20 Cu.importGlobalProperties(["PathUtils"]);
     21 
     22 var { DefaultMap } = ExtensionUtils;
     23 
     24 const findModuleByPath = function (path) {
     25  for (let module of pkcs11db.listModules()) {
     26    if (module && module.libName === path) {
     27      return module;
     28    }
     29  }
     30  return null;
     31 };
     32 
     33 this.pkcs11 = class extends ExtensionAPI {
     34  getAPI(context) {
     35    let manifestCache = new DefaultMap(async name => {
     36      let hostInfo = await NativeManifests.lookupManifest(
     37        "pkcs11",
     38        name,
     39        context
     40      );
     41      if (hostInfo) {
     42        // We don't normalize the absolute path below because
     43        // `Path.normalize` throws when the target file doesn't
     44        // exist, and that might be the case on non Windows
     45        // builds.
     46        let absolutePath = PathUtils.isAbsolute(hostInfo.manifest.path)
     47          ? hostInfo.manifest.path
     48          : PathUtils.joinRelative(
     49              PathUtils.parent(hostInfo.path),
     50              hostInfo.manifest.path
     51            );
     52 
     53        if (AppConstants.platform === "win") {
     54          // On Windows, `hostInfo.manifest.path` is expected to be a normalized
     55          // absolute path. On other platforms, this path may be relative but we
     56          // cannot use `PathUtils.normalize()` on non-absolute paths.
     57          absolutePath = PathUtils.normalize(absolutePath);
     58          hostInfo.manifest.path = absolutePath;
     59        }
     60 
     61        // PathUtils.filename throws if the path is not an absolute path.
     62        // The result is expected to be the basename of the file (without
     63        // the dir path and the extension) so it is fine to use an absolute
     64        // path that may not be normalized (non-Windows platforms).
     65        let manifestLib = PathUtils.filename(absolutePath);
     66 
     67        if (AppConstants.platform !== "linux") {
     68          manifestLib = manifestLib.toLowerCase(manifestLib);
     69        }
     70        if (
     71          manifestLib !== ctypes.libraryName("nssckbi") &&
     72          manifestLib !== ctypes.libraryName("osclientcerts") &&
     73          manifestLib !== ctypes.libraryName("ipcclientcerts")
     74        ) {
     75          return hostInfo.manifest;
     76        }
     77      }
     78      return Promise.reject({ message: `No such PKCS#11 module ${name}` });
     79    });
     80    return {
     81      pkcs11: {
     82        /**
     83         * Verify whether a given PKCS#11 module is installed.
     84         *
     85         * @param {string} name The name of the module, as specified in
     86         *                      the manifest file.
     87         * @returns {Promise} A Promise that resolves to true if the package
     88         *                    is installed, or false if it is not. May be
     89         *                    rejected if the module could not be found.
     90         */
     91        async isModuleInstalled(name) {
     92          let manifest = await manifestCache.get(name);
     93          return findModuleByPath(manifest.path) !== null;
     94        },
     95        /**
     96         * Install a PKCS#11 module
     97         *
     98         * @param {string} name The name of the module, as specified in
     99         *                      the manifest file.
    100         * @param {integer} [flags = 0] Any flags to be passed on to the
    101         *                              nsIPKCS11ModuleDB.addModule method
    102         * @returns {Promise} When the Promise resolves, the module will have
    103         *                    been installed. When it is rejected, the module
    104         *                    either is already installed or could not be
    105         *                    installed for some reason.
    106         */
    107        async installModule(name, flags = 0) {
    108          let manifest = await manifestCache.get(name);
    109          if (!manifest.description) {
    110            return Promise.reject({
    111              message: `The description field in the manifest for PKCS#11 module ${name} must have a value`,
    112            });
    113          }
    114          pkcs11db.addModule(manifest.description, manifest.path, flags, 0);
    115        },
    116        /**
    117         * Uninstall a PKCS#11 module
    118         *
    119         * @param {string} name The name of the module, as specified in
    120         *                      the manifest file.
    121         * @returns {Promise}. When the Promise resolves, the module will have
    122         *                     been uninstalled. When it is rejected, the
    123         *                     module either was not installed or could not be
    124         *                     uninstalled for some reason.
    125         */
    126        async uninstallModule(name) {
    127          let manifest = await manifestCache.get(name);
    128          let module = findModuleByPath(manifest.path);
    129          if (!module) {
    130            return Promise.reject({
    131              message: `The PKCS#11 module ${name} is not loaded`,
    132            });
    133          }
    134          pkcs11db.deleteModule(module.name);
    135        },
    136        /**
    137         * Get a list of slots for a given PKCS#11 module, with
    138         * information on the token (if any) in the slot.
    139         *
    140         * The PKCS#11 standard defines slots as an abstract concept
    141         * that may or may not have at most one token. In practice, when
    142         * using PKCS#11 for smartcards (the most likely use case of
    143         * PKCS#11 for Firefox), a slot corresponds to a cardreader, and
    144         * a token corresponds to a card.
    145         *
    146         * @param {string} name The name of the PKCS#11 module, as
    147         *                 specified in the manifest file.
    148         * @returns {Promise} A promise that resolves to an array of objects
    149         *                    with two properties.  The `name` object contains
    150         *                    the name of the slot; the `token` object is null
    151         *                    if there is no token in the slot, or is an object
    152         *                    describing various properties of the token if
    153         *                    there is.
    154         */
    155        async getModuleSlots(name) {
    156          let manifest = await manifestCache.get(name);
    157          let module = findModuleByPath(manifest.path);
    158          if (!module) {
    159            return Promise.reject({
    160              message: `The module ${name} is not installed`,
    161            });
    162          }
    163          let rv = [];
    164          for (let slot of module.listSlots()) {
    165            let token = slot.getToken();
    166            let slotobj = {
    167              name: slot.name,
    168              token: null,
    169            };
    170            if (slot.status != 1 /* SLOT_NOT_PRESENT */) {
    171              slotobj.token = {
    172                name: token.tokenName,
    173                manufacturer: token.tokenManID,
    174                HWVersion: token.tokenHWVersion,
    175                FWVersion: token.tokenFWVersion,
    176                serial: token.tokenSerialNumber,
    177                isLoggedIn: token.isLoggedIn(),
    178              };
    179            }
    180            rv.push(slotobj);
    181          }
    182          return rv;
    183        },
    184      },
    185    };
    186  }
    187 };