MacData.ts (5691B)
1 import * as asn1js from "asn1js"; 2 import * as pvutils from "pvutils"; 3 import { EMPTY_STRING } from "./constants"; 4 import { DigestInfo, DigestInfoJson, DigestInfoSchema } from "./DigestInfo"; 5 import { AsnError } from "./errors"; 6 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 7 import * as Schema from "./Schema"; 8 9 const MAC = "mac"; 10 const MAC_SALT = "macSalt"; 11 const ITERATIONS = "iterations"; 12 const CLEAR_PROPS = [ 13 MAC, 14 MAC_SALT, 15 ITERATIONS 16 ]; 17 18 export interface IMacData { 19 mac: DigestInfo; 20 macSalt: asn1js.OctetString; 21 iterations?: number; 22 } 23 24 export interface MacDataJson { 25 mac: DigestInfoJson; 26 macSalt: asn1js.OctetStringJson; 27 iterations?: number; 28 } 29 30 export type MacDataParameters = PkiObjectParameters & Partial<IMacData>; 31 32 export type MacDataSchema = Schema.SchemaParameters<{ 33 mac?: DigestInfoSchema; 34 macSalt?: string; 35 iterations?: string; 36 }>; 37 38 /** 39 * Represents the MacData structure described in [RFC7292](https://datatracker.ietf.org/doc/html/rfc7292) 40 */ 41 export class MacData extends PkiObject implements IMacData { 42 43 public static override CLASS_NAME = "MacData"; 44 45 public mac!: DigestInfo; 46 public macSalt!: asn1js.OctetString; 47 public iterations?: number; 48 49 /** 50 * Initializes a new instance of the {@link MacData} class 51 * @param parameters Initialization parameters 52 */ 53 constructor(parameters: MacDataParameters = {}) { 54 super(); 55 56 this.mac = pvutils.getParametersValue(parameters, MAC, MacData.defaultValues(MAC)); 57 this.macSalt = pvutils.getParametersValue(parameters, MAC_SALT, MacData.defaultValues(MAC_SALT)); 58 if (ITERATIONS in parameters) { 59 this.iterations = pvutils.getParametersValue(parameters, ITERATIONS, MacData.defaultValues(ITERATIONS)); 60 } 61 62 if (parameters.schema) { 63 this.fromSchema(parameters.schema); 64 } 65 } 66 67 /** 68 * Returns default values for all class members 69 * @param memberName String name for a class member 70 * @returns Default value 71 */ 72 public static override defaultValues(memberName: typeof MAC): DigestInfo; 73 public static override defaultValues(memberName: typeof MAC_SALT): asn1js.OctetString; 74 public static override defaultValues(memberName: typeof ITERATIONS): number; 75 public static override defaultValues(memberName: string): any { 76 switch (memberName) { 77 case MAC: 78 return new DigestInfo(); 79 case MAC_SALT: 80 return new asn1js.OctetString(); 81 case ITERATIONS: 82 return 1; 83 default: 84 return super.defaultValues(memberName); 85 } 86 } 87 88 /** 89 * Compare values with default values for all class members 90 * @param memberName String name for a class member 91 * @param memberValue Value to compare with default value 92 */ 93 public static compareWithDefault(memberName: string, memberValue: any): boolean { 94 switch (memberName) { 95 case MAC: 96 return ((DigestInfo.compareWithDefault("digestAlgorithm", memberValue.digestAlgorithm)) && 97 (DigestInfo.compareWithDefault("digest", memberValue.digest))); 98 case MAC_SALT: 99 return (memberValue.isEqual(MacData.defaultValues(memberName))); 100 case ITERATIONS: 101 return (memberValue === MacData.defaultValues(memberName)); 102 default: 103 return super.defaultValues(memberName); 104 } 105 } 106 107 /** 108 * @inheritdoc 109 * @asn ASN.1 schema 110 * ```asn 111 * MacData ::= SEQUENCE { 112 * mac DigestInfo, 113 * macSalt OCTET STRING, 114 * iterations INTEGER DEFAULT 1 115 * -- Note: The default is for historical reasons and its use is 116 * -- deprecated. A higher value, like 1024 is recommended. 117 * } 118 *``` 119 */ 120 public static override schema(parameters: MacDataSchema = {}): Schema.SchemaType { 121 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 122 123 return (new asn1js.Sequence({ 124 name: (names.blockName || EMPTY_STRING), 125 optional: (names.optional || true), 126 value: [ 127 DigestInfo.schema(names.mac || { 128 names: { 129 blockName: MAC 130 } 131 }), 132 new asn1js.OctetString({ name: (names.macSalt || MAC_SALT) }), 133 new asn1js.Integer({ 134 optional: true, 135 name: (names.iterations || ITERATIONS) 136 }) 137 ] 138 })); 139 } 140 141 public fromSchema(schema: Schema.SchemaType): void { 142 // Clear input data first 143 pvutils.clearProps(schema, CLEAR_PROPS); 144 145 // Check the schema is valid 146 const asn1 = asn1js.compareSchema(schema, 147 schema, 148 MacData.schema({ 149 names: { 150 mac: { 151 names: { 152 blockName: MAC 153 } 154 }, 155 macSalt: MAC_SALT, 156 iterations: ITERATIONS 157 } 158 }) 159 ); 160 AsnError.assertSchema(asn1, this.className); 161 162 // Get internal properties from parsed schema 163 this.mac = new DigestInfo({ schema: asn1.result.mac }); 164 this.macSalt = asn1.result.macSalt; 165 if (ITERATIONS in asn1.result) 166 this.iterations = asn1.result.iterations.valueBlock.valueDec; 167 } 168 169 public toSchema(): asn1js.Sequence { 170 //#region Construct and return new ASN.1 schema for this object 171 const outputArray: any[] = [ 172 this.mac.toSchema(), 173 this.macSalt 174 ]; 175 176 if (this.iterations !== undefined) { 177 outputArray.push(new asn1js.Integer({ value: this.iterations })); 178 } 179 180 return (new asn1js.Sequence({ 181 value: outputArray 182 })); 183 //#endregion 184 } 185 186 public toJSON(): MacDataJson { 187 const res: MacDataJson = { 188 mac: this.mac.toJSON(), 189 macSalt: this.macSalt.toJSON(), 190 }; 191 192 if (this.iterations !== undefined) { 193 res.iterations = this.iterations; 194 } 195 196 return res; 197 } 198 199 }