You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
matrix-spec-proposals/proposals/4100-scoped-signing-keys.md

9.2 KiB

MSC4100: Scoped signing keys

Matrix uses signing keys to authorize requests between servers and events in a room. Servers can additionally expose multiple signing keys through the key exchange system. All exposed signing keys can currently be used for either purpose: requests or events.

Following a principle of lease privilege, large distributed servers (one logical homeserver represented by several physical servers) may prefer to narrow the capabilities of a given key. These scoped keys can then be given to individual services within the overall homeserver system to perform exactly what is required.

Few examples of this homeserver architecture exist today, however components are emerging: providers which use a detached media repository service within their infrastructure may reasonably expect that signing capabilities are limited. If the media repository is further responsible for multiple homeservers, multiple homeserver signing keys may be stored in a single place. It is therefore more desirable to have highly specific and narrowly scoped keys to limit the reach of a malicious actor, should they get access to the collection of signing keys.

This proposal introduces such scoped signing keys, allowing large deployments (when they exist) to segment their infrastructure with highly specific keys.

Note: Currently, the media repository does not need a signing key in order to function. With the introduction of MSC3916 and similar however, the service does need to be able to authenticate requests. The specific use case of the author's own MMR project wishing to support MSC3916 is the (non-blocking) motivation for this MSC.

Proposal

A new GET /_matrix/key/v2/server endpoint at GET /_matrix/key/v3/server is introduced. The existing endpoint returns keys which serve any purpose, and simply adding a scope to them could still cause events to be sent in existing room versions or wrongly authorize network requests against servers unaware of the scope. By introducing a new endpoint, servers must explicitly be aware of the keys, therefore allowing them to be properly scoped.

The new /server endpoint takes the same request parameters as the old one. The response includes a scope on each of the keys, but is otherwise the same:

{
  "server_name": "example.org",
  "valid_until_ts": 1652262410000,
  "verify_keys": {
    "ed25519:abc123": {
      "key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA",
      "scope": ["m.events"] // NEW!
    },
    "ed25519:def456": {
      "key": "ThisShouldBeABase64Key",
      "scope": ["m.requests"] // NEW!
    }
  },
  "old_verify_keys": {
    "ed25519:0ldk3y": {
      "expired_ts": 1532645052628,
      "key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg",
      "scope": ["m.events"] // NEW!
    }
  },
  "signatures": {
    "example.org": {
      "ed25519:abc123": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU",
      "ed25519:def456": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU"
    }
  }
}

TODO: Make example truthful. Use real keys, valid signatures.

scope is required and must be an array of namespaced identifiers. The key can only be used for the listed scopes (see below). The scopes may change over time, and should only be cached for as long as the response object is (typically half the lifetime of valid_until_ts).

When a server is attempting to verify something, it will already know which scope is required. Therefore, unknown or empty scopes do not affect the validity of a given key.

This proposal defines two scopes:

  • m.events - The key may be used to sign events.
  • m.requests - The key may be used to sign requests (X-Matrix authentication).

TODO: Consider further scoping m.requests and maybe m.events down into smaller parts. For example, a key that can only sign /_matrix/media/* requests or m.room.member events.

To match the new /server endpoint, v3 endpoints for POST /_matrix/key/v2/query and GET /_matrix/key/v2/query/{serverName} are introduced. The endpoints both use the new /_matrix/key/v3/server endpoint, but otherwise remain unchanged in request and response behaviour.

The legacy /_matrix/key/v2/* endpoints are deprecated and discouraged from use.

TODO: Do we need to list m.requests-only keys in old_verify_keys when they rotate, or can we simply exclude them? old_verify_keys is typically used for proving old events are properly signed, and those keys can't be used to verify requests anyways.

Backwards compatibility: requests

MSC4029 clarifies how the X-Matrix authentication scheme is meant to work, and currently states that if a key is present then it must be valid. As part of a transition towards scoped signing keys, a server may expose a generic, all-purpose, key at /v2/server and a different, scoped, key at /v3/server. If the server included both keys in the Authorization headers, the request would fail when reaching a legacy server because that server would be unable to locate the newer signing key.

To get around this, the X-Matrix auth scheme is duplicated to X-Matrix-Scoped. Only scoped signing keys may be used for X-Matrix-Scoped. X-Matrix thus becomes deprecated, and only capable of legacy non-scoped keys.

Requests containing both X-Matrix and X-Matrix-Scoped auth must be valid in their respective schemes, otherwise the request is failed. Servers should use both in independent Authorization headers if possible, or otherwise downgrade their requests to X-Matrix if an auth error is received for X-Matrix-Scoped alone.

TODO: Verify this approach is compatible with existing servers. ie: that they don't fail requests due to unknown auth schemes being present (when combined with X-Matrix).

Backwards compatibility: events

Similar to requests, using a scoped signing key in an existing room version will potentially cause older servers to reject the event due to being unable to locate the newer key. We fix this by introducing a room version which requires the use of scoped signing keys, banning the use of legacy all-purpose keys. Existing room versions enact the opposite, as we have today: events must be signed by all-purpose keys, not scoped keys.

This sufficiently requires servers to become aware of scoped signing keys to continue participating in increasingly modern room versions.

Potential issues

This proposal does nothing to make a future breaking change to signing keys more manageable. Instead, this MSC attempts to diminish the impact of the change by providing fallback for requests and isolating event signing to dedicated room versions. This approach is awkward, however, and may need to be duplicated if the signing key scope/purpose were to ever change again in future.

Alternatives

Implied throughout is adding the scope to the existing signing key endpoints, however this can cause issues. Critically, a legacy server unaware of scopes could allow what is intended to be a scoped signing key to perform an action that is otherwise illegal in modern servers. This provides a high degree of backwards compatibility, but when a concern is that the media repo doesn't need to sign events, the security benefits of scoping are lost.

Security considerations

This proposal theoretically increases security for distributed or partially distributed homeserver systems. Such systems are not currently prevalent in Matrix today, however.

Unstable prefix

Before completing FCP:

  • X-Matrix-Scoped becomes X-MSC4100-Scoped.
  • /_matrix/key/v3/* becomes /_matrix/key/unstable/org.matrix.msc4100/*.
  • The room version is org.matrix.msc4100.11, based on room version 11.

After completing FCP, but before released in spec:

  • X-Matrix-Scoped may be used as described.
  • /_matrix/key/v3/* may be used as described.
  • The room version remains org.matrix.msc4100.11.

After released in the spec:

  • X-MSC4100-Scoped should no longer be used, except for backwards compatibility.
  • /_matrix/key/unstable/org.matrix.msc4100/* should no longer be used, except for backwards compatibility.
  • The room version remains org.matrix.msc4100.11.

Note that for a room version to become 'stable', an MSC needs to incorporate the changes described by this MSC and assign it a stable identifier. See MSC3820 as an example of this process.

Dependencies

This MSC would benefit from MSC4029 being merged, but does not require it.