From bf359477a9b5e43406a8c43b3f5fce7972748947 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sun, 25 Nov 2018 22:53:43 -0700 Subject: [PATCH] v1.1.0: add case for known primitive-only values --- README.md | 20 ++++++++++++++------ asn1-parser.js | 28 ++++++++++++++-------------- index.html | 3 +-- package.json | 2 +- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e33cfc4..f974504 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,22 @@ Note: `value` will be a `Uint8Array`, not a hex string. ### Optimistic Parsing -This is a dumbed-down, minimal ASN1 parser. +This is a dumbed-down, minimal ASN1 parser +(though quite clever in its simplicity). -Rather than incorporating knowledge of each possible x509 schema -to know whether to traverse deeper into a value container, -it always tries to dive in (and backs out when parsing fails). +There are some ASN.1 types (at least Bit String and Octet String, +possibly others) that can be treated either as primitive values or +as container types base on the schema being used. -It is possible that it will produce false positives, but not likely -in real-world scenarios (PEM, x509, CSR, etc). +Rather than incorporating knowledge of each possible x509 schema, +this parser will return values for types that are _always_ values, +it recurse on types that are _always_ containers and, for ambigiuous +types, it will first try to recurse and, on error, will fall back to +returning a value. + +In theory, it is possible that it will produce false positives, +but that would be highly unlikely in real-world scenarios +(PEM, x509, PKCS#1, SEC1, PKCS#8, SPKI, PKIX, CSR, etc). I'd be interested to hear if you encounter such a case. diff --git a/asn1-parser.js b/asn1-parser.js index 34e07b2..687f605 100644 --- a/asn1-parser.js +++ b/asn1-parser.js @@ -15,10 +15,12 @@ var PEM = exports.PEM; ASN1.ELOOP = "uASN1.js Error: iterated over 15+ elements (probably a malformed file)"; ASN1.EDEEP = "uASN1.js Error: element nested 20+ layers deep (probably a malformed file)"; -// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1) -// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06, +// Container Types are Sequence 0x30, Container Array? (0xA0, 0xA1) +// Value Types are Integer 0x02, Null 0x05, Object ID 0x06, Value Array? (0x82) +// Bit String (0x03) and Octet String (0x04) may be values or containers // Sometimes Bit String is used as a container (RSA Pub Spki) ASN1.CTYPES = [ 0x30, 0x31, 0xa0, 0xa1 ]; +ASN1.VTYPES = [ 0x02, 0x05, 0x06, 0x82 ]; ASN1.parse = function parseAsn1(buf, depth, ws) { if (!ws) { ws = ''; } if (!depth) { depth = 0; } @@ -81,23 +83,21 @@ ASN1.parse = function parseAsn1(buf, depth, ws) { return asn1; } - // We want to fail if we know for sure that it's bad - if (-1 !== ASN1.CTYPES.indexOf(asn1.type)) { - return parseChildren(); - } + // Recurse into types that are _always_ containers + if (-1 !== ASN1.CTYPES.indexOf(asn1.type)) { return parseChildren(); } + // Return types that are _always_ values asn1.value = buf.slice(index, index + adjustedLen); - try { - return parseChildren(true); - } catch(e) { - // leaving iterable array as a matter of convenience - asn1.children = []; - return asn1; - } + if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) { return asn1; } + + // For ambigious / unknown types, recurse and return on failure + // (and return child array size to zero) + try { return parseChildren(true); } + catch(e) { asn1.children.length = 0; return asn1; } }; ASN1._replacer = function (k, v) { if ('type' === k) { return '0x' + Enc.numToHex(v); } - if ('value' === k) { return '0x' + Enc.bufToHex(v.data || v); } + if (v && 'value' === k) { return '0x' + Enc.bufToHex(v.data || v); } return v; }; diff --git a/index.html b/index.html index b115dc7..8b04aaf 100644 --- a/index.html +++ b/index.html @@ -26,10 +26,9 @@ rMjgyCokrnjDft6Y/YnA4A50yZe7CnFsqeDcpnPbubP6cpYiVcnevNIYyg== var $input = document.querySelector('.js-input'); function convert() { - console.log('change'); + console.log('keyup'); var pem = PEM.parseBlock(document.querySelector('.js-input').value); var hex = Enc.bufToHex(pem.der); - console.log(hex); document.querySelector('.js-hex').innerText = hex .match(/.{2}/g).join(' ').match(/.{1,24}/g).join(' ').match(/.{1,50}/g).join('\n'); var json = ASN1.parse(pem.der); diff --git a/package.json b/package.json index 7d5183d..11f5729 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "asn1-parser", - "version": "1.0.2", + "version": "1.1.0", "description": "An ASN.1 parser in less than 100 lines of Vanilla JavaScript, part of the Bluecrypt suite.", "homepage": "https://git.coolaj86.com/coolaj86/asn1-parser.js", "main": "asn1-parser.js",