Skip to content

Commit

Permalink
propagate from branch 'it.lapo.asn1js' (head a9524436000d6561058ba0ae…
Browse files Browse the repository at this point in the history
…8e2a58a6c49837fd)

            to branch 'it.lapo.asn1js.esm' (head a6b77044e2cf0f91cb663d9d1fbfbca7f66c2d21)
  • Loading branch information
lapo-luchini committed Mar 30, 2024
2 parents 9ff23e1 + 8f048ac commit 5027c72
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 24 deletions.
34 changes: 20 additions & 14 deletions asn1.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,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) {
Expand Down Expand Up @@ -190,7 +190,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
Expand Down Expand Up @@ -245,7 +245,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) {
Expand Down Expand Up @@ -368,7 +368,7 @@ class ASN1Tag {

export 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;
Expand Down Expand Up @@ -531,15 +531,15 @@ export 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();
return buf;
}
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),
Expand All @@ -555,11 +555,11 @@ export 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 {
Expand All @@ -571,7 +571,7 @@ export 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);
}
}
};
Expand All @@ -583,11 +583,17 @@ export 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.';
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;
Expand All @@ -596,7 +602,7 @@ export 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);
Expand Down
7 changes: 6 additions & 1 deletion dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ export 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'),
Expand Down
24 changes: 15 additions & 9 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down Expand Up @@ -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
Expand All @@ -95,24 +97,28 @@ 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();
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 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);
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.');
Expand Down

0 comments on commit 5027c72

Please sign in to comment.