HIL Bridge
Tools/HilBridge/ is the physical-card-to-modem bridge. Use it when a real
UICC/eUICC must stay in a PC/SC reader on the host while serving a modem
through a SIMtrace2, and YggdraSIM shells still need live side-channel access
to the same card.
On this page
Underlying concept
Read HIL Model first. This page focuses on the operator surface and health signals.
When to use it
- reproducing a real modem's behavior against a real eUICC in the lab
- capturing end-to-end APDU traces with both modem and YggdraSIM activity visible
- observing a live relay or local-access session while the modem is interacting with the same card
- serving a SIMtrace2 in card-emulation mode for a DUT
- re-opening a previously saved
.pcap/.pcapngin the decoded-APDU TUI without bringing the bridge stack back up (offline review mode) - layering SCP03 / SCP11c plaintext onto ciphered APDUs in either live or offline review by pairing the capture with a keybag JSON sidecar
Entry points
The supervisor is the recommended process. The bridge alone is meant for manual debugging.
yggdrasim-hil-supervisor \
--reader-index 0 \
--host 127.0.0.1 \
--port 9997 \
--advertise-host 127.0.0.1 \
--usb-vidpid 1d50:60e3
python -m Tools.HilBridge.supervisor \
--reader-index 0 \
--host 127.0.0.1 \
--port 9997 \
--advertise-host 127.0.0.1 \
--usb-vidpid 1d50:60e3
yggdrasim-hil-bridge
python -m Tools.HilBridge.main
python main/main.py --open-pcap /path/to/capture.pcapng
python main/main.py --open-pcap /path/to/capture.pcap \
--keybag /path/to/session.keys.json
Opens the decoded-APDU TUI in offline mode. No SIMtrace2, no
supervisor, no FIFO, no tshark -i. The capture is read via
tshark -r. When a keybag is provided (or a sibling
<capture>.keys.json is auto-discovered), SCP03 / SCP11c ciphered
APDUs are unwrapped and shown as extra plaintext rows next to the
matching frame. See Replay a HIL pcap offline.
Supervisor responsibilities
The supervisor:
- starts and supervises both the HIL bridge process and
osmo-remsim-client-st2 - tracks USB presence of the SIMtrace2 by VID:PID
- writes health state to
state/hil_bridge_supervisor.json - writes card-relay endpoint state to
state/hil_bridge_card_relay.json - cleans up both processes on shutdown
Runtime dependencies
pcscdand its reader driversosmo-remsim-client-st2- SIMtrace2 hardware flashed for card emulation
- optional
simtrace2-list/simtrace2-toolfor manual inspection - optional Wireshark for GSMTAP capture
State the supervisor and bridge write
| File | Contents |
|---|---|
state/hil_bridge_supervisor.json |
supervisor status, bridge PID, USB presence |
state/hil_bridge_card_relay.json |
relay status, URLs, reader name, ATR |
Health signals
Healthy state reads:
- supervisor
status: running - supervisor
usbPresent: true - supervisor
bridgePidnon-zero - relay
status: ok - relay exposes
apduUrl,statusUrl,modemRefreshUrl - relay shows a non-empty
readerand a non-emptyatr
Anything else means the stack is not fully armed.
Common recipes
Start, check, stop
yggdrasim-hil-supervisor --reader-index 0 --host 127.0.0.1 --port 9997
# ... in another shell ...
cat state/hil_bridge_supervisor.json
cat state/hil_bridge_card_relay.json
# ... stop via the supervisor's shutdown path or Ctrl-C ...
Pair with a YggdraSIM shell
Once the relay reports status: ok, open any SCP11 or SCP03 shell that can
be pointed at the relay URLs. The card will see both modem APDUs and
YggdraSIM APDUs on one session, serialized through the bridge.
Use Wireshark to watch GSMTAP
Open Wireshark on UDP 4729 (loopback). The bridge mirrors every APDU as GSMTAP while it is running, even if no YggdraSIM shell is attached.
Offline pcap replay
The decoded-APDU TUI has two drive modes:
| Mode | How it is launched | Notes |
|---|---|---|
| Live capture | [B] HIL sub-menu pick [1] with view [3] (Decoded APDU) |
tails the running bridge's FIFO via tshark -i |
| Offline review | [B] sub-menu pick [3], or main/main.py --open-pcap <path> |
reads a saved .pcap / .pcapng via tshark -r, with no FIFO and no bridge |
Both modes accept a keybag JSON sidecar. It stores the per-session
SCP03 / SCP11c key material that the TUI's replay engine needs to
unwrap secure-messaging APDUs (CLA bit 0x04). When resolving the
keybag, the TUI tries, in order:
--keybag <path>on the launcher, or the prompt in the[B]offline-review flow<capture>.pcap.keys.jsonnext to the capture<capture>.keys.json(capture stem +.keys.json)
A missing or unreadable keybag is non-fatal — ciphered APDUs simply
stay wrapped in the TUI. See Keybag JSON schema
below for the file shape and how to produce one with
EXPORT-KEYBAG in SCP03 / SCP11 Local Access,
or with --dump-keybag from the same modules.
Session key export
Keybags are produced host-side by the same shells that derive the session keys. The two supported flows are:
| Source shell | Command | Where the keys come from |
|---|---|---|
SCP03 |
EXPORT-KEYBAG [OutputPath.keys.json] [Label] |
Scp03Session S-ENC / S-MAC / S-RMAC + SSC + chaining value after AUTH-SD |
SCP11.local_access (shell) |
EXPORT-KEYBAG [OutputPath.keys.json] [Label] |
last-built pySim BSP (S-ENC, S-MAC, MAC chain, block number, AID) |
SCP11.local_access (CLI) |
python -m SCP11.local_access --dump-keybag <path> |
same BSP snapshot, non-interactive |
SCP11.live (CLI) |
python -m SCP11.live --dump-keybag <path> |
no-op: live-mode BSP keys are derived inside the eUICC and never reach the host. The flag prints a clear message pointing at SCP11.local_access or SCP03. |
Both EXPORT-KEYBAG handlers refuse with a clear message when no
authenticated session / derived BSP snapshot is available.
Keybag JSON schema
{
"format": "yggdrasim-hil-keybag/v1",
"entries": [
{
"label": "case-1234",
"protocol": "SCP03",
"aid_hex": "A000000151000000",
"s_enc_hex": "...32 hex chars...",
"s_mac_hex": "...32 hex chars...",
"s_rmac_hex": "...32 hex chars...",
"ssc_hex": "0000000000000000",
"chaining_value_hex": "",
"block_nr": 0
}
]
}
Keys:
formatmust beyggdrasim-hil-keybag/v1.entriesis a list; multiple SCP03 / SCP11c sessions can coexist in a single file.protocolis"SCP03"or"SCP11c"; the TUI uses it to decide which crypto path to drive.s_enc_hex/s_mac_hex/s_rmac_hexare the session keys (SCP03 naming; SCP11c fills S-RMAC with empty string).ssc_hex/chaining_value_hex/block_nrcapture the state the replay engine needs to mirror the on-card counters at the moment of export.aid_hexbinds the entry to the SELECT AID that preceded the secure channel on capture time, so multiple sessions against the same card are disambiguated.
Write a keybag with EXPORT-KEYBAG / --dump-keybag or by hand; the
schema is stable across v1.
Pitfalls
- A second PC/SC client cannot open the same reader while the bridge owns it. Close other shells first, or go through the relay side-channel.
- USB presence alone is not readiness. Wait until the relay advertises
status: okand a non-emptyatr. - Restarting only the bridge without the supervisor can leave
osmo-remsim-client-st2orphaned. Use the supervisor for normal lifecycle. - A flashed firmware mismatch on the SIMtrace2 will let the supervisor enumerate the USB device, but the relay will never come up. Check the remsim-client logs.
- Offline review mode trusts the capture's ATR / SELECT context. If the
keybag entry's
aid_hexdoes not match the AID in the capture the corresponding APDUs simply stay wrapped. SCP11.live --dump-keybagis intentionally a stub — the keys never leave the card in live mode. UseSCP11.local_accessor SCP03 for real exports.
AT+CSIM / AT+CRSM transcoder
Tools/HilBridge/at_simlink.py (3GPP TS 27.007 §8.17 / §8.18) is a
transport-agnostic transcoder that turns AT+CSIM=... and
AT+CRSM=... request lines into raw ISO 7816 APDUs and stringifies
the responses back into +CSIM: / +CRSM: reply lines. Use it when
an AT-controlled modem must exercise the simulator or a SIMtrace2-bridged
card without a direct PC/SC handle:
| Request shape | Decoded APDU |
|---|---|
AT+CSIM=<length>,"<hex>" |
raw CLA INS P1 P2 P3 … |
AT+CRSM=<command>,<fileid>,<P1>,<P2>,<P3>[,"<data>"][,"<path>"] |
CLA=0x00, INS from the §8.18 command table |
Common modem REFRESH and AT-only flows can therefore be replayed through the same simulator backend the SCP shells use, with no host PC/SC involvement on the modem side.
Optional systemd --user service
guides/systemd/yggdrasim-hil-supervisor.service.example ships as a starting
point when the supervisor should be launched on demand under user service
control.
Related pages
- HIL Model
- Run a HIL Capture
- Replay a HIL pcap offline
- SCP03 Admin Shell — EXPORT-KEYBAG
- SCP11 Local Access — EXPORT-KEYBAG /
--dump-keybag guides/HIL_BRIDGE_GUIDE.mdfor the deep authored guide