tor-browser

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

TimeStampReq.ts (11565B)


      1 import * as asn1js from "asn1js";
      2 import * as pvutils from "pvutils";
      3 import { MessageImprint, MessageImprintJson, MessageImprintSchema } from "./MessageImprint";
      4 import { Extension, ExtensionJson } from "./Extension";
      5 import * as Schema from "./Schema";
      6 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      7 import { AsnError } from "./errors";
      8 import { EMPTY_STRING } from "./constants";
      9 
     10 const VERSION = "version";
     11 const MESSAGE_IMPRINT = "messageImprint";
     12 const REQ_POLICY = "reqPolicy";
     13 const NONCE = "nonce";
     14 const CERT_REQ = "certReq";
     15 const EXTENSIONS = "extensions";
     16 const TIME_STAMP_REQ = "TimeStampReq";
     17 const TIME_STAMP_REQ_VERSION = `${TIME_STAMP_REQ}.${VERSION}`;
     18 const TIME_STAMP_REQ_MESSAGE_IMPRINT = `${TIME_STAMP_REQ}.${MESSAGE_IMPRINT}`;
     19 const TIME_STAMP_REQ_POLICY = `${TIME_STAMP_REQ}.${REQ_POLICY}`;
     20 const TIME_STAMP_REQ_NONCE = `${TIME_STAMP_REQ}.${NONCE}`;
     21 const TIME_STAMP_REQ_CERT_REQ = `${TIME_STAMP_REQ}.${CERT_REQ}`;
     22 const TIME_STAMP_REQ_EXTENSIONS = `${TIME_STAMP_REQ}.${EXTENSIONS}`;
     23 const CLEAR_PROPS = [
     24  TIME_STAMP_REQ_VERSION,
     25  TIME_STAMP_REQ_MESSAGE_IMPRINT,
     26  TIME_STAMP_REQ_POLICY,
     27  TIME_STAMP_REQ_NONCE,
     28  TIME_STAMP_REQ_CERT_REQ,
     29  TIME_STAMP_REQ_EXTENSIONS,
     30 ];
     31 
     32 export interface ITimeStampReq {
     33  /**
     34   * Version of the Time-Stamp request. Should be version 1.
     35   */
     36  version: number;
     37  /**
     38   * Contains the hash of the datum to be time-stamped
     39   */
     40  messageImprint: MessageImprint;
     41  /**
     42   * Indicates the TSA policy under which the TimeStampToken SHOULD be provided.
     43   */
     44  reqPolicy?: string;
     45  /**
     46   * The nonce, if included, allows the client to verify the timeliness of
     47   * the response when no local clock is available. The nonce is a large
     48   * random number with a high probability that the client generates it
     49   * only once.
     50   */
     51  nonce?: asn1js.Integer;
     52  /**
     53   * If the certReq field is present and set to true, the TSA's public key
     54   * certificate that is referenced by the ESSCertID identifier inside a
     55   * SigningCertificate attribute in the response MUST be provided by the
     56   * TSA in the certificates field from the SignedData structure in that
     57   * response. That field may also contain other certificates.
     58   *
     59   * If the certReq field is missing or if the certReq field is present
     60   * and set to false then the certificates field from the SignedData
     61   * structure MUST not be present in the response.
     62   */
     63  certReq?: boolean;
     64  /**
     65   * The extensions field is a generic way to add additional information
     66   * to the request in the future.
     67   */
     68  extensions?: Extension[];
     69 }
     70 
     71 export interface TimeStampReqJson {
     72  version: number;
     73  messageImprint: MessageImprintJson;
     74  reqPolicy?: string;
     75  nonce?: asn1js.IntegerJson;
     76  certReq?: boolean;
     77  extensions?: ExtensionJson[];
     78 }
     79 
     80 export type TimeStampReqParameters = PkiObjectParameters & Partial<ITimeStampReq>;
     81 
     82 /**
     83 * Represents the TimeStampReq structure described in [RFC3161](https://www.ietf.org/rfc/rfc3161.txt)
     84 *
     85 * @example The following example demonstrates how to create Time-Stamp Request
     86 * ```js
     87 * const nonce = pkijs.getRandomValues(new Uint8Array(10)).buffer;
     88 *
     89 * const tspReq = new pkijs.TimeStampReq({
     90 *   version: 1,
     91 *   messageImprint: await pkijs.MessageImprint.create("SHA-256", message),
     92 *   reqPolicy: "1.2.3.4.5.6",
     93 *   certReq: true,
     94 *   nonce: new asn1js.Integer({ valueHex: nonce }),
     95 * });
     96 *
     97 * const tspReqRaw = tspReq.toSchema().toBER();
     98 * ```
     99 */
    100 export class TimeStampReq extends PkiObject implements ITimeStampReq {
    101 
    102  public static override CLASS_NAME = "TimeStampReq";
    103 
    104  public version!: number;
    105  public messageImprint!: MessageImprint;
    106  public reqPolicy?: string;
    107  public nonce?: asn1js.Integer;
    108  public certReq?: boolean;
    109  public extensions?: Extension[];
    110 
    111  /**
    112   * Initializes a new instance of the {@link TimeStampReq} class
    113   * @param parameters Initialization parameters
    114   */
    115  constructor(parameters: TimeStampReqParameters = {}) {
    116    super();
    117 
    118    this.version = pvutils.getParametersValue(parameters, VERSION, TimeStampReq.defaultValues(VERSION));
    119    this.messageImprint = pvutils.getParametersValue(parameters, MESSAGE_IMPRINT, TimeStampReq.defaultValues(MESSAGE_IMPRINT));
    120    if (REQ_POLICY in parameters) {
    121      this.reqPolicy = pvutils.getParametersValue(parameters, REQ_POLICY, TimeStampReq.defaultValues(REQ_POLICY));
    122    }
    123    if (NONCE in parameters) {
    124      this.nonce = pvutils.getParametersValue(parameters, NONCE, TimeStampReq.defaultValues(NONCE));
    125    }
    126    if (CERT_REQ in parameters) {
    127      this.certReq = pvutils.getParametersValue(parameters, CERT_REQ, TimeStampReq.defaultValues(CERT_REQ));
    128    }
    129    if (EXTENSIONS in parameters) {
    130      this.extensions = pvutils.getParametersValue(parameters, EXTENSIONS, TimeStampReq.defaultValues(EXTENSIONS));
    131    }
    132 
    133    if (parameters.schema) {
    134      this.fromSchema(parameters.schema);
    135    }
    136  }
    137 
    138  /**
    139   * Returns default values for all class members
    140   * @param memberName String name for a class member
    141   * @returns Default value
    142   */
    143  public static override defaultValues(memberName: typeof VERSION): number;
    144  public static override defaultValues(memberName: typeof MESSAGE_IMPRINT): MessageImprint;
    145  public static override defaultValues(memberName: typeof REQ_POLICY): string;
    146  public static override defaultValues(memberName: typeof NONCE): asn1js.Integer;
    147  public static override defaultValues(memberName: typeof CERT_REQ): boolean;
    148  public static override defaultValues(memberName: typeof EXTENSIONS): Extension[];
    149  public static override defaultValues(memberName: string): any {
    150    switch (memberName) {
    151      case VERSION:
    152        return 0;
    153      case MESSAGE_IMPRINT:
    154        return new MessageImprint();
    155      case REQ_POLICY:
    156        return EMPTY_STRING;
    157      case NONCE:
    158        return new asn1js.Integer();
    159      case CERT_REQ:
    160        return false;
    161      case EXTENSIONS:
    162        return [];
    163      default:
    164        return super.defaultValues(memberName);
    165    }
    166  }
    167 
    168  /**
    169   * Compare values with default values for all class members
    170   * @param memberName String name for a class member
    171   * @param memberValue Value to compare with default value
    172   */
    173  public static compareWithDefault(memberName: string, memberValue: any): boolean {
    174    switch (memberName) {
    175      case VERSION:
    176      case REQ_POLICY:
    177      case CERT_REQ:
    178        return (memberValue === TimeStampReq.defaultValues(memberName as typeof CERT_REQ));
    179      case MESSAGE_IMPRINT:
    180        return ((MessageImprint.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) &&
    181          (MessageImprint.compareWithDefault("hashedMessage", memberValue.hashedMessage)));
    182      case NONCE:
    183        return (memberValue.isEqual(TimeStampReq.defaultValues(memberName)));
    184      case EXTENSIONS:
    185        return (memberValue.length === 0);
    186      default:
    187        return super.defaultValues(memberName);
    188    }
    189  }
    190 
    191  /**
    192   * @inheritdoc
    193   * @asn ASN.1 schema
    194   * ```asn
    195   * TimeStampReq ::= SEQUENCE  {
    196   *    version               INTEGER  { v1(1) },
    197   *    messageImprint        MessageImprint,
    198   *    reqPolicy             TSAPolicyId              OPTIONAL,
    199   *    nonce                 INTEGER                  OPTIONAL,
    200   *    certReq               BOOLEAN                  DEFAULT FALSE,
    201   *    extensions            [0] IMPLICIT Extensions  OPTIONAL  }
    202   *
    203   * TSAPolicyId ::= OBJECT IDENTIFIER
    204   *```
    205   */
    206  public static override schema(parameters: Schema.SchemaParameters<{
    207    version?: string;
    208    messageImprint?: MessageImprintSchema;
    209    reqPolicy?: string;
    210    nonce?: string;
    211    certReq?: string;
    212    extensions?: string;
    213  }> = {}): Schema.SchemaType {
    214    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    215 
    216    return (new asn1js.Sequence({
    217      name: (names.blockName || TIME_STAMP_REQ),
    218      value: [
    219        new asn1js.Integer({ name: (names.version || TIME_STAMP_REQ_VERSION) }),
    220        MessageImprint.schema(names.messageImprint || {
    221          names: {
    222            blockName: TIME_STAMP_REQ_MESSAGE_IMPRINT
    223          }
    224        }),
    225        new asn1js.ObjectIdentifier({
    226          name: (names.reqPolicy || TIME_STAMP_REQ_POLICY),
    227          optional: true
    228        }),
    229        new asn1js.Integer({
    230          name: (names.nonce || TIME_STAMP_REQ_NONCE),
    231          optional: true
    232        }),
    233        new asn1js.Boolean({
    234          name: (names.certReq || TIME_STAMP_REQ_CERT_REQ),
    235          optional: true
    236        }),
    237        new asn1js.Constructed({
    238          optional: true,
    239          idBlock: {
    240            tagClass: 3, // CONTEXT-SPECIFIC
    241            tagNumber: 0 // [0]
    242          },
    243          value: [new asn1js.Repeated({
    244            name: (names.extensions || TIME_STAMP_REQ_EXTENSIONS),
    245            value: Extension.schema()
    246          })]
    247        }) // IMPLICIT SEQUENCE value
    248      ]
    249    }));
    250  }
    251 
    252  public fromSchema(schema: Schema.SchemaType): void {
    253    // Clear input data first
    254    pvutils.clearProps(schema, CLEAR_PROPS);
    255 
    256    // Check the schema is valid
    257    const asn1 = asn1js.compareSchema(schema,
    258      schema,
    259      TimeStampReq.schema()
    260    );
    261 
    262    AsnError.assertSchema(asn1, this.className);
    263 
    264    // Get internal properties from parsed schema
    265    this.version = asn1.result[TIME_STAMP_REQ_VERSION].valueBlock.valueDec;
    266    this.messageImprint = new MessageImprint({ schema: asn1.result[TIME_STAMP_REQ_MESSAGE_IMPRINT] });
    267    if (TIME_STAMP_REQ_POLICY in asn1.result)
    268      this.reqPolicy = asn1.result[TIME_STAMP_REQ_POLICY].valueBlock.toString();
    269    if (TIME_STAMP_REQ_NONCE in asn1.result)
    270      this.nonce = asn1.result[TIME_STAMP_REQ_NONCE];
    271    if (TIME_STAMP_REQ_CERT_REQ in asn1.result)
    272      this.certReq = asn1.result[TIME_STAMP_REQ_CERT_REQ].valueBlock.value;
    273    if (TIME_STAMP_REQ_EXTENSIONS in asn1.result)
    274      this.extensions = Array.from(asn1.result[TIME_STAMP_REQ_EXTENSIONS], element => new Extension({ schema: element }));
    275  }
    276 
    277  public toSchema(): asn1js.Sequence {
    278    //#region Create array for output sequence
    279    const outputArray = [];
    280 
    281    outputArray.push(new asn1js.Integer({ value: this.version }));
    282    outputArray.push(this.messageImprint.toSchema());
    283    if (this.reqPolicy)
    284      outputArray.push(new asn1js.ObjectIdentifier({ value: this.reqPolicy }));
    285    if (this.nonce)
    286      outputArray.push(this.nonce);
    287    if ((CERT_REQ in this) && (TimeStampReq.compareWithDefault(CERT_REQ, this.certReq) === false))
    288      outputArray.push(new asn1js.Boolean({ value: this.certReq }));
    289 
    290    //#region Create array of extensions
    291    if (this.extensions) {
    292      outputArray.push(new asn1js.Constructed({
    293        idBlock: {
    294          tagClass: 3, // CONTEXT-SPECIFIC
    295          tagNumber: 0 // [0]
    296        },
    297        value: Array.from(this.extensions, o => o.toSchema())
    298      }));
    299    }
    300    //#endregion
    301    //#endregion
    302 
    303    //#region Construct and return new ASN.1 schema for this object
    304    return (new asn1js.Sequence({
    305      value: outputArray
    306    }));
    307    //#endregion
    308  }
    309 
    310  public toJSON(): TimeStampReqJson {
    311    const res: TimeStampReqJson = {
    312      version: this.version,
    313      messageImprint: this.messageImprint.toJSON()
    314    };
    315 
    316    if (this.reqPolicy !== undefined)
    317      res.reqPolicy = this.reqPolicy;
    318 
    319    if (this.nonce !== undefined)
    320      res.nonce = this.nonce.toJSON();
    321 
    322    if ((this.certReq !== undefined) && (TimeStampReq.compareWithDefault(CERT_REQ, this.certReq) === false))
    323      res.certReq = this.certReq;
    324 
    325    if (this.extensions) {
    326      res.extensions = Array.from(this.extensions, o => o.toJSON());
    327    }
    328 
    329    return res;
    330  }
    331 
    332 }