tor-browser

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

RelativeDistinguishedNames.ts (6440B)


      1 import * as asn1js from "asn1js";
      2 import * as pvutils from "pvutils";
      3 import { AttributeTypeAndValue, AttributeTypeAndValueJson } from "./AttributeTypeAndValue";
      4 import { EMPTY_BUFFER, EMPTY_STRING } from "./constants";
      5 import { AsnError } from "./errors";
      6 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      7 import * as Schema from "./Schema";
      8 
      9 export const TYPE_AND_VALUES = "typesAndValues";
     10 export const VALUE_BEFORE_DECODE = "valueBeforeDecode";
     11 export const RDN = "RDN";
     12 
     13 export interface IRelativeDistinguishedNames {
     14  /**
     15   * Array of "type and value" objects
     16   */
     17  typesAndValues: AttributeTypeAndValue[];
     18  /**
     19   * Value of the RDN before decoding from schema
     20   */
     21  valueBeforeDecode: ArrayBuffer;
     22 }
     23 
     24 export type RelativeDistinguishedNamesParameters = PkiObjectParameters & Partial<IRelativeDistinguishedNames>;
     25 
     26 export type RelativeDistinguishedNamesSchema = Schema.SchemaParameters<{
     27  repeatedSequence?: string;
     28  repeatedSet?: string;
     29  typeAndValue?: Schema.SchemaType;
     30 }>;
     31 
     32 export interface RelativeDistinguishedNamesJson {
     33  typesAndValues: AttributeTypeAndValueJson[];
     34 }
     35 
     36 /**
     37 * Represents the RelativeDistinguishedNames structure described in [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280)
     38 */
     39 export class RelativeDistinguishedNames extends PkiObject implements IRelativeDistinguishedNames {
     40 
     41  public static override CLASS_NAME = "RelativeDistinguishedNames";
     42 
     43  public typesAndValues!: AttributeTypeAndValue[];
     44  public valueBeforeDecode!: ArrayBuffer;
     45 
     46  /**
     47   * Initializes a new instance of the {@link RelativeDistinguishedNames} class
     48   * @param parameters Initialization parameters
     49   */
     50  constructor(parameters: RelativeDistinguishedNamesParameters = {}) {
     51    super();
     52 
     53    this.typesAndValues = pvutils.getParametersValue(parameters, TYPE_AND_VALUES, RelativeDistinguishedNames.defaultValues(TYPE_AND_VALUES));
     54    this.valueBeforeDecode = pvutils.getParametersValue(parameters, VALUE_BEFORE_DECODE, RelativeDistinguishedNames.defaultValues(VALUE_BEFORE_DECODE));
     55 
     56    if (parameters.schema) {
     57      this.fromSchema(parameters.schema);
     58    }
     59  }
     60 
     61  /**
     62   * Returns default values for all class members
     63   * @param memberName String name for a class member
     64   * @returns Default value
     65   */
     66  public static override defaultValues(memberName: typeof TYPE_AND_VALUES): AttributeTypeAndValue[];
     67  public static override defaultValues(memberName: typeof VALUE_BEFORE_DECODE): ArrayBuffer;
     68  public static override defaultValues(memberName: string): any {
     69    switch (memberName) {
     70      case TYPE_AND_VALUES:
     71        return [];
     72      case VALUE_BEFORE_DECODE:
     73        return EMPTY_BUFFER;
     74      default:
     75        return super.defaultValues(memberName);
     76    }
     77  }
     78 
     79  /**
     80   * Compares values with default values for all class members
     81   * @param memberName String name for a class member
     82   * @param memberValue Value to compare with default value
     83   */
     84  public static compareWithDefault(memberName: string, memberValue: any): boolean {
     85    switch (memberName) {
     86      case TYPE_AND_VALUES:
     87        return (memberValue.length === 0);
     88      case VALUE_BEFORE_DECODE:
     89        return (memberValue.byteLength === 0);
     90      default:
     91        return super.defaultValues(memberName);
     92    }
     93  }
     94 
     95  /**
     96   * @inheritdoc
     97   * @asn ASN.1 schema
     98   * ```asn
     99   * RDNSequence ::= Sequence OF RelativeDistinguishedName
    100   *
    101   * RelativeDistinguishedName ::=
    102   * SET SIZE (1..MAX) OF AttributeTypeAndValue
    103   *```
    104   */
    105  static override schema(parameters: RelativeDistinguishedNamesSchema = {}): Schema.SchemaType {
    106    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    107 
    108    return (new asn1js.Sequence({
    109      name: (names.blockName || EMPTY_STRING),
    110      value: [
    111        new asn1js.Repeated({
    112          name: (names.repeatedSequence || EMPTY_STRING),
    113          value: new asn1js.Set({
    114            value: [
    115              new asn1js.Repeated({
    116                name: (names.repeatedSet || EMPTY_STRING),
    117                value: AttributeTypeAndValue.schema(names.typeAndValue || {})
    118              })
    119            ]
    120          } as any)
    121        } as any)
    122      ]
    123    } as any));
    124  }
    125 
    126  public fromSchema(schema: Schema.SchemaType): void {
    127    // Clear input data first
    128    pvutils.clearProps(schema, [
    129      RDN,
    130      TYPE_AND_VALUES
    131    ]);
    132 
    133    // Check the schema is valid
    134    const asn1 = asn1js.compareSchema(schema,
    135      schema,
    136      RelativeDistinguishedNames.schema({
    137        names: {
    138          blockName: RDN,
    139          repeatedSet: TYPE_AND_VALUES
    140        }
    141      })
    142    );
    143    AsnError.assertSchema(asn1, this.className);
    144 
    145    // Get internal properties from parsed schema
    146    if (TYPE_AND_VALUES in asn1.result) {// Could be a case when there is no "types and values"
    147      this.typesAndValues = Array.from(asn1.result.typesAndValues, element => new AttributeTypeAndValue({ schema: element }));
    148    }
    149 
    150    this.valueBeforeDecode = (asn1.result.RDN as asn1js.BaseBlock).valueBeforeDecodeView.slice().buffer;
    151  }
    152 
    153  public toSchema(): asn1js.Sequence {
    154    if (this.valueBeforeDecode.byteLength === 0) // No stored encoded array, create "from scratch"
    155    {
    156      return (new asn1js.Sequence({
    157        value: [new asn1js.Set({
    158          value: Array.from(this.typesAndValues, o => o.toSchema())
    159        } as any)]
    160      } as any));
    161    }
    162 
    163    const asn1 = asn1js.fromBER(this.valueBeforeDecode);
    164    AsnError.assert(asn1, "RelativeDistinguishedNames");
    165    if (!(asn1.result instanceof asn1js.Sequence)) {
    166      throw new Error("ASN.1 result should be SEQUENCE");
    167    }
    168 
    169    return asn1.result;
    170  }
    171 
    172  public toJSON(): RelativeDistinguishedNamesJson {
    173    return {
    174      typesAndValues: Array.from(this.typesAndValues, o => o.toJSON())
    175    };
    176  }
    177 
    178  /**
    179   * Compares two RDN values, or RDN with ArrayBuffer value
    180   * @param compareTo The value compare to current
    181   */
    182  public isEqual(compareTo: unknown): boolean {
    183    if (compareTo instanceof RelativeDistinguishedNames) {
    184      if (this.typesAndValues.length !== compareTo.typesAndValues.length)
    185        return false;
    186 
    187      for (const [index, typeAndValue] of this.typesAndValues.entries()) {
    188        if (typeAndValue.isEqual(compareTo.typesAndValues[index]) === false)
    189          return false;
    190      }
    191 
    192      return true;
    193    }
    194 
    195    if (compareTo instanceof ArrayBuffer) {
    196      return pvutils.isEqualBuffer(this.valueBeforeDecode, compareTo);
    197    }
    198 
    199    return false;
    200  }
    201 
    202 }