diff --git a/changelogs/client_server/newsfragments/1294.clarification b/changelogs/client_server/newsfragments/1294.clarification new file mode 100644 index 00000000..8132e060 --- /dev/null +++ b/changelogs/client_server/newsfragments/1294.clarification @@ -0,0 +1 @@ +Clarify parts of the end-to-end encryption sections. 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 1cba8a22..e396b409 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -510,6 +510,15 @@ could also send that message. As well, the order of the | | | | ``` +In contrast with the case of using to-devices messages, when using in-room +messages, Alice only sends one request event (an event with type +`m.room.message` with `msgtype: m.key.verification.request`, rather than an +event with type `m.key.verification.request`), to the room. In addition, Alice +does not send an `m.key.verification.cancel` event to tell Bob's other devices +that the request as already been accepted; instead, when Bob's other devices +see his `m.key.verification.ready` event, they will know that the request has +already been accepted, and that they should ignore the request. + When using in-room messages and the room has encryption enabled, clients should ensure that encryption does not hinder the verification. For example, if the verification messages are encrypted, clients must ensure that all the @@ -990,6 +999,23 @@ If a user's client sees that any other user has changed their master key, that client must notify the user about the change before allowing communication between the users to continue. +Since device key IDs (`ed25519:DEVICE_ID`) and cross-signing key IDs +(`ed25519:PUBLIC_KEY`) occupy the same namespace, clients must ensure that they +use the correct keys when verifying. + +While servers MUST not allow devices to have the same IDs as cross-signing +keys, a malicious server could construct such a situation, so clients must not +rely on the server being well-behaved and should take the following precautions +against this. + +1. Clients MUST refer to keys by their public keys during the verification + process, rather than only by the key ID. +2. Clients MUST fix the keys that are being verified at the beginning of the + verification process, and ensure that they do not change in the course of + verification. +3. Clients SHOULD also display a warning and MUST refuse to verify a user when + they detect that the user has a device with the same ID as a cross-signing key. + A user's user-signing and self-signing keys are intended to be easily replaceable if they are compromised by re-issuing a new key signed by the user's master key and possibly by re-verifying devices or users. @@ -1180,8 +1206,9 @@ withheld](#reporting-that-decryption-keys-are-withheld). {{% boxes/note %}} Key sharing can be a big attack vector, thus it must be done very -carefully. A reasonable strategy is for a user's client to only send -keys requested by the verified devices of the same user. +carefully. Clients should only send keys requested by the verified devices +of the same user, and should only request and accept forwarded keys from +verified devices of the same user. {{% /boxes/note %}} ##### Server-side key backups @@ -1211,9 +1238,15 @@ can be deleted using [DELETE /\_matrix/client/v3/room\_keys/keys](#delete_matrix one of its variants. Clients must only store keys in backups after they have ensured that the -`auth_data` is trusted, either by checking the signatures on it, or by -deriving the public key from a private key that it obtained from a -trusted source. +`auth_data` is trusted. This can be done either by: + +- checking that it is signed by the user's [master cross-signing + key](#cross-signing) or by a verified device belonging to the same user, or +- by deriving the public key from a private key that it obtained from a trusted + source. Trusted sources for the private key include the user entering the + key, retrieving the key stored in [secret storage](#secret-storage), or + obtaining the key via [secret sharing](#sharing) from a verified device + belonging to the same user. When a client uploads a key for a session that the server already has a key for, the server will choose to either keep the existing key or @@ -1590,9 +1623,15 @@ that they can decrypt future messages encrypted using this session. An `m.room_key` events sent by other devices in order to decrypt their messages. -When a client is updating a Megolm session (room key) in its store, the client MUST ensure: +When a client receives a Megolm session, the client MUST ensure that the +session was received via an Olm channel, in order to ensure the authenticity of +the messages. + +When a client is updating a Megolm session in its store, the client MUST ensure: -* that the updated session data comes from a trusted source. +* that the updated session data comes from a trusted source, such as via a + `m.forwarded_room_key` event from a verified device belonging to the same + user, or from a `m.room_key` event. * that the new session key has a lower message index than the existing session key. #### Protocol definitions diff --git a/content/client-server-api/modules/secrets.md b/content/client-server-api/modules/secrets.md index 7c174bfa..2d12d488 100644 --- a/content/client-server-api/modules/secrets.md +++ b/content/client-server-api/modules/secrets.md @@ -289,45 +289,6 @@ confirm sharing the secret. ##### Event definitions -###### `m.secret.request` +{{% event event="m.secret.request" %}} -Sent by a client to request a secret from another device or to cancel a -previous request. It is sent as an unencrypted to-device event. - -| Parameter | Type | Description | -|-----------------------|--------|----------------------------------------------------------------------------------------| -| name | string | Required if ``action`` is ``request``. The name of the secret that is being requested. | -| action | enum | **Required.** One of ["request", "request_cancellation"]. | -| requesting_device_id | string | **Required.** The ID of the device requesting the secret. | -| request_id | string | **Required.** A random string uniquely identifying (with respect to the requester and the target) the target for a secret. If the secret is requested from multiple devices at the same time, the same ID may be used for every target. The same ID is also used in order to cancel a previous request. | - -Example: - -```json -{ - "name": "org.example.some.secret", - "action": "request", - "requesting_device_id": "ABCDEFG", - "request_id": "randomly_generated_id_9573" -} -``` - -###### `m.secret.send` - -Sent by a client to share a secret with another device, in response to -an `m.secret.request` event. It must be encrypted as an -`m.room.encrypted` event, then sent as a to-device event. - -| Parameter | Type | Description | -|-------------|--------|--------------------------------------------------------------| -| request_id | string | **Required.** The ID of the request that this a response to. | -| secret | string | **Required.** The contents of the secret. | - -Example: - -```json -{ - "request_id": "randomly_generated_id_9573", - "secret": "ThisIsASecretDon'tTellAnyone" -} -``` +{{% event event="m.secret.send" %}} diff --git a/data/event-schemas/examples/m.secret.request.yaml b/data/event-schemas/examples/m.secret.request.yaml new file mode 100644 index 00000000..cce495fa --- /dev/null +++ b/data/event-schemas/examples/m.secret.request.yaml @@ -0,0 +1,9 @@ +{ + "type": "m.secret.request", + "content": { + "name": "org.example.some.secret", + "action": "request", + "requesting_device_id": "ABCDEFG", + "request_id": "randomly_generated_id_9573" + } +} diff --git a/data/event-schemas/examples/m.secret.send.yaml b/data/event-schemas/examples/m.secret.send.yaml new file mode 100644 index 00000000..d872e5cd --- /dev/null +++ b/data/event-schemas/examples/m.secret.send.yaml @@ -0,0 +1,7 @@ +{ + "type": "m.secret.send", + "content": { + "request_id": "randomly_generated_id_9573", + "secret": "ThisIsASecretDon'tTellAnyone" + } +} diff --git a/data/event-schemas/schema/m.forwarded_room_key.yaml b/data/event-schemas/schema/m.forwarded_room_key.yaml index 71ea6690..10b8b652 100644 --- a/data/event-schemas/schema/m.forwarded_room_key.yaml +++ b/data/event-schemas/schema/m.forwarded_room_key.yaml @@ -3,9 +3,9 @@ allOf: - $ref: core-event-schema/event.yaml description: |- - This event type is used to forward keys for end-to-end encryption. Typically - it is encrypted as an `m.room.encrypted` event, then sent as a [to-device](/client-server-api/#send-to-device-messaging) - event. + This event type is used to forward keys for end-to-end encryption. + It is encrypted as an `m.room.encrypted` event using [Olm](#molmv1curve25519-aes-sha2), + then sent as a [to-device](/client-server-api/#send-to-device-messaging) event. properties: content: properties: diff --git a/data/event-schemas/schema/m.room_key.yaml b/data/event-schemas/schema/m.room_key.yaml index 6eebbec5..34ceb9ae 100644 --- a/data/event-schemas/schema/m.room_key.yaml +++ b/data/event-schemas/schema/m.room_key.yaml @@ -3,8 +3,9 @@ allOf: - $ref: core-event-schema/event.yaml description: |- - This event type is used to exchange keys for end-to-end encryption. Typically - it is encrypted as an `m.room.encrypted` event, then sent as a [to-device](/client-server-api/#send-to-device-messaging) event. + This event type is used to exchange keys for end-to-end encryption. + It is encrypted as an `m.room.encrypted` event using [Olm](#molmv1curve25519-aes-sha2), + then sent as a [to-device](/client-server-api/#send-to-device-messaging) event. properties: content: properties: diff --git a/data/event-schemas/schema/m.secret.request.yaml b/data/event-schemas/schema/m.secret.request.yaml new file mode 100644 index 00000000..ac8142c1 --- /dev/null +++ b/data/event-schemas/schema/m.secret.request.yaml @@ -0,0 +1,40 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml +description: |- + Sent by a client to request a secret from another device or to cancel a + previous request. It is sent as an unencrypted to-device event. +properties: + content: + properties: + name: + type: string + description: |- + Required if `action` is `request`. The name of the secret that is + being requested. + action: + type: string + enum: + - request + - request_cancellation + requesting_device_id: + type: string + description: |- + The ID of the device requesting the secret. + request_id: + type: string + description: |- + A random string uniquely identifying (with respect to the requester + and the target) the target for a secret. If the secret is requested + from multiple devices at the same time, the same ID MAY be used for + every target. The same ID is also used in order to cancel a previous + request. + required: + - action + - requesting_device_id + - request_id + type: + enum: + - m.secret.request + type: string +type: object diff --git a/data/event-schemas/schema/m.secret.send.yaml b/data/event-schemas/schema/m.secret.send.yaml new file mode 100644 index 00000000..ecf22183 --- /dev/null +++ b/data/event-schemas/schema/m.secret.send.yaml @@ -0,0 +1,32 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml +description: |- + Sent by a client to share a secret with another device, in response to an + `m.secret.request` event. It must be encrypted as an `m.room.encrypted` event + using [Olm](#molmv1curve25519-aes-sha2), then sent as a to-device event. + + The `request_id` must match the ID previously given in an `m.secret.request` + event. The recipient must ensure that this event comes from a device that the + `m.secret.request` event was originally sent to, and that the device is + a verified device owned by the recipient. This should be done by checking the + sender key of the Olm session that the event was sent over. +properties: + content: + properties: + request_id: + type: string + description: |- + The ID of the request that this is a response to. + secret: + type: string + description: |- + The contents of the secret + required: + - request_id + - secret + type: + enum: + - m.secret.send + type: string +type: object