From 398defae076eb59056558d16f6c88e6340c486a3 Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Thu, 27 Oct 2022 20:32:39 +0000 Subject: [PATCH 1/4] More generic type searching. Still working with `Certificate`. --- dumpASN1.js | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/dumpASN1.js b/dumpASN1.js index d317d12..96c9c73 100755 --- a/dumpASN1.js +++ b/dumpASN1.js @@ -10,22 +10,31 @@ const colBlue = "\x1b[34m", colReset = "\x1b[0m"; +function searchType(name) { + for (const r of Object.values(rfc)) + if (name in r.types) { + // console.log(name + ' found in ' + r.name); + return r.types[name]; + } + throw 'Type not found: ' + name; +} + function translate(def) { if (def?.type?.type) def = def.type; while (def?.type == 'defined') { const name = def.name; - try { - def = rfc['1.3.6.1.5.5.7.0.18'].types[name].type; - } catch (e) { - throw 'Type not found: ' + name; - } + def = searchType(name).type; } return def ?? {}; } -function print(value, def, indent) { +function print(value, def, stats, indent) { if (indent === undefined) indent = ''; + if (stats) { + stats.total ??= 0; + stats.recognized ??= 0; + } // console.log(def); let deftype = translate(def); let tn = value.typeName(); @@ -40,8 +49,10 @@ function print(value, def, indent) { } if (tn.replaceAll('_', ' ') != deftype.name && deftype.name != 'ANY') def = null; + if (stats) ++stats.total; let name = ''; if (def) { + if (stats) ++stats.recognized; if (def.id) name += colBlue + def.id + colReset; if (def.type == 'defined') name = (name ? name + ' ' : '') + def.name; if (name) name += ' '; @@ -71,20 +82,22 @@ function print(value, def, indent) { let tn = subval.typeName().replaceAll('_', ' '); do { type = deftype.content[j++]; - } while (('optional' in type || 'default' in type) && type.name != tn); + } while (type && ('optional' in type || 'default' in type) && type.name != tn); } } - s += print(subval, type, indent); + s += print(subval, type, stats, indent); } } return s; } -let content = fs.readFileSync(process.argv[2]); +let content = fs.readFileSync(process.argv[3]); try { // try PEM first content = Base64.unarmor(content); } catch (e) { // try DER/BER then } let result = ASN1.decode(content); content = null; -console.log(print(result, rfc['1.3.6.1.5.5.7.0.18'].types.Certificate)); +let stats = {}; +console.log(print(result, searchType(process.argv[2]), stats)); +console.log('Stats:', (stats.recognized * 100 / stats.total).toFixed(2) + '%'); -- 2.51.2 From c29661d4fd379ddb4e6929500fa5bd8481405f78 Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Tue, 1 Nov 2022 20:56:56 +0000 Subject: [PATCH 2/4] Add somewhat support for `ContentInfo`. --- dumpASN1.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dumpASN1.js b/dumpASN1.js index 96c9c73..861cd55 100755 --- a/dumpASN1.js +++ b/dumpASN1.js @@ -29,12 +29,16 @@ function translate(def) { return def ?? {}; } +function firstUpper(s) { + return s[0].toUpperCase() + s.slice(1); +} + function print(value, def, stats, indent) { if (indent === undefined) indent = ''; - if (stats) { - stats.total ??= 0; - stats.recognized ??= 0; - } + stats ??= {}; + stats.total ??= 0; + stats.recognized ??= 0; + stats.defs ??= {}; // console.log(def); let deftype = translate(def); let tn = value.typeName(); @@ -83,6 +87,10 @@ function print(value, def, stats, indent) { do { type = deftype.content[j++]; } while (type && ('optional' in type || 'default' in type) && type.name != tn); + if (type?.type == 'defined') + stats.defs[type.id] = subval.content().split(/\n/); + else if (type?.type?.definedBy) // hope current OIDs contain the type name (will need to parse from RFC itself) + type = searchType(firstUpper(stats.defs[type.type.definedBy][1])); } } s += print(subval, type, stats, indent); @@ -101,3 +109,4 @@ content = null; let stats = {}; console.log(print(result, searchType(process.argv[2]), stats)); console.log('Stats:', (stats.recognized * 100 / stats.total).toFixed(2) + '%'); +console.log('Defs:', stats.defs); -- 2.51.2 From 7334473b5a20084db994dec13cc32ad1cbf131d7 Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Wed, 2 Nov 2022 22:56:00 +0000 Subject: [PATCH 3/4] Correctly use module default implicit/explicit setting. --- parseRFC.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parseRFC.js b/parseRFC.js index 0e20b95..6ed52f7 100755 --- a/parseRFC.js +++ b/parseRFC.js @@ -244,6 +244,7 @@ Parser.prototype.parseTaggedType = function () { let t = this.parseNumber(); this.expectToken(']'); let plicit = this.getRegEx('explicit/implicit', reTagType); + if (plicit == '') plicit = currentMod.tagDefault; let x = this.parseType(); return { name: '[' + t + ']', @@ -429,7 +430,7 @@ Parser.prototype.parseModuleDefinition = function (file) { currentMod = mod; // for deeply nested parsers mod.source = file; this.expectToken('DEFINITIONS'); - mod.tagDefault = this.getRegEx('tag default', reTagDefault); + mod.tagDefault = this.getRegEx('tag default', reTagDefault).split(' ')[0]; this.expectToken('::='); this.expectToken('BEGIN'); //TODO this.tryToken('EXPORTS') -- 2.51.2 From 24d9234fe33f47ec508d89308c4464c753a58385 Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Wed, 2 Nov 2022 23:08:51 +0000 Subject: [PATCH 4/4] Complete support for `ContentInfo`. --- dumpASN1.js | 76 +++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/dumpASN1.js b/dumpASN1.js index 861cd55..cfe29a7 100755 --- a/dumpASN1.js +++ b/dumpASN1.js @@ -19,14 +19,29 @@ function searchType(name) { throw 'Type not found: ' + name; } -function translate(def) { - if (def?.type?.type) - def = def.type; - while (def?.type == 'defined') { - const name = def.name; - def = searchType(name).type; +function translate(def, tn) { + const id = def?.id; + if (def?.type == 'tag' && !def.explicit) + // def.type = def.content[0].type; + def = def.content[0].type; + while (def?.type == 'defined' || def?.type?.type == 'defined') { + const name = def?.type?.type ? def.type.name : def.name; + def = Object.assign({}, def); + def.type = searchType(name).type; } - return def ?? {}; + if (def?.type?.name == 'CHOICE') { + for (let c of def.type.content) { + c = translate(c); + if (tn == c.type.name || tn == c.name) { + def = Object.assign({}, def); + def.type = c.type.name ? c.type : c; + break; + } + } + } + if (id) + def = Object.assign({}, def, { id }); + return def ?? { type: {} }; } function firstUpper(s) { @@ -39,26 +54,15 @@ function print(value, def, stats, indent) { stats.total ??= 0; stats.recognized ??= 0; stats.defs ??= {}; - // console.log(def); - let deftype = translate(def); let tn = value.typeName(); - if (deftype.name == 'CHOICE') { - for (let c of deftype.content) { - c = translate(c); - if (tn == c.name) { - deftype = translate(c); - break; - } - } - } - if (tn.replaceAll('_', ' ') != deftype.name && deftype.name != 'ANY') - def = null; + def = translate(def, tn); + tn = tn.replaceAll('_', ' '); if (stats) ++stats.total; let name = ''; - if (def) { - if (stats) ++stats.recognized; + if (def?.type) { if (def.id) name += colBlue + def.id + colReset; - if (def.type == 'defined') name = (name ? name + ' ' : '') + def.name; + if (typeof def.type == 'object' && def.name) name = (name ? name + ' ' : '') + def.name; + if (stats && name != '') ++stats.recognized; if (name) name += ' '; } let s = indent + name + colYellow + value.typeName() + colReset + " @" + value.stream.pos; @@ -75,22 +79,26 @@ function print(value, def, stats, indent) { s += "\n"; if (value.sub !== null) { indent += ' '; - let j = deftype?.content ? 0 : -1; - for (let i = 0, max = value.sub.length; i < max; ++i) { - const subval = value.sub[i]; + if (def?.type?.type) + def = def.type; + let j = def?.content ? 0 : -1; + for (const subval of value.sub) { let type; if (j >= 0) { - if (deftype?.typeOf) - type = deftype.content[0]; + if (def.typeOf) + type = def.content[0]; else { - let tn = subval.typeName().replaceAll('_', ' '); + let tn = subval.typeName(); //.replaceAll('_', ' '); do { - type = deftype.content[j++]; - } while (type && ('optional' in type || 'default' in type) && type.name != tn); + type = def.content[j++]; + // type = translate(type, tn); + if (type?.type?.type) + type = type.type; + } while (type && ('optional' in type || 'default' in type) && type.name != 'ANY' && type.name != tn); if (type?.type == 'defined') stats.defs[type.id] = subval.content().split(/\n/); - else if (type?.type?.definedBy) // hope current OIDs contain the type name (will need to parse from RFC itself) - type = searchType(firstUpper(stats.defs[type.type.definedBy][1])); + else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) // hope current OIDs contain the type name (will need to parse from RFC itself) + type = searchType(firstUpper(stats.defs[type.definedBy][1])); } } s += print(subval, type, stats, indent); @@ -109,4 +117,4 @@ content = null; let stats = {}; console.log(print(result, searchType(process.argv[2]), stats)); console.log('Stats:', (stats.recognized * 100 / stats.total).toFixed(2) + '%'); -console.log('Defs:', stats.defs); +// console.log('Defs:', stats.defs); -- 2.51.2