node-opcua-certificate-manager
Version:
pure nodejs OPCUA SDK - module certificate-manager
142 lines • 6.83 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OPCUACertificateManager = void 0;
exports.getDefaultCertificateManager = getDefaultCertificateManager;
/**
* @module node-opcua-certificate-manager
*/
// tslint:disable:no-empty
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const env_paths_1 = __importDefault(require("env-paths"));
const node_opcua_debug_1 = require("node-opcua-debug");
const web_1 = require("node-opcua-crypto/web");
const node_opcua_pki_1 = require("node-opcua-pki");
const node_opcua_status_code_1 = require("node-opcua-status-code");
const node_opcua_assert_1 = require("node-opcua-assert");
const node_opcua_object_registry_1 = require("node-opcua-object-registry");
const paths = (0, env_paths_1.default)("node-opcua-default");
const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
class OPCUACertificateManager extends node_opcua_pki_1.CertificateManager {
static defaultCertificateSubject = "/O=Sterfive/L=Orleans/C=FR";
static registry = new node_opcua_object_registry_1.ObjectRegistry();
referenceCounter;
automaticallyAcceptUnknownCertificate;
/* */
constructor(options) {
options = options || {};
const location = options.rootFolder || paths.config;
if (!fs_1.default.existsSync(location)) {
try {
fs_1.default.mkdirSync(location, { recursive: true });
}
catch (err) {
errorLog(" cannot create folder ", location, fs_1.default.existsSync(location));
}
}
const _options = {
keySize: options.keySize || 2048,
location
};
super(_options);
this.referenceCounter = 0;
this.automaticallyAcceptUnknownCertificate = !!options.automaticallyAcceptUnknownCertificate;
}
initialize(...args) {
const callback = args[0];
(0, node_opcua_assert_1.assert)(callback && typeof callback === "function");
return super.initialize().then(() => callback()).catch((err) => callback(err));
}
async dispose() {
if (this.referenceCounter === 0) {
await super.dispose();
}
else {
this.referenceCounter--;
}
}
checkCertificate(certificateChain, callback) {
// c8 ignore next
if (!callback || typeof callback !== "function") {
throw new Error("Internal error");
}
this.#checkCertificate(certificateChain)
.then((status) => callback(null, status))
.catch((err) => callback(err));
}
async #checkCertificate(certificateChain) {
const status = await this.verifyCertificate(certificateChain, { acceptCertificateWithValidIssuerChain: true });
const statusCode = node_opcua_status_code_1.StatusCodes[status];
const certificates = (0, web_1.split_der)(certificateChain);
debugLog("checkCertificate => StatusCode = ", statusCode.toString());
if (statusCode.equals(node_opcua_status_code_1.StatusCodes.BadCertificateUntrusted)) {
const topCertificateInChain = certificates[0];
const thumbprint = (0, web_1.makeSHA1Thumbprint)(topCertificateInChain).toString("hex");
if (this.automaticallyAcceptUnknownCertificate) {
debugLog("automaticallyAcceptUnknownCertificate = true");
debugLog("certificate with thumbprint " + thumbprint + " is now trusted");
try {
await this.trustCertificate(topCertificateInChain);
}
catch (err) {
if (err.code === "ENOENT") {
// Another concurrent caller already moved the certificate
// from rejected to trusted — verify it's now trusted.
const trustStatus = await this.getTrustStatus(topCertificateInChain);
if (trustStatus.equals(node_opcua_status_code_1.StatusCodes.Good)) {
debugLog("certificate with thumbprint " + thumbprint + " was already trusted by another caller");
return node_opcua_status_code_1.StatusCodes.Good;
}
}
throw err;
}
return node_opcua_status_code_1.StatusCodes.Good;
}
else {
debugLog("automaticallyAcceptUnknownCertificate = false");
debugLog("certificate with thumbprint " + thumbprint + " is now rejected");
await this.rejectCertificate(topCertificateInChain);
return node_opcua_status_code_1.StatusCodes.BadCertificateUntrusted;
}
}
else if (statusCode.equals(node_opcua_status_code_1.StatusCodes.BadCertificateChainIncomplete)) {
// put all certificates of the chain in the rejected folder
const rejectAll = async (certificates) => {
for (const certificate of certificates) {
await this.rejectCertificate(certificate);
}
};
await rejectAll(certificates);
return statusCode;
}
return statusCode;
}
getTrustStatus(certificate, callback) {
this.isCertificateTrusted(certificate)
.then((trustedStatus) => callback(null, node_opcua_status_code_1.StatusCodes[trustedStatus]))
.catch((err) => callback(err));
}
}
exports.OPCUACertificateManager = OPCUACertificateManager;
// tslint:disable:no-var-requires
// tslint:disable:max-line-length
const thenify_ex_1 = require("thenify-ex");
const opts = { multiArgs: false };
OPCUACertificateManager.prototype.checkCertificate = (0, thenify_ex_1.withCallback)(OPCUACertificateManager.prototype.checkCertificate, opts);
OPCUACertificateManager.prototype.getTrustStatus = (0, thenify_ex_1.withCallback)(OPCUACertificateManager.prototype.getTrustStatus, opts);
OPCUACertificateManager.prototype.initialize = (0, thenify_ex_1.withCallback)(OPCUACertificateManager.prototype.initialize, opts);
function getDefaultCertificateManager(name) {
const config = (0, env_paths_1.default)("node-opcua-default").config;
const pkiFolder = path_1.default.join(config, name);
return new OPCUACertificateManager({
name,
rootFolder: pkiFolder,
automaticallyAcceptUnknownCertificate: true
});
}
//# sourceMappingURL=certificate_manager.js.map