tor-browser

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

SignerInfo.ts (13366B)


      1 import * as asn1js from "asn1js";
      2 import * as pvutils from "pvutils";
      3 import { AlgorithmIdentifier, AlgorithmIdentifierJson, AlgorithmIdentifierSchema } from "./AlgorithmIdentifier";
      4 import { SignedAndUnsignedAttributes, SignedAndUnsignedAttributesJson, SignedAndUnsignedAttributesSchema } from "./SignedAndUnsignedAttributes";
      5 import { IssuerAndSerialNumber, IssuerAndSerialNumberSchema } from "./IssuerAndSerialNumber";
      6 import * as Schema from "./Schema";
      7 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      8 import { AsnError } from "./errors";
      9 
     10 const VERSION = "version";
     11 const SID = "sid";
     12 const DIGEST_ALGORITHM = "digestAlgorithm";
     13 const SIGNED_ATTRS = "signedAttrs";
     14 const SIGNATURE_ALGORITHM = "signatureAlgorithm";
     15 const SIGNATURE = "signature";
     16 const UNSIGNED_ATTRS = "unsignedAttrs";
     17 const SIGNER_INFO = "SignerInfo";
     18 const SIGNER_INFO_VERSION = `${SIGNER_INFO}.${VERSION}`;
     19 const SIGNER_INFO_SID = `${SIGNER_INFO}.${SID}`;
     20 const SIGNER_INFO_DIGEST_ALGORITHM = `${SIGNER_INFO}.${DIGEST_ALGORITHM}`;
     21 const SIGNER_INFO_SIGNED_ATTRS = `${SIGNER_INFO}.${SIGNED_ATTRS}`;
     22 const SIGNER_INFO_SIGNATURE_ALGORITHM = `${SIGNER_INFO}.${SIGNATURE_ALGORITHM}`;
     23 const SIGNER_INFO_SIGNATURE = `${SIGNER_INFO}.${SIGNATURE}`;
     24 const SIGNER_INFO_UNSIGNED_ATTRS = `${SIGNER_INFO}.${UNSIGNED_ATTRS}`;
     25 const CLEAR_PROPS = [
     26  SIGNER_INFO_VERSION,
     27  SIGNER_INFO_SID,
     28  SIGNER_INFO_DIGEST_ALGORITHM,
     29  SIGNER_INFO_SIGNED_ATTRS,
     30  SIGNER_INFO_SIGNATURE_ALGORITHM,
     31  SIGNER_INFO_SIGNATURE,
     32  SIGNER_INFO_UNSIGNED_ATTRS
     33 ];
     34 
     35 export interface ISignerInfo {
     36  version: number;
     37  sid: Schema.SchemaType;
     38  digestAlgorithm: AlgorithmIdentifier;
     39  signedAttrs?: SignedAndUnsignedAttributes;
     40  signatureAlgorithm: AlgorithmIdentifier;
     41  signature: asn1js.OctetString;
     42  unsignedAttrs?: SignedAndUnsignedAttributes;
     43 }
     44 
     45 export interface SignerInfoJson {
     46  version: number;
     47  sid?: Schema.SchemaType;
     48  digestAlgorithm: AlgorithmIdentifierJson;
     49  signedAttrs?: SignedAndUnsignedAttributesJson;
     50  signatureAlgorithm: AlgorithmIdentifierJson;
     51  signature: asn1js.OctetStringJson;
     52  unsignedAttrs?: SignedAndUnsignedAttributesJson;
     53 }
     54 
     55 export type SignerInfoParameters = PkiObjectParameters & Partial<ISignerInfo>;
     56 
     57 /**
     58 * Represents the SignerInfo structure described in [RFC5652](https://datatracker.ietf.org/doc/html/rfc5652)
     59 */
     60 export class SignerInfo extends PkiObject implements ISignerInfo {
     61 
     62  public static override CLASS_NAME = "SignerInfo";
     63 
     64  public version!: number;
     65  public sid: Schema.SchemaType;
     66  public digestAlgorithm!: AlgorithmIdentifier;
     67  public signedAttrs?: SignedAndUnsignedAttributes;
     68  public signatureAlgorithm!: AlgorithmIdentifier;
     69  public signature!: asn1js.OctetString;
     70  public unsignedAttrs?: SignedAndUnsignedAttributes;
     71 
     72  /**
     73   * Initializes a new instance of the {@link SignerInfo} class
     74   * @param parameters Initialization parameters
     75   */
     76  constructor(parameters: SignerInfoParameters = {}) {
     77    super();
     78 
     79    this.version = pvutils.getParametersValue(parameters, VERSION, SignerInfo.defaultValues(VERSION));
     80    this.sid = pvutils.getParametersValue(parameters, SID, SignerInfo.defaultValues(SID));
     81    this.digestAlgorithm = pvutils.getParametersValue(parameters, DIGEST_ALGORITHM, SignerInfo.defaultValues(DIGEST_ALGORITHM));
     82    if (SIGNED_ATTRS in parameters) {
     83      this.signedAttrs = pvutils.getParametersValue(parameters, SIGNED_ATTRS, SignerInfo.defaultValues(SIGNED_ATTRS));
     84    }
     85    this.signatureAlgorithm = pvutils.getParametersValue(parameters, SIGNATURE_ALGORITHM, SignerInfo.defaultValues(SIGNATURE_ALGORITHM));
     86    this.signature = pvutils.getParametersValue(parameters, SIGNATURE, SignerInfo.defaultValues(SIGNATURE));
     87    if (UNSIGNED_ATTRS in parameters) {
     88      this.unsignedAttrs = pvutils.getParametersValue(parameters, UNSIGNED_ATTRS, SignerInfo.defaultValues(UNSIGNED_ATTRS));
     89    }
     90 
     91    if (parameters.schema) {
     92      this.fromSchema(parameters.schema);
     93    }
     94  }
     95 
     96  /**
     97   * Returns default values for all class members
     98   * @param memberName String name for a class member
     99   * @returns Default value
    100   */
    101  public static override defaultValues(memberName: typeof VERSION): number;
    102  public static override defaultValues(memberName: typeof SID): Schema.SchemaType;
    103  public static override defaultValues(memberName: typeof DIGEST_ALGORITHM): AlgorithmIdentifier;
    104  public static override defaultValues(memberName: typeof SIGNED_ATTRS): SignedAndUnsignedAttributes;
    105  public static override defaultValues(memberName: typeof SIGNATURE_ALGORITHM): AlgorithmIdentifier;
    106  public static override defaultValues(memberName: typeof SIGNATURE): asn1js.OctetString;
    107  public static override defaultValues(memberName: typeof UNSIGNED_ATTRS): SignedAndUnsignedAttributes;
    108  public static override defaultValues(memberName: string): any {
    109    switch (memberName) {
    110      case VERSION:
    111        return 0;
    112      case SID:
    113        return new asn1js.Any();
    114      case DIGEST_ALGORITHM:
    115        return new AlgorithmIdentifier();
    116      case SIGNED_ATTRS:
    117        return new SignedAndUnsignedAttributes({ type: 0 });
    118      case SIGNATURE_ALGORITHM:
    119        return new AlgorithmIdentifier();
    120      case SIGNATURE:
    121        return new asn1js.OctetString();
    122      case UNSIGNED_ATTRS:
    123        return new SignedAndUnsignedAttributes({ type: 1 });
    124      default:
    125        return super.defaultValues(memberName);
    126    }
    127  }
    128 
    129  /**
    130   * Compare values with default values for all class members
    131   * @param memberName String name for a class member
    132   * @param memberValue Value to compare with default value
    133   */
    134  public static compareWithDefault(memberName: string, memberValue: any): boolean {
    135    switch (memberName) {
    136      case VERSION:
    137        return (SignerInfo.defaultValues(VERSION) === memberValue);
    138      case SID:
    139        return (memberValue instanceof asn1js.Any);
    140      case DIGEST_ALGORITHM:
    141        if ((memberValue instanceof AlgorithmIdentifier) === false)
    142          return false;
    143 
    144        return memberValue.isEqual(SignerInfo.defaultValues(DIGEST_ALGORITHM));
    145      case SIGNED_ATTRS:
    146        return ((SignedAndUnsignedAttributes.compareWithDefault("type", memberValue.type))
    147          && (SignedAndUnsignedAttributes.compareWithDefault("attributes", memberValue.attributes))
    148          && (SignedAndUnsignedAttributes.compareWithDefault("encodedValue", memberValue.encodedValue)));
    149      case SIGNATURE_ALGORITHM:
    150        if ((memberValue instanceof AlgorithmIdentifier) === false)
    151          return false;
    152 
    153        return memberValue.isEqual(SignerInfo.defaultValues(SIGNATURE_ALGORITHM));
    154      case SIGNATURE:
    155      case UNSIGNED_ATTRS:
    156        return ((SignedAndUnsignedAttributes.compareWithDefault("type", memberValue.type))
    157          && (SignedAndUnsignedAttributes.compareWithDefault("attributes", memberValue.attributes))
    158          && (SignedAndUnsignedAttributes.compareWithDefault("encodedValue", memberValue.encodedValue)));
    159      default:
    160        return super.defaultValues(memberName);
    161    }
    162  }
    163 
    164  /**
    165   * @inheritdoc
    166   * @asn ASN.1 schema
    167   * ```asn
    168   * SignerInfo ::= SEQUENCE {
    169   *    version CMSVersion,
    170   *    sid SignerIdentifier,
    171   *    digestAlgorithm DigestAlgorithmIdentifier,
    172   *    signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
    173   *    signatureAlgorithm SignatureAlgorithmIdentifier,
    174   *    signature SignatureValue,
    175   *    unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }
    176   *
    177   * SignerIdentifier ::= CHOICE {
    178   *    issuerAndSerialNumber IssuerAndSerialNumber,
    179   *    subjectKeyIdentifier [0] SubjectKeyIdentifier }
    180   *
    181   * SubjectKeyIdentifier ::= OCTET STRING
    182   *```
    183   */
    184  public static override schema(parameters: Schema.SchemaParameters<{
    185    version?: string;
    186    sidSchema?: IssuerAndSerialNumberSchema;
    187    sid?: string;
    188    digestAlgorithm?: AlgorithmIdentifierSchema;
    189    signedAttrs?: SignedAndUnsignedAttributesSchema;
    190    signatureAlgorithm?: AlgorithmIdentifierSchema;
    191    signature?: string;
    192    unsignedAttrs?: SignedAndUnsignedAttributesSchema;
    193  }> = {}): Schema.SchemaType {
    194    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    195 
    196    return (
    197      new asn1js.Sequence({
    198        name: SIGNER_INFO,
    199        value: [
    200          new asn1js.Integer({ name: (names.version || SIGNER_INFO_VERSION) }),
    201          new asn1js.Choice({
    202            value: [
    203              IssuerAndSerialNumber.schema(names.sidSchema || {
    204                names: {
    205                  blockName: SIGNER_INFO_SID
    206                }
    207              }),
    208              new asn1js.Choice({
    209                value: [
    210                  new asn1js.Constructed({
    211                    optional: true,
    212                    name: (names.sid || SIGNER_INFO_SID),
    213                    idBlock: {
    214                      tagClass: 3, // CONTEXT-SPECIFIC
    215                      tagNumber: 0 // [0]
    216                    },
    217                    value: [new asn1js.OctetString()]
    218                  }),
    219                  new asn1js.Primitive({
    220                    optional: true,
    221                    name: (names.sid || SIGNER_INFO_SID),
    222                    idBlock: {
    223                      tagClass: 3, // CONTEXT-SPECIFIC
    224                      tagNumber: 0 // [0]
    225                    }
    226                  }),
    227                ]
    228              }),
    229            ]
    230          }),
    231          AlgorithmIdentifier.schema(names.digestAlgorithm || {
    232            names: {
    233              blockName: SIGNER_INFO_DIGEST_ALGORITHM
    234            }
    235          }),
    236          SignedAndUnsignedAttributes.schema(names.signedAttrs || {
    237            names: {
    238              blockName: SIGNER_INFO_SIGNED_ATTRS,
    239              tagNumber: 0
    240            }
    241          }),
    242          AlgorithmIdentifier.schema(names.signatureAlgorithm || {
    243            names: {
    244              blockName: SIGNER_INFO_SIGNATURE_ALGORITHM
    245            }
    246          }),
    247          new asn1js.OctetString({ name: (names.signature || SIGNER_INFO_SIGNATURE) }),
    248          SignedAndUnsignedAttributes.schema(names.unsignedAttrs || {
    249            names: {
    250              blockName: SIGNER_INFO_UNSIGNED_ATTRS,
    251              tagNumber: 1
    252            }
    253          })
    254        ]
    255      })
    256    );
    257  }
    258 
    259  public fromSchema(schema: Schema.SchemaType): void {
    260    // Clear input data first
    261    pvutils.clearProps(schema, CLEAR_PROPS);
    262 
    263    // Check the schema is valid
    264    const asn1 = asn1js.compareSchema(schema,
    265      schema,
    266      SignerInfo.schema()
    267    );
    268    AsnError.assertSchema(asn1, this.className);
    269 
    270    // Get internal properties from parsed schema
    271    this.version = asn1.result[SIGNER_INFO_VERSION].valueBlock.valueDec;
    272 
    273    const currentSid = asn1.result[SIGNER_INFO_SID];
    274    if (currentSid.idBlock.tagClass === 1)
    275      this.sid = new IssuerAndSerialNumber({ schema: currentSid });
    276    else
    277      this.sid = currentSid;
    278 
    279    this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result[SIGNER_INFO_DIGEST_ALGORITHM] });
    280    if (SIGNER_INFO_SIGNED_ATTRS in asn1.result)
    281      this.signedAttrs = new SignedAndUnsignedAttributes({ type: 0, schema: asn1.result[SIGNER_INFO_SIGNED_ATTRS] });
    282 
    283    this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result[SIGNER_INFO_SIGNATURE_ALGORITHM] });
    284    this.signature = asn1.result[SIGNER_INFO_SIGNATURE];
    285    if (SIGNER_INFO_UNSIGNED_ATTRS in asn1.result)
    286      this.unsignedAttrs = new SignedAndUnsignedAttributes({ type: 1, schema: asn1.result[SIGNER_INFO_UNSIGNED_ATTRS] });
    287  }
    288 
    289  public toSchema(): asn1js.Sequence {
    290    if (SignerInfo.compareWithDefault(SID, this.sid))
    291      throw new Error("Incorrectly initialized \"SignerInfo\" class");
    292 
    293    //#region Create array for output sequence
    294    const outputArray = [];
    295 
    296    outputArray.push(new asn1js.Integer({ value: this.version }));
    297 
    298    if (this.sid instanceof IssuerAndSerialNumber)
    299      outputArray.push(this.sid.toSchema());
    300    else
    301      outputArray.push(this.sid);
    302 
    303    outputArray.push(this.digestAlgorithm.toSchema());
    304 
    305    if (this.signedAttrs) {
    306      if (SignerInfo.compareWithDefault(SIGNED_ATTRS, this.signedAttrs) === false)
    307        outputArray.push(this.signedAttrs.toSchema());
    308    }
    309 
    310    outputArray.push(this.signatureAlgorithm.toSchema());
    311    outputArray.push(this.signature);
    312 
    313    if (this.unsignedAttrs) {
    314      if (SignerInfo.compareWithDefault(UNSIGNED_ATTRS, this.unsignedAttrs) === false)
    315        outputArray.push(this.unsignedAttrs.toSchema());
    316    }
    317    //#endregion
    318 
    319    //#region Construct and return new ASN.1 schema for this object
    320    return (new asn1js.Sequence({
    321      value: outputArray
    322    }));
    323    //#endregion
    324  }
    325 
    326  public toJSON(): SignerInfoJson {
    327    if (SignerInfo.compareWithDefault(SID, this.sid)) {
    328      throw new Error("Incorrectly initialized \"SignerInfo\" class");
    329    }
    330 
    331    const res: SignerInfoJson = {
    332      version: this.version,
    333      digestAlgorithm: this.digestAlgorithm.toJSON(),
    334      signatureAlgorithm: this.signatureAlgorithm.toJSON(),
    335      signature: this.signature.toJSON(),
    336    };
    337 
    338    if (!(this.sid instanceof asn1js.Any))
    339      res.sid = this.sid.toJSON();
    340 
    341    if (this.signedAttrs && SignerInfo.compareWithDefault(SIGNED_ATTRS, this.signedAttrs) === false) {
    342      res.signedAttrs = this.signedAttrs.toJSON();
    343    }
    344 
    345    if (this.unsignedAttrs && SignerInfo.compareWithDefault(UNSIGNED_ATTRS, this.unsignedAttrs) === false) {
    346      res.unsignedAttrs = this.unsignedAttrs.toJSON();
    347    }
    348 
    349    return res;
    350  }
    351 
    352 }