UNPKG

node-opcua-certificate-manager

Version:

pure nodejs OPCUA SDK - module certificate-manager

142 lines 6.83 kB
"use strict"; 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