Summary
We've implemented and hardware-verified a full GlobalPlatform (GP) card management stack that runs entirely on the Specter-DIY STM32F469 firmware. This enables the device to manage installed JavaCard applets directly — no PC-based tools like GlobalPlatformPro required.
All 19/19 hardware tests pass on a real JCOP4 card, covering the complete applet lifecycle: install, verify, and delete.
What we built
Pure Python SCP02 Secure Channel
des3.py — Full DES/3DES implementation (FIPS 46-3) in pure Python, since MicroPython on STM32F469 has no DES/3DES hardware support (only AES via ucryptolib). Verified against pycryptodome on desktop.
scp02.py — SCP02 session management: INITIALIZE UPDATE, EXTERNAL AUTHENTICATE, session key derivation, and C-MAC wrapping. Verified byte-for-byte against a GlobalPlatformPro hardware trace captured from the same JCOP4 card.
GP Card Management Operations
registry.py — GET STATUS with auto-detection of both standard E3-tagged TLV responses and JCOP4's proprietary compact format. Finds applets by both top-level AID and module AIDs.
loader.py — INSTALL FOR LOAD, chunked LOAD, and INSTALL FOR INSTALL, all aligned byte-for-byte with GPPro trace output. LOAD uses 247-byte blocks (255 Lc minus 8-byte MAC).
deleter.py — DELETE with P2=0x80 for cascading deletion of related objects.
profiles.py — JCOP4 profile with GP default keys (404142...4F) and SCP02 configuration.
REPL Development & Testing Infrastructure
boot.py / main.py — VCP+MSC USB mode for REPL access, GUI skipped in HIL mode.
test_gp_flow.py — 9-test hardware test suite covering: SCP02 session, GET STATUS (4 element types), AID lookup, INSTALL FOR LOAD, chunked LOAD (831 bytes in 4 blocks, ~7.8s), INSTALL FOR INSTALL, verify installation, DELETE, verify deletion.
- DGP (deployed CAP) files uploaded to
/flash/gp/ via mpremote cp — avoids MemoryError from freezing large CAP files in firmware.
How we verified it
Every APDU format was validated against a GlobalPlatformPro hardware trace captured from the exact same JCOP4 card:
- SCP02 session — Session key derivation, card/host cryptogram computation, and MAC wrapping all match GPPro output byte-for-byte.
- INSTALL FOR LOAD — Data field format (
pkg_aid | sd_aid | 0x00 0x00 0x00) and P1=0x02 match GPPro.
- LOAD blocks — C4 header encoding, block sizes (247/247/247/94 for 831 bytes), P1/P2 sequence values all match.
- INSTALL FOR INSTALL — Data field format with split privileges/install_params fields matches GPPro.
- DGP extraction — CAP ZIP decomposed into 9 component files (excluding Descriptor.cap), concatenated in GPPro's order. All components verified byte-identical.
What this means for the project
This is the foundation for managing installed applets from within the Specter-DIY firmware itself, rather than requiring a separate PC with Java/GPPro. The implications:
- SeedKeeper provisioning — The full GP install flow can run on-device. Users can install the SeedKeeper applet directly from the Specter-DIY menu, without needing a PC with GlobalPlatformPro.
- Applet management UI — List, install, and delete applets through the device's touchscreen interface.
- Self-contained security — No need to expose card keys to a PC. The SCP02 session and all key material stay on the STM32.
- Multiple card support — The GP stack is card-agnostic (profile-driven), so it can support other JavaCard types beyond JCOP4.
Current status
| Component |
Status |
Notes |
| Pure Python DES/3DES |
Done |
Verified against pycryptodome |
| SCP02 secure channel |
Done |
Verified against GPPro trace |
| GET STATUS / Registry |
Done |
E3 + JCOP4 compact format |
| INSTALL FOR LOAD |
Done |
Byte-exact match with GPPro |
| Chunked LOAD |
Done |
247-byte blocks, ~7.8s for 831B |
| INSTALL FOR INSTALL |
Done |
Byte-exact match with GPPro |
| DELETE |
Done |
Cascading delete (P2=0x80) |
| Hardware test suite |
Done |
19/19 passing |
| HIL commands |
Done |
gp_init, gp_status, gp_delete, gp_install, gp_probe, gp_verify |
| GUI provisioning screens |
Done (M6) |
Progress + details screens exist |
| MicroPython compat |
Done |
No bytes.fromhex(), no time.sleep() |
Branch: gp-repl-tests (branched from applet-manager, which branched from seedkeeper)
Roadmap
Phase 1 — Merge and integrate (next)
Phase 2 — On-device SeedKeeper provisioning
Phase 3 — SCP02 performance optimization
Phase 4 — Advanced features
Phase 5 — Integration with Specter-DIY workflows
Test results
==================================================
GP Card Management Hardware Test
==================================================
--- Test 1: SCP02 Session ---
[PASS] Card present ATR: 3bd518ff8191fe1fc38073c821100a
[PASS] SCP02 session
--- Test 2: GET STATUS ---
[PASS] GET STATUS parsed
[PASS] ISD lifecycle LC=07
[PASS] ISD privileges 9e
[PASS] Apps found 1 entries
[PASS] Load files found 1 entries
[PASS] Packages found 1 entries
--- Test 3: AID Lookup ---
[PASS] SatoChip found
[PASS] MemoryCard absent
[PASS] TeapotApplet pre-check installed=False
--- Test 4: INSTALL FOR LOAD ---
[PASS] INSTALL for load
--- Test 5: LOAD CAP ---
[PASS] CAP file loaded 831 bytes from /flash/gp/TeapotApplet.dgp
[PASS] LOAD CAP 831 bytes in 4 blocks, 7829 ms
--- Test 6: INSTALL FOR INSTALL ---
[PASS] INSTALL for install
--- Test 7: Verify Installation ---
[PASS] TeapotApplet installed
--- Test 8: DELETE ---
[PASS] DELETE instance SW=9000
[PASS] DELETE package SW=9000
--- Test 9: Verify Deletion ---
[PASS] TeapotApplet removed
==================================================
Results: 19/19 passed, 0 failed
ALL TESTS PASSED
==================================================
Summary
We've implemented and hardware-verified a full GlobalPlatform (GP) card management stack that runs entirely on the Specter-DIY STM32F469 firmware. This enables the device to manage installed JavaCard applets directly — no PC-based tools like GlobalPlatformPro required.
All 19/19 hardware tests pass on a real JCOP4 card, covering the complete applet lifecycle: install, verify, and delete.
What we built
Pure Python SCP02 Secure Channel
des3.py— Full DES/3DES implementation (FIPS 46-3) in pure Python, since MicroPython on STM32F469 has no DES/3DES hardware support (only AES viaucryptolib). Verified against pycryptodome on desktop.scp02.py— SCP02 session management: INITIALIZE UPDATE, EXTERNAL AUTHENTICATE, session key derivation, and C-MAC wrapping. Verified byte-for-byte against a GlobalPlatformPro hardware trace captured from the same JCOP4 card.GP Card Management Operations
registry.py— GET STATUS with auto-detection of both standard E3-tagged TLV responses and JCOP4's proprietary compact format. Finds applets by both top-level AID and module AIDs.loader.py— INSTALL FOR LOAD, chunked LOAD, and INSTALL FOR INSTALL, all aligned byte-for-byte with GPPro trace output. LOAD uses 247-byte blocks (255 Lc minus 8-byte MAC).deleter.py— DELETE with P2=0x80 for cascading deletion of related objects.profiles.py— JCOP4 profile with GP default keys (404142...4F) and SCP02 configuration.REPL Development & Testing Infrastructure
boot.py/main.py— VCP+MSC USB mode for REPL access, GUI skipped in HIL mode.test_gp_flow.py— 9-test hardware test suite covering: SCP02 session, GET STATUS (4 element types), AID lookup, INSTALL FOR LOAD, chunked LOAD (831 bytes in 4 blocks, ~7.8s), INSTALL FOR INSTALL, verify installation, DELETE, verify deletion./flash/gp/viampremote cp— avoids MemoryError from freezing large CAP files in firmware.How we verified it
Every APDU format was validated against a GlobalPlatformPro hardware trace captured from the exact same JCOP4 card:
pkg_aid | sd_aid | 0x00 0x00 0x00) and P1=0x02 match GPPro.What this means for the project
This is the foundation for managing installed applets from within the Specter-DIY firmware itself, rather than requiring a separate PC with Java/GPPro. The implications:
Current status
bytes.fromhex(), notime.sleep()Branch:
gp-repl-tests(branched fromapplet-manager, which branched fromseedkeeper)Roadmap
Phase 1 — Merge and integrate (next)
gp-repl-testsintoapplet-manageror a unified branchboot.py/main.pychanges (keep GUI, add REPL as opt-in)teapot_cap.py(MemoryError when frozen, not needed for production)specter.pyprovisioning flow to usescp02instead ofscp03importsPhase 2 — On-device SeedKeeper provisioning
Phase 3 — SCP02 performance optimization
Phase 4 — Advanced features
/flash/gp/)Phase 5 — Integration with Specter-DIY workflows
Test results