diff --git a/changelogs/client_server/newsfragments/1655.feature b/changelogs/client_server/newsfragments/1655.feature new file mode 100644 index 000000000..bd200245a --- /dev/null +++ b/changelogs/client_server/newsfragments/1655.feature @@ -0,0 +1,2 @@ +Allow room keys to specify history visibility, as per +[MSC3061](https://github.com/matrix-org/matrix-spec-proposals/pull/3061). diff --git a/content/client-server-api/modules/end_to_end_encryption.md b/content/client-server-api/modules/end_to_end_encryption.md index f2f757056..1f6ed5e23 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -1232,20 +1232,22 @@ access to the previously exchanged messages. To address this issue, several methods are provided to allow users to transfer keys from one device to another. -##### Key requests - -When a device is missing keys to decrypt messages, it can request the -keys by sending [m.room\_key\_request](#mroom_key_request) to-device messages to other -devices with `action` set to `request`. - -If a device wishes to share the keys with that device, it can forward -the keys to the first device by sending an encrypted -[m.forwarded\_room\_key](#mforwarded_room_key) to-device message. The first device should -then send an [m.room\_key\_request](#mroom_key_request) to-device message with `action` -set to `request_cancellation` to the other devices that it had -originally sent the key request to; a device that receives a -`request_cancellation` should disregard any previously-received -`request` message with the same `request_id` and `requesting_device_id`. +##### Key requests and forwarding + +When a device is missing keys to decrypt messages, the keys can be forwarded to +it from a device that has the keys to allow it to decrypt the messages. + +The device that is missing the keys can request the keys from other devices by +sending [m.room\_key\_request](#mroom_key_request) to-device messages with +`action` set to `request`. If a device that receives the request wishes to +share the keys with that device, it can forward the keys to the first device by +sending an encrypted [m.forwarded\_room\_key](#mforwarded_room_key) to-device +message. The first device should then send an +[m.room\_key\_request](#mroom_key_request) to-device message with `action` set +to `request_cancellation` to the other devices that it had originally sent the +key request to; a device that receives a `request_cancellation` should +disregard any previously-received `request` message with the same `request_id` +and `requesting_device_id`. If a device does not wish to share keys with that device, it can indicate this by sending an [m.room\_key.withheld](#mroom_keywithheld) to-device message, @@ -1259,6 +1261,42 @@ of the same user, and should only request and accept forwarded keys from verified devices of the same user. {{% /boxes/note %}} +Devices can also forward keys without waiting for a request. For example, when +a user is invited to an encrypted room, the inviter may wish to allow the +invitee to decrypt old messages, as the invitee would otherwise be unable to +read the messages even if the [room history visibility +setting](#room-history-visibility) allows them to fetch the message events. + +To ensure that keys are only shared for messages sent while the history +visibility setting allowed for non-members to view the events, the `m.room_key` +event used to share the initial room key should have the `shared_history` +property set to `true` if the history visibility for the room is set to +`"world_readable"` or `"shared"`. If the history visibility for the room is any +other value, including being unset or an unrecognized value, the +`shared_history` property should be set to `false` or be unset. If the key is +subsequently backed up or forwarded, the `shared_history` property (if present) +should be preserved in the backup or `m.forwarded_room_key` event, +respectively. + +A consequence of this is that when a room's history visibility settings change +such that the value of the `shared_history` property would change, event +senders should rotate their room keys. + +This property may be used by clients to determine which keys to share with +other devices. For example, when inviting a user to an encrypted room, the +inviter may choose to share only the keys with `shared_history` set to `true`. + +{{% boxes/note %}} +When sharing keys for old messages, clients must not blindly trust the current +state as reported by the homeserver: clients should not assume that users who +have `m.room.member` events with `membership: "join"` are legitimately in the +room, as such events could be spoofed by the homeserver. Clients should use +other means of ensuring that a user is actually in the room before sharing keys +for old messages with them. For example, clients can share keys for old +messages only to users that they invite to the room, as then they know that the +user is supposed to be in the room. +{{% /boxes/note %}} + ##### Server-side key backups Devices may upload encrypted copies of keys to the server. When a device @@ -1266,7 +1304,7 @@ tries to read a message that it does not have keys for, it may request the key from the server and decrypt it. Backups are per-user, and users may replace backups with new backups. -In contrast with [Key requests](#key-requests), Server-side key backups +In contrast with [Key requests](#key-requests-and-forwarding), Server-side key backups do not require another device to be online from which to request keys. However, as the session keys are stored on the server encrypted, it requires users to enter a decryption key to decrypt the session keys. @@ -1780,7 +1818,7 @@ indicate to the user why it cannot decrypt the event, rather than just showing a generic error message. In the same way, when one device requests keys from another using [Key -requests](#key-requests), the device from which the key is being +requests](#key-requests-and-forwarding), the device from which the key is being requested may want to tell the requester that it is purposely not sharing the key. diff --git a/data/api/client-server/definitions/key_backup_session_data.yaml b/data/api/client-server/definitions/key_backup_session_data.yaml index 18963cbec..baf748ab6 100644 --- a/data/api/client-server/definitions/key_backup_session_data.yaml +++ b/data/api/client-server/definitions/key_backup_session_data.yaml @@ -43,6 +43,14 @@ properties: type: string description: |- Unpadded base64-encoded session key in [session-export format](https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md#session-export-format). + shared_history: + type: boolean + description: |- + Whether the key may be forwarded to users who join the room after the + messages encrypted with this key have been sent. Defaults to `false`. + + Should be set to the same value as the `shared_history` property of + the `m.room_key` event that was initially used to share the key. example: { "algorithm": "m.megolm.v1.aes-sha2", "forwarding_curve25519_key_chain": [ diff --git a/data/event-schemas/schema/m.forwarded_room_key.yaml b/data/event-schemas/schema/m.forwarded_room_key.yaml index 10b8b6525..831a976c5 100644 --- a/data/event-schemas/schema/m.forwarded_room_key.yaml +++ b/data/event-schemas/schema/m.forwarded_room_key.yaml @@ -52,6 +52,15 @@ properties: object must include the `code` and `reason` properties from the `m.room_key.withheld` message that was received by the sender of this message. + shared_history: + type: boolean + description: |- + Whether the key may be forwarded to users who join the room after the + messages encrypted with this key have been sent. Defaults to + `false`. + + Should be set to the same value as the `shared_history` property of + the `m.room_key` event that was initially used to share the key. required: - algorithm - room_id diff --git a/data/event-schemas/schema/m.room_key.yaml b/data/event-schemas/schema/m.room_key.yaml index 34ceb9ae8..611458562 100644 --- a/data/event-schemas/schema/m.room_key.yaml +++ b/data/event-schemas/schema/m.room_key.yaml @@ -23,6 +23,18 @@ properties: session_key: type: string description: The key to be exchanged. + shared_history: + type: boolean + description: |- + Whether the key may be forwarded to users who join the room after the + messages encrypted with this key have been sent. Defaults to + `false`. + + This can be set to `true` if the history visibility settings of the + room allow users to read events in the room from before they have + joined, that is, if the `m.room.history_visibility` state event is + `"world_readable"` or `"shared"`. For more information, see [Key + requests and forwarding](#key-requests-and-forwarding). required: - algorithm - room_id