diff --git a/changelogs/client_server/newsfragments/2122.feature b/changelogs/client_server/newsfragments/2122.feature new file mode 100644 index 00000000..0e299bad --- /dev/null +++ b/changelogs/client_server/newsfragments/2122.feature @@ -0,0 +1 @@ +Include device keys with Olm-encrypted events as per [MSC4147](https://github.com/matrix-org/matrix-spec-proposals/pull/4147). 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 298f6726..2c275089 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -1512,40 +1512,11 @@ message. The plaintext payload is of the form: -```json -{ - "type": "", - "content": "", - "sender": "", - "recipient": "", - "recipient_keys": { - "ed25519": "" - }, - "keys": { - "ed25519": "" - } -} -``` +{{% definition path="api/client-server/definitions/olm_payload" %}} The type and content of the plaintext message event are given in the payload. -Other properties are included in order to prevent an attacker from -publishing someone else's curve25519 keys as their own and subsequently -claiming to have sent messages which they didn't. `sender` must -correspond to the user who sent the event, `recipient` to the local -user, and `recipient_keys` to the local ed25519 key. - -Clients must confirm that the `sender_key` property in the cleartext -`m.room.encrypted` event body, and the `keys.ed25519` property in the -decrypted plaintext, match the keys returned by -[`/keys/query`](#post_matrixclientv3keysquery) for -the given user. Clients must also verify the signature of the keys from the -`/keys/query` response. Without this check, a client cannot be sure that -the sender device owns the private part of the ed25519 key it claims to -have in the Olm payload. This is crucial when the ed25519 key corresponds -to a verified device. - If a client has multiple sessions established with another device, it should use the session from which it last received and successfully decrypted a message. For these purposes, a session that has not received @@ -1555,6 +1526,68 @@ maximum number of olm sessions that it will maintain for each device, and expiring sessions on a Least Recently Used basis. The maximum number of olm sessions maintained per device should be at least 4. +###### Validation of incoming decrypted events + +{{% changed-in v="1.15" %}} Existing checks made more explicit, and checks for `sender_device_keys` added. + +After decrypting an incoming encrypted event, clients MUST apply the +following checks: + +1. The `sender` property in the decrypted content must match the + `sender` of the event. +2. The `keys.ed25519` property in the decrypted content must match + the `sender_key` property in the cleartext `m.room.encrypted` + event body. +3. The `recipient` property in the decrypted content must match + the user ID of the local user. +4. The `recipient_keys.ed25519` property in the decrypted content + must match the client device's [Ed25519 signing key](#device-keys). +5. Where `sender_device_keys` is present in the decrypted content: + 1. `sender_device_keys.user_id` must also match the `sender` + of the event. + 2. `sender_device_keys.keys.ed25519:` must also match + the `sender_key` property in the cleartext `m.room.encrypted` + event body. + 3. `sender_device_keys.keys.curve25519:` must match + the Curve25519 key used to establish the Olm session. + 4. The `sender_device_keys` structure must have a valid signature + from the key with ID `ed25519:` (i.e., the sending + device's Ed25519 key). + +Any event that does not comply with these checks MUST be discarded. + +###### Verification of the sending user for incoming events + +{{% added-in v="1.15" %}} + +In addition, for each Olm session, clients MUST verify that the +Curve25519 key used to establish the Olm session does indeed belong +to the claimed `sender`. This requires a signed "device keys" structure +for that Curve25519 key, which can be obtained in one of two ways: + +1. An Olm message may be received with a `sender_device_keys` property + in the decrypted content. +2. The keys are returned via a [`/keys/query`](#post_matrixclientv3keysquery) + request. Note that both the Curve25519 key **and** the Ed25519 key in + the returned device keys structure must match those used in an + Olm-encrypted event as above. (In particular, the Ed25519 key must + be present in the **encrypted** content of an Olm-encrypted event + to prevent an attacker from claiming another user's Curve25519 key + as their own.) + +Ownership of the Curve25519 key is then established in one of two ways: + +1. Via [cross-signing](#cross-signing). For this to be sufficient, the + device keys structure must be signed by the sender's self-signing key, + and that self-signing key must itself have been validated (either via + [explicit verification](#device-verification) or a "trust on first use" (TOFU) mechanism). +2. Via explicit verification of the device's Ed25519 signing key, as + contained in the device keys structure. This is no longer recommended. + +A failure to complete these verifications does not necessarily mean that +the session is bogus; however it is the case that there is no proof that +the claimed sender is accurate, and the user should be warned accordingly. + ###### Recovering from undecryptable messages Occasionally messages may be undecryptable by clients due to a variety diff --git a/data/api/client-server/definitions/olm_payload.yaml b/data/api/client-server/definitions/olm_payload.yaml new file mode 100644 index 00000000..8bac91e0 --- /dev/null +++ b/data/api/client-server/definitions/olm_payload.yaml @@ -0,0 +1,88 @@ +# Copyright 2025 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: OlmPayload +description: |- + The plaintext payload of Olm message events. +properties: + type: + type: string + description: The type of the event. + content: + type: object + description: The event content. + sender: + type: string + description: The user ID of the event sender. + recipient: + type: string + description: The user ID of the intended event recipient. + recipient_keys: + description: The recipient's signing keys of the encrypted event. + $ref: "#/components/schemas/SigningKeys" + keys: + $ref: "#/components/schemas/SigningKeys" + description: The sender's signing keys of the encrypted event. + sender_device_keys: + $ref: device_keys.yaml + description: The sender's device keys. + x-addedInMatrixVersion: "1.15" +required: + - type + - content + - sender + - recipient + - recipient_keys + - keys +components: + schemas: + SigningKeys: + type: object + title: SigningKeys + description: Public keys used for an `m.olm.v1.curve25519-aes-sha2` event. + properties: + ed25519: + type: string + description: The Ed25519 public key encoded using unpadded base64. + required: + - ed25519 +example: { + "type": "", + "content": "", + "sender": "", + "recipient": "", + "recipient_keys": { + "ed25519": "" + }, + "keys": { + "ed25519": "" + }, + "sender_device_keys": { + "algorithms": ["", ""], + "user_id": "", + "device_id": "", + "keys": { + "ed25519:": "", + "curve25519:": "" + }, + "signatures": { + "": { + "ed25519:": "", + "ed25519:": "", + } + } + } +}