Initial draft of simplified encrypted state events.
parent
130da801e3
commit
065ee565f2
@ -0,0 +1,172 @@
|
||||
# MSC4362: Simplified Encrypted State Events
|
||||
|
||||
<!--_Note: Text written in italics represents notes about the section or proposal process. This document
|
||||
serves as an example of what a proposal could look like (in this case, a proposal to have a
|
||||
template) and should be used where possible._
|
||||
|
||||
_In this first section, be sure to cover your problem and a broad overview of the solution. Covering
|
||||
related details, such as the expected impact, can also be a good idea. The example in this document
|
||||
says that we're missing a template and that things are confusing and goes on to say the solution is
|
||||
a template. There's no major expected impact in this proposal, so it doesn't list one. If your
|
||||
proposal was more invasive (such as proposing a change to how servers discover each other) then that
|
||||
would be a good thing to list here._
|
||||
|
||||
_If you're having troubles coming up with a description, a good question to ask is "how does this
|
||||
proposal improve Matrix?" - the answer could reveal a small impact, and that is okay._-->
|
||||
|
||||
This proposal builds upon the earlier MSC3414, aiming to provide a simplified approach to encrypted
|
||||
state events in Matrix. Currently, all room state is unencrypted and accessible to everyone in the
|
||||
room, and occasionally people outside the room (such as via the public room directory, invite state,
|
||||
or peekable rooms). Most events in room state could be encrypted to provide confidentiality, which
|
||||
is what this MSC seeks to achieve more straightforwardly. Some parts, however, cannot be encrypted
|
||||
to maintain a functioning protocol.
|
||||
|
||||
## Proposal
|
||||
|
||||
<!--_Here is where you'll reinforce your position from the introduction in more detail, as well as cover
|
||||
the technical points of your proposal. Including rationale for your proposed solution and detailing
|
||||
why parts are important helps reviewers understand the problem at hand. Not including enough detail
|
||||
can result in people guessing, leading to confusing arguments in the comments section. The example
|
||||
here covers why templates are important again, giving a stronger argument as to why we should have a
|
||||
template. Afterwards, it goes on to cover the specifics of what the template could look like._-->
|
||||
|
||||
Under this proposal, all room state events can be encrypted, except events critical to maintain the
|
||||
protocol. Those critical events are:
|
||||
|
||||
- `m.room.create`
|
||||
- `m.room.member`
|
||||
- `m.room.join_rules`
|
||||
- `m.room.power_levels`
|
||||
- `m.room.third_party_invite`
|
||||
- `m.room.history_visibility`
|
||||
- `m.room.guest_access`
|
||||
- `m.room.encryption`
|
||||
|
||||
An encrypted state event looks very similar to a regular encrypted room message: the `type` becomes
|
||||
`m.room.encrypted` and the `content` is the same shape as a regular `m.room.encrypted` event. The
|
||||
`state_key` for encrypted state events is constructed from the plaintext `type` and `state_key`
|
||||
fields, formatted as `{type}:{state_key}`, preserving the uniqueness of the `type`-`state_key`
|
||||
mapping required for the server to perform state resolution.
|
||||
|
||||
To track whether a room has state encryption enabled, and to preserve compatibility with older
|
||||
clients that cannot work with encrypted state events, a new boolean field `encrypt_state_events` is
|
||||
introduced to the content of `m.room.encryption`, which determines if clients should send state
|
||||
encrypted events.
|
||||
|
||||
Clients are expected to decrypt all room state on reception and validate the packed state key
|
||||
matches the decrypted type and state key. This ensures malicious clients cannot send state events
|
||||
that masquerade as message events and vice versa.
|
||||
|
||||
This MSC relies on the room key sharing mechanism outlined in
|
||||
[MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268), which enables clients to
|
||||
decrypt historical state events.
|
||||
|
||||
## Potential issues
|
||||
|
||||
<!--_Not all proposals are perfect. Sometimes there's a known disadvantage to implementing the proposal,
|
||||
and they should be documented here. There should be some explanation for why the disadvantage is
|
||||
acceptable, however - just like in this example._-->
|
||||
|
||||
At present, MSC4268
|
||||
[does not require invitees to download the key bundle upon receiving an invite](https://github.com/matrix-org/matrix-spec-proposals/blob/rav/proposal/encrypted_history_sharing/proposals/4268-encrypted-history-sharing.md#actions-as-a-receiving-client);
|
||||
instead, the key bundle is only fetched when the user joins the room, which could lead to problems
|
||||
displaying the room name, topic, and avatar to invitees. One way to address this is to always
|
||||
download the room key bundle on invite, but as MSC4268 notes, this introduces a potential
|
||||
denial-of-service (DoS) attack vector.
|
||||
|
||||
If the client does not receive the keys needed to decrypt state events, the room may become
|
||||
unusable, as information such as the room's name, topic, avatar, and other metadata will be
|
||||
inaccessible. Additionally, if there are state events sent both before and after state encryption is
|
||||
enabled, existing clients might display the unencrypted, outdated state.
|
||||
|
||||
Encrypting certain state events would prevent servers from displaying meaningful information about
|
||||
rooms, as the room directory relies on being able to read these events. Rooms with encrypted
|
||||
metadata could either appear as blank, generic, or broken entries in the public room list, or could
|
||||
be omitted entirely, impeding room discovery. A similar issue arises with the space room list: if
|
||||
room metadata is encrypted, clients and servers will be unable to display meaningful information
|
||||
about child rooms within a space. It may be necessary to introduce an unencrypted state event,
|
||||
`m.space.child_info`, that stores plaintext copies of a child room's avatar, name, and topic, which
|
||||
can then be used over the encrypted metadata.
|
||||
|
||||
The `:` delimiter may not be suitable in all cases. Additionally, string packing introduces size
|
||||
limitations, as the combined length of the packed string cannot exceed the 255-byte maximum for a
|
||||
state key. This effectively reduces the available space for both event types and state keys.
|
||||
|
||||
## Alternatives
|
||||
|
||||
<!--
|
||||
_This is where alternative solutions could be listed. There's almost always another way to do things
|
||||
and this section gives you the opportunity to highlight why those ways are not as desirable. The
|
||||
argument made in this example is that all of the text provided by the template could be integrated
|
||||
into the proposals introduction, although with some risk of losing clarity._-->
|
||||
|
||||
A number of alternatives to string-packing the plaintext `type` and `state_key` are possible:
|
||||
|
||||
- Preserving the values of `type` and `state_key`;
|
||||
- Introducing an adjacent `true_type` field;
|
||||
- Hashing `type` and `state_key` with HMAC.
|
||||
|
||||
### Preserved Fields
|
||||
|
||||
Rather than string-packing the `type` and `state_key` together, we could preserve these values on
|
||||
the encrypted event, but still encrypt the event content. This provides the same (lack of)
|
||||
confidentiality as the approach laid out in this MSC while avoiding string packing. However, this
|
||||
approach would introduce a difference between the encryption of message events and state events,
|
||||
which may be undesirable.
|
||||
|
||||
### Adjacent Type Field
|
||||
|
||||
In a similar manner to preserved fields, we could introduce a new `true_type` field to the events
|
||||
`content`, which holds the plaintext type of the state event. This would require modifying the
|
||||
server to utilise this field over the value of the `type` field, which may be undesirable.
|
||||
|
||||
### HMAC-hashed `state_key`s
|
||||
|
||||
This is the _ideal solution_, as it hides the state key and type from the server entirely; however,
|
||||
there are some considerable downsides. We have two choices:
|
||||
|
||||
- Use a static key generated on room creation to encrypt all state events for the duration of the
|
||||
room's existence;
|
||||
- Rotate the key periodically, perhaps deriving it from the current Megolm session key.
|
||||
|
||||
The former case lacks post-compromise confidentiality (PCS), which, although quite hard to pull off
|
||||
as an attacker, makes this approach undesirable. This approach is also vulnerable to frequency
|
||||
analysis through comparison between the distribution of state key hashes and a known distribution of
|
||||
public `type`-`state_key` pairs.
|
||||
|
||||
The latter option has issues too: rotating the key breaks the server's ability to track room state,
|
||||
since two events with identical state keys will produce encrypted events with different hashed state
|
||||
keys when using different (HMAC) keys. The server will treat each as unique and send both to
|
||||
clients. This would require clients to perform state resolution locally (to decide which of two
|
||||
clashing events to accept), which in turn would require them to consume and understand the room DAG.
|
||||
This approach may also be vulnerable to frequency analysis, but, based on some naive calculations,
|
||||
the probability a malicious server is able to infer the hash to `type`-`state_key` mapping correctly
|
||||
becomes increasingly unlikely as the number of state events encrypted by any given key decreases.
|
||||
|
||||
## Security considerations
|
||||
|
||||
This proposal relies on the security of the Olm/Megolm primitives, and an attack against them could
|
||||
be a viable method to derive partial or complete knowledge of the encrypted content.
|
||||
|
||||
Confidential information **should not** be stored in the `type` and `state_key` fields, since both
|
||||
are present in plaintext.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
<!-- _If a proposal is implemented before it is included in the spec, then implementers must ensure that
|
||||
the implementation is compatible with the final version that lands in the spec. This generally means
|
||||
that experimental implementations should use `/unstable` endpoints, and use vendor prefixes where
|
||||
necessary. For more information, see [MSC2324](https://github.com/matrix-org/matrix-doc/pull/2324).
|
||||
This section should be used to document things such as what endpoints and names are being used while
|
||||
the feature is in development, the name of the unstable feature flag to use to detect support for
|
||||
the feature, or what migration steps are needed to switch to newer versions of the proposal._-->
|
||||
|
||||
The current implementation uses an `io.element` vendor prefix for the `encrypt_state_events` flag
|
||||
(i.e. `io.element.msc3414.encrypt_state_events`) for compatibility.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This MSC builds on
|
||||
[MSC3414](https://github.com/matrix-org/matrix-spec-propsals/tree/main/proposals/3414-encrypted-state-events.md)
|
||||
and depends on [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268), neither of
|
||||
which have been accepted into the spec at the time of writing.
|
||||
Loading…
Reference in New Issue