20 KiB
Status Keycard Application
Version
Version numbers are in the form major.minor. An major revision increment indicates the presence of breaking changes as compared to the previous released version. This is version 2.0 of the specs (unreleased).
Changes since 1.2
- BREAKING Completely redefined the EXPORT KEY command
- BREAKING Removed assisted key derivation
- BREAKING Removed plain data signing, now only 32-byte long hashes can be signed
- Added internal key generation (GENERATE KEY)
- Added the ability to customize the NDEF response (SET NDEF)
- Added DUPLICATE KEY command
Overview
This application allows signing of transactions using ECDSA with a keyset stored on card. The keys are defined on the SECP256k1 curve. Signing is available only after PIN authentication.
The keyset used for signing is generated externally and loaded on card. This is also only available after PIN authentication.
Before any application command is processed, a Secure Channel session must be established as specified in the SECURE_CHANNEL.MD document.
INITIALIZATION
After installation, the applet is not ready to operate and is in a pre-initializaed state. In this state the applet can only process the SELECT and INIT command. The INIT command is used to personalize the PIN, PUK and pairing secret, which must be generated off-card.
PIN
The PIN length is fixed at 6 digits. After 3 failed authentication attempts the PIN is blocked and authentication is not possible anymore. A blocked PIN can be replaced and unblocked using a PUK. The PUK is a 12-digit number. After 5 failed attempts to unblock the applet using the PUK, the PUK is blocked, meaning the wallet is lost.
After authentication, the user remains authenticated until the application is either deselected or the card is reset. Authentication with PIN is a requirement for most commands to succeed.
The PIN and PUK can be changed by the user after authentication.
Keys & Signature
The application allows loading and replacing of a single EC keyset, defined on the SECP256k1 curve. The keyset can contain a 32-byte chain code to further derive keys according to the BIP32 specifications. This keyset is used to sign transactions. When the applet is first installed, no keyset is available so signing will fail. It is necessary to first load the keyset in order for the application to be fully operational.
Signing of transactions is done by uploading the data in blocks no larger than 255 bytes (including the overhead caused by the Secure Channel). Segmentation must be handled at the application protocol. Another option is to sign the hash of the transaction, with the hash being calculated off-card. Signing generally requires the PIN to be authenticated, however the user can set a special key path which requires no authentication.
APDUs
These are the commands supported by the application. When a command has a precondition clause and these are not met the SW 0x6985 is returned. All tagged data structures are encoded in the BER-TLV format
SELECT
- CLA = 0x00
- INS = 0xA4
- P1 = 0x04
- P2 = 0x00
- Data = 53746174757357616C6C6574417070 (hex)
- Response = Application Info Template or ECC public key.
Response Data format:
- Tag 0xA4 = Application Info Template
- Tag 0x8F = Instance UID (16 bytes)
- Tag 0x80 = ECC public Key
- Tag 0x02 = Application Version (2 bytes)
- Tag 0x02 = Number of remaining pairing slots (1 byte)
- Tag 0x8E = Key UID (0 or 32 bytes)
The SELECT command is documented in the ISO 7816-4 specifications and is used to select the application on the card, making it the active one. The data field is the AID of the application. The response is the Application Info template which contains the instance UID (which can be used by the client to keep track of multiple cards) and the public key which must be used by the client to establish the Secure Channel. Additionally it contains the version number of the application, formatted on two bytes. The first byte is the major version and the second is the minor version (e.g: version 1.1 is formatted as 0x0101). The number of remaining pairing slots is also included in the response.
The Key UID can be either empty (when no key is loaded on card) or the SHA-256 hash of the master public key.
When the applet is in pre-initializated state, it only returns the ECC public key, BER-TLV encoded with tag 0x80.
INIT
- CLA = 0x80
- INS = 0xFE
- P1 = 0x00
- P2 = 0x00
- Data = EC public key (LV encoded) | IV | encrypted payload
- Response SW = 0x9000 on success, 0x6D00 if the applet is already initialized, 0x6A80 if the data is invalid
This command is only available when the applet is in pre-initialized state and successful execution brings the applet in the initialized state. This command is needed to allow securely storing secrets on the applet at a different moment and place than installation is taking place. Currently these are the PIN, PUK and pairing password.
The client must take the public key received after the SELECT command, generate a random keypair and perform EC-DH to generate an AES key. It must then generate a random IV and encrypt the payload using AES-CBC with ISO/IEC 9797-1 Method 2 padding.
They payload is the concatenation of the PIN (6 digits/bytes), PUK (12 digits/bytes) and pairing secret (32 bytes).
This scheme guarantees protection against passive MITM attacks. Since the applet has no "owner" before the execution of this command, protection against active MITM cannot be provided at this stage. However since the communication happens locally (either through NFC or contacted interface) the realization of such an attack at this point is unrealistic.
After successful execution, this command cannot be executed anymore. The regular SecureChannel (with pairing) is active and PIN and PUK are initialized.
OPEN SECURE CHANNEL
The OPEN SECURE CHANNEL command is as specified in the SECURE_CHANNEL.MD.
MUTUALLY AUTHENTICATE
The MUTUALLY AUTHENTICATE command is as specified in the SECURE_CHANNEL.MD.
PAIR
The PAIR command is as specified in the SECURE_CHANNEL.MD. The shared secret is 32 bytes long. The way the secret is generated is not within the scope of this document because the applet accepts the already generated secret as an installation parameter. However the card issuer and clients must agree on the way it is generated for interoperability reasons.
If the code is meant to be input manually, a random, variable length alphanumeric password to be used in conjuction with an algorithm such as scrypt or PBKDF2 is suggested. If another input mechanism is foreseen (such as QR-code scanning), then the sequence should be composed of random bytes from a secure source of randomness.
UNPAIR
The UNPAIR command is as specified in the SECURE_CHANNEL.MD. The user PIN must be verified for the command to work.
GET STATUS
- CLA = 0x80
- INS = 0xF2
- P1 = 0x00 for application status, 0x01 for key path status
- P2 = 0x00
- Response SW = 0x9000 on success, 0x6A86 on undefined P1
- Response Data = Application Status Template or Key Path
- Preconditions: Secure Channel must be opened
Response Data format: if P1 = 0x00:
- Tag 0xA3 = Application Status Template
- Tag 0x02 = PIN retry count (1 byte)
- Tag 0x02 = PUK retry count (1 byte)
- Tag 0x01 = 0xff if key is initialized, 0 otherwise
if P1 = 0x01
- a sequence of 32-bit numbers indicating the current key path. Empty if master key is selected.
SET NDEF
- CLA = 0x80
- INS = 0xF3
- P1 = 0x00
- P2 = 0x00
- Data = the data to store
- Response SW = 0x9000 on success, 0x6A80 on invalid data
- Preconditions: Secure Channel must be opened, PIN must be verified
Used to set the content of the data file owned by the NDEF applet. This allows changing the behavior of Android and other clients when tapping the card with no open client. As an example, it could be used to launch a specific wallet software.
The data is stored as is. A check is made that the first 2 bytes, read as a MSB first short, are equal to the Lc field minus 2 (the length of the field itself). This does not ensure that the NDEF record is valid, but ensures that no out of bound access happens.
VERIFY PIN
- CLA = 0x80
- INS = 0x20
- P1 = 0x00
- P2 = 0x00
- Data = the PIN to be verified
- Response SW = 0x9000 on success, 0x63CX on failure, where X is the number of attempt remaining
- Preconditions: Secure Channel must be opened
Used to verify the user PIN. On correct PIN entry the card returns 0x9000, the retry counter is reset and the PIN is marked as authenticated for the entire session (until the application is deselected or the card reset/teared). On error, the number of remaining retries is decreased and the SW 0x63CX, where X is the number of available retries is returned. When the number of remaining retries reaches 0 the PIN is blocked. When the PIN is blocked this command always returns 0x63C0, even if the PIN is inserted correctly.
CHANGE PIN
- CLA = 0x80
- INS = 0x21
- P1 = PIN identifier
- P2 = 0x00
- Data = the new PIN
- Response SW = 0x9000 on success, 0x6A80 if the PIN format is invalid, 0x6A86 if P1 is invalid
- Preconditions: Secure Channel must be opened, user PIN must be verified
Used to change a PIN or secret. In case of invalid format, the code 0x6A80 is returned. If the conditions match, the PIN or secret is updated. The no-error SW 0x9000 is returned.
P1:
- 0x00: User PIN. Must be 6-digits. The updated PIN is authenticated for the rest of the session.
- 0x01: Applet PUK. Must be 12-digits.
- 0x02: Pairing secret. Must be 32-bytes long. Existing pairings are not broken, but new pairings will need to use the new secret.
UNBLOCK PIN
- CLA = 0x80
- INS = 0x22
- P1 = 0x00
- P2 = 0x00
- Data = the PUK followed by the new PIN
- Response SW = 0x9000 on success, 0x6A80 if the format is invalid
- Preconditions: Secure Channel must be opened, user PIN must be blocked
Used to unblock the user PIN. The data field must contain exactly 18 numeric digits, otherwise SW 0x6A80 is returned. The first 12 digits are the PUK and the last 6 are the new PIN. If the PUK is correct the PIN is changed to the supplied one, it is unblocked and authenticated for the rest of the session. The status code 0x9000 is returned. When the PUK is wrong, the number of remaining retries is decreased and the SW 0x63CX, where X is the number of available retries is returned. When the number of remaining retries reaches 0 the PUK is blocked. When the PUK is blocked this command always returns 0x63C0, even if the PUK is inserted correctly. In this case the wallet is effectively lost.
LOAD KEY
- CLA = 0x80
- INS = 0xD0
- P1 = key type
- P2 = 0x00
- Data = the key data
- Response SW = 0x9000 on success, 0x6A80 if the format is invalid, 0x6A86 if P1 is invalid
- Response Data = the key UID, defined as the SHA-256 of the public key
- Preconditions: Secure Channel must be opened, user PIN must be verified
P1:
- 0x01 = ECC SECP256k1 keypair
- 0x02 = ECC SECP256k1 extended keypair
- 0x03 = Binary seed as defined in BIP39
Data:
If P1 is 0x01 or 0x02
- Tag 0xA1 = keypair template
- Tag 0x80 = ECC public key component (can be omitted)
- Tag 0x81 = ECC private key component
- Tag 0x82 = chain code (if P1=0x02)
If P1 is 0x03 a 64 byte sequence generated according to the BIP39 specifications is expected. The master key will be generated according to the BIP32 specifications. This is only supported if the hardware supports public key derivation.
This command is used to load or replace the keypair used for signing on the card. This command always aborts open signing sessions, if any. Unless a DERIVE KEY is sent, a subsequent SIGN command will use this keypair for signature.
DERIVE KEY
- CLA = 0x80
- INS = 0xD1
- P1 = derivation options
- P2 = 0x00
- Data = a sequence of 32-bit integers (most significant byte first). Empty if the master key must be used.
- Response SW = 0x9000 on success, 0x6A80 if the format is invalid, 0x6984 if one of the components in the path generates an invalid key, 0x6B00 if derivation from parent keys is selected but no valid parent key is cached.
- Preconditions: Secure Channel must be opened, user PIN must be verified (if no PIN-less key is defined), an extended keyset must be loaded
This command is used before a signing session to generate a private key according to the BIP32 specifications. This command always aborts open signing sessions, if any. The generated key is used for all subsequent SIGN sessions. The maximum depth of derivation from the master key is 10. Any attempt to get deeper results in 0x6A80 being returned. The BIP32 specifications define a few checks which must be performed on the derived keys. If these fail, the 0x6984 is returned and the invalid key is discarded. A client should perform a GET STATUS command to get the actual current key path and resume derivation using a different path.
The ability to start derivation from the parent keys allows to more efficiently switch between children of the same key. Note however that only the immediate parent of the current key is cached so you cannot use this to go back in the hierarchy. If no valid parent key is available the status code 0x6B00 will be returned.
P1:
- bit 0-5 = reserved
- bit 7-6:
- 00 derive from master keys
- 01 derive from parent keys
- 10 derive from current keys
- 11 reserved
GENERATE MNEMONIC
- CLA = 0x80
- INS = 0xD2
- P1 = checksum size (between 4 and 8)
- P2 = 0x00
- Response SW = 0x9000 on success. 0x6A86 if P1 is invalid.
- Response Data = a sequence of 16-bit integers (most significant byte first).
- Preconditions: Secure Channel must be opened
Used to generate a mnemonic according to the algorithm specified in BIP39. The returned data is a list of 16-byte integers which should be used as indexes in a wordlist to generate the human-readable mnemonic. Each integer can have a value from 0 to 2047.
REMOVE KEY
- CLA = 0x80
- INS = 0xD3
- P1 = 0x00
- P2 = 0x00
- Response SW = 0x9000 on success.
- Preconditions: Secure Channel must be opened, user PIN must be verified
Removes the key from the card, bringing it back to an uninitialized state. No signing operation is possible after this command until a new LOAD KEY command is performed.
GENERATE KEY
- CLA = 0x80
- INS = 0xD4
- P1 = 0x00
- P2 = 0x00
- Response SW = 0x9000 on success.
- Response Data = the key UID, defined as the SHA-256 of the public key
- Preconditions: Secure Channel must be opened, user PIN must be verified
Generates and stores keys completely on card. The state of the card after execution is the same as if a LOAD KEY command had been performed.
DUPLICATE KEY
- CLA = 0x80
- INS = 0xD5
- P1 = subcommand
- P2 = depends on subcommand
- Data = depends on phase
- Response SW = 0x9000 on success.
- Response Data = depends on subcommand
- Preconditions: depends on subcommand
P1:
- 0x00: START DUPLICATE
- 0x01: ADD ENTROPY
- 0x02: EXPORT DUPLICATE
- 0x03: IMPORT DUPLICATE
START DUPLICATE
This is the first step to start duplication. Requires an open secure channel and user PIN must be verified. Aborts any on-going duplication session. P2 is the number of entropy pieces to expect in total (including this command). The data contain the first piece of entropy. Returns no data. Must be performed with exactly the same parameters and data on all cards taking part in the duplication.
ADD ENTROPY
This command uses the same one-shot secure channel scheme as defined in the INIT command. P2 is 00. Requires an ongoing duplicate session started with the START DUPLICATE subcommand. Must be performed once per device taking part in the duplication process, for a total number of devices equaling the P2 parameter of the START DUPLICATE subcommand (counting the device which sent the START DUPLICATE command as the first device). The data is a random 256-bit number. The same data must be sent to all the cards taking part in the duplication process.
EXPORT DUPLICATE
This command must be sent to the card which you wish to duplicate. Requires an open secure channel and authenticated PIN. Works only if a duplication session is active and ADD ENTROPY has been performed the required number of times. Returns the encrypted duplicate of the master key and terminates the duplication session for this card. The format is exactly the same as the one defined in the LOAD KEY (TLV) command with omitted public key. It is however prepended by a 16-bytes IV and the entire TLV structure is encrypted.
IMPORT DUPLICATE
This command must be sent to all the cards which are a target for duplication. The Data field must contain the output from the EXPORT DUPLICATE command performed on the source card. Returns the key UID. It follows exactly the same rules as the EXPORT DUPLICATE subcommand.
SIGN
- CLA = 0x80
- INS = 0xC0
- P1 = 0x00
- P2 = 0x00
- Data = the hash to sign
- Response = public key and the signature
- Response SW = 0x9000 on success, 0x6A80 if the data is not 32-byte long
- Preconditions: Secure Channel must be opened, user PIN must be verified (or a PIN-less key must be active), a valid keypair must be loaded
Response Data format:
- Tag 0xA0 = signature template
- Tag 0x80 = ECC public key component
- Tag 0x30 = ECDSA Signature
- Tag 0x02 = R value
- Tag 0x02 = S value
Returns the ECDSA signature of the hash. The hash can be calculated using any algorithm, but must be 32-bytes long. The signature is returned in a signature template, containing the public key associated to the signature and the signature itself. For usage on the blockchain, you will need to calculate the recovery ID in addition to extracting R and S. To calculate the recovery ID you need to apply the same algorithm used for public key recovery from a transaction starting with a recovery ID of 0. If the public key matches the one returned in the template, then you have found the recovery ID, otherwise you try again by incrementing the recovery ID.
SET PINLESS PATH
- CLA = 0x80
- INS = 0xC1
- P1 = 0x00
- P2 = 0x00
- Data = a sequence of 32-bit integers
- Response SW = 0x9000 on success, 0x6A80 if data is invalid
- Preconditions: Secure Channel must be opened, user PIN must be verified
Sets the given sequence of 32-bit integers as a PIN-less path. When the current derived key matches this path, SIGN will work even if no PIN authentication has been performed. An empty sequence means that no PIN-less path is defined.
EXPORT KEY
- CLA = 0x80
- INS = 0xC2
- P1 = derivation options
- P2 = export options
- Response SW = 0x9000 on success, 0x6A86 if P1 or P2 are wrong
- Data = a sequence of 32-bit integers (empty if P1=0x00)
- Response Data = key pair template
- Response SW = 0x9000 on success, 0x6985 if the private key cannot be exported, 0x6A80 if the path is malformed
- Preconditions: Secure Channel must be opened, user PIN must be verified
P1: 0x00 = Current key 0x01 = Derive 0x02 = Derive and make current
P2: 0x00 = private and public key 0x01 = public key only
Response Data format:
- Tag 0xA1 = keypair template
- Tag 0x80 = ECC public key component (could be omitted)
- Tag 0x81 = ECC private key component (if P2=0x00)
This command exports the requested public and private key. The public key can be always exported (P2=0x01), but the private key (P2=0x00) can be exported if and only if the requested key path is in the EIP-1581 subtree.
The P1 parameter indicates how to the derive the desired key. P1 = 0x00 indicates that the current key must be exported, and no derivation will be performed. P1 = 0x01 derives the path given in the data field without changing the current path of the card. P1 = 0x02 derives the path but also changes the current path of the card. The source for derivation can be set by OR'ing P1 with the constants defined in the DERIVE KEY command. This allows deriving from master, parent or current.
If the private key is being exported, the card could omit exporting the public key for performance reason. The public key can then be calculate off-card if needed.