JavaScript generic ASN.1 parser (mirror)
fork

Configure Feed

Select the types of activity you want to include in your feed.

Separate common definitions to a new (static) class.

+123 -90
+118
defs.js
··· 1 + // ASN.1 RFC definitions matcher 2 + // Copyright (c) 2023-2023 Lapo Luchini <lapo@lapo.it> 3 + 4 + // Permission to use, copy, modify, and/or distribute this software for any 5 + // purpose with or without fee is hereby granted, provided that the above 6 + // copyright notice and this permission notice appear in all copies. 7 + // 8 + // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + 16 + (typeof define != 'undefined' ? define : function (factory) { 'use strict'; 17 + if (typeof module == 'object') module.exports = factory(); 18 + else window.defs = factory(); 19 + })(function () { 20 + 'use strict'; 21 + 22 + const rfc = require('./rfcdef'); 23 + 24 + function translate(def, tn) { 25 + const id = def?.id; 26 + if (def?.type == 'tag' && !def.explicit) 27 + // def.type = def.content[0].type; 28 + def = def.content[0].type; 29 + while (def?.type == 'defined' || def?.type?.type == 'defined') { 30 + const name = def?.type?.type ? def.type.name : def.name; 31 + def = Object.assign({}, def); 32 + def.type = Defs.searchType(name).type; 33 + } 34 + if (def?.type?.name == 'CHOICE') { 35 + for (let c of def.type.content) { 36 + c = translate(c); 37 + if (tn == c.type.name || tn == c.name) { 38 + def = Object.assign({}, def); 39 + def.type = c.type.name ? c.type : c; 40 + break; 41 + } 42 + } 43 + } 44 + if (id) 45 + def = Object.assign({}, def, { id }); 46 + return def ?? { type: {} }; 47 + } 48 + 49 + function firstUpper(s) { 50 + return s[0].toUpperCase() + s.slice(1); 51 + } 52 + 53 + class Defs { 54 + 55 + static moduleAndType(mod, name) { 56 + return Object.assign({ module: { oid: mod.oid, name: mod.name, source: mod.source } }, mod.types[name]); 57 + } 58 + 59 + static searchType(name) { 60 + for (const mod of Object.values(rfc)) 61 + if (name in mod.types) { 62 + // console.log(name + ' found in ' + r.name); 63 + // return r.types[name]; 64 + return Defs.moduleAndType(mod, name); 65 + } 66 + throw 'Type not found: ' + name; 67 + } 68 + 69 + static match(value, def, stats = { total: 0, recognized: 0, defs: {} }) { 70 + value.def = {}; 71 + let tn = value.typeName(); 72 + def = translate(def, tn); 73 + ++stats.total; 74 + if (def?.type) { 75 + value.def = def; 76 + if (def.id || def.name) ++stats.recognized; 77 + } 78 + if (value.sub !== null) { 79 + if (def?.type?.type) 80 + def = def.type; 81 + let j = def?.content ? 0 : -1; 82 + for (const subval of value.sub) { 83 + let type; 84 + if (j >= 0) { 85 + if (def.typeOf) 86 + type = def.content[0]; 87 + else { 88 + let tn = subval.typeName(); //.replaceAll('_', ' '); 89 + do { 90 + type = def.content[j++]; 91 + // type = translate(type, tn); 92 + if (type?.type?.type) 93 + type = type.type; 94 + } while (type && ('optional' in type || 'default' in type) && type.name != 'ANY' && type.name != tn); 95 + if (type?.type == 'defined') 96 + stats.defs[type.id] = subval.content().split(/\n/); 97 + else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) // hope current OIDs contain the type name (will need to parse from RFC itself) 98 + type = searchType(firstUpper(stats.defs[type.definedBy][1])); 99 + } 100 + } 101 + Defs.match(subval, type, stats); 102 + } 103 + } 104 + return stats; 105 + } 106 + 107 + } 108 + 109 + Defs.RFC = rfc; 110 + 111 + Defs.commonTypes = [ 112 + ['X.509 certificate', '1.3.6.1.5.5.7.0.18', 'Certificate' ], 113 + [ 'CMS / PKCS#7 envelope', '1.2.840.113549.1.9.16.0.14', 'ContentInfo' ], 114 + ].map(arr => ({ description: arr[0], ...Defs.moduleAndType(rfc[arr[1]], arr[2]) })); 115 + 116 + return Defs; 117 + 118 + });
+5 -90
dumpASN1.js
··· 5 5 fs = require('fs'), 6 6 Base64 = require('./base64'), 7 7 ASN1 = require('./asn1'), 8 - rfc = require('./rfcdef'), 8 + Defs = require('./defs'), 9 9 colYellow = '\x1b[33m', 10 10 colBlue = '\x1b[34m', 11 - colReset = '\x1b[0m', 12 - commonTypes = [ 13 - { description: 'X.509 certificate', ...moduleAndType(rfc['1.3.6.1.5.5.7.0.18'], 'Certificate') }, 14 - { description: 'CMS / PKCS#7 envelope', ...moduleAndType(rfc['1.2.840.113549.1.9.16.0.14'], 'ContentInfo') }, 15 - ]; 16 - 17 - function moduleAndType(mod, name) { 18 - return Object.assign({ module: { oid: mod.oid, name: mod.name, source: mod.source } }, mod.types[name]); 19 - } 20 - 21 - function searchType(name) { 22 - for (const mod of Object.values(rfc)) 23 - if (name in mod.types) { 24 - // console.log(name + ' found in ' + r.name); 25 - // return r.types[name]; 26 - return moduleAndType(mod, name); 27 - } 28 - throw 'Type not found: ' + name; 29 - } 30 - 31 - function translate(def, tn) { 32 - const id = def?.id; 33 - if (def?.type == 'tag' && !def.explicit) 34 - // def.type = def.content[0].type; 35 - def = def.content[0].type; 36 - while (def?.type == 'defined' || def?.type?.type == 'defined') { 37 - const name = def?.type?.type ? def.type.name : def.name; 38 - def = Object.assign({}, def); 39 - def.type = searchType(name).type; 40 - } 41 - if (def?.type?.name == 'CHOICE') { 42 - for (let c of def.type.content) { 43 - c = translate(c); 44 - if (tn == c.type.name || tn == c.name) { 45 - def = Object.assign({}, def); 46 - def.type = c.type.name ? c.type : c; 47 - break; 48 - } 49 - } 50 - } 51 - if (id) 52 - def = Object.assign({}, def, { id }); 53 - return def ?? { type: {} }; 54 - } 55 - 56 - function firstUpper(s) { 57 - return s[0].toUpperCase() + s.slice(1); 58 - } 59 - 60 - function applyDef(value, def, stats = { total: 0, recognized: 0, defs: {} }) { 61 - value.def = {}; 62 - let tn = value.typeName(); 63 - def = translate(def, tn); 64 - ++stats.total; 65 - if (def?.type) { 66 - value.def = def; 67 - if (def.id || def.name) ++stats.recognized; 68 - } 69 - if (value.sub !== null) { 70 - if (def?.type?.type) 71 - def = def.type; 72 - let j = def?.content ? 0 : -1; 73 - for (const subval of value.sub) { 74 - let type; 75 - if (j >= 0) { 76 - if (def.typeOf) 77 - type = def.content[0]; 78 - else { 79 - let tn = subval.typeName(); //.replaceAll('_', ' '); 80 - do { 81 - type = def.content[j++]; 82 - // type = translate(type, tn); 83 - if (type?.type?.type) 84 - type = type.type; 85 - } while (type && ('optional' in type || 'default' in type) && type.name != 'ANY' && type.name != tn); 86 - if (type?.type == 'defined') 87 - stats.defs[type.id] = subval.content().split(/\n/); 88 - else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) // hope current OIDs contain the type name (will need to parse from RFC itself) 89 - type = searchType(firstUpper(stats.defs[type.definedBy][1])); 90 - } 91 - } 92 - applyDef(subval, type, stats); 93 - } 94 - } 95 - return stats; 96 - } 11 + colReset = '\x1b[0m'; 97 12 98 13 function print(value, indent) { 99 14 if (indent === undefined) indent = ''; ··· 132 47 let result = ASN1.decode(content); 133 48 content = null; 134 49 const t0 = performance.now(); 135 - const types = commonTypes 50 + const types = Defs.commonTypes 136 51 .map(type => { 137 - const stats = applyDef(result, type); 52 + const stats = Defs.match(result, type); 138 53 return { type, match: stats.recognized / stats.total }; 139 54 }) 140 55 .sort((a, b) => b.match - a.match); ··· 142 57 console.log('Parsed in ' + (t1 - t0).toFixed(2) + ' ms; possible types:'); 143 58 for (const t of types) 144 59 console.log((t.match * 100).toFixed(2).padStart(6) + '% ' + t.type.description); 145 - applyDef(result, types[0].match >= 0.1 ? types[0].type : null); 60 + Defs.match(result, types[0].match >= 0.1 ? types[0].type : null); 146 61 console.log('Parsed as:', result.def); 147 62 // const type = searchType(process.argv[2]); 148 63 // const stats = applyDef(result, type);