RelativeDistinguishedNames.ts (6440B)
1 import * as asn1js from "asn1js"; 2 import * as pvutils from "pvutils"; 3 import { AttributeTypeAndValue, AttributeTypeAndValueJson } from "./AttributeTypeAndValue"; 4 import { EMPTY_BUFFER, EMPTY_STRING } from "./constants"; 5 import { AsnError } from "./errors"; 6 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 7 import * as Schema from "./Schema"; 8 9 export const TYPE_AND_VALUES = "typesAndValues"; 10 export const VALUE_BEFORE_DECODE = "valueBeforeDecode"; 11 export const RDN = "RDN"; 12 13 export interface IRelativeDistinguishedNames { 14 /** 15 * Array of "type and value" objects 16 */ 17 typesAndValues: AttributeTypeAndValue[]; 18 /** 19 * Value of the RDN before decoding from schema 20 */ 21 valueBeforeDecode: ArrayBuffer; 22 } 23 24 export type RelativeDistinguishedNamesParameters = PkiObjectParameters & Partial<IRelativeDistinguishedNames>; 25 26 export type RelativeDistinguishedNamesSchema = Schema.SchemaParameters<{ 27 repeatedSequence?: string; 28 repeatedSet?: string; 29 typeAndValue?: Schema.SchemaType; 30 }>; 31 32 export interface RelativeDistinguishedNamesJson { 33 typesAndValues: AttributeTypeAndValueJson[]; 34 } 35 36 /** 37 * Represents the RelativeDistinguishedNames structure described in [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) 38 */ 39 export class RelativeDistinguishedNames extends PkiObject implements IRelativeDistinguishedNames { 40 41 public static override CLASS_NAME = "RelativeDistinguishedNames"; 42 43 public typesAndValues!: AttributeTypeAndValue[]; 44 public valueBeforeDecode!: ArrayBuffer; 45 46 /** 47 * Initializes a new instance of the {@link RelativeDistinguishedNames} class 48 * @param parameters Initialization parameters 49 */ 50 constructor(parameters: RelativeDistinguishedNamesParameters = {}) { 51 super(); 52 53 this.typesAndValues = pvutils.getParametersValue(parameters, TYPE_AND_VALUES, RelativeDistinguishedNames.defaultValues(TYPE_AND_VALUES)); 54 this.valueBeforeDecode = pvutils.getParametersValue(parameters, VALUE_BEFORE_DECODE, RelativeDistinguishedNames.defaultValues(VALUE_BEFORE_DECODE)); 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 TYPE_AND_VALUES): AttributeTypeAndValue[]; 67 public static override defaultValues(memberName: typeof VALUE_BEFORE_DECODE): ArrayBuffer; 68 public static override defaultValues(memberName: string): any { 69 switch (memberName) { 70 case TYPE_AND_VALUES: 71 return []; 72 case VALUE_BEFORE_DECODE: 73 return EMPTY_BUFFER; 74 default: 75 return super.defaultValues(memberName); 76 } 77 } 78 79 /** 80 * Compares values with default values for all class members 81 * @param memberName String name for a class member 82 * @param memberValue Value to compare with default value 83 */ 84 public static compareWithDefault(memberName: string, memberValue: any): boolean { 85 switch (memberName) { 86 case TYPE_AND_VALUES: 87 return (memberValue.length === 0); 88 case VALUE_BEFORE_DECODE: 89 return (memberValue.byteLength === 0); 90 default: 91 return super.defaultValues(memberName); 92 } 93 } 94 95 /** 96 * @inheritdoc 97 * @asn ASN.1 schema 98 * ```asn 99 * RDNSequence ::= Sequence OF RelativeDistinguishedName 100 * 101 * RelativeDistinguishedName ::= 102 * SET SIZE (1..MAX) OF AttributeTypeAndValue 103 *``` 104 */ 105 static override schema(parameters: RelativeDistinguishedNamesSchema = {}): Schema.SchemaType { 106 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 107 108 return (new asn1js.Sequence({ 109 name: (names.blockName || EMPTY_STRING), 110 value: [ 111 new asn1js.Repeated({ 112 name: (names.repeatedSequence || EMPTY_STRING), 113 value: new asn1js.Set({ 114 value: [ 115 new asn1js.Repeated({ 116 name: (names.repeatedSet || EMPTY_STRING), 117 value: AttributeTypeAndValue.schema(names.typeAndValue || {}) 118 }) 119 ] 120 } as any) 121 } as any) 122 ] 123 } as any)); 124 } 125 126 public fromSchema(schema: Schema.SchemaType): void { 127 // Clear input data first 128 pvutils.clearProps(schema, [ 129 RDN, 130 TYPE_AND_VALUES 131 ]); 132 133 // Check the schema is valid 134 const asn1 = asn1js.compareSchema(schema, 135 schema, 136 RelativeDistinguishedNames.schema({ 137 names: { 138 blockName: RDN, 139 repeatedSet: TYPE_AND_VALUES 140 } 141 }) 142 ); 143 AsnError.assertSchema(asn1, this.className); 144 145 // Get internal properties from parsed schema 146 if (TYPE_AND_VALUES in asn1.result) {// Could be a case when there is no "types and values" 147 this.typesAndValues = Array.from(asn1.result.typesAndValues, element => new AttributeTypeAndValue({ schema: element })); 148 } 149 150 this.valueBeforeDecode = (asn1.result.RDN as asn1js.BaseBlock).valueBeforeDecodeView.slice().buffer; 151 } 152 153 public toSchema(): asn1js.Sequence { 154 if (this.valueBeforeDecode.byteLength === 0) // No stored encoded array, create "from scratch" 155 { 156 return (new asn1js.Sequence({ 157 value: [new asn1js.Set({ 158 value: Array.from(this.typesAndValues, o => o.toSchema()) 159 } as any)] 160 } as any)); 161 } 162 163 const asn1 = asn1js.fromBER(this.valueBeforeDecode); 164 AsnError.assert(asn1, "RelativeDistinguishedNames"); 165 if (!(asn1.result instanceof asn1js.Sequence)) { 166 throw new Error("ASN.1 result should be SEQUENCE"); 167 } 168 169 return asn1.result; 170 } 171 172 public toJSON(): RelativeDistinguishedNamesJson { 173 return { 174 typesAndValues: Array.from(this.typesAndValues, o => o.toJSON()) 175 }; 176 } 177 178 /** 179 * Compares two RDN values, or RDN with ArrayBuffer value 180 * @param compareTo The value compare to current 181 */ 182 public isEqual(compareTo: unknown): boolean { 183 if (compareTo instanceof RelativeDistinguishedNames) { 184 if (this.typesAndValues.length !== compareTo.typesAndValues.length) 185 return false; 186 187 for (const [index, typeAndValue] of this.typesAndValues.entries()) { 188 if (typeAndValue.isEqual(compareTo.typesAndValues[index]) === false) 189 return false; 190 } 191 192 return true; 193 } 194 195 if (compareTo instanceof ArrayBuffer) { 196 return pvutils.isEqualBuffer(this.valueBeforeDecode, compareTo); 197 } 198 199 return false; 200 } 201 202 }