tor-browser

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

GeneralName.ts (18270B)


      1 import * as asn1js from "asn1js";
      2 import * as pvutils from "pvutils";
      3 import { EMPTY_STRING } from "./constants";
      4 import { AsnError } from "./errors";
      5 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      6 import { RelativeDistinguishedNames } from "./RelativeDistinguishedNames";
      7 import * as Schema from "./Schema";
      8 
      9 export const TYPE = "type";
     10 export const VALUE = "value";
     11 
     12 //#region Additional asn1js schema elements existing inside GeneralName schema
     13 
     14 /**
     15 * Schema for "builtInStandardAttributes" of "ORAddress"
     16 * @param parameters
     17 * @property names
     18 * @param optional
     19 * @returns
     20 */
     21 function builtInStandardAttributes(parameters: Schema.SchemaParameters<{
     22  country_name?: string;
     23  administration_domain_name?: string;
     24  network_address?: string;
     25  terminal_identifier?: string;
     26  private_domain_name?: string;
     27  organization_name?: string;
     28  numeric_user_identifier?: string;
     29  personal_name?: string;
     30  organizational_unit_names?: string;
     31 }> = {}, optional = false) {
     32  //builtInStandardAttributes ::= Sequence {
     33  //    country-name                  CountryName OPTIONAL,
     34  //    administration-domain-name    AdministrationDomainName OPTIONAL,
     35  //    network-address           [0] IMPLICIT NetworkAddress OPTIONAL,
     36  //    terminal-identifier       [1] IMPLICIT TerminalIdentifier OPTIONAL,
     37  //    private-domain-name       [2] PrivateDomainName OPTIONAL,
     38  //    organization-name         [3] IMPLICIT OrganizationName OPTIONAL,
     39  //    numeric-user-identifier   [4] IMPLICIT NumericUserIdentifier OPTIONAL,
     40  //    personal-name             [5] IMPLICIT PersonalName OPTIONAL,
     41  //    organizational-unit-names [6] IMPLICIT OrganizationalUnitNames OPTIONAL }
     42  const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
     43 
     44  return (new asn1js.Sequence({
     45    optional,
     46    value: [
     47      new asn1js.Constructed({
     48        optional: true,
     49        idBlock: {
     50          tagClass: 2, // APPLICATION-SPECIFIC
     51          tagNumber: 1 // [1]
     52        },
     53        name: (names.country_name || EMPTY_STRING),
     54        value: [
     55          new asn1js.Choice({
     56            value: [
     57              new asn1js.NumericString(),
     58              new asn1js.PrintableString()
     59            ]
     60          })
     61        ]
     62      }),
     63      new asn1js.Constructed({
     64        optional: true,
     65        idBlock: {
     66          tagClass: 2, // APPLICATION-SPECIFIC
     67          tagNumber: 2 // [2]
     68        },
     69        name: (names.administration_domain_name || EMPTY_STRING),
     70        value: [
     71          new asn1js.Choice({
     72            value: [
     73              new asn1js.NumericString(),
     74              new asn1js.PrintableString()
     75            ]
     76          })
     77        ]
     78      }),
     79      new asn1js.Primitive({
     80        optional: true,
     81        idBlock: {
     82          tagClass: 3, // CONTEXT-SPECIFIC
     83          tagNumber: 0 // [0]
     84        },
     85        name: (names.network_address || EMPTY_STRING),
     86        isHexOnly: true
     87      }),
     88      new asn1js.Primitive({
     89        optional: true,
     90        idBlock: {
     91          tagClass: 3, // CONTEXT-SPECIFIC
     92          tagNumber: 1 // [1]
     93        },
     94        name: (names.terminal_identifier || EMPTY_STRING),
     95        isHexOnly: true
     96      }),
     97      new asn1js.Constructed({
     98        optional: true,
     99        idBlock: {
    100          tagClass: 3, // CONTEXT-SPECIFIC
    101          tagNumber: 2 // [2]
    102        },
    103        name: (names.private_domain_name || EMPTY_STRING),
    104        value: [
    105          new asn1js.Choice({
    106            value: [
    107              new asn1js.NumericString(),
    108              new asn1js.PrintableString()
    109            ]
    110          })
    111        ]
    112      }),
    113      new asn1js.Primitive({
    114        optional: true,
    115        idBlock: {
    116          tagClass: 3, // CONTEXT-SPECIFIC
    117          tagNumber: 3 // [3]
    118        },
    119        name: (names.organization_name || EMPTY_STRING),
    120        isHexOnly: true
    121      }),
    122      new asn1js.Primitive({
    123        optional: true,
    124        name: (names.numeric_user_identifier || EMPTY_STRING),
    125        idBlock: {
    126          tagClass: 3, // CONTEXT-SPECIFIC
    127          tagNumber: 4 // [4]
    128        },
    129        isHexOnly: true
    130      }),
    131      new asn1js.Constructed({
    132        optional: true,
    133        name: (names.personal_name || EMPTY_STRING),
    134        idBlock: {
    135          tagClass: 3, // CONTEXT-SPECIFIC
    136          tagNumber: 5 // [5]
    137        },
    138        value: [
    139          new asn1js.Primitive({
    140            idBlock: {
    141              tagClass: 3, // CONTEXT-SPECIFIC
    142              tagNumber: 0 // [0]
    143            },
    144            isHexOnly: true
    145          }),
    146          new asn1js.Primitive({
    147            optional: true,
    148            idBlock: {
    149              tagClass: 3, // CONTEXT-SPECIFIC
    150              tagNumber: 1 // [1]
    151            },
    152            isHexOnly: true
    153          }),
    154          new asn1js.Primitive({
    155            optional: true,
    156            idBlock: {
    157              tagClass: 3, // CONTEXT-SPECIFIC
    158              tagNumber: 2 // [2]
    159            },
    160            isHexOnly: true
    161          }),
    162          new asn1js.Primitive({
    163            optional: true,
    164            idBlock: {
    165              tagClass: 3, // CONTEXT-SPECIFIC
    166              tagNumber: 3 // [3]
    167            },
    168            isHexOnly: true
    169          })
    170        ]
    171      }),
    172      new asn1js.Constructed({
    173        optional: true,
    174        name: (names.organizational_unit_names || EMPTY_STRING),
    175        idBlock: {
    176          tagClass: 3, // CONTEXT-SPECIFIC
    177          tagNumber: 6 // [6]
    178        },
    179        value: [
    180          new asn1js.Repeated({
    181            value: new asn1js.PrintableString()
    182          })
    183        ]
    184      })
    185    ]
    186  }));
    187 }
    188 
    189 /**
    190 * Schema for "builtInDomainDefinedAttributes" of "ORAddress"
    191 * @param optional
    192 */
    193 function builtInDomainDefinedAttributes(optional = false): Schema.SchemaType {
    194  return (new asn1js.Sequence({
    195    optional,
    196    value: [
    197      new asn1js.PrintableString(),
    198      new asn1js.PrintableString()
    199    ]
    200  }));
    201 }
    202 
    203 /**
    204 * Schema for "builtInDomainDefinedAttributes" of "ORAddress"
    205 * @param optional
    206 */
    207 function extensionAttributes(optional = false): Schema.SchemaType {
    208  return (new asn1js.Set({
    209    optional,
    210    value: [
    211      new asn1js.Primitive({
    212        optional: true,
    213        idBlock: {
    214          tagClass: 3, // CONTEXT-SPECIFIC
    215          tagNumber: 0 // [0]
    216        },
    217        isHexOnly: true
    218      }),
    219      new asn1js.Constructed({
    220        optional: true,
    221        idBlock: {
    222          tagClass: 3, // CONTEXT-SPECIFIC
    223          tagNumber: 1 // [1]
    224        },
    225        value: [new asn1js.Any()]
    226      })
    227    ]
    228  }));
    229 }
    230 
    231 //#endregion
    232 
    233 export interface IGeneralName {
    234  /**
    235   * value type - from a tagged value (0 for "otherName", 1 for "rfc822Name" etc.)
    236   */
    237  type: number;
    238  /**
    239   * ASN.1 object having GeneralName value (type depends on TYPE value)
    240   */
    241  value: any;
    242 }
    243 
    244 export type GeneralNameParameters = PkiObjectParameters & Partial<{ type: 1 | 2 | 6; value: string; } | { type: 0 | 3 | 4 | 7 | 8; value: any; }>;
    245 
    246 export interface GeneralNameSchema {
    247  names?: {
    248    blockName?: string;
    249    directoryName?: object;
    250    builtInStandardAttributes?: object;
    251    otherName?: string;
    252    rfc822Name?: string;
    253    dNSName?: string;
    254    x400Address?: string;
    255    ediPartyName?: string;
    256    uniformResourceIdentifier?: string;
    257    iPAddress?: string;
    258    registeredID?: string;
    259  };
    260 }
    261 
    262 export interface GeneralNameJson {
    263  type: number;
    264  value: string;
    265 }
    266 
    267 /**
    268 * Represents the GeneralName structure described in [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280)
    269 */
    270 export class GeneralName extends PkiObject implements IGeneralName {
    271 
    272  public static override CLASS_NAME = "GeneralName";
    273 
    274  public type!: number;
    275  public value: any;
    276 
    277  /**
    278   * Initializes a new instance of the {@link GeneralName} class
    279   * @param parameters Initialization parameters
    280   */
    281  constructor(parameters: GeneralNameParameters = {}) {
    282    super();
    283 
    284    this.type = pvutils.getParametersValue(parameters, TYPE, GeneralName.defaultValues(TYPE));
    285    this.value = pvutils.getParametersValue(parameters, VALUE, GeneralName.defaultValues(VALUE));
    286 
    287    if (parameters.schema) {
    288      this.fromSchema(parameters.schema);
    289    }
    290  }
    291 
    292  /**
    293   * Returns default values for all class members
    294   * @param memberName String name for a class member
    295   * @returns Default value
    296   */
    297  public static override defaultValues(memberName: typeof TYPE): number;
    298  public static override defaultValues(memberName: typeof VALUE): any;
    299  public static override defaultValues(memberName: string): any {
    300    switch (memberName) {
    301      case TYPE:
    302        return 9;
    303      case VALUE:
    304        return {};
    305      default:
    306        return super.defaultValues(memberName);
    307    }
    308  }
    309 
    310  /**
    311   * Compares values with default values for all class members
    312   * @param memberName String name for a class member
    313   * @param memberValue Value to compare with default value
    314   */
    315  public static compareWithDefault(memberName: string, memberValue: any): boolean {
    316    switch (memberName) {
    317      case TYPE:
    318        return (memberValue === GeneralName.defaultValues(memberName));
    319      case VALUE:
    320        return (Object.keys(memberValue).length === 0);
    321      default:
    322        return super.defaultValues(memberName);
    323    }
    324  }
    325 
    326  /**
    327   * @inheritdoc
    328   * @asn ASN.1 schema
    329   * ```asn
    330   * GeneralName ::= Choice {
    331   *    otherName                       [0]     OtherName,
    332   *    rfc822Name                      [1]     IA5String,
    333   *    dNSName                         [2]     IA5String,
    334   *    x400Address                     [3]     ORAddress,
    335   *    directoryName                   [4]     value,
    336   *    ediPartyName                    [5]     EDIPartyName,
    337   *    uniformResourceIdentifier       [6]     IA5String,
    338   *    iPAddress                       [7]     OCTET STRING,
    339   *    registeredID                    [8]     OBJECT IDENTIFIER }
    340   *```
    341   */
    342  static override schema(parameters: GeneralNameSchema = {}): asn1js.Choice {
    343    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    344 
    345    return (new asn1js.Choice({
    346      value: [
    347        new asn1js.Constructed({
    348          idBlock: {
    349            tagClass: 3, // CONTEXT-SPECIFIC
    350            tagNumber: 0 // [0]
    351          },
    352          name: (names.blockName || EMPTY_STRING),
    353          value: [
    354            new asn1js.ObjectIdentifier(),
    355            new asn1js.Constructed({
    356              idBlock: {
    357                tagClass: 3, // CONTEXT-SPECIFIC
    358                tagNumber: 0 // [0]
    359              },
    360              value: [new asn1js.Any()]
    361            })
    362          ]
    363        }),
    364        new asn1js.Primitive({
    365          name: (names.blockName || EMPTY_STRING),
    366          idBlock: {
    367            tagClass: 3, // CONTEXT-SPECIFIC
    368            tagNumber: 1 // [1]
    369          }
    370        }),
    371        new asn1js.Primitive({
    372          name: (names.blockName || EMPTY_STRING),
    373          idBlock: {
    374            tagClass: 3, // CONTEXT-SPECIFIC
    375            tagNumber: 2 // [2]
    376          }
    377        }),
    378        new asn1js.Constructed({
    379          idBlock: {
    380            tagClass: 3, // CONTEXT-SPECIFIC
    381            tagNumber: 3 // [3]
    382          },
    383          name: (names.blockName || EMPTY_STRING),
    384          value: [
    385            builtInStandardAttributes((names.builtInStandardAttributes || {}), false),
    386            builtInDomainDefinedAttributes(true),
    387            extensionAttributes(true)
    388          ]
    389        }),
    390        new asn1js.Constructed({
    391          idBlock: {
    392            tagClass: 3, // CONTEXT-SPECIFIC
    393            tagNumber: 4 // [4]
    394          },
    395          name: (names.blockName || EMPTY_STRING),
    396          value: [RelativeDistinguishedNames.schema(names.directoryName || {})]
    397        }),
    398        new asn1js.Constructed({
    399          idBlock: {
    400            tagClass: 3, // CONTEXT-SPECIFIC
    401            tagNumber: 5 // [5]
    402          },
    403          name: (names.blockName || EMPTY_STRING),
    404          value: [
    405            new asn1js.Constructed({
    406              optional: true,
    407              idBlock: {
    408                tagClass: 3, // CONTEXT-SPECIFIC
    409                tagNumber: 0 // [0]
    410              },
    411              value: [
    412                new asn1js.Choice({
    413                  value: [
    414                    new asn1js.TeletexString(),
    415                    new asn1js.PrintableString(),
    416                    new asn1js.UniversalString(),
    417                    new asn1js.Utf8String(),
    418                    new asn1js.BmpString()
    419                  ]
    420                })
    421              ]
    422            }),
    423            new asn1js.Constructed({
    424              idBlock: {
    425                tagClass: 3, // CONTEXT-SPECIFIC
    426                tagNumber: 1 // [1]
    427              },
    428              value: [
    429                new asn1js.Choice({
    430                  value: [
    431                    new asn1js.TeletexString(),
    432                    new asn1js.PrintableString(),
    433                    new asn1js.UniversalString(),
    434                    new asn1js.Utf8String(),
    435                    new asn1js.BmpString()
    436                  ]
    437                })
    438              ]
    439            })
    440          ]
    441        }),
    442        new asn1js.Primitive({
    443          name: (names.blockName || EMPTY_STRING),
    444          idBlock: {
    445            tagClass: 3, // CONTEXT-SPECIFIC
    446            tagNumber: 6 // [6]
    447          }
    448        }),
    449        new asn1js.Primitive({
    450          name: (names.blockName || EMPTY_STRING),
    451          idBlock: {
    452            tagClass: 3, // CONTEXT-SPECIFIC
    453            tagNumber: 7 // [7]
    454          }
    455        }),
    456        new asn1js.Primitive({
    457          name: (names.blockName || EMPTY_STRING),
    458          idBlock: {
    459            tagClass: 3, // CONTEXT-SPECIFIC
    460            tagNumber: 8 // [8]
    461          }
    462        })
    463      ]
    464    }));
    465  }
    466 
    467  public fromSchema(schema: Schema.SchemaType): void {
    468    //#region Clear input data first
    469    pvutils.clearProps(schema, [
    470      "blockName",
    471      "otherName",
    472      "rfc822Name",
    473      "dNSName",
    474      "x400Address",
    475      "directoryName",
    476      "ediPartyName",
    477      "uniformResourceIdentifier",
    478      "iPAddress",
    479      "registeredID"
    480    ]);
    481    //#endregion
    482 
    483    //#region Check the schema is valid
    484    const asn1 = asn1js.compareSchema(schema,
    485      schema,
    486      GeneralName.schema({
    487        names: {
    488          blockName: "blockName",
    489          otherName: "otherName",
    490          rfc822Name: "rfc822Name",
    491          dNSName: "dNSName",
    492          x400Address: "x400Address",
    493          directoryName: {
    494            names: {
    495              blockName: "directoryName"
    496            }
    497          },
    498          ediPartyName: "ediPartyName",
    499          uniformResourceIdentifier: "uniformResourceIdentifier",
    500          iPAddress: "iPAddress",
    501          registeredID: "registeredID"
    502        }
    503      })
    504    );
    505 
    506    AsnError.assertSchema(asn1, this.className);
    507    //#endregion
    508 
    509    //#region Get internal properties from parsed schema
    510    this.type = asn1.result.blockName.idBlock.tagNumber;
    511 
    512    switch (this.type) {
    513      case 0: // otherName
    514        this.value = asn1.result.blockName;
    515        break;
    516      case 1: // rfc822Name + dNSName + uniformResourceIdentifier
    517      case 2:
    518      case 6:
    519        {
    520          const value = asn1.result.blockName;
    521 
    522          value.idBlock.tagClass = 1; // UNIVERSAL
    523          value.idBlock.tagNumber = 22; // IA5STRING
    524 
    525          const valueBER = value.toBER(false);
    526 
    527          const asnValue = asn1js.fromBER(valueBER);
    528          AsnError.assert(asnValue, "GeneralName value");
    529 
    530          this.value = (asnValue.result as asn1js.BaseStringBlock).valueBlock.value;
    531        }
    532        break;
    533      case 3: // x400Address
    534        this.value = asn1.result.blockName;
    535        break;
    536      case 4: // directoryName
    537        this.value = new RelativeDistinguishedNames({ schema: asn1.result.directoryName });
    538        break;
    539      case 5: // ediPartyName
    540        this.value = asn1.result.ediPartyName;
    541        break;
    542      case 7: // iPAddress
    543        this.value = new asn1js.OctetString({ valueHex: asn1.result.blockName.valueBlock.valueHex });
    544        break;
    545      case 8: // registeredID
    546        {
    547          const value = asn1.result.blockName;
    548 
    549          value.idBlock.tagClass = 1; // UNIVERSAL
    550          value.idBlock.tagNumber = 6; // ObjectIdentifier
    551 
    552          const valueBER = value.toBER(false);
    553 
    554          const asnValue = asn1js.fromBER(valueBER);
    555          AsnError.assert(asnValue, "GeneralName registeredID");
    556          this.value = asnValue.result.valueBlock.toString(); // Getting a string representation of the ObjectIdentifier
    557        }
    558        break;
    559      default:
    560    }
    561    //#endregion
    562  }
    563 
    564  public toSchema(): asn1js.Constructed | asn1js.IA5String | asn1js.ObjectIdentifier | asn1js.Choice {
    565    //#region Construct and return new ASN.1 schema for this object
    566    switch (this.type) {
    567      case 0:
    568      case 3:
    569      case 5:
    570        return new asn1js.Constructed({
    571          idBlock: {
    572            tagClass: 3, // CONTEXT-SPECIFIC
    573            tagNumber: this.type
    574          },
    575          value: [
    576            this.value
    577          ]
    578        });
    579      case 1:
    580      case 2:
    581      case 6:
    582        {
    583          const value = new asn1js.IA5String({ value: this.value });
    584 
    585          value.idBlock.tagClass = 3;
    586          value.idBlock.tagNumber = this.type;
    587 
    588          return value;
    589        }
    590      case 4:
    591        return new asn1js.Constructed({
    592          idBlock: {
    593            tagClass: 3, // CONTEXT-SPECIFIC
    594            tagNumber: 4
    595          },
    596          value: [this.value.toSchema()]
    597        });
    598      case 7:
    599        {
    600          const value = this.value;
    601 
    602          value.idBlock.tagClass = 3;
    603          value.idBlock.tagNumber = this.type;
    604 
    605          return value;
    606        }
    607      case 8:
    608        {
    609          const value = new asn1js.ObjectIdentifier({ value: this.value });
    610 
    611          value.idBlock.tagClass = 3;
    612          value.idBlock.tagNumber = this.type;
    613 
    614          return value;
    615        }
    616      default:
    617        return GeneralName.schema();
    618    }
    619    //#endregion
    620  }
    621 
    622  public toJSON(): GeneralNameJson {
    623    const _object = {
    624      type: this.type,
    625      value: EMPTY_STRING
    626    } as GeneralNameJson;
    627 
    628    if ((typeof this.value) === "string")
    629      _object.value = this.value;
    630    else {
    631      try {
    632        _object.value = this.value.toJSON();
    633      }
    634      catch {
    635        // nothing
    636      }
    637    }
    638 
    639    return _object;
    640  }
    641 
    642 }