CertBag.ts (6561B)
1 import * as asn1js from "asn1js"; 2 import * as pvutils from "pvutils"; 3 import { Certificate } from "./Certificate"; 4 import { AttributeCertificateV2 } from "./AttributeCertificateV2"; 5 import * as Schema from "./Schema"; 6 import { id_CertBag_AttributeCertificate, id_CertBag_SDSICertificate, id_CertBag_X509Certificate } from "./ObjectIdentifiers"; 7 import { AsnError } from "./errors"; 8 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 9 import { EMPTY_STRING } from "./constants"; 10 11 const CERT_ID = "certId"; 12 const CERT_VALUE = "certValue"; 13 const PARSED_VALUE = "parsedValue"; 14 const CLEAR_PROPS = [ 15 CERT_ID, 16 CERT_VALUE 17 ]; 18 19 export interface ICertBag { 20 certId: string; 21 certValue: asn1js.OctetString | PkiObject; 22 parsedValue: any; 23 } 24 25 export type CertBagParameters = PkiObjectParameters & Partial<ICertBag>; 26 27 export interface CertBagJson { 28 certId: string; 29 certValue: any; 30 } 31 32 /** 33 * Represents the CertBag structure described in [RFC7292](https://datatracker.ietf.org/doc/html/rfc7292) 34 */ 35 export class CertBag extends PkiObject implements ICertBag { 36 37 public static override CLASS_NAME = "CertBag"; 38 39 public certId!: string; 40 public certValue: PkiObject | asn1js.OctetString; 41 public parsedValue: any; 42 43 /** 44 * Initializes a new instance of the {@link CertBag} class 45 * @param parameters Initialization parameters 46 */ 47 constructor(parameters: CertBagParameters = {}) { 48 super(); 49 50 this.certId = pvutils.getParametersValue(parameters, CERT_ID, CertBag.defaultValues(CERT_ID)); 51 this.certValue = pvutils.getParametersValue(parameters, CERT_VALUE, CertBag.defaultValues(CERT_VALUE)); 52 if (PARSED_VALUE in parameters) { 53 this.parsedValue = pvutils.getParametersValue(parameters, PARSED_VALUE, CertBag.defaultValues(PARSED_VALUE)); 54 } 55 56 if (parameters.schema) { 57 this.fromSchema(parameters.schema); 58 } 59 } 60 61 /** 62 * Returns default values for all class members 63 * @param memberName String name for a class member 64 * @returns Default value 65 */ 66 public static override defaultValues(memberName: typeof CERT_ID): string; 67 public static override defaultValues(memberName: typeof CERT_VALUE): any; 68 public static override defaultValues(memberName: typeof PARSED_VALUE): any; 69 public static override defaultValues(memberName: string): any { 70 switch (memberName) { 71 case CERT_ID: 72 return EMPTY_STRING; 73 case CERT_VALUE: 74 return (new asn1js.Any()); 75 case PARSED_VALUE: 76 return {}; 77 default: 78 return super.defaultValues(memberName); 79 } 80 } 81 82 /** 83 * Compare values with default values for all class members 84 * @param memberName String name for a class member 85 * @param memberValue Value to compare with default value 86 */ 87 public static compareWithDefault(memberName: string, memberValue: any): boolean { 88 switch (memberName) { 89 case CERT_ID: 90 return (memberValue === EMPTY_STRING); 91 case CERT_VALUE: 92 return (memberValue instanceof asn1js.Any); 93 case PARSED_VALUE: 94 return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0)); 95 default: 96 return super.defaultValues(memberName); 97 } 98 } 99 100 /** 101 * @inheritdoc 102 * @asn ASN.1 schema 103 * ```asn 104 * CertBag ::= SEQUENCE { 105 * certId BAG-TYPE.&id ({CertTypes}), 106 * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId}) 107 * } 108 *``` 109 */ 110 public static override schema(parameters: Schema.SchemaParameters<{ 111 id?: string; 112 value?: string; 113 }> = {}): Schema.SchemaType { 114 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 115 116 return (new asn1js.Sequence({ 117 name: (names.blockName || EMPTY_STRING), 118 value: [ 119 new asn1js.ObjectIdentifier({ name: (names.id || "id") }), 120 new asn1js.Constructed({ 121 idBlock: { 122 tagClass: 3, // CONTEXT-SPECIFIC 123 tagNumber: 0 // [0] 124 }, 125 value: [new asn1js.Any({ name: (names.value || "value") })] // EXPLICIT ANY value 126 }) 127 ] 128 })); 129 } 130 131 public fromSchema(schema: Schema.SchemaType): void { 132 // Clear input data first 133 pvutils.clearProps(schema, CLEAR_PROPS); 134 135 // Check the schema is valid 136 const asn1 = asn1js.compareSchema(schema, 137 schema, 138 CertBag.schema({ 139 names: { 140 id: CERT_ID, 141 value: CERT_VALUE 142 } 143 }) 144 ); 145 AsnError.assertSchema(asn1, this.className); 146 147 //#region Get internal properties from parsed schema 148 this.certId = asn1.result.certId.valueBlock.toString(); 149 this.certValue = asn1.result.certValue as asn1js.OctetString; 150 151 const certValueHex = this.certValue.valueBlock.valueHexView; 152 switch (this.certId) { 153 case id_CertBag_X509Certificate: // x509Certificate 154 { 155 try { 156 this.parsedValue = Certificate.fromBER(certValueHex as BufferSource); 157 } 158 catch // In some realizations the same OID used for attribute certificates 159 { 160 AttributeCertificateV2.fromBER(certValueHex as BufferSource); 161 } 162 } 163 break; 164 case id_CertBag_AttributeCertificate: // attributeCertificate - (!!!) THIS OID IS SUBJECT FOR CHANGE IN FUTURE (!!!) 165 { 166 this.parsedValue = AttributeCertificateV2.fromBER(certValueHex as BufferSource); 167 } 168 break; 169 case id_CertBag_SDSICertificate: // sdsiCertificate 170 default: 171 throw new Error(`Incorrect CERT_ID value in CertBag: ${this.certId}`); 172 } 173 //#endregion 174 } 175 176 public toSchema(): asn1js.Sequence { 177 //#region Construct and return new ASN.1 schema for this object 178 if (PARSED_VALUE in this) { 179 if ("acinfo" in this.parsedValue) {// attributeCertificate 180 this.certId = id_CertBag_AttributeCertificate; 181 } else {// x509Certificate 182 this.certId = id_CertBag_X509Certificate; 183 } 184 185 this.certValue = new asn1js.OctetString({ valueHex: this.parsedValue.toSchema().toBER(false) }); 186 } 187 188 return (new asn1js.Sequence({ 189 value: [ 190 new asn1js.ObjectIdentifier({ value: this.certId }), 191 new asn1js.Constructed({ 192 idBlock: { 193 tagClass: 3, // CONTEXT-SPECIFIC 194 tagNumber: 0 // [0] 195 }, 196 value: [(("toSchema" in this.certValue) ? this.certValue.toSchema() : this.certValue)] 197 }) 198 ] 199 })); 200 //#endregion 201 } 202 203 public toJSON(): CertBagJson { 204 return { 205 certId: this.certId, 206 certValue: this.certValue.toJSON() 207 }; 208 } 209 210 }