Files
tubestation/browser/components/extensions/parent/ext-pkcs11.js
Dana Keeler a13bccff29 Bug 1712837 - introduce ipcclientcerts to allow client certificates to work with the socket process r=rmf,kershaw,necko-reviewers,ipc-reviewers,nika,jschanck
This patch introduces ipcclientcerts, a PKCS#11 module that the socket process
can load to get access to client certificates and keys managed by the parent
process. This enables client certificate authentication to work with the socket
process (particularly for keys stored outside of NSS, as with osclientcerts or
third-party PKCS#11 modules).

Differential Revision: https://phabricator.services.mozilla.com/D122392
2021-12-01 18:10:34 +00:00

168 lines
6.2 KiB
JavaScript

/* 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",
OS: "resource://gre/modules/osfile.jsm",
});
XPCOMUtils.defineLazyServiceGetter(
this,
"pkcs11db",
"@mozilla.org/security/pkcs11moduledb;1",
"nsIPKCS11ModuleDB"
);
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) {
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") &&
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;
},
},
};
}
};