DevelopersKeycard API
OPEN SECURE CHANNEL
23 Sept 2026

  • CLA = 0x80
  • INS = 0x10
  • P1 = 0x00
  • P2 = 0x00
  • Data = a 256-bit HKDF salt followed by a 256-bit client ephemeral public key on the secp256k1 curve, encoded as an uncompressed point (65 bytes)
  • Response Data = the card ephemeral public key (65 bytes) followed by an ECDSA signature over the handshake transcript
  • Response SW = 0x9000 on success, 0x6A80 if the data is malformed, 0x6985 if the card identity is not provisioned
  • Capability: Secure Channel

This APDU is the first step of the SecureChannel v2 handshake, introduced in 4.0. The protocol needs no pairing: the card proves its identity with its factory identity certificate, so a client can connect to a card it has never seen before. A session is aborted when the application is deselected, either directly or because of a card reset/tear.

The client generates an ephemeral secp256k1 key pair and a random 256-bit HKDF salt, and sends salt || client_eph_pub. The card then:

  1. 1
    Generates its own ephemeral key pair.
  2. 2
    Computes shared_X, the X coordinate of the ECDH shared secret between the two ephemeral keys.
  3. 3
    Derives the session keys with HKDF-SHA256:
    PRK       = HMAC-SHA256(salt, shared_X)
    OKM       = HKDF-Expand(PRK, "sc_v2_ccm", 32)
    key_h2c   = OKM[0..15]
    key_c2h   = OKM[16..31]
    
    The two directions use independent keys. key_h2c encrypts host-to-card traffic, key_c2h card-to-host traffic.
  4. 4
    Signs the transcript "sc_v2_ccm" || salt || client_eph_pub || card_eph_pub with its authentikey.
  5. 5
    Responds with card_eph_pub || signature.

The client verifies that signature using the public key from the certificate received in the SELECT response. Because the transcript includes the client's own ephemeral key, an active attacker substituting it is detected. This is the same construction as TLS 1.3's Finished messages.

After a successful OPEN SECURE CHANNEL command, every command is sent with the SECURED APDU instruction (INS 0x18) and every response is encrypted. Unlike SecureChannel v1, the entire inner APDUCLA, INS, P1, P2, LC and data — is encrypted, not just the data field. Nothing useful about the command is visible on the wire apart from the wrapper header and the payload length.

Payloads are protected with AES-128-CCM (8-byte authentication tag). The nonce is a 13-byte counter starting at zero for the session and incremented after every card response. No nonce bytes are transmitted: request and reply of a round trip share the same counter value, which is safe because the two directions use different keys. A counter overflow (2^104 round trips) tears the session down.

Because responses can only carry data when the ISO status word indicates success, all responses over an open secure channel have SW 0x9000. The real status word is the last two bytes of the decrypted response payload and must be interpreted by the client. The only status word returned in the clear is 0x6982, which signals a secure channel failure — the session is then reset and the handshake must be repeated.

The maximum plaintext for a command is 247 bytes and for a response 245 bytes.

  1. 1
    If a command other than OPEN SECURE CHANNEL, SECURED APDU or FACTORY RESET is sent without an open secure channel, the card responds with SW 0x6985 (SW_CONDITIONS_NOT_SATISFIED)
  2. 2
    If a CCM tag cannot be verified the card responds 0x6982 and the secure channel must be closed and re-opened

caution
Everything in this section applies to applet versions below 4.0 only. Those cards cannot be upgraded and are still common, so clients integrating directly with the protocol must implement both variants and choose based on the applet version reported by SELECT.

Version 1 relied on a shared secret established out of band by PAIR and required an explicit MUTUALLY AUTHENTICATE step. Its OPEN SECURE CHANNEL command has the same CLA/INS but a completely different shape:

  • P1 = the pairing index, P2 = 0x00
  • Data = a 256-bit client public key on secp256k1, uncompressed
  • Response = a 256-bit salt followed by a 128-bit seed IV

Key derivation worked as follows:

  1. 1
    Both parties run EC-DH with their private key and the counterpart public key.
  2. 2
    The shared secret, the pairing key and the salt are concatenated and hashed with SHA-512.
  3. 3
    The 64-byte digest is split in two 256-bit halves: the encryption key and the MAC key.

Only the data field of a C-APDU was encrypted, so CLA, INS, P1 and P2 travelled in clear and were covered by the MAC instead. Data was padded with ISO/IEC 9797-1 Method 2, encrypted with AES-CBC, and a AES-CBC-MAC was calculated over the whole APDU and prepended to the data field. The IV for each message was the previous MAC from the counterpart, which both chained the messages and prevented replays. Because AES-CBC requires 16-byte multiples, the effective maximum payload was 223 bytes.

Last edited
23 Sept 2026