From 6b7268ab472bf4dd68abb27b24bea5e5d4401136 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Fri, 28 Mar 2025 12:52:02 +0100 Subject: [PATCH 1/4] MSC4147: Including device keys with Olm-encrypted events Signed-off-by: Johannes Marbach --- .../modules/end_to_end_encryption.md | 37 +++----- .../definitions/olm_payload.yaml | 87 +++++++++++++++++++ 2 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 data/api/client-server/definitions/olm_payload.yaml 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 49b053f6..29e3ab50 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -1512,20 +1512,7 @@ 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. @@ -1536,15 +1523,19 @@ 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. +Clients must ensure that the sending 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. To perform +this check, 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 under the `sender_device_keys` +property. Additionally, clients MUST also verify the signature of the keys. +If `sender_device_keys` is absent, clients MUST retrieve the sender's +keys from [`/keys/query`](#post_matrixclientv3keysquery) instead. This +will not allow them to verify key ownership if the sending device was +logged out or had its keys reset since sending the event. Therefore, +clients MUST populate the `sender_device_keys` property when sending +events themselves. If a client has multiple sessions established with another device, it should use the session from which it last received and successfully 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..1d8e5055 --- /dev/null +++ b/data/api/client-server/definitions/olm_payload.yaml @@ -0,0 +1,87 @@ +# 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. +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:": "", + } + } + } +} From 00fdf603a9df72661dd7b0a9eaae4aeb1adccb8b Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Fri, 28 Mar 2025 12:55:10 +0100 Subject: [PATCH 2/4] Add changelog --- changelogs/client_server/newsfragments/2122.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/client_server/newsfragments/2122.feature 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). From 6656f00beef16bb08866d35b32daaeb3854a0023 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Fri, 28 Mar 2025 13:33:18 +0100 Subject: [PATCH 3/4] Add missing x-addedInMatrixVersion --- data/api/client-server/definitions/olm_payload.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/data/api/client-server/definitions/olm_payload.yaml b/data/api/client-server/definitions/olm_payload.yaml index 1d8e5055..8bac91e0 100644 --- a/data/api/client-server/definitions/olm_payload.yaml +++ b/data/api/client-server/definitions/olm_payload.yaml @@ -39,6 +39,7 @@ properties: sender_device_keys: $ref: device_keys.yaml description: The sender's device keys. + x-addedInMatrixVersion: "1.15" required: - type - content From 3f3c0ca0ba67437146333bbcd1cf9b70b4cb9d11 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Mon, 26 May 2025 11:05:36 +0200 Subject: [PATCH 4/4] Expand description of validation and verification --- .../modules/end_to_end_encryption.md | 74 ++++++++++++++----- 1 file changed, 56 insertions(+), 18 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 29e3ab50..32ad8fa6 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -1517,25 +1517,63 @@ The plaintext payload is of the form: 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. +###### Validation of incoming decrypted events -Clients must ensure that the sending 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. To perform -this check, 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 under the `sender_device_keys` -property. Additionally, clients MUST also verify the signature of the keys. -If `sender_device_keys` is absent, clients MUST retrieve the sender's -keys from [`/keys/query`](#post_matrixclientv3keysquery) instead. This -will not allow them to verify key ownership if the sending device was -logged out or had its keys reset since sending the event. Therefore, -clients MUST populate the `sender_device_keys` property when sending -events themselves. +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 + +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 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. If a client has multiple sessions established with another device, it should use the session from which it last received and successfully