2017-12-31 17:07:08 -05:00
|
|
|
# Tendermint Peers
|
|
|
|
|
2018-01-19 17:10:08 -05:00
|
|
|
This document explains how Tendermint Peers are identified and how they connect to one another.
|
|
|
|
|
|
|
|
For details on peer discovery, see the [peer exchange (PEX) reactor doc](pex.md).
|
2017-12-31 17:07:08 -05:00
|
|
|
|
|
|
|
## Peer Identity
|
|
|
|
|
2018-01-09 12:44:49 -05:00
|
|
|
Tendermint peers are expected to maintain long-term persistent identities in the form of a public key.
|
|
|
|
Each peer has an ID defined as `peer.ID == peer.PubKey.Address()`, where `Address` uses the scheme defined in go-crypto.
|
2017-12-31 17:07:08 -05:00
|
|
|
|
2018-01-01 15:59:53 -05:00
|
|
|
A single peer ID can have multiple IP addresses associated with it.
|
2018-01-09 12:44:49 -05:00
|
|
|
TODO: define how to deal with this.
|
2017-12-31 17:07:08 -05:00
|
|
|
|
|
|
|
When attempting to connect to a peer, we use the PeerURL: `<ID>@<IP>:<PORT>`.
|
|
|
|
We will attempt to connect to the peer at IP:PORT, and verify,
|
|
|
|
via authenticated encryption, that it is in possession of the private key
|
|
|
|
corresponding to `<ID>`. This prevents man-in-the-middle attacks on the peer layer.
|
|
|
|
|
2018-01-01 15:59:53 -05:00
|
|
|
Peers can also be connected to without specifying an ID, ie. just `<IP>:<PORT>`.
|
|
|
|
In this case, the peer must be authenticated out-of-band of Tendermint,
|
2018-01-09 12:44:49 -05:00
|
|
|
for instance via VPN.
|
2017-12-31 17:07:08 -05:00
|
|
|
|
|
|
|
## Connections
|
|
|
|
|
|
|
|
All p2p connections use TCP.
|
|
|
|
Upon establishing a successful TCP connection with a peer,
|
|
|
|
two handhsakes are performed: one for authenticated encryption, and one for Tendermint versioning.
|
|
|
|
Both handshakes have configurable timeouts (they should complete quickly).
|
|
|
|
|
|
|
|
### Authenticated Encryption Handshake
|
|
|
|
|
|
|
|
Tendermint implements the Station-to-Station protocol
|
|
|
|
using ED25519 keys for Diffie-Helman key-exchange and NACL SecretBox for encryption.
|
|
|
|
It goes as follows:
|
|
|
|
- generate an emphemeral ED25519 keypair
|
|
|
|
- send the ephemeral public key to the peer
|
|
|
|
- wait to receive the peer's ephemeral public key
|
|
|
|
- compute the Diffie-Hellman shared secret using the peers ephemeral public key and our ephemeral private key
|
2018-01-01 15:59:53 -05:00
|
|
|
- generate two nonces to use for encryption (sending and receiving) as follows:
|
|
|
|
- sort the ephemeral public keys in ascending order and concatenate them
|
|
|
|
- RIPEMD160 the result
|
|
|
|
- append 4 empty bytes (extending the hash to 24-bytes)
|
|
|
|
- the result is nonce1
|
|
|
|
- flip the last bit of nonce1 to get nonce2
|
|
|
|
- if we had the smaller ephemeral pubkey, use nonce1 for receiving, nonce2 for sending;
|
|
|
|
else the opposite
|
|
|
|
- all communications from now on are encrypted using the shared secret and the nonces, where each nonce
|
|
|
|
increments by 2 every time it is used
|
2018-01-09 12:44:49 -05:00
|
|
|
- we now have an encrypted channel, but still need to authenticate
|
2018-01-01 15:59:53 -05:00
|
|
|
- generate a common challenge to sign:
|
|
|
|
- SHA256 of the sorted (lowest first) and concatenated ephemeral pub keys
|
2017-12-31 17:07:08 -05:00
|
|
|
- sign the common challenge with our persistent private key
|
2018-01-01 15:59:53 -05:00
|
|
|
- send the go-wire encoded persistent pubkey and signature to the peer
|
|
|
|
- wait to receive the persistent public key and signature from the peer
|
|
|
|
- verify the signature on the challenge using the peer's persistent public key
|
2017-12-31 17:07:08 -05:00
|
|
|
|
|
|
|
|
|
|
|
If this is an outgoing connection (we dialed the peer) and we used a peer ID,
|
2018-01-01 15:59:53 -05:00
|
|
|
then finally verify that the peer's persistent public key corresponds to the peer ID we dialed,
|
2017-12-31 17:07:08 -05:00
|
|
|
ie. `peer.PubKey.Address() == <ID>`.
|
|
|
|
|
|
|
|
The connection has now been authenticated. All traffic is encrypted.
|
|
|
|
|
2018-01-25 05:02:26 +00:00
|
|
|
Note: only the dialer can authenticate the identity of the peer,
|
2017-12-31 17:07:08 -05:00
|
|
|
but this is what we care about since when we join the network we wish to
|
|
|
|
ensure we have reached the intended peer (and are not being MITMd).
|
|
|
|
|
|
|
|
### Peer Filter
|
|
|
|
|
2018-01-01 15:59:53 -05:00
|
|
|
Before continuing, we check if the new peer has the same ID as ourselves or
|
2017-12-31 17:07:08 -05:00
|
|
|
an existing peer. If so, we disconnect.
|
|
|
|
|
|
|
|
We also check the peer's address and public key against
|
|
|
|
an optional whitelist which can be managed through the ABCI app -
|
2018-01-09 12:44:49 -05:00
|
|
|
if the whitelist is enabled and the peer does not qualify, the connection is
|
2017-12-31 17:07:08 -05:00
|
|
|
terminated.
|
|
|
|
|
|
|
|
|
|
|
|
### Tendermint Version Handshake
|
|
|
|
|
2018-01-01 15:59:53 -05:00
|
|
|
The Tendermint Version Handshake allows the peers to exchange their NodeInfo:
|
2017-12-31 17:07:08 -05:00
|
|
|
|
2018-01-25 05:02:26 +00:00
|
|
|
```golang
|
2017-12-31 17:07:08 -05:00
|
|
|
type NodeInfo struct {
|
2018-01-09 12:44:49 -05:00
|
|
|
PubKey crypto.PubKey
|
|
|
|
Moniker string
|
|
|
|
Network string
|
|
|
|
RemoteAddr string
|
|
|
|
ListenAddr string
|
|
|
|
Version string
|
|
|
|
Channels []int8
|
|
|
|
Other []string
|
2017-12-31 17:07:08 -05:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The connection is disconnected if:
|
|
|
|
- `peer.NodeInfo.PubKey != peer.PubKey`
|
|
|
|
- `peer.NodeInfo.Version` is not formatted as `X.X.X` where X are integers known as Major, Minor, and Revision
|
|
|
|
- `peer.NodeInfo.Version` Major is not the same as ours
|
|
|
|
- `peer.NodeInfo.Version` Minor is not the same as ours
|
|
|
|
- `peer.NodeInfo.Network` is not the same as ours
|
2018-01-01 15:59:53 -05:00
|
|
|
- `peer.Channels` does not intersect with our known Channels.
|
2017-12-31 17:07:08 -05:00
|
|
|
|
|
|
|
|
2018-01-01 15:59:53 -05:00
|
|
|
At this point, if we have not disconnected, the peer is valid.
|
|
|
|
It is added to the switch and hence all reactors via the `AddPeer` method.
|
|
|
|
Note that each reactor may handle multiple channels.
|
2017-12-31 17:07:08 -05:00
|
|
|
|
2018-01-01 15:59:53 -05:00
|
|
|
## Connection Activity
|
2017-12-31 17:07:08 -05:00
|
|
|
|
2018-01-01 15:59:53 -05:00
|
|
|
Once a peer is added, incoming messages for a given reactor are handled through
|
|
|
|
that reactor's `Receive` method, and output messages are sent directly by the Reactors
|
2018-01-25 05:02:26 +00:00
|
|
|
on each peer. A typical reactor maintains per-peer go-routine(s) that handle this.
|