tor-browser

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

CertificateSet.ts (7484B)


      1 import * as asn1js from "asn1js";
      2 import * as pvutils from "pvutils";
      3 import { Certificate, CertificateJson } from "./Certificate";
      4 import { AttributeCertificateV1, AttributeCertificateV1Json } from "./AttributeCertificateV1";
      5 import { AttributeCertificateV2, AttributeCertificateV2Json } from "./AttributeCertificateV2";
      6 import { OtherCertificateFormat, OtherCertificateFormatJson } from "./OtherCertificateFormat";
      7 import * as Schema from "./Schema";
      8 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      9 import { AsnError } from "./errors";
     10 import { EMPTY_STRING } from "./constants";
     11 
     12 const CERTIFICATES = "certificates";
     13 const CLEAR_PROPS = [
     14  CERTIFICATES,
     15 ];
     16 
     17 export interface ICertificateSet {
     18  certificates: CertificateSetItem[];
     19 }
     20 
     21 export interface CertificateSetJson {
     22  certificates: CertificateSetItemJson[];
     23 }
     24 
     25 export type CertificateSetItemJson = CertificateJson | AttributeCertificateV1Json | AttributeCertificateV2Json | OtherCertificateFormatJson;
     26 
     27 export type CertificateSetItem = Certificate | AttributeCertificateV1 | AttributeCertificateV2 | OtherCertificateFormat;
     28 
     29 export type CertificateSetParameters = PkiObjectParameters & Partial<ICertificateSet>;
     30 
     31 /**
     32 * Represents the CertificateSet structure described in [RFC5652](https://datatracker.ietf.org/doc/html/rfc5652)
     33 */
     34 export class CertificateSet extends PkiObject implements ICertificateSet {
     35 
     36  public static override CLASS_NAME = "CertificateSet";
     37 
     38  public certificates!: CertificateSetItem[];
     39 
     40  /**
     41   * Initializes a new instance of the {@link CertificateSet} class
     42   * @param parameters Initialization parameters
     43   */
     44  constructor(parameters: CertificateSetParameters = {}) {
     45    super();
     46 
     47    this.certificates = pvutils.getParametersValue(parameters, CERTIFICATES, CertificateSet.defaultValues(CERTIFICATES));
     48 
     49    if (parameters.schema) {
     50      this.fromSchema(parameters.schema);
     51    }
     52  }
     53 
     54  /**
     55   * Returns default values for all class members
     56   * @param memberName String name for a class member
     57   * @returns Default value
     58   */
     59  public static override defaultValues(memberName: typeof CERTIFICATES): CertificateSetItem[];
     60  public static override defaultValues(memberName: string): any {
     61    switch (memberName) {
     62      case CERTIFICATES:
     63        return [];
     64      default:
     65        return super.defaultValues(memberName);
     66    }
     67  }
     68 
     69  /**
     70   * @inheritdoc
     71   * @asn ASN.1 schema
     72   * ```asn
     73   * CertificateSet ::= SET OF CertificateChoices
     74   *
     75   * CertificateChoices ::= CHOICE {
     76   *    certificate Certificate,
     77   *    extendedCertificate [0] IMPLICIT ExtendedCertificate,  -- Obsolete
     78   *    v1AttrCert [1] IMPLICIT AttributeCertificateV1,        -- Obsolete
     79   *    v2AttrCert [2] IMPLICIT AttributeCertificateV2,
     80   *    other [3] IMPLICIT OtherCertificateFormat }
     81   *```
     82   */
     83  public static override schema(parameters: Schema.SchemaParameters<{
     84    certificates?: string;
     85  }> = {}): Schema.SchemaType {
     86    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
     87 
     88    return (
     89      new asn1js.Set({
     90        name: (names.blockName || EMPTY_STRING),
     91        value: [
     92          new asn1js.Repeated({
     93            name: (names.certificates || CERTIFICATES),
     94            value: new asn1js.Choice({
     95              value: [
     96                Certificate.schema(),
     97                new asn1js.Constructed({
     98                  idBlock: {
     99                    tagClass: 3, // CONTEXT-SPECIFIC
    100                    tagNumber: 0 // [0]
    101                  },
    102                  value: [
    103                    new asn1js.Any()
    104                  ]
    105                }), // JUST A STUB
    106                new asn1js.Constructed({
    107                  idBlock: {
    108                    tagClass: 3, // CONTEXT-SPECIFIC
    109                    tagNumber: 1 // [1]
    110                  },
    111                  value: [
    112                    new asn1js.Sequence
    113                  ]
    114                }),
    115                new asn1js.Constructed({
    116                  idBlock: {
    117                    tagClass: 3, // CONTEXT-SPECIFIC
    118                    tagNumber: 2 // [2]
    119                  },
    120                  value: AttributeCertificateV2.schema().valueBlock.value
    121                }),
    122                new asn1js.Constructed({
    123                  idBlock: {
    124                    tagClass: 3, // CONTEXT-SPECIFIC
    125                    tagNumber: 3 // [3]
    126                  },
    127                  value: OtherCertificateFormat.schema().valueBlock.value
    128                })
    129              ]
    130            })
    131          })
    132        ]
    133      })
    134    );
    135  }
    136 
    137  public fromSchema(schema: Schema.SchemaType): void {
    138    // Clear input data first
    139    pvutils.clearProps(schema, CLEAR_PROPS);
    140 
    141    // Check the schema is valid
    142    const asn1 = asn1js.compareSchema(schema,
    143      schema,
    144      CertificateSet.schema()
    145    );
    146    AsnError.assertSchema(asn1, this.className);
    147 
    148    //#region Get internal properties from parsed schema
    149    this.certificates = Array.from(asn1.result.certificates || [], (element: any) => {
    150      const initialTagNumber = element.idBlock.tagNumber;
    151 
    152      if (element.idBlock.tagClass === 1)
    153        return new Certificate({ schema: element });
    154 
    155      //#region Making "Sequence" from "Constructed" value
    156      const elementSequence = new asn1js.Sequence({
    157        value: element.valueBlock.value
    158      });
    159      //#endregion
    160 
    161      switch (initialTagNumber) {
    162        case 1:
    163          // WARN: It's possible that CMS contains AttributeCertificateV2 instead of AttributeCertificateV1
    164          // Check the certificate version
    165          if ((elementSequence.valueBlock.value[0] as any).valueBlock.value[0].valueBlock.valueDec === 1) {
    166            return new AttributeCertificateV2({ schema: elementSequence });
    167          } else {
    168            return new AttributeCertificateV1({ schema: elementSequence });
    169          }
    170        case 2:
    171          return new AttributeCertificateV2({ schema: elementSequence });
    172        case 3:
    173          return new OtherCertificateFormat({ schema: elementSequence });
    174        case 0:
    175        default:
    176      }
    177 
    178      return element;
    179    });
    180    //#endregion
    181  }
    182 
    183  public toSchema(): asn1js.Set {
    184    // Construct and return new ASN.1 schema for this object
    185    return (new asn1js.Set({
    186      value: Array.from(this.certificates, element => {
    187        switch (true) {
    188          case (element instanceof Certificate):
    189            return element.toSchema();
    190          case (element instanceof AttributeCertificateV1):
    191            return new asn1js.Constructed({
    192              idBlock: {
    193                tagClass: 3,
    194                tagNumber: 1 // [1]
    195              },
    196              value: element.toSchema().valueBlock.value
    197            });
    198          case (element instanceof AttributeCertificateV2):
    199            return new asn1js.Constructed({
    200              idBlock: {
    201                tagClass: 3,
    202                tagNumber: 2 // [2]
    203              },
    204              value: element.toSchema().valueBlock.value
    205            });
    206          case (element instanceof OtherCertificateFormat):
    207            return new asn1js.Constructed({
    208              idBlock: {
    209                tagClass: 3,
    210                tagNumber: 3 // [3]
    211              },
    212              value: element.toSchema().valueBlock.value
    213            });
    214          default:
    215        }
    216 
    217        return (element as any).toSchema();
    218      })
    219    }));
    220  }
    221 
    222  public toJSON(): CertificateSetJson {
    223    return {
    224      certificates: Array.from(this.certificates, o => o.toJSON())
    225    };
    226  }
    227 
    228 }