Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bLIP-0028: Paratonnerre #28

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ For more detail on the process, please read [bLIP-0001](./blip-0001.md) and
| [10](./blip-0010.md) | Podcasting 2.0 | Satoshis Stream | Active |
| [11](./blip-0011.md) | NameDesc | Hampus Sjöberg | Active |
| [17](./blip-0017.md) | Hosted Channels | Anton Kumaigorodskiy | Active |
| [28](./blip-0028.md) | Paratonnerre | Bastien Teinturier | Active |
3 changes: 3 additions & 0 deletions blip-0002.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ bLIPs may create new messages and reserve their type in the following table:
| 63501 | `hc_updated_fail_htlc` | [bLIP 17](./blip-0017.md) |
| 63499 | `hc_update_fail_malformed_htlc` | [bLIP 17](./blip-0017.md) |
| 63497 | `hc_error` | [bLIP 17](./blip-0017.md) |
| 73760 | `hd_init` | [bLIP 28](./blip-0028.md) |
| 73761 | `hd_command` | [bLIP 28](./blip-0028.md) |
| 73762 | `hd_command_result` | [bLIP 28](./blip-0028.md) |

### TLV fields in BOLT messages

Expand Down
326 changes: 326 additions & 0 deletions blip-0028.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
```
bLIP: 28
Title: Paratonnerre
Status: Draft
Author: Bastien Teinturier <bastien@acinq.fr>
Created: 2023-09-05
License: CC0
```

## Abstract

This bLIP details how hardware devices can be used to securely control a remote lightning node from an untrusted machine.

## Motivation

Lightning nodes are effectively hot wallets, which makes them valuable targets for attackers.
Node operators thus need to take great care when securing access to their node.
But on the other hand, lightning nodes regularly require actions from the node operator (to open and close channels, pay invoices, etc).
We'd like node operators to be able to complete those tasks without exposing their node to additional threats.

The most common ways of completing such tasks are:

- directly connecting to the node's machine (e.g. using ssh) and calling its local RPCs
- exposing the node's RPCs over the internet, with some form of authentication

Both of these options are dangerous if the machine used to perform those tasks is compromised. This where hardware devices such as hardware wallets come in handy: they let their owner securely perform critical operations from a potentially compromised machine.

## Specification

### Terminology

We use the following three components:

- lightning node: the user's lightning node, running on a remote server
- hardware device: a secure hardware device with a trusted display (e.g. Ledger Nano S)
- companion app: an untrusted application used to communicate with the hardware device and the lightning node

The companion app can run on any kind of untrusted hardware: laptop, desktop, mobile phone, smart watch...anything that has network connectivity and a way to communicate with the hardware device (e.g. bluetooth).

### High-level Architecture

```diagram
+-----------------+ commands +---------------+ +----------------+
| |<-----------------------| | TCP packets | |
| Hardware Device | TCP packets | Companion app |<---------------------->| Lightning Node |
| |<---------------------->| | encrypted (Bolt 8) | |
+-----------------+ encrypted (Bolt 8) +---------------+ +----------------+
```

### Initial Setup

On the hardware device:

- generate a secp256k1 private key and securely store it (e.g. in a secure element)
- display the corresponding public key (`hd_node_id`) on the trusted display

On the lightning node:

- add the corresponding `hd_node_id` to a list of trusted hardware devices

The lightning node will then accept custom lightning messages (defined in the [messages](#messages) section below) from Bolt 8 connections that were initiated from a `node_id` in its list of trusted hardware devices.

### Protocol flow

The protocol is fairly simple: the hardware device implements Bolt 8 and establishes a connection to the lightning node, with the help of the companion app which simply forwards encrypted TCP packets in both directions. Since Bolt 8 encryption and decryption is done entirely within the hardware device, the companion app cannot read or modify any of the messages exchanged between the hardware device and the lightning node.

Before sending any message, the hardware device prints its details on its trusted display and waits for confirmation from the node operator. Similarly, messages from the lightning node are printed on the hardware device's trusted display, which lets the node operator verify the result of the commands that were issued.

The companion app is used to provide an easy-to-use interface to prepare commands. If the companion app tries to trick the hardware device into sending a different command to the lightning node, the node operator will notice it when confirming the command on the hardware device's trusted display.

```diagram
Node Operator Companion App Lightning Node
| create command | |
|------------------------------------------------------->| |
| | |
| Hardware Device | |
| | send(command) | |
| |<------------------------------| |
| confirm command | | |
|<-----------------------| | |
| ok | | |
|----------------------->| | |
| | | |
| +---| | |
| encrypt | | | |
| +-->| | |
| | forward(encrypted_packet) | |
| |------------------------------>| |
| | | encrypted_packet |
| | |------------------------->|
| | | |---+
| | | | | - verify that remote `node_id`
| | | | | is allowed to issue command
| | | | | - execute command
| | | | | - send response
| | | |<--+
| | | encrypted_packet |
| | |<-------------------------|
| | receive(encrypted_packet) | |
| |<------------------------------| |
| +---| | |
| decrypt | | | |
| +-->| | |
| | | |
| command result | | |
|<-----------------------| | |
| | | |
```

### Messages

We define the following new lightning messages:

| Type | Name |
|-------|---------------------|
| 73760 | `hd_init` |
| 73761 | `hd_command` |
| 73762 | `hd_command_result` |

#### The `hd_init` message

The `hd_init` message is used to initialize a connection between a hardware device and a lightning node and negotiate the commands that can be issued on that connection.

1. type: 73760 (`hd_init`)
2. data:
- [`u16`:`commands_len`]
- [`commands_len*byte`:`commands`]

The `commands` field is a bitset where the bit at index `i` indicates support for the `hd_command` with `command_type=i`.

#### The `hd_command` message

The `hd_command` message is always sent by the hardware device. It wraps an actual command.

1. type: 73761 (`hd_command`)
2. data:
- [`u16`:`command_type`]
- [`...byte`:`command`]

#### The `hd_command_result` message

The `hd_command_result` message is always sent by the lightning node in response to an `hd_command`.
It lets the node operator know whether the command was successfully applied or not.

1. type: 73762 (`hd_command_result`)
2. data:
- [`u16`:`command_result_type`]
- [`...byte`:`command_result`]

#### Commands

##### Connect

The `connect` command tells the lightning node to connect to another lightning node.
The `address` field uses the same encoding as the corresponding `node_announcement` field.

1. command type: 0
2. data:
- [`point`:`remote_node_id`]
- [`...*byte`:`address`]

The corresponding `hd_command_result` is:

1. command type: 0
2. data:
- [`point`:`remote_node_id`]
- [`byte`:`success`]

##### Disconnect

The `disconnect` command tells the lightning node to disconnect from one of its peers.

1. command type: 1
2. data:
- [`point`:`remote_node_id`]

The corresponding `hd_command_result` is:

1. command type: 1
2. data:
- [`point`:`remote_node_id`]
- [`byte`:`success`]

##### Open Channel

The `open_channel` command tells the lightning node to open a channel to a given peer.

1. command type: 2
2. data:
- [`point`:`remote_node_id`]
- [`u64`:`funding_satoshis`]
- [`u32`:`feerate_per_kw`]
- [`byte`:`announce_channel`]
- [`u16`:`channel_type_len`]
- [`channel_type_len*byte`:`channel_type`]

The corresponding `hd_command_result` is:

1. command type: 2
2. data:
- [`point`:`remote_node_id`]
- [`byte`:`success`]
- [`channel_id`:`channel_id`]
- [`u64`:`funding_fee_satoshis`]

##### Close Channel

The `close_channel` command tells the lightning node to cooperatively close a channel.

1. command type: 3
2. data:
- [`point`:`remote_node_id`]
- [`channel_id`:`channel_id`]
- [`u32`:`feerate_per_kw`]
- [`u16`:`len`]
- [`len*byte`:`scriptpubkey`]

The corresponding `hd_command_result` is:

1. command type: 3
2. data:
- [`point`:`remote_node_id`]
- [`channel_id`:`channel_id`]
- [`byte`:`success`]

##### Force-Close Channel

The `force_close_channel` command tells the lightning node to unilaterally close a channel.

1. command type: 4
2. data:
- [`point`:`remote_node_id`]
- [`channel_id`:`channel_id`]

The corresponding `hd_command_result` is:

1. command type: 4
2. data:
- [`point`:`remote_node_id`]
- [`channel_id`:`channel_id`]
- [`byte`:`success`]

##### Update Relay Fee

The `update_relay_fee` command tells the lightning node to update the routing fees for channels with a given peer.

1. command type: 5
2. data:
- [`point`:`remote_node_id`]
- [`u32`:`fee_base_msat`]
- [`u32`:`fee_proportional_millionths`]
- [`u16`:`cltv_expiry_delta`]

The corresponding `hd_command_result` is:

1. command type: 5
2. data:
- [`point`:`remote_node_id`]
- [`byte`:`success`]
- [`u32`:`previous_fee_base_msat`]
- [`u32`:`fee_base_msat`]
- [`u32`:`previous_fee_proportional_millionths`]
- [`u32`:`fee_proportional_millionths`]
- [`u16`:`previous_cltv_expiry_delta`]
- [`u16`:`cltv_expiry_delta`]

##### Create Invoice

The `create_invoice` command tells the lightning node to create a Bolt 11 invoice.

1. command type: 6
2. data:
- [`u32`:`amount_msat`]
- [`u16`:`description_len`]
- [`description_len*byte`:`description`]

The corresponding `hd_command_result` is:

1. command type: 6
2. data:
- [`u16`:`invoice_len`]
- [`invoice_len*byte`:`invoice`]

##### Pay Invoice

The `pay_invoice` command tells the lightning node to pay a given Bolt 11 invoice.

1. command type: 7
2. data:
- [`u16`:`invoice_len`]
- [`invoice_len*byte`:`invoice`]
- [`u32`:`amount_msat`]
- [`u32`:`max_fee_msat`]

The corresponding `hd_command_result` is:

1. command type: 7
2. data:
- [`byte`:`success`]
- [`32*byte`:`payment_preimage`]
- [`u32`:`routing_fees_msat`]

### Requirements

The hardware device:

- MUST display the `node_id` of the lightning node and wait for confirmation before initiating a connection
- MUST encrypted packets as specified in Bolt 8 before sending them to the companion app
- MUST send `hd_init` instead of the standard `init` message once the connection has been established
- MUST display commands and wait for confirmation before sending them
- MUST send `ping` messages to keep the lightning connection alive
- MUST respond to `ping` messages
- SHOULD NOT require confirmation before sending `ping` and `pong` messages

The lightning node, when receiving a connection from a `node_id` in its configured list of trusted hardware devices:

- MUST send `hd_init` instead of the standard `init` message once the connection has been established
- MUST only send the following messages on that connection:
- `hd_init`
- `hd_command_result`
- `ping`
- `pong`

## Copyright

This bLIP is licensed under the CC0 license.