跳转到内容

Relay identity

此内容尚不支持你的语言。

The relay has a long-term Ed25519 identity key, separate from its TLS certificate. In every connection it signs the client’s challenge together with a value taken from the TLS session. The app pins the key per relay origin (scheme://host:port) after the first connection and stops connecting if it changes without a handover signed by the old key.

  • Default: relay_identity.key next to the config file.

  • [server] relay_identity_path overrides the location. With the systemd units, use the state directory:

    [server]
    relay_identity_path = "/var/lib/rchat/relay_identity.key"

The file holds 32 bytes, must have mode 0600 or narrower and must be owned by the service user. The service user needs write access to its directory to create or rotate it.

Terminal window
sudo -u rchat /usr/local/bin/rchat-server --config /etc/rchat/server.toml --init-relay-identity
# FreeBSD:
su -m rchat -c '/usr/local/bin/rchat-server --config /usr/local/etc/rchat/server.toml --init-relay-identity'

It prints the pin and exits. --init-relay-identity refuses to overwrite an existing key. A relay run from a config file refuses to start without the key, so a redeploy that loses it fails loudly instead of silently changing identity.

Back the key up like a TLS private key. If it is lost, every client that pinned the relay refuses to connect to a new one.

Terminal window
sudo -u rchat /usr/local/bin/rchat-server --config /etc/rchat/server.toml --print-relay-pin
# rk:1:… (version 0)

The relay also logs the pin at startup. Publish it for your users, for example on your website or as a QR code:

Terminal window
qrencode -t ANSIUTF8 "$(sudo -u rchat /usr/local/bin/rchat-server --config /etc/rchat/server.toml --print-relay-pin | cut -d' ' -f1)"

The simplest way to hand out the pin is a relay invite, which carries the address and the pin together and pins the relay before the first connection: see Inviting people to your relay. Users can also enter the pin in Connection settings and turn on Require a saved server identity. Without an entered pin, the app trusts whatever identity the relay presents on the first connection, so an attacker present at that first connection would be pinned instead.

To replace the key without breaking users’ pins:

Terminal window
sudo systemctl stop rchat-server
sudo -u rchat /usr/local/bin/rchat-server --config /etc/rchat/server.toml --rotate-relay-identity
sudo systemctl start rchat-server

This creates a new key at version + 1, writes a handover signed by the old key to relay_identity.chain next to the key (the last 3 handovers are kept, and the previous chain file is kept as relay_identity.chain.prev), prints the new pin, and deletes the previous key: an archived key could sign handovers for clients pinned at older versions. Clients pinned to an earlier key follow the handover without asking the user. Publish the new pin.

Both the relay’s signature and the client’s connection proof bind the TLS session. A TLS-terminating reverse proxy, load balancer or CDN in front of the relay gives each side a different session, and every connection fails. The app shows “This server couldn’t prove its identity”. Use a TCP (layer-4) passthrough instead; see Behind a TCP front end.

Over plain ws:// there is nothing to bind, and pinning protects nothing. Release builds of the app connect only over wss://, except to a test relay on the same device.