Commit Graph

39 Commits

Author SHA1 Message Date
catarrh aa4bf8e008 feat: expanded registry on by default, form ladder + fallback report (v3.6.54)
The 'Fetch expanded registry details' checkbox is now on by default: the
expanded pass carries the package versions, the SD/load-file associations
and the applet menu entries; an explicit stored opt-out is still honoured.

Live 2026-09-30: a card with a non-default ISD AID answered 6A88 to the
reference expanded query (P2=02 + the tag list), so the ELF rows had no
versions.  Cards differ in what they accept, so the query is now tried in
three forms (RAM_EXPANDED_FORMS):

  tags   - the reference tag list (incl. the TS 102 226 EA SCP Registry Data)
  noea   - the same list without EA (a card that errors on it)
  notags - no tag list at all (GPPro's 4F00-only data field); the card
           builds the default E3

The first form that answers is remembered for the run and tried first for
the later listings; the ISD gets a single attempt - its 6A88/6A86 is normal
('no data to report', GPPro) and must not poison the detection for the
apps/ELF queries.

Every listing's outcome is reported in the explorer (ramExpandedReport):
'Expanded registry: tag list + EA (Apps, ELFs) - ISD: no expanded data
(6A88) - compact listing used', or 'Expanded registry refused by the card -
compact listing only (package versions unavailable)'; the ELF section hints
when no version came back.  Tooltip/help (EN/RU) updated.

sw cache simple-v327; tests: 550 Python / 707 Node.
2026-09-30 09:44:39 +03:00
catarrh 4906c91463 feat: install LOAD failures get the compatibility-test analysis (v3.6.53)
ramShowInstallResult appends ramCompatDetailHtml(data, capMem) to the
install modal (the modal content is HTML now - the step lines are escaped
and ramOpModalFinish takes the asHtml mode), so a failed LOAD / INSTALL
[for load] shows the same block analysis as the compatibility test:

- the failing block's CAP section (load-file byte range and components, and
  what completes there), with the JC VM spec 4.5.2 note - or 'the import
  list already passed' when the failure is later in the file;
- the remote status word with its name;
- the import list at the CAP's own versions (a real install runs no probe);
  the closing hint points at the compatibility test ('Set all 0.0' first,
  then bisect), while a probe run keeps the lower-the-versions wording.

ramInstallFailHint stays as the short inline hint; INSTALL [for install] and
/api/ram-install-app failures show no block (the LOAD guard in the helper).

sw cache simple-v326; tests: 550 Python / 704 Node.
2026-09-30 09:27:42 +03:00
catarrh ee747003f2 feat: CAP compatibility test in the popup + per-AID failure analysis (v3.6.52)
The compatibility test now runs in the same operation modal as the installs
(live progress from the server's ram_progress, Close disabled until done) and
its result gains a per-AID detail block instead of the comma list:

- the probe summary (probe: 2 imports -> 0.0 . +1 appended);
- the import list as tested (ramCompatImportRows): the CAP's imports with the
  version the card was asked for and the CAP's own version when the probe
  lowered it, appended synthetic entries and unmatched lines - each with the
  resolved library name (jcAidName), so a raw AID list becomes readable rows;
- on a rejection, the failure analysis (ramCompatFailureHtml): which CAP
  section the failing block covers (load-file byte range and component names,
  'completes Import'), what the card checks at that point (JC VM spec 4.5.2)
  or that the import list already passed, the remote status word with its
  name, and what the probe state implies (every import at 0.0 -> a missing
  package or another load-file check is the cause; otherwise lower the
  versions and bisect).

ramCompatVerdict names the remote SW; the inline result keeps the verdict +
short probe note and the modal carries the escaped step lines + the detail
HTML (ramOpModalFinish gained an asHtml mode); the server reports
probe_unmatched as [{'aid', 'version'}] (_probe_unmatched), documented in
docs/api.md.  The same failure block for the real install is the next step.

sw cache simple-v325; tests: 550 Python / 703 Node.
2026-09-30 09:22:22 +03:00
catarrh 599d84fd66 feat: Explore exposes the rest of the registry data + install NV footprint (v3.6.51)
The compact (legacy) GET STATUS entry is <aid_len><AID><life cycle>
<privileges> + (P1=10) <module count> (<len><module AID>)*, cross-checked
against GlobalPlatformPro's populate_legacy (the 4th byte is privileges;
0x00 is required for load files).  The parser read it as a 'version' one
byte late, so ELF rows showed the module count / the next entry's length as
Version: 00/10 - the compact listing has no version at all; it now comes
from the expanded CE tag (ramFmtVersion: 2 bytes -> major.minor, GP Table
11-37 Note 1) and merges (the bogus compact value no longer blocked it).

New data exposed:
- EA SCP Registry Data (TS 102 226 8.2.1.6) -> 80 Menu Parameters -> the
  applet's STK menu entries: STK menu entry: 0x80 (position 1, Enabled)
- unknown registry objects are preserved (rawTlvs) and shown as
  'Other registry data: 8F=752B . 90=012D ...' instead of being dropped
- 84 parses the GP coding (one Executable Module AID per TLV, repeated; the
  concatenated 4F<len><aid> form stays as fallback) and the ELF expanded
  queries add 84 to the tag list (with a tag list the card returns only the
  listed tags - the fallback path would otherwise lose the module lists and
  their Install buttons)
- life cycle names decode per object kind (GP Tables 11-3..11-6: ISD/card,
  app, SD - detected via the Security Domain privilege - and ELF), with
  multi-byte 9F70 (02 0700 on live cards) decoding the first byte and
  surfacing non-zero extras; the R-APDU parser's LIFECYCLE_MAP labels were
  aligned with the same tables

/api/ram-install measures the NV footprint: a silent GET DATA FF21 read
before and after the chain (also on failure) returns nv_before/nv_after/
nv_delta; the reads never fail the operation (no FF21 -> no fields) and the
PWA shows 'NV used: ~N B (free A -> B)' in the install result.

sw cache simple-v324; tests: 548 Python / 698 Node.
2026-09-30 09:00:33 +03:00
catarrh be411a7b4b feat: toolkit parameters in three columns + one access row (v3.6.50)
The SIM/UICC Toolkit parameters grid is grid-cols-3 now: the 12 narrow
fields (priority, timers, text length, menus, first pos/id, last pos/id,
channels, MSL, TAR, access domain) fit in four clean rows, Max services
keeps its own row (it was a lone half-row in the 2-column layout) and the
file-access group is one col-span-3 row: File system access (full) ·
ADF.USIM access (full) · ADF AID (hex) + From card.

The ADF AID cell is its own rc-tk-adfaid-row; the whole group is wrapped
in rc-tk-access-row, which updateRcTkMode hides in SIM/CA mode (hiding
only the old checkbox rows would leave the AID field behind).

grid-cols-3/col-span-3 were already compiled (no Tailwind rebuild); the
html test pins the 3-column grid and the spanning access row with its
three cells, the JS guard pins the CA/EA visibility.

sw cache simple-v323; tests: 540 Python / 689 Node.
2026-09-30 08:22:46 +03:00
catarrh 80c26f14f2 fix: CAP compatibility test review fixes (v3.6.49)
Review of v3.6.48 found six issues; the two that matter in use:

- ramProbeParse('') errored, so the basic 'is this CAP compatible with
  this card at all?' run (no overrides) was refused by an alert.  An empty
  list is valid now: the test runs with the CAP's own versions.
- ramCompatVerdict said 'Import list rejected' for every failure.  It now
  distinguishes: a request error (no steps), a failed format probe (the
  card not answering), an INSTALL [for load] refusal, and only then the
  import list - each with its own headline.

Plus:
- the result line shows the applied probe (ramCompatProbeNote: 'probe:
  7 imports -> 0.0 · +1 appended', unmatched AIDs included);
- #ram-compat-block validates 1..240 like the install's block size;
- the server reports probe_unmatched (override AIDs matching no entry,
  previously silent when another override matched) and logs them;
- tests: the endpoint's probe-400 path (a mini CAP + a dummy scc),
  _cap_import_aids, the verdict cases and the probe note.

sw cache simple-v322; tests: 540 Python / 687 Node.
2026-09-30 08:13:12 +03:00
catarrh 0dc79a3ba4 feat: CAP compatibility test as its own operation + append-only imports (v3.6.48)
The import probe no longer lives in 'Install Package (.cap file)': a
diagnostic that can leave a LOADED-only package does not belong in the
operation meant to produce a working applet.  /api/ram-install no longer
takes probe_imports; the install form's probe fieldset is gone.

New RAM operation CAP compatibility test (POST /api/cap-compat): the
server runs the format check, INSTALL [for load] and the LOAD blocks only
up to the block that completes the Import component (_cap_import_end +
_cap_compat_blocks, computed from the load file and the C4 TLV framing),
then stops - no last-block flag, no INSTALL [for install], so nothing is
committed and nothing needs deleting.  The verdict (imports_ok,
boundary_block/total_blocks) states it covers the LOAD/import gate only;
the link gate stays the real install's business.  Verified on the real
RemMobileID CAP: the boundary is LOAD 1/64, 2/128, 3/240 for 240/120/64 B
blocks - exactly the blocks where the live cards rejected the load.

_probe_import_versions(load_file, overrides, additions) now supports
append-only synthetic imports: +AID=version appends a new entry, the
Import component's size field and the Directory's Import size are patched,
and existing entries keep their positions (constant-pool import indices
stay valid); an AID that is already imported becomes a version override.
This is the card-capability query ('does this card export package X at
>= Y?') without building a probe applet.

PWA: new op section (CAP file + analysis + the version list + block size),
ramCompatTest with inline results and ramCompatVerdict, ramProbeParse
understands +AID=version; help EN/RU documents the operation, the two-step
bisect and the gate scope.

sw cache simple-v321; tests: 538 Python / 686 Node.
2026-09-30 07:57:11 +03:00
catarrh ef949e6a17 fix: cached GETs bypass the card lock; compact install step lines (v3.6.47)
The install modal's progress bar froze around 70% and jumped to 100% at
the end: not a math bug - the UI's other polls (/api/stk-status,
/api/poll-status, /api/proactive-log, /api/menu, ...) were card-locked in
do_GET even though they only read cached state, queued behind the install
and exhausted the browser's 6-connections-per-host budget, starving
/api/status.  _CARD_FREE_GET lists every card-free GET (status, version,
stk-status, poll-status, proactive-log, menu, events, terminal-profile,
pli-*, commands, net-state, mcc-mnc, scp81/bip status|script|log);
/api/cardinfo and /api/esim/* stay locked (they touch the card).

tests/test_fetch_routes.py holds _CARD_LOCK and asserts the cached
endpoints still answer - verified to time out on the pre-fix list.

The install modal is wider (max-w-3xl) and successful step lines are
compact: '✅ Step 3: LOAD (1/240) - 6101 · 274 B / 3 SMS' (no verbose SW
name, B instead of bytes, the SMS count only when >1); failed steps keep
the full detail and the hint.

sw cache simple-v320; tests: 533 Python / 684 Node.
2026-09-30 00:02:52 +03:00
catarrh cf9c9b7bab feat: clean up the Explore UX (v3.6.45)
- Explore runs inline: no blocking modal (that stays for the install
  operations, which can leave a half-loaded package; Explore leaves the
  card consistent).  A test guards that ramExplore never calls the modal.
- Minimal success line: just OK - the details live in the explorer below;
  error runs keep the detailed 'Partial - ...' line.
- Counts moved into the section headings (Applications / Applet Instances
  (n), Executable Load Files (ELFs) / Packages (n)); the redundant '1 ISD'
  count is gone (P1=80 returns the ISD as a single occurrence, GP
  11.4.2.1).
- The RAM command format line gained a tooltip: compact = TS 102 226
  5.2.1 command string, expanded = the AA/22 scripting template (5.2.1.0),
  detected per operation with a read-only GET STATUS probe.
- The expanded-registry checkbox is relabelled 'Fetch expanded registry
  details (load-file / SD associations)' with a tooltip (extra secured
  packets, card support varies, the fallback is automatic) and is now a
  sticky per-browser preference (simple_ram_expanded).

sw cache simple-v318; tests: 531 Python / 681 Node.
2026-09-29 23:34:42 +03:00
catarrh 755470e4ba feat: RAM-install import probe for LOAD rejections (v3.6.42)
Cards that cannot satisfy the CAP's import list reject the LOAD as soon
as the Import component is complete (live 2026-09-29: 6438/6985 in the
block containing its last byte, on several cards incl. an eUICC profile
whose ISD is not the default AID and which does not answer GET DATA 0066 -
no direct platform-version readout exists).

_probe_import_versions (pure) rewrites the Import component's two version
bytes per entry in the assembled load file: same length, component sizes,
Directory and offsets untouched; unknown AIDs and bad versions are
rejected.  /api/ram-install takes probe_imports ({'all': '0.0'} or
per-AID), echoes the applied changes in the response and logs them.  The
PWA's RAM install form gains a collapsed Import probe fieldset (checkbox,
AID=version lines prefilled from the CAP analysis, 'Set all 0.0') and the
result line reports the applied changes.  Diagnostic only - never used for
a real install.

Also verified _cap_parse's component order against the reference TCA load
trace (Header, Directory, Import, Applet, Class, Method, StaticField,
ConstantPool, RefLocation, Descriptor - Import before Applet, not
ascending tag order), so the order is correct and the import list remains
the prime suspect.

sw cache simple-v315; tests: 530 Python / 676 Node.
2026-09-29 03:41:07 +03:00
catarrh ddf5cbb8e7 fix: late-PoR handler on every path, one poll per packet, LOAD-step components (v3.6.37)
_send_envelope defined its SEND SHORT MESSAGE capture handler inside the
91xx branch, but the 'STATUS poll (PoR not captured)' path used it: a
packet whose ENVELOPE answered 9000 and whose late PoR arrived on the
STATUS poll raised UnboundLocalError, returned 500 and aborted the RAM
operation mid-packet with the card's command left pending (live
2026-09-29, 120-byte LOAD blocks).  The handler is now defined for every
path, and the late-PoR poll runs only after a packet's last segment
(poll_status from _send_secured_packet) - a concatenated download makes
no spurious mid-packet STATUS exchanges.

The PWA annotates every LOAD step with the CAP components its block
covers (ramStepComponents: 'completes Import' / 'inside Method' /
'Header...Import') and ramInstallFailHint names the component the failing
block completed - the live import-verification rejection lands in the
block completing Import (6438/6985 at both 240 B and 64 B blocks).

sw cache simple-v310; tests: 509 Python / 672 Node.
2026-09-29 01:14:37 +03:00
catarrh f007d5c9be feat: CAP platform requirement + LOAD rejection hint (v3.6.36)
capmem derives the minimum platform from the CAP's Import component
(javacard.framework -> Java Card level via the SDK-kit corpus, int flag)
and /api/cap-info exposes it; the CAP details show it as a Platform row
('Java Card >= 2.2.2 - CAP format 2.1 - int support').

A failed RAM install at a LOAD / INSTALL [for load] step now appends a
hint naming the import requirement and the smaller-block fallback
(ramInstallFailHint, pure): JC VM spec 4.5.2 makes every import a
'>= version' demand on the card's own packages checked while the load
file is verified - live 2026-09-29, a CAP requiring Java Card 2.2.2 was
rejected exactly at the block containing the end of Import (6438 at
240 B blocks, 6985 at 64 B), not at a step count.

sw cache simple-v309; tests: 507 Python / 670 Node.
2026-09-29 00:59:17 +03:00
catarrh 0b7b6b8157 feat: RAM operations run behind a blocking modal (v3.6.34)
A CAP install is a long chain of LOAD commands whose progress and results
were only visible at the bottom of a large form - and an interrupted
install can leave a half-loaded package.

- Server: _RAM_PROGRESS (+ _ram_progress_begin/step/end) records the live
  step of the running RAM operation; /api/ram-install and
  /api/ram-install-app wrap their chains in it (total = steps + 1 for the
  format check) and /api/status carries it as ram_progress - lock-free, so
  the 2 s poll works while the request holds _CARD_LOCK.
- PWA: #ram-op-modal (the STK panel pattern) blocks everything while a RAM
  operation runs: title, spinner, status line, progress bar, per-step
  result lines, Close disabled until it finishes; a beforeunload guard
  protects the window during the run.  install-cap, install-app /
  make-selectable and Explore all use the shared helpers
  (ramOpModalBegin/Status/Finish); the install results stay in the form
  area as before once the modal is closed.  The status poll feeds the modal
  via ramOpProgress (headline from the pure ramOpProgressText).
- Tests: ramOpProgressText (JS) + the progress lifecycle (Python); the
  card-state and capmem suites stub the DOM-bound hooks.
- Stylesheet rebuilt; version 3.6.34; sw simple-v307.
2026-09-29 00:09:35 +03:00
catarrh e820a7ed41 feat: toolkit block emphasised + auto CA/EA from the CAP (v3.6.32)
The RAM install form's toolkit parameters are the make-or-break field for
toolkit applets, and CA vs EA is easy to get wrong (the earlier live 6A80s).

- "SIM/UICC Toolkit parameters" is now an accented bordered fieldset (blue
  border/legend, always visible in the cap / install / make-selectable
  modes) with the checkbox in the legend and the fields inside.
- ramCapToolkitMode(imports) maps the CAP's linked libraries to the install
  parameter family: sim.* (AID tree A0000000090003FFFFFFFF89...) -> SIM
  Toolkit (Tag CA), uicc.* / uicc.usim.* (A0000000090005FFFFFFFF89...,
  A0000000871005FFFFFFFF89...) -> UICC Toolkit (Tag EA) - family-based, so
  access-only applets get the right field too.  Applied when the block is
  enabled and when the CAP is swapped while it is on, with a "detected from
  the CAP" hint under the select; no CAP keeps the manual choice.
- Rebuilt style.css for the new accent classes; tests pin the fieldset and
  the family mapping.

663 frontend / 504 Python green; version 3.6.32; sw simple-v305.
2026-09-28 23:49:00 +03:00
catarrh c3117e90fa fix: rebuilt stylesheet + visible explorer rows (v3.6.30)
The compiled Tailwind stylesheet (frontend/style.css) had been stale since
2026-09-22: classes introduced later were missing from it, so the Install /
Make selectable chips had no background or text colour in light mode (dark
mode only looked green because an older dark:text-emerald-400 rule matched)
and the new w-28 action column did not apply.

- Rebuilt with `npm run build` (Tailwind + appended src/contrast.css);
  verified the previously missing classes (bg-emerald-100, text-emerald-700,
  hover:bg-emerald-200, bg-red-100, bg-blue-100, w-28, ...).
- Explorer rows are visible chips now: rounded bg-gray-50 dark:bg-slate-800/60
  with a hover:bg-gray-100 highlight and the colored left accent kept (module
  rows a subtler variant), so a right-column button is unambiguously tied to
  its row; ISD/app/ELF/module rows all use the same treatment.
- AGENTS working conventions: an index.html change that introduces new
  utility classes also requires `npm run build` in frontend/.

660 frontend / 504 Python green; version 3.6.30; sw simple-v303.
2026-09-28 23:38:06 +03:00
catarrh 3b5a1495f5 feat: table-align the explorer action buttons, Install green (v3.6.29)
The explorer buttons sat inline after each AID/detail line, so their columns
moved with the text length.  Now every entry (app / ELF) and every module
line is a row with a fixed-width action column (w-28):

- left cell: the text (module rows are siblings of their ELF entry, indented
  pl-6, so their buttons share the same column as the entry buttons);
- right cell: the buttons, full width of the column, so Delete / Delete All /
  Make selectable / Install line up vertically across rows.

All buttons go through ramActionBtn(label, action, tone): Danger (red) for
Delete / Delete All, Ok (emerald) for Make selectable and the **Install**
buttons, which were blue.  Test pins the column width and the Install tone.

660 frontend / 504 Python green; version 3.6.29; sw simple-v302.
2026-09-28 23:29:55 +03:00
catarrh 90fe409dec fix: correct the GP privilege decode and remove the duplicate (v3.6.28)
The RAM explorer's ramFmtPrivileges used a private table with wrong bits and
invented names ("Cum Deletion Ctr", "GSM Card Binding", "Global PIN",
"RFM"/"CFM") and no case for 0x80: a live ISD 9E printed four wrong names
and dropped Security Domain.  Per GP Card Spec v2.3.1 11.1.2 Tables
11-7/8/9, 9E = Security Domain, Card Lock, Card Terminate, Card Reset, CVM
Management.

- ramFmtPrivileges now delegates to decodePrivileges (one spec table).
- decodePrivileges decodes byte 1's DAP pair per Table 11-7: b8+b7 = DAP
  Verification, b8+b7+b1 = Mandated DAP Verification; the flag bits alone
  are no privilege.
- The file had two decodePrivileges copies (the runtime used the later one,
  the C-APDU parser test the earlier); the duplicate and its private table
  are gone - the single implementation plus PRIVILEGE_NAMES live in the
  parser section, which the test evaluates (converted to var like PARSE_INS).
- Tests: 9E/9A live values, the DAP pair, byte 2/3 spot checks; the
  PRIVILEGE_NAMES spec pin moved to apdu_parse.

659 frontend / 504 Python green; version 3.6.28; sw simple-v301.
2026-09-28 23:29:01 +03:00
catarrh 85ba2a709d fix: explain the FF21 resource block and move the format line last (v3.6.27)
The explorer's FF21 block was titled "Memory (GET DATA FF21)" although the
tag is the Extended Card Resources Information (GP tag FF21, TS 102 226
8.2.1.7.2: installed applications, free non-volatile and free volatile
memory), and the detected RAM command format line sat between the Free NV
and Free Volatile lines.

- Heading is now "Card resources (GET DATA FF21)" with a tooltip naming the
  tag and its three fields (EN/RU).
- The "RAM command format:" line moved after the resource lines.
- Help EN/RU spells out what FF21 returns; test asserts the format line
  follows the resource lines.

657 frontend / 504 Python green; version 3.6.27; sw simple-v300.
2026-09-28 23:18:00 +03:00
catarrh 7c81f02308 feat: Explore expanded (E3) listing fallback + details pass + format display (v3.6.25)
The E3 parsers existed since the vendor-trace work; what was missing was
issuing the query.  Per GP 11.4.2.2 the compact listing format (P2.b2=0) is
deprecated and a card may reject it, while the expanded form (P2=02 + the
tag list 4F 9F70 C5 C4 CC CE EA) returns the richer registry data.

- ramExpandedQueryApdu(p1): the reference trace bytes
  (80F2 <p1> 02 0C 4F005C084F9F70C5C4CCCEEA 00), pinned in a test.
- Explore: when the compact pass for a P1 yields nothing, the query is
  retried in the expanded format and the result becomes the listing (the
  compact error only surfaces if the retry also fails); the new "Query
  expanded registry details (E3)" checkbox runs the expanded pass on top of
  a working compact listing and merges the expanded-only fields
  (privileges, ELF AID C4, SD AID CC, module lists) into the entries.
- The detected RAM command format (v3.6.24 ram_format) is now shown in the
  Explore result + explorer view, the delete verdict and the plain-send
  message.
- Tests parse the real trace payloads (NC ISD, ET application, NP ELF E3
  templates); help EN/RU updated.

656 frontend / 504 Python green; version 3.6.25; sw simple-v298.
2026-09-28 22:51:20 +03:00
catarrh 5372a770eb fix: keep a hand-edited packet TAR in the SCP80 send (v3.6.21)
The plain "Send to Card" path refreshed the whole preset right before
sending (spRefreshFromPreset -> cardsApply -> cardsApplyFields) and
re-applied the preset's slot TAR - so a TAR typed for a push/link trigger,
an applet OTA message or the HTTP OTA admin params was silently replaced by
the preset's ISD TAR (the pack buttons for those sources deliberately leave
the TAR manual; the help even said so).

- spRefreshFromPreset(selId, keepTar): the plain send passes keepTar, so
  the form's TAR survives; the counter, keys and SPI are still re-read.
- selecting a card preset, ramApplyCard and the chain packs still set the
  TAR; the RAM operations keep the preset's ISD TAR by design.
- spParams()/getRamSpParams() normalise the TAR (strip/upper/pad to 6);
  only the preview padded before, a short TAR went to the server raw.
- help EN/RU clarified, cards_counter/ram tests updated, sw simple-v294.

652 frontend / 499 Python green; version 3.6.21.
2026-09-28 21:43:57 +03:00
catarrh face2268ca feat: single-APDU INSTALL [for install] / [for make selectable] ops (v3.6.18)
Iterating the final install step no longer needs a delete + re-load of the
.cap:

- `POST /api/ram-install-app` runs INSTALL [for install] (`mode: "install"`,
  P1 0x0C/0x04 by make_selectable) or INSTALL [for make selectable]
  (`mode: "make_selectable"`, GP 11.5.2.3.3 Table 11-44) for an already
  loaded package.  The APDU builders are shared with `_cap_apdu_sequence`
  (`_cap_install_apdu`, `_cap_make_selectable_apdu` - one builder, no drift)
  and the per-step send/PoR/counter logic is the extracted shared
  `_ram_send_gp_apdu` (used by /api/ram-install too).
- PWA: the RAM op selector gains "INSTALL [for install] (loaded package)"
  and "INSTALL [for make selectable]" with Load File / Module / Instance AID
  inputs (instance defaults to the module AID); the result renders through
  the shared `ramShowInstallResult` and `final_cntr` keeps the preset in
  sync.
- Explore: an **Install** button on a package's module AIDs that have no
  instance yet, and a **Make selectable** button on INSTALLED (0x03)
  instances - both switch the op and pre-fill the AIDs.
- tests: the install APDU pinned to the live no-STK packet and to the
  sequence tail, the make-selectable APDU, ramHasInstance, the Explore
  buttons and the op wiring; docs/api.md updated.

650 frontend / 498 Python green; version 3.6.18; sw simple-v291.
2026-09-28 08:10:40 +03:00
catarrh bab787fac1 fix: DELETE APDU is case 3 - no phantom command (v3.6.15)
The Explore delete showed "Failed: por_ok - remote SW 6700" while the delete
executed: ramDeleteApdu appended the trailing Le, and this card's SCP80
layer counts a trailing byte as a phantom second command whose SW 6700
masked the real result (count=2, last SW 6700) - the same quirk as
INSTALL [for load] before v3.6.8.

- ramDeleteApdu and the chain builder's DELETE row emit the case-3 APDU
  (4F AID TLV, no Le); the SCP81 Delete-AID template follows (it reuses
  ramDeleteApdu).
- tests updated (delete APDU expectations in ram/ram_counter_flow/scripts).

641 frontend / 496 Python green; version 3.6.15; sw simple-v288.
2026-09-28 03:16:10 +03:00
catarrh 138760f75c fix: Explore delete - real SPI2, no-PoR verdict, local removal (v3.6.13)
"Failed: 9000" although the delete executed: the RAM helpers sent
`sp-spi2` - the base SPI2 select, whose default is "00 - No PoR" - so the
card answered the envelope 9000 with no PoR and the verdict treated the
missing PoR as a failure.  `cardsApplyFields` also set `sp-spi2-hex` from
the preset and then `updateSp()` recomputed it from the selects (which the
preset never updated), clobbering the preset byte for anything reading it.

- `getRamSpParams()` reads the computed `sp-spi2-hex`; `cardsApplyFields`
  syncs the SPI2 selects from the preset byte (base = low 5 bits, bit 0x20
  = PoR via SMS-SUBMIT, dynamic option for unlisted bases) and the base
  select gains the missing cipher + RC/CC/DS combinations (15/19/1D).
- a missing PoR is no longer a failure (the SPI may request none, and the
  card sometimes refuses one): `OK` with the SW, or `OK (no PoR)`.
- a successful delete drops the object from the Explore result locally (no
  re-explore): an applet row goes away; a cascade package delete also drops
  the applets whose AID starts with the package AID.  The consumed counter
  is still saved.
- tests: ramRemoveFromExplorer (app/cascade/prefix), the no-PoR flow, the
  SPI2 source guard, and the updated delete-flow stubs.

641 frontend / 496 Python green; version 3.6.13; sw simple-v286.
2026-09-28 03:03:53 +03:00
catarrh a0704a8fd0 fix: Explore Apps listing uses the SMS-submit PoR transport (v3.6.10)
The Apps query (P1=40) was sent with SPI2=0x01 while only the ELF queries
(P1=20/10) used SPI2=0x21.  The Apps listing can exceed the ENVELOPE
response, and the card then answers the envelope PoR with
`actual_response_sms_submit` - the actual response would follow as an
SMS-SUBMIT, which is never sent unless the PoR is requested in submit mode.
The paginate only accepted `por_ok`, so the Explore reported the raw status
as an error ("Partial - Apps: actual_response_sms_submit") and the Apps list
never rendered (live 2026-09-28).

- `ramListingSpi2(p1)`: 40/20/10 -> '21', else '01'; the paginate uses it.
- the paginate accepts `actual_response_sms_submit` via `spPorAccepted` and,
  when no data arrived, notes "response via SMS not captured" instead of
  reporting the card status as a failure.
- the Explore delete verdict follows the same acceptance rule (an accepted
  SMS-submit delete no longer shows "Failed" while its counter advanced) and
  no longer prints a dangling " -> " without a SW.
- tests: ramListingSpi2 + the delete-accepted-via-sms-submit flow.

633 frontend / 496 Python green; version 3.6.10; sw simple-v283.
2026-09-28 02:13:13 +03:00
catarrh 9fb2ad5d2b fix: send the STK install parameters as entered (v3.6.9)
The RAM install form sent the `STK parameters (hex)` field, which was only
regenerated when the toolkit checkbox or the mode select changed - editing
the TAR (or any other toolkit field) afterwards was silently dropped.  The
live install therefore carried the form defaults (TAR B00001, textLen 0,
menus 0, MSL 16, channels 0) instead of the entered AF4D01 / MSL 12 /
channels 1, and the card rejected the install parameters with 6A80
(TS 102 226 8.2.1.3.2.7: a TAR already assigned on the card).

- every `rc-tk-*` field regenerates the hex on input/change; the install
  recomputes it at send time unless the user hand-edited the hex
  (`dataset.manual`), so the edit order can no longer drop values;
- one pure `stkParamsBuild` serves the RAM form (`buildRcToolkitParams`) and
  the RAM/GP chain rows (`buildTkParams`) - no drift between them (the chain
  row also gains the menu-ID <= 7F check);
- applet TAR field: empty by default, no placeholder - B0 00 01 is the
  allocated ADF RFM TAR (TS 101 220 Annex D), not an applet TAR; an empty
  field is coded as TAR length 00 (the card may take a TAR from the AID only
  when the AID carries one, PIX hex digits 15-20);
- the chain builder's INSTALL/LOAD rows drop the trailing Le (the v3.6.8
  server form; a trailing Le made the card execute a phantom command);
- tests: stk_params.test.js (the decrypted live parameters, empty-TAR
  coding, CA wrapper, long-form lengths, rejection cases, form wiring, and
  the form -> hex path with the real builders) and ram_counter_flow.test.js
  (the Explore delete persists the consumed counter through the real
  ramSaveCntr); STK fixtures no longer use B00001.

631 frontend / 496 Python green; version 3.6.9; sw simple-v282.
2026-09-28 01:49:35 +03:00
catarrh 50fa8744fd fix: keep the preset counter intact through the Explore delete flow (v3.6.7)
Delete All worked but reset the preset counter: the handler never re-read
the preset (unlike ramExecute), saved N+1, then re-ran the Explore with the
OLD sp (counter N).  Every page answered cntr_low, nothing was accepted, and
ramExplore's final ramSaveCntr wrote N back over the preset.

- ramDeleteFromExplorer re-reads the preset first (spRefreshFromPreset
  'ram-card-sel'), advances and saves the counter only for a packet the card
  accepted (spPorAccepted) - a rejected packet leaves it untouched - and
  continues the follow-up Explore from the consumed counter instead of
  replaying it.
- the delete result also checks the remote command's SW via a new
  `ramRemoteSwOk` (9000 / 61xx / 62xx / 63xx / CAFE, mirroring the server's
  `_ram_remote_sw_ok`): a por_ok packet whose DELETE was refused (e.g. 6A88)
  no longer shows "OK" (the counter still advances, the card consumed it).
- ramExplore only saves the counter when it advanced, so a stale caller can
  never lower a preset counter again.
- tests: flow tests for accepted / rejected / refused-remote-SW deletes
  (refresh order, saved counter, the counter passed to the re-explore) and
  the ramRemoteSwOk set.

615 frontend / 495 Python green; version 3.6.7; sw simple-v280.
2026-09-28 00:50:07 +03:00
catarrh c39250f1b4 fix: make the Explore Delete buttons send the GP DELETE APDU (v3.6.6)
ramDeleteFromExplorer() called an undefined `_ber_len()` helper, so clicking
Delete / Delete All raised a ReferenceError right after the confirm and no
APDU was ever sent.  The inline builder also omitted the mandatory Le byte.

- new pure `ramDeleteApdu(aid, withCascade)` = GP Card Spec v2.3.1 Table
  11-20/23 form: `80 E4 00 <p2> <Lc> 4F <len> <AID> 00` (P2 00 = object,
  80 = object and related objects), used by the Explore handler.
- `scp81DeleteApdus()` (the "Delete AID" script template) now shares the
  same builder: it used to send the raw AID without the mandatory '4F' TLV.
- tests: exact bytes for 7/16-byte AIDs and both P2 modes, the SCP81 script
  expectations updated to the TLV form, and a wiring check that the undefined
  helper call does not come back (`_ber_len(`).

611 frontend / 495 Python green; version 3.6.6; sw simple-v279.
2026-09-28 00:42:37 +03:00
catarrh 40f20d539e fix: decode the Response Scripting template and the compact listings (v3.6.5)
Explore still missed the F0414C46416101 package on a card whose responses
wrap the R-APDU in the TS 102 226 5.2.2 Response Scripting template
(`AB <len> 80 <count> 23 <len> <R-APDU>`): `_decode_por` parsed that as a
compact response, so the frontend got `last_status_word` 81d0/7680 and data
starting `80 01 01 23 ...` instead of the listing.

- server: `_parse_response_scripting()` (AB definite / AF 80 ... 00 00
  indefinite) extracts the executed-command count and the last R-APDU's SW
  and data; `_decode_por` exposes it as `response_type: scripting` in the
  same `decoded` shape as compact, so the RAM explore paging and the RAM
  install `por_sw` see the real 9000/6310.
- frontend: the compact listing walk is deterministic on the AID length
  (`len AID life ver`; P1=10 adds `module_count (len module_AID)*`).
  `_parseRawAppEntry` no longer guesses `rawLen-1` for >8-byte AIDs (16-byte
  A113 applet AIDs were truncated), and `_parseRawElfEntry` no longer scans
  for `0x10` (a length/AID byte equal to 0x10 derailed the walk: a live page
  parsed to 1 entry with no F0414C46416101).
- tests: exact trace fixtures - the ELF page lists F0414C46416101 (11
  entries), the P1=10 page attaches its F0414C4641610101 module, the app page
  keeps the 16-byte A113 AIDs; Python covers the scripting template
  (definite/indefinite) against the live `AB 12` ISD and listing vectors.

610 frontend / 495 Python green; version 3.6.5; sw simple-v278.
2026-09-28 00:31:01 +03:00
catarrh 9e85f522f6 fix: recover the SMS-SUBMIT listings in RAM Explore (v3.6.4)
Explore returned partial data (no ELF/module entries, the installed package
missing) and then failed with cntr_low.  Two causes, both in the
actual-response SMS-SUBMIT path the card uses for big listings:

- `_find_sms_tpdu` read TLV lengths as a single byte; the FETCH carries
  `8B 81 97 ...` (BER long form) for the big pages, so it returned a
  corrupted, truncated TPDU.
- `_calc_ud_offset` treated the SMS-SUBMIT relative validity period (VPF=10)
  as 7 bytes instead of 1, shifting the UD offset: `_parse_sms_concat` then
  read a bogus UDH and reported no concatenation, so the segments never
  assembled and the PoR/data was dropped ("RAM RESPONSE-PACKET: empty").
  The step was marked failed, the counter did not advance, the same counter
  was retried and the card answered `cntr_low`, which also blocked P1=10
  (modules) where the installed package appears.

- the captured segments now always store the assembled UD (`submit_ud_hex`);
  `_sms_submit_por()` rebuilds the DELIVER-style packet (`02 71 00` + UD) for
  `_decode_por`.  Verified against the live capture: por_ok, remote SW 6310,
  438 hex chars of listing data (the exact bytes of the P1=20 page).
- `spPorAccepted` counts `actual_response_sms_submit` (0x0B) as accepted, so
  the counter advances when the data follows via SMS-SUBMIT.

Explore queries follow GP Card Spec v2.3.1 11.4.2.2: compact listings
(P2.b2=0) with the chained GET RESPONSE (`ramGetStatusApdu`, paging P2=00 ->
P2=01), the malformed P2=02 attempt is gone, and the ISD-only query (P1=80)
never pages with next-occurrence (the card shall reject it).

Tests: Python SmsSubmitCaptureTest with the live FETCH bytes (TPDU length,
UD offset, concat reassembly, 027100+UD decode); ram.test.js checks the APDU
builder and the missing P2=02 attempt; cards_counter covers 0x0B.

608 frontend / 492 Python green; version 3.6.4; sw simple-v277.
2026-09-28 00:09:54 +03:00
catarrh 39c82f26f3 fix: SCP80/RAM re-read the preset before every operation; no counter bump on a rejected send (v3.6.3)
The SCP80/RAM forms hold a copy of the preset (counter, keys, TAR, SPI).
Editing the preset on the Cards tab saved correctly, but the form kept the
old copy: the operation sent the stale counter (the card answers cntr_low)
and the post-send sync wrote the stale value back over the preset - the
saved counter silently reverted.  Reproduced in a real DOM:

  after select in SCP80:  preset=0000000001  sp=0000000001
  after Cards edit+save:  preset=00000000AA  sp=0000000001
  after a sync:           preset=0000000001  (edit lost)

- `cardsApply()` split into `cardsApplyFields()` (field copy, no packet) and
  `cardsApply()` = fields + genSp; new `spRefreshFromPreset(selId)` re-reads
  the selected preset from `sp-card-sel` / `ram-card-sel` and re-applies it.
- `pysimSendOta()` and `ramExecute()` call it before starting, so every
  SCP80/RAM operation uses the preset as it is now.
- A rejected send no longer advances the counter: new `spPorAccepted(por)`
  gates the advance+write-back in `pysimSendOta`, the Explore pagination and
  its GET DATA step, and the server's RAM install (`_ram_next_cntr`: advance
  only for `por_ok`/`no_por` steps).  A failed install still returns
  `final_cntr` (the accepted prefix) and the PWA persists it, so a retry
  never replays a counter the card already consumed.
- tests: cards_counter.test.js (the stale-form regression, RAM selector,
  fields-without-genSp, spPorAccepted) and `_ram_next_cntr` cases; the
  cards_form/ram harnesses updated for the split.
- docs/api.md counter semantics; AGENTS preset-source-of-truth rule.

607 frontend / 488 Python green; version 3.6.3; sw simple-v276.
2026-09-27 23:43:28 +03:00
catarrh 36d2f71bc7 fix: report the real PoR/remote-SW result of every RAM install step (v3.6.2)
The RAM installer read `por['decoded']['response_status']`, but the compact
response decoder's `decoded` only carries {number_of_commands,
last_status_word, last_response_data} - so the suffix was always empty and
every step showed the useless `por_error_`, even when the PoR was por_ok.
The PoR verdict is the top-level `response_status`.

With that fixed, the decoded details also show that the remote command's own
status word was the real verdict all along: a captured live install returned
por_ok with `last_status_word` 6700/6F00 (the card rejected every RAM APDU)
while the installer reported success.

- new `_ram_step_result()`/`_por_remote_sw()`/`_ram_remote_sw_ok()`: a step
  fails on a non-por_ok PoR, on a remote SW outside the success set (9000,
  61xx more data, 62xx/63xx warnings, CAFE GP "more data"), or on an
  undecodable PoR (a 9000 transport SW with no PoR at all is `no_por`, not a
  failure).  A decoded 61xx is explicitly success, per GP/ISO.
- step records gain por_sw/por_type/por_cntr/por_data/por_raw and
  `por_error`; the response carries `failed_step` and a detailed error such
  as `LOAD (1/9): remote SW 6700`; the log line now prints
  `status=por_ok remote_sw=6700`.
- PWA: new pure `ramStepLine()` renders e.g.
  `❌ Шаг 2: LOAD (1/9) — PoR ok · remote SW 6700 (Wrong length in Lc) · 274 B / 3 SMS`
  (SW meaning via the existing lookupSw decoder) and the transport SW only
  when it is not 9000.
- tests: tests/test_ota_helpers.py RamPorStepTest (success set incl. 61xx,
  the captured 6700 failure, no-PoR/undecodable, expanded responses);
  ram.test.js ramStepLine cases.
- docs/api.md RAM install step fields + failure semantics; AGENTS updated.

603 frontend / 487 Python green; version 3.6.2; sw simple-v275.
2026-09-27 23:21:56 +03:00
catarrh 0255a956e2 feat: show the CAP's required libraries, package identity and components (v3.5.16)
The Import component (JC VM spec 6.6) is now exposed by /api/cap-info and
rendered in the CAP analysis box:

- imports: the libraries the CAP is linked against with the export-file
  versions and the number of distinct constant-pool references (6.7),
  displayed as "name >= version" (a card resolves an import only with the
  same major and a minor >= the recorded one, 4.5.2).  Standard names come
  from the AID table; each gets a family label (Oracle JavaCard / ETSI SIM
  2G / ETSI UICC / 3GPP USIM-ISIM / GlobalPlatform) and, for
  javacard.framework, a Java Card SDK release hint derived from the local
  Oracle SDK kit corpus (jc211..jc305u4 exports; unknown versions stay
  unhinted).  Vendor/applet AIDs stay bare.
- Header package flags (Table 6-4: int / exports / applet package) and the
  optional JC 2.2 package_name (absent in all CAP 2.1 files).
- components: every archive entry in load-file order with its size and
  share of the load file (including the Directory/Export entries capmem
  does not parse); the sizes sum to load_file_bytes.
- The PWA box leads with "Requires: ..." when imports exist, keeps the
  compiled-against line (Java Card hint + CAP format), the package/applet
  identity, the import details (family, refs, AID) and the component
  breakdown in Details; a memory-only response still renders.

Tests: Python +2 (imports/flags/name/components; header flags + package
name) with the synthetic CAP builder extended; frontend +2 renderer cases
(unknown AIDs, no-import responses) plus jcAidNorm/jcAidFamily tests; the
jcAidNorm extraction added to the ram/scp81 harnesses.
Help EN/RU, docs/api.md, AGENTS.

591 frontend / 473 Python green; version 3.5.16; sw simple-v269.
2026-09-27 02:23:03 +03:00
catarrh b88f04fc69 feat: name standard package AIDs in the Explore / SCP81 / R-APDU views (v3.5.7)
The RAM Explore view, the SCP81 GET STATUS script results and the R-APDU
parser tree showed package AIDs as bare hex.  A shared resolver now
annotates the known standard JavaCard / ETSI / 3GPP / GlobalPlatform
package AIDs with their library name (workspace export-file study
`docs/JAVACARD.md`, 2026-09-26, plus the GP default ISD AID from GP Card
Spec v2.3.1 H.1.3); a RID table gives a weak owner hint for otherwise
unknown AIDs, and vendor/applet AIDs stay bare.

- JC_AID_NAMES / JC_AID_RIDS + jcAidName / jcAidSuffix / jcAidHtml.
- Wired into ramRenderExploreHtml (ISD, applications, ELFs, module and SD
  AIDs), scp81ResultLines GET STATUS listings and decodeTlvValue
  (4F/84/C4/CC - the R-APDU parser tree).
- aid_names.test.js (families, normalisation, RID hints, malformed input,
  table sanity) plus render assertions in ram.test.js and scp81.test.js.
- Help EN/RU note the annotation; table is hand-maintained from the note.

561 frontend / 421 Python green; version 3.5.7; sw cache simple-v260.
2026-09-26 00:33:38 +03:00
catarrh 2494e04984 ui: clear stale RAM status on op change, remember the card preset
- ramOpChanged() now clears the previous execution status (result line,
  steps, explorer, progress) only when the Operation value actually
  changes, so switching Explore -> Install Package no longer shows the
  old 'Partial - ELF Modules: no data' until Execute; re-entering the
  RAM subtab still preserves the last result
- ramClearResults() also hides the progress caption
- the Card preset dropdown no longer resets to the placeholder after
  every executed operation (ramSaveCntr -> ramRender rebuilt it) or on
  subtab re-entry: ramRender keeps the current/remembered index,
  ramApplyCard and ramExecute remember the selection for the session,
  and cardsRemove keeps _ramCardIdx aligned via ramCardIdxAfterRemove
- tests: op-change clearing, selection preservation across rebuilds,
  pick/execute remembering, index bookkeeping; SW cache v126 -> v127.
2026-09-12 23:20:26 +03:00
catarrh b49e6728b4 ui: translate SCP80/RAM explorer labels, buttons and result strings
The RAM explorer HTML is generated after load, so its data-l10n sections
and Delete/Delete All buttons stayed English until a language switch, and
the memory/AID/lifecycle labels were hardcoded with no key at all.

- ramRenderExploreHtml() now builds every label and button with t()
  (reusing the existing Delete/Delete All/heading/AID keys and wiring the
  three previously-unused Application/Instance, Load File and Module AID
  keys); new RU keys cover Applications:, Free NV:, Free Volatile:, AID:,
  Lifecycle:, Privileges:, SD AID:, Implicit sel:, Version: and (none)
- the explorer dataset is cached in _ramExplorerData and re-rendered by
  refreshDynamicI18n() on language switch (cleared on op change/results
  reset)
- RAM flow strings localized too: Partial/OK summaries, error labels
  (Memory/ISD/Apps/ELFs/ELF Modules/no data), GET DATA progress, delete
  confirm/labels, install alerts/progress/steps and Error:
- tests: ram.test.js asserts every explorer label/button goes through t()
  and the (none) placeholder; SW cache v125 -> v126.
2026-09-12 23:07:28 +03:00
catarrh 8b55a7159f v1.9.24: chain builder for SIM/USIM/RAM C-APDU sub-tabs
Replaced single-command builders with row-based chain builder:
- chainInit/chainAddRow/chainDeleteRow/chainRender
- chainSimBuildRowHex/chainRamBuildRowHex per-sub-tab hex builders
- Auto-updating chain preview (no Generate button)
- GET RESPONSE as fixed row in SIM chain
- Le stripping for Case 4 + GET RESPONSE (ETSI TS 102 226)
- Each row: command dropdown + context fields + delete x + hex preview
- + SIM: SELECT (FID/path/chain/GET RESPONSE), PIN ops, file ops
- + USIM: SELECT with FCP requests, silent mode, record ops
- + RAM/GP: INSTALL[for install/delete/move], LOAD, STORE DATA, GET STATUS
- UICC toolkit nested inside EA (C900 EF00 EA...), SIM CA (EF CA)
- Updated tests: 21 SIM + 11 RAM tests for new chain builder API
- Removed old genSimUsim/genRam/OPS/updateSimUsimFields and friends
- SW cache v35, version 1.9.24
2026-09-01 07:50:14 +03:00
catarrh 54dfb2f6b6 v1.9.17: fix explore card — chain GET STATUS + GET RESPONSE inside SCP80
Key fix: re-add chained C0000000 (GET RESPONSE Le=00) in paginate() so the
full GP APDU inside SCP80 is 80F2<p1>p2024F0000C0000000, matching the
working tool. The card's SCP80 layer executes both commands internally
(GET STATUS → 61XX → GET RESPONSE) and puts the final 9000 + data in
the PoR.

Also: server logging improvements (RAM RESPONSE-PACKET label, no truncation
of FETCH/PoR hex), docs for /api/ram-install endpoint, minor test fix.
2026-08-30 14:13:13 +03:00
catarrh 288c2e5954 C-APDU constructor spec fixes (TS 102 221 / GPC v2.3 / TS 102 226)
SIM/USIM tab (TS 102 221):
- Record P2 modes: 04/06/02 -> 04/02/03; P1=00 for next/previous
- SELECT Le rules: USIM FID no Le, path/dfname P2=04+Le; SIM no Le
- Path placeholder: 3F007FFF6FC5 -> 7FFF6FC5
- ACTIVATE/DEACTIVATE: 5-byte -> 4-byte case-1
- VERIFY PIN: dedicated input, Lc=08, FF-pad to 8 bytes
- CHANGE PIN: old/new inputs, Lc=10, two 8-byte fields
- ERASE BINARY removed from USIM tab

RAM tab (GPC v2.3):
- INSTALL: all 5 variants rewritten to strict LV + Le 00
- ELF/Module AID inputs for install-install
- Privileges: 1 byte if only byte-1, else 3 bytes
- InstallParams: C9 00 + toolkit TLV (mandatory)
- LOAD/DELETE/GET STATUS: append Le 00
- GET STATUS P2: drop 40/42, keep 02/03/00
- GET DATA: 2F00/5031 -> case-4 5C00 data
- SET STATUS: raw AID (no 4F), ISD card states, P1=60
- EXT AUTH: CLA 84, P1 security level, Lc=10
- INT AUTH: CLA 00

Toolkit (TS 102 226):
- MSL: 01 <msl> -> 00 (no check) or 02 01 <msl>
- SIM CA wrapped in EF: C9 00 EF <len> CA...
- TAR length %3 validation
- Menu IDs <= 7F validation

Script Chaining (TS 102 226 Table 5.9a):
- Removed Script ID + Additional Data fields
- Emit strictly 83 01 <flags>
- Deleted generateScriptIdHint

Privilege label: Token Verification -> Token Management
2026-08-21 22:37:39 +03:00
catarrh e6602c40bf RAM constructor fixes: EA/CA nesting, access domain order, menu pairs, BER lengths, services byte (TS 102 226)
- UICC Toolkit tag 80 nested inside EA (EA 12 80 10 ...)
- ram-tk-mode value ea (was 80), label 'UICC Toolkit (Tag EA)'
- SIM (CA) access domain FIRST in payload, blank = 00
- Menu entries: 2×m pairs (i=1 first, i=m last, else 0000)
- CA/EA lengths via berLenStr() (supports 81xx long form)
- UICC trailing 'Maximum number of services' byte (ram-tk-services)
- DELETE: P1=00 fixed, mode in P2 (80E4 00 <mode> ...)
- STORE DATA: ram-enc 00/40/80/C0/E0 with correct labels
- LOAD: P1 fixed to 0x80 (last block)
- USIM SELECT: selP1 0x09 -> 0x00 (select by file id)
- ram.test.js: 11 exact-hex tests from exchange vectors
- v1.8.1, SW cache otaman-v9
2026-08-20 21:23:37 +03:00