UNPKG

@shockpkg/ria-packager

Version:

Package for creating Adobe AIR packages

220 lines (207 loc) 7.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SecurityTimestamper = void 0; var _nodeForge = require("node-forge"); var _meta = require("../meta.js"); /** * SecurityTimestamper object. */ class SecurityTimestamper { /** * The timestamp server URL. */ /** * The default headers for HTTP requests. */ headers = { // eslint-disable-next-line @typescript-eslint/naming-convention 'User-Agent': `${_meta.NAME}/${_meta.VERSION}` }; /** * A fetch-like interface requiring only a sebset of features. */ fetch = typeof fetch === 'undefined' ? null : fetch; /** * SecurityTimestamper constructor. * * @param url The timestamp server URL. */ constructor(url) { this.url = url; } /** * Timestamp data digested with specified algorithm. * * @param digested The data to timestamp. * @param digest Digest algorithm. * @returns Timestamp data. */ async timestamp(digested, digest) { const encodedRequest = this._encodeRequest(digested, digest); const response = await this._sendRequest(encodedRequest); return this._decodeResponse(response); } /** * Send message request and return response or error on failure. * * @param message Encoded message. * @returns Encoded response. */ async _sendRequest(message) { const { url, headers } = this; const fetch = this._ensureFetch(); const response = await fetch(url, { method: 'POST', headers, body: message }); if (response.status !== 200) { throw new Error(`Status code: ${response.status}: ${url}`); } return new Uint8Array(await response.arrayBuffer()); } /** * Encode request. * * @param digested Digested message. * @param digest Digest algorithm. * @returns Encoded request. */ _encodeRequest(digested, digest) { digest = digest.toLowerCase(); let iod = ''; switch (digest) { case 'sha1': { iod = _nodeForge.pki.oids.sha1; break; } case 'sha256': { iod = _nodeForge.pki.oids.sha256; break; } default: { throw new Error(`Unsupported digest algorithm: ${digest}`); } } const certReq = true; const hashAlgoDef = _nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.SEQUENCE, true, [_nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.OID, false, _nodeForge.asn1.oidToDer(iod).getBytes()), _nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.NULL, false, '')]); const messageImprintDef = _nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.SEQUENCE, true, [hashAlgoDef, _nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.OCTETSTRING, false, // eslint-disable-next-line unicorn/prefer-code-point String.fromCharCode(...digested))]); // Could be set to some bytes. // ie: reqPolicy = 'some bytes'; const reqPolicy = null; const asn1ReqPolicy = reqPolicy ? _nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.OID, false, reqPolicy) : null; // Always null. const nonceDER = null; // This could be a DER encodable, if extensions is set to be? // Just null for now. // const extensions = null; // const asn1Extn = extensions ? extensions : null; const asn1Extn = null; const tsaReqDef = _nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.SEQUENCE, true, [_nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.INTEGER, false, // eslint-disable-next-line unicorn/prefer-code-point String.fromCharCode(1)), messageImprintDef, asn1ReqPolicy, nonceDER, _nodeForge.asn1.create(_nodeForge.asn1.Class.UNIVERSAL, _nodeForge.asn1.Type.BOOLEAN, false, // eslint-disable-next-line unicorn/prefer-code-point String.fromCharCode(certReq ? 0xff : 0)), asn1Extn].filter(Boolean)); return _nodeForge.util.binary.raw.decode(_nodeForge.asn1.toDer(tsaReqDef).bytes()); } /** * Decode response. * * @param response Encoded response. * @returns Decoded response. */ _decodeResponse(response) { const object = _nodeForge.asn1.fromDer(new _nodeForge.util.ByteStringBuffer(response)); const validator = { name: 'root', tagClass: _nodeForge.asn1.Class.UNIVERSAL, type: _nodeForge.asn1.Type.SEQUENCE, constructed: true, value: [{ name: 'root.statusInfo', tagClass: _nodeForge.asn1.Class.UNIVERSAL, type: _nodeForge.asn1.Type.SEQUENCE, constructed: true, value: [{ name: 'root.statusInfo.pkiStatus', tagClass: _nodeForge.asn1.Class.UNIVERSAL, type: _nodeForge.asn1.Type.INTEGER, constructed: false, captureAsn1: 'root.statusInfo.pkiStatus', optional: true }, { name: 'root.statusInfo.pkiFreeText', tagClass: _nodeForge.asn1.Class.UNIVERSAL, type: _nodeForge.asn1.Type.UTF8, constructed: false, captureAsn1: 'root.statusInfo.pkiFreeText', optional: true }, { name: 'root.statusInfo.pkiFailureInfo', tagClass: _nodeForge.asn1.Class.UNIVERSAL, type: _nodeForge.asn1.Type.BITSTRING, constructed: false, captureAsn1: 'root.statusInfo.pkiFailureInfo', optional: true }] }, { name: 'root.tst', tagClass: _nodeForge.asn1.Class.UNIVERSAL, type: _nodeForge.asn1.Type.SEQUENCE, constructed: true, captureAsn1: 'root.tst', optional: true }] }; const capture = {}; const errors = []; const success = _nodeForge.asn1.validate(object, validator, capture, errors); if (!success || errors.length) { const error = errors[0] || 'Unknown error'; throw new Error(`Decode error: ${error}`); } const pkiStatus = capture['root.statusInfo.pkiStatus']; if (!pkiStatus) { throw new Error('Missing PKI status'); } if (pkiStatus.value.length !== 1) { throw new Error(`Unexpected PKI status length: ${pkiStatus.value.length}`); } // eslint-disable-next-line unicorn/prefer-code-point const pkiStatusCode = pkiStatus.value.charCodeAt(0); if (pkiStatusCode !== 0 && pkiStatusCode !== 1) { throw new Error(`Unexpected PKI status code: ${pkiStatusCode}`); } const tst = capture['root.tst']; if (!tst) { throw new Error('Missing PKI TSTInfo'); } return _nodeForge.util.binary.raw.decode(_nodeForge.asn1.toDer(tst).bytes()); } /** * Ensure fetch-like function is set. * * @returns The fetch-like function. */ _ensureFetch() { const { fetch } = this; if (!fetch) { throw new Error('Default fetch not available'); } return fetch; } } exports.SecurityTimestamper = SecurityTimestamper; //# sourceMappingURL=timestamper.js.map