JavaScript generic ASN.1 parser (mirror)
at github-64 136 lines 5.5 kB view raw
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(function (name) { return require(name); }); 18 else window.defs = factory(function (name) { return window[name.substring(2)]; }); 19})(function (require) { 20'use strict'; 21 22const rfc = require('./rfcdef'); 23 24function translate(def, tn, stats) { 25 if (def?.type == 'tag' && !def.explicit) 26 // def.type = def.content[0].type; 27 def = def.content[0].type; 28 if (def?.definedBy) 29 try { 30 // hope current OIDs contain the type name (will need to parse from RFC itself) 31 def = Defs.searchType(firstUpper(stats.defs[def.definedBy][1])); 32 } catch (e) {} 33 while (def?.type == 'defined' || def?.type?.type == 'defined') { 34 const name = def?.type?.type ? def.type.name : def.name; 35 def = Object.assign({}, def); 36 def.type = Defs.searchType(name).type; 37 } 38 if (def?.type?.name == 'CHOICE') { 39 for (let c of def.type.content) { 40 c = translate(c); 41 if (tn == c.type.name || tn == c.name) { 42 def = Object.assign({}, def); 43 def.type = c.type.name ? c.type : c; 44 break; 45 } 46 } 47 } 48 const id = def?.id; 49 if (id) 50 def = Object.assign({}, def, { id }); 51 return def ?? { type: {} }; 52} 53 54function firstUpper(s) { 55 return s[0].toUpperCase() + s.slice(1); 56} 57 58class Defs { 59 60 static moduleAndType(mod, name) { 61 return Object.assign({ module: { oid: mod.oid, name: mod.name, source: mod.source } }, mod.types[name]); 62 } 63 64 static searchType(name) { 65 for (const mod of Object.values(rfc)) 66 if (name in mod.types) { 67 // console.log(name + ' found in ' + r.name); 68 // return r.types[name]; 69 return Defs.moduleAndType(mod, name); 70 } 71 throw 'Type not found: ' + name; 72 } 73 74 static match(value, def, stats = { total: 0, recognized: 0, defs: {} }) { 75 value.def = {}; 76 let tn = value.typeName().replaceAll('_', ' '); 77 def = translate(def, tn, stats); 78 ++stats.total; 79 if (def?.type) { 80 // if (def.id || def.name) ++stats.recognized; 81 if (tn == def.type.name || tn == def.name || def.name == 'ANY') 82 ++stats.recognized; 83 else if (def.name) 84 def = Object.assign({ mismatch: 1 }, def); 85 value.def = def; 86 } 87 if (value.sub !== null) { 88 if (def?.type?.type) 89 def = def.type; 90 let j = def?.content ? 0 : -1; 91 for (const subval of value.sub) { 92 let type; 93 if (j >= 0) { 94 if (def.typeOf) 95 type = def.content[0]; 96 else { 97 let tn = subval.typeName().replaceAll('_', ' '); 98 do { 99 type = def.content[j++]; 100 // type = translate(type, tn); 101 if (type?.type?.type) 102 type = type.type; 103 } while (type && typeof type == 'object' && ('optional' in type || 'default' in type) && type.name != 'ANY' && type.name != tn); 104 if (type?.type == 'builtin' || type?.type == 'defined') { 105 let v = subval.content(); 106 if (typeof v == 'string') 107 v = v.split(/\n/); 108 stats.defs[type.id] = v; 109 } else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) { // hope current OIDs contain the type name (will need to parse from RFC itself) 110 try { 111 type = Defs.searchType(firstUpper(stats.defs[type.definedBy][1])); 112 } catch (e) {} 113 } 114 } 115 } 116 Defs.match(subval, type, stats); 117 } 118 } 119 return stats; 120 } 121 122} 123 124Defs.RFC = rfc; 125 126Defs.commonTypes = [ 127 [ 'X.509 certificate', '1.3.6.1.5.5.7.0.18', 'Certificate' ], 128 [ 'CMS / PKCS#7 envelope', '1.2.840.113549.1.9.16.0.14', 'ContentInfo' ], 129 [ 'PKCS#8 encrypted private key', '1.2.840.113549.1.8.1.1', 'EncryptedPrivateKeyInfo' ], 130 [ 'PKCS#8 private key', '1.2.840.113549.1.8.1.1', 'PrivateKeyInfo' ], 131 [ 'PKCS#10 certification request', '1.2.840.113549.1.10.1.1', 'CertificationRequest' ], 132].map(arr => ({ description: arr[0], ...Defs.moduleAndType(rfc[arr[1]], arr[2]) })); 133 134return Defs; 135 136});