fix BER long-form lengths: parseBerLen read b length bytes instead of b & 0x7F

parseBerLen treated the first long-form length byte (0x81/0x82/...) as the
count of length bytes, so any TLV with a long-form length parsed as
garbage: the profiler FCI decoder returned ok:false (decoded preview
disappeared and never came back after editing an FCP with a '62 81 xx'
outer length or a long-form inner TLV), and the same bug hit parseTlvList
(C-APDU parser, INSTALL param walker), parseBerScript (expanded script
rows >= 128 bytes) and readLvField.

Per ISO 7816-4 5.2 / UICC_SPECS.md 1.7 the long form is 81-84 followed by
(b & 0x7F) length bytes. Fixed; short-form behavior unchanged.

New tests: parseBerLen short/81/82 forms, parseTlvList long-form outer and
inner TLVs, fcpDecode long-form regression (81/82, nested A5, >=128-byte
FCP) incl. the editor preview path. SW cache v73 -> v74.
This commit is contained in:
2026-09-11 21:32:23 +03:00
parent 6bfbb00994
commit 1e067dc883
4 changed files with 65 additions and 3 deletions
+33
View File
@@ -165,6 +165,39 @@ test('parseTlvList handles BER-TLVs', () => {
assert.strictEqual(tlvs[1].tag, '82');
});
test('parseBerLen handles short and long form lengths (ISO 7816-4 5.2)', () => {
assert.deepStrictEqual(parseBerLen('1200', 0), { len: 18, consumed: 2 });
assert.deepStrictEqual(parseBerLen('8112', 0), { len: 18, consumed: 4 });
assert.deepStrictEqual(parseBerLen('820100', 0), { len: 256, consumed: 6 });
assert.deepStrictEqual(parseBerLen('820182' + '0102030405060708', 0), { len: 386, consumed: 6 });
});
test('parseTlvList parses long-form lengths (81/82)', () => {
const short = parseTlvList('6212' + '8202412183026F078A010580020009880110');
assert.strictEqual(short.length, 1);
assert.strictEqual(short[0].tag, '62');
assert.strictEqual(short[0].length, 18);
// same content with a long-form outer length
const long81 = parseTlvList('628112' + '8202412183026F078A010580020009880110');
assert.strictEqual(long81.length, 1);
assert.strictEqual(long81[0].length, 18);
assert.strictEqual(long81[0].value, short[0].value);
// 2-byte length form
const long82 = parseTlvList('62820004' + '80020009');
assert.strictEqual(long82.length, 1);
assert.strictEqual(long82[0].length, 4);
assert.strictEqual(long82[0].value, '80020009');
// inner TLV with a long-form length (A5 81 05 85 03 00 00 00)
const inner = parseTlvList('A581058503000000');
assert.strictEqual(inner.length, 1);
assert.strictEqual(inner[0].tag, 'A5');
assert.strictEqual(inner[0].length, 5);
assert.strictEqual(inner[0].value, '8503000000');
});
test('gsm7Decode unpacks "HI" from C824', () => {
const bytes = new Uint8Array([0xC8, 0x24]);
assert.strictEqual(gsm7Decode(bytes), 'HI');