diff options
Diffstat (limited to 'browser/components/extensions/parent/ext-pkcs11.js')
-rw-r--r-- | browser/components/extensions/parent/ext-pkcs11.js | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/browser/components/extensions/parent/ext-pkcs11.js b/browser/components/extensions/parent/ext-pkcs11.js new file mode 100644 index 0000000000..5f72786cae --- /dev/null +++ b/browser/components/extensions/parent/ext-pkcs11.js @@ -0,0 +1,187 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +XPCOMUtils.defineLazyModuleGetters(this, { + ctypes: "resource://gre/modules/ctypes.jsm", + NativeManifests: "resource://gre/modules/NativeManifests.jsm", +}); + +XPCOMUtils.defineLazyServiceGetter( + this, + "pkcs11db", + "@mozilla.org/security/pkcs11moduledb;1", + "nsIPKCS11ModuleDB" +); + +// eslint-disable-next-line mozilla/reject-importGlobalProperties +Cu.importGlobalProperties(["PathUtils"]); + +var { DefaultMap } = ExtensionUtils; + +const findModuleByPath = function(path) { + for (let module of pkcs11db.listModules()) { + if (module && module.libName === path) { + return module; + } + } + return null; +}; + +this.pkcs11 = class extends ExtensionAPI { + getAPI(context) { + let manifestCache = new DefaultMap(async name => { + let hostInfo = await NativeManifests.lookupManifest( + "pkcs11", + name, + context + ); + if (hostInfo) { + // We don't normalize the absolute path below because + // `Path.normalize` throws when the target file doesn't + // exist, and that might be the case on non Windows + // builds. + let absolutePath = PathUtils.isAbsolute(hostInfo.manifest.path) + ? hostInfo.manifest.path + : PathUtils.joinRelative( + PathUtils.parent(hostInfo.path), + hostInfo.manifest.path + ); + + if (AppConstants.platform === "win") { + // On Windows, `hostInfo.manifest.path` is expected to be a normalized + // absolute path. On other platforms, this path may be relative but we + // cannot use `PathUtils.normalize()` on non-absolute paths. + absolutePath = PathUtils.normalize(absolutePath); + hostInfo.manifest.path = absolutePath; + } + + // PathUtils.filename throws if the path is not an absolute path. + // The result is expected to be the basename of the file (without + // the dir path and the extension) so it is fine to use an absolute + // path that may not be normalized (non-Windows platforms). + let manifestLib = PathUtils.filename(absolutePath); + + if (AppConstants.platform !== "linux") { + manifestLib = manifestLib.toLowerCase(manifestLib); + } + if ( + manifestLib !== ctypes.libraryName("nssckbi") && + manifestLib !== ctypes.libraryName("osclientcerts") && + manifestLib !== ctypes.libraryName("ipcclientcerts") + ) { + return hostInfo.manifest; + } + } + return Promise.reject({ message: `No such PKCS#11 module ${name}` }); + }); + return { + pkcs11: { + /** + * Verify whether a given PKCS#11 module is installed. + * + * @param {string} name The name of the module, as specified in + * the manifest file. + * @returns {Promise} A Promise that resolves to true if the package + * is installed, or false if it is not. May be + * rejected if the module could not be found. + */ + async isModuleInstalled(name) { + let manifest = await manifestCache.get(name); + return findModuleByPath(manifest.path) !== null; + }, + /** + * Install a PKCS#11 module + * + * @param {string} name The name of the module, as specified in + * the manifest file. + * @param {integer} [flags = 0] Any flags to be passed on to the + * nsIPKCS11ModuleDB.addModule method + * @returns {Promise} When the Promise resolves, the module will have + * been installed. When it is rejected, the module + * either is already installed or could not be + * installed for some reason. + */ + async installModule(name, flags = 0) { + let manifest = await manifestCache.get(name); + if (!manifest.description) { + return Promise.reject({ + message: `The description field in the manifest for PKCS#11 module ${name} must have a value`, + }); + } + pkcs11db.addModule(manifest.description, manifest.path, flags, 0); + }, + /** + * Uninstall a PKCS#11 module + * + * @param {string} name The name of the module, as specified in + * the manifest file. + * @returns {Promise}. When the Promise resolves, the module will have + * been uninstalled. When it is rejected, the + * module either was not installed or could not be + * uninstalled for some reason. + */ + async uninstallModule(name) { + let manifest = await manifestCache.get(name); + let module = findModuleByPath(manifest.path); + if (!module) { + return Promise.reject({ + message: `The PKCS#11 module ${name} is not loaded`, + }); + } + pkcs11db.deleteModule(module.name); + }, + /** + * Get a list of slots for a given PKCS#11 module, with + * information on the token (if any) in the slot. + * + * The PKCS#11 standard defines slots as an abstract concept + * that may or may not have at most one token. In practice, when + * using PKCS#11 for smartcards (the most likely use case of + * PKCS#11 for Firefox), a slot corresponds to a cardreader, and + * a token corresponds to a card. + * + * @param {string} name The name of the PKCS#11 module, as + * specified in the manifest file. + * @returns {Promise} A promise that resolves to an array of objects + * with two properties. The `name` object contains + * the name of the slot; the `token` object is null + * if there is no token in the slot, or is an object + * describing various properties of the token if + * there is. + */ + async getModuleSlots(name) { + let manifest = await manifestCache.get(name); + let module = findModuleByPath(manifest.path); + if (!module) { + return Promise.reject({ + message: `The module ${name} is not installed`, + }); + } + let rv = []; + for (let slot of module.listSlots()) { + let token = slot.getToken(); + let slotobj = { + name: slot.name, + token: null, + }; + if (slot.status != 1 /* SLOT_NOT_PRESENT */) { + slotobj.token = { + name: token.tokenName, + manufacturer: token.tokenManID, + HWVersion: token.tokenHWVersion, + FWVersion: token.tokenFWVersion, + serial: token.tokenSerialNumber, + isLoggedIn: token.isLoggedIn(), + }; + } + rv.push(slotobj); + } + return rv; + }, + }, + }; + } +}; |