fune/browser/components/extensions/ext-pkcs11.js

145 lines
5.9 KiB
JavaScript

"use strict";
XPCOMUtils.defineLazyModuleGetters(this, {
ctypes: "resource://gre/modules/ctypes.jsm",
NativeManifests: "resource://gre/modules/NativeManifests.jsm",
OS: "resource://gre/modules/osfile.jsm",
});
XPCOMUtils.defineLazyServiceGetter(this,
"pkcs11db",
"@mozilla.org/security/pkcs11moduledb;1",
"nsIPKCS11ModuleDB");
var {DefaultMap} = ExtensionUtils;
const findModuleByPath = function(path) {
let modules = pkcs11db.listModules();
for (let module of XPCOMUtils.IterSimpleEnumerator(modules, Ci.nsIPKCS11Module)) {
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) {
if (AppConstants.platform === "win") {
hostInfo.manifest.path = OS.Path.join(OS.Path.dirname(hostInfo.path), hostInfo.manifest.path);
}
let manifestLib = OS.Path.basename(hostInfo.manifest.path);
if (AppConstants.platform !== "linux") {
manifestLib = manifestLib.toLowerCase(manifestLib);
}
if (manifestLib !== ctypes.libraryName("nssckbi")) {
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 XPCOMUtils.IterSimpleEnumerator(module.listSlots(), Ci.nsIPKCS11Slot)) {
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;
},
},
};
}
};