tor-browser

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

Signature.ts (6654B)


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