import * as asn1js from "asn1js"; import { getParametersValue, clearProps } from "pvutils"; import GeneralName from "./GeneralName.js"; import Request from "./Request.js"; import Extension from "./Extension.js"; import Extensions from "./Extensions.js"; //************************************************************************************** /** * Class from RFC6960 */ export default class TBSRequest { //********************************************************************************** /** * Constructor for TBSRequest class * @param {Object} [parameters={}] * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from */ constructor(parameters = {}) { //region Internal properties of the object /** * @type {ArrayBuffer} * @desc tbs */ this.tbs = getParametersValue(parameters, "tbs", TBSRequest.defaultValues("tbs")); if("version" in parameters) /** * @type {number} * @desc version */ this.version = getParametersValue(parameters, "version", TBSRequest.defaultValues("version")); if("requestorName" in parameters) /** * @type {GeneralName} * @desc requestorName */ this.requestorName = getParametersValue(parameters, "requestorName", TBSRequest.defaultValues("requestorName")); /** * @type {Array.} * @desc requestList */ this.requestList = getParametersValue(parameters, "requestList", TBSRequest.defaultValues("requestList")); if("requestExtensions" in parameters) /** * @type {Array.} * @desc requestExtensions */ this.requestExtensions = getParametersValue(parameters, "requestExtensions", TBSRequest.defaultValues("requestExtensions")); //endregion //region If input argument array contains "schema" for this object if("schema" in parameters) this.fromSchema(parameters.schema); //endregion } //********************************************************************************** /** * Return default values for all class members * @param {string} memberName String name for a class member */ static defaultValues(memberName) { switch(memberName) { case "tbs": return new ArrayBuffer(0); case "version": return 0; case "requestorName": return new GeneralName(); case "requestList": case "requestExtensions": return []; default: throw new Error(`Invalid member name for TBSRequest class: ${memberName}`); } } //********************************************************************************** /** * Compare values with default values for all class members * @param {string} memberName String name for a class member * @param {*} memberValue Value to compare with default value */ static compareWithDefault(memberName, memberValue) { switch(memberName) { case "tbs": return (memberValue.byteLength === 0); case "version": return (memberValue === TBSRequest.defaultValues(memberName)); case "requestorName": return ((memberValue.type === GeneralName.defaultValues("type")) && (Object.keys(memberValue.value).length === 0)); case "requestList": case "requestExtensions": return (memberValue.length === 0); default: throw new Error(`Invalid member name for TBSRequest class: ${memberName}`); } } //********************************************************************************** /** * Return value of pre-defined ASN.1 schema for current class * * ASN.1 schema: * ```asn1 * TBSRequest ::= SEQUENCE { * version [0] EXPLICIT Version DEFAULT v1, * requestorName [1] EXPLICIT GeneralName OPTIONAL, * requestList SEQUENCE OF Request, * requestExtensions [2] EXPLICIT Extensions OPTIONAL } * ``` * * @param {Object} parameters Input parameters for the schema * @returns {Object} asn1js schema object */ static schema(parameters = {}) { /** * @type {Object} * @property {string} [blockName] * @property {string} [TBSRequestVersion] * @property {string} [requestorName] * @property {string} [requestList] * @property {string} [requests] * @property {string} [requestNames] * @property {string} [extensions] * @property {string} [requestExtensions] */ const names = getParametersValue(parameters, "names", {}); return (new asn1js.Sequence({ name: (names.blockName || "TBSRequest"), value: [ new asn1js.Constructed({ optional: true, idBlock: { tagClass: 3, // CONTEXT-SPECIFIC tagNumber: 0 // [0] }, value: [new asn1js.Integer({ name: (names.TBSRequestVersion || "TBSRequest.version") })] }), new asn1js.Constructed({ optional: true, idBlock: { tagClass: 3, // CONTEXT-SPECIFIC tagNumber: 1 // [1] }, value: [GeneralName.schema(names.requestorName || { names: { blockName: "TBSRequest.requestorName" } })] }), new asn1js.Sequence({ name: (names.requestList || "TBSRequest.requestList"), value: [ new asn1js.Repeated({ name: (names.requests || "TBSRequest.requests"), value: Request.schema(names.requestNames || {}) }) ] }), new asn1js.Constructed({ optional: true, idBlock: { tagClass: 3, // CONTEXT-SPECIFIC tagNumber: 2 // [2] }, value: [Extensions.schema(names.extensions || { names: { blockName: (names.requestExtensions || "TBSRequest.requestExtensions") } })] }) ] })); } //********************************************************************************** /** * Convert parsed asn1js object into current class * @param {!Object} schema */ fromSchema(schema) { //region Clear input data first clearProps(schema, [ "TBSRequest", "TBSRequest.version", "TBSRequest.requestorName", "TBSRequest.requests", "TBSRequest.requestExtensions" ]); //endregion //region Check the schema is valid const asn1 = asn1js.compareSchema(schema, schema, TBSRequest.schema() ); if(asn1.verified === false) throw new Error("Object's schema was not verified against input data for TBSRequest"); //endregion //region Get internal properties from parsed schema this.tbs = asn1.result.TBSRequest.valueBeforeDecode; if("TBSRequest.version" in asn1.result) this.version = asn1.result["TBSRequest.version"].valueBlock.valueDec; if("TBSRequest.requestorName" in asn1.result) this.requestorName = new GeneralName({ schema: asn1.result["TBSRequest.requestorName"] }); this.requestList = Array.from(asn1.result["TBSRequest.requests"], element => new Request({ schema: element })); if("TBSRequest.requestExtensions" in asn1.result) this.requestExtensions = Array.from(asn1.result["TBSRequest.requestExtensions"].valueBlock.value, element => new Extension({ schema: element })); //endregion } //********************************************************************************** /** * Convert current object to asn1js object and set correct values * @param {boolean} 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. * @returns {Object} asn1js object */ toSchema(encodeFlag = false) { //region Decode stored TBS value let tbsSchema; if(encodeFlag === false) { if(this.tbs.byteLength === 0) // No stored TBS part return TBSRequest.schema(); tbsSchema = asn1js.fromBER(this.tbs).result; } //endregion //region Create TBS schema via assembling from TBS parts else { const outputArray = []; if("version" in this) { outputArray.push(new asn1js.Constructed({ idBlock: { tagClass: 3, // CONTEXT-SPECIFIC tagNumber: 0 // [0] }, value: [new asn1js.Integer({ value: this.version })] })); } if("requestorName" in this) { outputArray.push(new asn1js.Constructed({ idBlock: { tagClass: 3, // CONTEXT-SPECIFIC tagNumber: 1 // [1] }, value: [this.requestorName.toSchema()] })); } outputArray.push(new asn1js.Sequence({ value: Array.from(this.requestList, element => element.toSchema()) })); if("requestExtensions" in this) { outputArray.push(new asn1js.Constructed({ idBlock: { tagClass: 3, // CONTEXT-SPECIFIC tagNumber: 2 // [2] }, value: [ new asn1js.Sequence({ value: Array.from(this.requestExtensions, element => element.toSchema()) }) ] })); } tbsSchema = new asn1js.Sequence({ value: outputArray }); } //endregion //region Construct and return new ASN.1 schema for this object return tbsSchema; //endregion } //********************************************************************************** /** * Convertion for the class to JSON object * @returns {Object} */ toJSON() { const _object = {}; if("version" in this) _object.version = this.version; if("requestorName" in this) _object.requestorName = this.requestorName.toJSON(); _object.requestList = Array.from(this.requestList, element => element.toJSON()); if("requestExtensions" in this) _object.requestExtensions = Array.from(this.requestExtensions, element => element.toJSON()); return _object; } //********************************************************************************** } //**************************************************************************************