Skip to main content

OTA SIM Management — over-the-air RFM/RAM

The OTA module manages SIMs over the air: it reads and edits files on a remote card by sending secured packets (ETSI TS 102 225 / 3GPP TS 31.115 — "03.48" / SCP80) that carry Remote File Management (RFM) and Remote Application Management (RAM) commands. The card verifies and decrypts each packet, executes the commands, and returns a signed Proof-of-Receipt (POR).

In practice it gives you the same file-level editing as the offline SIM Filesystem Explorer — browse the file tree, decode an EF, edit the fields, write it back — except the card is reached remotely: through a PC/SC reader on the central host, a reader at a remote agent, or over SMPP to a SIM in the field.

It builds on the same per-ICCID key store as the SIM Key Store: a profile says which keyset and algorithms, the key store holds the actual KIC/KID for that card, and the engine never logs or returns the keys — only the resulting ciphertext and the POR.

OTA SIM Explorer — browse the file catalog, read an EF over OTA, see the decoded fields and the Proof-of-Receipt


What a secured packet is

A secured packet protects the command APDUs end-to-end, independent of the (plain) bearer. The engine has been validated against physical ISIM cards.

Command Packet  =  CPL | CHL | SPI | KIc | KID | TAR(3) | CIPHERED
CIPHERED = 3DES-CBC( CNTR(5) | PCNTR(1) | CC(8) | APDUs+padding ) IV=0
CC = last8( 3DES-CBC( KID, zeropad(CPL+hdr+CNTR+PCNTR+APDUs) ) )
  • TAR (Toolkit Application Reference, 3 bytes) routes the packet to a service on the card — a specific RFM application or the RAM (card manager).
  • SPI flags select ciphering, the cryptographic checksum (CC), the counter policy, and what the POR must contain.
  • KIc / KID index which transport (ciphering) and authentication keyset the card uses; the values come from the key store per ICCID.

The APDUs inside are an ordinary C-APDU script — SELECT + READ BINARY for an RFM read, SELECT + UPDATE BINARY for a write, GlobalPlatform DELETE / INSTALL for RAM.

On the wire (an SMS-PP) the packet rides in the TP-User-Data with a UDH Command Packet Identifier (IEI 0x70), PID 0x7F (SIM data download), DCS 0xF6 (8-bit, message class 2). In-shell it is delivered as a CAT ENVELOPE(SMS-PP-Download) APDU and the POR comes back synchronously.


Profiles, contexts, and auto-routing

An OTA profile is a reusable security preset — it holds no key material:

OTA Profiles — reusable {TAR, keyset index, algorithms, SPI} presets; keys stay per-ICCID in the SIM Key Store

FieldMeaning
tar3-byte Toolkit Application Reference (the target service).
kic_index / kid_indexWhich keyset (1/2/3) → KIC{n}/KID{n} from the card's key-store row.
cipher_algo / cc_algoCiphering and checksum algorithm (triple_des_cbc2, aes_cbc, …).
ciphering, rc_cc_ds, counter_modeSPI: encrypt? CC vs RC vs none? replay-counter policy.
por, por_ciphered, por_rc_cc_dsPOR required? ciphered? signed?

Two profiles are seeded, matching the values validated on sysmoISIM:

  • RFM-USIM-3DES-keyset3 — TAR B00011, keyset 3, 3DES, ciphering + CC, POR required + ciphered + CC. Operates inside ADF.USIM.
  • RFM-SIM-3DES-keyset2 — TAR B00010, keyset 2. Operates on the MF-rooted 2G tree (DF.GSM / DF.TELECOM).

Different applications need different services, so the explorer routes the profile and the SELECT context automatically per file, from the file's application:

File applicationContextProfile (by TAR)Pre-SELECT before the ENVELOPE
ADF.USIMusimTAR B00011SELECT ADF.USIM (by AID)
DF.GSM, DF.TELECOMsimTAR B00010none (MF-rooted)
ADF.ISIMisimTAR B00013SELECT ADF.ISIM (by AID)

Each context maps to one of your profiles (defaulted by matching TAR, overridable in the explorer). Pick a card and click any file — USIM, GSM or TELECOM — and the right profile, keyset and SELECT are applied without switching anything. ISIM works as soon as you create a profile for it (its TAR varies by card).


Transports

A transport delivers the secured packet and, where the bearer allows, collects the POR. The pluggable adapters share one interface:

KindReachesPORNotes
local_pcsca card in a PC/SC reader on the central hostsynchronousthe directly-attached validation path.
agent_readera card in a reader at a remote agentsynchronousrides the same agent WebSocket as Test Devices / SIM Bank (session_apdu relay).
smppa field SIM over SMPP submit_smasynchronousMT SMS to an SMSC; the POR returns later as an MO SMS.

The Explorer uses only the in-shell transports (it needs a synchronous POR); Campaigns can use any, including SMPP.


Explorer

src/pages/ota/OtaExplorer.tsx — the remote SIM file editor.

  1. Pick a target ICCID (from the SIM Key Store) and a transport.
  2. Browse the file catalog — every known EF from the offline file model (ADF.USIM, ADF.ISIM, DF.GSM, DF.TELECOM), grouped by application and searchable by code / name / description.
  3. Select a file → Read over OTA. The secured RFM read is delivered, the POR decoded, and the EF rendered: POR status, last SW, raw hex + ASCII, and a typed field form (decoded to named fields).
  4. Edit the fields (re-encoded automatically) or the raw hex, then Write over OTA. The secured RFM UPDATE is sent and the file is read back automatically so you see the on-card state after the write.

Reads/writes are gated by the ota control permission; everything is recorded as a job.


Campaigns

src/pages/ota/OtaCampaigns.tsx — a saved operation fanned out across a set of SIMs: target query → operation → profile → transport.

OTA Campaigns — saved {target query, operation, profile, transport}; preview targets, run, and one job per matched card

  • Target query is evaluated against the SIM Bank inventory at run time: ICCID list / prefix, IMSI prefix or range, agent, bank. An empty query deliberately matches nothing (no accidental fan-out).
  • Operation is the RFM/RAM command (read/update binary or record, GP delete / get-status / install).
  • Run creates one job per matched card. SMPP campaigns are fire-and-forget (the POR arrives later as an MO SMS).

A run is bounded (CAMPAIGN_MAX_TARGETS) so a fat-finger query can't blast thousands of cards in one request.


Jobs

src/pages/ota/OtaJobs.tsx — every OTA delivery (explorer reads/writes and campaign runs) with its status and POR. The detail drawer shows the secured request packet (ciphertext), the Proof-of-Receipt, and the decoded result (commands executed, last SW, response data). Card secrets are never stored on a job — only the ciphertext and POR.

OTA Jobs — every delivery with operation, transport, status and POR; click a row for the ciphertext + decoded result


REST API (/api/ota, JWT, RBAC element type ota)

MethodRoutePurpose
GET/profiles · POST · /profiles/<id> PUT/DELETEOTA security profiles.
GET/campaigns · POST · /campaigns/<id> GET/PUT/DELETECampaigns.
GET/campaigns/<id>/targetsPreview which SIMs the query currently matches.
POST/campaigns/<id>/runExecute — one job per matched card.
GET/jobs, /jobs/<id>Job history (filter by campaign_id / iccid).
GET/files/catalogThe browsable EF catalog (offline file model).
POST/explore/readRead one EF over OTA; returns the job + decoded EF.
POST/executeRun one operation (RFM update, RAM, raw) against one card.
POST/previewBuild the secured packet without sending (inspect the ciphertext + SMS framings).
POST/decode · /encodeDecode EF bytes ↔ typed fields (offline).

RBAC mirrors simbank/ir38: admins always pass; otherwise a JWT permission with element_type == "ota" grants view, and POST in its methods grants control. Reads are treated as control (they transmit a packet to the card). Routes are auto-documented in the API Reference.


Database schema

TableRowKey columns
ota_profilesone security presetname, tar, kic_index/kid_index, algorithms, SPI flags.
ota_campaignsone saved fan-outname, profile_id, target_query (JSON), operation (JSON), transport (JSON), status.
ota_jobsone delivery to one cardiccid, operation, request_hex (ciphertext), response_hex (POR), por_status, result (JSON), status.

Keys live in the existing simbank_keys table (the SIM Key Store), referenced per ICCID by the profile's keyset index — not duplicated here.


How it works

The OTA engine handles the crypto, secured-packet structure, CAT/SMS TLVs and the offline file model needed to build and decode 03.48/SCP80 RFM/RAM packets. It runs in the agent-role backend service and shares the agent connection for the in-shell transport. Delivery is pluggable across the local-reader, remote-agent-reader, and SMPP transports.


Security notes

  • Card secrets (KIC/KID) are read from the key store to build packets but are never written to the audit log or returned in any response — only the ciphertext request and the POR are stored.
  • Writing a file is destructive; the explorer confirms before each write and reads back the result.
  • The secured packet is genuine 03.48: tamper a byte and the card rejects it (the CC fails); with ciphering on, the plaintext APDUs never appear on the wire.
  • SCP80 only — this is not SCP81 (no PSK-TLS / HTTPS Admin Agent).