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