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
+29
View File
@@ -641,6 +641,35 @@ test('fcpDecode unwraps an FCI 6F template and rejects malformed input', () => {
assert.strictEqual(fcpDecode('6213' + FCP_TRANSPARENT.slice(4)).ok, false); // wrong outer length
});
test('fcpDecode accepts long-form BER lengths (81/82) — editor preview regression', () => {
// 62 12 <18B> vs 62 81 12 <same content>
const long81 = '628112' + FCP_TRANSPARENT.slice(4);
const d1 = fcpDecode(long81);
assert.strictEqual(d1.ok, true);
assert.strictEqual(d1.items.find(it => it.key === '80').decoded, '9 bytes');
// 2-byte length form
const d2 = fcpDecode('62820004' + '80020009');
assert.strictEqual(d2.ok, true);
assert.strictEqual(d2.items.find(it => it.key === '80').decoded, '9 bytes');
// nested A5 with a long-form length (A5 81 05 …)
const d3 = fcpDecode('62138202412183026F078A0105A581058503000000');
assert.strictEqual(d3.ok, true);
assert.strictEqual(d3.items.find(it => it.key === 'A5/85').decoded, '0 bytes');
// FCP content >= 128 bytes uses a long-form outer length
let big = '';
for (let i = 0; i < 13; i++) big += '8808' + '0102030405060708'; // 13 x 10B = 130B
const d4 = fcpDecode('628182' + big);
assert.strictEqual(d4.ok, true);
assert.strictEqual(d4.items.filter(it => it.key === '88').length, 13);
global.t = s => s;
assert.ok(profilerFciPreviewItems(long81).includes('File size: '));
delete global.t;
});
test('fcpDiffHtml highlights differing FCP parameters', () => {
global.t = s => s;
const same = fcpDiffHtml(FCP_TRANSPARENT, FCP_TRANSPARENT);