@estos/asn1ts
Version:
ASN1.ts is a cross platform ASN1 library written in typescript. It supports encoding and (schema supported) decoding of ber encoded asn1 structures.
1,330 lines (1,308 loc) • 147 kB
JavaScript
/*!
* Copyright (c) 2014, GMO GlobalSign
* Copyright (c) 2015-2022, Peculiar Ventures
* Copyright (c) 2022, estos GmbH (extensions missing features see README.md - What has been added by estos)
* All rights reserved.
*
* Author 2014-2019, Yury Strozhevsky
* Author 2019-2022, Peculiar Ventures
* Author from 2022, estos GmbH
*
* estos created a fork of the library, mainly written by Yury Strozhevsky and
* Peculiar Ventures, in 2022 to add extensions, missing features. Details about those in the README.md
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * 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.
*
* * 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.
*
*/
import * as pvtsutils from 'pvtsutils';
import * as pvutils from 'pvutils';
function assertBigInt() {
if (typeof BigInt === "undefined") {
throw new Error("BigInt is not defined. Your environment doesn't implement BigInt.");
}
}
function concat(buffers) {
let outputLength = 0;
let prevLength = 0;
for (let i = 0; i < buffers.length; i++) {
const buffer = buffers[i];
outputLength += buffer.byteLength;
}
const retView = new Uint8Array(outputLength);
for (let i = 0; i < buffers.length; i++) {
const buffer = buffers[i];
retView.set(new Uint8Array(buffer), prevLength);
prevLength += buffer.byteLength;
}
return retView.buffer;
}
function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) {
if (!(inputBuffer instanceof Uint8Array)) {
baseBlock.error = "Wrong parameter: inputBuffer must be 'Uint8Array'";
return false;
}
if (!inputBuffer.byteLength) {
baseBlock.error = "Wrong parameter: inputBuffer has zero length";
return false;
}
if (inputOffset < 0) {
baseBlock.error = "Wrong parameter: inputOffset less than zero";
return false;
}
if (inputLength < 0) {
baseBlock.error = "Wrong parameter: inputLength less than zero";
return false;
}
if ((inputBuffer.byteLength - inputOffset - inputLength) < 0) {
baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
return false;
}
return true;
}
var ESpecialNumber;
(function (ESpecialNumber) {
ESpecialNumber[ESpecialNumber["nan"] = 1] = "nan";
ESpecialNumber[ESpecialNumber["infinite"] = 2] = "infinite";
})(ESpecialNumber || (ESpecialNumber = {}));
function getNumberParts(x) {
if (isNaN(x)) {
return {
mantissa: -6755399441055744,
exponent: 972,
sign: 1,
special: ESpecialNumber.nan
};
}
const float = new Float64Array(1);
const bytes = new Uint8Array(float.buffer);
float[0] = x;
const msb = bytes[7] >> 7;
const sign = msb ? -1 : 1;
if (!isFinite(x)) {
return {
mantissa: 4503599627370496,
exponent: 972,
sign,
special: ESpecialNumber.infinite
};
}
let exponent = ((bytes[7] & 0x7f) << 4 | bytes[6] >> 4) - 0x3ff;
bytes[7] = 0x3f;
bytes[6] |= 0xf0;
let mantissa = float[0];
while (mantissa >= 1) {
mantissa /= 2;
exponent++;
}
return {
sign,
exponent,
mantissa,
};
}
function getSignedFromUnsigned(x) {
return x << 24 >> 24;
}
class ViewWriter {
constructor() {
this.items = [];
}
write(buf) {
this.items.push(buf);
}
final() {
return concat(this.items);
}
}
const powers2 = [new Uint8Array([1])];
const digitsString = "0123456789";
const VALUE_HEX_VIEW = "valueHexView";
const IS_HEX_ONLY = "isHexOnly";
const ID_BLOCK = "idBlock";
const TAG_CLASS = "tagClass";
const TAG_NUMBER = "tagNumber";
const IS_CONSTRUCTED = "isConstructed";
const FROM_BER = "fromBER";
const TO_BER = "toBER";
const EMPTY_STRING = "";
const EMPTY_BUFFER = new ArrayBuffer(0);
const EMPTY_VIEW = new Uint8Array(0);
const END_OF_CONTENT_NAME = "EndOfContent";
const OCTET_STRING_NAME = "OCTET STRING";
const BIT_STRING_NAME = "BIT STRING";
function HexBlock(BaseClass) {
var _a;
return _a = class Some extends BaseClass {
get valueHex() {
return this.valueHexView.slice().buffer;
}
set valueHex(value) {
this.valueHexView = new Uint8Array(value);
}
constructor(...args) {
var _b;
super(...args);
const params = args[0] || {};
this.isHexOnly = (_b = params.isHexOnly) !== null && _b !== void 0 ? _b : false;
this.valueHexView = params.valueHex ? pvtsutils.BufferSourceConverter.toUint8Array(params.valueHex) : EMPTY_VIEW;
}
fromBER(inputBuffer, inputOffset, inputLength) {
const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer;
if (!checkBufferParams(this, view, inputOffset, inputLength)) {
return -1;
}
const endLength = inputOffset + inputLength;
this.valueHexView = view.subarray(inputOffset, endLength);
if (!this.valueHexView.length) {
this.warnings.push("Zero buffer length");
return inputOffset;
}
this.blockLength = inputLength;
return endLength;
}
toBER(sizeOnly = false) {
if (!this.isHexOnly) {
this.error = "Flag 'isHexOnly' is not set, abort";
return EMPTY_BUFFER;
}
if (sizeOnly) {
return new ArrayBuffer(this.valueHexView.byteLength);
}
return (this.valueHexView.byteLength === this.valueHexView.buffer.byteLength)
? this.valueHexView.buffer
: this.valueHexView.slice().buffer;
}
toJSON() {
return {
...super.toJSON(),
isHexOnly: this.isHexOnly,
valueHex: pvtsutils.Convert.ToHex(this.valueHexView),
};
}
},
_a.NAME = "hexBlock",
_a;
}
class LocalBaseBlock {
static blockName() {
return this.NAME;
}
get valueBeforeDecode() {
return this.valueBeforeDecodeView.slice().buffer;
}
set valueBeforeDecode(value) {
this.valueBeforeDecodeView = new Uint8Array(value);
}
constructor({ blockLength = 0, error = EMPTY_STRING, warnings = [], valueBeforeDecode = EMPTY_VIEW, } = {}) {
this.blockLength = blockLength;
this.error = error;
this.warnings = warnings;
this.valueBeforeDecodeView = pvtsutils.BufferSourceConverter.toUint8Array(valueBeforeDecode);
}
toJSON() {
return {
blockName: this.constructor.NAME,
blockLength: this.blockLength,
error: this.error,
warnings: this.warnings,
valueBeforeDecode: pvtsutils.Convert.ToHex(this.valueBeforeDecodeView),
};
}
}
LocalBaseBlock.NAME = "LocalBaseBlock";
LocalBaseBlock.defaultIDs = { tagClass: -1, tagNumber: -1 };
class ValueBlock extends LocalBaseBlock {
fromBER(inputBuffer, inputOffset, inputLength) {
throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'");
}
toBER(sizeOnly, writer) {
throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'");
}
}
ValueBlock.NAME = "valueBlock";
var ETagClass;
(function (ETagClass) {
ETagClass[ETagClass["UNKNOWN"] = -1] = "UNKNOWN";
ETagClass[ETagClass["UNIVERSAL"] = 1] = "UNIVERSAL";
ETagClass[ETagClass["APPLICATION"] = 2] = "APPLICATION";
ETagClass[ETagClass["CONTEXT_SPECIFIC"] = 3] = "CONTEXT_SPECIFIC";
ETagClass[ETagClass["PRIVATE"] = 4] = "PRIVATE";
})(ETagClass || (ETagClass = {}));
var EUniversalTagNumber;
(function (EUniversalTagNumber) {
EUniversalTagNumber[EUniversalTagNumber["unknown"] = -1] = "unknown";
EUniversalTagNumber[EUniversalTagNumber["EndOfContent"] = 0] = "EndOfContent";
EUniversalTagNumber[EUniversalTagNumber["Boolean"] = 1] = "Boolean";
EUniversalTagNumber[EUniversalTagNumber["Integer"] = 2] = "Integer";
EUniversalTagNumber[EUniversalTagNumber["BitString"] = 3] = "BitString";
EUniversalTagNumber[EUniversalTagNumber["OctetString"] = 4] = "OctetString";
EUniversalTagNumber[EUniversalTagNumber["Null"] = 5] = "Null";
EUniversalTagNumber[EUniversalTagNumber["ObjectIdentifier"] = 6] = "ObjectIdentifier";
EUniversalTagNumber[EUniversalTagNumber["Real"] = 9] = "Real";
EUniversalTagNumber[EUniversalTagNumber["Enumerated"] = 10] = "Enumerated";
EUniversalTagNumber[EUniversalTagNumber["Utf8String"] = 12] = "Utf8String";
EUniversalTagNumber[EUniversalTagNumber["RelativeObjectIdentifier"] = 13] = "RelativeObjectIdentifier";
EUniversalTagNumber[EUniversalTagNumber["TIME"] = 14] = "TIME";
EUniversalTagNumber[EUniversalTagNumber["Sequence"] = 16] = "Sequence";
EUniversalTagNumber[EUniversalTagNumber["Set"] = 17] = "Set";
EUniversalTagNumber[EUniversalTagNumber["NumericString"] = 18] = "NumericString";
EUniversalTagNumber[EUniversalTagNumber["PrintableString"] = 19] = "PrintableString";
EUniversalTagNumber[EUniversalTagNumber["TeletexString"] = 20] = "TeletexString";
EUniversalTagNumber[EUniversalTagNumber["VideotexString"] = 21] = "VideotexString";
EUniversalTagNumber[EUniversalTagNumber["IA5String"] = 22] = "IA5String";
EUniversalTagNumber[EUniversalTagNumber["UTCTime"] = 23] = "UTCTime";
EUniversalTagNumber[EUniversalTagNumber["GeneralizedTime"] = 24] = "GeneralizedTime";
EUniversalTagNumber[EUniversalTagNumber["GraphicString"] = 25] = "GraphicString";
EUniversalTagNumber[EUniversalTagNumber["VisibleString"] = 26] = "VisibleString";
EUniversalTagNumber[EUniversalTagNumber["GeneralString"] = 27] = "GeneralString";
EUniversalTagNumber[EUniversalTagNumber["UniversalString"] = 28] = "UniversalString";
EUniversalTagNumber[EUniversalTagNumber["CharacterString"] = 29] = "CharacterString";
EUniversalTagNumber[EUniversalTagNumber["BmpString"] = 30] = "BmpString";
EUniversalTagNumber[EUniversalTagNumber["DATE"] = 31] = "DATE";
EUniversalTagNumber[EUniversalTagNumber["TimeOfDay"] = 32] = "TimeOfDay";
EUniversalTagNumber[EUniversalTagNumber["DateTime"] = 33] = "DateTime";
EUniversalTagNumber[EUniversalTagNumber["Duration"] = 34] = "Duration";
EUniversalTagNumber[EUniversalTagNumber["Extension"] = 35] = "Extension";
})(EUniversalTagNumber || (EUniversalTagNumber = {}));
function getTagClassAsText(tagClass) {
switch (tagClass) {
case ETagClass.UNIVERSAL:
return "UNIVERSAL";
case ETagClass.APPLICATION:
return "APPLICATION";
case ETagClass.CONTEXT_SPECIFIC:
return "CONTEXT_SPECIFIC";
case ETagClass.PRIVATE:
return "PRIVATE";
default:
return `TAGCLASS(${tagClass})`;
}
}
function getTagNumberAsText(tagNumber) {
switch (tagNumber) {
case EUniversalTagNumber.EndOfContent:
return "EndOfContent";
case EUniversalTagNumber.Boolean:
return "Boolean";
case EUniversalTagNumber.Integer:
return "Integer";
case EUniversalTagNumber.BitString:
return "BitString";
case EUniversalTagNumber.OctetString:
return "OctetString";
case EUniversalTagNumber.Null:
return "Null";
case EUniversalTagNumber.ObjectIdentifier:
return "ObjectIdentifier";
case EUniversalTagNumber.Real:
return "Real";
case EUniversalTagNumber.Enumerated:
return "Enumerated";
case EUniversalTagNumber.Utf8String:
return "Utf8String";
case EUniversalTagNumber.RelativeObjectIdentifier:
return "RelativeObjectIdentifier";
case EUniversalTagNumber.TIME:
return "TIME";
case EUniversalTagNumber.Sequence:
return "Sequence";
case EUniversalTagNumber.Set:
return "Set";
case EUniversalTagNumber.NumericString:
return "NumericString";
case EUniversalTagNumber.PrintableString:
return "PrintableString";
case EUniversalTagNumber.TeletexString:
return "TeletexString";
case EUniversalTagNumber.VideotexString:
return "VideotexString";
case EUniversalTagNumber.IA5String:
return "IA5String";
case EUniversalTagNumber.UTCTime:
return "UTCTime";
case EUniversalTagNumber.GeneralizedTime:
return "GeneralizedTime";
case EUniversalTagNumber.GraphicString:
return "GraphicString";
case EUniversalTagNumber.VisibleString:
return "VisibleString";
case EUniversalTagNumber.GeneralString:
return "GeneralString";
case EUniversalTagNumber.UniversalString:
return "UniversalString";
case EUniversalTagNumber.CharacterString:
return "CharacterString";
case EUniversalTagNumber.BmpString:
return "BmpString";
case EUniversalTagNumber.DATE:
return "DATE";
case EUniversalTagNumber.TimeOfDay:
return "TimeOfDay";
case EUniversalTagNumber.DateTime:
return "DateTime";
case EUniversalTagNumber.Duration:
return "Duration";
case EUniversalTagNumber.Extension:
return "Extension";
default:
return `TAGNUMBER(${tagNumber})`;
}
}
const typeStore = {};
class LocalIdentificationBlock extends HexBlock(LocalBaseBlock) {
constructor({ idBlock = {}, } = {}) {
var _a, _b, _c, _d, _e;
super();
if (idBlock) {
this.isHexOnly = (_a = idBlock.isHexOnly) !== null && _a !== void 0 ? _a : false;
this.valueHexView = idBlock.valueHex ? pvtsutils.BufferSourceConverter.toUint8Array(idBlock.valueHex) : EMPTY_VIEW;
this.tagClass = (_b = idBlock.tagClass) !== null && _b !== void 0 ? _b : ETagClass.UNKNOWN;
this.tagNumber = (_c = idBlock.tagNumber) !== null && _c !== void 0 ? _c : EUniversalTagNumber.unknown;
this.isConstructed = (_d = idBlock.isConstructed) !== null && _d !== void 0 ? _d : false;
this.optionalID = (_e = idBlock.optionalID) !== null && _e !== void 0 ? _e : -1;
}
else {
this.tagClass = ETagClass.UNKNOWN;
this.tagNumber = EUniversalTagNumber.unknown;
this.isConstructed = false;
this.optionalID = -1;
}
}
getDebug(delimiter = "") {
let result = "";
result += getTagClassAsText(this.tagClass);
result += delimiter;
if (this.tagClass === ETagClass.UNIVERSAL)
result += getTagNumberAsText(this.tagNumber);
else
result += this.tagNumber;
return result;
}
toBER(sizeOnly = false, ignoreOptionalID = false) {
let firstOctet = 0;
let tagClass = this.tagClass;
let tagNumber = this.tagNumber;
if (this.optionalID >= 0 && !ignoreOptionalID) {
tagClass = ETagClass.CONTEXT_SPECIFIC;
tagNumber = this.optionalID;
}
switch (tagClass) {
case ETagClass.UNIVERSAL:
firstOctet |= 0x00;
break;
case ETagClass.APPLICATION:
firstOctet |= 0x40;
break;
case ETagClass.CONTEXT_SPECIFIC:
firstOctet |= 0x80;
break;
case ETagClass.PRIVATE:
firstOctet |= 0xC0;
break;
default:
this.error = "Unknown tag class";
return EMPTY_BUFFER;
}
if (this.isConstructed)
firstOctet |= 0x20;
if (tagNumber < 31 && !this.isHexOnly) {
const retView = new Uint8Array(1);
if (!sizeOnly) {
let number = tagNumber;
number &= 0x1F;
firstOctet |= number;
retView[0] = firstOctet;
}
return retView.buffer;
}
if (!this.isHexOnly) {
const encodedBuf = pvutils.utilToBase(tagNumber, 7);
const encodedView = new Uint8Array(encodedBuf);
const size = encodedBuf.byteLength;
const retView = new Uint8Array(size + 1);
retView[0] = (firstOctet | 0x1F);
if (!sizeOnly) {
for (let i = 0; i < (size - 1); i++)
retView[i + 1] = encodedView[i] | 0x80;
retView[size] = encodedView[size - 1];
}
return retView.buffer;
}
const retView = new Uint8Array(this.valueHexView.byteLength + 1);
retView[0] = (firstOctet | 0x1F);
if (!sizeOnly) {
const curView = this.valueHexView;
for (let i = 0; i < (curView.length - 1); i++)
retView[i + 1] = curView[i] | 0x80;
retView[this.valueHexView.byteLength] = curView[curView.length - 1];
}
return retView.buffer;
}
fromBER(inputBuffer, inputOffset, inputLength) {
const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
return -1;
}
const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
if (intBuffer.length === 0) {
this.error = "Zero buffer length";
return -1;
}
const tagClassMask = intBuffer[0] & 0xC0;
switch (tagClassMask) {
case 0x00:
this.tagClass = ETagClass.UNIVERSAL;
break;
case 0x40:
this.tagClass = ETagClass.APPLICATION;
break;
case 0x80:
this.tagClass = ETagClass.CONTEXT_SPECIFIC;
break;
case 0xC0:
this.tagClass = ETagClass.PRIVATE;
break;
default:
this.error = "Unknown tag class";
return -1;
}
this.isConstructed = (intBuffer[0] & 0x20) === 0x20;
this.isHexOnly = false;
const tagNumberMask = intBuffer[0] & 0x1F;
if (tagNumberMask !== 0x1F) {
this.tagNumber = (tagNumberMask);
this.blockLength = 1;
}
else {
let count = 1;
let intTagNumberBuffer = this.valueHexView = new Uint8Array(255);
let tagNumberBufferMaxLength = 255;
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;
}
if (count === tagNumberBufferMaxLength) {
tagNumberBufferMaxLength += 255;
const tempBufferView = new Uint8Array(tagNumberBufferMaxLength);
for (let i = 0; i < intTagNumberBuffer.length; i++)
tempBufferView[i] = intTagNumberBuffer[i];
intTagNumberBuffer = this.valueHexView = new Uint8Array(tagNumberBufferMaxLength);
}
}
this.blockLength = (count + 1);
intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F;
const tempBufferView = new Uint8Array(count);
for (let i = 0; i < count; i++)
tempBufferView[i] = intTagNumberBuffer[i];
intTagNumberBuffer = this.valueHexView = new Uint8Array(count);
intTagNumberBuffer.set(tempBufferView);
if (this.blockLength <= 9)
this.tagNumber = pvutils.utilFromBase(intTagNumberBuffer, 7);
else {
this.isHexOnly = true;
this.warnings.push("Tag too long, represented as hex-coded");
}
}
if (((this.tagClass === 1)) &&
(this.isConstructed)) {
switch (this.tagNumber) {
case 1:
case 2:
case 5:
case 6:
case 9:
case 13:
case 14:
case 23:
case 24:
case 31:
case 32:
case 33:
case 34:
this.error = "Constructed encoding used for primitive type";
return -1;
}
}
return (inputOffset + this.blockLength);
}
toJSON() {
return {
...super.toJSON(),
tagClass: this.tagClass,
tagNumber: this.tagNumber,
isConstructed: this.isConstructed,
optionalID: this.optionalID
};
}
isIdenticalType(other) {
return this.tagClass === other.tagClass && this.tagNumber === other.tagNumber;
}
}
LocalIdentificationBlock.NAME = "identificationBlock";
class LocalLengthBlock extends LocalBaseBlock {
constructor({ lenBlock = {}, } = {}) {
var _a, _b, _c;
super();
this.isIndefiniteForm = (_a = lenBlock.isIndefiniteForm) !== null && _a !== void 0 ? _a : false;
this.longFormUsed = (_b = lenBlock.longFormUsed) !== null && _b !== void 0 ? _b : false;
this.length = (_c = lenBlock.length) !== null && _c !== void 0 ? _c : 0;
}
fromBER(inputBuffer, inputOffset, inputLength) {
const view = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
if (!checkBufferParams(this, view, inputOffset, inputLength)) {
return -1;
}
const intBuffer = view.subarray(inputOffset, inputOffset + inputLength);
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;
}
this.isIndefiniteForm = intBuffer[0] === 0x80;
if (this.isIndefiniteForm) {
this.blockLength = 1;
return (inputOffset + this.blockLength);
}
this.longFormUsed = !!(intBuffer[0] & 0x80);
if (this.longFormUsed === false) {
this.length = (intBuffer[0]);
this.blockLength = 1;
return (inputOffset + this.blockLength);
}
const count = intBuffer[0] & 0x7F;
if (count > 8) {
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;
}
const lenOffset = inputOffset + 1;
const lengthBufferView = view.subarray(lenOffset, lenOffset + count);
if (lengthBufferView[count - 1] === 0x00)
this.warnings.push("Needlessly long encoded length");
this.length = pvutils.utilFromBase(lengthBufferView, 8);
if (this.longFormUsed && (this.length <= 127))
this.warnings.push("Unnecessary usage of long length form");
this.blockLength = count + 1;
return (inputOffset + this.blockLength);
}
toBER(sizeOnly = false) {
let retBuf;
let retView;
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) {
const encodedBuf = pvutils.utilToBase(this.length, 8);
if (encodedBuf.byteLength > 127) {
this.error = "Too big length";
return (EMPTY_BUFFER);
}
retBuf = new ArrayBuffer(encodedBuf.byteLength + 1);
if (sizeOnly)
return retBuf;
const encodedView = new Uint8Array(encodedBuf);
retView = new Uint8Array(retBuf);
retView[0] = encodedBuf.byteLength | 0x80;
for (let 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;
}
toJSON() {
return {
...super.toJSON(),
isIndefiniteForm: this.isIndefiniteForm,
longFormUsed: this.longFormUsed,
length: this.length,
};
}
}
LocalLengthBlock.NAME = "lengthBlock";
class BaseBlock extends LocalBaseBlock {
constructor({ name = EMPTY_STRING, optional = false, primitiveSchema, ...parameters } = {}, valueBlockType) {
var _a;
super(parameters);
this.name = name;
this.optional = optional;
if (((_a = parameters.idBlock) === null || _a === void 0 ? void 0 : _a.optionalID) !== undefined && parameters.idBlock.optionalID >= 0)
this.optional = true;
if (primitiveSchema)
this.primitiveSchema = primitiveSchema;
this.idBlock = new LocalIdentificationBlock(parameters);
this.lenBlock = new LocalLengthBlock(parameters);
this.valueBlock = valueBlockType ? new valueBlockType(parameters) : new ValueBlock(parameters);
}
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
if (!this.idBlock.error.length) {
this.blockLength += this.idBlock.blockLength;
this.blockLength += this.lenBlock.blockLength;
this.blockLength += this.valueBlock.blockLength;
}
return resultOffset;
}
toBER(sizeOnly, writer) {
const _writer = writer || new ViewWriter();
if (!writer) {
prepareIndefiniteForm(this);
}
const idBlockBuf = this.idBlock.toBER(sizeOnly);
_writer.write(idBlockBuf);
if (this.lenBlock.isIndefiniteForm) {
_writer.write(new Uint8Array([0x80]).buffer);
this.valueBlock.toBER(sizeOnly, _writer);
_writer.write(new ArrayBuffer(2));
}
else {
const valueBlockBuf = this.valueBlock.toBER(sizeOnly);
this.lenBlock.length = valueBlockBuf.byteLength;
const lenBlockBuf = this.lenBlock.toBER(sizeOnly);
_writer.write(lenBlockBuf);
_writer.write(valueBlockBuf);
}
if (!writer) {
return _writer.final();
}
return EMPTY_BUFFER;
}
toJSON() {
const object = {
...super.toJSON(),
idBlock: this.idBlock.toJSON(),
lenBlock: this.lenBlock.toJSON(),
valueBlock: this.valueBlock.toJSON(),
name: this.name,
optional: this.optional,
};
if (this.primitiveSchema)
object.primitiveSchema = this.primitiveSchema.toJSON();
return object;
}
toString(encoding = "ascii") {
if (encoding === "ascii") {
return this.onAsciiEncoding();
}
return pvtsutils.Convert.ToHex(this.toBER());
}
onAsciiEncoding() {
return `${this.constructor.NAME} : ${pvtsutils.Convert.ToHex(this.valueBlock.valueBeforeDecodeView)}`;
}
isEqual(other) {
if (this === other) {
return true;
}
if (!(other instanceof this.constructor)) {
return false;
}
const thisRaw = this.toBER();
const otherRaw = other.toBER();
return pvutils.isEqualBuffer(thisRaw, otherRaw);
}
getUniversalTagNumber() {
if (this.idBlock.tagClass === ETagClass.UNIVERSAL)
return this.idBlock.tagNumber;
return undefined;
}
static mergeIDBlock(params, baseIDs) {
if (!params.idBlock)
params.idBlock = {};
if (params.idBlock.tagClass === undefined)
params.idBlock.tagClass = baseIDs.tagClass;
if (params.idBlock.tagNumber === undefined)
params.idBlock.tagNumber = baseIDs.tagNumber;
}
static matches(obj) {
if (!obj)
return false;
const comp = obj;
try {
return comp.idBlock.tagClass === this.defaultIDs.tagClass && comp.idBlock.tagNumber === this.defaultIDs.tagNumber;
}
catch (error) {
return false;
}
}
}
BaseBlock.NAME = "BaseBlock";
BaseBlock.defaultIDs = { tagClass: -1, tagNumber: -1 };
function prepareIndefiniteForm(baseBlock) {
if (baseBlock instanceof typeStore.Constructed) {
for (const value of baseBlock.valueBlock.value) {
if (prepareIndefiniteForm(value)) {
baseBlock.lenBlock.isIndefiniteForm = true;
}
}
}
return !!baseBlock.lenBlock.isIndefiniteForm;
}
class BaseStringBlock extends BaseBlock {
getValue() {
return this.valueBlock.value;
}
setValue(value) {
this.valueBlock.value = value;
}
constructor({ value = EMPTY_STRING, ...parameters } = {}, stringValueBlockType) {
super(parameters, stringValueBlockType);
if (value) {
this.fromString(value);
}
}
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
this.fromBuffer(this.valueBlock.valueHexView);
if (!this.idBlock.error.length)
this.blockLength += this.idBlock.blockLength;
if (!this.lenBlock.error.length)
this.blockLength += this.lenBlock.blockLength;
if (!this.valueBlock.error.length)
this.blockLength += this.valueBlock.blockLength;
return resultOffset;
}
onAsciiEncoding() {
return `${this.constructor.NAME} : '${this.valueBlock.value}'`;
}
}
BaseStringBlock.NAME = "BaseStringBlock";
class LocalPrimitiveValueBlock extends HexBlock(ValueBlock) {
constructor({ isHexOnly = true, ...parameters } = {}) {
super(parameters);
this.isHexOnly = isHexOnly;
}
}
LocalPrimitiveValueBlock.NAME = "PrimitiveValueBlock";
var _a$z;
class Primitive extends BaseBlock {
constructor(parameters = {}) {
super(parameters, LocalPrimitiveValueBlock);
this.idBlock.isConstructed = false;
}
getValue() {
return null;
}
setValue(value) {
}
}
_a$z = Primitive;
(() => {
typeStore.Primitive = _a$z;
})();
Primitive.NAME = "PRIMITIVE";
function localChangeType(inputObject, newType) {
if (inputObject instanceof newType) {
return inputObject;
}
const newObject = new newType();
newObject.idBlock = inputObject.idBlock;
newObject.lenBlock = inputObject.lenBlock;
newObject.warnings = inputObject.warnings;
newObject.valueBeforeDecodeView = inputObject.valueBeforeDecodeView;
return newObject;
}
function getTypeForIDBlock(idBlock) {
if (idBlock.tagClass === 1) {
switch (idBlock.tagNumber) {
case EUniversalTagNumber.EndOfContent:
return typeStore.EndOfContent;
case EUniversalTagNumber.Boolean:
return typeStore.Boolean;
case EUniversalTagNumber.Integer:
return typeStore.Integer;
case EUniversalTagNumber.BitString:
return typeStore.BitString;
case EUniversalTagNumber.OctetString:
return typeStore.OctetString;
case EUniversalTagNumber.Null:
return typeStore.Null;
case EUniversalTagNumber.ObjectIdentifier:
return typeStore.ObjectIdentifier;
case EUniversalTagNumber.Real:
return typeStore.Real;
case EUniversalTagNumber.Enumerated:
return typeStore.Enumerated;
case EUniversalTagNumber.Utf8String:
return typeStore.Utf8String;
case EUniversalTagNumber.RelativeObjectIdentifier:
return typeStore.RelativeObjectIdentifier;
case EUniversalTagNumber.TIME:
return typeStore.TIME;
case EUniversalTagNumber.Sequence:
return typeStore.Sequence;
case EUniversalTagNumber.Set:
return typeStore.Set;
case EUniversalTagNumber.NumericString:
return typeStore.NumericString;
case EUniversalTagNumber.PrintableString:
return typeStore.PrintableString;
case EUniversalTagNumber.TeletexString:
return typeStore.TeletexString;
case EUniversalTagNumber.VideotexString:
return typeStore.VideotexString;
case EUniversalTagNumber.IA5String:
return typeStore.IA5String;
case EUniversalTagNumber.UTCTime:
return typeStore.UTCTime;
case EUniversalTagNumber.GeneralizedTime:
return typeStore.GeneralizedTime;
case EUniversalTagNumber.GraphicString:
return typeStore.GraphicString;
case EUniversalTagNumber.VisibleString:
return typeStore.VisibleString;
case EUniversalTagNumber.GeneralString:
return typeStore.GeneralString;
case EUniversalTagNumber.UniversalString:
return typeStore.UniversalString;
case EUniversalTagNumber.CharacterString:
return typeStore.CharacterString;
case EUniversalTagNumber.BmpString:
return typeStore.BmpString;
case EUniversalTagNumber.DATE:
return typeStore.DATE;
case EUniversalTagNumber.TimeOfDay:
return typeStore.TimeOfDay;
case EUniversalTagNumber.DateTime:
return typeStore.DateTime;
case EUniversalTagNumber.Duration:
return typeStore.Duration;
default:
return undefined;
}
}
else {
return idBlock.isConstructed ? typeStore.Constructed : typeStore.Primitive;
}
}
function localFromBER(inputBuffer, inputOffset = 0, inputLength = inputBuffer.length) {
const incomingOffset = inputOffset;
let returnObject = new BaseBlock({}, ValueBlock);
const baseBlock = new LocalBaseBlock();
if (!checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength)) {
returnObject.error = baseBlock.error;
return {
offset: -1,
result: returnObject
};
}
const intBuffer = inputBuffer.subarray(inputOffset, inputOffset + inputLength);
if (!intBuffer.length) {
returnObject.error = "Zero buffer length";
return {
offset: -1,
result: returnObject
};
}
let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength);
if (returnObject.idBlock.warnings.length) {
returnObject.warnings.concat(returnObject.idBlock.warnings);
}
if (resultOffset === -1) {
returnObject.error = returnObject.idBlock.error;
return {
offset: -1,
result: returnObject
};
}
inputOffset = resultOffset;
inputLength -= returnObject.idBlock.blockLength;
resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength);
if (returnObject.lenBlock.warnings.length) {
returnObject.warnings.concat(returnObject.lenBlock.warnings);
}
if (resultOffset === -1) {
returnObject.error = returnObject.lenBlock.error;
return {
offset: -1,
result: returnObject
};
}
inputOffset = resultOffset;
inputLength -= returnObject.lenBlock.blockLength;
if (!returnObject.idBlock.isConstructed &&
returnObject.lenBlock.isIndefiniteForm) {
returnObject.error = "Indefinite length form used for primitive encoding form";
return {
offset: -1,
result: returnObject
};
}
if (returnObject.idBlock.tagClass === 1) {
if (returnObject.idBlock.tagNumber === 0 && returnObject.idBlock.isConstructed && returnObject.lenBlock.length > 0) {
returnObject.error = "Type [UNIVERSAL 0] is reserved";
return {
offset: -1,
result: returnObject
};
}
else if (returnObject.idBlock.tagNumber >= 37 && returnObject.idBlock.isHexOnly === false) {
returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard";
return {
offset: -1,
result: returnObject
};
}
}
const newASN1Type = getTypeForIDBlock(returnObject.idBlock);
if (newASN1Type === undefined) {
returnObject.error = `Unable to create property for tagClass:${returnObject.idBlock.tagClass} tagNumber:${returnObject.idBlock.tagNumber}`;
return {
offset: -1,
result: returnObject
};
}
if ((newASN1Type instanceof typeStore.Constructed || newASN1Type instanceof typeStore.Primitive) && returnObject.idBlock.tagClass === ETagClass.UNIVERSAL) {
newASN1Type.idBlock = returnObject.idBlock;
newASN1Type.lenBlock = returnObject.lenBlock;
newASN1Type.warnings = returnObject.warnings;
returnObject = newASN1Type;
}
returnObject = localChangeType(returnObject, newASN1Type);
resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm ? inputLength : returnObject.lenBlock.length);
returnObject.valueBeforeDecodeView = inputBuffer.subarray(incomingOffset, incomingOffset + returnObject.blockLength);
return {
offset: resultOffset,
result: returnObject
};
}
function fromBER(inputBuffer) {
if (!inputBuffer.byteLength) {
const result = new BaseBlock({}, ValueBlock);
result.error = "Input buffer has zero length";
return {
offset: -1,
result
};
}
return localFromBER(pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer).slice(), 0, inputBuffer.byteLength);
}
function checkLen(indefiniteLength, length) {
if (indefiniteLength) {
return 1;
}
return length;
}
class LocalConstructedValueBlock extends ValueBlock {
constructor({ value = [], isIndefiniteForm = false, ...parameters } = {}) {
super(parameters);
this.value = value;
this.isIndefiniteForm = isIndefiniteForm;
}
fromBER(inputBuffer, inputOffset, inputLength) {
const view = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
if (!checkBufferParams(this, view, inputOffset, inputLength)) {
return -1;
}
this.valueBeforeDecodeView = view.subarray(inputOffset, inputOffset + inputLength);
if (this.valueBeforeDecodeView.length === 0) {
this.warnings.push("Zero buffer length");
return inputOffset;
}
let currentOffset = inputOffset;
while (checkLen(this.isIndefiniteForm, inputLength) > 0) {
const returnObject = localFromBER(view, 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 && returnObject.result.constructor.NAME === END_OF_CONTENT_NAME) {
break;
}
}
if (this.isIndefiniteForm) {
if (this.value[this.value.length - 1].constructor.NAME === END_OF_CONTENT_NAME) {
this.value.pop();
}
else {
this.warnings.push("No EndOfContent block encoded");
}
}
return currentOffset;
}
toBER(sizeOnly, writer) {
const _writer = writer || new ViewWriter();
for (let i = 0; i < this.value.length; i++) {
this.value[i].toBER(sizeOnly, _writer);
}
if (!writer) {
return _writer.final();
}
return EMPTY_BUFFER;
}
toJSON() {
const object = {
...super.toJSON(),
isIndefiniteForm: this.isIndefiniteForm,
value: [],
};
for (const value of this.value) {
object.value.push(value.toJSON());
}
return object;
}
}
LocalConstructedValueBlock.NAME = "ConstructedValueBlock";
var _a$y;
class Constructed extends BaseBlock {
constructor(parameters = {}) {
super(parameters, LocalConstructedValueBlock);
this.idBlock.isConstructed = true;
}
fromBER(inputBuffer, inputOffset, inputLength) {
this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
if (!this.idBlock.error.length)
this.blockLength += this.idBlock.blockLength;
if (!this.lenBlock.error.length)
this.blockLength += this.lenBlock.blockLength;
if (!this.valueBlock.error.length)
this.blockLength += this.valueBlock.blockLength;
return resultOffset;
}
onAsciiEncoding() {
const values = [];
for (const value of this.valueBlock.value) {
values.push(value.toString("ascii").split("\n").map(o => ` ${o}`).join("\n"));
}
const blockName = this.idBlock.tagClass === 3
? `[${this.idBlock.tagNumber}]`
: this.constructor.NAME;
return values.length
? `${blockName} :\n${values.join("\n")}`
: `${blockName} :`;
}
getValueByName(name) {
const fields = this.valueBlock.value;
for (const value of fields) {
if (value.name === name)
return value;
}
return undefined;
}
getTypedValueByName(c, name) {
const ids = c.defaultIDs;
if (ids) {
const fields = this.valueBlock.value;
for (const value of fields) {
if (value.name === name) {
if (value.idBlock.isIdenticalType(ids))
return value;
}
}
}
return undefined;
}
getValue() {
return this.valueBlock.value;
}
setValue(value) {
this.valueBlock.value = value;
}
}
_a$y = Constructed;
(() => {
typeStore.Constructed = _a$y;
})();
Constructed.NAME = "CONSTRUCTED";
class LocalEndOfContentValueBlock extends ValueBlock {
fromBER(inputBuffer, inputOffset, inputLength) {
return inputOffset;
}
toBER(sizeOnly) {
return EMPTY_BUFFER;
}
}
LocalEndOfContentValueBlock.override = "EndOfContentValueBlock";
var _a$x;
class EndOfContent extends BaseBlock {
constructor(parameters = {}) {
_a$x.mergeIDBlock(parameters, _a$x.defaultIDs);
super(parameters, LocalEndOfContentValueBlock);
}
getValue() {
return null;
}
setValue(value) {
}
static typeGuard(obj) {
return this.matches(obj);
}
}
_a$x = EndOfContent;
(() => {
typeStore.EndOfContent = _a$x;
})();
EndOfContent.NAME = END_OF_CONTENT_NAME;
EndOfContent.defaultIDs = { tagClass: ETagClass.UNIVERSAL, tagNumber: EUniversalTagNumber.EndOfContent };
var _a$w;
class Null extends BaseBlock {
constructor(parameters = {}) {
_a$w.mergeIDBlock(parameters, _a$w.defaultIDs);
super(parameters, ValueBlock);
}
getValue() {
return null;
}
setValue(value) {
}
fromBER(inputBuffer, inputOffset, inputLength) {
if (this.lenBlock.length > 0)
this.warnings.push("Non-zero length of value block for Null type");
if (!this.idBlock.error.length)
this.blockLength += this.idBlock.blockLength;
if (!this.lenBlock.error.length)
this.blockLength += this.lenBlock.blockLength;
this.blockLength += inputLength;
if ((inputOffset + inputLength) > inputBuffer.byteLength) {
this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
return -1;
}
return (inputOffset + inputLength);
}
toBER(sizeOnly, writer) {
const retBuf = new ArrayBuffer(2);
if (!sizeOnly) {
const retView = new Uint8Array(retBuf);
retView[0] = 0x05;
retView[1] = 0x00;
}
if (writer) {
writer.write(retBuf);
}
return retBuf;
}
onAsciiEncoding() {
return `${this.constructor.NAME}`;
}
static typeGuard(obj) {
return this.matches(obj);
}
}
_a$w = Null;
(() => {
typeStore.Null = _a$w;
})();
Null.NAME = "NULL";
Null.defaultIDs = { tagClass: ETagClass.UNIVERSAL, tagNumber: EUniversalTagNumber.Null };
var _a$v;
class Extension extends BaseBlock {
constructor() {
super({ idBlock: _a$v.defaultIDs, optional: true }, ValueBlock);
}
getValue() {
return null;
}
setValue(value) {
}
fromBER(inputBuffer, inputOffset, inputLength) {
throw new Error("An extension attribute should never get decoded... It´s just for schema validation");
}
toBER(sizeOnly, writer) {
throw new Error("An extension attribute should never get encoded... It´s just for schema validation");
}
onAsciiEncoding() {
return `${this.constructor.NAME}`;
}
static typeGuard(obj) {
return this.matches(obj);
}
}
_a$v = Extension;
(() => {
typeStore.Extension = _a$v;
})();
Extension.NAME = "NULL";
Extension.defaultIDs = { tagClass: ETagClass.UNIVERSAL, tagNumber: EUniversalTagNumber.Extension };
class LocalBooleanValueBlock extends HexBlock(ValueBlock) {
get value() {
for (const octet of this.valueHexView) {
if (octet > 0) {
return true;
}
}
return false;
}
set value(value) {
this.valueHexView[0] = value ? 0xFF : 0x00;
}
constructor({ value, ...parameters } = {}) {
super(parameters);
if (parameters.valueHex) {
this.valueHexView = pvtsutils.BufferSourceConverter.toUint8Array(parameters.valueHex);
}
else {
this.valueHexView = new Uint8Array(1);
}
if (value) {
this.value = value;
}
}
fromBER(inputBuffer, inputOffset, inputLength) {
const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
return -1;
}
this.valueHexView = inputView.subarray(inputOffset, inputOffset + inputLength);
if (inputLength > 1)
this.warnings.push("Boolean value encoded in more then 1 octet");
pvuti