NameConstraints.ts (5822B)
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 { GeneralSubtree, GeneralSubtreeJson } from "./GeneralSubtree"; 6 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 7 import * as Schema from "./Schema"; 8 9 const PERMITTED_SUBTREES = "permittedSubtrees"; 10 const EXCLUDED_SUBTREES = "excludedSubtrees"; 11 const CLEAR_PROPS = [ 12 PERMITTED_SUBTREES, 13 EXCLUDED_SUBTREES 14 ]; 15 16 export interface INameConstraints { 17 permittedSubtrees?: GeneralSubtree[]; 18 excludedSubtrees?: GeneralSubtree[]; 19 } 20 21 export interface NameConstraintsJson { 22 permittedSubtrees?: GeneralSubtreeJson[]; 23 excludedSubtrees?: GeneralSubtreeJson[]; 24 } 25 26 export type NameConstraintsParameters = PkiObjectParameters & Partial<INameConstraints>; 27 28 /** 29 * Represents the NameConstraints structure described in [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) 30 */ 31 export class NameConstraints extends PkiObject implements INameConstraints { 32 33 public static override CLASS_NAME = "NameConstraints"; 34 35 public permittedSubtrees?: GeneralSubtree[]; 36 public excludedSubtrees?: GeneralSubtree[]; 37 38 /** 39 * Initializes a new instance of the {@link NameConstraints} class 40 * @param parameters Initialization parameters 41 */ 42 constructor(parameters: NameConstraintsParameters = {}) { 43 super(); 44 45 if (PERMITTED_SUBTREES in parameters) { 46 this.permittedSubtrees = pvutils.getParametersValue(parameters, PERMITTED_SUBTREES, NameConstraints.defaultValues(PERMITTED_SUBTREES)); 47 } 48 if (EXCLUDED_SUBTREES in parameters) { 49 this.excludedSubtrees = pvutils.getParametersValue(parameters, EXCLUDED_SUBTREES, NameConstraints.defaultValues(EXCLUDED_SUBTREES)); 50 } 51 52 if (parameters.schema) { 53 this.fromSchema(parameters.schema); 54 } 55 } 56 57 /** 58 * Returns default values for all class members 59 * @param memberName String name for a class member 60 * @returns Default value 61 */ 62 public static override defaultValues(memberName: typeof PERMITTED_SUBTREES): GeneralSubtree[]; 63 public static override defaultValues(memberName: typeof EXCLUDED_SUBTREES): GeneralSubtree[]; 64 public static override defaultValues(memberName: string): any { 65 switch (memberName) { 66 case PERMITTED_SUBTREES: 67 case EXCLUDED_SUBTREES: 68 return []; 69 default: 70 return super.defaultValues(memberName); 71 } 72 } 73 74 /** 75 * @inheritdoc 76 * @asn ASN.1 schema 77 * ```asn 78 * NameConstraints ::= SEQUENCE { 79 * permittedSubtrees [0] GeneralSubtrees OPTIONAL, 80 * excludedSubtrees [1] GeneralSubtrees OPTIONAL } 81 *``` 82 */ 83 public static override schema(parameters: Schema.SchemaParameters<{ 84 permittedSubtrees?: string; 85 excludedSubtrees?: string; 86 }> = {}): Schema.SchemaType { 87 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 88 89 return (new asn1js.Sequence({ 90 name: (names.blockName || EMPTY_STRING), 91 value: [ 92 new asn1js.Constructed({ 93 optional: true, 94 idBlock: { 95 tagClass: 3, // CONTEXT-SPECIFIC 96 tagNumber: 0 // [0] 97 }, 98 value: [ 99 new asn1js.Repeated({ 100 name: (names.permittedSubtrees || EMPTY_STRING), 101 value: GeneralSubtree.schema() 102 }) 103 ] 104 }), 105 new asn1js.Constructed({ 106 optional: true, 107 idBlock: { 108 tagClass: 3, // CONTEXT-SPECIFIC 109 tagNumber: 1 // [1] 110 }, 111 value: [ 112 new asn1js.Repeated({ 113 name: (names.excludedSubtrees || EMPTY_STRING), 114 value: GeneralSubtree.schema() 115 }) 116 ] 117 }) 118 ] 119 })); 120 } 121 122 public fromSchema(schema: Schema.SchemaType): void { 123 // Clear input data first 124 pvutils.clearProps(schema, CLEAR_PROPS); 125 126 // Check the schema is valid 127 const asn1 = asn1js.compareSchema(schema, 128 schema, 129 NameConstraints.schema({ 130 names: { 131 permittedSubtrees: PERMITTED_SUBTREES, 132 excludedSubtrees: EXCLUDED_SUBTREES 133 } 134 }) 135 ); 136 AsnError.assertSchema(asn1, this.className); 137 138 // Get internal properties from parsed schema 139 if (PERMITTED_SUBTREES in asn1.result) 140 this.permittedSubtrees = Array.from(asn1.result.permittedSubtrees, element => new GeneralSubtree({ schema: element })); 141 if (EXCLUDED_SUBTREES in asn1.result) 142 this.excludedSubtrees = Array.from(asn1.result.excludedSubtrees, element => new GeneralSubtree({ schema: element })); 143 } 144 145 public toSchema(): asn1js.Sequence { 146 //#region Create array for output sequence 147 const outputArray = []; 148 149 if (this.permittedSubtrees) { 150 outputArray.push(new asn1js.Constructed({ 151 idBlock: { 152 tagClass: 3, // CONTEXT-SPECIFIC 153 tagNumber: 0 // [0] 154 }, 155 value: Array.from(this.permittedSubtrees, o => o.toSchema()) 156 })); 157 } 158 159 if (this.excludedSubtrees) { 160 outputArray.push(new asn1js.Constructed({ 161 idBlock: { 162 tagClass: 3, // CONTEXT-SPECIFIC 163 tagNumber: 1 // [1] 164 }, 165 value: Array.from(this.excludedSubtrees, o => o.toSchema()) 166 })); 167 } 168 //#endregion 169 170 //#region Construct and return new ASN.1 schema for this object 171 return (new asn1js.Sequence({ 172 value: outputArray 173 })); 174 //#endregion 175 } 176 177 public toJSON(): NameConstraintsJson { 178 const object: NameConstraintsJson = {}; 179 180 if (this.permittedSubtrees) { 181 object.permittedSubtrees = Array.from(this.permittedSubtrees, o => o.toJSON()); 182 } 183 184 if (this.excludedSubtrees) { 185 object.excludedSubtrees = Array.from(this.excludedSubtrees, o => o.toJSON()); 186 } 187 188 return object; 189 } 190 191 }