From fbbf3b81c56ee9b8294f13cb5d8d8865bc6e1c75 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 18 Oct 2022 18:02:27 -0400 Subject: [PATCH 1/7] add some e2ee clarifications --- .../modules/end_to_end_encryption.md | 17 ++++++++++++++++- content/client-server-api/modules/secrets.md | 10 +++++++--- .../schema/m.forwarded_room_key.yaml | 6 +++--- data/event-schemas/schema/m.room_key.yaml | 5 +++-- 4 files changed, 29 insertions(+), 9 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 10f21e86..05093b63 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -987,6 +987,17 @@ 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 IDs and cross-signing keys 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 precautions against this. For example, clients +should refer to keys using the public keys rather than only by the device +ID. Clients should also fix the keys that are being verified, and ensure that +they do not change in the course of verification. Clients may also display a +warning and refuse to verify a user when it detects 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. @@ -1587,7 +1598,11 @@ 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 a channel that ensures authenticity of the messages. +Practically speaking, this means that Megolm sessions must be received via Olm. + +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 new session key has a lower message index than the existing session key. diff --git a/content/client-server-api/modules/secrets.md b/content/client-server-api/modules/secrets.md index 6fe8586a..fcc36898 100644 --- a/content/client-server-api/modules/secrets.md +++ b/content/client-server-api/modules/secrets.md @@ -317,9 +317,13 @@ Example: ###### `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. +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, and this event must come from a device that the `m.secret.request` event +was originally sent to. | Parameter | Type | Description | |-------------|--------|--------------------------------------------------------------| 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: From 2395dd87c061f6b37f91857e5a410b4ef150abc2 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 1 Nov 2022 17:49:45 -0400 Subject: [PATCH 2/7] more clarifications, and move event definitions to yaml --- .../newsfragments/1294.clarification | 1 + .../modules/end_to_end_encryption.md | 9 ++++ content/client-server-api/modules/secrets.md | 47 +------------------ .../examples/m.secret.request.yaml | 6 +++ .../event-schemas/examples/m.secret.send.yaml | 4 ++ .../schema/m.secret.request.yaml | 40 ++++++++++++++++ data/event-schemas/schema/m.secret.send.yaml | 32 +++++++++++++ 7 files changed, 94 insertions(+), 45 deletions(-) create mode 100644 changelogs/client_server/newsfragments/1294.clarification create mode 100644 data/event-schemas/examples/m.secret.request.yaml create mode 100644 data/event-schemas/examples/m.secret.send.yaml create mode 100644 data/event-schemas/schema/m.secret.request.yaml create mode 100644 data/event-schemas/schema/m.secret.send.yaml 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 05093b63..cc4b1571 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 diff --git a/content/client-server-api/modules/secrets.md b/content/client-server-api/modules/secrets.md index fcc36898..38534a4e 100644 --- a/content/client-server-api/modules/secrets.md +++ b/content/client-server-api/modules/secrets.md @@ -292,49 +292,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 -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, and this event must come from a device that the `m.secret.request` event -was originally sent to. - -| 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..e510632d --- /dev/null +++ b/data/event-schemas/examples/m.secret.request.yaml @@ -0,0 +1,6 @@ +{ + "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..02c7ad6b --- /dev/null +++ b/data/event-schemas/examples/m.secret.send.yaml @@ -0,0 +1,4 @@ +{ + "request_id": "randomly_generated_id_9573", + "secret": "ThisIsASecretDon'tTellAnyone" +} 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..e9d72200 --- /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..0ec9d2b4 --- /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 + trusted. 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 From dd0f867fad009de61eaa13149e9d7a387cd76e39 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 1 Nov 2022 17:56:29 -0400 Subject: [PATCH 3/7] make examples agree with schema --- data/event-schemas/examples/m.secret.request.yaml | 11 +++++++---- data/event-schemas/examples/m.secret.send.yaml | 7 +++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/data/event-schemas/examples/m.secret.request.yaml b/data/event-schemas/examples/m.secret.request.yaml index e510632d..cce495fa 100644 --- a/data/event-schemas/examples/m.secret.request.yaml +++ b/data/event-schemas/examples/m.secret.request.yaml @@ -1,6 +1,9 @@ { - "name": "org.example.some.secret", - "action": "request", - "requesting_device_id": "ABCDEFG", - "request_id": "randomly_generated_id_9573" + "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 index 02c7ad6b..d872e5cd 100644 --- a/data/event-schemas/examples/m.secret.send.yaml +++ b/data/event-schemas/examples/m.secret.send.yaml @@ -1,4 +1,7 @@ { - "request_id": "randomly_generated_id_9573", - "secret": "ThisIsASecretDon'tTellAnyone" + "type": "m.secret.send", + "content": { + "request_id": "randomly_generated_id_9573", + "secret": "ThisIsASecretDon'tTellAnyone" + } } From d0cbd4c8ddab52409185e18a7bab30f13cc27d40 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 15 Nov 2022 18:17:20 -0500 Subject: [PATCH 4/7] Apply suggestions from code review Co-authored-by: Denis Kasak --- .../modules/end_to_end_encryption.md | 27 ++++++++++++------- .../schema/m.secret.request.yaml | 2 +- data/event-schemas/schema/m.secret.send.yaml | 4 +-- 3 files changed, 20 insertions(+), 13 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 cc4b1571..199a6662 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -996,16 +996,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 IDs and cross-signing keys 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 precautions against this. For example, clients -should refer to keys using the public keys rather than only by the device -ID. Clients should also fix the keys that are being verified, and ensure that -they do not change in the course of verification. Clients may also display a -warning and refuse to verify a user when it detects that the user has a device -with the same ID as a cross-signing key. +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 MAY refuse to verify a user when + it detects 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 diff --git a/data/event-schemas/schema/m.secret.request.yaml b/data/event-schemas/schema/m.secret.request.yaml index e9d72200..ac8142c1 100644 --- a/data/event-schemas/schema/m.secret.request.yaml +++ b/data/event-schemas/schema/m.secret.request.yaml @@ -26,7 +26,7 @@ properties: 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 + 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: diff --git a/data/event-schemas/schema/m.secret.send.yaml b/data/event-schemas/schema/m.secret.send.yaml index 0ec9d2b4..aec84456 100644 --- a/data/event-schemas/schema/m.secret.send.yaml +++ b/data/event-schemas/schema/m.secret.send.yaml @@ -9,8 +9,8 @@ description: |- 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 - trusted. This should be done by checking the sender key of the Olm session that - the event was sent over. + a trusted 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: From 19e29e36af9f32d09ad182e9d7956f3cfb718358 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 15 Nov 2022 19:17:49 -0500 Subject: [PATCH 5/7] more clarifications --- .../client-server-api/modules/end_to_end_encryption.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 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 199a6662..e4d8137d 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -1013,6 +1013,10 @@ against this. 3. Clients SHOULD also display a warning and MAY refuse to verify a user when it detects that the user has a device with the same ID as a cross-signing key. +4. If a client does not detect when a device has the same ID as a cross-signing + key, it MUST check key IDs being verified in a consistent order: it must + check if the key ID matches a cross-signing key first, and if not, treat it + as a device ID. 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 @@ -1615,8 +1619,8 @@ that they can decrypt future messages encrypted using this session. An messages. When a client receives a Megolm session, the client MUST ensure that the -session was received via a channel that ensures authenticity of the messages. -Practically speaking, this means that Megolm sessions must be received via Olm. +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: From 9fafadf311f2e37d649ea648d4179510ad8244bd Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 16 Nov 2022 09:00:35 -0500 Subject: [PATCH 6/7] Upgraded refusal to verify to a MUST Co-authored-by: Denis Kasak --- .../client-server-api/modules/end_to_end_encryption.md | 9 ++------- 1 file changed, 2 insertions(+), 7 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 e4d8137d..f68c2fce 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -1010,13 +1010,8 @@ against this. 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 MAY refuse to verify a user when - it detects that the user has a device with the same ID as a cross-signing - key. -4. If a client does not detect when a device has the same ID as a cross-signing - key, it MUST check key IDs being verified in a consistent order: it must - check if the key ID matches a cross-signing key first, and if not, treat it - as a device ID. +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 From 0f0caf582d9402212011bc38d9b8dff83eb6ca7b Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 16 Nov 2022 11:12:41 -0500 Subject: [PATCH 7/7] more clarifications --- .../modules/end_to_end_encryption.md | 21 +++++++++++++------ data/event-schemas/schema/m.secret.send.yaml | 2 +- 2 files changed, 16 insertions(+), 7 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 f68c2fce..62a8f932 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -1203,8 +1203,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 @@ -1234,9 +1235,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 @@ -1619,7 +1626,9 @@ 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/data/event-schemas/schema/m.secret.send.yaml b/data/event-schemas/schema/m.secret.send.yaml index aec84456..ecf22183 100644 --- a/data/event-schemas/schema/m.secret.send.yaml +++ b/data/event-schemas/schema/m.secret.send.yaml @@ -9,7 +9,7 @@ description: |- 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 trusted device owned by the recipient. This should be done by checking the + 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: