GeneralSubtree.ts (6659B)
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, GeneralNameSchema } from "./GeneralName"; 6 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 7 import * as Schema from "./Schema"; 8 9 const BASE = "base"; 10 const MINIMUM = "minimum"; 11 const MAXIMUM = "maximum"; 12 const CLEAR_PROPS = [ 13 BASE, 14 MINIMUM, 15 MAXIMUM 16 ]; 17 18 export interface IGeneralSubtree { 19 base: GeneralName; 20 minimum: number | asn1js.Integer; 21 maximum?: number | asn1js.Integer; 22 } 23 24 export interface GeneralSubtreeJson { 25 base: GeneralNameJson; 26 minimum?: number | asn1js.IntegerJson; 27 maximum?: number | asn1js.IntegerJson; 28 } 29 30 export type GeneralSubtreeParameters = PkiObjectParameters & Partial<IGeneralSubtree>; 31 32 /** 33 * Represents the GeneralSubtree structure described in [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) 34 */ 35 export class GeneralSubtree extends PkiObject implements IGeneralSubtree { 36 37 public static override CLASS_NAME = "GeneralSubtree"; 38 39 public base!: GeneralName; 40 public minimum!: number | asn1js.Integer; 41 public maximum?: number | asn1js.Integer; 42 43 /** 44 * Initializes a new instance of the {@link GeneralSubtree} class 45 * @param parameters Initialization parameters 46 */ 47 constructor(parameters: GeneralSubtreeParameters = {}) { 48 super(); 49 50 this.base = pvutils.getParametersValue(parameters, BASE, GeneralSubtree.defaultValues(BASE)); 51 this.minimum = pvutils.getParametersValue(parameters, MINIMUM, GeneralSubtree.defaultValues(MINIMUM)); 52 if (MAXIMUM in parameters) { 53 this.maximum = pvutils.getParametersValue(parameters, MAXIMUM, GeneralSubtree.defaultValues(MAXIMUM)); 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 BASE): GeneralName; 67 public static override defaultValues(memberName: typeof MINIMUM): number; 68 public static override defaultValues(memberName: typeof MAXIMUM): number; 69 public static override defaultValues(memberName: string): any { 70 switch (memberName) { 71 case BASE: 72 return new GeneralName(); 73 case MINIMUM: 74 return 0; 75 case MAXIMUM: 76 return 0; 77 default: 78 return super.defaultValues(memberName); 79 } 80 } 81 82 /** 83 * @inheritdoc 84 * @asn ASN.1 schema 85 * ```asn 86 * GeneralSubtree ::= SEQUENCE { 87 * base GeneralName, 88 * minimum [0] BaseDistance DEFAULT 0, 89 * maximum [1] BaseDistance OPTIONAL } 90 * 91 * BaseDistance ::= INTEGER (0..MAX) 92 *``` 93 */ 94 public static override schema(parameters: Schema.SchemaParameters<{ 95 base?: GeneralNameSchema; 96 minimum?: string; 97 maximum?: string; 98 }> = {}): Schema.SchemaType { 99 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 100 101 return (new asn1js.Sequence({ 102 name: (names.blockName || EMPTY_STRING), 103 value: [ 104 GeneralName.schema(names.base || {}), 105 new asn1js.Constructed({ 106 optional: true, 107 idBlock: { 108 tagClass: 3, // CONTEXT-SPECIFIC 109 tagNumber: 0 // [0] 110 }, 111 value: [new asn1js.Integer({ name: (names.minimum || EMPTY_STRING) })] 112 }), 113 new asn1js.Constructed({ 114 optional: true, 115 idBlock: { 116 tagClass: 3, // CONTEXT-SPECIFIC 117 tagNumber: 1 // [1] 118 }, 119 value: [new asn1js.Integer({ name: (names.maximum || EMPTY_STRING) })] 120 }) 121 ] 122 })); 123 } 124 125 public fromSchema(schema: Schema.SchemaType): void { 126 // Clear input data first 127 pvutils.clearProps(schema, CLEAR_PROPS); 128 129 // Check the schema is valid 130 const asn1 = asn1js.compareSchema(schema, 131 schema, 132 GeneralSubtree.schema({ 133 names: { 134 base: { 135 names: { 136 blockName: BASE 137 } 138 }, 139 minimum: MINIMUM, 140 maximum: MAXIMUM 141 } 142 }) 143 ); 144 AsnError.assertSchema(asn1, this.className); 145 146 // Get internal properties from parsed schema 147 this.base = new GeneralName({ schema: asn1.result.base }); 148 149 if (MINIMUM in asn1.result) { 150 if (asn1.result.minimum.valueBlock.isHexOnly) 151 this.minimum = asn1.result.minimum; 152 else 153 this.minimum = asn1.result.minimum.valueBlock.valueDec; 154 } 155 156 if (MAXIMUM in asn1.result) { 157 if (asn1.result.maximum.valueBlock.isHexOnly) 158 this.maximum = asn1.result.maximum; 159 else 160 this.maximum = asn1.result.maximum.valueBlock.valueDec; 161 } 162 } 163 164 public toSchema(): asn1js.Sequence { 165 //#region Create array for output sequence 166 const outputArray = []; 167 168 outputArray.push(this.base.toSchema()); 169 170 if (this.minimum !== 0) { 171 let valueMinimum: number | asn1js.Integer = 0; 172 173 if (this.minimum instanceof asn1js.Integer) { 174 valueMinimum = this.minimum; 175 } else { 176 valueMinimum = new asn1js.Integer({ value: this.minimum }); 177 } 178 179 outputArray.push(new asn1js.Constructed({ 180 optional: true, 181 idBlock: { 182 tagClass: 3, // CONTEXT-SPECIFIC 183 tagNumber: 0 // [0] 184 }, 185 value: [valueMinimum] 186 })); 187 } 188 189 if (MAXIMUM in this) { 190 let valueMaximum: number | asn1js.Integer = 0; 191 192 if (this.maximum instanceof asn1js.Integer) { 193 valueMaximum = this.maximum; 194 } else { 195 valueMaximum = new asn1js.Integer({ value: this.maximum }); 196 } 197 198 outputArray.push(new asn1js.Constructed({ 199 optional: true, 200 idBlock: { 201 tagClass: 3, // CONTEXT-SPECIFIC 202 tagNumber: 1 // [1] 203 }, 204 value: [valueMaximum] 205 })); 206 } 207 //#endregion 208 209 //#region Construct and return new ASN.1 schema for this object 210 return (new asn1js.Sequence({ 211 value: outputArray 212 })); 213 //#endregion 214 } 215 216 public toJSON(): GeneralSubtreeJson { 217 const res: GeneralSubtreeJson = { 218 base: this.base.toJSON() 219 }; 220 221 if (this.minimum !== 0) { 222 if (typeof this.minimum === "number") { 223 res.minimum = this.minimum; 224 } else { 225 res.minimum = this.minimum.toJSON(); 226 } 227 } 228 229 if (this.maximum !== undefined) { 230 if (typeof this.maximum === "number") { 231 res.maximum = this.maximum; 232 } else { 233 res.maximum = this.maximum.toJSON(); 234 } 235 } 236 237 return res; 238 } 239 240 }