From fdb611fa707ec2bd5646f31c1d24d4787f619304 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 26 Sep 2023 16:30:04 -0400 Subject: [PATCH] add spec for shared-history room keys --- .../modules/end_to_end_encryption.md | 62 +++++++++++++++---- .../definitions/key_backup_session_data.yaml | 8 +++ .../schema/m.forwarded_room_key.yaml | 9 +++ data/event-schemas/schema/m.room_key.yaml | 12 ++++ 4 files changed, 79 insertions(+), 12 deletions(-) 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 f2f75705..0af6f79e 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 +##### Key requests and forwarding -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`. +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. -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`. +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 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 18963cbe..baf748ab 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 10b8b652..831a976c 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 34ceb9ae..61145856 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