UNPKG

@penneo/asn1js

Version:

asn1js is a pure JavaScript library implementing this standard. ASN.1 is the basis of all X.509 related data structures and numerous other protocols used on the web

1,400 lines (1,140 loc) 205 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RawData = exports.Repeated = exports.Any = exports.Choice = exports.TIME = exports.Duration = exports.DateTime = exports.TimeOfDay = exports.DATE = exports.GeneralizedTime = exports.UTCTime = exports.CharacterString = exports.GeneralString = exports.VisibleString = exports.GraphicString = exports.IA5String = exports.VideotexString = exports.TeletexString = exports.PrintableString = exports.NumericString = exports.UniversalString = exports.BmpString = exports.Utf8String = exports.ObjectIdentifier = exports.Enumerated = exports.Integer = exports.BitString = exports.OctetString = exports.Null = exports.Set = exports.Sequence = exports.Boolean = exports.EndOfContent = exports.Constructed = exports.Primitive = exports.BaseBlock = undefined; var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /* eslint-disable indent */ /* * Copyright (c) 2016-2018, Peculiar Ventures * All rights reserved. * * Author 2016-2018, Yury Strozhevsky <www.strozhevsky.com>. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * */ //************************************************************************************** exports.fromBER = fromBER; exports.compareSchema = compareSchema; exports.verifySchema = verifySchema; exports.fromJSON = fromJSON; var _pvutils = require("@penneo/pvutils"); function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } //************************************************************************************** //region Declaration of global variables //************************************************************************************** var powers2 = [new Uint8Array([1])]; var digitsString = "0123456789"; //************************************************************************************** //endregion //************************************************************************************** //region Declaration for "LocalBaseBlock" class //************************************************************************************** /** * Class used as a base block for all remaining ASN.1 classes * @typedef LocalBaseBlock * @interface * @property {number} blockLength * @property {string} error * @property {Array.<string>} warnings * @property {ArrayBuffer} valueBeforeDecode */ var LocalBaseBlock = function () { //********************************************************************************** /** * Constructor for "LocalBaseBlock" class * @param {Object} [parameters={}] * @property {ArrayBuffer} [valueBeforeDecode] */ function LocalBaseBlock() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, LocalBaseBlock); /** * @type {number} blockLength */ this.blockLength = (0, _pvutils.getParametersValue)(parameters, "blockLength", 0); /** * @type {string} error */ this.error = (0, _pvutils.getParametersValue)(parameters, "error", ""); /** * @type {Array.<string>} warnings */ this.warnings = (0, _pvutils.getParametersValue)(parameters, "warnings", []); //noinspection JSCheckFunctionSignatures /** * @type {ArrayBuffer} valueBeforeDecode */ if ("valueBeforeDecode" in parameters) this.valueBeforeDecode = parameters.valueBeforeDecode.slice(0);else this.valueBeforeDecode = new ArrayBuffer(0); } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ _createClass(LocalBaseBlock, [{ key: "toJSON", //********************************************************************************** /** * Convertion for the block to JSON object * @returns {{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}} */ value: function toJSON() { return { blockName: this.constructor.blockName(), blockLength: this.blockLength, error: this.error, warnings: this.warnings, valueBeforeDecode: (0, _pvutils.bufferToHexCodes)(this.valueBeforeDecode, 0, this.valueBeforeDecode.byteLength) }; } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "baseBlock"; } }]); return LocalBaseBlock; }(); //************************************************************************************** //endregion //************************************************************************************** //region Description for "LocalHexBlock" class //************************************************************************************** /** * Class used as a base block for all remaining ASN.1 classes * @extends LocalBaseBlock * @typedef LocalHexBlock * @property {number} blockLength * @property {string} error * @property {Array.<string>} warnings * @property {ArrayBuffer} valueBeforeDecode * @property {boolean} isHexOnly * @property {ArrayBuffer} valueHex */ //noinspection JSUnusedLocalSymbols var LocalHexBlock = function LocalHexBlock(BaseClass) { return function (_BaseClass) { _inherits(LocalHexBlockMixin, _BaseClass); //********************************************************************************** //noinspection JSUnusedGlobalSymbols /** * Constructor for "LocalHexBlock" class * @param {Object} [parameters={}] * @property {ArrayBuffer} [valueHex] */ function LocalHexBlockMixin() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, LocalHexBlockMixin); /** * @type {boolean} */ var _this = _possibleConstructorReturn(this, (LocalHexBlockMixin.__proto__ || Object.getPrototypeOf(LocalHexBlockMixin)).call(this, parameters)); _this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", false); /** * @type {ArrayBuffer} */ if ("valueHex" in parameters) _this.valueHex = parameters.valueHex.slice(0);else _this.valueHex = new ArrayBuffer(0); return _this; } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ _createClass(LocalHexBlockMixin, [{ key: "fromBER", //********************************************************************************** /** * Base function for converting block from BER encoded array of bytes * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started * @param {!number} inputLength Maximum length of array of bytes which can be using in this function * @returns {number} Offset after least decoded byte */ value: function fromBER(inputBuffer, inputOffset, inputLength) { //region Basic check for parameters //noinspection JSCheckFunctionSignatures if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion //region Getting Uint8Array from ArrayBuffer var intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion //region Initial checks if (intBuffer.length === 0) { this.warnings.push("Zero buffer length"); return inputOffset; } //endregion //region Copy input buffer to internal buffer this.valueHex = inputBuffer.slice(inputOffset, inputOffset + inputLength); //endregion this.blockLength = inputLength; return inputOffset + inputLength; } //********************************************************************************** /** * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes * @returns {ArrayBuffer} */ }, { key: "toBER", value: function toBER() { var sizeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; if (this.isHexOnly !== true) { this.error = "Flag \"isHexOnly\" is not set, abort"; return new ArrayBuffer(0); } if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength); //noinspection JSCheckFunctionSignatures return this.valueHex.slice(0); } //********************************************************************************** /** * Convertion for the block to JSON object * @returns {Object} */ }, { key: "toJSON", value: function toJSON() { var object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object try { object = _get(LocalHexBlockMixin.prototype.__proto__ || Object.getPrototypeOf(LocalHexBlockMixin.prototype), "toJSON", this).call(this); } catch (ex) {} //endregion object.blockName = this.constructor.blockName(); object.isHexOnly = this.isHexOnly; object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); return object; } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "hexBlock"; } }]); return LocalHexBlockMixin; }(BaseClass); }; //************************************************************************************** //endregion //************************************************************************************** //region Declaration of identification block class //************************************************************************************** var LocalIdentificationBlock = function (_LocalHexBlock) { _inherits(LocalIdentificationBlock, _LocalHexBlock); //********************************************************************************** /** * Constructor for "LocalBaseBlock" class * @param {Object} [parameters={}] * @property {Object} [idBlock] */ function LocalIdentificationBlock() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, LocalIdentificationBlock); var _this2 = _possibleConstructorReturn(this, (LocalIdentificationBlock.__proto__ || Object.getPrototypeOf(LocalIdentificationBlock)).call(this)); if ("idBlock" in parameters) { //region Properties from hexBlock class _this2.isHexOnly = (0, _pvutils.getParametersValue)(parameters.idBlock, "isHexOnly", false); _this2.valueHex = (0, _pvutils.getParametersValue)(parameters.idBlock, "valueHex", new ArrayBuffer(0)); //endregion _this2.tagClass = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagClass", -1); _this2.tagNumber = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagNumber", -1); _this2.isConstructed = (0, _pvutils.getParametersValue)(parameters.idBlock, "isConstructed", false); } else { _this2.tagClass = -1; _this2.tagNumber = -1; _this2.isConstructed = false; } return _this2; } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ _createClass(LocalIdentificationBlock, [{ key: "toBER", //********************************************************************************** /** * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes * @returns {ArrayBuffer} */ value: function toBER() { var sizeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; //region Initial variables var firstOctet = 0; var retBuf = void 0; var retView = void 0; //endregion switch (this.tagClass) { case 1: firstOctet |= 0x00; // UNIVERSAL break; case 2: firstOctet |= 0x40; // APPLICATION break; case 3: firstOctet |= 0x80; // CONTEXT-SPECIFIC break; case 4: firstOctet |= 0xC0; // PRIVATE break; default: this.error = "Unknown tag class"; return new ArrayBuffer(0); } if (this.isConstructed) firstOctet |= 0x20; if (this.tagNumber < 31 && !this.isHexOnly) { retBuf = new ArrayBuffer(1); retView = new Uint8Array(retBuf); if (!sizeOnly) { var number = this.tagNumber; number &= 0x1F; firstOctet |= number; retView[0] = firstOctet; } return retBuf; } if (this.isHexOnly === false) { var encodedBuf = (0, _pvutils.utilToBase)(this.tagNumber, 7); var encodedView = new Uint8Array(encodedBuf); var size = encodedBuf.byteLength; retBuf = new ArrayBuffer(size + 1); retView = new Uint8Array(retBuf); retView[0] = firstOctet | 0x1F; if (!sizeOnly) { for (var i = 0; i < size - 1; i++) { retView[i + 1] = encodedView[i] | 0x80; }retView[size] = encodedView[size - 1]; } return retBuf; } retBuf = new ArrayBuffer(this.valueHex.byteLength + 1); retView = new Uint8Array(retBuf); retView[0] = firstOctet | 0x1F; if (sizeOnly === false) { var curView = new Uint8Array(this.valueHex); for (var _i = 0; _i < curView.length - 1; _i++) { retView[_i + 1] = curView[_i] | 0x80; }retView[this.valueHex.byteLength] = curView[curView.length - 1]; } return retBuf; } //********************************************************************************** /** * Base function for converting block from BER encoded array of bytes * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started * @param {!number} inputLength Maximum length of array of bytes which can be using in this function * @returns {number} */ }, { key: "fromBER", value: function fromBER(inputBuffer, inputOffset, inputLength) { //region Basic check for parameters //noinspection JSCheckFunctionSignatures if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion //region Getting Uint8Array from ArrayBuffer var intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion //region Initial checks if (intBuffer.length === 0) { this.error = "Zero buffer length"; return -1; } //endregion //region Find tag class var tagClassMask = intBuffer[0] & 0xC0; switch (tagClassMask) { case 0x00: this.tagClass = 1; // UNIVERSAL break; case 0x40: this.tagClass = 2; // APPLICATION break; case 0x80: this.tagClass = 3; // CONTEXT-SPECIFIC break; case 0xC0: this.tagClass = 4; // PRIVATE break; default: this.error = "Unknown tag class"; return -1; } //endregion //region Find it's constructed or not this.isConstructed = (intBuffer[0] & 0x20) === 0x20; //endregion //region Find tag number this.isHexOnly = false; var tagNumberMask = intBuffer[0] & 0x1F; //region Simple case (tag number < 31) if (tagNumberMask !== 0x1F) { this.tagNumber = tagNumberMask; this.blockLength = 1; } //endregion //region Tag number bigger or equal to 31 else { var count = 1; this.valueHex = new ArrayBuffer(255); var tagNumberBufferMaxLength = 255; var intTagNumberBuffer = new Uint8Array(this.valueHex); //noinspection JSBitwiseOperatorUsage while (intBuffer[count] & 0x80) { intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; count++; if (count >= intBuffer.length) { this.error = "End of input reached before message was fully decoded"; return -1; } //region In case if tag number length is greater than 255 bytes (rare but possible case) if (count === tagNumberBufferMaxLength) { tagNumberBufferMaxLength += 255; var _tempBuffer = new ArrayBuffer(tagNumberBufferMaxLength); var _tempBufferView = new Uint8Array(_tempBuffer); for (var i = 0; i < intTagNumberBuffer.length; i++) { _tempBufferView[i] = intTagNumberBuffer[i]; }this.valueHex = new ArrayBuffer(tagNumberBufferMaxLength); intTagNumberBuffer = new Uint8Array(this.valueHex); } //endregion } this.blockLength = count + 1; intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer //region Cut buffer var tempBuffer = new ArrayBuffer(count); var tempBufferView = new Uint8Array(tempBuffer); for (var _i2 = 0; _i2 < count; _i2++) { tempBufferView[_i2] = intTagNumberBuffer[_i2]; }this.valueHex = new ArrayBuffer(count); intTagNumberBuffer = new Uint8Array(this.valueHex); intTagNumberBuffer.set(tempBufferView); //endregion //region Try to convert long tag number to short form if (this.blockLength <= 9) this.tagNumber = (0, _pvutils.utilFromBase)(intTagNumberBuffer, 7);else { this.isHexOnly = true; this.warnings.push("Tag too long, represented as hex-coded"); } //endregion } //endregion //endregion //region Check if constructed encoding was using for primitive type if (this.tagClass === 1 && this.isConstructed) { switch (this.tagNumber) { case 1: // Boolean case 2: // REAL case 5: // Null case 6: // OBJECT IDENTIFIER case 9: // REAL case 14: // Time case 23: case 24: case 31: case 32: case 33: case 34: this.error = "Constructed encoding used for primitive type"; return -1; default: } } //endregion return inputOffset + this.blockLength; // Return current offset in input buffer } //********************************************************************************** /** * Convertion for the block to JSON object * @returns {{blockName: string, * tagClass: number, * tagNumber: number, * isConstructed: boolean, * isHexOnly: boolean, * valueHex: ArrayBuffer, * blockLength: number, * error: string, warnings: Array.<string>, * valueBeforeDecode: string}} */ }, { key: "toJSON", value: function toJSON() { var object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object try { object = _get(LocalIdentificationBlock.prototype.__proto__ || Object.getPrototypeOf(LocalIdentificationBlock.prototype), "toJSON", this).call(this); } catch (ex) {} //endregion object.blockName = this.constructor.blockName(); object.tagClass = this.tagClass; object.tagNumber = this.tagNumber; object.isConstructed = this.isConstructed; return object; } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "identificationBlock"; } }]); return LocalIdentificationBlock; }(LocalHexBlock(LocalBaseBlock)); //************************************************************************************** //endregion //************************************************************************************** //region Declaration of length block class //************************************************************************************** var LocalLengthBlock = function (_LocalBaseBlock) { _inherits(LocalLengthBlock, _LocalBaseBlock); //********************************************************************************** /** * Constructor for "LocalLengthBlock" class * @param {Object} [parameters={}] * @property {Object} [lenBlock] */ function LocalLengthBlock() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, LocalLengthBlock); var _this3 = _possibleConstructorReturn(this, (LocalLengthBlock.__proto__ || Object.getPrototypeOf(LocalLengthBlock)).call(this)); if ("lenBlock" in parameters) { _this3.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters.lenBlock, "isIndefiniteForm", false); _this3.longFormUsed = (0, _pvutils.getParametersValue)(parameters.lenBlock, "longFormUsed", false); _this3.length = (0, _pvutils.getParametersValue)(parameters.lenBlock, "length", 0); } else { _this3.isIndefiniteForm = false; _this3.longFormUsed = false; _this3.length = 0; } return _this3; } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ _createClass(LocalLengthBlock, [{ key: "fromBER", //********************************************************************************** /** * Base function for converting block from BER encoded array of bytes * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started * @param {!number} inputLength Maximum length of array of bytes which can be using in this function * @returns {number} */ value: function fromBER(inputBuffer, inputOffset, inputLength) { //region Basic check for parameters //noinspection JSCheckFunctionSignatures if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion //region Getting Uint8Array from ArrayBuffer var intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion //region Initial checks if (intBuffer.length === 0) { this.error = "Zero buffer length"; return -1; } if (intBuffer[0] === 0xFF) { this.error = "Length block 0xFF is reserved by standard"; return -1; } //endregion //region Check for length form type this.isIndefiniteForm = intBuffer[0] === 0x80; //endregion //region Stop working in case of indefinite length form if (this.isIndefiniteForm === true) { this.blockLength = 1; return inputOffset + this.blockLength; } //endregion //region Check is long form of length encoding using this.longFormUsed = !!(intBuffer[0] & 0x80); //endregion //region Stop working in case of short form of length value if (this.longFormUsed === false) { this.length = intBuffer[0]; this.blockLength = 1; return inputOffset + this.blockLength; } //endregion //region Calculate length value in case of long form var count = intBuffer[0] & 0x7F; if (count > 8) // Too big length value { this.error = "Too big integer"; return -1; } if (count + 1 > intBuffer.length) { this.error = "End of input reached before message was fully decoded"; return -1; } var lengthBufferView = new Uint8Array(count); for (var i = 0; i < count; i++) { lengthBufferView[i] = intBuffer[i + 1]; }if (lengthBufferView[count - 1] === 0x00) this.warnings.push("Needlessly long encoded length"); this.length = (0, _pvutils.utilFromBase)(lengthBufferView, 8); if (this.longFormUsed && this.length <= 127) this.warnings.push("Unneccesary usage of long length form"); this.blockLength = count + 1; //endregion return inputOffset + this.blockLength; // Return current offset in input buffer } //********************************************************************************** /** * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes * @returns {ArrayBuffer} */ }, { key: "toBER", value: function toBER() { var sizeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; //region Initial variables var retBuf = void 0; var retView = void 0; //endregion if (this.length > 127) this.longFormUsed = true; if (this.isIndefiniteForm) { retBuf = new ArrayBuffer(1); if (sizeOnly === false) { retView = new Uint8Array(retBuf); retView[0] = 0x80; } return retBuf; } if (this.longFormUsed === true) { var encodedBuf = (0, _pvutils.utilToBase)(this.length, 8); if (encodedBuf.byteLength > 127) { this.error = "Too big length"; return new ArrayBuffer(0); } retBuf = new ArrayBuffer(encodedBuf.byteLength + 1); if (sizeOnly === true) return retBuf; var encodedView = new Uint8Array(encodedBuf); retView = new Uint8Array(retBuf); retView[0] = encodedBuf.byteLength | 0x80; for (var i = 0; i < encodedBuf.byteLength; i++) { retView[i + 1] = encodedView[i]; }return retBuf; } retBuf = new ArrayBuffer(1); if (sizeOnly === false) { retView = new Uint8Array(retBuf); retView[0] = this.length; } return retBuf; } //********************************************************************************** /** * Convertion for the block to JSON object * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}} */ }, { key: "toJSON", value: function toJSON() { var object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object try { object = _get(LocalLengthBlock.prototype.__proto__ || Object.getPrototypeOf(LocalLengthBlock.prototype), "toJSON", this).call(this); } catch (ex) {} //endregion object.blockName = this.constructor.blockName(); object.isIndefiniteForm = this.isIndefiniteForm; object.longFormUsed = this.longFormUsed; object.length = this.length; return object; } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "lengthBlock"; } }]); return LocalLengthBlock; }(LocalBaseBlock); //************************************************************************************** //endregion //************************************************************************************** //region Declaration of value block class //************************************************************************************** var LocalValueBlock = function (_LocalBaseBlock2) { _inherits(LocalValueBlock, _LocalBaseBlock2); //********************************************************************************** /** * Constructor for "LocalValueBlock" class * @param {Object} [parameters={}] */ function LocalValueBlock() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, LocalValueBlock); return _possibleConstructorReturn(this, (LocalValueBlock.__proto__ || Object.getPrototypeOf(LocalValueBlock)).call(this, parameters)); } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ _createClass(LocalValueBlock, [{ key: "fromBER", //********************************************************************************** //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols,JSUnusedLocalSymbols /** * Base function for converting block from BER encoded array of bytes * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started * @param {!number} inputLength Maximum length of array of bytes which can be using in this function * @returns {number} */ value: function fromBER(inputBuffer, inputOffset, inputLength) { //region Throw an exception for a function which needs to be specified in extended classes throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); //endregion } //********************************************************************************** //noinspection JSUnusedLocalSymbols /** * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes * @returns {ArrayBuffer} */ }, { key: "toBER", value: function toBER() { var sizeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; //region Throw an exception for a function which needs to be specified in extended classes throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); //endregion } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "valueBlock"; } }]); return LocalValueBlock; }(LocalBaseBlock); //************************************************************************************** //endregion //************************************************************************************** //region Declaration of basic ASN.1 block class //************************************************************************************** var BaseBlock = exports.BaseBlock = function (_LocalBaseBlock3) { _inherits(BaseBlock, _LocalBaseBlock3); //********************************************************************************** /** * Constructor for "BaseBlock" class * @param {Object} [parameters={}] * @property {Object} [primitiveSchema] * @property {string} [name] * @property {boolean} [optional] * @param valueBlockType Type of value block */ function BaseBlock() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var valueBlockType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : LocalValueBlock; _classCallCheck(this, BaseBlock); var _this5 = _possibleConstructorReturn(this, (BaseBlock.__proto__ || Object.getPrototypeOf(BaseBlock)).call(this, parameters)); if ("name" in parameters) _this5.name = parameters.name; if ("optional" in parameters) _this5.optional = parameters.optional; if ("primitiveSchema" in parameters) _this5.primitiveSchema = parameters.primitiveSchema; _this5.idBlock = new LocalIdentificationBlock(parameters); _this5.lenBlock = new LocalLengthBlock(parameters); _this5.valueBlock = new valueBlockType(parameters); return _this5; } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ _createClass(BaseBlock, [{ key: "fromBER", //********************************************************************************** /** * Base function for converting block from BER encoded array of bytes * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started * @param {!number} inputLength Maximum length of array of bytes which can be using in this function * @returns {number} */ value: function fromBER(inputBuffer, inputOffset, inputLength) { var resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); if (resultOffset === -1) { this.error = this.valueBlock.error; return resultOffset; } if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; return resultOffset; } //********************************************************************************** /** * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes * @returns {ArrayBuffer} */ }, { key: "toBER", value: function toBER() { var sizeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var retBuf = void 0; var idBlockBuf = this.idBlock.toBER(sizeOnly); var valueBlockSizeBuf = this.valueBlock.toBER(true); this.lenBlock.length = valueBlockSizeBuf.byteLength; var lenBlockBuf = this.lenBlock.toBER(sizeOnly); retBuf = (0, _pvutils.utilConcatBuf)(idBlockBuf, lenBlockBuf); var valueBlockBuf = void 0; if (sizeOnly === false) valueBlockBuf = this.valueBlock.toBER(sizeOnly);else valueBlockBuf = new ArrayBuffer(this.lenBlock.length); retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBlockBuf); if (this.lenBlock.isIndefiniteForm === true) { var indefBuf = new ArrayBuffer(2); if (sizeOnly === false) { var indefView = new Uint8Array(indefBuf); indefView[0] = 0x00; indefView[1] = 0x00; } retBuf = (0, _pvutils.utilConcatBuf)(retBuf, indefBuf); } return retBuf; } //********************************************************************************** /** * Convertion for the block to JSON object * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}} */ }, { key: "toJSON", value: function toJSON() { var object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object try { object = _get(BaseBlock.prototype.__proto__ || Object.getPrototypeOf(BaseBlock.prototype), "toJSON", this).call(this); } catch (ex) {} //endregion object.idBlock = this.idBlock.toJSON(); object.lenBlock = this.lenBlock.toJSON(); object.valueBlock = this.valueBlock.toJSON(); if ("name" in this) object.name = this.name; if ("optional" in this) object.optional = this.optional; if ("primitiveSchema" in this) object.primitiveSchema = this.primitiveSchema.toJSON(); return object; } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "BaseBlock"; } }]); return BaseBlock; }(LocalBaseBlock); //************************************************************************************** //endregion //************************************************************************************** //region Declaration of basic block for all PRIMITIVE types //************************************************************************************** var LocalPrimitiveValueBlock = function (_LocalValueBlock) { _inherits(LocalPrimitiveValueBlock, _LocalValueBlock); //********************************************************************************** /** * Constructor for "LocalPrimitiveValueBlock" class * @param {Object} [parameters={}] * @property {ArrayBuffer} [valueBeforeDecode] */ function LocalPrimitiveValueBlock() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, LocalPrimitiveValueBlock); //region Variables from "hexBlock" class var _this6 = _possibleConstructorReturn(this, (LocalPrimitiveValueBlock.__proto__ || Object.getPrototypeOf(LocalPrimitiveValueBlock)).call(this, parameters)); if ("valueHex" in parameters) _this6.valueHex = parameters.valueHex.slice(0);else _this6.valueHex = new ArrayBuffer(0); _this6.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", true); //endregion return _this6; } //********************************************************************************** /** * Base function for converting block from BER encoded array of bytes * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started * @param {!number} inputLength Maximum length of array of bytes which can be using in this function * @returns {number} */ _createClass(LocalPrimitiveValueBlock, [{ key: "fromBER", value: function fromBER(inputBuffer, inputOffset, inputLength) { //region Basic check for parameters //noinspection JSCheckFunctionSignatures if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion //region Getting Uint8Array from ArrayBuffer var intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion //region Initial checks if (intBuffer.length === 0) { this.warnings.push("Zero buffer length"); return inputOffset; } //endregion //region Copy input buffer into internal buffer this.valueHex = new ArrayBuffer(intBuffer.length); var valueHexView = new Uint8Array(this.valueHex); for (var i = 0; i < intBuffer.length; i++) { valueHexView[i] = intBuffer[i]; } //endregion this.blockLength = inputLength; return inputOffset + inputLength; } //********************************************************************************** //noinspection JSUnusedLocalSymbols /** * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes * @returns {ArrayBuffer} */ }, { key: "toBER", value: function toBER() { var sizeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; return this.valueHex.slice(0); } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ }, { key: "toJSON", //********************************************************************************** /** * Convertion for the block to JSON object * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}} */ value: function toJSON() { var object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object try { object = _get(LocalPrimitiveValueBlock.prototype.__proto__ || Object.getPrototypeOf(LocalPrimitiveValueBlock.prototype), "toJSON", this).call(this); } catch (ex) {} //endregion object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); object.isHexOnly = this.isHexOnly; return object; } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "PrimitiveValueBlock"; } }]); return LocalPrimitiveValueBlock; }(LocalValueBlock); //************************************************************************************** var Primitive = exports.Primitive = function (_BaseBlock) { _inherits(Primitive, _BaseBlock); //********************************************************************************** /** * Constructor for "Primitive" class * @param {Object} [parameters={}] * @property {ArrayBuffer} [valueHex] */ function Primitive() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, Primitive); var _this7 = _possibleConstructorReturn(this, (Primitive.__proto__ || Object.getPrototypeOf(Primitive)).call(this, parameters, LocalPrimitiveValueBlock)); _this7.idBlock.isConstructed = false; return _this7; } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ _createClass(Primitive, null, [{ key: "blockName", value: function blockName() { return "PRIMITIVE"; } //********************************************************************************** }]); return Primitive; }(BaseBlock); //************************************************************************************** //endregion //************************************************************************************** //region Declaration of basic block for all CONSTRUCTED types //************************************************************************************** var LocalConstructedValueBlock = function (_LocalValueBlock2) { _inherits(LocalConstructedValueBlock, _LocalValueBlock2); //********************************************************************************** /** * Constructor for "LocalConstructedValueBlock" class * @param {Object} [parameters={}] */ function LocalConstructedValueBlock() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, LocalConstructedValueBlock); var _this8 = _possibleConstructorReturn(this, (LocalConstructedValueBlock.__proto__ || Object.getPrototypeOf(LocalConstructedValueBlock)).call(this, parameters)); _this8.value = (0, _pvutils.getParametersValue)(parameters, "value", []); _this8.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters, "isIndefiniteForm", false); return _this8; } //********************************************************************************** /** * Base function for converting block from BER encoded array of bytes * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started * @param {!number} inputLength Maximum length of array of bytes which can be using in this function * @returns {number} */ _createClass(LocalConstructedValueBlock, [{ key: "fromBER", value: function fromBER(inputBuffer, inputOffset, inputLength) { //region Store initial offset and length var initialOffset = inputOffset; var initialLength = inputLength; //endregion //region Basic check for parameters //noinspection JSCheckFunctionSignatures if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion //region Getting Uint8Array from ArrayBuffer var intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion //region Initial checks if (intBuffer.length === 0) { this.warnings.push("Zero buffer length"); return inputOffset; } //endregion //region Aux function function checkLen(indefiniteLength, length) { if (indefiniteLength === true) return 1; return length; } //endregion var currentOffset = inputOffset; while (checkLen(this.isIndefiniteForm, inputLength) > 0) { var returnObject = LocalFromBER(inputBuffer, currentOffset, inputLength); if (returnObject.offset === -1) { this.error = returnObject.result.error; this.warnings.concat(returnObject.result.warnings); return -1; } currentOffset = returnObject.offset; this.blockLength += returnObject.result.blockLength; inputLength -= returnObject.result.blockLength; this.value.push(returnObject.result); if (this.isIndefiniteForm === true && returnObject.result.constructor.blockName() === EndOfContent.blockName()) break; } if (this.isIndefiniteForm === true) { if (this.value[this.value.length - 1].constructor.blockName() === EndOfContent.blockName()) this.value.pop();else this.warnings.push("No EndOfContent block encoded"); } //region Copy "inputBuffer" to "valueBeforeDecode" this.valueBeforeDecode = inputBuffer.slice(initialOffset, initialOffset + initialLength); //endregion return currentOffset; } //********************************************************************************** /** * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes * @returns {ArrayBuffer} */ }, { key: "toBER", value: function toBER() { var sizeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var retBuf = new ArrayBuffer(0); for (var i = 0; i < this.value.length; i++) { var valueBuf = this.value[i].toBER(sizeOnly); retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBuf); } return retBuf; } //********************************************************************************** /** * Aux function, need to get a block name. Need to have it here for inhiritence * @returns {string} */ }, { key: "toJSON", //********************************************************************************** /** * Convertion for the block to JSON object * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}} */ value: function toJSON() { var object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object try { object = _get(LocalConstructedValueBlock.prototype.__proto__ || Object.getPrototypeOf(LocalConstructedValueBlock.prototype), "toJSON", this).call(this); } catch (ex) {} //endregion object.isIndefiniteForm = this.isIndefiniteForm; object.value = []; for (var i = 0; i < this.value.length; i++) { object.value.push(this.value[i].toJSON()); }return object; } //********************************************************************************** }], [{ key: "blockName", value: function blockName() { return "ConstructedValueBlock"; } }]); return LocalConstructedValueBlock; }(LocalValueBlock); //************************************************************************************** var Constructed = exports.Constructed = function (_BaseBlock2) { _inherits(Constructed, _BaseBlock2); //********************************************************************************** /** * Constructor for "Constructed" class * @param {Object} [parameters={}] */ function Constructed() { var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, Constructed); var _this9 = _possibleConstructorReturn(this, (Constructed.__proto__ || Object.getPrototypeOf(Constructed)).call(this, parameters, LocalConstructedValueBlock)); _this9.i