parser.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.AsnParser = void 0;
  4. const asn1js = require("asn1js");
  5. const enums_1 = require("./enums");
  6. const converters = require("./converters");
  7. const errors_1 = require("./errors");
  8. const helper_1 = require("./helper");
  9. const storage_1 = require("./storage");
  10. class AsnParser {
  11. static parse(data, target) {
  12. const asn1Parsed = asn1js.fromBER(data);
  13. if (asn1Parsed.result.error) {
  14. throw new Error(asn1Parsed.result.error);
  15. }
  16. const res = this.fromASN(asn1Parsed.result, target);
  17. return res;
  18. }
  19. static fromASN(asn1Schema, target) {
  20. try {
  21. if ((0, helper_1.isConvertible)(target)) {
  22. const value = new target();
  23. return value.fromASN(asn1Schema);
  24. }
  25. const schema = storage_1.schemaStorage.get(target);
  26. storage_1.schemaStorage.cache(target);
  27. let targetSchema = schema.schema;
  28. const choiceResult = this.handleChoiceTypes(asn1Schema, schema, target, targetSchema);
  29. if (choiceResult === null || choiceResult === void 0 ? void 0 : choiceResult.result) {
  30. return choiceResult.result;
  31. }
  32. if (choiceResult === null || choiceResult === void 0 ? void 0 : choiceResult.targetSchema) {
  33. targetSchema = choiceResult.targetSchema;
  34. }
  35. const sequenceResult = this.handleSequenceTypes(asn1Schema, schema, target, targetSchema);
  36. const res = new target();
  37. if ((0, helper_1.isTypeOfArray)(target)) {
  38. return this.handleArrayTypes(asn1Schema, schema, target);
  39. }
  40. this.processSchemaItems(schema, sequenceResult, res);
  41. return res;
  42. }
  43. catch (error) {
  44. if (error instanceof errors_1.AsnSchemaValidationError) {
  45. error.schemas.push(target.name);
  46. }
  47. throw error;
  48. }
  49. }
  50. static handleChoiceTypes(asn1Schema, schema, target, targetSchema) {
  51. if (asn1Schema.constructor === asn1js.Constructed &&
  52. schema.type === enums_1.AsnTypeTypes.Choice &&
  53. asn1Schema.idBlock.tagClass === 3) {
  54. for (const key in schema.items) {
  55. const schemaItem = schema.items[key];
  56. if (schemaItem.context === asn1Schema.idBlock.tagNumber && schemaItem.implicit) {
  57. if (typeof schemaItem.type === "function" &&
  58. storage_1.schemaStorage.has(schemaItem.type)) {
  59. const fieldSchema = storage_1.schemaStorage.get(schemaItem.type);
  60. if (fieldSchema && fieldSchema.type === enums_1.AsnTypeTypes.Sequence) {
  61. const newSeq = new asn1js.Sequence();
  62. if ("value" in asn1Schema.valueBlock &&
  63. Array.isArray(asn1Schema.valueBlock.value) &&
  64. "value" in newSeq.valueBlock) {
  65. newSeq.valueBlock.value = asn1Schema.valueBlock.value;
  66. const fieldValue = this.fromASN(newSeq, schemaItem.type);
  67. const res = new target();
  68. res[key] = fieldValue;
  69. return { result: res };
  70. }
  71. }
  72. }
  73. }
  74. }
  75. }
  76. else if (asn1Schema.constructor === asn1js.Constructed &&
  77. schema.type !== enums_1.AsnTypeTypes.Choice) {
  78. const newTargetSchema = new asn1js.Constructed({
  79. idBlock: {
  80. tagClass: 3,
  81. tagNumber: asn1Schema.idBlock.tagNumber,
  82. },
  83. value: schema.schema.valueBlock.value,
  84. });
  85. for (const key in schema.items) {
  86. delete asn1Schema[key];
  87. }
  88. return { targetSchema: newTargetSchema };
  89. }
  90. return null;
  91. }
  92. static handleSequenceTypes(asn1Schema, schema, target, targetSchema) {
  93. if (schema.type === enums_1.AsnTypeTypes.Sequence) {
  94. const asn1ComparedSchema = asn1js.compareSchema({}, asn1Schema, targetSchema);
  95. if (!asn1ComparedSchema.verified) {
  96. throw new errors_1.AsnSchemaValidationError(`Data does not match to ${target.name} ASN1 schema.${asn1ComparedSchema.result.error ? ` ${asn1ComparedSchema.result.error}` : ""}`);
  97. }
  98. return asn1ComparedSchema;
  99. }
  100. else {
  101. const asn1ComparedSchema = asn1js.compareSchema({}, asn1Schema, targetSchema);
  102. if (!asn1ComparedSchema.verified) {
  103. throw new errors_1.AsnSchemaValidationError(`Data does not match to ${target.name} ASN1 schema.${asn1ComparedSchema.result.error ? ` ${asn1ComparedSchema.result.error}` : ""}`);
  104. }
  105. return asn1ComparedSchema;
  106. }
  107. }
  108. static processRepeatedField(asn1Elements, asn1Index, schemaItem) {
  109. let elementsToProcess = asn1Elements.slice(asn1Index);
  110. if (elementsToProcess.length === 1 && elementsToProcess[0].constructor.name === "Sequence") {
  111. const seq = elementsToProcess[0];
  112. if (seq.valueBlock && seq.valueBlock.value && Array.isArray(seq.valueBlock.value)) {
  113. elementsToProcess = seq.valueBlock.value;
  114. }
  115. }
  116. if (typeof schemaItem.type === "number") {
  117. const converter = converters.defaultConverter(schemaItem.type);
  118. if (!converter)
  119. throw new Error(`No converter for ASN.1 type ${schemaItem.type}`);
  120. return elementsToProcess
  121. .filter((el) => el && el.valueBlock)
  122. .map((el) => {
  123. try {
  124. return converter.fromASN(el);
  125. }
  126. catch {
  127. return undefined;
  128. }
  129. })
  130. .filter((v) => v !== undefined);
  131. }
  132. else {
  133. return elementsToProcess
  134. .filter((el) => el && el.valueBlock)
  135. .map((el) => {
  136. try {
  137. return this.fromASN(el, schemaItem.type);
  138. }
  139. catch {
  140. return undefined;
  141. }
  142. })
  143. .filter((v) => v !== undefined);
  144. }
  145. }
  146. static processPrimitiveField(asn1Element, schemaItem) {
  147. const converter = converters.defaultConverter(schemaItem.type);
  148. if (!converter)
  149. throw new Error(`No converter for ASN.1 type ${schemaItem.type}`);
  150. return converter.fromASN(asn1Element);
  151. }
  152. static isOptionalChoiceField(schemaItem) {
  153. return (schemaItem.optional &&
  154. typeof schemaItem.type === "function" &&
  155. storage_1.schemaStorage.has(schemaItem.type) &&
  156. storage_1.schemaStorage.get(schemaItem.type).type === enums_1.AsnTypeTypes.Choice);
  157. }
  158. static processOptionalChoiceField(asn1Element, schemaItem) {
  159. try {
  160. const value = this.fromASN(asn1Element, schemaItem.type);
  161. return { processed: true, value };
  162. }
  163. catch (err) {
  164. if (err instanceof errors_1.AsnSchemaValidationError &&
  165. /Wrong values for Choice type/.test(err.message)) {
  166. return { processed: false };
  167. }
  168. throw err;
  169. }
  170. }
  171. static handleArrayTypes(asn1Schema, schema, target) {
  172. if (!("value" in asn1Schema.valueBlock && Array.isArray(asn1Schema.valueBlock.value))) {
  173. throw new Error(`Cannot get items from the ASN.1 parsed value. ASN.1 object is not constructed.`);
  174. }
  175. const itemType = schema.itemType;
  176. if (typeof itemType === "number") {
  177. const converter = converters.defaultConverter(itemType);
  178. if (!converter) {
  179. throw new Error(`Cannot get default converter for array item of ${target.name} ASN1 schema`);
  180. }
  181. return target.from(asn1Schema.valueBlock.value, (element) => converter.fromASN(element));
  182. }
  183. else {
  184. return target.from(asn1Schema.valueBlock.value, (element) => this.fromASN(element, itemType));
  185. }
  186. }
  187. static processSchemaItems(schema, asn1ComparedSchema, res) {
  188. for (const key in schema.items) {
  189. const asn1SchemaValue = asn1ComparedSchema.result[key];
  190. if (!asn1SchemaValue) {
  191. continue;
  192. }
  193. const schemaItem = schema.items[key];
  194. const schemaItemType = schemaItem.type;
  195. let parsedValue;
  196. if (typeof schemaItemType === "number" || (0, helper_1.isConvertible)(schemaItemType)) {
  197. parsedValue = this.processPrimitiveSchemaItem(asn1SchemaValue, schemaItem, schemaItemType);
  198. }
  199. else {
  200. parsedValue = this.processComplexSchemaItem(asn1SchemaValue, schemaItem, schemaItemType);
  201. }
  202. if (parsedValue &&
  203. typeof parsedValue === "object" &&
  204. "value" in parsedValue &&
  205. "raw" in parsedValue) {
  206. res[key] = parsedValue.value;
  207. res[`${key}Raw`] = parsedValue.raw;
  208. }
  209. else {
  210. res[key] = parsedValue;
  211. }
  212. }
  213. }
  214. static processPrimitiveSchemaItem(asn1SchemaValue, schemaItem, schemaItemType) {
  215. var _a;
  216. const converter = (_a = schemaItem.converter) !== null && _a !== void 0 ? _a : ((0, helper_1.isConvertible)(schemaItemType)
  217. ? new schemaItemType()
  218. : null);
  219. if (!converter) {
  220. throw new Error("Converter is empty");
  221. }
  222. if (schemaItem.repeated) {
  223. return this.processRepeatedPrimitiveItem(asn1SchemaValue, schemaItem, converter);
  224. }
  225. else {
  226. return this.processSinglePrimitiveItem(asn1SchemaValue, schemaItem, schemaItemType, converter);
  227. }
  228. }
  229. static processRepeatedPrimitiveItem(asn1SchemaValue, schemaItem, converter) {
  230. if (schemaItem.implicit) {
  231. const Container = schemaItem.repeated === "sequence" ? asn1js.Sequence : asn1js.Set;
  232. const newItem = new Container();
  233. newItem.valueBlock = asn1SchemaValue.valueBlock;
  234. const newItemAsn = asn1js.fromBER(newItem.toBER(false));
  235. if (newItemAsn.offset === -1) {
  236. throw new Error(`Cannot parse the child item. ${newItemAsn.result.error}`);
  237. }
  238. if (!("value" in newItemAsn.result.valueBlock &&
  239. Array.isArray(newItemAsn.result.valueBlock.value))) {
  240. throw new Error("Cannot get items from the ASN.1 parsed value. ASN.1 object is not constructed.");
  241. }
  242. const value = newItemAsn.result.valueBlock.value;
  243. return Array.from(value, (element) => converter.fromASN(element));
  244. }
  245. else {
  246. return Array.from(asn1SchemaValue, (element) => converter.fromASN(element));
  247. }
  248. }
  249. static processSinglePrimitiveItem(asn1SchemaValue, schemaItem, schemaItemType, converter) {
  250. let value = asn1SchemaValue;
  251. if (schemaItem.implicit) {
  252. let newItem;
  253. if ((0, helper_1.isConvertible)(schemaItemType)) {
  254. newItem = new schemaItemType().toSchema("");
  255. }
  256. else {
  257. const Asn1TypeName = enums_1.AsnPropTypes[schemaItemType];
  258. const Asn1Type = asn1js[Asn1TypeName];
  259. if (!Asn1Type) {
  260. throw new Error(`Cannot get '${Asn1TypeName}' class from asn1js module`);
  261. }
  262. newItem = new Asn1Type();
  263. }
  264. newItem.valueBlock = value.valueBlock;
  265. value = asn1js.fromBER(newItem.toBER(false)).result;
  266. }
  267. return converter.fromASN(value);
  268. }
  269. static processComplexSchemaItem(asn1SchemaValue, schemaItem, schemaItemType) {
  270. if (schemaItem.repeated) {
  271. if (!Array.isArray(asn1SchemaValue)) {
  272. throw new Error("Cannot get list of items from the ASN.1 parsed value. ASN.1 value should be iterable.");
  273. }
  274. return Array.from(asn1SchemaValue, (element) => this.fromASN(element, schemaItemType));
  275. }
  276. else {
  277. const valueToProcess = this.handleImplicitTagging(asn1SchemaValue, schemaItem, schemaItemType);
  278. if (this.isOptionalChoiceField(schemaItem)) {
  279. try {
  280. return this.fromASN(valueToProcess, schemaItemType);
  281. }
  282. catch (err) {
  283. if (err instanceof errors_1.AsnSchemaValidationError &&
  284. /Wrong values for Choice type/.test(err.message)) {
  285. return undefined;
  286. }
  287. throw err;
  288. }
  289. }
  290. else {
  291. const parsedValue = this.fromASN(valueToProcess, schemaItemType);
  292. if (schemaItem.raw) {
  293. return {
  294. value: parsedValue,
  295. raw: asn1SchemaValue.valueBeforeDecodeView,
  296. };
  297. }
  298. return parsedValue;
  299. }
  300. }
  301. }
  302. static handleImplicitTagging(asn1SchemaValue, schemaItem, schemaItemType) {
  303. if (schemaItem.implicit && typeof schemaItem.context === "number") {
  304. const schema = storage_1.schemaStorage.get(schemaItemType);
  305. if (schema.type === enums_1.AsnTypeTypes.Sequence) {
  306. const newSeq = new asn1js.Sequence();
  307. if ("value" in asn1SchemaValue.valueBlock &&
  308. Array.isArray(asn1SchemaValue.valueBlock.value) &&
  309. "value" in newSeq.valueBlock) {
  310. newSeq.valueBlock.value = asn1SchemaValue.valueBlock.value;
  311. return newSeq;
  312. }
  313. }
  314. else if (schema.type === enums_1.AsnTypeTypes.Set) {
  315. const newSet = new asn1js.Set();
  316. if ("value" in asn1SchemaValue.valueBlock &&
  317. Array.isArray(asn1SchemaValue.valueBlock.value) &&
  318. "value" in newSet.valueBlock) {
  319. newSet.valueBlock.value = asn1SchemaValue.valueBlock.value;
  320. return newSet;
  321. }
  322. }
  323. }
  324. return asn1SchemaValue;
  325. }
  326. }
  327. exports.AsnParser = AsnParser;