Skip to content

Security

Each component in the Greenlight system is uniquely identified by an mTLS keypair, also called an identity. These are either used directly to setup mutually authenticated TLS connections, or to sign payloads in cases direct connections are not desirable or possible.

In addition the signer also has access to the Bitcoin keypair that backs the Node ID, as well as the on-chain wallet. We will refer to this keypair as the signer-identity, whereas mTLS keypairs are just called the client-identities.

In the following scenarios we will consider an attacker that has access to the node infrastructure, but not the client or the signer. This can either be an external attacker or a rogue Greenlight operator. Our goal is to prevent any access to funds from such an attacker, whether internal or external, by checking authorization on both the node as well as the signer level.

Client ⇄ Node Authentication

This is a direct connection from a client to the node, or the signer to the node. The mTLS certificate hierarchy is under the control of the Greenlight Team. Each user gets their own CA, and nodes are configured to only accept client connections from certificates matching that CA. This guarantees that users can only contact their own node, while all other nodes would cause a mismatch and disconnect the client.

Experimental

Access to the node is currently all-or-nothing. The planned introduction of Rune-based access control will enable users to limit the operations a given client can execute. This is dependent on the pairing process as any client that has access to the signer could just escalate its privileges via the recovery.

The private key for the client-identity is generated on the client itself, and never leaves the client, sending only a certificate signature request (CSR) to the scheduler which creates and signs the certificate. This puts the client in the correct subtree of the CA hierarchy, enabling it to contact the node.

Impersonation by a potential attacker is prevented by keeping the private key for the client-identity on the client, and not share it with the server. Notice however that the Greenlight team, being in control of the CA hierarchy, could create a bogus client certificate and use that to issue commands to the node. More on this in the next section.

Client ⇄ Signer Authentication

The signer cannot rely on the mTLS CA structure, since that is under control of the Greenlight team. Instead, Greenlight employs an attestation scheme in which the signer identity attests to itself and other signers that a particular client is authorized to perform certain operations.

When registering a new client, the signer will submit a rune as an access token. The rune serves mainly as an authentication while the client's identity in form of a mTLS key-pair provides authorization. The run is bound to the client's identity; it is presented to the signer on each request. This will allow multiple signers to recognize which clients are authorized, even if the signer who carved the rune is not the signer verifying the authorization.

Before signing a request the signer independently verifies that:

  1. The operations that it is asked to sign off on match pending RPC commands, and are safe to perform.
  2. The pending RPC commands are all signed by a valid client-identity
  3. The client-identity has a valid rune that qualifies for the request.
  4. None of the pending RPC commands is a replay of a previously completed RPC command.

An attacker that has gotten access to the node infrastructure may inject RPC commands directly into the node, side-stepping any authorization check on the node. For this reason the signer performs the same checks both on the node as well as the signer, the former preventing read-access that doesn't involve the signer, while the latter ensures funds are not moved without a client authorizing it.

The client-identity pubkey, its signature of the command payload, and the rune are all passed to the node via grpc headers. The node extracts them, alongside the call itself, and adds it to a request context which will itself be attached to requests that are sent to the signer, so it can verify the validity and authenticity of the operations. An attacker that gains access to the node is unable to provide either these signatures and will therefore fail to convince the signer of its injected commands.

Signer State Integrity

The signer does not store its own state. The node stores the signer state (channel states, allowed on-chain destinations, known invoices) and attaches it to every request. An attacker with access to the node infrastructure can therefore read, withhold, replay or modify the state a signer receives, and the signer must not trust it blindly.

Party Trusted with Not trusted with
Node infrastructure Storing and returning the state The content, age or completeness of the state
Signer Writing and signing state entries
Application embedding the signer Keeping the state anchor, choosing enforcement options
  • Authenticity: every state entry is signed with a key derived from the node secret. In hard state signature mode the signer refuses entries with missing or invalid signatures, so the node cannot inject or alter state.
  • Freshness and completeness (planned): a small state anchor kept on the device records the latest version of every key the signer has seen. On start, the signer refuses state that is older than its anchor, is missing keys, or brings back deleted keys.
  • Enforcement options belong to the application. The state signature mode and anchor enforcement are set where the signer is embedded; the node cannot change them, and there is no way for the node to reset an anchor.

A signer without an anchor, for example right after pairing or recovery, trusts the first state it receives. See Signer State for the details and the configuration options.

Client ⇄ Signer Authorization

The rune-based signer authentication verifies a client's identity and their authorization to execute commands. To achieve more granular control over command authorization for individual clients, a rune can be created with specific restrictions. When verifying client identity, the signer additionally ensures that specific conditions, such as the requested command, align with the limitations of the given rune.

This enables a user to share access to the signer across multiple clients that are restricted to a subset of commands, for example read-only clients, or invoice-only clients, or clients that can only create on-chain addresses and so on.