Applet 4.0 is the largest protocol revision since 2.0. Cards cannot be upgraded from 3.x to 4.0 — the applet is locked on shipped cards — so both versions will be in the field indefinitely and clients should support both. This page is the migration checklist; each command page documents its own version differences.
The applet version is the 0x02 field of the SELECT response. Version 4.0 is 0x0400. Branch on it before doing anything else:
if (appVersion >= 0x0400) use SecureChannel v2 (certificate based)
else use SecureChannel v1 (pairing based)
Everything else follows from that choice.
| 3.x | 4.0 | |
|---|---|---|
| Channel establishment | PAIR → OPEN SECURE CHANNEL → MUTUALLY AUTHENTICATE | OPEN SECURE CHANNEL only |
| Card authentication | pairing cryptograms | factory certificate + transcript signature |
| Client state to persist | pairing secret, per card | nothing |
| Credentials at INIT | PIN, PUK, pairing password | PIN, PUK |
| Command transport | only the data field encrypted, per-command INS | whole APDU encrypted, wrapped in SECURED APDU |
| Card identity check | IDENT command | certificate in the SELECT response |
| Current key path | set by DERIVE KEY, read with GET STATUS | no such state; every command carries its path |
| Pinless signing | SET PINLESS PATH | removed |
| SELECT response | Instance UID, channel public key, pairing slots | status byte, identity certificate |
| Unsigned commands | SELECT, OPEN SC, FACTORY RESET, GET DATA, pinless SIGN | SELECT, OPEN SC, FACTORY RESET |
| Platform | JavaCard 3.0.4+ | JavaCard 3.0.5 + keycard-math package |
Drop pairing entirely for 4.0 cards. There is no pairing password, no pairing index, no pairing slot to store or clean up.
Verify the certificate instead. Read the 98-byte certificate from the SELECT response, recover the CA public key from its r/s/v fields and check it against your anchors — see Card identity.
Always pass a path. There is no card state to remember, which removes an entire category of "signed with the wrong key" bugs. A path of zero length means the master key.
Expect everything to need a secure channel. Notably GET DATA used to work without one. Only SELECT, the handshake and factory reset are still exempt.
Re-key local storage if you used the Instance UID. It is gone. The Key UID identifies the wallet; the certificate public key identifies the card across reinstalls.
P2 = 0x03, BIP-340/BIP-341 compatible, with optional key tweaking. Enough for Bitcoin Taproot key-path spends.IDENT for 3.x.