diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/third_party/asn1js/src/parser.ts | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/third_party/asn1js/src/parser.ts')
-rw-r--r-- | comm/third_party/asn1js/src/parser.ts | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/comm/third_party/asn1js/src/parser.ts b/comm/third_party/asn1js/src/parser.ts new file mode 100644 index 0000000000..51ab7dfcd8 --- /dev/null +++ b/comm/third_party/asn1js/src/parser.ts @@ -0,0 +1,301 @@ +import * as pvtsutils from "pvtsutils"; +import { ValueBlock } from "./ValueBlock"; +import { BaseBlock } from "./BaseBlock"; +import { LocalBaseBlock } from "./internals/LocalBaseBlock"; +import { AsnType, typeStore } from "./TypeStore"; +import { checkBufferParams } from "./internals/utils"; + +export interface FromBerResult { + offset: number; + result: AsnType; +} + +/** + * Local function changing a type for ASN.1 classes + * @param inputObject Incoming object + * @param newType Target type to convert + * @returns Converted object + */ +function localChangeType<T extends BaseBlock>(inputObject: BaseBlock, newType: new () => T): T { + 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; +} + +/** + * Internal library function for decoding ASN.1 BER + * @param inputBuffer ASN.1 BER encoded array + * @param inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param inputLength Maximum length of array of bytes which can be using in this function + * @returns + */ +export function localFromBER(inputBuffer: Uint8Array, inputOffset = 0, inputLength = inputBuffer.length): FromBerResult { + const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function + + // Create a basic ASN.1 type since we need to return errors and warnings from the function + let returnObject = new BaseBlock({}, ValueBlock); + + // Basic check for parameters + const baseBlock = new LocalBaseBlock(); + if (!checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength)) { + returnObject.error = baseBlock.error; + + return { + offset: -1, + result: returnObject + }; + } + + // Getting Uint8Array subarray + const intBuffer = inputBuffer.subarray(inputOffset, inputOffset + inputLength); + + // Initial checks + if (!intBuffer.length) { + returnObject.error = "Zero buffer length"; + + return { + offset: -1, + result: returnObject + }; + } + + // Decode identification block of ASN.1 BER structure + // console.time("idBlock"); + 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 + }; + } + // console.timeEnd("idBlock"); + + inputOffset = resultOffset; + inputLength -= returnObject.idBlock.blockLength; + + // Decode length block of ASN.1 BER structure + // console.time("lengthBlock"); + 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 + }; + } + // console.timeEnd("lengthBlock"); + + inputOffset = resultOffset; + inputLength -= returnObject.lenBlock.blockLength; + + // Check for using indefinite length form in encoding for primitive types + if (!returnObject.idBlock.isConstructed && + returnObject.lenBlock.isIndefiniteForm) { + returnObject.error = "Indefinite length form used for primitive encoding form"; + + return { + offset: -1, + result: returnObject + }; + } + + // Switch ASN.1 block type + let newASN1Type: new () => AsnType = BaseBlock as any; + + switch (returnObject.idBlock.tagClass) { + // UNIVERSAL + case 1: + // Check for reserved tag numbers + 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 + }; + } + switch (returnObject.idBlock.tagNumber) { + case 0: // EndOfContent + // Check for EndOfContent type + if ((returnObject.idBlock.isConstructed) && + (returnObject.lenBlock.length > 0)) { + returnObject.error = "Type [UNIVERSAL 0] is reserved"; + + return { + offset: -1, + result: returnObject + }; + } + + newASN1Type = typeStore.EndOfContent; + + break; + case 1: // Boolean + newASN1Type = typeStore.Boolean; + break; + case 2: // Integer + newASN1Type = typeStore.Integer; + break; + case 3: // BitString + newASN1Type = typeStore.BitString; + break; + case 4: // OctetString + newASN1Type = typeStore.OctetString; + break; + case 5: // Null + newASN1Type = typeStore.Null; + break; + case 6: // ObjectIdentifier + newASN1Type = typeStore.ObjectIdentifier; + break; + case 10: // Enumerated + newASN1Type = typeStore.Enumerated; + break; + case 12: // Utf8String + newASN1Type = typeStore.Utf8String; + break; + case 13: // RelativeObjectIdentifier + newASN1Type = typeStore.RelativeObjectIdentifier; + break; + case 14: // TIME + newASN1Type = typeStore.TIME; + break; + case 15: + returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard"; + + return { + offset: -1, + result: returnObject + }; + case 16: // Sequence + newASN1Type = typeStore.Sequence; + break; + case 17: // Set + newASN1Type = typeStore.Set; + break; + case 18: // NumericString + newASN1Type = typeStore.NumericString; + break; + case 19: // PrintableString + newASN1Type = typeStore.PrintableString; + break; + case 20: // TeletexString + newASN1Type = typeStore.TeletexString; + break; + case 21: // VideotexString + newASN1Type = typeStore.VideotexString; + break; + case 22: // IA5String + newASN1Type = typeStore.IA5String; + break; + case 23: // UTCTime + newASN1Type = typeStore.UTCTime; + break; + case 24: // GeneralizedTime + newASN1Type = typeStore.GeneralizedTime; + break; + case 25: // GraphicString + newASN1Type = typeStore.GraphicString; + break; + case 26: // VisibleString + newASN1Type = typeStore.VisibleString; + break; + case 27: // GeneralString + newASN1Type = typeStore.GeneralString; + break; + case 28: // UniversalString + newASN1Type = typeStore.UniversalString; + break; + case 29: // CharacterString + newASN1Type = typeStore.CharacterString; + break; + case 30: // BmpString + newASN1Type = typeStore.BmpString; + break; + case 31: // DATE + newASN1Type = typeStore.DATE; + break; + case 32: // TimeOfDay + newASN1Type = typeStore.TimeOfDay; + break; + case 33: // DateTime + newASN1Type = typeStore.DateTime; + break; + case 34: // Duration + newASN1Type = typeStore.Duration; + break; + default: { + const newObject = returnObject.idBlock.isConstructed + ? new typeStore.Constructed() + : new typeStore.Primitive(); + + newObject.idBlock = returnObject.idBlock; + newObject.lenBlock = returnObject.lenBlock; + newObject.warnings = returnObject.warnings; + + returnObject = newObject; + } + } + break; + // All other tag classes + case 2: // APPLICATION + case 3: // CONTEXT-SPECIFIC + case 4: // PRIVATE + default: { + newASN1Type = returnObject.idBlock.isConstructed + ? typeStore.Constructed + : typeStore.Primitive; + } + } + + + // Change type and perform BER decoding + returnObject = localChangeType(returnObject, newASN1Type); + // console.time("valueBlock"); + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm ? inputLength : returnObject.lenBlock.length); + + // Coping incoming buffer for entire ASN.1 block + returnObject.valueBeforeDecodeView = inputBuffer.subarray(incomingOffset, incomingOffset + returnObject.blockLength); + // console.timeEnd("valueBlock"); + + return { + offset: resultOffset, + result: returnObject + }; +} + +/** + * Major function for decoding ASN.1 BER array into internal library structures + * @param inputBuffer ASN.1 BER encoded array of bytes + */ +export function fromBER(inputBuffer: pvtsutils.BufferSource): FromBerResult { + 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); +} |