tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

EncapsulatedContentInfo.ts (6954B)


      1 import * as asn1js from "asn1js";
      2 import * as pvutils from "pvutils";
      3 import { EMPTY_STRING } from "./constants";
      4 import { AsnError } from "./errors";
      5 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      6 import * as Schema from "./Schema";
      7 
      8 const E_CONTENT_TYPE = "eContentType";
      9 const E_CONTENT = "eContent";
     10 const CLEAR_PROPS = [
     11  E_CONTENT_TYPE,
     12  E_CONTENT,
     13 ];
     14 
     15 export interface IEncapsulatedContentInfo {
     16  eContentType: string;
     17  eContent?: asn1js.OctetString;
     18 }
     19 
     20 export interface EncapsulatedContentInfoJson {
     21  eContentType: string;
     22  eContent?: asn1js.OctetStringJson;
     23 }
     24 
     25 export type EncapsulatedContentInfoParameters = PkiObjectParameters & Partial<IEncapsulatedContentInfo>;
     26 
     27 export type EncapsulatedContentInfoSchema = Schema.SchemaParameters<{
     28  eContentType?: string;
     29  eContent?: string;
     30 }>;
     31 
     32 /**
     33 * Represents the EncapsulatedContentInfo structure described in [RFC5652](https://datatracker.ietf.org/doc/html/rfc5652)
     34 */
     35 export class EncapsulatedContentInfo extends PkiObject implements IEncapsulatedContentInfo {
     36 
     37  public static override CLASS_NAME = "EncapsulatedContentInfo";
     38 
     39  public eContentType!: string;
     40  public eContent?: asn1js.OctetString;
     41 
     42  /**
     43   * Initializes a new instance of the {@link EncapsulatedContentInfo} class
     44   * @param parameters Initialization parameters
     45   */
     46  constructor(parameters: EncapsulatedContentInfoParameters = {}) {
     47    super();
     48 
     49    this.eContentType = pvutils.getParametersValue(parameters, E_CONTENT_TYPE, EncapsulatedContentInfo.defaultValues(E_CONTENT_TYPE));
     50    if (E_CONTENT in parameters) {
     51      this.eContent = pvutils.getParametersValue(parameters, E_CONTENT, EncapsulatedContentInfo.defaultValues(E_CONTENT));
     52      if ((this.eContent.idBlock.tagClass === 1) &&
     53        (this.eContent.idBlock.tagNumber === 4)) {
     54        //#region Divide OCTET STRING value down to small pieces
     55        if (this.eContent.idBlock.isConstructed === false) {
     56          const constrString = new asn1js.OctetString({
     57            idBlock: { isConstructed: true },
     58            isConstructed: true
     59          });
     60 
     61          let offset = 0;
     62          const viewHex = this.eContent.valueBlock.valueHexView.slice().buffer;
     63          let length = viewHex.byteLength;
     64 
     65          while (length > 0) {
     66            const pieceView = new Uint8Array(viewHex, offset, ((offset + 65536) > viewHex.byteLength) ? (viewHex.byteLength - offset) : 65536);
     67            const _array = new ArrayBuffer(pieceView.length);
     68            const _view = new Uint8Array(_array);
     69 
     70            for (let i = 0; i < _view.length; i++) {
     71              _view[i] = pieceView[i];
     72            }
     73 
     74            constrString.valueBlock.value.push(new asn1js.OctetString({ valueHex: _array }));
     75 
     76            length -= pieceView.length;
     77            offset += pieceView.length;
     78          }
     79 
     80          this.eContent = constrString;
     81        }
     82        //#endregion
     83      }
     84    }
     85 
     86    if (parameters.schema) {
     87      this.fromSchema(parameters.schema);
     88    }
     89  }
     90 
     91  /**
     92   * Returns default values for all class members
     93   * @param memberName String name for a class member
     94   * @returns Default value
     95   */
     96  public static override defaultValues(memberName: typeof E_CONTENT_TYPE): string;
     97  public static override defaultValues(memberName: typeof E_CONTENT): asn1js.OctetString;
     98  public static override defaultValues(memberName: string): any {
     99    switch (memberName) {
    100      case E_CONTENT_TYPE:
    101        return EMPTY_STRING;
    102      case E_CONTENT:
    103        return new asn1js.OctetString();
    104      default:
    105        return super.defaultValues(memberName);
    106    }
    107  }
    108 
    109  /**
    110   * Compare values with default values for all class members
    111   * @param memberName String name for a class member
    112   * @param memberValue Value to compare with default value
    113   */
    114  public static compareWithDefault(memberName: string, memberValue: any): boolean {
    115    switch (memberName) {
    116      case E_CONTENT_TYPE:
    117        return (memberValue === EMPTY_STRING);
    118      case E_CONTENT:
    119        {
    120          if ((memberValue.idBlock.tagClass === 1) && (memberValue.idBlock.tagNumber === 4))
    121            return (memberValue.isEqual(EncapsulatedContentInfo.defaultValues(E_CONTENT)));
    122 
    123          return false;
    124        }
    125      default:
    126        return super.defaultValues(memberName);
    127    }
    128  }
    129 
    130  /**
    131   * @inheritdoc
    132   * @asn ASN.1 schema
    133   * ```asn
    134   * EncapsulatedContentInfo ::= SEQUENCE {
    135   *    eContentType ContentType,
    136   *    eContent [0] EXPLICIT OCTET STRING OPTIONAL } * Changed it to ANY, as in PKCS#7
    137   *```
    138   */
    139  public static override schema(parameters: EncapsulatedContentInfoSchema = {}): Schema.SchemaType {
    140    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    141 
    142    return (new asn1js.Sequence({
    143      name: (names.blockName || EMPTY_STRING),
    144      value: [
    145        new asn1js.ObjectIdentifier({ name: (names.eContentType || EMPTY_STRING) }),
    146        new asn1js.Constructed({
    147          optional: true,
    148          idBlock: {
    149            tagClass: 3, // CONTEXT-SPECIFIC
    150            tagNumber: 0 // [0]
    151          },
    152          value: [
    153            new asn1js.Any({ name: (names.eContent || EMPTY_STRING) }) // In order to aling this with PKCS#7 and CMS as well
    154          ]
    155        })
    156      ]
    157    }));
    158  }
    159 
    160  public fromSchema(schema: Schema.SchemaType): void {
    161    // Clear input data first
    162    pvutils.clearProps(schema, CLEAR_PROPS);
    163 
    164    // Check the schema is valid
    165    const asn1 = asn1js.compareSchema(schema,
    166      schema,
    167      EncapsulatedContentInfo.schema({
    168        names: {
    169          eContentType: E_CONTENT_TYPE,
    170          eContent: E_CONTENT
    171        }
    172      })
    173    );
    174    AsnError.assertSchema(asn1, this.className);
    175 
    176    // Get internal properties from parsed schema
    177    this.eContentType = asn1.result.eContentType.valueBlock.toString();
    178    if (E_CONTENT in asn1.result)
    179      this.eContent = asn1.result.eContent;
    180  }
    181 
    182  public toSchema(): asn1js.Sequence {
    183    //#region Create array for output sequence
    184    const outputArray = [];
    185 
    186    outputArray.push(new asn1js.ObjectIdentifier({ value: this.eContentType }));
    187    if (this.eContent) {
    188      if (EncapsulatedContentInfo.compareWithDefault(E_CONTENT, this.eContent) === false) {
    189        outputArray.push(new asn1js.Constructed({
    190          optional: true,
    191          idBlock: {
    192            tagClass: 3, // CONTEXT-SPECIFIC
    193            tagNumber: 0 // [0]
    194          },
    195          value: [this.eContent]
    196        }));
    197      }
    198    }
    199    //#endregion
    200 
    201    //#region Construct and return new ASN.1 schema for this object
    202    return (new asn1js.Sequence({
    203      value: outputArray
    204    }));
    205    //#endregion
    206  }
    207 
    208  public toJSON(): EncapsulatedContentInfoJson {
    209    const res: EncapsulatedContentInfoJson = {
    210      eContentType: this.eContentType
    211    };
    212 
    213    if (this.eContent && EncapsulatedContentInfo.compareWithDefault(E_CONTENT, this.eContent) === false) {
    214      res.eContent = this.eContent.toJSON();
    215    }
    216 
    217    return res;
    218  }
    219 
    220 }