tor-browser

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

SignedAndUnsignedAttributes.ts (6493B)


      1 import * as asn1js from "asn1js";
      2 import * as pvtsutils from "pvtsutils";
      3 import * as pvutils from "pvutils";
      4 import { Attribute, AttributeJson } from "./Attribute";
      5 import { EMPTY_BUFFER, EMPTY_STRING } from "./constants";
      6 import { AsnError } from "./errors";
      7 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      8 import * as Schema from "./Schema";
      9 
     10 const TYPE = "type";
     11 const ATTRIBUTES = "attributes";
     12 const ENCODED_VALUE = "encodedValue";
     13 const CLEAR_PROPS = [
     14  ATTRIBUTES
     15 ];
     16 
     17 export interface ISignedAndUnsignedAttributes {
     18  type: number;
     19  attributes: Attribute[];
     20  /**
     21   * Need to have it in order to successfully process with signature verification
     22   */
     23  encodedValue: ArrayBuffer;
     24 }
     25 
     26 export interface SignedAndUnsignedAttributesJson {
     27  type: number;
     28  attributes: AttributeJson[];
     29 }
     30 
     31 export type SignedAndUnsignedAttributesParameters = PkiObjectParameters & Partial<ISignedAndUnsignedAttributes>;
     32 
     33 export type SignedAndUnsignedAttributesSchema = Schema.SchemaParameters<{
     34  tagNumber?: number;
     35  attributes?: string;
     36 }>;
     37 
     38 /**
     39 * Represents the SignedAndUnsignedAttributes structure described in [RFC5652](https://datatracker.ietf.org/doc/html/rfc5652)
     40 */
     41 export class SignedAndUnsignedAttributes extends PkiObject implements ISignedAndUnsignedAttributes {
     42 
     43  public static override CLASS_NAME = "SignedAndUnsignedAttributes";
     44 
     45  public type!: number;
     46  public attributes!: Attribute[];
     47  public encodedValue!: ArrayBuffer;
     48 
     49  /**
     50   * Initializes a new instance of the {@link SignedAndUnsignedAttributes} class
     51   * @param parameters Initialization parameters
     52   */
     53  constructor(parameters: SignedAndUnsignedAttributesParameters = {}) {
     54    super();
     55 
     56    this.type = pvutils.getParametersValue(parameters, TYPE, SignedAndUnsignedAttributes.defaultValues(TYPE));
     57    this.attributes = pvutils.getParametersValue(parameters, ATTRIBUTES, SignedAndUnsignedAttributes.defaultValues(ATTRIBUTES));
     58    this.encodedValue = pvutils.getParametersValue(parameters, ENCODED_VALUE, SignedAndUnsignedAttributes.defaultValues(ENCODED_VALUE));
     59 
     60    if (parameters.schema) {
     61      this.fromSchema(parameters.schema);
     62    }
     63  }
     64 
     65  /**
     66   * Returns default values for all class members
     67   * @param memberName String name for a class member
     68   * @returns Default value
     69   */
     70  public static override defaultValues(memberName: typeof TYPE): number;
     71  public static override defaultValues(memberName: typeof ATTRIBUTES): Attribute[];
     72  public static override defaultValues(memberName: typeof ENCODED_VALUE): ArrayBuffer;
     73  public static override defaultValues(memberName: string): any {
     74    switch (memberName) {
     75      case TYPE:
     76        return (-1);
     77      case ATTRIBUTES:
     78        return [];
     79      case ENCODED_VALUE:
     80        return EMPTY_BUFFER;
     81      default:
     82        return super.defaultValues(memberName);
     83    }
     84  }
     85 
     86  /**
     87   * Compare values with default values for all class members
     88   * @param memberName String name for a class member
     89   * @param memberValue Value to compare with default value
     90   */
     91  public static compareWithDefault(memberName: string, memberValue: any): boolean {
     92    switch (memberName) {
     93      case TYPE:
     94        return (memberValue === SignedAndUnsignedAttributes.defaultValues(TYPE));
     95      case ATTRIBUTES:
     96        return (memberValue.length === 0);
     97      case ENCODED_VALUE:
     98        return (memberValue.byteLength === 0);
     99      default:
    100        return super.defaultValues(memberName);
    101    }
    102  }
    103 
    104  /**
    105   * @inheritdoc
    106   * @asn ASN.1 schema
    107   * ```asn
    108   * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute
    109   *
    110   * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
    111   *```
    112   */
    113  public static override schema(parameters: SignedAndUnsignedAttributesSchema = {}): Schema.SchemaType {
    114    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    115 
    116    return (new asn1js.Constructed({
    117      name: (names.blockName || EMPTY_STRING),
    118      optional: true,
    119      idBlock: {
    120        tagClass: 3, // CONTEXT-SPECIFIC
    121        tagNumber: names.tagNumber || 0 // "SignedAttributes" = 0, "UnsignedAttributes" = 1
    122      },
    123      value: [
    124        new asn1js.Repeated({
    125          name: (names.attributes || EMPTY_STRING),
    126          value: Attribute.schema()
    127        })
    128      ]
    129    }));
    130  }
    131 
    132  public fromSchema(schema: Schema.SchemaType): void {
    133    // Clear input data first
    134    pvutils.clearProps(schema, CLEAR_PROPS);
    135 
    136    // Check the schema is valid
    137    const asn1 = asn1js.compareSchema(schema,
    138      schema,
    139      SignedAndUnsignedAttributes.schema({
    140        names: {
    141          tagNumber: this.type,
    142          attributes: ATTRIBUTES
    143        }
    144      })
    145    );
    146    AsnError.assertSchema(asn1, this.className);
    147 
    148    // Get internal properties from parsed schema
    149    this.type = asn1.result.idBlock.tagNumber;
    150    this.encodedValue = pvtsutils.BufferSourceConverter.toArrayBuffer(asn1.result.valueBeforeDecodeView);
    151 
    152    //#region Change type from "[0]" to "SET" accordingly to standard
    153    const encodedView = new Uint8Array(this.encodedValue);
    154    encodedView[0] = 0x31;
    155    //#endregion
    156 
    157    if ((ATTRIBUTES in asn1.result) === false) {
    158      if (this.type === 0)
    159        throw new Error("Wrong structure of SignedUnsignedAttributes");
    160      else
    161        return; // Not so important in case of "UnsignedAttributes"
    162    }
    163 
    164    this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element }));
    165    //#endregion
    166  }
    167 
    168  public toSchema(): asn1js.Sequence {
    169    if (SignedAndUnsignedAttributes.compareWithDefault(TYPE, this.type) || SignedAndUnsignedAttributes.compareWithDefault(ATTRIBUTES, this.attributes))
    170      throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class");
    171 
    172    //#region Construct and return new ASN.1 schema for this object
    173    return (new asn1js.Constructed({
    174      optional: true,
    175      idBlock: {
    176        tagClass: 3, // CONTEXT-SPECIFIC
    177        tagNumber: this.type // "SignedAttributes" = 0, "UnsignedAttributes" = 1
    178      },
    179      value: Array.from(this.attributes, o => o.toSchema())
    180    }));
    181    //#endregion
    182  }
    183 
    184  public toJSON(): SignedAndUnsignedAttributesJson {
    185    if (SignedAndUnsignedAttributes.compareWithDefault(TYPE, this.type) || SignedAndUnsignedAttributes.compareWithDefault(ATTRIBUTES, this.attributes))
    186      throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class");
    187 
    188    return {
    189      type: this.type,
    190      attributes: Array.from(this.attributes, o => o.toJSON())
    191    };
    192  }
    193 
    194 }