7388f39bd6
- C-APDU tab: describe chain builder for SIM RFM/USIM RFM/RAM-GP (row-based + Command buttons, chain preview, GET RESPONSE, Le stripping, USIM silent select); remove obsolete single-command options (Start with SELECT, Selection mode, Record size, Allow P1/P2 editing) - Add DISABLE/ENABLE/UNBLOCK PIN + GET RESPONSE to SIM/USIM command table - Fix RAM/GP INSTALL P1 (make-sel 08, registry-update 40, extradition 10), LOAD P1=80, STORE DATA add E0, add GET RESPONSE; privileges are a length-value field (drop incorrect 'Tag C7') - Add new 'C-APDU Parser' sub-tab (section 2.6) - Card reader: add Profiler sub-tab (section 5.6) and STK menu block (5.5.1); renumber proactive/scenario subsections - Fix Russian response-parser section (was a duplicated copy of the Cards table) No index.html change -> no sw.js cache bump needed.
518 lines
52 KiB
HTML
518 lines
52 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>OTAMan — Help</title>
|
||
<link rel="stylesheet" href="style.css">
|
||
</head>
|
||
<body class="bg-neutral-50 dark:bg-slate-900 text-gray-800 dark:text-slate-200">
|
||
|
||
<div class="flex">
|
||
|
||
<aside class="sticky top-0 h-screen overflow-y-auto w-72 shrink-0 border-r border-gray-300 dark:border-slate-700 px-4 py-6">
|
||
<a href="index.html" class="block text-xs text-gray-400 hover:text-gray-600 dark:text-slate-500 dark:hover:text-slate-300 mb-4">← Back to app</a>
|
||
<nav id="toc" class="text-sm"></nav>
|
||
</aside>
|
||
|
||
<main class="flex-1 min-w-0 px-6 py-8">
|
||
<h1 class="text-2xl font-bold text-heading mb-6">OTAMan <span class="text-xs text-gray-400 dark:text-slate-500 ml-2">Documentation</span></h1>
|
||
<section class="mb-10">
|
||
<h2 id="overview" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">1. Overview</h2>
|
||
<p class="mb-3">OTAMan is a Progressive Web App (PWA) for building APDU commands, assembling SCP80 secured packets, browsing the SIM Toolkit (STK) menu, and simulating a real network environment against a SIM/USIM/UICC card via a PC/SC reader.</p>
|
||
<p class="mb-3">The application is a single static <code class="font-mono text-sm">index.html</code> file. All computation runs in the browser; the card is accessed through a local HTTP server (<code class="font-mono text-sm">pysim-otaman-server</code>) that wraps the <a href="https://osmocom.org/projects/pysim" class="text-blue-600 dark:text-blue-400 hover:underline">pySim</a> library.</p>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">Browser (OTAMan PWA) → HTTP :8080 → pysim-otaman-server → pySim → PC/SC → card reader → UICC/SIM</pre>
|
||
<p class="mb-3">Standards referenced across the application:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li>ETSI TS 102 221 — UICC-Terminal interface (CLA 00, USIM files)</li>
|
||
<li>ETSI TS 102 222 — Administrative commands</li>
|
||
<li>ETSI TS 102 223 — Card Application Toolkit (CAT, proactive commands)</li>
|
||
<li>ETSI TS 102 225 — Secured packet structure for (U)SIM toolkit</li>
|
||
<li>ETSI TS 102 226 — Remote APDU structure for UICC based applications</li>
|
||
<li>ETSI TS 151 011 — SIM-ME interface (CLA A0)</li>
|
||
<li>3GPP TS 131 111 — USIM Application Toolkit (USAT)</li>
|
||
<li>3GPP TS 31.102 — USIM application characteristics</li>
|
||
<li>3GPP TS 23.038 — GSM 7-bit alphabet and DCS</li>
|
||
<li>3GPP TS 24.008 / 24.301 / 24.501 — NAS cause codes</li>
|
||
<li>GlobalPlatform Card Specification v2.3.1</li>
|
||
<li>ISO/IEC 7816-4 — commands for interchange</li>
|
||
<li>ISO/IEC 9797-1 — MAC algorithms</li>
|
||
</ul>
|
||
|
||
|
||
<section class="mb-10">
|
||
<h2 id="c-apdu" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">2. C-APDU tab</h2>
|
||
<p class="mb-3">Builds command APDUs (C-APDUs). Five sub-tabs cover different card generations and command sets: <strong>SIM RFM</strong>, <strong>USIM RFM</strong>, <strong>Expanded Script</strong>, <strong>RAM/GP</strong>, and <strong>C-APDU Parser</strong>.</p>
|
||
|
||
<h3 id="sim-rfm" class="text-lg font-medium mb-2">2.1 SIM RFM</h3>
|
||
<p class="mb-2">CLA = <code class="font-mono text-sm">A0</code> (GSM 11.11 / TS 151 011, ISO 7816-4). Remote File Management for classic SIM cards.</p>
|
||
<p class="mb-2">Commands are assembled as a <strong>chain</strong>: press a <code class="font-mono text-sm">+ Command</code> button to append a row, fill that row’s fields, and the chain preview (above the pack button) updates automatically. Add a <strong>GET RESPONSE</strong> row to fetch data following a SELECT. Press <strong>Pack into Secured packet</strong> to wrap the whole chain into an SCP80 packet.</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Command</th><th class="text-left py-1 px-2">INS</th><th class="text-left py-1 px-2">Description</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">SELECT</td><td class="py-1 px-2 font-mono">A4</td><td class="py-1 px-2">Select EF/DF by FID, path, AID or chain</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">UPDATE RECORD</td><td class="py-1 px-2 font-mono">DC</td><td class="py-1 px-2">Update a record in a record-oriented EF</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">UPDATE BINARY</td><td class="py-1 px-2 font-mono">D6</td><td class="py-1 px-2">Update binary content at an offset</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">READ RECORD</td><td class="py-1 px-2 font-mono">B2</td><td class="py-1 px-2">Read a record</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">READ BINARY</td><td class="py-1 px-2 font-mono">B0</td><td class="py-1 px-2">Read binary content</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">ERASE BINARY</td><td class="py-1 px-2 font-mono">0E</td><td class="py-1 px-2">Erase binary at an offset</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">ACTIVATE FILE</td><td class="py-1 px-2 font-mono">44</td><td class="py-1 px-2">Activate a file</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">DEACTIVATE FILE</td><td class="py-1 px-2 font-mono">04</td><td class="py-1 px-2">Deactivate a file</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">VERIFY PIN</td><td class="py-1 px-2 font-mono">20</td><td class="py-1 px-2">Verify PIN1 or PIN2</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CHANGE PIN</td><td class="py-1 px-2 font-mono">24</td><td class="py-1 px-2">Change PIN1 or PIN2</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">DISABLE PIN</td><td class="py-1 px-2 font-mono">26</td><td class="py-1 px-2">Disable a PIN</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">ENABLE PIN</td><td class="py-1 px-2 font-mono">28</td><td class="py-1 px-2">Enable a PIN</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">UNBLOCK PIN</td><td class="py-1 px-2 font-mono">2C</td><td class="py-1 px-2">Unblock a PIN with PUK</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">GET RESPONSE</td><td class="py-1 px-2 font-mono">C0</td><td class="py-1 px-2">Fetch data indicated by a preceding <code class="font-mono text-sm">61XX</code>/<code class="font-mono text-sm">9FXX</code> status word</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="sim-select-methods" class="font-medium mb-1">SELECT methods</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Method</th><th class="text-left py-1 px-2">P1</th><th class="text-left py-1 px-2">P2</th><th class="text-left py-1 px-2">Input</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">By FID</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">2-byte FID (4 hex)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">By full path from MF</td><td class="py-1 px-2 font-mono">08</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Full path hex from MF</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">By DF name / AID</td><td class="py-1 px-2 font-mono">04</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">AID (application ID)</td></tr>
|
||
<tr><td class="py-1 px-2">Chain</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Comma-separated FIDs; a <code class="font-mono text-sm">C0</code> (or <code class="font-mono text-sm">C0:NN</code>) token inserts a GET RESPONSE hop</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3">For record commands, the P2 mode is <strong>Absolute (04)</strong>, <strong>Next (02)</strong>, or <strong>Previous (03)</strong>. When a Case 4 command is immediately followed by a GET RESPONSE row, the chain builder strips its trailing Le byte automatically (ETSI TS 102 226 §5.1.1). A conversion panel is embedded in the right column (IMSI, MSISDN, ICCID, SPN, PLMN, nibble swap). See <a href="#conversion" class="text-blue-600 dark:text-blue-400 hover:underline">§2.5</a>.</p>
|
||
|
||
<h3 id="usim-rfm" class="text-lg font-medium mb-2">2.2 USIM RFM</h3>
|
||
<p class="mb-2">CLA = <code class="font-mono text-sm">00</code> (ETSI TS 102 221). Same chain builder and command set as SIM. Differences:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>SELECT</strong> requests FCP by default (P2=<code class="font-mono text-sm">04</code>) and appends Le=<code class="font-mono text-sm">00</code>; a <strong>Silent (P2=0C)</strong> checkbox selects without requesting FCP (no Le, no response data).</li>
|
||
<li><strong>By path</strong> offers <strong>from MF</strong> (P1=<code class="font-mono text-sm">08</code>) or <strong>from current DF</strong> (P1=<code class="font-mono text-sm">09</code>).</li>
|
||
<li>Each SELECT hop in a chain requests FCP unless marked silent.</li>
|
||
</ul>
|
||
|
||
<h3 id="ber-tlv" class="text-lg font-medium mb-2">2.3 Expanded Script</h3>
|
||
<p class="mb-2">Builds the Expanded Remote Application data format per ETSI TS 102 226 §5.2.1.</p>
|
||
<h4 id="ber-format" class="font-medium mb-1">Format</h4>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Definite (AA)</strong>: <code class="font-mono text-sm">AA</code> + length + Command TLVs</li>
|
||
<li><strong>Indefinite (AE)</strong>: <code class="font-mono text-sm">AE</code> + <code class="font-mono text-sm">80</code> + Command TLVs + <code class="font-mono text-sm">00 00</code></li>
|
||
</ul>
|
||
<h4 id="ber-command-tlvs" class="font-medium mb-1">Command TLVs</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Type</th><th class="text-left py-1 px-2">Tag</th><th class="text-left py-1 px-2">Description</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">C-APDU</td><td class="py-1 px-2 font-mono">22</td><td class="py-1 px-2">Raw APDU hex</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Immediate Action</td><td class="py-1 px-2 font-mono">81</td><td class="py-1 px-2">Proactive command or action indicator</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Error Action</td><td class="py-1 px-2 font-mono">82</td><td class="py-1 px-2">Conditional error recovery with action indicator or proactive command</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Script Chaining</td><td class="py-1 px-2 font-mono">83</td><td class="py-1 px-2">Multi-packet script execution with First/Intermediary/Last flags</td></tr>
|
||
<tr><td class="py-1 px-2">Response Type</td><td class="py-1 px-2 font-mono">-</td><td class="py-1 px-2">Expanded/Compact/None response parsing indicator</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3">The Immediate Action builder offers an action indicator (<code class="font-mono text-sm">81</code>/<code class="font-mono text-sm">82</code>), a structured proactive command builder (REFRESH, DISPLAY TEXT, PLAY TONE with auto-generated COMPREHENSION-TLV objects), or a freeform hex input.</p>
|
||
|
||
<h4 id="ber-error-action" class="font-medium mb-2 text-base">Error Action TLV (Tag 82)</h4>
|
||
<p class="text-sm mb-2">Error recovery per TS 102 226 §5.2.1.3 — one of three forms:</p>
|
||
<ul class="text-sm list-disc pl-5 mb-2">
|
||
<li><strong>Proactive command:</strong> COMPREHENSION-TLV set with DISPLAY TEXT or PLAY TONE (only these two are allowed in an Error Action, TS 102 226 Table 5.9)</li>
|
||
<li><strong>No action:</strong> <code class="font-mono text-sm">82 00</code></li>
|
||
<li><strong>Reference to EFRMA record:</strong> <code class="font-mono text-sm">82 01 <ref></code> with record number <code class="font-mono text-sm">01</code>–<code class="font-mono text-sm">7F</code></li>
|
||
<li><strong>Custom hex:</strong> arbitrary TLV value</li>
|
||
</ul>
|
||
|
||
<h4 id="ber-script-chaining" class="font-medium mb-2 text-base">Script Chaining TLV (Tag 83)</h4>
|
||
<p class="text-sm mb-2">Multi-packet script execution with context preservation:</p>
|
||
<ul class="text-sm list-disc pl-5 mb-2">
|
||
<li><strong>Chaining Flags:</strong> <code class="font-mono text-sm">01</code> first script (delete chaining info on reset), <code class="font-mono text-sm">11</code> first script (keep chaining info across reset, RFM only), <code class="font-mono text-sm">02</code> subsequent script (more to follow), <code class="font-mono text-sm">03</code> subsequent script (last)</li>
|
||
<li><strong>Script ID:</strong> Correlation identifier across packets (1-4 bytes hex, auto-increment hints provided)</li>
|
||
<li><strong>Additional Data:</strong> Extended chaining information (optional hex)</li>
|
||
<li><strong>Context Preservation:</strong> UICC keeps security/transaction state open across chained scripts</li>
|
||
</ul>
|
||
|
||
<h4 id="expanded-response" class="font-medium mb-2 text-base">Expanded Remote Response (TS 102 226 §5.2.2)</h4>
|
||
<p class="text-sm mb-2">Per-command results with error details and chaining context:</p>
|
||
<ul class="text-sm list-disc pl-5">
|
||
<li>Command number, status word, response data for each command</li>
|
||
<li>Error code and error info for failed commands (highlighted in red)</li>
|
||
<li>Script ID and position for chained script correlation (ID, FIRST, LAST)</li>
|
||
<li>Response type indicator: 'expanded' vs 'compact' vs 'none'</li>
|
||
</ul>
|
||
|
||
<h3 id="ram-gp" class="text-lg font-medium mb-2">2.4 RAM/GP</h3>
|
||
<p class="mb-2">CLA = <code class="font-mono text-sm">80</code> (GlobalPlatform Card Specification v2.3.1). Remote Application Management commands for card content management. Built with the same chain builder as SIM/USIM: add rows, fill fields, and the chain preview updates automatically.</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Command</th><th class="text-left py-1 px-2">INS</th><th class="text-left py-1 px-2">P1</th><th class="text-left py-1 px-2">Description</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [for load]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">02</td><td class="py-1 px-2">Register a load file for loading</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [for install]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">0C</td><td class="py-1 px-2">Install an application or SD</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [make selectable]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">08</td><td class="py-1 px-2">Make an application selectable</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [registry update]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">40</td><td class="py-1 px-2">Update registry entries</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [extradition]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">10</td><td class="py-1 px-2">Extradition between SDs</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">LOAD</td><td class="py-1 px-2 font-mono">E8</td><td class="py-1 px-2 font-mono">80</td><td class="py-1 px-2">Load executable code block (P1=80 last block, block number in P2)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">DELETE</td><td class="py-1 px-2 font-mono">E4</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Delete application or SD (P2=00 AID only / 80 AID + related objects)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">GET STATUS</td><td class="py-1 px-2 font-mono">F2</td><td class="py-1 px-2 font-mono">80/40/20/10</td><td class="py-1 px-2">Get card status</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">GET DATA</td><td class="py-1 px-2 font-mono">CA</td><td class="py-1 px-2 font-mono">tag</td><td class="py-1 px-2">Read card data objects</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">STORE DATA</td><td class="py-1 px-2 font-mono">E2</td><td class="py-1 px-2 font-mono">00/40/80/C0/E0</td><td class="py-1 px-2">Store data (key, certificate, …)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">SET STATUS</td><td class="py-1 px-2 font-mono">F0</td><td class="py-1 px-2 font-mono">80/40/60</td><td class="py-1 px-2">Lifecycle state management</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">EXTERNAL AUTHENTICATE</td><td class="py-1 px-2 font-mono">82</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">SCP host authentication</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INTERNAL AUTHENTICATE</td><td class="py-1 px-2 font-mono">88</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Card challenge-response</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">GET RESPONSE</td><td class="py-1 px-2 font-mono">C0</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Fetch data after a <code class="font-mono text-sm">61XX</code> status (Le configurable)</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="ram-privileges" class="font-medium mb-1">Privileges (INSTALL [for install])</h4>
|
||
<p class="text-sm mb-2">Three privilege bytes (GP spec Tables 11-7/8/9), encoded as a length-value field inside the INSTALL data:</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Bit</th><th class="text-left py-1 px-2">Byte 1</th><th class="text-left py-1 px-2">Byte 2</th><th class="text-left py-1 px-2">Byte 3</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b8</td><td class="py-1 px-2">Security Domain</td><td class="py-1 px-2">Trusted Path</td><td class="py-1 px-2">Receipt Generation</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b7</td><td class="py-1 px-2">DAP Verification</td><td class="py-1 px-2">Authorized Management</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b6</td><td class="py-1 px-2">Delegated Management</td><td class="py-1 px-2">Token Verification</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b5</td><td class="py-1 px-2">Card Lock</td><td class="py-1 px-2">Global Delete</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b4</td><td class="py-1 px-2">Card Terminate</td><td class="py-1 px-2">Global Lock</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b3</td><td class="py-1 px-2">Card Reset</td><td class="py-1 px-2">Global Registry</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b2</td><td class="py-1 px-2">CVM Management</td><td class="py-1 px-2">Final Application</td><td class="py-1 px-2"></td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">b1</td><td class="py-1 px-2">Mandated DAP Verification</td><td class="py-1 px-2"></td><td class="py-1 px-2"></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="ram-msl" class="font-medium mb-1">MSL (Minimum Security Level) — SPI1 byte per TS 102 225</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Value</th><th class="text-left py-1 px-2">Meaning</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">No check</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">11</td><td class="py-1 px-2">RC/CC/DS</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">12</td><td class="py-1 px-2">RC/DS/CC</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">15</td><td class="py-1 px-2">RC/DS/CC + MAC</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">16</td><td class="py-1 px-2">RC/DS/CC + MAC + Cipher</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">19</td><td class="py-1 px-2">RC/DS/CC + MAC + Cipher + DS</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3">Refer to GlobalPlatform v2.3.1 and ETSI TS 102 226 §8.2.1.3.2 for the full GET STATUS P1/P2, GET DATA tag, DELETE P1, STORE DATA P1, and SET STATUS tables.</p>
|
||
|
||
<h3 id="conversion" class="text-lg font-medium mb-2">2.5 Conversion (SIM/USIM sidebars)</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1">
|
||
<li><strong>IMSI → EF.IMSI</strong> — 15-digit IMSI to 9-byte format (TS 31.102 §4.2.3).</li>
|
||
<li><strong>MSISDN → BCD</strong> — strip <code class="font-mono text-sm">+</code>, pad odd length with <code class="font-mono text-sm">f</code>, swap nibbles.</li>
|
||
<li><strong>ICCID → hex</strong> — nibble-swap the ICCID string.</li>
|
||
<li><strong>Provider Name → SPN</strong> — GSM 7-bit packed, UCS2 non-BMP, or UCS2 BMP (TS 31.102 §4.2.5, TS 23.038).</li>
|
||
<li><strong>PLMN → EF_PLMNsel / PLMNwAcT</strong> — 3-byte BCD + optional access technology selector.</li>
|
||
<li><strong>Nibble swap</strong> — swap nibble pairs of an even-length hex string.</li>
|
||
</ul>
|
||
|
||
<h3 id="c-apdu-parser" class="text-lg font-medium mb-2">2.6 C-APDU Parser</h3>
|
||
<p class="text-sm mb-3">Pastes raw APDU hex and renders a collapsible tree. It auto-detects the container: an <strong>Expanded Script</strong> (leading <code class="font-mono text-sm">AA</code> or <code class="font-mono text-sm">AE80</code>, decoded per ETSI TS 102 226 §5.2.1) or a <strong>Compact C-APDU chain</strong> (a sequence of ISO 7816 C-APDUs). Each node shows its label, hex and a short description; parent nodes expand to reveal their sub-elements.
|
||
|
||
|
||
<section class="mb-10">
|
||
<h2 id="scp80" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">3. SCP80 tab</h2>
|
||
<p class="mb-3">The <strong>SCP80</strong> top-level tab groups the SCP80-related views. It is switched by three pills: <strong>Secured Packet</strong>, <strong>Cards</strong>, and <strong>RAM</strong>. Assembles SCP80 secured packets per ETSI TS 102 225.</p>
|
||
|
||
<h3 id="secured-packet" class="text-lg font-medium mb-2">3.1 Secured Packet</h3>
|
||
<p class="mb-2">Builds SCP80 secured packets per ETSI TS 102 225.</p>
|
||
<h4 id="packet-structure" class="font-medium mb-1">Packet structure</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Field</th><th class="text-left py-1 px-2">Size</th><th class="text-left py-1 px-2">Description</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CPI</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Command Packet Identifier (02)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CPL</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Command Packet Length</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CHI</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Command Header Identifier (01)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CHL</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Command Header Length</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">SPI</td><td class="py-1 px-2">2</td><td class="py-1 px-2">Security Parameter Indicator</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">KIc</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Key Identifier for ciphering</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">KID</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Key Identifier for MAC</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">TAR</td><td class="py-1 px-2">3</td><td class="py-1 px-2">Toolkit Application Reference</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CNTR</td><td class="py-1 px-2">5</td><td class="py-1 px-2">Replay counter</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">PCNTR</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Padding counter</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">RC/CC/DS</td><td class="py-1 px-2">8</td><td class="py-1 px-2">Cryptographic Checksum / MAC</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">Secured Data</td><td class="py-1 px-2">var.</td><td class="py-1 px-2">Padded APDU (encrypted if required)</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="packet-crypto" class="font-medium mb-1">Crypto</h4>
|
||
<ul class="list-disc list-inside text-sm space-y-1">
|
||
<li><strong>3DES-CBC</strong> encryption (zero ICV), 8/16/24-byte keys — deprecated since Rel-18, still supported for backwards compatibility</li>
|
||
<li><strong>AES-CBC</strong> encryption (zero ICV, zero-padded to 16), 16/24/32-byte keys (TS 102 225 §5.1.2, KIc <code class="font-mono text-sm">x2</code>)</li>
|
||
<li><strong>Retail MAC</strong> (ISO 9797-1 MAC algorithm 3) for the DES/3DES cryptographic checksum</li>
|
||
<li><strong>AES-CMAC</strong> (NIST SP 800-38B, truncated to 8 octets) for the AES cryptographic checksum (TS 102 225 §5.1.3.1, KID <code class="font-mono text-sm">x2</code>)</li>
|
||
<li>AES requires a replay-protected counter: SPI1 bits b5 b4 must be <code class="font-mono text-sm">10</code> (counter higher) or <code class="font-mono text-sm">11</code> (counter +1) per TS 102 225 §5.1.2/§5.1.3.1</li>
|
||
<li>Padding byte configurable (<code class="font-mono text-sm">00</code> default, or <code class="font-mono text-sm">FF</code>)</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">A “Verify vs pySim” button cross-checks the assembled packet against pySim’s reference <code class="font-mono text-sm">OtaDialectSms.encode_cmd</code>. A “Send to Card” button delivers it via SMS-PP-DOWNLOAD ENVELOPE (when connected to the server).</p>
|
||
|
||
<h3 id="cards" class="text-lg font-medium mb-2">3.2 Cards</h3>
|
||
<p class="mb-2">Stores card presets locally in the browser (<code class="font-mono text-sm">localStorage</code>) so the Secured Packet view can auto-fill keys and parameters.</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Field</th><th class="text-left py-1 px-2">Description</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Name</td><td class="py-1 px-2">Human-readable label</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">ICCID</td><td class="py-1 px-2">Optional card identifier</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">KIc / KID</td><td class="py-1 px-2">Key and algorithm indicators (e.g. 15 = index 1, 3DES-CBC2; x2 = AES)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">SPI1 / SPI2</td><td class="py-1 px-2">Security Parameter Indicators</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">TAR</td><td class="py-1 px-2">Toolkit Application Reference</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Counter</td><td class="py-1 px-2">Replay counter (5 bytes)</td></tr>
|
||
<tr><td class="py-1 px-2">KIc key / KID key</td><td class="py-1 px-2">16/24/32 hex chars (8/16/24-byte 3DES) or 32/48/64 hex chars (16/24/32-byte AES) keys</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3"><strong>Export as JSON</strong> / <strong>Import JSON from clipboard</strong> share presets. The selected card preset auto-fills the Secured Packet form.</p>
|
||
|
||
<h3 id="ram" class="text-lg font-medium mb-2">3.3 RAM</h3>
|
||
<p class="mb-2">Delivers Remote Application Management operations as SCP80 secured packets via SMS-PP-DOWNLOAD ENVELOPE. The card must support SCP03 (AES or 3DES). A saved card preset from the <strong>Cards</strong> sub-tab provides the SPI, keys, TAR, and counter.</p>
|
||
|
||
<h4 id="ram-operations" class="font-medium mb-1">Operations</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Operation</th><th class="text-left py-1 px-2">Description</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Explore Card (all GP data)</td><td class="py-1 px-2">Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 for memory info. Results appear in an explorer view with per-item <strong>Delete</strong> buttons.</td></tr>
|
||
<tr><td class="py-1 px-2">Install Package (.cap file)</td><td class="py-1 px-2">Sends a <code class="font-mono text-sm">.cap</code> file to the card via the server: INSTALL[for load] → LOAD ×N → INSTALL[for install (+make selectable)].</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h4 id="ram-explorer" class="font-medium mb-1">Explorer View</h4>
|
||
<p class="text-sm mb-2">After “Explore Card” runs, the explorer displays:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>ISD</strong> — AID, lifecycle, privileges (no delete; the ISD cannot be removed)</li>
|
||
<li><strong>Applications</strong> — AID, lifecycle, privileges, associated ELF/SD. Each has a <strong>Delete</strong> button (GP <code class="font-mono text-sm">DELETE</code> by AID).</li>
|
||
<li><strong>Executable Load Files</strong> — AID, lifecycle, version, module AIDs. Each has <strong>Delete</strong> (ELF only) and <strong>Delete All</strong> (cascade: ELF + modules + installed Applications, P2=<code class="font-mono text-sm">0x80</code>) buttons.</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Delete confirms via a browser prompt before sending the GP <code class="font-mono text-sm">DELETE</code> command via SCP80. The explorer auto-refreshes after a successful deletion.</p>
|
||
|
||
|
||
<section class="mb-10">
|
||
<h2 id="response-parser" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">4. Response parser tab</h2>
|
||
<p class="mb-3">Decodes a raw command response: pick the command that was sent, enter the SW (e.g. <code class="font-mono text-sm">9000</code>) and the response data hex, then press <strong>Decode</strong>.</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1">
|
||
<li><strong>Command</strong> — SIM/USIM group (SELECT, STATUS, READ/UPDATE, PIN ops, CAT commands like TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, …) or RAM/GP group (INSTALL, LOAD, DELETE, GET/STORE DATA, auth, SCP commands).</li>
|
||
<li><strong>SW decode</strong> — status words resolved against generic, UICC (TS 102 221), and GlobalPlatform maps, with context auto-detected.</li>
|
||
<li><strong>Privilege decode</strong> — GET DATA / INSTALL response payloads decode the privilege bytes into human-readable flags.</li>
|
||
<li><strong>Response data</strong> — raw hex rendered and interpreted per command (e.g. SELECT FCP templates).</li>
|
||
</ul>
|
||
|
||
|
||
<section class="mb-10">
|
||
<h2 id="card-reader" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">5. Card reader (pySim) tab</h2>
|
||
<p class="mb-3">Connects to a local <a href="https://github.com/anttro/otaman" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-otaman-server</a> for live card operations. Sub-tabs: <strong>File manager</strong>, <strong>Custom files</strong>, <strong>Profiler</strong>, <strong>pySim command line</strong>, <strong>Raw APDU</strong>, and <strong>Proactive UICC</strong>.</p>
|
||
|
||
<h3 id="file-manager" class="text-lg font-medium mb-2">5.1 File manager</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Read</strong> — reads the selected file (auto-detects transparent vs record files)</li>
|
||
<li><strong>Edit</strong> — modify hex data, <strong>Save</strong> to write back</li>
|
||
<li><strong>Raw / Decoded</strong> — toggle between hex dump and pySim-decoded JSON</li>
|
||
</ul>
|
||
|
||
<h3 id="custom-files" class="text-lg font-medium mb-2">5.2 Custom files</h3>
|
||
<p class="text-sm mb-3">Add files that pySim’s model does not cover. Persists in <code class="font-mono text-sm">localStorage</code>; JSON export/import.</p>
|
||
|
||
<h3 id="pysim-cmdline" class="text-lg font-medium mb-2">5.3 pySim command line</h3>
|
||
<p class="text-sm mb-3">Execute any pySim-shell command with usage hints (300 ms) and autocomplete.</p>
|
||
|
||
<h3 id="raw-apdu" class="text-lg font-medium mb-2">5.4 Raw APDU</h3>
|
||
<p class="text-sm mb-3">Send an arbitrary APDU and view the raw response.</p>
|
||
|
||
<h3 id="proactive-uicc" class="text-lg font-medium mb-2">5.5 Proactive UICC</h3>
|
||
<p class="text-sm mb-3">Interacts with the Card Application Toolkit session: the STK menu, subscribed events, the proactive command log, the PROVIDE LOCAL INFORMATION data dictionary, and STATUS polling.</p>
|
||
|
||
<h4 id="stk-menu" class="font-medium mb-1">5.5.1 STK menu</h4>
|
||
<p class="text-sm mb-3">When the card has issued a SET UP MENU command, a “STK menu” block appears at the top of this view with an emerald <strong>STK: <title></strong> button that opens the menu overlay (same as the card’s STK menu browser). If the card has not set up a menu, the block shows “No menu set by the card” instead. The menu state is refreshed each time the view is opened.</p>
|
||
|
||
<h4 id="subscribed-events" class="font-medium mb-1">5.5.2 Subscribed events (SET UP EVENT LIST)</h4>
|
||
<p class="text-sm mb-2">The events the card monitors. Each event has a <strong>Send</strong> button that opens a form specific to the event type:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>No-data events</strong> (User Activity, Idle Screen, Data Available, …) — one-click notification</li>
|
||
<li><strong>Location Status</strong> — dropdown: Normal / Limited / No service (tag <code class="font-mono text-sm">9B</code>)</li>
|
||
<li><strong>Access Technology Change</strong> — 13 RAT types (tag <code class="font-mono text-sm">BF</code>)</li>
|
||
<li><strong>Network Rejection</strong> — full adaptive form: registration type (LU / GPRS / EPS / 5GS), location fields (MCC, MNC, LAC, RAC, TAC), access technology, and a 53-cause unified rejection cause dropdown covering EMM, GMM, 5GMM and LU causes</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Sending an event uses <code class="font-mono text-sm">ENVELOPE(Event Download)</code> per TS 102 223 / TS 131 111.</p>
|
||
|
||
<h4 id="proactive-log" class="font-medium mb-1">5.5.3 Proactive command log</h4>
|
||
<p class="text-sm mb-2">Chronological list of fetched proactive commands. Each row shows the elapsed time, type code, name, and a decoded qualifier (for commands that have one). Commands with response data show a <code class="font-mono text-sm">Response:</code> line with the TERMINAL RESPONSE bytes (boilerplate TLVs stripped); PROVIDE LOCAL INFORMATION responses are decoded using the PLI data dictionary decoders.</p>
|
||
|
||
<h4 id="pli-dict" class="font-medium mb-1">5.5.4 PROVIDE LOCAL INFORMATION data dictionary</h4>
|
||
<p class="text-sm mb-2">Editable hex values for all 22 PLI qualifiers (TS 102 223 §8.6 + TS 131 111). Ten qualifiers have inline decode/encode forms:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>00</strong> Location Info (MCC, MNC, LAC/TAC, Cell ID)</li>
|
||
<li><strong>01</strong> IMEI · <strong>03</strong> Date/Time/TZ · <strong>04</strong> Language · <strong>05</strong> Timing Advance</li>
|
||
<li><strong>06</strong> Access Technology · <strong>08</strong> IMEISV · <strong>09</strong> Search Mode</li>
|
||
<li><strong>0A</strong> Battery · <strong>0E</strong> Multiple Access Technologies</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Values persist server-side until restart. When the card issues PLI, the server injects the dictionary values into the TERMINAL RESPONSE.</p>
|
||
|
||
<h4 id="status-polling" class="font-medium mb-1">5.5.5 STATUS polling</h4>
|
||
<p class="text-sm mb-3">A <strong>Send STATUS</strong> button issues a manual STATUS (F2). A <strong>Polling</strong> toggle enables background polling: after a configurable idle interval (server CLI <code class="font-mono text-sm">--poll-interval</code>, 1–255 s, default 30 s) the server sends STATUS and handles any pending proactive command. Polling stops and card state resets if the card is removed.</p>
|
||
|
||
<h3 id="profiler" class="text-lg font-medium mb-2">5.6 Profiler</h3>
|
||
<p class="text-sm mb-2">Verifies that a card matches a named <strong>profile</strong> — an ordered set of rules describing the expected file system and (optionally) file contents. Profiles are stored in <code class="font-mono text-sm">localStorage</code>.</p>
|
||
<h4 class="font-medium mb-1">Profile list</h4>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>New profile</strong> — creates an empty ruleset after prompting for a name.</li>
|
||
<li><strong>Profile from card</strong> — scans the equipped card and generates one rule per existing file (see below), then opens the editor.</li>
|
||
<li><strong>Import profile</strong> — loads a ruleset from a JSON file (the name is stored inside the JSON).</li>
|
||
<li>Each profile row shows its name and creation time, with <strong>Edit</strong>, <strong>Check</strong>, <strong>Export</strong> (download JSON), and <strong>Delete</strong> actions.</li>
|
||
</ul>
|
||
<h4 class="font-medium mb-1">Filesystem rules</h4>
|
||
<p class="text-sm mb-2">Rules run sequentially. A filesystem rule is defined by:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Path</strong> — starts with <code class="font-mono text-sm">MF</code> (e.g. <code class="font-mono text-sm">MF/7F10/6F3A</code>) or an ADF AID (e.g. <code class="font-mono text-sm">A0000000871002/6F07</code>).</li>
|
||
<li><strong>File attributes</strong> — file type, size, record length and record count, taken from the FCI template (any may be left unset).</li>
|
||
<li><strong>Contents</strong> (optional) — <strong>Exact</strong> hex equality, or <strong>Mask</strong> where <code class="font-mono text-sm">?</code> is a per-nibble wildcard (a mask with no <code class="font-mono text-sm">?</code> is a prefix match, e.g. <code class="font-mono text-sm">0891</code> for the IMSI MCC/MNC). Record files store a per-record list.</li>
|
||
</ul>
|
||
<p class="text-sm mb-3"><strong>Check</strong> runs every rule against the equipped card and shows a live progress line plus a pass/fail report (existence, each FCI attribute, and the content match).</p>
|
||
<h4 class="font-medium mb-1">“Profile from card” scan options</h4>
|
||
<p class="text-sm mb-2">The scan dialog asks for a profile name and offers an <strong>“Ignore contents of”</strong> checklist (all checked by default) of frequently-overwritten files whose contents are skipped: <code class="font-mono text-sm">EF.LOCI</code>, <code class="font-mono text-sm">EF.PSLOCI</code>, <code class="font-mono text-sm">EF.EPSLOCI</code>, <code class="font-mono text-sm">EF.5GS3GPPLOCI</code>, <code class="font-mono text-sm">EF.Keys</code>, <code class="font-mono text-sm">EF.KeysPS</code>, <code class="font-mono text-sm">EF.SMS</code>, <code class="font-mono text-sm">EF.Kc</code>, <code class="font-mono text-sm">EF.KcGPRS</code>, <code class="font-mono text-sm">EF.LOCIGPRS</code>, <code class="font-mono text-sm">EF.CBMID</code>, <code class="font-mono text-sm">EF.SMSS</code>. Rules are created only for files that actually exist on the card (an FCI template is returned); missing files are skipped. Custom files from the <strong>Custom files</strong> sub-tab are included under the same existence check.</p>
|
||
|
||
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">5.7 Usage scenarios</h3>
|
||
|
||
<h4 id="scenario-a" class="font-medium mb-1">Scenario A — Working with files not in pySim’s model (Custom files)</h4>
|
||
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
|
||
<li>Obtain the FID of the target file (vendor documentation or ATR/file-system analysis; such files are often not in public specs).</li>
|
||
<li>Open the <strong>Card reader</strong> tab → <strong>Custom files</strong> sub-tab.</li>
|
||
<li>Enter the full path (e.g. <code class="font-mono text-sm">3F00/7F20/6F46</code>) and an alias (e.g. <code class="font-mono text-sm">EF.SPN</code>).</li>
|
||
<li>Click <strong>Add</strong> — the file appears in the tree in italics (unverified).</li>
|
||
<li>Click the file to verify existence; on success (<code class="font-mono text-sm">9000</code>) it behaves like a normal file.</li>
|
||
<li>Read, edit and save hex data; toggle Raw/Decoded views.</li>
|
||
<li>Export the custom-file list as JSON to share with other machines.</li>
|
||
</ol>
|
||
|
||
<h4 id="scenario-b" class="font-medium mb-1">Scenario B — Simulating a real network environment for SIM testing</h4>
|
||
<p class="text-sm mb-1"><strong>B.1 Answer PROVIDE LOCAL INFORMATION (PLI)</strong></p>
|
||
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
|
||
<li>Open <strong>Proactive UICC</strong> → <strong>PROVIDE LOCAL INFORMATION response data</strong>.</li>
|
||
<li>Use the decode/encode forms to set IMEI (<code class="font-mono text-sm">01</code>), Location Info (<code class="font-mono text-sm">00</code>), Access Technology (<code class="font-mono text-sm">06</code>), etc.</li>
|
||
<li>Click <strong>Save</strong> — values persist server-side.</li>
|
||
<li>Enable <strong>Polling</strong> (interval 30 s) so the card issues PLI periodically.</li>
|
||
<li>The server injects the dictionary values into each TERMINAL RESPONSE.</li>
|
||
<li>Verify in the proactive log: the PLI entry shows the decoded response.</li>
|
||
</ol>
|
||
<p class="text-sm mb-1"><strong>B.2 Simulate network actions via ENVELOPE (event download)</strong></p>
|
||
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
|
||
<li>Check the <strong>subscribed events</strong> list (from SET UP EVENT LIST).</li>
|
||
<li>Click <strong>Send</strong> on an event (e.g. Location Status) and fill the form; an <code class="font-mono text-sm">ENVELOPE(Event Download)</code> is sent.</li>
|
||
<li>For <strong>Network Rejection</strong>, select registration type → location fields → access technology → rejection cause.</li>
|
||
<li>The card may respond with a proactive command, which the chain handler logs and answers automatically.</li>
|
||
</ol>
|
||
<p class="text-sm mb-1"><strong>B.3 Verify the simulated environment</strong></p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li>The proactive command log shows the full round-trip (command + TERMINAL RESPONSE bytes).</li>
|
||
<li>The STATUS button / auto-polling keep the CAT session alive (drain loop).</li>
|
||
</ul>
|
||
|
||
|
||
<section class="mb-10">
|
||
<h2 id="server" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">6. Server installation</h2>
|
||
<p class="mb-3">Live card operations (Card reader tab, Proactive UICC, OTA delivery) require the local <a href="https://github.com/anttro/otaman" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-otaman-server</a> — a small HTTP server bundled with OTAMan that wraps pySim, talks to the reader over PC/SC or serial, and also serves the PWA itself (open <code class="font-mono text-sm">http://127.0.0.1:8080</code>).</p>
|
||
|
||
<h3 id="prerequisites" class="text-lg font-medium mb-2">6.1 Prerequisites</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Python 3.8+</strong> with <code class="font-mono text-sm">pip</code></li>
|
||
<li><strong>Git</strong></li>
|
||
<li><strong>Smart card reader</strong> (PC/SC or serial/FTDI). PC/SC is preferable; on Linux it requires <code class="font-mono text-sm">pcsc-lite</code> + <code class="font-mono text-sm">ccid</code></li>
|
||
<li><strong>Windows only</strong> — use <strong>Python 3.10–3.13</strong> (3.13 recommended): <code class="font-mono text-sm">pyscard</code> (the PC/SC driver wrapper) ships precompiled wheels for these versions. On Python 3.9 / 3.14 pip builds <code class="font-mono text-sm">pyscard</code> from source, which requires Microsoft C++ Build Tools (“Desktop development with C++”). The SMPP bridge (<code class="font-mono text-sm">smpp.twisted3</code>) is intentionally not installed on Windows, so no C++ Build Tools are needed for Python 3.10–3.13.</li>
|
||
</ul>
|
||
|
||
<h3 id="quickstart-linux" class="text-lg font-medium mb-2">6.2 Quick start — Linux / macOS</h3>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/otaman.git
|
||
cd otaman
|
||
chmod +x setup.sh start.sh
|
||
./setup.sh # creates .venv, installs pysim + server (run once)
|
||
./start.sh # starts the server (serves PWA + API, auto-detects reader)</pre>
|
||
|
||
<h3 id="quickstart-windows" class="text-lg font-medium mb-2">6.3 Quick start — Windows</h3>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/otaman.git
|
||
cd otaman
|
||
setup.bat # creates .venv, installs pysim + server (run once)
|
||
start.bat # starts the server (serves PWA + API)</pre>
|
||
|
||
<h3 id="helper-scripts" class="text-lg font-medium mb-2">6.4 Helper scripts</h3>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Script</th><th class="text-left py-1 px-2">Purpose</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">setup.sh / setup.bat</td><td class="py-1 px-2">Creates <code class="font-mono text-sm">.venv/</code>, installs pySim and the server. Run once after cloning.</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">start.sh / start.bat</td><td class="py-1 px-2">Starts the server from the venv (falls back to a global install).</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 id="reader-autodetect" class="text-lg font-medium mb-2">6.5 Reader auto-detection (<code class="font-mono text-sm">start.sh</code>)</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>PC/SC (Linux)</strong> — if the <code class="font-mono text-sm">pcscd</code> daemon is running, passes <code class="font-mono text-sm">-p 0</code></li>
|
||
<li><strong>Serial (Linux)</strong> — if <code class="font-mono text-sm">/dev/ttyUSB0</code> exists, passes <code class="font-mono text-sm">-d /dev/ttyUSB0</code></li>
|
||
<li><strong>PC/SC (Windows)</strong> — always uses <code class="font-mono text-sm">-p 0</code> (PC/SC is built into Windows)</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">If no reader is detected, the server starts without reader arguments and shows “Reader: none”. The card can be initialized later via the <strong>Equip</strong> button in the Card reader tab.</p>
|
||
|
||
<h3 id="manual-install" class="text-lg font-medium mb-2">6.6 Manual installation</h3>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3"># Create and activate a venv
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate # Linux/macOS
|
||
# .venv\Scripts\activate # Windows
|
||
|
||
# Install pysim
|
||
pip install git+https://github.com/osmocom/pysim.git
|
||
|
||
# Install pysim-otaman-server (editable, so it serves the bundled PWA)
|
||
pip install -e .
|
||
|
||
# Start the server (serves PWA + API)
|
||
pysim-otaman-server --http-port 8080</pre>
|
||
<p class="text-sm mb-3">Connect a PC/SC reader with a SIM card, then open <code class="font-mono text-sm">http://127.0.0.1:8080</code> — the PWA and API share one origin, so no CORS is involved.</p>
|
||
<p class="text-sm mb-3">If the PWA is served from a public HTTPS host (e.g. <code class="font-mono text-sm">https://otaman.example.com</code>), two things are required to reach a local card server: (1) the server must answer the preflight with <code class="font-mono text-sm">Access-Control-Allow-Private-Network: true</code> (pysim-otaman-server ≥ 1.6.1 does this automatically), and (2) the browser must be allowed to access the local network — in Chrome/Edge/Vivaldi: Site settings → Local network access → allow the site (or accept the permission prompt). Without the browser permission, the request to <code class="font-mono text-sm">127.0.0.1</code> is blocked before any preflight is sent.</p>
|
||
|
||
|
||
<section class="mb-10">
|
||
<h2 id="compatibility" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">7. Version compatibility</h2>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">PWA (OTAMan)</th><th class="text-left py-1 px-2">Server</th><th class="text-left py-1 px-2">Status</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">1.x.x</td><td class="py-1 px-2 font-mono">1.x.x</td><td class="py-1 px-2">✅ Compatible</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">1.x.x</td><td class="py-1 px-2 font-mono">0.x.x</td><td class="py-1 px-2">❌ Outdated — update server</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">1.x.x</td><td class="py-1 px-2 font-mono">2.x.x+</td><td class="py-1 px-2">⚠️ Server newer — update PWA</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm">The PWA checks the server version on connect via <code class="font-mono text-sm">GET /api/version</code> and warns if versions are incompatible.</p>
|
||
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
if (localStorage.getItem('theme') === 'dark' ||
|
||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||
document.documentElement.classList.add('dark');
|
||
}
|
||
var toc = document.getElementById('toc');
|
||
var main = document.querySelector('main');
|
||
if (!toc || !main) return;
|
||
var headings = Array.prototype.filter.call(main.querySelectorAll('h2, h3, h4'), function (h) {
|
||
return /^\d/.test(h.textContent.trim());
|
||
});
|
||
var stack = [document.createElement('ol')];
|
||
stack[0].className = 'space-y-1 list-none';
|
||
var lastLevel = 2;
|
||
headings.forEach(function (h) {
|
||
var level = parseInt(h.tagName.charAt(1), 10);
|
||
var li = document.createElement('li');
|
||
var a = document.createElement('a');
|
||
a.href = '#' + h.id;
|
||
a.textContent = h.textContent;
|
||
li.appendChild(a);
|
||
if (level > lastLevel) {
|
||
var ul = document.createElement('ul');
|
||
ul.className = 'pl-4 mt-1 space-y-1 list-none';
|
||
var parent = stack[stack.length - 1].lastElementChild;
|
||
parent.appendChild(ul);
|
||
stack.push(ul);
|
||
} else if (level < lastLevel) {
|
||
while (stack.length > 1 && level < lastLevel) { stack.pop(); lastLevel--; }
|
||
}
|
||
stack[stack.length - 1].appendChild(li);
|
||
lastLevel = level;
|
||
});
|
||
toc.appendChild(stack[0]);
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|