IssuingDistributionPoint.ts (15117B)
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 { GeneralName, GeneralNameJson } from "./GeneralName"; 6 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 7 import { RelativeDistinguishedNames, RelativeDistinguishedNamesJson } from "./RelativeDistinguishedNames"; 8 import * as Schema from "./Schema"; 9 10 const DISTRIBUTION_POINT = "distributionPoint"; 11 const DISTRIBUTION_POINT_NAMES = "distributionPointNames"; 12 const ONLY_CONTAINS_USER_CERTS = "onlyContainsUserCerts"; 13 const ONLY_CONTAINS_CA_CERTS = "onlyContainsCACerts"; 14 const ONLY_SOME_REASON = "onlySomeReasons"; 15 const INDIRECT_CRL = "indirectCRL"; 16 const ONLY_CONTAINS_ATTRIBUTE_CERTS = "onlyContainsAttributeCerts"; 17 const CLEAR_PROPS = [ 18 DISTRIBUTION_POINT, 19 DISTRIBUTION_POINT_NAMES, 20 ONLY_CONTAINS_USER_CERTS, 21 ONLY_CONTAINS_CA_CERTS, 22 ONLY_SOME_REASON, 23 INDIRECT_CRL, 24 ONLY_CONTAINS_ATTRIBUTE_CERTS, 25 ]; 26 27 export interface IIssuingDistributionPoint { 28 distributionPoint?: DistributionPointName; 29 onlyContainsUserCerts: boolean; 30 onlyContainsCACerts: boolean; 31 onlySomeReasons?: number; 32 indirectCRL: boolean; 33 onlyContainsAttributeCerts: boolean; 34 } 35 36 export interface IssuingDistributionPointJson { 37 distributionPoint?: DistributionPointNameJson; 38 onlyContainsUserCerts?: boolean; 39 onlyContainsCACerts?: boolean; 40 onlySomeReasons?: number; 41 indirectCRL?: boolean; 42 onlyContainsAttributeCerts?: boolean; 43 } 44 45 export type DistributionPointName = GeneralName[] | RelativeDistinguishedNames; 46 export type DistributionPointNameJson = GeneralNameJson[] | RelativeDistinguishedNamesJson; 47 48 export type IssuingDistributionPointParameters = PkiObjectParameters & Partial<IIssuingDistributionPoint>; 49 50 /** 51 * Represents the IssuingDistributionPoint structure described in [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) 52 */ 53 export class IssuingDistributionPoint extends PkiObject implements IIssuingDistributionPoint { 54 55 public static override CLASS_NAME = "IssuingDistributionPoint"; 56 57 public distributionPoint?: DistributionPointName; 58 public onlyContainsUserCerts!: boolean; 59 public onlyContainsCACerts!: boolean; 60 public onlySomeReasons?: number; 61 public indirectCRL!: boolean; 62 public onlyContainsAttributeCerts!: boolean; 63 64 /** 65 * Initializes a new instance of the {@link IssuingDistributionPoint} class 66 * @param parameters Initialization parameters 67 */ 68 constructor(parameters: IssuingDistributionPointParameters = {}) { 69 super(); 70 71 if (DISTRIBUTION_POINT in parameters) { 72 this.distributionPoint = pvutils.getParametersValue(parameters, DISTRIBUTION_POINT, IssuingDistributionPoint.defaultValues(DISTRIBUTION_POINT)); 73 } 74 75 this.onlyContainsUserCerts = pvutils.getParametersValue(parameters, ONLY_CONTAINS_USER_CERTS, IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_USER_CERTS)); 76 this.onlyContainsCACerts = pvutils.getParametersValue(parameters, ONLY_CONTAINS_CA_CERTS, IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_CA_CERTS)); 77 if (ONLY_SOME_REASON in parameters) { 78 this.onlySomeReasons = pvutils.getParametersValue(parameters, ONLY_SOME_REASON, IssuingDistributionPoint.defaultValues(ONLY_SOME_REASON)); 79 } 80 this.indirectCRL = pvutils.getParametersValue(parameters, INDIRECT_CRL, IssuingDistributionPoint.defaultValues(INDIRECT_CRL)); 81 this.onlyContainsAttributeCerts = pvutils.getParametersValue(parameters, ONLY_CONTAINS_ATTRIBUTE_CERTS, IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_ATTRIBUTE_CERTS)); 82 83 if (parameters.schema) { 84 this.fromSchema(parameters.schema); 85 } 86 } 87 88 /** 89 * Returns default values for all class members 90 * @param memberName String name for a class member 91 * @returns Default value 92 */ 93 public static override defaultValues(memberName: typeof DISTRIBUTION_POINT): DistributionPointName; 94 public static override defaultValues(memberName: typeof ONLY_CONTAINS_USER_CERTS): boolean; 95 public static override defaultValues(memberName: typeof ONLY_CONTAINS_CA_CERTS): boolean; 96 public static override defaultValues(memberName: typeof ONLY_SOME_REASON): number; 97 public static override defaultValues(memberName: typeof INDIRECT_CRL): boolean; 98 public static override defaultValues(memberName: typeof ONLY_CONTAINS_ATTRIBUTE_CERTS): boolean; 99 public static override defaultValues(memberName: string): any { 100 switch (memberName) { 101 case DISTRIBUTION_POINT: 102 return []; 103 case ONLY_CONTAINS_USER_CERTS: 104 return false; 105 case ONLY_CONTAINS_CA_CERTS: 106 return false; 107 case ONLY_SOME_REASON: 108 return 0; 109 case INDIRECT_CRL: 110 return false; 111 case ONLY_CONTAINS_ATTRIBUTE_CERTS: 112 return false; 113 default: 114 return super.defaultValues(memberName); 115 } 116 } 117 118 /** 119 * @inheritdoc 120 * @asn ASN.1 schema 121 * ```asn 122 * IssuingDistributionPoint ::= SEQUENCE { 123 * distributionPoint [0] DistributionPointName OPTIONAL, 124 * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, 125 * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, 126 * onlySomeReasons [3] ReasonFlags OPTIONAL, 127 * indirectCRL [4] BOOLEAN DEFAULT FALSE, 128 * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } 129 * 130 * ReasonFlags ::= BIT STRING { 131 * unused (0), 132 * keyCompromise (1), 133 * cACompromise (2), 134 * affiliationChanged (3), 135 * superseded (4), 136 * cessationOfOperation (5), 137 * certificateHold (6), 138 * privilegeWithdrawn (7), 139 * aACompromise (8) } 140 *``` 141 */ 142 public static override schema(parameters: Schema.SchemaParameters<{ 143 distributionPoint?: string; 144 distributionPointNames?: string; 145 onlyContainsUserCerts?: string; 146 onlyContainsCACerts?: string; 147 onlySomeReasons?: string; 148 indirectCRL?: string; 149 onlyContainsAttributeCerts?: string; 150 }> = {}): Schema.SchemaType { 151 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 152 153 return (new asn1js.Sequence({ 154 name: (names.blockName || EMPTY_STRING), 155 value: [ 156 new asn1js.Constructed({ 157 optional: true, 158 idBlock: { 159 tagClass: 3, // CONTEXT-SPECIFIC 160 tagNumber: 0 // [0] 161 }, 162 value: [ 163 new asn1js.Choice({ 164 value: [ 165 new asn1js.Constructed({ 166 name: (names.distributionPoint || EMPTY_STRING), 167 idBlock: { 168 tagClass: 3, // CONTEXT-SPECIFIC 169 tagNumber: 0 // [0] 170 }, 171 value: [ 172 new asn1js.Repeated({ 173 name: (names.distributionPointNames || EMPTY_STRING), 174 value: GeneralName.schema() 175 }) 176 ] 177 }), 178 new asn1js.Constructed({ 179 name: (names.distributionPoint || EMPTY_STRING), 180 idBlock: { 181 tagClass: 3, // CONTEXT-SPECIFIC 182 tagNumber: 1 // [1] 183 }, 184 value: RelativeDistinguishedNames.schema().valueBlock.value 185 }) 186 ] 187 }) 188 ] 189 }), 190 new asn1js.Primitive({ 191 name: (names.onlyContainsUserCerts || EMPTY_STRING), 192 optional: true, 193 idBlock: { 194 tagClass: 3, // CONTEXT-SPECIFIC 195 tagNumber: 1 // [1] 196 } 197 }), // IMPLICIT boolean value 198 new asn1js.Primitive({ 199 name: (names.onlyContainsCACerts || EMPTY_STRING), 200 optional: true, 201 idBlock: { 202 tagClass: 3, // CONTEXT-SPECIFIC 203 tagNumber: 2 // [2] 204 } 205 }), // IMPLICIT boolean value 206 new asn1js.Primitive({ 207 name: (names.onlySomeReasons || EMPTY_STRING), 208 optional: true, 209 idBlock: { 210 tagClass: 3, // CONTEXT-SPECIFIC 211 tagNumber: 3 // [3] 212 } 213 }), // IMPLICIT BitString value 214 new asn1js.Primitive({ 215 name: (names.indirectCRL || EMPTY_STRING), 216 optional: true, 217 idBlock: { 218 tagClass: 3, // CONTEXT-SPECIFIC 219 tagNumber: 4 // [4] 220 } 221 }), // IMPLICIT boolean value 222 new asn1js.Primitive({ 223 name: (names.onlyContainsAttributeCerts || EMPTY_STRING), 224 optional: true, 225 idBlock: { 226 tagClass: 3, // CONTEXT-SPECIFIC 227 tagNumber: 5 // [5] 228 } 229 }) // IMPLICIT boolean value 230 ] 231 })); 232 } 233 234 public fromSchema(schema: Schema.SchemaType): void { 235 // Clear input data first 236 pvutils.clearProps(schema, CLEAR_PROPS); 237 238 // Check the schema is valid 239 const asn1 = asn1js.compareSchema(schema, 240 schema, 241 IssuingDistributionPoint.schema({ 242 names: { 243 distributionPoint: DISTRIBUTION_POINT, 244 distributionPointNames: DISTRIBUTION_POINT_NAMES, 245 onlyContainsUserCerts: ONLY_CONTAINS_USER_CERTS, 246 onlyContainsCACerts: ONLY_CONTAINS_CA_CERTS, 247 onlySomeReasons: ONLY_SOME_REASON, 248 indirectCRL: INDIRECT_CRL, 249 onlyContainsAttributeCerts: ONLY_CONTAINS_ATTRIBUTE_CERTS 250 } 251 }) 252 ); 253 AsnError.assertSchema(asn1, this.className); 254 255 // Get internal properties from parsed schema 256 if (DISTRIBUTION_POINT in asn1.result) { 257 switch (true) { 258 case (asn1.result.distributionPoint.idBlock.tagNumber === 0): // GENERAL_NAMES variant 259 this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element })); 260 break; 261 case (asn1.result.distributionPoint.idBlock.tagNumber === 1): // RDN variant 262 { 263 this.distributionPoint = new RelativeDistinguishedNames({ 264 schema: new asn1js.Sequence({ 265 value: asn1.result.distributionPoint.valueBlock.value 266 }) 267 }); 268 } 269 break; 270 default: 271 throw new Error("Unknown tagNumber for distributionPoint: {$asn1.result.distributionPoint.idBlock.tagNumber}"); 272 } 273 } 274 275 if (ONLY_CONTAINS_USER_CERTS in asn1.result) { 276 const view = new Uint8Array(asn1.result.onlyContainsUserCerts.valueBlock.valueHex); 277 this.onlyContainsUserCerts = (view[0] !== 0x00); 278 } 279 280 if (ONLY_CONTAINS_CA_CERTS in asn1.result) { 281 const view = new Uint8Array(asn1.result.onlyContainsCACerts.valueBlock.valueHex); 282 this.onlyContainsCACerts = (view[0] !== 0x00); 283 } 284 285 if (ONLY_SOME_REASON in asn1.result) { 286 const view = new Uint8Array(asn1.result.onlySomeReasons.valueBlock.valueHex); 287 this.onlySomeReasons = view[0]; 288 } 289 290 if (INDIRECT_CRL in asn1.result) { 291 const view = new Uint8Array(asn1.result.indirectCRL.valueBlock.valueHex); 292 this.indirectCRL = (view[0] !== 0x00); 293 } 294 295 if (ONLY_CONTAINS_ATTRIBUTE_CERTS in asn1.result) { 296 const view = new Uint8Array(asn1.result.onlyContainsAttributeCerts.valueBlock.valueHex); 297 this.onlyContainsAttributeCerts = (view[0] !== 0x00); 298 } 299 } 300 301 public toSchema(): asn1js.Sequence { 302 //#region Create array for output sequence 303 const outputArray = []; 304 305 if (this.distributionPoint) { 306 let value; 307 308 if (this.distributionPoint instanceof Array) { 309 value = new asn1js.Constructed({ 310 idBlock: { 311 tagClass: 3, // CONTEXT-SPECIFIC 312 tagNumber: 0 // [0] 313 }, 314 value: Array.from(this.distributionPoint, o => o.toSchema()) 315 }); 316 } else { 317 value = this.distributionPoint.toSchema(); 318 319 value.idBlock.tagClass = 3; // CONTEXT - SPECIFIC 320 value.idBlock.tagNumber = 1; // [1] 321 } 322 323 outputArray.push(new asn1js.Constructed({ 324 idBlock: { 325 tagClass: 3, // CONTEXT-SPECIFIC 326 tagNumber: 0 // [0] 327 }, 328 value: [value] 329 })); 330 } 331 332 if (this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_USER_CERTS)) { 333 outputArray.push(new asn1js.Primitive({ 334 idBlock: { 335 tagClass: 3, // CONTEXT-SPECIFIC 336 tagNumber: 1 // [1] 337 }, 338 valueHex: (new Uint8Array([0xFF])).buffer 339 })); 340 } 341 342 if (this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_CA_CERTS)) { 343 outputArray.push(new asn1js.Primitive({ 344 idBlock: { 345 tagClass: 3, // CONTEXT-SPECIFIC 346 tagNumber: 2 // [2] 347 }, 348 valueHex: (new Uint8Array([0xFF])).buffer 349 })); 350 } 351 352 if (this.onlySomeReasons !== undefined) { 353 const buffer = new ArrayBuffer(1); 354 const view = new Uint8Array(buffer); 355 356 view[0] = this.onlySomeReasons; 357 358 outputArray.push(new asn1js.Primitive({ 359 idBlock: { 360 tagClass: 3, // CONTEXT-SPECIFIC 361 tagNumber: 3 // [3] 362 }, 363 valueHex: buffer 364 })); 365 } 366 367 if (this.indirectCRL !== IssuingDistributionPoint.defaultValues(INDIRECT_CRL)) { 368 outputArray.push(new asn1js.Primitive({ 369 idBlock: { 370 tagClass: 3, // CONTEXT-SPECIFIC 371 tagNumber: 4 // [4] 372 }, 373 valueHex: (new Uint8Array([0xFF])).buffer 374 })); 375 } 376 377 if (this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_ATTRIBUTE_CERTS)) { 378 outputArray.push(new asn1js.Primitive({ 379 idBlock: { 380 tagClass: 3, // CONTEXT-SPECIFIC 381 tagNumber: 5 // [5] 382 }, 383 valueHex: (new Uint8Array([0xFF])).buffer 384 })); 385 } 386 //#endregion 387 388 //#region Construct and return new ASN.1 schema for this object 389 return (new asn1js.Sequence({ 390 value: outputArray 391 })); 392 //#endregion 393 } 394 395 public toJSON(): IssuingDistributionPointJson { 396 const obj: IssuingDistributionPointJson = {}; 397 398 if (this.distributionPoint) { 399 if (this.distributionPoint instanceof Array) { 400 obj.distributionPoint = Array.from(this.distributionPoint, o => o.toJSON()); 401 } else { 402 obj.distributionPoint = this.distributionPoint.toJSON(); 403 } 404 } 405 406 if (this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_USER_CERTS)) { 407 obj.onlyContainsUserCerts = this.onlyContainsUserCerts; 408 } 409 410 if (this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_CA_CERTS)) { 411 obj.onlyContainsCACerts = this.onlyContainsCACerts; 412 } 413 414 if (ONLY_SOME_REASON in this) { 415 obj.onlySomeReasons = this.onlySomeReasons; 416 } 417 418 if (this.indirectCRL !== IssuingDistributionPoint.defaultValues(INDIRECT_CRL)) { 419 obj.indirectCRL = this.indirectCRL; 420 } 421 422 if (this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_ATTRIBUTE_CERTS)) { 423 obj.onlyContainsAttributeCerts = this.onlyContainsAttributeCerts; 424 } 425 426 return obj; 427 } 428 429 }