diff options
Diffstat (limited to 'third_party/js/PKI.js/src/AttributeCertificateV2')
6 files changed, 1173 insertions, 0 deletions
diff --git a/third_party/js/PKI.js/src/AttributeCertificateV2/AttributeCertificateInfoV2.ts b/third_party/js/PKI.js/src/AttributeCertificateV2/AttributeCertificateInfoV2.ts new file mode 100644 index 0000000000..cb7bb12f7a --- /dev/null +++ b/third_party/js/PKI.js/src/AttributeCertificateV2/AttributeCertificateInfoV2.ts @@ -0,0 +1,341 @@ +import * as asn1js from "asn1js"; +import * as pvutils from "pvutils"; +import { GeneralNames, GeneralNamesJson } from "../GeneralNames"; +import { AlgorithmIdentifier, AlgorithmIdentifierJson, AlgorithmIdentifierSchema } from "../AlgorithmIdentifier"; +import { Attribute, AttributeJson } from "../Attribute"; +import { Extensions, ExtensionsJson, ExtensionsSchema } from "../Extensions"; +import { AttCertValidityPeriod, AttCertValidityPeriodJson, AttCertValidityPeriodSchema } from "../AttributeCertificateV1"; +import { V2Form, V2FormJson } from "./V2Form"; +import { Holder, HolderJson, HolderSchema } from "./Holder"; +import * as Schema from "../Schema"; +import { PkiObject, PkiObjectParameters } from "../PkiObject"; +import { AsnError } from "../errors"; +import { EMPTY_STRING } from "../constants"; + +const VERSION = "version"; +const HOLDER = "holder"; +const ISSUER = "issuer"; +const SIGNATURE = "signature"; +const SERIAL_NUMBER = "serialNumber"; +const ATTR_CERT_VALIDITY_PERIOD = "attrCertValidityPeriod"; +const ATTRIBUTES = "attributes"; +const ISSUER_UNIQUE_ID = "issuerUniqueID"; +const EXTENSIONS = "extensions"; +const CLEAR_PROPS = [ + VERSION, + HOLDER, + ISSUER, + SIGNATURE, + SERIAL_NUMBER, + ATTR_CERT_VALIDITY_PERIOD, + ATTRIBUTES, + ISSUER_UNIQUE_ID, + EXTENSIONS +]; + +export interface IAttributeCertificateInfoV2 { + version: number; + holder: Holder; + issuer: GeneralNames | V2Form; + signature: AlgorithmIdentifier; + serialNumber: asn1js.Integer; + attrCertValidityPeriod: AttCertValidityPeriod; + attributes: Attribute[]; + issuerUniqueID?: asn1js.BitString; + extensions?: Extensions; +} + +export type AttributeCertificateInfoV2Parameters = PkiObjectParameters & Partial<AttributeCertificateInfoV2>; + +export type AttributeCertificateInfoV2Schema = Schema.SchemaParameters<{ + version?: string; + holder?: HolderSchema; + issuer?: string; + signature?: AlgorithmIdentifierSchema; + serialNumber?: string; + attrCertValidityPeriod?: AttCertValidityPeriodSchema; + attributes?: string; + issuerUniqueID?: string; + extensions?: ExtensionsSchema; +}>; + +export interface AttributeCertificateInfoV2Json { + version: number; + holder: HolderJson; + issuer: GeneralNamesJson | V2FormJson; + signature: AlgorithmIdentifierJson; + serialNumber: asn1js.IntegerJson; + attrCertValidityPeriod: AttCertValidityPeriodJson; + attributes: AttributeJson[]; + issuerUniqueID?: asn1js.BitStringJson; + extensions?: ExtensionsJson; +} + +/** + * Represents the AttributeCertificateInfoV2 structure described in [RFC5755](https://datatracker.ietf.org/doc/html/rfc5755) + */ +export class AttributeCertificateInfoV2 extends PkiObject implements IAttributeCertificateInfoV2 { + + public static override CLASS_NAME = "AttributeCertificateInfoV2"; + + public version!: number; + public holder!: Holder; + public issuer!: GeneralNames | V2Form; + public signature!: AlgorithmIdentifier; + public serialNumber!: asn1js.Integer; + public attrCertValidityPeriod!: AttCertValidityPeriod; + public attributes!: Attribute[]; + public issuerUniqueID?: asn1js.BitString; + public extensions?: Extensions; + + /** + * Initializes a new instance of the {@link AttributeCertificateInfoV2} class + * @param parameters Initialization parameters + */ + constructor(parameters: AttributeCertificateInfoV2Parameters = {}) { + super(); + + this.version = pvutils.getParametersValue(parameters, VERSION, AttributeCertificateInfoV2.defaultValues(VERSION)); + this.holder = pvutils.getParametersValue(parameters, HOLDER, AttributeCertificateInfoV2.defaultValues(HOLDER)); + this.issuer = pvutils.getParametersValue(parameters, ISSUER, AttributeCertificateInfoV2.defaultValues(ISSUER)); + this.signature = pvutils.getParametersValue(parameters, SIGNATURE, AttributeCertificateInfoV2.defaultValues(SIGNATURE)); + this.serialNumber = pvutils.getParametersValue(parameters, SERIAL_NUMBER, AttributeCertificateInfoV2.defaultValues(SERIAL_NUMBER)); + this.attrCertValidityPeriod = pvutils.getParametersValue(parameters, ATTR_CERT_VALIDITY_PERIOD, AttributeCertificateInfoV2.defaultValues(ATTR_CERT_VALIDITY_PERIOD)); + this.attributes = pvutils.getParametersValue(parameters, ATTRIBUTES, AttributeCertificateInfoV2.defaultValues(ATTRIBUTES)); + if (ISSUER_UNIQUE_ID in parameters) { + this.issuerUniqueID = pvutils.getParametersValue(parameters, ISSUER_UNIQUE_ID, AttributeCertificateInfoV2.defaultValues(ISSUER_UNIQUE_ID)); + } + if (EXTENSIONS in parameters) { + this.extensions = pvutils.getParametersValue(parameters, EXTENSIONS, AttributeCertificateInfoV2.defaultValues(EXTENSIONS)); + } + + if (parameters.schema) { + this.fromSchema(parameters.schema); + } + } + + /** + * Returns default values for all class members + * @param memberName String name for a class member + * @returns Default value + */ + public static override defaultValues(memberName: typeof VERSION): number; + public static override defaultValues(memberName: typeof HOLDER): Holder; + public static override defaultValues(memberName: typeof ISSUER): GeneralNames | V2Form; + public static override defaultValues(memberName: typeof SIGNATURE): AlgorithmIdentifier; + public static override defaultValues(memberName: typeof SERIAL_NUMBER): asn1js.Integer; + public static override defaultValues(memberName: typeof ATTR_CERT_VALIDITY_PERIOD): AttCertValidityPeriod; + public static override defaultValues(memberName: typeof ATTRIBUTES): Attribute[]; + public static override defaultValues(memberName: typeof ISSUER_UNIQUE_ID): asn1js.BitString; + public static override defaultValues(memberName: typeof EXTENSIONS): Extensions; + public static override defaultValues(memberName: string): any { + switch (memberName) { + case VERSION: + return 1; + case HOLDER: + return new Holder(); + case ISSUER: + return {}; + case SIGNATURE: + return new AlgorithmIdentifier(); + case SERIAL_NUMBER: + return new asn1js.Integer(); + case ATTR_CERT_VALIDITY_PERIOD: + return new AttCertValidityPeriod(); + case ATTRIBUTES: + return []; + case ISSUER_UNIQUE_ID: + return new asn1js.BitString(); + case EXTENSIONS: + return new Extensions(); + default: + return super.defaultValues(memberName); + } + } + + /** + * @inheritdoc + * @asn ASN.1 schema + * ```asn + * AttributeCertificateInfoV2 ::= SEQUENCE { + * version AttCertVersion, -- version is v2 + * holder Holder, + * issuer AttCertIssuer, + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + *``` + */ + public static override schema(parameters: AttributeCertificateInfoV2Schema = {}): Schema.SchemaType { + const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || EMPTY_STRING), + value: [ + new asn1js.Integer({ name: (names.version || EMPTY_STRING) }), + Holder.schema(names.holder || {}), + new asn1js.Choice({ + value: [ + GeneralNames.schema({ + names: { + blockName: (names.issuer || EMPTY_STRING) + } + }), + new asn1js.Constructed({ + name: (names.issuer || EMPTY_STRING), + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: V2Form.schema().valueBlock.value + }) + ] + }), + AlgorithmIdentifier.schema(names.signature || {}), + new asn1js.Integer({ name: (names.serialNumber || EMPTY_STRING) }), + AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}), + new asn1js.Sequence({ + name: (names.attributes || EMPTY_STRING), + value: [ + new asn1js.Repeated({ + value: Attribute.schema() + }) + ] + }), + new asn1js.BitString({ + optional: true, + name: (names.issuerUniqueID || EMPTY_STRING) + }), + Extensions.schema(names.extensions || {}, true) + ] + })); + } + + public fromSchema(schema: Schema.SchemaType): void { + // Clear input data first + pvutils.clearProps(schema, CLEAR_PROPS); + + // Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttributeCertificateInfoV2.schema({ + names: { + version: VERSION, + holder: { + names: { + blockName: HOLDER + } + }, + issuer: ISSUER, + signature: { + names: { + blockName: SIGNATURE + } + }, + serialNumber: SERIAL_NUMBER, + attrCertValidityPeriod: { + names: { + blockName: ATTR_CERT_VALIDITY_PERIOD + } + }, + attributes: ATTRIBUTES, + issuerUniqueID: ISSUER_UNIQUE_ID, + extensions: { + names: { + blockName: EXTENSIONS + } + } + } + }) + ); + AsnError.assertSchema(asn1, this.className); + + //#region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.holder = new Holder({ schema: asn1.result.holder }); + + switch (asn1.result.issuer.idBlock.tagClass) { + case 3: // V2Form + this.issuer = new V2Form({ + schema: new asn1js.Sequence({ + value: asn1.result.issuer.valueBlock.value + }) + }); + break; + case 1: // GeneralNames (should not be used) + default: + throw new Error("Incorrect value for 'issuer' in AttributeCertificateInfoV2"); + } + + this.signature = new AlgorithmIdentifier({ schema: asn1.result.signature }); + this.serialNumber = asn1.result.serialNumber; + this.attrCertValidityPeriod = new AttCertValidityPeriod({ schema: asn1.result.attrCertValidityPeriod }); + this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new Attribute({ schema: element })); + + if (ISSUER_UNIQUE_ID in asn1.result) { + this.issuerUniqueID = asn1.result.issuerUniqueID; + } + + if (EXTENSIONS in asn1.result) { + this.extensions = new Extensions({ schema: asn1.result.extensions }); + } + //#endregion + } + + public toSchema(): asn1js.Sequence { + const result = new asn1js.Sequence({ + value: [ + new asn1js.Integer({ value: this.version }), + this.holder.toSchema(), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: this.issuer.toSchema().valueBlock.value + }), + this.signature.toSchema(), + this.serialNumber, + this.attrCertValidityPeriod.toSchema(), + new asn1js.Sequence({ + value: Array.from(this.attributes, o => o.toSchema()) + }) + ] + }); + + if (this.issuerUniqueID) { + result.valueBlock.value.push(this.issuerUniqueID); + } + if (this.extensions) { + result.valueBlock.value.push(this.extensions.toSchema()); + } + + return result; + } + + public toJSON(): AttributeCertificateInfoV2Json { + const result: AttributeCertificateInfoV2Json = { + version: this.version, + holder: this.holder.toJSON(), + issuer: this.issuer.toJSON(), + signature: this.signature.toJSON(), + serialNumber: this.serialNumber.toJSON(), + attrCertValidityPeriod: this.attrCertValidityPeriod.toJSON(), + attributes: Array.from(this.attributes, o => o.toJSON()) + }; + + if (this.issuerUniqueID) { + result.issuerUniqueID = this.issuerUniqueID.toJSON(); + } + if (this.extensions) { + result.extensions = this.extensions.toJSON(); + } + + return result; + } + +} diff --git a/third_party/js/PKI.js/src/AttributeCertificateV2/AttributeCertificateV2.ts b/third_party/js/PKI.js/src/AttributeCertificateV2/AttributeCertificateV2.ts new file mode 100644 index 0000000000..822ce03a34 --- /dev/null +++ b/third_party/js/PKI.js/src/AttributeCertificateV2/AttributeCertificateV2.ts @@ -0,0 +1,169 @@ +import * as asn1js from "asn1js"; +import * as pvutils from "pvutils"; +import { AlgorithmIdentifier, AlgorithmIdentifierJson, AlgorithmIdentifierSchema } from "../AlgorithmIdentifier"; +import { AttributeCertificateInfoV2, AttributeCertificateInfoV2Json, AttributeCertificateInfoV2Schema } from "./AttributeCertificateInfoV2"; +import * as Schema from "../Schema"; +import { PkiObject, PkiObjectParameters } from "../PkiObject"; +import { AsnError } from "../errors"; +import { EMPTY_STRING } from "../constants"; + +const ACINFO = "acinfo"; +const SIGNATURE_ALGORITHM = "signatureAlgorithm"; +const SIGNATURE_VALUE = "signatureValue"; +const CLEAR_PROPS = [ + ACINFO, + SIGNATURE_ALGORITHM, + SIGNATURE_VALUE, +]; + +export interface IAttributeCertificateV2 { + /** + * Attribute certificate information + */ + acinfo: AttributeCertificateInfoV2; + /** + * Signature algorithm + */ + signatureAlgorithm: AlgorithmIdentifier; + /** + * Signature value + */ + signatureValue: asn1js.BitString; +} + +export type AttributeCertificateV2Parameters = PkiObjectParameters & Partial<IAttributeCertificateV2>; + +export interface AttributeCertificateV2Json { + acinfo: AttributeCertificateInfoV2Json; + signatureAlgorithm: AlgorithmIdentifierJson; + signatureValue: asn1js.BitStringJson; +} + +/** + * Represents the AttributeCertificateV2 structure described in [RFC5755](https://datatracker.ietf.org/doc/html/rfc5755) + */ +export class AttributeCertificateV2 extends PkiObject implements IAttributeCertificateV2 { + + public static override CLASS_NAME = "AttributeCertificateV2"; + + public acinfo!: AttributeCertificateInfoV2; + public signatureAlgorithm!: AlgorithmIdentifier; + public signatureValue!: asn1js.BitString; + + /** + * Initializes a new instance of the {@link AttributeCertificateV2} class + * @param parameters Initialization parameters + */ + constructor(parameters: AttributeCertificateV2Parameters = {}) { + super(); + + this.acinfo = pvutils.getParametersValue(parameters, ACINFO, AttributeCertificateV2.defaultValues(ACINFO)); + this.signatureAlgorithm = pvutils.getParametersValue(parameters, SIGNATURE_ALGORITHM, AttributeCertificateV2.defaultValues(SIGNATURE_ALGORITHM)); + this.signatureValue = pvutils.getParametersValue(parameters, SIGNATURE_VALUE, AttributeCertificateV2.defaultValues(SIGNATURE_VALUE)); + + if (parameters.schema) { + this.fromSchema(parameters.schema); + } + } + + /** + * Returns default values for all class members + * @param memberName String name for a class member + * @returns Default value + */ + public static override defaultValues(memberName: typeof ACINFO): AttributeCertificateInfoV2; + public static override defaultValues(memberName: typeof SIGNATURE_ALGORITHM): AlgorithmIdentifier; + public static override defaultValues(memberName: typeof SIGNATURE_VALUE): asn1js.BitString; + public static override defaultValues(memberName: string): any { + switch (memberName) { + case ACINFO: + return new AttributeCertificateInfoV2(); + case SIGNATURE_ALGORITHM: + return new AlgorithmIdentifier(); + case SIGNATURE_VALUE: + return new asn1js.BitString(); + default: + return super.defaultValues(memberName); + } + } + + /** + * @inheritdoc + * @asn ASN.1 schema + * ```asn + * AttributeCertificate ::= SEQUENCE { + * acinfo AttributeCertificateInfoV2, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + *``` + */ + public static override schema(parameters: Schema.SchemaParameters<{ + acinfo?: AttributeCertificateInfoV2Schema; + signatureAlgorithm?: AlgorithmIdentifierSchema; + signatureValue?: string; + }> = {}): Schema.SchemaType { + const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || EMPTY_STRING), + value: [ + AttributeCertificateInfoV2.schema(names.acinfo || {}), + AlgorithmIdentifier.schema(names.signatureAlgorithm || {}), + new asn1js.BitString({ name: (names.signatureValue || EMPTY_STRING) }) + ] + })); + } + + public fromSchema(schema: Schema.SchemaType): void { + // Clear input data first + pvutils.clearProps(schema, CLEAR_PROPS); + + //#region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttributeCertificateV2.schema({ + names: { + acinfo: { + names: { + blockName: ACINFO + } + }, + signatureAlgorithm: { + names: { + blockName: SIGNATURE_ALGORITHM + } + }, + signatureValue: SIGNATURE_VALUE + } + }) + ); + AsnError.assertSchema(asn1, this.className); + //#endregion + + // Get internal properties from parsed schema + this.acinfo = new AttributeCertificateInfoV2({ schema: asn1.result.acinfo }); + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm }); + this.signatureValue = asn1.result.signatureValue; + } + + public toSchema(): asn1js.Sequence { + return (new asn1js.Sequence({ + value: [ + this.acinfo.toSchema(), + this.signatureAlgorithm.toSchema(), + this.signatureValue + ] + })); + } + + public toJSON(): AttributeCertificateV2Json { + return { + acinfo: this.acinfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON(), + }; + } + +} + diff --git a/third_party/js/PKI.js/src/AttributeCertificateV2/Holder.ts b/third_party/js/PKI.js/src/AttributeCertificateV2/Holder.ts new file mode 100644 index 0000000000..dc2bffd7f8 --- /dev/null +++ b/third_party/js/PKI.js/src/AttributeCertificateV2/Holder.ts @@ -0,0 +1,242 @@ +import * as asn1js from "asn1js"; +import * as pvutils from "pvutils"; +import { GeneralNames, GeneralNamesJson } from "../GeneralNames"; +import { IssuerSerial, IssuerSerialJson } from "../AttributeCertificateV1"; +import { ObjectDigestInfo, ObjectDigestInfoJson } from "./ObjectDigestInfo"; +import * as Schema from "../Schema"; +import { PkiObject, PkiObjectParameters } from "../PkiObject"; +import { AsnError } from "../errors"; +import { EMPTY_STRING } from "../constants"; + +const BASE_CERTIFICATE_ID = "baseCertificateID"; +const ENTITY_NAME = "entityName"; +const OBJECT_DIGEST_INFO = "objectDigestInfo"; +const CLEAR_PROPS = [ + BASE_CERTIFICATE_ID, + ENTITY_NAME, + OBJECT_DIGEST_INFO +]; + +export interface IHolder { + baseCertificateID?: IssuerSerial; + entityName?: GeneralNames; + objectDigestInfo?: ObjectDigestInfo; +} + +export type HolderParameters = PkiObjectParameters & Partial<IHolder>; + +export type HolderSchema = Schema.SchemaParameters<{ + baseCertificateID?: string; + entityName?: string; + objectDigestInfo?: string; +}>; + +export interface HolderJson { + baseCertificateID?: IssuerSerialJson; + entityName?: GeneralNamesJson; + objectDigestInfo?: ObjectDigestInfoJson; +} + +/** + * Represents the Holder structure described in [RFC5755](https://datatracker.ietf.org/doc/html/rfc5755) + */ +export class Holder extends PkiObject implements IHolder { + + public static override CLASS_NAME = "Holder"; + + public baseCertificateID?: IssuerSerial; + public entityName?: GeneralNames; + public objectDigestInfo?: ObjectDigestInfo; + + /** + * Initializes a new instance of the {@link AttributeCertificateInfoV1} class + * @param parameters Initialization parameters + */ + constructor(parameters: HolderParameters = {}) { + super(); + + if (BASE_CERTIFICATE_ID in parameters) { + this.baseCertificateID = pvutils.getParametersValue(parameters, BASE_CERTIFICATE_ID, Holder.defaultValues(BASE_CERTIFICATE_ID)); + } + if (ENTITY_NAME in parameters) { + this.entityName = pvutils.getParametersValue(parameters, ENTITY_NAME, Holder.defaultValues(ENTITY_NAME)); + } + if (OBJECT_DIGEST_INFO in parameters) { + this.objectDigestInfo = pvutils.getParametersValue(parameters, OBJECT_DIGEST_INFO, Holder.defaultValues(OBJECT_DIGEST_INFO)); + } + + if (parameters.schema) { + this.fromSchema(parameters.schema); + } + } + + /** + * Returns default values for all class members + * @param memberName String name for a class member + * @returns Default value + */ + public static override defaultValues(memberName: typeof BASE_CERTIFICATE_ID): IssuerSerial; + public static override defaultValues(memberName: typeof ENTITY_NAME): GeneralNames; + public static override defaultValues(memberName: typeof OBJECT_DIGEST_INFO): ObjectDigestInfo; + public static override defaultValues(memberName: string): any { + switch (memberName) { + case BASE_CERTIFICATE_ID: + return new IssuerSerial(); + case ENTITY_NAME: + return new GeneralNames(); + case OBJECT_DIGEST_INFO: + return new ObjectDigestInfo(); + default: + return super.defaultValues(memberName); + } + } + + /** + * @inheritdoc + * @asn ASN.1 schema + * ```asn + * Holder ::= SEQUENCE { + * baseCertificateID [0] IssuerSerial OPTIONAL, + * -- the issuer and serial number of + * -- the holder's Public Key Certificate + * entityName [1] GeneralNames OPTIONAL, + * -- the name of the claimant or role + * objectDigestInfo [2] ObjectDigestInfo OPTIONAL + * -- used to directly authenticate the holder, + * -- for example, an executable + * } + *``` + */ + public static override schema(parameters: HolderSchema = {}): Schema.SchemaType { + const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || EMPTY_STRING), + value: [ + new asn1js.Constructed({ + optional: true, + name: (names.baseCertificateID || EMPTY_STRING), + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: IssuerSerial.schema().valueBlock.value + }), + new asn1js.Constructed({ + optional: true, + name: (names.entityName || EMPTY_STRING), + idBlock: { + tagClass: 3, + tagNumber: 1 // [2] + }, + value: GeneralNames.schema().valueBlock.value + }), + new asn1js.Constructed({ + optional: true, + name: (names.objectDigestInfo || EMPTY_STRING), + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + }, + value: ObjectDigestInfo.schema().valueBlock.value + }) + ] + })); + } + + public fromSchema(schema: Schema.SchemaType): void { + // Clear input data first + pvutils.clearProps(schema, CLEAR_PROPS); + + // Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Holder.schema({ + names: { + baseCertificateID: BASE_CERTIFICATE_ID, + entityName: ENTITY_NAME, + objectDigestInfo: OBJECT_DIGEST_INFO + } + }) + ); + AsnError.assertSchema(asn1, this.className); + + // Get internal properties from parsed schema + if (BASE_CERTIFICATE_ID in asn1.result) { + this.baseCertificateID = new IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + if (ENTITY_NAME in asn1.result) { + this.entityName = new GeneralNames({ + schema: new asn1js.Sequence({ + value: asn1.result.entityName.valueBlock.value + }) + }); + } + if (OBJECT_DIGEST_INFO in asn1.result) { + this.objectDigestInfo = new ObjectDigestInfo({ + schema: new asn1js.Sequence({ + value: asn1.result.objectDigestInfo.valueBlock.value + }) + }); + } + } + + public toSchema(): asn1js.Sequence { + const result = new asn1js.Sequence(); + + if (this.baseCertificateID) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if (this.entityName) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: this.entityName.toSchema().valueBlock.value + })); + } + + if (this.objectDigestInfo) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + }, + value: this.objectDigestInfo.toSchema().valueBlock.value + })); + } + + return result; + } + + public toJSON(): HolderJson { + const result: HolderJson = {}; + + if (this.baseCertificateID) { + result.baseCertificateID = this.baseCertificateID.toJSON(); + } + + if (this.entityName) { + result.entityName = this.entityName.toJSON(); + } + + if (this.objectDigestInfo) { + result.objectDigestInfo = this.objectDigestInfo.toJSON(); + } + + return result; + } + +} diff --git a/third_party/js/PKI.js/src/AttributeCertificateV2/ObjectDigestInfo.ts b/third_party/js/PKI.js/src/AttributeCertificateV2/ObjectDigestInfo.ts new file mode 100644 index 0000000000..32ab2ff7eb --- /dev/null +++ b/third_party/js/PKI.js/src/AttributeCertificateV2/ObjectDigestInfo.ts @@ -0,0 +1,193 @@ +import * as asn1js from "asn1js"; +import * as pvutils from "pvutils"; +import { AlgorithmIdentifier, AlgorithmIdentifierJson, AlgorithmIdentifierSchema } from "../AlgorithmIdentifier"; +import { EMPTY_STRING } from "../constants"; +import { AsnError } from "../errors"; +import { PkiObject, PkiObjectParameters } from "../PkiObject"; +import * as Schema from "../Schema"; + +const DIGESTED_OBJECT_TYPE = "digestedObjectType"; +const OTHER_OBJECT_TYPE_ID = "otherObjectTypeID"; +const DIGEST_ALGORITHM = "digestAlgorithm"; +const OBJECT_DIGEST = "objectDigest"; +const CLEAR_PROPS = [ + DIGESTED_OBJECT_TYPE, + OTHER_OBJECT_TYPE_ID, + DIGEST_ALGORITHM, + OBJECT_DIGEST, +]; + +export interface IObjectDigestInfo { + digestedObjectType: asn1js.Enumerated; + otherObjectTypeID?: asn1js.ObjectIdentifier; + digestAlgorithm: AlgorithmIdentifier; + objectDigest: asn1js.BitString; +} + +export type ObjectDigestInfoParameters = PkiObjectParameters & Partial<IObjectDigestInfo>; + +export interface ObjectDigestInfoJson { + digestedObjectType: asn1js.EnumeratedJson; + otherObjectTypeID?: asn1js.ObjectIdentifierJson; + digestAlgorithm: AlgorithmIdentifierJson; + objectDigest: asn1js.BitStringJson; +} + +/** + * Represents the ObjectDigestInfo structure described in [RFC5755](https://datatracker.ietf.org/doc/html/rfc5755) + */ +export class ObjectDigestInfo extends PkiObject implements IObjectDigestInfo { + + public static override CLASS_NAME = "ObjectDigestInfo"; + + public digestedObjectType!: asn1js.Enumerated; + public otherObjectTypeID?: asn1js.ObjectIdentifier; + public digestAlgorithm!: AlgorithmIdentifier; + public objectDigest!: asn1js.BitString; + + /** + * Initializes a new instance of the {@link ObjectDigestInfo} class + * @param parameters Initialization parameters + */ + constructor(parameters: ObjectDigestInfoParameters = {}) { + super(); + + this.digestedObjectType = pvutils.getParametersValue(parameters, DIGESTED_OBJECT_TYPE, ObjectDigestInfo.defaultValues(DIGESTED_OBJECT_TYPE)); + if (OTHER_OBJECT_TYPE_ID in parameters) { + this.otherObjectTypeID = pvutils.getParametersValue(parameters, OTHER_OBJECT_TYPE_ID, ObjectDigestInfo.defaultValues(OTHER_OBJECT_TYPE_ID)); + } + this.digestAlgorithm = pvutils.getParametersValue(parameters, DIGEST_ALGORITHM, ObjectDigestInfo.defaultValues(DIGEST_ALGORITHM)); + this.objectDigest = pvutils.getParametersValue(parameters, OBJECT_DIGEST, ObjectDigestInfo.defaultValues(OBJECT_DIGEST)); + + if (parameters.schema) { + this.fromSchema(parameters.schema); + } + } + + /** + * Returns default values for all class members + * @param memberName String name for a class member + * @returns Default value + */ + public static override defaultValues(memberName: typeof DIGESTED_OBJECT_TYPE): asn1js.Enumerated; + public static override defaultValues(memberName: typeof OTHER_OBJECT_TYPE_ID): asn1js.ObjectIdentifier; + public static override defaultValues(memberName: typeof DIGEST_ALGORITHM): AlgorithmIdentifier; + public static override defaultValues(memberName: typeof OBJECT_DIGEST): asn1js.BitString; + public static override defaultValues(memberName: string): any { + switch (memberName) { + case DIGESTED_OBJECT_TYPE: + return new asn1js.Enumerated(); + case OTHER_OBJECT_TYPE_ID: + return new asn1js.ObjectIdentifier(); + case DIGEST_ALGORITHM: + return new AlgorithmIdentifier(); + case OBJECT_DIGEST: + return new asn1js.BitString(); + default: + return super.defaultValues(memberName); + } + } + + /** + * @inheritdoc + * @asn ASN.1 schema + * ```asn + * ObjectDigestInfo ::= SEQUENCE { + * digestedObjectType ENUMERATED { + * publicKey (0), + * publicKeyCert (1), + * otherObjectTypes (2) }, + * -- otherObjectTypes MUST NOT + * -- be used in this profile + * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + * digestAlgorithm AlgorithmIdentifier, + * objectDigest BIT STRING + * } + *``` + */ + public static override schema(parameters: Schema.SchemaParameters<{ + digestedObjectType?: string; + otherObjectTypeID?: string; + digestAlgorithm?: AlgorithmIdentifierSchema; + objectDigest?: string; + }> = {}): Schema.SchemaType { + const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || EMPTY_STRING), + value: [ + new asn1js.Enumerated({ name: (names.digestedObjectType || EMPTY_STRING) }), + new asn1js.ObjectIdentifier({ + optional: true, + name: (names.otherObjectTypeID || EMPTY_STRING) + }), + AlgorithmIdentifier.schema(names.digestAlgorithm || {}), + new asn1js.BitString({ name: (names.objectDigest || EMPTY_STRING) }), + ] + })); + } + + public fromSchema(schema: Schema.SchemaType): void { + // Clear input data first + pvutils.clearProps(schema, CLEAR_PROPS); + + // Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ObjectDigestInfo.schema({ + names: { + digestedObjectType: DIGESTED_OBJECT_TYPE, + otherObjectTypeID: OTHER_OBJECT_TYPE_ID, + digestAlgorithm: { + names: { + blockName: DIGEST_ALGORITHM + } + }, + objectDigest: OBJECT_DIGEST + } + }) + ); + AsnError.assertSchema(asn1, this.className); + + //#region Get internal properties from parsed schema + this.digestedObjectType = asn1.result.digestedObjectType; + + if (OTHER_OBJECT_TYPE_ID in asn1.result) { + this.otherObjectTypeID = asn1.result.otherObjectTypeID; + } + + this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.digestAlgorithm }); + this.objectDigest = asn1.result.objectDigest; + //#endregion + } + + public toSchema(): asn1js.Sequence { + const result = new asn1js.Sequence({ + value: [this.digestedObjectType] + }); + + if (this.otherObjectTypeID) { + result.valueBlock.value.push(this.otherObjectTypeID); + } + + result.valueBlock.value.push(this.digestAlgorithm.toSchema()); + result.valueBlock.value.push(this.objectDigest); + + return result; + } + + public toJSON(): ObjectDigestInfoJson { + const result: ObjectDigestInfoJson = { + digestedObjectType: this.digestedObjectType.toJSON(), + digestAlgorithm: this.digestAlgorithm.toJSON(), + objectDigest: this.objectDigest.toJSON(), + }; + + if (this.otherObjectTypeID) { + result.otherObjectTypeID = this.otherObjectTypeID.toJSON(); + } + + return result; + } + +} diff --git a/third_party/js/PKI.js/src/AttributeCertificateV2/V2Form.ts b/third_party/js/PKI.js/src/AttributeCertificateV2/V2Form.ts new file mode 100644 index 0000000000..dd8b69d51b --- /dev/null +++ b/third_party/js/PKI.js/src/AttributeCertificateV2/V2Form.ts @@ -0,0 +1,223 @@ +import * as asn1js from "asn1js"; +import * as pvutils from "pvutils"; +import { GeneralNames, GeneralNamesJson } from "../GeneralNames"; +import { IssuerSerial, IssuerSerialJson } from "../AttributeCertificateV1"; +import { ObjectDigestInfo, ObjectDigestInfoJson } from "./ObjectDigestInfo"; +import * as Schema from "../Schema"; +import { PkiObject, PkiObjectParameters } from "../PkiObject"; +import { AsnError } from "../errors"; +import { EMPTY_STRING } from "../constants"; + +const ISSUER_NAME = "issuerName"; +const BASE_CERTIFICATE_ID = "baseCertificateID"; +const OBJECT_DIGEST_INFO = "objectDigestInfo"; +const CLEAR_PROPS = [ + ISSUER_NAME, + BASE_CERTIFICATE_ID, + OBJECT_DIGEST_INFO +]; + +export interface IV2Form { + issuerName?: GeneralNames; + baseCertificateID?: IssuerSerial; + objectDigestInfo?: ObjectDigestInfo; +} + +export type V2FormParameters = PkiObjectParameters & Partial<IV2Form>; + +export interface V2FormJson { + issuerName?: GeneralNamesJson; + baseCertificateID?: IssuerSerialJson; + objectDigestInfo?: ObjectDigestInfoJson; +} + +/** + * Represents the V2Form structure described in [RFC5755](https://datatracker.ietf.org/doc/html/rfc5755) + */ +export class V2Form extends PkiObject implements IV2Form { + + public static override CLASS_NAME = "V2Form"; + + public issuerName?: GeneralNames; + public baseCertificateID?: IssuerSerial; + public objectDigestInfo?: ObjectDigestInfo; + + /** + * Initializes a new instance of the {@link V2Form} class + * @param parameters Initialization parameters + */ + constructor(parameters: V2FormParameters = {}) { + super(); + + if (ISSUER_NAME in parameters) { + this.issuerName = pvutils.getParametersValue(parameters, ISSUER_NAME, V2Form.defaultValues(ISSUER_NAME)); + } + if (BASE_CERTIFICATE_ID in parameters) { + this.baseCertificateID = pvutils.getParametersValue(parameters, BASE_CERTIFICATE_ID, V2Form.defaultValues(BASE_CERTIFICATE_ID)); + } + if (OBJECT_DIGEST_INFO in parameters) { + this.objectDigestInfo = pvutils.getParametersValue(parameters, OBJECT_DIGEST_INFO, V2Form.defaultValues(OBJECT_DIGEST_INFO)); + } + + if (parameters.schema) { + this.fromSchema(parameters.schema); + } + } + + /** + * Returns default values for all class members + * @param memberName String name for a class member + * @returns Default value + */ + public static override defaultValues(memberName: typeof ISSUER_NAME): GeneralNames; + public static override defaultValues(memberName: typeof BASE_CERTIFICATE_ID): IssuerSerial; + public static override defaultValues(memberName: typeof OBJECT_DIGEST_INFO): ObjectDigestInfo; + public static override defaultValues(memberName: string): any { + switch (memberName) { + case ISSUER_NAME: + return new GeneralNames(); + case BASE_CERTIFICATE_ID: + return new IssuerSerial(); + case OBJECT_DIGEST_INFO: + return new ObjectDigestInfo(); + default: + return super.defaultValues(memberName); + } + } + + /** + * @inheritdoc + * @asn ASN.1 schema + * ```asn + * V2Form ::= SEQUENCE { + * issuerName GeneralNames OPTIONAL, + * baseCertificateID [0] IssuerSerial OPTIONAL, + * objectDigestInfo [1] ObjectDigestInfo OPTIONAL + * -- issuerName MUST be present in this profile + * -- baseCertificateID and objectDigestInfo MUST NOT + * -- be present in this profile + * } + *``` + */ + public static override schema(parameters: Schema.SchemaParameters<{ + issuerName?: string; + baseCertificateID?: string; + objectDigestInfo?: string; + }> = {}): Schema.SchemaType { + const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || EMPTY_STRING), + value: [ + GeneralNames.schema({ + names: { + blockName: names.issuerName + } + }, true), + new asn1js.Constructed({ + optional: true, + name: (names.baseCertificateID || EMPTY_STRING), + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: IssuerSerial.schema().valueBlock.value + }), + new asn1js.Constructed({ + optional: true, + name: (names.objectDigestInfo || EMPTY_STRING), + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: ObjectDigestInfo.schema().valueBlock.value + }) + ] + })); + } + + public fromSchema(schema: Schema.SchemaType): void { + // Clear input data first + pvutils.clearProps(schema, CLEAR_PROPS); + + // Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + V2Form.schema({ + names: { + issuerName: ISSUER_NAME, + baseCertificateID: BASE_CERTIFICATE_ID, + objectDigestInfo: OBJECT_DIGEST_INFO + } + }) + ); + AsnError.assertSchema(asn1, this.className); + + //#region Get internal properties from parsed schema + if (ISSUER_NAME in asn1.result) + this.issuerName = new GeneralNames({ schema: asn1.result.issuerName }); + + if (BASE_CERTIFICATE_ID in asn1.result) { + this.baseCertificateID = new IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + + if (OBJECT_DIGEST_INFO in asn1.result) { + this.objectDigestInfo = new ObjectDigestInfo({ + schema: new asn1js.Sequence({ + value: asn1.result.objectDigestInfo.valueBlock.value + }) + }); + } + //#endregion + } + + public toSchema(): asn1js.Sequence { + const result = new asn1js.Sequence(); + + if (this.issuerName) + result.valueBlock.value.push(this.issuerName.toSchema()); + + if (this.baseCertificateID) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if (this.objectDigestInfo) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: this.objectDigestInfo.toSchema().valueBlock.value + })); + } + + return result; + } + + public toJSON(): V2FormJson { + const result: V2FormJson = {}; + + if (this.issuerName) { + result.issuerName = this.issuerName.toJSON(); + } + if (this.baseCertificateID) { + result.baseCertificateID = this.baseCertificateID.toJSON(); + } + if (this.objectDigestInfo) { + result.objectDigestInfo = this.objectDigestInfo.toJSON(); + } + + return result; + } + +} diff --git a/third_party/js/PKI.js/src/AttributeCertificateV2/index.ts b/third_party/js/PKI.js/src/AttributeCertificateV2/index.ts new file mode 100644 index 0000000000..53ca2f7ba7 --- /dev/null +++ b/third_party/js/PKI.js/src/AttributeCertificateV2/index.ts @@ -0,0 +1,5 @@ +export * from "./AttributeCertificateInfoV2"; +export * from "./Holder"; +export * from "./ObjectDigestInfo"; +export * from "./V2Form"; +export * from "./AttributeCertificateV2";
\ No newline at end of file |