fix: UICC file-access parameters use tag 81, not 82 (v3.6.14)

TS 102 226 8.2.1.3.2.2 defines the EA inner tags as 80 (toolkit params),
C3 (toolkit DAP), 81 (UICC Access Application specific parameters) and 82
(UICC *Administrative* Access) - the plain-text spec extract had shifted the
table columns, so the access list was emitted under 82.  With the list under
82 the card rejected the ADF.USIM entry with 6A80 and the applet never got
its uicc.access.FileView rights (live 2026-09-28).

- stkParamsBuild emits the access list under 81 (the structure is unchanged:
  the admin field is coded the same way per 8.2.1.3.2.2.4).
- tests updated (81 04 / 81 0F / 81 17 expectations).

641 frontend / 496 Python green; version 3.6.14; sw simple-v287.
This commit is contained in:
2026-09-28 03:07:40 +03:00
parent 138760f75c
commit 7c683fcb0a
5 changed files with 22 additions and 21 deletions
+9 -8
View File
@@ -1682,7 +1682,7 @@
// ===== Version =====
// Single source of truth for the PWA version: shown in the header and used
// by the server version check in pysimConnect().
const SIMPLE_VERSION = '3.6.13';
const SIMPLE_VERSION = '3.6.14';
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
// ===== Tab switching =====
@@ -2548,7 +2548,7 @@ function ramResetGrants() {
// value cannot be coded: each TAR is 3 bytes (6 hex digits), and menu item
// identifiers 128..255 are reserved for the toolkit framework, so only
// 01..7F may be requested (TS 102 226 8.2.1.3.2.3). In EA mode `v.fsAccess`
// adds the UICC file-access parameters (tag '82') and `v.adfAccess` extends
// adds the UICC file-access parameters (tag '81') and `v.adfAccess` extends
// them with an ADF entry (AID from `v.adfAid`, default ADF.USIM); the SIM path
// grants access via the CA Access Domain field instead.
function stkParamsBuild(v) {
@@ -2600,21 +2600,22 @@ function stkParamsBuild(v) {
services.toString(16).padStart(2, '0');
let eaValue = '80' + berLenStr(tkPayload.length / 2) + tkPayload;
if (v.fsAccess) {
// UICC Access Application specific parameters (TS 102 226
// 8.2.1.3.2.2.2): every entry ends with the "Length of Access Domain
// DAP" byte (00 = no DAP):
// UICC Access Application specific parameters (tag '81', TS 102 226
// 8.2.1.3.2.2/8.2.1.3.2.2.2; '82' is the *Administrative* Access
// field): every entry ends with the "Length of Access Domain DAP"
// byte (00 = no DAP):
// [file system AID length 00 = shared FS][AD length 01]
// [ADP 00 = full access][DAP length 00]
// [ADF AID length][ADF AID][AD length 01][ADP 00][DAP length 00]
// (without the DAP length byte the card rejected the ADF entry with
// 6A80; the ADF AID must be 5..16 bytes.)
// (the ADF AID must be 5..16 bytes; under '82' the card rejected the
// ADF entry with 6A80 - the applet never got its FileView rights.)
let acc = '000100' + '00';
if (v.adfAccess) {
const adf = (v.adfAid || 'A0000000871002').replace(/[^0-9a-fA-F]/g, '').toUpperCase();
if (adf.length < 10 || adf.length > 32) return null;
acc += (adf.length / 2).toString(16).padStart(2, '0').toUpperCase() + adf + '0100' + '00';
}
eaValue += '82' + berLenStr(acc.length / 2) + acc;
eaValue += '81' + berLenStr(acc.length / 2) + acc;
}
return 'EA' + berLenStr(eaValue.length / 2) + eaValue;
}
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simple-v286';
const CACHE = 'simple-v287';
const URLS = [
'index.html',
'help.html',
+10 -10
View File
@@ -150,24 +150,24 @@ test('the RAM form fields build the live install parameters end to end', () => {
});
test('UICC file-access parameters (82) are appended in EA mode', () => {
// TS 102 226 8.2.1.3.2.2.2: every entry ends with the "Length of Access
// Domain DAP" byte (00 = no DAP):
// TS 102 226 8.2.1.3.2.2/8.2.1.3.2.2.2: the file-access list is the
// tag '81' field ('82' is the *Administrative* Access field); every entry
// ends with the "Length of Access Domain DAP" byte (00 = no DAP):
// [FS AID len 00 = shared FS][AD len 01][ADP 00 = full][DAP len 00]
// [ADF AID len][ADF AID][AD len 01][ADP 00][DAP len 00]
// The SIM path grants the same rights via the CA Access Domain field; the
// ADF entry is an extension of the file-system entry. A missing DAP
// length byte made the card reject the ADF entry with 6A80 (live
// 2026-09-28).
// ADF entry is an extension of the file-system entry. Under '82' the card
// rejected the ADF entry with 6A80 (live 2026-09-28).
const base = vals({ channels: '1', msl: '12', tar: 'AF4D01' });
assert.strictEqual(stkParamsBuild(Object.assign({}, base, { fsAccess: true })),
'EA15800D000000000102011203AF4D0100820400010000');
'EA15800D000000000102011203AF4D0100810400010000');
assert.strictEqual(
stkParamsBuild(Object.assign({}, base, { fsAccess: true, adfAccess: true })),
'EA20800D000000000102011203AF4D0100820F0001000007A0000000871002010000');
'EA20800D000000000102011203AF4D0100810F0001000007A0000000871002010000');
assert.strictEqual(
stkParamsBuild(Object.assign({}, base, { fsAccess: true, adfAccess: true,
adfAid: 'A0000000871002FF33FFFF89010101' })),
'EA28800D000000000102011203AF4D01008217000100000FA0000000871002FF33FFFF89010101010000');
'EA28800D000000000102011203AF4D01008117000100000FA0000000871002FF33FFFF89010101010000');
assert.strictEqual(stkParamsBuild(base), 'EA0F800D000000000102011203AF4D0100');
assert.strictEqual(stkParamsBuild(Object.assign({}, base, { adfAccess: true })),
'EA0F800D000000000102011203AF4D0100');
@@ -182,12 +182,12 @@ test('the RAM form emits full file access when the checkbox is ticked', () => {
fakeForm({ 'rc-toolkit-enable': true, 'rc-tk-mode': 'ea', 'rc-tk-msl': '12',
'rc-tk-tar': 'AF4D01', 'rc-tk-channels': '1', 'rc-tk-fsaccess': true });
assert.strictEqual(buildRcToolkitParams(),
'EA15800D000000000102011203AF4D0100820400010000');
'EA15800D000000000102011203AF4D0100810400010000');
fakeForm({ 'rc-toolkit-enable': true, 'rc-tk-mode': 'ea', 'rc-tk-msl': '12',
'rc-tk-tar': 'AF4D01', 'rc-tk-channels': '1', 'rc-tk-fsaccess': true,
'rc-tk-adfaccess': true });
assert.strictEqual(buildRcToolkitParams(),
'EA20800D000000000102011203AF4D0100820F0001000007A0000000871002010000');
'EA20800D000000000102011203AF4D0100810F0001000007A0000000871002010000');
});
test('updateStkParamsHex refreshes the field and clears the manual flag', () => {