From 603290156b0002b9bc18ec4cee08eef712786dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Tue, 27 Feb 2024 13:15:28 +0100 Subject: [PATCH] Doc: update documentation --- APDUs.md | 137 ---------------- doc/NVRAM.md | 37 +++++ doc/apdu.md | 432 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/signing.md | 52 ++++++ 4 files changed, 521 insertions(+), 137 deletions(-) delete mode 100644 APDUs.md create mode 100644 doc/NVRAM.md create mode 100644 doc/apdu.md create mode 100644 doc/signing.md diff --git a/APDUs.md b/APDUs.md deleted file mode 100644 index a2d07d34..00000000 --- a/APDUs.md +++ /dev/null @@ -1,137 +0,0 @@ -# APDU - -An APDU is sent by a client to the ledger hardware. This message tells -the ledger some operation to run. Most APDU messages will be -accompanied by an Accept / Deny prompt on the Ledger. Once the user -hits “Accept” the Ledger will issue a response to the Tezos client. -The basic format of the APDU request follows. - -| Field | Length | Description | -|-------|--------|-------------------------------------------------------------------------| -| CLA | 1 byte | Instruction class (always 0x80) | -| INS | 1 byte | Instruction code (0x00-0x0f) | -| P1 | 1 byte | Message sequence (0x00 = first, 0x81 = last, 0x01 = other) | -| P2 | 1 byte | Derivation type (0=ED25519, 1=SECP256K1, 2=SECP256R1, 3=BIPS32_ED25519) | -| LC | 1 byte | Length of CDATA | -| CDATA | | Payload containing instruction arguments | - -Each APDU has a header of 5 bytes followed by some data. The format of -the data will depend on which instruction is being used. - -## Example - -Here is an example of an APDU message from the ledger-app-tezos tests: - -> 0x8001000011048000002c800006c18000000080000000 - -This parses as: - -| Field | Value | -|-------|--------------------------------------| -| CLA | 0x80 | -| INS | 0x01 | -| P1 | 0x00 | -| P2 | 0x00 | -| LC | 0x11 (17) | -| CDATA | 0x048000002c800006c18000000080000000 | - -0x01 is the first instruction and is used for "authorize baking". This -APDU tells the ledger to save the choice of curve and derivation path -to memory so that future operations know which of these to use when -baking. Note that this instruction is only recognized by the baking -app, and not the wallet app. - -A list of more instructions follows. - -## APDU instructions in use by Tezos Ledger apps - -| Instruction | Code | App | Prompt | Short description | -|---------------------------------|------|-----|--------|--------------------------------------------------| -| `INS_VERSION` | 0x00 | WB | No | Get version information for the ledger | -| `INS_AUTHORIZE_BAKING` | 0x01 | B | Yes | Authorize baking | -| `INS_GET_PUBLIC_KEY` | 0x02 | WB | No | Get the ledger’s internal public key | -| `INS_PROMPT_PUBLIC_KEY` | 0x03 | WB | Yes | Prompt for the ledger’s internal public key | -| `INS_SIGN` | 0x04 | WB | Yes | Sign a message with the ledger’s key | -| `INS_SIGN_UNSAFE` | 0x05 | W | Yes | Sign a message with the ledger’s key (no hash) | -| `INS_RESET` | 0x06 | B | Yes | Reset high water mark block level | -| `INS_QUERY_AUTH_KEY` | 0x07 | B | No | Get auth key | -| `INS_QUERY_MAIN_HWM` | 0x08 | B | No | Get current high water mark | -| `INS_GIT` | 0x09 | WB | No | Get the commit hash | -| `INS_SETUP` | 0x0a | B | Yes | Setup a baking address | -| `INS_QUERY_ALL_HWM` | 0x0b | B | No | Get all high water mark information | -| `INS_DEAUTHORIZE` | 0x0c | B | No | Deauthorize baking | -| `INS_QUERY_AUTH_KEY_WITH_CURVE` | 0x0d | B | No | Get auth key and curve | -| `INS_HMAC` | 0x0e | B | No | Get the HMAC of a message | -| `INS_SIGN_WITH_HASH` | 0x0f | WB | Yes | Sign a message with the ledger’s key (with hash) | - -- B = Baking app, W = Wallet app - -## Signing operations - -There are 3 APDUs that deal with signing things. They use the Ledger’s -private key to sign messages sent. They are: - -| Instruction | Code | App | Parsing | Send hash | -|----------------------|------|-----|---------|-----------| -| `INS_SIGN` | 0x04 | WB | Yes | No | -| `INS_SIGN_UNSAFE` | 0x05 | W | No | No | -| `INS_SIGN_WITH_HASH` | 0x0f | WB | Yes | Yes | - -The main difference between `INS_SIGN` and `INS_SIGN_UNSAFE` is that -`INS_SIGN_UNSAFE` skips the parsing step which shows what operation is -included in the APDU data. This is unsafe, because the user doesn’t -see what operation they are actually signing. When this happens, we -tell the user “Unrecognized: Sign Hash” so that they can make -appropriate external steps to verify this hash. The difference between -`INS_SIGN` and `INS_SIGN_WITH_HASH` is that the latter returns both the -signature *AND* the hash of the data (while the former only returns the signature). - -### Parsing operations - -Each Tezos block that is received through `INS_SIGN` is parsed and the -results are shown on the Ledger’s display. At many points, this -parsing may fail, and the Tezos app will fall back in this case to -“Unrecognized: Sign Hash” mode. - -Parsing some Tezos blocks are particularly difficult. Contract -“originations” contain Michelson data that could be too big to display -and transactions can contain “parameters” which can be any valid -Michelson data. Currently, only a small subset of parameters are -parsed, and no contract originations can be parsed. - -There is not enough resources on the Ledger Nano S to parse any -arbitrary operation, but we can match to a predefined template. -Currently, the Tezos app matches to templates provided for specific -Manager.tz operations, which are part of the migration to Babylon. In -the Babylon migration, implicit contracts are converted to originated -contracts. We support Babylon to make sure those contracts are still -accessible via Ledger signing. More details on the migration are -available at -[migration_004_to_005.md](https://gitlab.com/cryptiumlabs/tezos/blob/master/specs/migration_004_to_005.md). - -There are four Michelson operations currently supported in the Ledger. -They are: - -- set delegate -- remove delegate -- transfer implicit to contract -- transfer contract to contract - -Each of these comes with its own Michelson sequence, each beginning -with `DROP ; NIL operation` and ending with `CONS`. From there, we -match like this: - -![Michelson manager.tz ops graph](michelson_ops.png) - -#### Manager.tz parsing limitations - -There are some limitations for Michelson parsing that should be noted. - -- Arguments passed to Manager.tz contract must match exactly those - described in the migration document. Any variations will be - rejected. -- All endpoints other than “do” are rejected. -- Amount transferred must be 0. -- “contract-to-contract” requires that you use: - - the default endpoint for your destination contract - - the parameters must be of type unit diff --git a/doc/NVRAM.md b/doc/NVRAM.md new file mode 100644 index 00000000..0b4807aa --- /dev/null +++ b/doc/NVRAM.md @@ -0,0 +1,37 @@ +# NVRAM + +To enable verification, the ledger will retain following data in its Non-volatile memory. It will also modify data after each signing operation. + +Following data is saved to NVRAM: + +## `authorized-key` + +The key only key authorized to sign. + +It can be set, given a path and a curve, using [`AUTHORIZE_BAKING`](apdu.md#authorize_baking) and [`SETUP`](apdu.md#setup). +A manual user validation will be required. +And its public key will be returned. + +It can be unset using [`DEAUTHORIZE`](apdu.md#deauthorize). + +Its path can be retrieved using [`QUERY_AUTH_KEY`](apdu.md#query_auth_key) (and +[`QUERY_AUTH_KEY_WITH_CURVE`](apdu.md#query_auth_key_with_curve) that also gives its curve) + +## `chain-id` + +The main chain id. + +If no chain is registered, all chains encounter will be considered as main. + +It can be set using [`SETUP`](apdu.md#setup) and retrieved using [`QUERY_ALL_HWM`](apdu.md#query_all_hwm). + +## `HWM` + +Two High Water Mark representing: + - the main chain HWM. + - the test chain HWM. + +Each HWM contains informations about the current state of the chain. +It contains the highest level encounter and the highest round encounter for this level. + +The both HWM can be set using [`SETUP`](apdu.md#setup) and retrieved using [`QUERY_ALL_HWM`](apdu.md#query_all_hwm). diff --git a/doc/apdu.md b/doc/apdu.md new file mode 100644 index 00000000..558e8ad8 --- /dev/null +++ b/doc/apdu.md @@ -0,0 +1,432 @@ +# APDU + +An APDU is sent by a client to the ledger hardware. This message tells +the ledger some operation to run. The basic format of the APDU +request follows. + +| Field | Length | Description | +|---------|----------|------------------------------------------------------------------------| +| *CLA* | `1 byte` | Instruction class (always 0x80) | +| *INS* | `1 byte` | Instruction code (0x00-0x0f) | +| *P1* | `1 byte` | Index of the message (0x80 lor index = last index) | +| *P2* | `1 byte` | Derivation type (0=ED25519, 1=SECP256K1, 2=SECP256R1, 3=BIP32_ED25519) | +| *LC* | `1 byte` | Length of *CDATA* | +| *CDATA* | `` | Payload containing instruction arguments | + +Each APDU has a header of 5 bytes followed by some data. The format of +the data will depend on which instruction is being used. + +## Example + +Here is an example of an APDU message: + +> 0x8001000011048000002c800006c18000000080000000 + +This parses as: + +| Field | Value | +|---------|----------------------------------------| +| *CLA* | `0x80` | +| *INS* | `0x01` | +| *P1* | `0x00` | +| *P2* | `0x00` | +| *LC* | `0x11` (17) | +| *CDATA* | `0x048000002c800006c18000000080000000` | + +0x01 is the first instruction and is used for "authorize baking". This +APDU tells the ledger to save the choice of curve and derivation path +to memory so that future operations know which of these to use when +baking. + +## Exceptions + +| Exception | Code | Short description | +|---------------------------------|--------|-------------------------------------------------| +| `EXC_WRONG_PARAM` | 0x6B00 | Wrong parameter(s) *P1*-*P2* | +| `EXC_WRONG_LENGTH` | 0x6C00 | Incorrect length. | +| `EXC_INVALID_INS` | 0x6D00 | Instruction code not supported or invalid. | +| `EXC_WRONG_LENGTH_FOR_INS` | 0x917E | Length of command string invalid. | +| `EXC_REJECT` | 0x6985 | Conditions of use not satisfied. | +| `EXC_PARSE_ERROR` | 0x9405 | Problems in the data field. | +| `EXC_REFERENCED_DATA_NOT_FOUND` | 0x6A88 | Referenced data not found. | +| `EXC_WRONG_VALUES` | 0x6A80 | The parameters in the data field are incorrect. | +| `EXC_SECURITY` | 0x6982 | Security condition not satisfied. | +| `EXC_HID_REQUIRED` | 0x6983 | Authentication method blocked. | +| `EXC_CLASS` | 0x6E00 | Class not supported. | +| `EXC_MEMORY_ERROR` | 0x9200 | Memory error. | + +## Instructions + +| Instruction | Code | Short description | +|------------------------------------------------------------------|------|---------------------------------------------| +| [`VERSION`](apdu.md#version) | 0x00 | Get version information for the ledger | +| [`AUTHORIZE_BAKING`](apdu.md#authorize_baking) | 0x01 | Authorize baking | +| [`GET_PUBLIC_KEY`](apdu.md#get_public_key) | 0x02 | Get the ledger’s internal public key | +| [`PROMPT_PUBLIC_KEY`](apdu.md#prompt_public_key) | 0x03 | Prompt for the ledger’s internal public key | +| [`SIGN`](apdu.md#sign) | 0x04 | Sign a message with the ledger’s key | +| [`RESET`](apdu.md#reset) | 0x06 | Reset high water mark block level | +| [`QUERY_AUTH_KEY`](apdu.md#query_auth_key) | 0x07 | Get auth key | +| [`QUERY_MAIN_HWM`](apdu.md#query_main_hwm) | 0x08 | Get current high water mark | +| [`GIT`](apdu.md#git) | 0x09 | Get the commit hash | +| [`SETUP`](apdu.md#setup) | 0x0a | Setup a baking address | +| [`QUERY_ALL_HWM`](apdu.md#query_all_hwm) | 0x0b | Get all high water mark information | +| [`DEAUTHORIZE`](apdu.md#deauthorize) | 0x0c | Deauthorize baking | +| [`QUERY_AUTH_KEY_WITH_CURVE`](apdu.md#query_auth_key_with_curve) | 0x0d | Get auth key and curve | +| [`HMAC`](apdu.md#HMAC) | 0x0e | Get the HMAC of a message | +| [`SIGN_WITH_HASH`](apdu.md#sign_with_hash) | 0x0f | Sign a message with the ledger’s key | + +### `VERSION` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x00` | `__` | `__` | + +Get version information of the application. + +#### Input data + +No input data. + +#### Output data + +| Length | Description | +|--------|--------------------------| +| `1` | Should be 1 for `baking` | +| `1` | The major version | +| `1` | The minor version | +| `1` | The patch version | + +### `AUTHORIZE_BAKING` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|--------|------| +| `0x80` | `0x01` | `0x00` | `P2` | + +Requests authorization to bake with the key associated with the given +`path` and `P2`. + +If no `path` is provided, the request is performed using the key +already authorized. + +If the request is accepted, the key is defined as the [`authorized-key`](NVRAM.md#authorized-key) +and the public key is returned. + +Refusing the request do not erase the existing [`authorized-key`](NVRAM.md#authorized-key) + +#### Input data + +| Length | Description | +|--------------|---------------------------| +| `` | The `path` (can be empty) | + +#### Output data + +| Length | Description | +|------------|-------------------------| +| `1` | The public key `length` | +| `` | The public key | + +### `GET_PUBLIC_KEY` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|--------|------| +| `0x80` | `0x02` | `0x00` | `P2` | + +Get the public key according to the `path` and `P2`. + +This instruction is not allowed for permissionless legacy comm in browser. + +#### Input data + +| Length | Description | +|--------------|-------------| +| `` | The `path` | + +#### Output data + +| Length | Description | +|------------|-------------------------| +| `1` | The public key `length` | +| `` | The public key | + +### `PROMPT_PUBLIC_KEY` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|--------|------| +| `0x80` | `0x02` | `0x00` | `P2` | + +Requests to get the public key according to the `path` and `P2`. + +#### Input data + +| Length | Description | +|--------------|-------------| +| `` | The `path` | + +#### Output data + +| Length | Description | +|------------|-------------------------| +| `1` | The public key `length` | +| `` | The public key | + +### `SIGN` + +#### First apdu + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------------------|------| +| `0x80` | `0x04` | `0x00` or `0x80` | `P2` | + +Set the signing key to the key associated with the given `path` and +`P2`. + +This step is not required, as long as the [`authorized-key`](NVRAM.md#authorized-key) has been +defined. In this case the signature will be performed by this +[`authorized-key`](NVRAM.md#authorized-key). + +##### Input data + +| Length | Description | +|--------------|-------------| +| `` | The `path` | + +##### Output data + +No output data. + +#### Other apdus + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------------------|------| +| `0x80` | `0x04` | `0x01` or `0x81` | `__` | + +Request to sign the `message`. + +Use `P1 = 0x81` to indicate that the message has been fully sent. + +Once the message has been fully sent and the request has been +accepted, the signature of the message is returned. + +Messages sent in more than one packet will be refused. + +See [the messages in the specification](signing.md#messages) and the [API](https://tezos.gitlab.io/shell/p2p_api.html). + +##### Input data + +| Length | Description | +|--------------|-----------------------| +| `` | The `message` to sign | + +##### Output data + +| Length | Description | +|--------------|---------------| +| `` | The signature | + +### `RESET` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x06` | `__` | `__` | + +Requests a reset of the minimum level authorised in the main and the +test chains to `level`. + +Once accepted the two [`HWM`](NVRAM.md#hwm) will be set their level to `level` and +their round will be set to `0`. + +#### Input data + +| Length | Description | +|--------|-------------| +| `4` | The `level` | + +#### Output data + +No output data. + +### `QUERY_AUTH_KEY` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x07` | `__` | `__` | + +Get the path of the [`authorized-key`](NVRAM.md#authorized-key). + +#### Input data + +No input data. + +#### Output data + +| Length | Description | +|--------------|-------------| +| `` | The `path` | + +### `QUERY_MAIN_HWM` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x08` | `__` | `__` | + +Get the [`HWM`](NVRAM.md#hwm) of the main chain. + +#### Input data + +No input data. + +#### Output data + +| Length | Description | +|--------|-------------| +| `4` | The `level` | +| `4` | The `round` | + +### `GIT` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x09` | `__` | `__` | + +Get the commit hash. + +#### Input data + +No input data. + +#### Output data + +| Length | Description | +|--------------|--------------| +| `` | The `commit` | + +### `SETUP` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|--------|------| +| `0x80` | `0x0a` | `0x00` | `P2` | + +Requests: + - authorization to bake with the key associated with the given `path` + and `P2` + - a reset of the minimum level authorised in the main chain by + `main-level`. + - a reset of the minimum level authorised in the test chains by + `test-level`. + - to set the main chain id to `chain_id`. + +Once accepted: + - the key will be defined as the [`authorized-key`](NVRAM.md#authorized-key) + - the maintened [`chain-id`](NVRAM.md#chain-id) will be set to `chain_id`. + - the main [`HWM`](NVRAM.md#hwm) level will be set to `main-level` and its round will + be set to `0`. + - the test [`HWM`](NVRAM.md#hwm) level will be set to `test-level` and its round will + be set to `0`. + - the public key is returned. + +#### Input data + +| Length | Description | +|--------------|------------------| +| `4` | The `chain_id` | +| `4` | The `main-level` | +| `4` | The `test-level` | +| `` | The `path` | + +#### Output data + +| Length | Description | +|------------|-------------------------| +| `1` | The public key `length` | +| `` | The public key | + +### `QUERY_ALL_HWM` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x0b` | `__` | `__` | + +Get: + - the [`HWM`](NVRAM.md#hwm) of the main chain. + - the [`HWM`](NVRAM.md#hwm) of the test chains. + - the main [`chain-id`](NVRAM.md#chain-id). + +#### Input data + +No input data. + +#### Output data + +| Length | Description | +|--------|------------------| +| `4` | The main `level` | +| `4` | The main `round` | +| `4` | The test `level` | +| `4` | The test `round` | +| `4` | The `chain_id` | + +### `DEAUTHORIZE` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|--------|------| +| `0x80` | `0x0c` | `0x00` | `__` | + +Deauthorize the [`authorized-key`](NVRAM.md#authorized-key). + +#### Input data + +No input data expected. + +#### Output data + +No output data. + +### `QUERY_AUTH_KEY_WITH_CURVE` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x0d` | `__` | `__` | + +Get the path and the curve of the [`authorized-key`](NVRAM.md#authorized-key). + +#### Input data + +No input data. + +#### Output data + +| Length | Description | +|--------------|-------------| +| `1` | The `curve` | +| `` | The `path` | + +### `HMAC` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|--------|------| +| `0x80` | `0x0e` | `0x00` | `P2` | + +Get the HMAC of the `message` produced using as key the signature of a +fixed message signed by the key associated with the `path` and `P2`. + +#### Input data + +| Length | Description | +|--------------|---------------| +| `` | The `path` | +| `` | The `message` | + +#### Output data + +| Length | Description | +|--------------|-------------| +| `` | The `hmac` | + +### `SIGN_WITH_HASH` + +| *CLA* | *INS* | *P1* | *P2* | +|--------|--------|------|------| +| `0x80` | `0x0e` | `__` | `__` | + +Alias for `SIGN` diff --git a/doc/signing.md b/doc/signing.md new file mode 100644 index 00000000..e4a6b84a --- /dev/null +++ b/doc/signing.md @@ -0,0 +1,52 @@ +# Signing + +The baking application is designed for bakers. + +The application enables dedicated baking message to be signed. + +To avoid bakers having to check and accept each block and each +consensus operation, the ledger will take care of the checks and will +sign without user intervention. + +## Messages + +- A `Block`. +- A `Consensus operation`: + - A `Preattestation`: an operation implements a first vote for a + candidate block with the aim of building a preattestation quorum. + - An `Attestation`: an operation implements a vote for a candidate + block for which a preattestation quorum certificate (PQC) has been + observed. + - A `DAL_attestation`: an operation to verify whether attesters were + able to successfully download the shards assigned to them. +- A `Reveal`: an operation reveals the public key of the sending + manager. Knowing this public key is indeed necessary to check the + signature of future operations signed by this manager. +- A `Delegation`: an operation allows users to delegate their stake to + a delegate (a baker), or to register themselves as delegates. + +## Checks + +The ledger will refuse to sign: +- a message if the key requested to sign the message is not the + [`authorized-key`](NVRAM.md#authorized-key). +- Relative to the [`HWM`](NVRAM.md#hwm) of the corresponding [`chain-id`](NVRAM.md#chain-id): + - an `Attestation` if another `Attestation` has already been signed + by the ledger at the same level and round or higher (a higher + level or the same level, but a higher round). + - a `Pre-attestation` if another `Pre-attestation` or `Attestation` + has already been signed by the ledger at the same level and round + or higher. + - a `Block` if another `Block`, a `Pre-attestation` or an + `Attestation` has already been signed by the ledger at the same + level and in the same round or higher. +- a manager operation if it contains: + - operations other than `Reveal` or `Delegation`. A point to note is that you can only set/unset Delegation using baking app. To stake your tez, you need to use tezos-wallet app. + - operations with their source different from the [`authorized-key`](NVRAM.md#authorized-key). + - a `Reveal` with its revealed key different from the + [`authorized-key`](NVRAM.md#authorized-key) (More than one `Reveal` can be signed in a + manager operation). + - more than one `Delegation`. + +For signing, a user validation will be required only if the message is +a valid manager operation that contains a `Delegation`.