parser.js 14 KB

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