DistributionPoint.ts (10341B)
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 { DistributionPointName, DistributionPointNameJson } from "./IssuingDistributionPoint"; 7 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 8 import { RelativeDistinguishedNames } from "./RelativeDistinguishedNames"; 9 import * as Schema from "./Schema"; 10 11 const DISTRIBUTION_POINT = "distributionPoint"; 12 const DISTRIBUTION_POINT_NAMES = "distributionPointNames"; 13 const REASONS = "reasons"; 14 const CRL_ISSUER = "cRLIssuer"; 15 const CRL_ISSUER_NAMES = "cRLIssuerNames"; 16 const CLEAR_PROPS = [ 17 DISTRIBUTION_POINT, 18 DISTRIBUTION_POINT_NAMES, 19 REASONS, 20 CRL_ISSUER, 21 CRL_ISSUER_NAMES, 22 ]; 23 24 export interface IDistributionPoint { 25 distributionPoint?: DistributionPointName; 26 reasons?: asn1js.BitString; 27 cRLIssuer?: GeneralName[]; 28 } 29 30 export interface DistributionPointJson { 31 distributionPoint?: DistributionPointNameJson; 32 reasons?: asn1js.BitStringJson; 33 cRLIssuer?: GeneralNameJson[]; 34 } 35 36 export type DistributionPointParameters = PkiObjectParameters & Partial<IDistributionPoint>; 37 38 /** 39 * Represents the DistributionPoint structure described in [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) 40 */ 41 export class DistributionPoint extends PkiObject implements IDistributionPoint { 42 43 public static override CLASS_NAME = "DistributionPoint"; 44 45 public distributionPoint?: DistributionPointName; 46 public reasons?: asn1js.BitString; 47 public cRLIssuer?: GeneralName[]; 48 49 /** 50 * Initializes a new instance of the {@link DistributionPoint} class 51 * @param parameters Initialization parameters 52 */ 53 constructor(parameters: DistributionPointParameters = {}) { 54 super(); 55 56 if (DISTRIBUTION_POINT in parameters) { 57 this.distributionPoint = pvutils.getParametersValue(parameters, DISTRIBUTION_POINT, DistributionPoint.defaultValues(DISTRIBUTION_POINT)); 58 } 59 if (REASONS in parameters) { 60 this.reasons = pvutils.getParametersValue(parameters, REASONS, DistributionPoint.defaultValues(REASONS)); 61 } 62 if (CRL_ISSUER in parameters) { 63 this.cRLIssuer = pvutils.getParametersValue(parameters, CRL_ISSUER, DistributionPoint.defaultValues(CRL_ISSUER)); 64 } 65 66 if (parameters.schema) { 67 this.fromSchema(parameters.schema); 68 } 69 } 70 71 /** 72 * Returns default values for all class members 73 * @param memberName String name for a class member 74 * @returns Default value 75 */ 76 public static override defaultValues(memberName: typeof DISTRIBUTION_POINT): DistributionPointName; 77 public static override defaultValues(memberName: typeof REASONS): asn1js.BitString; 78 public static override defaultValues(memberName: typeof CRL_ISSUER): GeneralName[]; 79 public static override defaultValues(memberName: string): any { 80 switch (memberName) { 81 case DISTRIBUTION_POINT: 82 return []; 83 case REASONS: 84 return new asn1js.BitString(); 85 case CRL_ISSUER: 86 return []; 87 default: 88 return super.defaultValues(memberName); 89 } 90 } 91 92 /** 93 * @inheritdoc 94 * @asn ASN.1 schema 95 * ```asn 96 * DistributionPoint ::= SEQUENCE { 97 * distributionPoint [0] DistributionPointName OPTIONAL, 98 * reasons [1] ReasonFlags OPTIONAL, 99 * cRLIssuer [2] GeneralNames OPTIONAL } 100 * 101 * DistributionPointName ::= CHOICE { 102 * fullName [0] GeneralNames, 103 * nameRelativeToCRLIssuer [1] RelativeDistinguishedName } 104 * 105 * ReasonFlags ::= BIT STRING { 106 * unused (0), 107 * keyCompromise (1), 108 * cACompromise (2), 109 * affiliationChanged (3), 110 * superseded (4), 111 * cessationOfOperation (5), 112 * certificateHold (6), 113 * privilegeWithdrawn (7), 114 * aACompromise (8) } 115 *``` 116 */ 117 public static override schema(parameters: Schema.SchemaParameters<{ 118 distributionPoint?: string; 119 distributionPointNames?: string; 120 reasons?: string; 121 cRLIssuer?: string; 122 cRLIssuerNames?: string; 123 }> = {}): Schema.SchemaType { 124 /** 125 * @type {Object} 126 * @property {string} [blockName] 127 * @property {string} [distributionPoint] 128 * @property {string} [distributionPointNames] 129 * @property {string} [reasons] 130 * @property {string} [cRLIssuer] 131 * @property {string} [cRLIssuerNames] 132 */ 133 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 134 135 return (new asn1js.Sequence({ 136 name: (names.blockName || EMPTY_STRING), 137 value: [ 138 new asn1js.Constructed({ 139 optional: true, 140 idBlock: { 141 tagClass: 3, // CONTEXT-SPECIFIC 142 tagNumber: 0 // [0] 143 }, 144 value: [ 145 new asn1js.Choice({ 146 value: [ 147 new asn1js.Constructed({ 148 name: (names.distributionPoint || EMPTY_STRING), 149 optional: true, 150 idBlock: { 151 tagClass: 3, // CONTEXT-SPECIFIC 152 tagNumber: 0 // [0] 153 }, 154 value: [ 155 new asn1js.Repeated({ 156 name: (names.distributionPointNames || EMPTY_STRING), 157 value: GeneralName.schema() 158 }) 159 ] 160 }), 161 new asn1js.Constructed({ 162 name: (names.distributionPoint || EMPTY_STRING), 163 optional: true, 164 idBlock: { 165 tagClass: 3, // CONTEXT-SPECIFIC 166 tagNumber: 1 // [1] 167 }, 168 value: RelativeDistinguishedNames.schema().valueBlock.value 169 }) 170 ] 171 }) 172 ] 173 }), 174 new asn1js.Primitive({ 175 name: (names.reasons || EMPTY_STRING), 176 optional: true, 177 idBlock: { 178 tagClass: 3, // CONTEXT-SPECIFIC 179 tagNumber: 1 // [1] 180 } 181 }), // IMPLICIT BitString value 182 new asn1js.Constructed({ 183 name: (names.cRLIssuer || EMPTY_STRING), 184 optional: true, 185 idBlock: { 186 tagClass: 3, // CONTEXT-SPECIFIC 187 tagNumber: 2 // [2] 188 }, 189 value: [ 190 new asn1js.Repeated({ 191 name: (names.cRLIssuerNames || EMPTY_STRING), 192 value: GeneralName.schema() 193 }) 194 ] 195 }) // IMPLICIT BitString value 196 ] 197 })); 198 } 199 200 public fromSchema(schema: Schema.SchemaType): void { 201 // Clear input data first 202 pvutils.clearProps(schema, CLEAR_PROPS); 203 204 // Check the schema is valid 205 const asn1 = asn1js.compareSchema(schema, 206 schema, 207 DistributionPoint.schema({ 208 names: { 209 distributionPoint: DISTRIBUTION_POINT, 210 distributionPointNames: DISTRIBUTION_POINT_NAMES, 211 reasons: REASONS, 212 cRLIssuer: CRL_ISSUER, 213 cRLIssuerNames: CRL_ISSUER_NAMES 214 } 215 }) 216 ); 217 AsnError.assertSchema(asn1, this.className); 218 219 //#region Get internal properties from parsed schema 220 if (DISTRIBUTION_POINT in asn1.result) { 221 if (asn1.result.distributionPoint.idBlock.tagNumber === 0) { // GENERAL_NAMES variant 222 this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element })); 223 } 224 225 if (asn1.result.distributionPoint.idBlock.tagNumber === 1) {// RDN variant 226 this.distributionPoint = new RelativeDistinguishedNames({ 227 schema: new asn1js.Sequence({ 228 value: asn1.result.distributionPoint.valueBlock.value 229 }) 230 }); 231 } 232 } 233 234 if (REASONS in asn1.result) { 235 this.reasons = new asn1js.BitString({ valueHex: asn1.result.reasons.valueBlock.valueHex }); 236 } 237 238 if (CRL_ISSUER in asn1.result) { 239 this.cRLIssuer = Array.from(asn1.result.cRLIssuerNames, element => new GeneralName({ schema: element })); 240 } 241 //#endregion 242 } 243 244 public toSchema(): asn1js.Sequence { 245 //#region Create array for output sequence 246 const outputArray = []; 247 248 if (this.distributionPoint) { 249 let internalValue; 250 251 if (this.distributionPoint instanceof Array) { 252 internalValue = new asn1js.Constructed({ 253 idBlock: { 254 tagClass: 3, // CONTEXT-SPECIFIC 255 tagNumber: 0 // [0] 256 }, 257 value: Array.from(this.distributionPoint, o => o.toSchema()) 258 }); 259 } else { 260 internalValue = new asn1js.Constructed({ 261 idBlock: { 262 tagClass: 3, // CONTEXT-SPECIFIC 263 tagNumber: 1 // [1] 264 }, 265 value: [this.distributionPoint.toSchema()] 266 }); 267 } 268 269 outputArray.push(new asn1js.Constructed({ 270 idBlock: { 271 tagClass: 3, // CONTEXT-SPECIFIC 272 tagNumber: 0 // [0] 273 }, 274 value: [internalValue] 275 })); 276 } 277 278 if (this.reasons) { 279 outputArray.push(new asn1js.Primitive({ 280 idBlock: { 281 tagClass: 3, // CONTEXT-SPECIFIC 282 tagNumber: 1 // [1] 283 }, 284 valueHex: this.reasons.valueBlock.valueHexView 285 })); 286 } 287 288 if (this.cRLIssuer) { 289 outputArray.push(new asn1js.Constructed({ 290 idBlock: { 291 tagClass: 3, // CONTEXT-SPECIFIC 292 tagNumber: 2 // [2] 293 }, 294 value: Array.from(this.cRLIssuer, o => o.toSchema()) 295 })); 296 } 297 //#endregion 298 299 //#region Construct and return new ASN.1 schema for this object 300 return (new asn1js.Sequence({ 301 value: outputArray 302 })); 303 //#endregion 304 } 305 306 public toJSON(): DistributionPointJson { 307 const object: DistributionPointJson = {}; 308 309 if (this.distributionPoint) { 310 if (this.distributionPoint instanceof Array) { 311 object.distributionPoint = Array.from(this.distributionPoint, o => o.toJSON()); 312 } else { 313 object.distributionPoint = this.distributionPoint.toJSON(); 314 } 315 } 316 317 if (this.reasons) { 318 object.reasons = this.reasons.toJSON(); 319 } 320 321 if (this.cRLIssuer) { 322 object.cRLIssuer = Array.from(this.cRLIssuer, o => o.toJSON()); 323 } 324 325 return object; 326 } 327 328 }