OTAMan Documentation
1. Overview
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.
The application is a single static index.html file. All computation runs in the browser; the card is accessed through a local HTTP server (pysim-otaman-server) that wraps the pySim library.
Browser (OTAMan PWA) → HTTP :8080 → pysim-otaman-server → pySim → PC/SC → card reader → UICC/SIM
Standards referenced across the application:
- ETSI TS 102 221 — UICC-Terminal interface (CLA 00, USIM files)
- ETSI TS 102 222 — Administrative commands
- ETSI TS 102 223 — Card Application Toolkit (CAT, proactive commands)
- ETSI TS 102 225 — Secured packet structure for (U)SIM toolkit
- ETSI TS 102 226 — Remote APDU structure for UICC based applications
- ETSI TS 151 011 — SIM-ME interface (CLA A0)
- 3GPP TS 131 111 — USIM Application Toolkit (USAT)
- 3GPP TS 31.102 — USIM application characteristics
- 3GPP TS 23.038 — GSM 7-bit alphabet and DCS
- 3GPP TS 24.008 / 24.301 / 24.501 — NAS cause codes
- GlobalPlatform Card Specification v2.3.1
- ISO/IEC 7816-4 — commands for interchange
- ISO/IEC 9797-1 — MAC algorithms
2. C-APDU tab
Builds command APDUs (C-APDUs). Four sub-tabs cover different card generations and command sets.
2.1 SIM RFM
CLA = A0 (GSM 11.11 / TS 151 011, ISO 7816-4). Remote File Management for classic SIM cards.
| Command | INS | Description |
|---|---|---|
| SELECT | A4 | Select EF/DF by FID, path, DF name or chain |
| UPDATE RECORD | DC | Update a record in a record-oriented EF |
| UPDATE BINARY | D6 | Update binary content at an offset |
| READ RECORD | B2 | Read a record |
| READ BINARY | B0 | Read binary content |
| ERASE BINARY | 0E | Erase binary at an offset |
| ACTIVATE FILE | 44 | Activate a file |
| DEACTIVATE FILE | 04 | Deactivate a file |
| VERIFY PIN | 20 | Verify PIN1 or PIN2 |
| CHANGE PIN | 24 | Change PIN1 or PIN2 |
SELECT methods
| Method | P1 | P2 | Input |
|---|---|---|---|
| By FID | 00 | 00 | 2-byte FID (4 hex) |
| By full path from MF | 08 | 00 | Full path hex from MF |
| By DF name / AID | 04 | 00 | AID (application ID) |
| ADF RFM chain | 00 | 00 | Comma-separated FIDs |
Options
- Start with SELECT — prepend a SELECT before the operation; unchecked sends standalone.
- Selection mode (P2) — record commands: Absolute (04), Next (06), Previous (02).
- Record size — pad/truncate data to the specified byte count.
- Allow P1/P2 editing — manual override of P1/P2 bytes.
A conversion panel is embedded in the right column (IMSI, MSISDN, ICCID, SPN, PLMN, nibble swap). See §2.5.
2.2 USIM RFM
CLA = 00 (ETSI TS 102 221). Same commands as SIM, but SELECT uses P1=09, P2=0C (select by FID from the current directory).
2.3 Expanded BER-TLV
Builds the Expanded Remote Application data format per ETSI TS 102 226 §5.2.1.
Format
- Definite (AA):
AA+ length + Command TLVs - Indefinite (AE):
AE+80+ Command TLVs +00 00
Command TLVs
| Type | Tag | Description |
|---|---|---|
| C-APDU | 22 | Raw APDU hex |
| Immediate Action | 81 | Proactive command or action indicator |
| Error Action | 82 | Proactive command on error |
| Script Chaining | 83 | Chaining data for multi-packet scripts |
The Immediate Action builder offers an action indicator (81/82), a structured proactive command builder (REFRESH, DISPLAY TEXT, PLAY TONE with auto-generated COMPREHENSION-TLV objects), or a freeform hex input.
2.4 RAM/GP
CLA = 80 (GlobalPlatform Card Specification v2.3.1). Remote Application Management commands for card content management.
| Command | INS | P1 | Description |
|---|---|---|---|
| INSTALL [for load] | E6 | 02 | Register a load file for loading |
| INSTALL [for install] | E6 | 0C | Install an application or SD |
| INSTALL [make selectable] | E6 | 10 | Make an application selectable |
| INSTALL [registry update] | E6 | 01 | Update registry entries |
| INSTALL [extradition] | E6 | 04 | Extradition between SDs |
| LOAD | E8 | 00 | Load executable code blocks |
| DELETE | E4 | 00/80 | Delete application or SD |
| GET STATUS | F2 | 80/40/20/10 | Get card status |
| GET DATA | CA | tag | Read card data objects |
| STORE DATA | E2 | 00/40/80/C0 | Store data (key, certificate, …) |
| SET STATUS | F0 | 80/40/60 | Lifecycle state management |
| EXTERNAL AUTHENTICATE | 82 | 00 | SCP host authentication |
| INTERNAL AUTHENTICATE | 88 | 00 | Card challenge-response |
Privileges (INSTALL [for install])
Tag C7 in the INSTALL data field, built from 3 privilege bytes (GP spec Tables 11-7/8/9):
| Bit | Byte 1 | Byte 2 | Byte 3 |
|---|---|---|---|
| b8 | Security Domain | Trusted Path | Receipt Generation |
| b7 | DAP Verification | Authorized Management | |
| b6 | Delegated Management | Token Verification | |
| b5 | Card Lock | Global Delete | |
| b4 | Card Terminate | Global Lock | |
| b3 | Card Reset | Global Registry | |
| b2 | CVM Management | Final Application | |
| b1 | Mandated DAP Verification |
MSL (Minimum Security Level) — SPI1 byte per TS 102 225
| Value | Meaning |
|---|---|
| 00 | No check |
| 11 | RC/CC/DS |
| 12 | RC/DS/CC |
| 15 | RC/DS/CC + MAC |
| 16 | RC/DS/CC + MAC + Cipher |
| 19 | RC/DS/CC + MAC + Cipher + DS |
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.
2.5 Conversion (SIM/USIM sidebars)
- IMSI → EF.IMSI — 15-digit IMSI to 9-byte format (TS 31.102 §4.2.3).
- MSISDN → BCD — strip
+, pad odd length withf, swap nibbles. - ICCID → hex — nibble-swap the ICCID string.
- Provider Name → SPN — GSM 7-bit packed, UCS2 non-BMP, or UCS2 BMP (TS 31.102 §4.2.5, TS 23.038).
- PLMN → EF_PLMNsel / PLMNwAcT — 3-byte BCD + optional access technology selector.
- Nibble swap — swap nibble pairs of an even-length hex string.
3. Secured Packet tab
Assembles SCP80 secured packets per ETSI TS 102 225.
Packet structure
| Field | Size | Description |
|---|---|---|
| CPI | 1 | Command Packet Identifier (02) |
| CPL | 1 | Command Packet Length |
| CHI | 1 | Command Header Identifier (01) |
| CHL | 1 | Command Header Length |
| SPI | 2 | Security Parameter Indicator |
| KIc | 1 | Key Identifier for ciphering |
| KID | 1 | Key Identifier for MAC |
| TAR | 3 | Toolkit Application Reference |
| CNTR | 5 | Replay counter |
| PCNTR | 1 | Padding counter |
| RC/CC/DS | 8 | Cryptographic Checksum / MAC |
| Secured Data | var. | Padded APDU (encrypted if required) |
Crypto
- 3DES-CBC encryption (zero ICV), 8/16/24-byte keys — deprecated since Rel-18, still supported for backwards compatibility
- AES-CBC encryption (zero ICV, zero-padded to 16), 16/24/32-byte keys (TS 102 225 §5.1.2, KIc
x2) - Retail MAC (ISO 9797-1 MAC algorithm 3) for the DES/3DES cryptographic checksum
- AES-CMAC (NIST SP 800-38B, truncated to 8 octets) for the AES cryptographic checksum (TS 102 225 §5.1.3.1, KID
x2) - AES requires a replay-protected counter: SPI1 bits b5 b4 must be
10(counter higher) or11(counter +1) per TS 102 225 §5.1.2/§5.1.3.1 - Padding byte configurable (
00default, orFF)
A “Verify vs pySim” button cross-checks the assembled packet against pySim’s reference OtaDialectSms.encode_cmd. A “Send to Card” button delivers it via SMS-PP-DOWNLOAD ENVELOPE (when connected to the server).
4. Response parser tab
Decodes a raw command response: pick the command that was sent, enter the SW (e.g. 9000) and the response data hex, then press Decode.
- Command — 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).
- SW decode — status words resolved against generic, UICC (TS 102 221), and GlobalPlatform maps, with context auto-detected.
- Privilege decode — GET DATA / INSTALL response payloads decode the privilege bytes into human-readable flags.
- Response data — raw hex rendered and interpreted per command (e.g. SELECT FCP templates).
5. Cards tab
Stores card presets locally in the browser (localStorage) so the Secured Packet tab can auto-fill keys and parameters.
| Field | Description |
|---|---|
| Name | Human-readable label |
| ICCID | Optional card identifier |
| KIc / KID | Key and algorithm indicators (e.g. 15 = index 1, 3DES-CBC2; x2 = AES) |
| SPI1 / SPI2 | Security Parameter Indicators |
| TAR | Toolkit Application Reference |
| Counter | Replay counter (5 bytes) |
| KIc key / KID key | 16/24/32 hex chars (8/16/24-byte 3DES) or 32/48/64 hex chars (16/24/32-byte AES) keys |
Export as JSON / Import JSON from clipboard share presets. The selected card preset auto-fills the Secured Packet form.
6. Card reader (pySim) tab
Connects to a local pysim-otaman-server for live card operations. Sub-tabs: File manager, Custom files, pySim command line, Raw APDU, and Proactive UICC.
6.1 File manager
- Read — reads the selected file (auto-detects transparent vs record files)
- Edit — modify hex data, Save to write back
- Raw / Decoded — toggle between hex dump and pySim-decoded JSON
6.2 Custom files
Add files that pySim’s model does not cover. Persists in localStorage; JSON export/import.
6.3 pySim command line
Execute any pySim-shell command with usage hints (300 ms) and autocomplete.
6.4 Raw APDU
Send an arbitrary APDU and view the raw response.
6.5 Proactive UICC
Interacts with the Card Application Toolkit session: subscribed events, the proactive command log, the PROVIDE LOCAL INFORMATION data dictionary, and STATUS polling.
6.5.1 Subscribed events (SET UP EVENT LIST)
The events the card monitors. Each event has a Send button that opens a form specific to the event type:
- No-data events (User Activity, Idle Screen, Data Available, …) — one-click notification
- Location Status — dropdown: Normal / Limited / No service (tag
9B) - Access Technology Change — 13 RAT types (tag
BF) - Network Rejection — 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
Sending an event uses ENVELOPE(Event Download) per TS 102 223 / TS 131 111.
6.5.2 Proactive command log
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 Response: line with the TERMINAL RESPONSE bytes (boilerplate TLVs stripped); PROVIDE LOCAL INFORMATION responses are decoded using the PLI data dictionary decoders.
6.5.3 PROVIDE LOCAL INFORMATION data dictionary
Editable hex values for all 22 PLI qualifiers (TS 102 223 §8.6 + TS 131 111). Ten qualifiers have inline decode/encode forms:
- 00 Location Info (MCC, MNC, LAC/TAC, Cell ID)
- 01 IMEI · 03 Date/Time/TZ · 04 Language · 05 Timing Advance
- 06 Access Technology · 08 IMEISV · 09 Search Mode
- 0A Battery · 0E Multiple Access Technologies
Values persist server-side until restart. When the card issues PLI, the server injects the dictionary values into the TERMINAL RESPONSE.
6.5.4 STATUS polling
A Send STATUS button issues a manual STATUS (F2). A Polling toggle enables background polling: after a configurable idle interval (server CLI --poll-interval, 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.
6.6 Usage scenarios
Scenario A — Working with files not in pySim’s model (Custom files)
- Obtain the FID of the target file (vendor documentation or ATR/file-system analysis; such files are often not in public specs).
- Open the Card reader tab → Custom files sub-tab.
- Enter the full path (e.g.
3F00/7F20/6F46) and an alias (e.g.EF.SPN). - Click Add — the file appears in the tree in italics (unverified).
- Click the file to verify existence; on success (
9000) it behaves like a normal file. - Read, edit and save hex data; toggle Raw/Decoded views.
- Export the custom-file list as JSON to share with other machines.
Scenario B — Simulating a real network environment for SIM testing
B.1 Answer PROVIDE LOCAL INFORMATION (PLI)
- Open Proactive UICC → PROVIDE LOCAL INFORMATION response data.
- Use the decode/encode forms to set IMEI (
01), Location Info (00), Access Technology (06), etc. - Click Save — values persist server-side.
- Enable Polling (interval 30 s) so the card issues PLI periodically.
- The server injects the dictionary values into each TERMINAL RESPONSE.
- Verify in the proactive log: the PLI entry shows the decoded response.
B.2 Simulate network actions via ENVELOPE (event download)
- Check the subscribed events list (from SET UP EVENT LIST).
- Click Send on an event (e.g. Location Status) and fill the form; an
ENVELOPE(Event Download)is sent. - For Network Rejection, select registration type → location fields → access technology → rejection cause.
- The card may respond with a proactive command, which the chain handler logs and answers automatically.
B.3 Verify the simulated environment
- The proactive command log shows the full round-trip (command + TERMINAL RESPONSE bytes).
- The STATUS button / auto-polling keep the CAT session alive (drain loop).
7. Server installation
Live card operations (Card reader tab, Proactive UICC, OTA delivery) require the local pysim-otaman-server — 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 http://127.0.0.1:8080).
7.1 Prerequisites
- Python 3.8+ with
pip - Git
- Smart card reader (PC/SC or serial/FTDI). PC/SC is preferable; on Linux it requires
pcsc-lite+ccid - Windows only — use Python 3.10–3.13 (3.13 recommended):
pyscard(the PC/SC driver wrapper) ships precompiled wheels for these versions. On Python 3.9 / 3.14 pip buildspyscardfrom source, which requires Microsoft C++ Build Tools (“Desktop development with C++”). The SMPP bridge (smpp.twisted3) is intentionally not installed on Windows, so no C++ Build Tools are needed for Python 3.10–3.13.
7.2 Quick start — Linux / macOS
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)
7.3 Quick start — Windows
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)
7.4 Helper scripts
| Script | Purpose |
|---|---|
| setup.sh / setup.bat | Creates .venv/, installs pySim and the server. Run once after cloning. |
| start.sh / start.bat | Starts the server from the venv (falls back to a global install). |
7.5 Reader auto-detection (start.sh)
- PC/SC (Linux) — if the
pcscddaemon is running, passes-p 0 - Serial (Linux) — if
/dev/ttyUSB0exists, passes-d /dev/ttyUSB0 - PC/SC (Windows) — always uses
-p 0(PC/SC is built into Windows)
If no reader is detected, the server starts without reader arguments and shows “Reader: none”. The card can be initialized later via the Equip button in the Card reader tab.
7.6 Manual installation
# 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
Connect a PC/SC reader with a SIM card, then open http://127.0.0.1:8080 — the PWA and API share one origin, so no CORS is involved.
If the PWA is served from a public HTTPS host (e.g. https://otaman.example.com), two things are required to reach a local card server: (1) the server must answer the preflight with Access-Control-Allow-Private-Network: true (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 127.0.0.1 is blocked before any preflight is sent.
8. Version compatibility
| PWA (OTAMan) | Server | Status |
|---|---|---|
| 1.x.x | 1.x.x | ✅ Compatible |
| 1.x.x | 0.x.x | ❌ Outdated — update server |
| 1.x.x | 2.x.x+ | ⚠️ Server newer — update PWA |
The PWA checks the server version on connect via GET /api/version and warns if versions are incompatible.