TBSRequest.ts (10885B)
1 import * as asn1js from "asn1js"; 2 import * as pvtsutils from "pvtsutils"; 3 import * as pvutils from "pvutils"; 4 import { GeneralName, GeneralNameJson, GeneralNameSchema } from "./GeneralName"; 5 import { Request, RequestJson, RequestSchema } from "./Request"; 6 import { Extension, ExtensionJson } from "./Extension"; 7 import { Extensions, ExtensionsSchema } from "./Extensions"; 8 import * as Schema from "./Schema"; 9 import { AsnError } from "./errors"; 10 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 11 import { EMPTY_BUFFER } from "./constants"; 12 13 const TBS = "tbs"; 14 const VERSION = "version"; 15 const REQUESTOR_NAME = "requestorName"; 16 const REQUEST_LIST = "requestList"; 17 const REQUEST_EXTENSIONS = "requestExtensions"; 18 const TBS_REQUEST = "TBSRequest"; 19 const TBS_REQUEST_VERSION = `${TBS_REQUEST}.${VERSION}`; 20 const TBS_REQUEST_REQUESTOR_NAME = `${TBS_REQUEST}.${REQUESTOR_NAME}`; 21 const TBS_REQUEST_REQUESTS = `${TBS_REQUEST}.requests`; 22 const TBS_REQUEST_REQUEST_EXTENSIONS = `${TBS_REQUEST}.${REQUEST_EXTENSIONS}`; 23 const CLEAR_PROPS = [ 24 TBS_REQUEST, 25 TBS_REQUEST_VERSION, 26 TBS_REQUEST_REQUESTOR_NAME, 27 TBS_REQUEST_REQUESTS, 28 TBS_REQUEST_REQUEST_EXTENSIONS 29 ]; 30 31 export interface ITBSRequest { 32 tbs: ArrayBuffer; 33 version?: number; 34 requestorName?: GeneralName; 35 requestList: Request[]; 36 requestExtensions?: Extension[]; 37 } 38 39 export interface TBSRequestJson { 40 tbs: string; 41 version?: number; 42 requestorName?: GeneralNameJson; 43 requestList: RequestJson[]; 44 requestExtensions?: ExtensionJson[]; 45 } 46 47 export type TBSRequestParameters = PkiObjectParameters & Partial<ITBSRequest>; 48 49 export type TBSRequestSchema = Schema.SchemaParameters<{ 50 TBSRequestVersion?: string; 51 requestorName?: GeneralNameSchema; 52 requestList?: string; 53 requests?: string; 54 requestNames?: RequestSchema; 55 extensions?: ExtensionsSchema; 56 requestExtensions?: string; 57 }>; 58 59 /** 60 * Represents the TBSRequest structure described in [RFC6960](https://datatracker.ietf.org/doc/html/rfc6960) 61 */ 62 export class TBSRequest extends PkiObject implements ITBSRequest { 63 64 public static override CLASS_NAME = "TBSRequest"; 65 66 public tbsView!: Uint8Array; 67 /** 68 * @deprecated Since version 3.0.0 69 */ 70 public get tbs(): ArrayBuffer { 71 return pvtsutils.BufferSourceConverter.toArrayBuffer(this.tbsView); 72 } 73 74 /** 75 * @deprecated Since version 3.0.0 76 */ 77 public set tbs(value: ArrayBuffer) { 78 this.tbsView = new Uint8Array(value); 79 } 80 public version?: number; 81 public requestorName?: GeneralName; 82 public requestList!: Request[]; 83 public requestExtensions?: Extension[]; 84 85 /** 86 * Initializes a new instance of the {@link TBSRequest} class 87 * @param parameters Initialization parameters 88 */ 89 constructor(parameters: TBSRequestParameters = {}) { 90 super(); 91 92 this.tbsView = new Uint8Array(pvutils.getParametersValue(parameters, TBS, TBSRequest.defaultValues(TBS))); 93 if (VERSION in parameters) { 94 this.version = pvutils.getParametersValue(parameters, VERSION, TBSRequest.defaultValues(VERSION)); 95 } 96 if (REQUESTOR_NAME in parameters) { 97 this.requestorName = pvutils.getParametersValue(parameters, REQUESTOR_NAME, TBSRequest.defaultValues(REQUESTOR_NAME)); 98 } 99 this.requestList = pvutils.getParametersValue(parameters, REQUEST_LIST, TBSRequest.defaultValues(REQUEST_LIST)); 100 if (REQUEST_EXTENSIONS in parameters) { 101 this.requestExtensions = pvutils.getParametersValue(parameters, REQUEST_EXTENSIONS, TBSRequest.defaultValues(REQUEST_EXTENSIONS)); 102 } 103 104 if (parameters.schema) { 105 this.fromSchema(parameters.schema); 106 } 107 } 108 109 /** 110 * Returns default values for all class members 111 * @param memberName String name for a class member 112 * @returns Default value 113 */ 114 public static override defaultValues(memberName: typeof TBS): ArrayBuffer; 115 public static override defaultValues(memberName: typeof VERSION): number; 116 public static override defaultValues(memberName: typeof REQUESTOR_NAME): GeneralName; 117 public static override defaultValues(memberName: typeof REQUEST_LIST): Request[]; 118 public static override defaultValues(memberName: typeof REQUEST_EXTENSIONS): Extension[]; 119 public static override defaultValues(memberName: string): any { 120 switch (memberName) { 121 case TBS: 122 return EMPTY_BUFFER; 123 case VERSION: 124 return 0; 125 case REQUESTOR_NAME: 126 return new GeneralName(); 127 case REQUEST_LIST: 128 case REQUEST_EXTENSIONS: 129 return []; 130 default: 131 return super.defaultValues(memberName); 132 } 133 } 134 135 /** 136 * Compare values with default values for all class members 137 * @param memberName String name for a class member 138 * @param memberValue Value to compare with default value 139 */ 140 public static compareWithDefault(memberName: string, memberValue: any): boolean { 141 switch (memberName) { 142 case TBS: 143 return (memberValue.byteLength === 0); 144 case VERSION: 145 return (memberValue === TBSRequest.defaultValues(memberName)); 146 case REQUESTOR_NAME: 147 return ((memberValue.type === GeneralName.defaultValues("type")) && (Object.keys(memberValue.value).length === 0)); 148 case REQUEST_LIST: 149 case REQUEST_EXTENSIONS: 150 return (memberValue.length === 0); 151 default: 152 return super.defaultValues(memberName); 153 } 154 } 155 156 /** 157 * @inheritdoc 158 * @asn ASN.1 schema 159 * ```asn 160 * TBSRequest ::= SEQUENCE { 161 * version [0] EXPLICIT Version DEFAULT v1, 162 * requestorName [1] EXPLICIT GeneralName OPTIONAL, 163 * requestList SEQUENCE OF Request, 164 * requestExtensions [2] EXPLICIT Extensions OPTIONAL } 165 *``` 166 */ 167 public static override schema(parameters: TBSRequestSchema = {}): Schema.SchemaType { 168 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 169 170 return (new asn1js.Sequence({ 171 name: (names.blockName || TBS_REQUEST), 172 value: [ 173 new asn1js.Constructed({ 174 optional: true, 175 idBlock: { 176 tagClass: 3, // CONTEXT-SPECIFIC 177 tagNumber: 0 // [0] 178 }, 179 value: [new asn1js.Integer({ name: (names.TBSRequestVersion || TBS_REQUEST_VERSION) })] 180 }), 181 new asn1js.Constructed({ 182 optional: true, 183 idBlock: { 184 tagClass: 3, // CONTEXT-SPECIFIC 185 tagNumber: 1 // [1] 186 }, 187 value: [GeneralName.schema(names.requestorName || { 188 names: { 189 blockName: TBS_REQUEST_REQUESTOR_NAME 190 } 191 })] 192 }), 193 new asn1js.Sequence({ 194 name: (names.requestList || "TBSRequest.requestList"), 195 value: [ 196 new asn1js.Repeated({ 197 name: (names.requests || TBS_REQUEST_REQUESTS), 198 value: Request.schema(names.requestNames || {}) 199 }) 200 ] 201 }), 202 new asn1js.Constructed({ 203 optional: true, 204 idBlock: { 205 tagClass: 3, // CONTEXT-SPECIFIC 206 tagNumber: 2 // [2] 207 }, 208 value: [Extensions.schema(names.extensions || { 209 names: { 210 blockName: (names.requestExtensions || TBS_REQUEST_REQUEST_EXTENSIONS) 211 } 212 })] 213 }) 214 ] 215 })); 216 } 217 218 public fromSchema(schema: Schema.SchemaType): void { 219 // Clear input data first 220 pvutils.clearProps(schema, CLEAR_PROPS); 221 222 // Check the schema is valid 223 const asn1 = asn1js.compareSchema(schema, 224 schema, 225 TBSRequest.schema() 226 ); 227 AsnError.assertSchema(asn1, this.className); 228 229 // Get internal properties from parsed schema 230 this.tbsView = asn1.result.TBSRequest.valueBeforeDecodeView; 231 232 if (TBS_REQUEST_VERSION in asn1.result) 233 this.version = asn1.result[TBS_REQUEST_VERSION].valueBlock.valueDec; 234 if (TBS_REQUEST_REQUESTOR_NAME in asn1.result) 235 this.requestorName = new GeneralName({ schema: asn1.result[TBS_REQUEST_REQUESTOR_NAME] }); 236 237 this.requestList = Array.from(asn1.result[TBS_REQUEST_REQUESTS], element => new Request({ schema: element })); 238 239 if (TBS_REQUEST_REQUEST_EXTENSIONS in asn1.result) 240 this.requestExtensions = Array.from(asn1.result[TBS_REQUEST_REQUEST_EXTENSIONS].valueBlock.value, element => new Extension({ schema: element })); 241 } 242 243 /** 244 * Convert current object to asn1js object and set correct values 245 * @param encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts. 246 * @returns asn1js object 247 */ 248 public toSchema(encodeFlag = false): asn1js.Sequence { 249 //#region Decode stored TBS value 250 let tbsSchema; 251 252 if (encodeFlag === false) { 253 if (this.tbsView.byteLength === 0) // No stored TBS part 254 return TBSRequest.schema(); 255 256 const asn1 = asn1js.fromBER(this.tbsView); 257 AsnError.assert(asn1, "TBS Request"); 258 if (!(asn1.result instanceof asn1js.Sequence)) { 259 throw new Error("ASN.1 result should be SEQUENCE"); 260 } 261 262 tbsSchema = asn1.result; 263 } 264 //#endregion 265 //#region Create TBS schema via assembling from TBS parts 266 else { 267 const outputArray = []; 268 269 if (this.version !== undefined) { 270 outputArray.push(new asn1js.Constructed({ 271 idBlock: { 272 tagClass: 3, // CONTEXT-SPECIFIC 273 tagNumber: 0 // [0] 274 }, 275 value: [new asn1js.Integer({ value: this.version })] 276 })); 277 } 278 279 if (this.requestorName) { 280 outputArray.push(new asn1js.Constructed({ 281 idBlock: { 282 tagClass: 3, // CONTEXT-SPECIFIC 283 tagNumber: 1 // [1] 284 }, 285 value: [this.requestorName.toSchema()] 286 })); 287 } 288 289 outputArray.push(new asn1js.Sequence({ 290 value: Array.from(this.requestList, o => o.toSchema()) 291 })); 292 293 if (this.requestExtensions) { 294 outputArray.push(new asn1js.Constructed({ 295 idBlock: { 296 tagClass: 3, // CONTEXT-SPECIFIC 297 tagNumber: 2 // [2] 298 }, 299 value: [ 300 new asn1js.Sequence({ 301 value: Array.from(this.requestExtensions, o => o.toSchema()) 302 }) 303 ] 304 })); 305 } 306 307 tbsSchema = new asn1js.Sequence({ 308 value: outputArray 309 }); 310 } 311 //#endregion 312 313 //#region Construct and return new ASN.1 schema for this object 314 return tbsSchema; 315 //#endregion 316 } 317 318 public toJSON(): TBSRequestJson { 319 const res: any = {}; 320 321 if (this.version != undefined) 322 res.version = this.version; 323 324 if (this.requestorName) { 325 res.requestorName = this.requestorName.toJSON(); 326 } 327 328 res.requestList = Array.from(this.requestList, o => o.toJSON()); 329 330 if (this.requestExtensions) { 331 res.requestExtensions = Array.from(this.requestExtensions, o => o.toJSON()); 332 } 333 334 return res; 335 } 336 337 }