From 7c2a63b4bbaa6b402ae2d58131404873a98704ea Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Mon, 18 Sep 2023 20:02:48 +0000 Subject: [PATCH 1/8] Update `eslint` rules a bit. --- asn1.js | 2 +- defs.js | 4 ++-- dom.js | 4 ++-- oids.js | 5 ++--- package.json | 15 ++++++++++----- release.sh | 6 +++--- rfcdef.js | 4 ++-- tags.js | 22 +++++++++++----------- updateOID.sh | 5 ++--- updateRFC.sh | 4 ++-- 10 files changed, 37 insertions(+), 34 deletions(-) diff --git a/asn1.js b/asn1.js index a1d755c..3ccb228 100644 --- a/asn1.js +++ b/asn1.js @@ -43,7 +43,7 @@ const ['', ''], ['OUou', 'ŐŰőű'], // Double Acute ['AEIUaeiu', 'ĄĘĮŲąęįų'], // Ogonek - ['CDELNRSTZcdelnrstz', 'ČĎĚĽŇŘŠŤŽčďěľňřšťž'] // Caron + ['CDELNRSTZcdelnrstz', 'ČĎĚĽŇŘŠŤŽčďěľňřšťž'], // Caron ]; function stringCut(str, len) { diff --git a/defs.js b/defs.js index 75bdaee..35a113e 100644 --- a/defs.js +++ b/defs.js @@ -29,7 +29,7 @@ function translate(def, tn, stats) { try { // hope current OIDs contain the type name (will need to parse from RFC itself) def = Defs.searchType(firstUpper(stats.defs[def.definedBy][1])); - } catch (e) {} + } catch (e) { /*ignore*/ } while (def?.type == 'defined' || def?.type?.type == 'defined') { const name = def?.type?.type ? def.type.name : def.name; def = Object.assign({}, def); @@ -109,7 +109,7 @@ class Defs { } else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) { // hope current OIDs contain the type name (will need to parse from RFC itself) try { type = Defs.searchType(firstUpper(stats.defs[type.definedBy][1])); - } catch (e) {} + } catch (e) { /*ignore*/ } } } } diff --git a/dom.js b/dom.js index 4c0b32d..f9552ad 100644 --- a/dom.js +++ b/dom.js @@ -52,8 +52,8 @@ const o += line; } return o; - } - } + }, + }; class ASN1DOM extends ASN1 { diff --git a/oids.js b/oids.js index 06fb616..e315454 100644 --- a/oids.js +++ b/oids.js @@ -3,8 +3,8 @@ // You can use this code in whatever way you want, // as long as you don't try to claim you wrote it. (typeof define != "undefined" ? define : function (factory) { "use strict"; - if (typeof module == "object") module.exports = factory(); - else window.oids = factory(); + if (typeof module == "object") module.exports = factory(); + else window.oids = factory(); })(function () { "use strict"; return { @@ -2727,5 +2727,4 @@ return { "1.3.6.1.4.1.40869.1.1.22.3": { "d": "TWCA EV policy", "c": "TWCA Root Certification Authority" }, "2.16.840.1.113733.1.7.23.6": { "d": "VeriSign EV policy", "c": "VeriSign Class 3 Public Primary Certification Authority" }, "2.16.840.1.114171.500.9": { "d": "Wells Fargo EV policy", "c": "Wells Fargo WellsSecure Public Root Certificate Authority" }, -"END": "" };}); diff --git a/package.json b/package.json index 5b07679..6d92cce 100644 --- a/package.json +++ b/package.json @@ -43,17 +43,21 @@ "semi": [ "warn", "always" ], "quotes": [ "error", "single", { "avoidEscape": true } ], "no-var": [ "warn" ], - "comma-dangle": [ "error", "never" ] + "comma-dangle": [ "error", "always-multiline" ] }, "overrides": [ { + "files": [ "defs.js" ], + "parserOptions": { + "ecmaVersion": 2020 + } + }, { "files": [ "test.js", "parseRFC.js", "dumpASN1.js" ], "parserOptions": { "ecmaVersion": 2021 }, "rules": { - "strict": [ "error", "global" ], - "comma-dangle": [ "error", "always-multiline" ] + "strict": [ "error", "global" ] } }, { "files": [ "oids.js" ], @@ -62,9 +66,10 @@ "quotes": [ "warn", "double" ] } }, { - "files": [ "tags.js" ], + "files": [ "tags.js", "rfcdef.js" ], "rules": { - "comma-dangle": [ "error", "always-multiline" ], + "indent": [ "error", 2, { "ignoredNodes": [ "Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement > ExpressionStatement[directive='use strict']:first-child" ] } ], + "comma-dangle": "off", "quotes": [ "warn", "double" ] } } diff --git a/release.sh b/release.sh index 37b4c1a..466eb63 100755 --- a/release.sh +++ b/release.sh @@ -20,13 +20,13 @@ mtn automate tags it.lapo.asn1js | \ done | sort -r | awk -v q='"' ' BEGIN { print "(typeof define != " q "undefined" q " ? define : function (factory) { " q "use strict" q ";"; - print " if (typeof module == " q "object" q ") module.exports = factory();"; - print " else window.tags = factory();"; + print " if (typeof module == " q "object" q ") module.exports = factory();"; + print " else window.tags = factory();"; print "})(function () {"; print q "use strict" q ";"; print "return {" } - { print " " q $2 q ":" q $1 q "," } + { print " " q $2 q ": " q $1 q "," } END { print "};});" } ' > tags.js type gsha256sum >/dev/null && SHA256=gsha256sum || SHA256=sha256sum diff --git a/rfcdef.js b/rfcdef.js index 4283ba7..6d0e5f1 100644 --- a/rfcdef.js +++ b/rfcdef.js @@ -4,8 +4,8 @@ // It is acceptable under the current IETF rules (RFC 5378) to modify extracted code if necessary. // https://trustee.ietf.org/about/faq/#reproducing-rfcs (typeof define != "undefined" ? define : function (factory) { "use strict"; - if (typeof module == "object") module.exports = factory(); - else window.rfcdef = factory(); + if (typeof module == "object") module.exports = factory(); + else window.rfcdef = factory(); })(function () { "use strict"; return { diff --git a/tags.js b/tags.js index b3d23ab..3e3af57 100644 --- a/tags.js +++ b/tags.js @@ -1,16 +1,16 @@ (typeof define != "undefined" ? define : function (factory) { "use strict"; - if (typeof module == "object") module.exports = factory(); - else window.tags = factory(); + if (typeof module == "object") module.exports = factory(); + else window.tags = factory(); })(function () { "use strict"; return { - "1.2.4":"2022-11-14", - "1.2.3":"2021-10-21", - "1.2.2":"2021-10-21", - "1.2.1":"2020-09-06", - "1.2.0":"2020-07-20", - "1.1.0":"2019-07-13", - "1.0.2":"2018-08-23", - "1.0.1":"2018-08-14", - "1.0.0":"2018-08-14", + "1.2.4": "2022-11-14", + "1.2.3": "2021-10-21", + "1.2.2": "2021-10-21", + "1.2.1": "2020-09-06", + "1.2.0": "2020-07-20", + "1.1.0": "2019-07-13", + "1.0.2": "2018-08-23", + "1.0.1": "2018-08-14", + "1.0.0": "2018-08-14", };}); diff --git a/updateOID.sh b/updateOID.sh index 1bced65..f32fd72 100755 --- a/updateOID.sh +++ b/updateOID.sh @@ -25,8 +25,8 @@ awk -v apos="'" -v q='"' -v url="$URL" ' print "// You can use this code in whatever way you want,"; print "// as long as you don" apos "t try to claim you wrote it."; print "(typeof define != " q "undefined" q " ? define : function (factory) { " q "use strict" q ";"; - print " if (typeof module == " q "object" q ") module.exports = factory();"; - print " else window.oids = factory();"; + print " if (typeof module == " q "object" q ") module.exports = factory();"; + print " else window.oids = factory();"; print "})(function () {"; print q "use strict" q ";"; print "return {"; @@ -48,7 +48,6 @@ awk -v apos="'" -v q='"' -v url="$URL" ' } } END { - print "\"END\": \"\"" print "};});" } ' >oids.js diff --git a/updateRFC.sh b/updateRFC.sh index 0839acc..6f82192 100755 --- a/updateRFC.sh +++ b/updateRFC.sh @@ -27,8 +27,8 @@ cd .. echo "// https://trustee.ietf.org/about/faq/#reproducing-rfcs" cat - < Date: Thu, 28 Mar 2024 22:42:03 +0000 Subject: [PATCH 2/8] Improve type matching. Improved CMP example recognition from 47.62% to 68.25%. Closes #78 on GitHub. --- defs.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/defs.js b/defs.js index 35a113e..8cbfd96 100644 --- a/defs.js +++ b/defs.js @@ -37,7 +37,8 @@ function translate(def, tn, stats) { } if (def?.type?.name == 'CHOICE') { for (let c of def.type.content) { - c = translate(c); + if (tn != c.type.name && tn != c.name) + c = translate(c); if (tn == c.type.name || tn == c.name) { def = Object.assign({}, def); def.type = c.type.name ? c.type : c; From 26d3a722131b1bf4337918635a368bdfc268258e Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Sat, 30 Mar 2024 19:03:45 +0000 Subject: [PATCH 3/8] Throw exceptions, not strings. --- asn1.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/asn1.js b/asn1.js index 3ccb228..9916515 100644 --- a/asn1.js +++ b/asn1.js @@ -77,7 +77,7 @@ class Stream { if (pos === undefined) pos = this.pos++; if (pos >= this.enc.length) - throw 'Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length; + throw new Error('Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length); return (typeof this.enc == 'string') ? this.enc.charCodeAt(pos) : this.enc[pos]; } hexByte(b) { @@ -250,7 +250,7 @@ class Stream { parseBitString(start, end, maxLength) { let unusedBits = this.get(start); if (unusedBits > 7) - throw 'Invalid BitString with unusedBits=' + unusedBits; + throw new Error('Invalid BitString with unusedBits=' + unusedBits); let lenBit = ((end - start - 1) << 3) - unusedBits, s = ''; for (let i = start + 1; i < end; ++i) { @@ -373,7 +373,7 @@ class ASN1Tag { class ASN1 { constructor(stream, header, length, tag, tagLen, sub) { - if (!(tag instanceof ASN1Tag)) throw 'Invalid tag value.'; + if (!(tag instanceof ASN1Tag)) throw new Error('Invalid tag value.'); this.stream = stream; this.header = header; this.length = length; @@ -536,7 +536,7 @@ class ASN1 { if (len === 0) // long form with length 0 is a special case return null; // undefined length if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways - throw 'Length over 48 bits not supported at position ' + (stream.pos - 1); + throw new Error('Length over 48 bits not supported at position ' + (stream.pos - 1)); buf = 0; for (let i = 0; i < len; ++i) buf = (buf * 256) + stream.get(); @@ -544,7 +544,7 @@ class ASN1 { } static decode(stream, offset, type = ASN1) { if (!(type == ASN1 || type.prototype instanceof ASN1)) - throw 'Must pass a class that extends ASN1'; + throw new Error('Must pass a class that extends ASN1'); if (!(stream instanceof Stream)) stream = new Stream(stream, offset || 0); let streamStart = new Stream(stream), @@ -560,11 +560,11 @@ class ASN1 { // definite length let end = start + len; if (end > stream.enc.length) - throw 'Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream'; + throw new Error('Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream'); while (stream.pos < end) sub[sub.length] = type.decode(stream); if (stream.pos != end) - throw 'Content size is not correct for container at offset ' + start; + throw new Error('Content size is not correct for container at offset ' + start); } else { // undefined length try { @@ -576,7 +576,7 @@ class ASN1 { } len = start - stream.pos; // undefined lengths are represented as negative values } catch (e) { - throw 'Exception while decoding undefined length content at offset ' + start + ': ' + e; + throw new Error('Exception while decoding undefined length content at offset ' + start + ': ' + e); } } }; @@ -588,11 +588,11 @@ class ASN1 { try { if (tag.tagNumber == 0x03) if (stream.get() != 0) - throw 'BIT STRINGs with unused bits cannot encapsulate.'; + throw new Error('BIT STRINGs with unused bits cannot encapsulate.'); getSub(); for (let i = 0; i < sub.length; ++i) if (sub[i].tag.isEOC()) - throw 'EOC is not supposed to be actual content.'; + throw new Error('EOC is not supposed to be actual content.'); } catch (e) { // but silently ignore when they don't sub = null; @@ -601,7 +601,7 @@ class ASN1 { } if (sub === null) { if (len === null) - throw "We can't skip over an invalid tag with undefined length at offset " + start; + throw new Error("We can't skip over an invalid tag with undefined length at offset " + start); stream.pos = start + Math.abs(len); } return new type(streamStart, header, len, tag, tagLen, sub); From 7a51b8a08c5a3e9076b996ee26f50b0b0da490a2 Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Sat, 30 Mar 2024 19:21:39 +0000 Subject: [PATCH 4/8] Fix tests. --- test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.js b/test.js index c4945f7..263a10f 100755 --- a/test.js +++ b/test.js @@ -36,7 +36,7 @@ const tests = [ ['170D3931303530363233343534305A', '1991-05-06 23:45:40 UTC', 'ntop, utc time: UTC'], ['17113931303530363136343534302D30373030', '1991-05-06 16:45:40 UTC-07:00', 'ntop, utc time: PDT'], // inspired by http://luca.ntop.org/Teaching/Appunti/asn1.html - ['0304086E5DC0', 'Exception:\nInvalid BitString with unusedBits=8', 'bit string: invalid unusedBits'], + ['0304086E5DC0', 'Exception:\nError: Invalid BitString with unusedBits=8', 'bit string: invalid unusedBits'], // http://msdn.microsoft.com/en-us/library/windows/desktop/aa379076(v=vs.85).aspx ['30820319308202820201003023310F300D0603550403130654657374434E3110300E060355040A1307546573744F726730819F300D06092A864886F70D010101050003818D00308189028181008FE2412A08E851A88CB3E853E7D54950B3278A2BCBEAB54273EA0257CC6533EE882061A11756C12418E3A808D3BED931F3370B94B8CC43080B7024F79CB18D5DD66D82D0540984F89F970175059C89D4D5C91EC913D72A6B309119D6D442E0C49D7C9271E1B22F5C8DEEF0F1171ED25F315BB19CBC2055BF3A37424575DC90650203010001A08201B4301A060A2B0601040182370D0203310C160A362E302E353336312E323042060A2B0601040182370D0201313430321E260043006500720074006900660069006300610074006500540065006D0070006C0061007400651E080055007300650072305706092B0601040182371514314A30480201090C237669636833642E6A646F6D6373632E6E74746573742E6D6963726F736F66742E636F6D0C154A444F4D4353435C61646D696E6973747261746F720C07636572747265713074060A2B0601040182370D0202316630640201011E5C004D006900630072006F0073006F0066007400200045006E00680061006E006300650064002000430072007900700074006F0067007200610070006800690063002000500072006F00760069006400650072002000760031002E003003010030818206092A864886F70D01090E31753073301706092B0601040182371402040A1E08005500730065007230290603551D2504223020060A2B0601040182370A030406082B0601050507030406082B06010505070302300E0603551D0F0101FF0404030205A0301D0603551D0E041604143C0F73DAF8EF41D83AEABE922A5D2C966A7B9454300D06092A864886F70D01010505000381810047EB995ADF9E700DFBA73132C15F5C24C2E0BFC624AF15660EB86A2EAB2BC4971FE3CBDC63A525ECC7B428616636A1311BBFDDD0FCBF1794901DE55EC7115EC9559FEBA33E14C799A6CBBAA1460F39D444C4C84B760E205D6DA9349ED4D58742EB2426511490B40F065E5288327A9520A0FDF7E57D60DD72689BF57B058F6D1E', '(3 elem)', 'PKCS#10 request'], From 405c036110d39f349558da19d2c591aaafde6bb5 Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Sat, 30 Mar 2024 19:22:03 +0000 Subject: [PATCH 5/8] Drop dead code. --- test.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test.js b/test.js index 263a10f..db976ab 100755 --- a/test.js +++ b/test.js @@ -95,8 +95,7 @@ let tests.forEach(function (t) { const input = t[0], expected = t[1], - comment = t[2], - errorReason = t[3]; + comment = t[2]; let result; try { result = ASN1.decode(Hex.decode(input)).content(); @@ -107,9 +106,6 @@ tests.forEach(function (t) { ++run; if (result == expected) { if (all) console.log('\x1B[1m\x1B[32mOK \x1B[39m\x1B[22m ' + comment); - } else if (errorReason) { - ++expErr; - console.log('\x1B[1m\x1B[33mEXP\x1B[39m\x1B[22m ' + comment + ' (' + errorReason + ')' + '\n' + result); } else { ++error; console.log('\x1B[1m\x1B[31mERR\x1B[39m\x1B[22m ' + comment + '\n' + result); From 8f048accac80bc166a24325d53b49a504144e7af Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Sat, 30 Mar 2024 20:05:23 +0000 Subject: [PATCH 6/8] When trying to parse encapsulated values, check that the content can be parsed as well. Closes #79 on GitHub. --- asn1.js | 12 +++++++++--- dom.js | 7 ++++++- test.js | 16 +++++++++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/asn1.js b/asn1.js index 9916515..2a6bdfd 100644 --- a/asn1.js +++ b/asn1.js @@ -195,7 +195,7 @@ class Stream { let s = this.parseStringISO(start, end).str, m = (shortYear ? reTimeS : reTimeL).exec(s); if (!m) - return 'Unrecognized time: ' + s; + throw new Error('Unrecognized time: ' + s); if (shortYear) { // to avoid querying the timer, use the fixed range [1970, 2069] // it will conform with ITU X.400 [-10, +40] sliding window until 2030 @@ -590,9 +590,15 @@ class ASN1 { if (stream.get() != 0) throw new Error('BIT STRINGs with unused bits cannot encapsulate.'); getSub(); - for (let i = 0; i < sub.length; ++i) - if (sub[i].tag.isEOC()) + for (let s of sub) { + if (s.tag.isEOC()) throw new Error('EOC is not supposed to be actual content.'); + try { + s.content(); + } catch (e) { + throw new Error('Unable to parse content: ' + e); + } + } } catch (e) { // but silently ignore when they don't sub = null; diff --git a/dom.js b/dom.js index f9552ad..fb3182d 100644 --- a/dom.js +++ b/dom.js @@ -80,7 +80,12 @@ class ASN1DOM extends ASN1 { } } head.appendChild(DOM.text(typeName)); - let content = this.content(contentLength); + let content; + try { + content = this.content(contentLength); + } catch (e) { + content = 'Cannot decode: ' + e; + } let oid; if (content !== null) { let preview = DOM.tag('span', 'preview'), diff --git a/test.js b/test.js index db976ab..c69505b 100755 --- a/test.js +++ b/test.js @@ -86,6 +86,8 @@ const tests = [ ['0420041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', '(32 byte)\n041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', 'Do not mix encapsulated and structured octet strings'], // GitHub issue #47 ['181531393835313130363231303632372E332D31323334', '1985-11-06 21:06:27.3 UTC-12:34', 'UTC offsets with minutes'], // GitHub issue #54 ['181331393835313130363231303632372E332B3134', '1985-11-06 21:06:27.3 UTC+14:00', 'UTC offset +13 and +14'], // GitHub issue #54 + ['032100171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', n => { if (n.sub != null) return 'Should not decode content: ' + n.sub[0].content(); }, 'Key that resembles an UTCTime'], // GitHub issue #79 + ['171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', /^Exception:\nError: Unrecognized time: /, 'Invalid UTCTime'], // GitHub issue #79 ]; let @@ -98,17 +100,25 @@ tests.forEach(function (t) { comment = t[2]; let result; try { - result = ASN1.decode(Hex.decode(input)).content(); + let node = ASN1.decode(Hex.decode(input)); + if (typeof expected == 'function') + result = expected(node); + else + result = node.content(); //TODO: check structure, not only first level content } catch (e) { result = 'Exception:\n' + e; } + if (expected instanceof RegExp) + result = expected.test(result) ? null : 'does not match'; ++run; - if (result == expected) { + if (!result || result == expected) { if (all) console.log('\x1B[1m\x1B[32mOK \x1B[39m\x1B[22m ' + comment); } else { ++error; - console.log('\x1B[1m\x1B[31mERR\x1B[39m\x1B[22m ' + comment + '\n' + result); + console.log('\x1B[1m\x1B[31mERR\x1B[39m\x1B[22m ' + comment); + console.log(' \x1B[1m\x1B[34mEXP\x1B[39m\x1B[22m ' + expected.toString().replace(/\n/g, '\n ')); + console.log(' \x1B[1m\x1B[33mGOT\x1B[39m\x1B[22m ' + result.replace(/\n/g, '\n ')); } }); console.log(run + ' tested, ' + expErr + ' expected, ' + error + ' errors.'); From 2654e9cd3cc5f421e9a8446aa26dfbe753206bef Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Sun, 31 Mar 2024 09:34:18 +0000 Subject: [PATCH 7/8] Add very basic PKCS#1 support and RSA key examples. --- defs.js | 1 + examples/pkcs1.pem | 18 ++ examples/pkcs8-rsa.pem | 18 ++ index.html | 2 + parseRFC.js | 16 +- rfcdef.js | 531 ++++++++++++++++++++++++++++++++++++++++- updateRFC.sh | 2 +- 7 files changed, 585 insertions(+), 3 deletions(-) create mode 100644 examples/pkcs1.pem create mode 100644 examples/pkcs8-rsa.pem diff --git a/defs.js b/defs.js index 8cbfd96..d331efa 100644 --- a/defs.js +++ b/defs.js @@ -127,6 +127,7 @@ Defs.RFC = rfc; Defs.commonTypes = [ [ 'X.509 certificate', '1.3.6.1.5.5.7.0.18', 'Certificate' ], [ 'CMS / PKCS#7 envelope', '1.2.840.113549.1.9.16.0.14', 'ContentInfo' ], + [ 'PKCS#1 RSA private key', '1.2.840.113549.1.1.0.1', 'RSAPrivateKey' ], [ 'PKCS#8 encrypted private key', '1.2.840.113549.1.8.1.1', 'EncryptedPrivateKeyInfo' ], [ 'PKCS#8 private key', '1.2.840.113549.1.8.1.1', 'PrivateKeyInfo' ], [ 'PKCS#10 certification request', '1.2.840.113549.1.10.1.1', 'CertificationRequest' ], diff --git a/examples/pkcs1.pem b/examples/pkcs1.pem new file mode 100644 index 0000000..7077a97 --- /dev/null +++ b/examples/pkcs1.pem @@ -0,0 +1,18 @@ +PKCS#1 RSA key +$ openssl genrsa -out examples/pkcs8-rsa.pem 1024 +$ openssl rsa -in examples/pkcs8-rsa.pem -out examples/pkcs1.pem -traditional +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCmy23ifN9pi5LO4MR3LUhU0v+LZmv78H+jd+R6kFcWZf1qW4yf +KTDkryjjLlIhYqxmzXCqGyaIjj7uJoorWf7KfkxpOuJrh4swJ/WGhCn9i+voW/7T +sOXfDp1yqrEhaQKwdPot1ZAB78TNsecwX/SODTEMCk95jvx1j5cDxPlskwIDAQAB +AoGBAINn4bp+BsVwYMj768y4sDOjyBBbMNfcMbLn0el9rh7HW09fsPnzycFg/iV9 +aNdEle6oDAr4OPN8nbeiRVjCHijEnVdHCwAtkKODyuu1ghpZWD0VUC8AEskjX4Bs +Ysl/HjyvvHIRj89gdDFoElgB4GzHKTzeZNJBM5qtUW57zBCBAkEA0A6N5l98MglL +cypWKM7+3DXteWt86mKXYUVF33HY28Z+oUVlU0v8m8XxpoAjkicYnC1JOSSlvWRk +EWlTMgHW5QJBAM06yIHMR6p3apgpwOUp49DbtaQ8NmhCV4NBoFHa+vT2Fk8twOcq +O9OzP4svhKbPNfB4HnxGbmd/+OVT3lySxhcCQHRPPpqD1K0wLwKxrzrfBPDcIOaY +5VsuRIw3KqmQPngWTiIf5lYbi5sVnFLFHZ2Nx58/XcjZKOJopdxp8f1ps9UCQQC3 +rOqSsF9bg3DVKllHQAxyepDAolsXSHjGMk/nspJz9mLVDl/dBAFzYLN4QFj6ae0e +gILYOrjIzNHXfQ4/z+SVAkBPebkAzpGFgzVzu6VOGx0Vft/ow3/DKNJSDM58yASp +ootY2TdibrrV/ellNLvuTiku6AEM/8jbHlRsmfxRe0xn +-----END RSA PRIVATE KEY----- diff --git a/examples/pkcs8-rsa.pem b/examples/pkcs8-rsa.pem new file mode 100644 index 0000000..39829b5 --- /dev/null +++ b/examples/pkcs8-rsa.pem @@ -0,0 +1,18 @@ +PKCS#8 RSA key +$ openssl genrsa -out examples/pkcs8-rsa.pem 1024 +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKbLbeJ832mLks7g +xHctSFTS/4tma/vwf6N35HqQVxZl/WpbjJ8pMOSvKOMuUiFirGbNcKobJoiOPu4m +iitZ/sp+TGk64muHizAn9YaEKf2L6+hb/tOw5d8OnXKqsSFpArB0+i3VkAHvxM2x +5zBf9I4NMQwKT3mO/HWPlwPE+WyTAgMBAAECgYEAg2fhun4GxXBgyPvrzLiwM6PI +EFsw19wxsufR6X2uHsdbT1+w+fPJwWD+JX1o10SV7qgMCvg483ydt6JFWMIeKMSd +V0cLAC2Qo4PK67WCGllYPRVQLwASySNfgGxiyX8ePK+8chGPz2B0MWgSWAHgbMcp +PN5k0kEzmq1RbnvMEIECQQDQDo3mX3wyCUtzKlYozv7cNe15a3zqYpdhRUXfcdjb +xn6hRWVTS/ybxfGmgCOSJxicLUk5JKW9ZGQRaVMyAdblAkEAzTrIgcxHqndqmCnA +5Snj0Nu1pDw2aEJXg0GgUdr69PYWTy3A5yo707M/iy+Eps818HgefEZuZ3/45VPe +XJLGFwJAdE8+moPUrTAvArGvOt8E8Nwg5pjlWy5EjDcqqZA+eBZOIh/mVhuLmxWc +UsUdnY3Hnz9dyNko4mil3Gnx/Wmz1QJBALes6pKwX1uDcNUqWUdADHJ6kMCiWxdI +eMYyT+eyknP2YtUOX90EAXNgs3hAWPpp7R6Agtg6uMjM0dd9Dj/P5JUCQE95uQDO +kYWDNXO7pU4bHRV+3+jDf8Mo0lIMznzIBKmii1jZN2JuutX96WU0u+5OKS7oAQz/ +yNseVGyZ/FF7TGc= +-----END PRIVATE KEY----- diff --git a/index.html b/index.html index 7b7a9f3..15d2759 100644 --- a/index.html +++ b/index.html @@ -46,6 +46,8 @@

ASN.1 JavaScript decoder

+ + diff --git a/parseRFC.js b/parseRFC.js index 41e256c..d625388 100755 --- a/parseRFC.js +++ b/parseRFC.js @@ -45,6 +45,17 @@ const 4210: [ [ /^\s+-- .*\r?\n/mg, '' ], // comments ], + 8017: [ // this RFC uses a lot of currently unsupported syntax + [ /ALGORITHM-IDENTIFIER ::= CLASS[^-]+--/, '--' ], + [ /\n +\S+ +ALGORITHM-IDENTIFIER[^\n]+(\n [^\n]+)+\n [}]/g, '' ], + [ /AlgorithmIdentifier [{] ALGORITHM-IDENTIFIER:InfoObjectSet [}] ::=(\n [^\n]+)+\n [}]/, 'AlgorithmIdentifier ::= ANY'], + [ /algorithm +id-[^,\n]+,/g, 'algorithm ANY,' ], + [ / (sha1 HashAlgorithm|mgf1SHA1 MaskGenAlgorithm|pSpecifiedEmpty PSourceAlgorithm|rSAES-OAEP-Default-Identifier RSAES-AlgorithmIdentifier|rSASSA-PSS-Default-Identifier RSASSA-AlgorithmIdentifier) ::= [{](\n( [^\n]+)?)+\n [}]/g, '' ], + [ / ::= AlgorithmIdentifier [{]\s+[{][^}]+[}]\s+[}]/g, ' ::= AlgorithmIdentifier' ], + [ /OCTET STRING[(]SIZE[(]0..MAX[)][)]/g, 'OCTET STRING' ], + [ /emptyString EncodingParameters ::= ''H/g, '' ], + [ /[(]CONSTRAINED BY[^)]+[)]/g, '' ], + ], }; // const reWhitespace = /(?:\s|--(?:[}-]?[^\n}-])*(?:\n|--))*/y; @@ -349,8 +360,11 @@ class Parser { } else { if (id in currentMod.values) // defined in local module val = currentMod.values[id].value; - else + else try { val = searchImportedValue(id); + } catch (e) { + this.exception(e.message); + } } } if (v.length) v += '.'; diff --git a/rfcdef.js b/rfcdef.js index 6d0e5f1..d03ccad 100644 --- a/rfcdef.js +++ b/rfcdef.js @@ -1,4 +1,4 @@ -// content parsed from ASN.1 definitions as found in the following RFCs: 5280 5208 3369 3161 2986 4211 4210 +// content parsed from ASN.1 definitions as found in the following RFCs: 5280 5208 3369 3161 2986 4211 4210 8017 // Copyright (C) The IETF Trust (2008) // as far as I can tell this file is allowed under the following clause: // It is acceptable under the current IETF rules (RFC 5378) to modify extracted code if necessary. @@ -9861,6 +9861,535 @@ return { } } } + }, + "1.2.840.113549.1.1.0.1": { + "name": "PKCS-1", + "oid": "1.2.840.113549.1.1.0.1", + "source": "rfc8017.txt", + "tagDefault": "EXPLICIT", + "imports": { + "2.16.840.1.101.3.4.2": { + "name": "NIST-SHA2", + "oid": "2.16.840.1.101.3.4.2", + "types": [ + "id-sha224", + "id-sha256", + "id-sha384", + "id-sha512", + "id-sha512-224", + "id-sha512-256" + ] + } + }, + "values": { + "pkcs-1": { + "name": "pkcs-1", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1" + }, + "rsaEncryption": { + "name": "rsaEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.1" + }, + "id-RSAES-OAEP": { + "name": "id-RSAES-OAEP", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.7" + }, + "id-pSpecified": { + "name": "id-pSpecified", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.9" + }, + "id-RSASSA-PSS": { + "name": "id-RSASSA-PSS", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.10" + }, + "md2WithRSAEncryption": { + "name": "md2WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.2" + }, + "md5WithRSAEncryption": { + "name": "md5WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.4" + }, + "sha1WithRSAEncryption": { + "name": "sha1WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.5" + }, + "sha224WithRSAEncryption": { + "name": "sha224WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.14" + }, + "sha256WithRSAEncryption": { + "name": "sha256WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.11" + }, + "sha384WithRSAEncryption": { + "name": "sha384WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.12" + }, + "sha512WithRSAEncryption": { + "name": "sha512WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.13" + }, + "sha512-224WithRSAEncryption": { + "name": "sha512-224WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.15" + }, + "sha512-256WithRSAEncryption": { + "name": "sha512-256WithRSAEncryption", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.16" + }, + "id-sha1": { + "name": "id-sha1", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.3.14.3.2.26" + }, + "id-md2": { + "name": "id-md2", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.2.2" + }, + "id-md5": { + "name": "id-md5", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.2.5" + }, + "id-mgf1": { + "name": "id-mgf1", + "type": { + "name": "OBJECT IDENTIFIER", + "type": "builtin" + }, + "value": "1.2.840.113549.1.1.8" + } + }, + "types": { + "AlgorithmIdentifier": { + "name": "AlgorithmIdentifier", + "type": { + "name": "ANY", + "type": "builtin" + } + }, + "HashAlgorithm": { + "name": "HashAlgorithm", + "type": { + "name": "AlgorithmIdentifier", + "type": "defined" + } + }, + "SHA1Parameters": { + "name": "SHA1Parameters", + "type": { + "name": "NULL", + "type": "defined" + } + }, + "MaskGenAlgorithm": { + "name": "MaskGenAlgorithm", + "type": { + "name": "AlgorithmIdentifier", + "type": "defined" + } + }, + "EncodingParameters": { + "name": "EncodingParameters", + "type": { + "name": "OCTET STRING", + "type": "builtin" + } + }, + "PSourceAlgorithm": { + "name": "PSourceAlgorithm", + "type": { + "name": "AlgorithmIdentifier", + "type": "defined" + } + }, + "RSAPublicKey": { + "name": "RSAPublicKey", + "type": { + "name": "SEQUENCE", + "type": "builtin", + "content": [ + { + "id": "modulus", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "publicExponent", + "name": "INTEGER", + "type": "builtin" + } + ] + } + }, + "RSAPrivateKey": { + "name": "RSAPrivateKey", + "type": { + "name": "SEQUENCE", + "type": "builtin", + "content": [ + { + "id": "version", + "name": "Version", + "type": "defined" + }, + { + "id": "modulus", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "publicExponent", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "privateExponent", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "prime1", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "prime2", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "exponent1", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "exponent2", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "coefficient", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "otherPrimeInfos", + "name": "OtherPrimeInfos", + "type": "defined", + "optional": true + } + ] + } + }, + "Version": { + "name": "Version", + "type": { + "name": "INTEGER", + "type": "builtin", + "content": { + "two-prime": 0, + "multi": 1 + } + } + }, + "OtherPrimeInfos": { + "name": "OtherPrimeInfos", + "type": { + "name": "SEQUENCE", + "type": "builtin", + "typeOf": 1, + "size": [ + 1, + "MAX" + ], + "content": [ + { + "name": "OtherPrimeInfo", + "type": "defined" + } + ] + } + }, + "OtherPrimeInfo": { + "name": "OtherPrimeInfo", + "type": { + "name": "SEQUENCE", + "type": "builtin", + "content": [ + { + "id": "prime", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "exponent", + "name": "INTEGER", + "type": "builtin" + }, + { + "id": "coefficient", + "name": "INTEGER", + "type": "builtin" + } + ] + } + }, + "RSAES-OAEP-params": { + "name": "RSAES-OAEP-params", + "type": { + "name": "SEQUENCE", + "type": "builtin", + "content": [ + { + "id": "hashAlgorithm", + "name": "[0]", + "type": "tag", + "class": "CONTEXT", + "explicit": true, + "content": [ + { + "name": "", + "type": { + "name": "HashAlgorithm", + "type": "defined" + } + } + ], + "default": "sha1" + }, + { + "id": "maskGenAlgorithm", + "name": "[1]", + "type": "tag", + "class": "CONTEXT", + "explicit": true, + "content": [ + { + "name": "", + "type": { + "name": "MaskGenAlgorithm", + "type": "defined" + } + } + ], + "default": "mgf1SHA1" + }, + { + "id": "pSourceAlgorithm", + "name": "[2]", + "type": "tag", + "class": "CONTEXT", + "explicit": true, + "content": [ + { + "name": "", + "type": { + "name": "PSourceAlgorithm", + "type": "defined" + } + } + ], + "default": "pSpecifiedEmpty" + } + ] + } + }, + "RSAES-AlgorithmIdentifier": { + "name": "RSAES-AlgorithmIdentifier", + "type": { + "name": "AlgorithmIdentifier", + "type": "defined" + } + }, + "RSASSA-PSS-params": { + "name": "RSASSA-PSS-params", + "type": { + "name": "SEQUENCE", + "type": "builtin", + "content": [ + { + "id": "hashAlgorithm", + "name": "[0]", + "type": "tag", + "class": "CONTEXT", + "explicit": true, + "content": [ + { + "name": "", + "type": { + "name": "HashAlgorithm", + "type": "defined" + } + } + ], + "default": "sha1" + }, + { + "id": "maskGenAlgorithm", + "name": "[1]", + "type": "tag", + "class": "CONTEXT", + "explicit": true, + "content": [ + { + "name": "", + "type": { + "name": "MaskGenAlgorithm", + "type": "defined" + } + } + ], + "default": "mgf1SHA1" + }, + { + "id": "saltLength", + "name": "[2]", + "type": "tag", + "class": "CONTEXT", + "explicit": true, + "content": [ + { + "name": "", + "type": { + "name": "INTEGER", + "type": "builtin" + } + } + ], + "default": 20 + }, + { + "id": "trailerField", + "name": "[3]", + "type": "tag", + "class": "CONTEXT", + "explicit": true, + "content": [ + { + "name": "", + "type": { + "name": "TrailerField", + "type": "defined" + } + } + ], + "default": "trailerFieldBC" + } + ] + } + }, + "TrailerField": { + "name": "TrailerField", + "type": { + "name": "INTEGER", + "type": "builtin", + "content": { + "trailerFieldBC": 1 + } + } + }, + "RSASSA-AlgorithmIdentifier": { + "name": "RSASSA-AlgorithmIdentifier", + "type": { + "name": "AlgorithmIdentifier", + "type": "defined" + } + }, + "DigestInfo": { + "name": "DigestInfo", + "type": { + "name": "SEQUENCE", + "type": "builtin", + "content": [ + { + "id": "digestAlgorithm", + "name": "DigestAlgorithm", + "type": "defined" + }, + { + "id": "digest", + "name": "OCTET STRING", + "type": "builtin" + } + ] + } + }, + "DigestAlgorithm": { + "name": "DigestAlgorithm", + "type": { + "name": "AlgorithmIdentifier", + "type": "defined" + } + } + } } } ;}); diff --git a/updateRFC.sh b/updateRFC.sh index 6f82192..e2b2cf3 100755 --- a/updateRFC.sh +++ b/updateRFC.sh @@ -1,5 +1,5 @@ #/bin/sh -RFCs="5280 5208 3369 3161 2986 4211 4210" +RFCs="5280 5208 3369 3161 2986 4211 4210 8017" downloadRFC() { URL="https://www.ietf.org/rfc/rfc$1.txt" if [ -x /usr/bin/fetch ]; then From 1fcc683e9f7b2a1fe9eb88e277d7b995bc1af67c Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Sun, 31 Mar 2024 09:45:54 +0000 Subject: [PATCH 8/8] Force examples permissions. --- release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/release.sh b/release.sh index 466eb63..8aaea34 100755 --- a/release.sh +++ b/release.sh @@ -29,6 +29,7 @@ mtn automate tags it.lapo.asn1js | \ { print " " q $2 q ": " q $1 q "," } END { print "};});" } ' > tags.js +chmod 644 examples/* type gsha256sum >/dev/null && SHA256=gsha256sum || SHA256=sha256sum $SHA256 -t $FILES | gpg --clearsign > sha256sums.asc 7z a -tzip -mx=9 asn1js.zip $FILES sha256sums.asc