mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-07-29 17:17:47 +02:00
Basic spec for history sharing
This commit is contained in:
parent
f48bf2e9eb
commit
1efc0623fa
|
|
@ -1547,6 +1547,143 @@ objects described as follows:
|
||||||
|
|
||||||
{{% definition path="api/client-server/definitions/megolm_export_session_data" %}}
|
{{% definition path="api/client-server/definitions/megolm_export_session_data" %}}
|
||||||
|
|
||||||
|
#### Sharing keys between users
|
||||||
|
|
||||||
|
{{% added-in v="1.19" %}}
|
||||||
|
|
||||||
|
When Alice invites Bob to an encrypted room, she might want Bob to have access
|
||||||
|
to messages that were previously sent in that room, subject to the [history
|
||||||
|
visibility](#room-history-visibility) setting of the room.
|
||||||
|
|
||||||
|
Alice does this by constructing an [encrypted key
|
||||||
|
bundle](#construction-and-sharing-of-the-key-bundle) and sharing it with Bob
|
||||||
|
before inviting him.
|
||||||
|
|
||||||
|
##### Shareable encryption sessions
|
||||||
|
|
||||||
|
Only room keys which were marked as "shareable" by the creator of the
|
||||||
|
encryption session should be shared with new users.
|
||||||
|
|
||||||
|
When Alice wants to send a message in the room she shares with Bob, she first
|
||||||
|
checks the [history visibility](#room-history-visibility) state of the
|
||||||
|
room. If it is `shared` or `world_readable`, then when she sends the Megolm
|
||||||
|
keys to Bob via an [`m.room_key`](#mroom_key) message, she sets
|
||||||
|
`shared_history` to `true`.
|
||||||
|
|
||||||
|
If the history visibility changes in a way that would affect the
|
||||||
|
`shared_history` flag (i.e., it changes from `joined` or `invited` to `shared`
|
||||||
|
or `world_readable`, or vice versa), then clients MUST rotate their outbound
|
||||||
|
megolm session before sending more messages.
|
||||||
|
|
||||||
|
Clients SHOULD show a visual indication to users that their encrypted messages
|
||||||
|
may be shared with future room members in this way.
|
||||||
|
|
||||||
|
Recipients SHOULD keep a record of the `shared_history` flag for each
|
||||||
|
encryption session. The state of the flag is also saved in the
|
||||||
|
[`BackedUpSessionData`](#definition-backedupsessiondata) type in key backups,
|
||||||
|
and the [`ExportedSessionData`](#definition-exportedsessiondata) type in key
|
||||||
|
exports.
|
||||||
|
|
||||||
|
A session is therefore considered as "shareable" if any of the following
|
||||||
|
conditions are satisfied:
|
||||||
|
|
||||||
|
* The client created the session itself, when the `history_visibility` state
|
||||||
|
was set to `shared` or `world_readable`.
|
||||||
|
* The keys to the session were received from an [`m.room_key`](#mroom_key)
|
||||||
|
message with `shared_history` set to `true`.
|
||||||
|
* The keys to the session were loaded from key backup, and the
|
||||||
|
[`BackedUpSessionData`](#definition-backedupsessiondata) structure had
|
||||||
|
`shared_history` set to `true`.
|
||||||
|
* The keys to the session were loaded from a key export, and the
|
||||||
|
[`ExportedSessionData`](#definition-exportedsessiondata) structure had
|
||||||
|
`shared_history` set to `true`.
|
||||||
|
* The keys were received as part of a
|
||||||
|
[`RoomKeyBundle`](#definition-roomkeybundle).
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
Tracking shareable sessions in this way prevents an attack where a malicious
|
||||||
|
homeserver can incorrectly flag history as shared, without telling the sender
|
||||||
|
of the messages. It also ensures that a user that sends an encrypted message does
|
||||||
|
so in the knowledge that the message may be shared with new members in the
|
||||||
|
room.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
##### Construction and sharing of the key bundle
|
||||||
|
|
||||||
|
Alice MAY choose not to share any room history (even messages sent when the
|
||||||
|
history visibity setting would allow sharing) if the current history
|
||||||
|
visibility setting does not allow sharing (i.e. if `history_visibility` is
|
||||||
|
set to `invited` or `joined`).
|
||||||
|
|
||||||
|
Otherwise, before inviting Bob to a room, Alice constructs and sends a key bundle as follows:
|
||||||
|
|
||||||
|
1. Alice SHOULD ensure that she has downloaded all keys relevant to the room
|
||||||
|
from [server-side key backup](#server-side-key-backups), if she is using it.
|
||||||
|
|
||||||
|
2. Alice constructs a [`RoomKeyBundle`](#definition-roomkeybundle) structure,
|
||||||
|
containing the sessions she is aware of in the room. Alice SHOULD include
|
||||||
|
only [shareable encryption sessions](#shareable-encryption-sessions) in the
|
||||||
|
`room_keys` section of the structure; other sessions should be listed un the
|
||||||
|
with `withheld` section.
|
||||||
|
|
||||||
|
3. Alice serialises the `RoomKeyBundle` as JSON.
|
||||||
|
|
||||||
|
4. Alice encrypts and uploads the serialised JSON in the same way as when
|
||||||
|
[sending an encrypted attachment](#sending-encrypted-attachments).
|
||||||
|
|
||||||
|
5. Alice ensures she has an up-to-date list of Bob's devices (performing a
|
||||||
|
[`/keys/query`](#post_matrixclientv3keysquery) request if necessary).
|
||||||
|
|
||||||
|
6. For each of Bob's devices which are correctly
|
||||||
|
[cross-signed](#cross-signing), Alice encrypts and sends an
|
||||||
|
[`m.room_key_bundle`](#mroom_key_bundle) message.
|
||||||
|
|
||||||
|
Alice MUST NOT send the `m.room.key_bundle` message to devices that have not
|
||||||
|
been correctly cross-signed by their owner, due to the risk of sharing
|
||||||
|
significant amounts of encrypted content with an attacker-controlled device.
|
||||||
|
|
||||||
|
{{% definition path="api/client-server/definitions/room_key_bundle" %}}
|
||||||
|
|
||||||
|
{{% event event="m.room_key_bundle" %}}
|
||||||
|
|
||||||
|
##### Receiving a key bundle event
|
||||||
|
|
||||||
|
When Bob's client receives an `m.room_key_bundle` event from Alice, there are two possibilities:
|
||||||
|
|
||||||
|
* If Bob has recently accepted an invite to the room from Alice, the client
|
||||||
|
should immediately download and decrypt the key bundle and start processing
|
||||||
|
it. Note, however, that this process must be resilient to Bob's client being
|
||||||
|
restarted before the download/import completes.
|
||||||
|
|
||||||
|
The definition of "recently" is left up to clients. (They should consider
|
||||||
|
balancing the needs of (a) a user that closes their client just after
|
||||||
|
joining a room but before the bundle is imported, against (b) the overhead
|
||||||
|
of attempting to download a key bundle on every startup. 24 hours is a
|
||||||
|
recommended time limit.)
|
||||||
|
|
||||||
|
* Otherwise, Bob's client should store the details of the key bundle but not
|
||||||
|
download it immediately. If he later accepts an invite to the room from
|
||||||
|
Alice, his client downloads and processes the bundle at that point.
|
||||||
|
|
||||||
|
Delaying the download in this way avoids a potential DoS vector in which an
|
||||||
|
attacker can cause the victim to download a large quantity of useless data.
|
||||||
|
|
||||||
|
Once Bob has downloaded and decrypted the key bundle, the sessions are imported
|
||||||
|
as they would be when importing a [key export](#key-exports); however:
|
||||||
|
|
||||||
|
* Only keys for the relevant room should be imported. Keys for other rooms
|
||||||
|
SHOULD be ignored.
|
||||||
|
|
||||||
|
* Bob's client MUST remember who he received the keys from (Alice, in this
|
||||||
|
case), and MUST show that information to the user, since he has only that
|
||||||
|
user's word for the authenticity of those sessions.
|
||||||
|
|
||||||
|
Client implementations should note that server implementations may delete or
|
||||||
|
expire old media that appears unused. They must therefore gracefully handle
|
||||||
|
download failures due to the key bundle having expired (typically by just
|
||||||
|
giving up on the attempt to download the bundle, though they could also warn
|
||||||
|
the user.)
|
||||||
|
|
||||||
#### Messaging Algorithms
|
#### Messaging Algorithms
|
||||||
|
|
||||||
##### Messaging Algorithm Names
|
##### Messaging Algorithm Names
|
||||||
|
|
|
||||||
104
data/api/client-server/definitions/room_key_bundle.yaml
Normal file
104
data/api/client-server/definitions/room_key_bundle.yaml
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
# Copyright 2026 The Matrix.org Foundation C.I.C.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
type: object
|
||||||
|
title: RoomKeyBundle
|
||||||
|
description: |
|
||||||
|
A bundle of room keys and withheld indications, sent from one user to another, to share encrypted history.
|
||||||
|
|
||||||
|
A single session MUST NOT appear in both the `room_keys` and `withheld`
|
||||||
|
sections. Handling such malformed bundles as a receiving client is
|
||||||
|
implementation-defined.
|
||||||
|
properties:
|
||||||
|
room_keys:
|
||||||
|
description: |
|
||||||
|
The room keys to be shared with the recipient of the bundle.
|
||||||
|
|
||||||
|
The data type is similar to the format used for [key exports](/client-server-api/#key-export-format),
|
||||||
|
but omits `forwarding_curve25519_key_chain` and `shared_history`.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
title: HistoricRoomKey
|
||||||
|
description: |-
|
||||||
|
The format of a session key, when shared as part of a `RoomKeyBundle`.
|
||||||
|
properties:
|
||||||
|
algorithm:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The end-to-end message encryption algorithm that the key is for. Must be `m.megolm.v1.aes-sha2`.
|
||||||
|
example: "m.megolm.v1.aes-sha2"
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The room where the session is used.
|
||||||
|
example: "!Cuyf34gef24t:localhost"
|
||||||
|
sender_claimed_keys:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A map from algorithm name (`ed25519`) to the Ed25519 signing key of
|
||||||
|
the device which initiated the session originally, according to the
|
||||||
|
creator of this key bundle.
|
||||||
|
example: { "ed25519": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y" }
|
||||||
|
sender_key:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
Unpadded base64-encoded device Curve25519 key, of the device which
|
||||||
|
initiated the session originally, according to the creator of this
|
||||||
|
key bundle.
|
||||||
|
example: "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU"
|
||||||
|
session_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The Megolm session ID.
|
||||||
|
example: "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
|
||||||
|
session_key:
|
||||||
|
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).
|
||||||
|
example: "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..."
|
||||||
|
required:
|
||||||
|
- algorithm
|
||||||
|
- room_id
|
||||||
|
- sender_claimed_keys
|
||||||
|
- sender_key
|
||||||
|
- session_id
|
||||||
|
- session_key
|
||||||
|
withheld:
|
||||||
|
description: |-
|
||||||
|
The room keys that the creator of the bundle is choosing not to share
|
||||||
|
with the recipient.
|
||||||
|
|
||||||
|
The `code` will normally be `m.history_not_shared`, to indicate that the
|
||||||
|
recipient isn't allowed to receive the key.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
allOf:
|
||||||
|
- $ref: "../../../event-schemas/schema/components/room_key_withheld_content.yaml"
|
||||||
|
- title: RoomKeyWithheld
|
||||||
|
example: {
|
||||||
|
"algorithm": "m.megolm.v1.aes-sha2",
|
||||||
|
"code": "m.history_not_shared",
|
||||||
|
"reason": "History not shared",
|
||||||
|
"room_id": "!Cuyf34gef24t:localhost",
|
||||||
|
"sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
|
||||||
|
"session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
21
data/event-schemas/examples/m.room_key_bundle.yaml
Normal file
21
data/event-schemas/examples/m.room_key_bundle.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"type": "m.room_key_bundle",
|
||||||
|
"content": {
|
||||||
|
"room_id": "!Cuyf34gef24t:localhost",
|
||||||
|
"file": {
|
||||||
|
"v": "v2",
|
||||||
|
"url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
|
||||||
|
"key": {
|
||||||
|
"alg": "A256CTR",
|
||||||
|
"ext": true,
|
||||||
|
"k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0",
|
||||||
|
"key_ops": ["encrypt","decrypt"],
|
||||||
|
"kty": "oct"
|
||||||
|
},
|
||||||
|
"iv": "w+sE15fzSc0AAAAAAAAAAA",
|
||||||
|
"hashes": {
|
||||||
|
"sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
data/event-schemas/schema/m.room_key_bundle.yaml
Normal file
40
data/event-schemas/schema/m.room_key_bundle.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
This event type is used to share a bundle of room keys when inviting a new user to the room.
|
||||||
|
|
||||||
|
It is encrypted as an
|
||||||
|
[`m.room.encrypted`](/client-server-api/#mroomencrypted) [to-device
|
||||||
|
event](/client-server-api/#send-to-device-messaging) using
|
||||||
|
[Olm](/client-server-api/#molmv1curve25519-aes-sha2).
|
||||||
|
|
||||||
|
The `sender_device_keys` property in the [Olm
|
||||||
|
plaintext](/client-server-api/#definition-olmpayload) MUST be
|
||||||
|
populated. Recipients SHOULD ignore `m.room_key_bundle` messages which omit
|
||||||
|
them.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: The room to which the keys in the key bundle relate.
|
||||||
|
file:
|
||||||
|
description: |-
|
||||||
|
An [EncryptedFile](/client-server-api/#definition-encryptedfile)
|
||||||
|
structure. The location and decryption keys for the encrypted
|
||||||
|
[`RoomKeyBundle`](/client-server-api/#definition-roomkeybundle).
|
||||||
|
title: EncryptedFile
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- room_id
|
||||||
|
- file
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.room_key_bundle
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
Loading…
Reference in a new issue