Cardano app communicates with APDU protocol (a decent overview of APDU protocol can be found here). Each "logical" call consists of a series of APDU exchanges where APDU is in the following form
field | CLA | INS | P1 | P2 | Lc | Data | Le |
---|---|---|---|---|---|---|---|
size (B) | 1 | 1 | 1 | 1 | 1 | variable | 0 |
Where
CLA=0xD7
is APDU class number. As we do not adhere to the strict APDU protocol, we have somehow arbitrarily chosen a value belonging to "proprietary structure and coding of command/response" CLA rangeINS
is the instruction numberP1
andP2
are instruction parametersLc
is length of the data body encoded asuint8
. Note: unlike standard APDU,ledger.js
producesLc
of exactly 1 byte (even for empty data). Data of length >= 256 are not supported- Data is binary data
Le
is max length of response. This APDU field is not present inledger.js
protocol
Ledger responsibilities
Upon receiving general APDU, Ledger must check
rx
size >= 5 (i.e., the request has all required APDU fields)CLA
is valid CLA of the Ledger Cardano AppINS
is known and enabled instruction. (Note: development version of the Ledger App might provide some testing/debugging instructions. Such version however must visibly display "devel" status to the user.)Lc
is consistent withrx
, i.e.Lc + 5 == rx
INS
is not changed in the middle of multi-APDU exchange. (Note: This is a security measure. Ledger Apps need to conserve RAM memory and thus might reuse the same memory regions for different INS calls. We must prevent attack vectors where changing calls might lead to state confusion.)
Generally the response from the app looks like this:
field | response data | SW1 | SW2 |
---|---|---|---|
size (B) | variable | 1 | 1 |
where SW1 SW2
represents the return code.
Known error codes are:
- 0x9000 = OK
- see src/errors.h for the full listing of other errors
Instructions are split into several groups depending on their purpose. See src/handlers.c for full listing
Instructions related to general app status
0x00
: Get app version0x01
: Get device serial number
Instructions related to public keys/addresses/scripts
0x10
Get extended public keys0x11
Derive address0x12
Derive native script hash
Instructions related to signing (transactions etc.)
0x21
Sign Transaction0x22
Sign operational certificate
Instructions related to debug mode of the app. These instructions must not be available on the production build of the app
0xF0
Run unit tests
In order to ensure safe forward compatibility, sender must set any unused field to zero. When upgrading protocol, any unused field that is no longer unused must define only values != 0. This will ensure that clients using old protocol will receive errors instead of an unexpected behavior.
❓(VL,IOHK): Do we want to force clients to check app version (mis)match, e.g. by having an explicit handshake? A custom (non ledgerjs
-based) client app might omit version checks which might lead to potential problems