From d56527ba95d1897c2589f26c6122810edddf6a55 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 18 May 2021 16:50:09 -0600 Subject: [PATCH 01/12] Encrypted appservices --- proposals/0000-encrypted-appservices.md | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 proposals/0000-encrypted-appservices.md diff --git a/proposals/0000-encrypted-appservices.md b/proposals/0000-encrypted-appservices.md new file mode 100644 index 00000000000..952910e1eaf --- /dev/null +++ b/proposals/0000-encrypted-appservices.md @@ -0,0 +1,82 @@ +# MSC0000: Encrypted Appservices + +Presently, appservices in Matrix are capable of attaching themselves to a homeserver for high-traffic +bot-like usecases, such as bridging and operationally expensive bots. Traditionally, these appservices +only work in unencrypted rooms due to not having enough context on the encryption state to actually +function properly. + +This MSC targets the missing bits to support encryption at the appservice level: other MSCs, such as +[MSC2409](https://github.com/matrix-org/matrix-doc/pull/2409) and [MSC2778](https://github.com/matrix-org/matrix-doc/pull/2778) +give appservices foundational pieces to get device IDs and to-device messages, as required by encryption. + +## Proposal + +This proposal takes inspiration from [MSC2409](https://github.com/matrix-org/matrix-doc/pull/2409) by +defining a new set of keys on the appservice `/transactions` endpoint, similar to sync: + +```json5 +{ + "events": [ + // as defined today + ], + "ephemeral": [ + // MSC2409 + ], + "device_lists": { + "changed": ["@alice:example.org"], + "left": ["@bob:example.com"] + }, + "device_one_time_keys_count": { + "@_irc_bob:example.org": { + "curve25519": 10, + "signed_curve25519": 20 + } + } +} +``` + +These fields are heavily inspired by [the extensions to /sync](https://matrix.org/docs/spec/client_server/r0.6.1#id84) +in the client-server API. + +Both new fields can be omitted if there are no changes for the appservice to handle. For +`device_one_time_keys_count`, the format is slightly different from the client-server API to better +map the appservice's user namespace users to the counts. Users in the namespace without keys or +which have unchanged keys since the last transaction can be omitted. + +Like MSC2409, any user the appservice would be considered "interested" in (user in the appservice's +namespace, or sharing a room with an appservice user/namespaced room) would qualify for the device +list changes section. + +## Potential issues + +Servers would have to track and send this information to appservices, however this is still perceived +to be more performant than appservices using potentionally thousands of `/sync` streams. + +Appservices additionally cannot opt-in (or out) of this functionality unlike with MSC2409. It is +expected that servers will optimize for not including/calculating the fields if the appservice has +no interest in the information. Specifically, appservices which don't have any keys under their user +namespace can be assumed to not need device list changes and thus can be optimized out. + +## Alternatives + +An endpoint for appservices to poll could work, though this is extra work for the appservice and would +likely need pagination and such, which is all heavyweight for the server. Instead, having the server +batch up updates and send them to the appservice is likely faster. + +## Security considerations + +None relevant - this is the same information the appservice would get if it spawned `/sync` streams for +all the users in its namespace. + +## Unstable prefix + +While this MSC is not considered stable for implementation, implementations should use `org.matrix.msc0000.` +as a prefix to the fields on the `/transactions` endpoint. For example: +* `device_lists` becomes `org.matrix.msc0000.device_lists` +* `device_one_time_keys_count` becomes `org.matrix.msc0000.device_one_time_keys_count` + +Appservices which support encryption but never see these fields (ie: server is not implementing this in an +unstable capacity) should be fine, though encryption might not function properly for them. It is the +responsibility of the appservice to try and recover safely and sanely, if desired, when the server is not +implementing this in an unstable capacity. This is not a concern once the MSC becomes stable in a released +version of the specification, as servers will be required to implement it. From efabfe44020ba09bc884ba0797149e251bdd42e0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 18 May 2021 16:50:40 -0600 Subject: [PATCH 02/12] Guess number --- proposals/0000-encrypted-appservices.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/0000-encrypted-appservices.md b/proposals/0000-encrypted-appservices.md index 952910e1eaf..06f45919057 100644 --- a/proposals/0000-encrypted-appservices.md +++ b/proposals/0000-encrypted-appservices.md @@ -1,4 +1,4 @@ -# MSC0000: Encrypted Appservices +# MSC3202: Encrypted Appservices Presently, appservices in Matrix are capable of attaching themselves to a homeserver for high-traffic bot-like usecases, such as bridging and operationally expensive bots. Traditionally, these appservices @@ -70,10 +70,10 @@ all the users in its namespace. ## Unstable prefix -While this MSC is not considered stable for implementation, implementations should use `org.matrix.msc0000.` +While this MSC is not considered stable for implementation, implementations should use `org.matrix.msc3202.` as a prefix to the fields on the `/transactions` endpoint. For example: -* `device_lists` becomes `org.matrix.msc0000.device_lists` -* `device_one_time_keys_count` becomes `org.matrix.msc0000.device_one_time_keys_count` +* `device_lists` becomes `org.matrix.msc3202.device_lists` +* `device_one_time_keys_count` becomes `org.matrix.msc3202.device_one_time_keys_count` Appservices which support encryption but never see these fields (ie: server is not implementing this in an unstable capacity) should be fine, though encryption might not function properly for them. It is the From 3f394a8e3dc7972551207e43fc69e541fc9877ad Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 18 May 2021 16:51:22 -0600 Subject: [PATCH 03/12] number --- ...000-encrypted-appservices.md => 3202-encrypted-appservices.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename proposals/{0000-encrypted-appservices.md => 3202-encrypted-appservices.md} (100%) diff --git a/proposals/0000-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md similarity index 100% rename from proposals/0000-encrypted-appservices.md rename to proposals/3202-encrypted-appservices.md From f551ae58415d063dcc194c7b0a432274db5acc8f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 2 Nov 2021 21:47:32 -0600 Subject: [PATCH 04/12] Mention opt-in registration flag --- proposals/3202-encrypted-appservices.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index 06f45919057..8262fdbcb84 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -80,3 +80,7 @@ unstable capacity) should be fine, though encryption might not function properly responsibility of the appservice to try and recover safely and sanely, if desired, when the server is not implementing this in an unstable capacity. This is not a concern once the MSC becomes stable in a released version of the specification, as servers will be required to implement it. + +For servers wishing to force appservices to opt-in to this behaviour, they may use `org.matrix.msc3202: true` +in the registration file. Servers will be able to check for "opt-in" behaviour once this MSC is stable by +seeing whether or not the appservice has an encryption-capable device recorded in its users namespaces. From 4f6e2565d7ea6fb58ce6163b042c7ca4f39daf28 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 2 Nov 2021 21:52:36 -0600 Subject: [PATCH 05/12] Add device_id assertion --- proposals/3202-encrypted-appservices.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index 8262fdbcb84..b609a89cf75 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -47,6 +47,15 @@ Like MSC2409, any user the appservice would be considered "interested" in (user namespace, or sharing a room with an appservice user/namespaced room) would qualify for the device list changes section. +In order to allow the appservice to masquerade as its users, an extension to the existing +[identity assertion](https://matrix.org/docs/spec/application_service/r0.1.2#identity-assertion) +ability is proposed. To compliment the (optional) `user_id` when using an `as_token` as an access +token, a similarly optional `device_id` query parameter is proposed. When provided, the server asserts +that the device ID is valid for the user, and that the appservice is able to masquerade as that user. +If valid, that device ID should be assumed as being used for that request. For many requests, this +means updating the "last seen IP" and "last seen timestamp" for the device, however for some endpoints +it means interacting with that device (such as when uploading keys). + ## Potential issues Servers would have to track and send this information to appservices, however this is still perceived From 9001a6784c01644cc59856fd6414596506ec78a9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 3 Nov 2021 18:52:56 -0600 Subject: [PATCH 06/12] Mention device_id prefixing --- proposals/3202-encrypted-appservices.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index b609a89cf75..7b1c385fc91 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -93,3 +93,6 @@ version of the specification, as servers will be required to implement it. For servers wishing to force appservices to opt-in to this behaviour, they may use `org.matrix.msc3202: true` in the registration file. Servers will be able to check for "opt-in" behaviour once this MSC is stable by seeing whether or not the appservice has an encryption-capable device recorded in its users namespaces. + +To use device ID masquerading, implementations should use `org.matrix.msc3202.device_id` instead of `device_id` +in the query string while this MSC is considered unstable. From 472226b976ee74532eb60fbdaba40227bb57ca08 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 23 Nov 2021 22:17:47 -0700 Subject: [PATCH 07/12] Document optimizations --- proposals/3202-encrypted-appservices.md | 50 +++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index 7b1c385fc91..497780a3b6c 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -22,14 +22,19 @@ defining a new set of keys on the appservice `/transactions` endpoint, similar t "ephemeral": [ // MSC2409 ], + "to_device": [ + // MSC2409 + ], "device_lists": { "changed": ["@alice:example.org"], "left": ["@bob:example.com"] }, "device_one_time_keys_count": { "@_irc_bob:example.org": { - "curve25519": 10, - "signed_curve25519": 20 + "DEVICEID": { + "curve25519": 10, + "signed_curve25519": 20 + } } } } @@ -41,7 +46,7 @@ in the client-server API. Both new fields can be omitted if there are no changes for the appservice to handle. For `device_one_time_keys_count`, the format is slightly different from the client-server API to better map the appservice's user namespace users to the counts. Users in the namespace without keys or -which have unchanged keys since the last transaction can be omitted. +which have unchanged keys since the last transaction can be omitted (more details on this later on). Like MSC2409, any user the appservice would be considered "interested" in (user in the appservice's namespace, or sharing a room with an appservice user/namespaced room) would qualify for the device @@ -56,6 +61,45 @@ If valid, that device ID should be assumed as being used for that request. For m means updating the "last seen IP" and "last seen timestamp" for the device, however for some endpoints it means interacting with that device (such as when uploading keys). +### Optimization: when to send OTKs + +As mentioned above, in order to keep the transaction byte size down the server can (and should) exclude +OTK counts when they haven't changed since the last transaction. Appservices however should be tolerable +of the server over-communicating the counts as a quick/cheap approach would be to *always* include the +counts for all known users rather than trying to detect changes. + +As a middle ground, servers might be interested in an algorithm which doesn't detect changes between +transactions but does attempt to reduce traffic. If the appservice is about to receive an event or +message typically associated with encryption, the counts for the affected users could be included. This +would result in the following rules: +* If an `m.room.encrypted` event is being included in the transaction's `events`, include OTK counts for + all appservice users which reside in that room. +* If an appservice user is receiving a to-device message in the transaction's `to_device` array, include + OTK counts for that user. + +This approach has the advantage of typically minimal changes to the internals of the homeserver, works +similar to `/sync`, and reduces noisy traffic in the transaction sending. This additionally still honours +the "when they change, send the counts" requirement to a reasonable degree: typically a use of an OTK will +be followed by a to-device message. It is theoretically possible for an appservice to run out of OTKs if +a remote user claims all OTKs without actually using them. Implementations may be interested in +[MSC2732: Fallback keys](https://github.com/matrix-org/matrix-doc/pull/2732) which will avoid a scenario +where the appservice can no longer decrypt messages. + +However, as mentioned, servers are free to include this information as little or often as they'd like, +provided they send it at least as often as when it changes. + +### Optimization: Don't encrypt as often + +Appservices theoretically do not need to establish Olm sessions with other appservice users as the appservice +will typically be managing the devices in one place. In short, this means that a room with 10k appservice +users and only 1 non-appservice user can be sped up by only encrypting from the appservice's users to the +non-appservice user. The appservice would not need to set up 10k * 10k Olm sessions given the encryption +and decryption all happens in the same place. As an added bonus, this improves performance of the appservice +as it doesn't have to handle to-device messages sent to itself. + +Some implementations might not be able to support this sort of optimization though, so it is still permitted +to establish sessions and such between appservice users. + ## Potential issues Servers would have to track and send this information to appservices, however this is still perceived From 937e4c53e7c81d7ac344a8c0564d6c0935e5bd5a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 23 Nov 2021 22:23:47 -0700 Subject: [PATCH 08/12] Include fallback key support --- proposals/3202-encrypted-appservices.md | 30 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index 497780a3b6c..37ba646b867 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -36,6 +36,11 @@ defining a new set of keys on the appservice `/transactions` endpoint, similar t "signed_curve25519": 20 } } + }, + "device_unused_fallback_key_types": { + "@_irc_bob:example.org": { + "DEVICEID": ["signed_curve25519"] + } } } ``` @@ -43,10 +48,12 @@ defining a new set of keys on the appservice `/transactions` endpoint, similar t These fields are heavily inspired by [the extensions to /sync](https://matrix.org/docs/spec/client_server/r0.6.1#id84) in the client-server API. -Both new fields can be omitted if there are no changes for the appservice to handle. For -`device_one_time_keys_count`, the format is slightly different from the client-server API to better -map the appservice's user namespace users to the counts. Users in the namespace without keys or -which have unchanged keys since the last transaction can be omitted (more details on this later on). +All the new fields can be omitted if there are no changes for the appservice to handle. For +`device_one_time_keys_count` and `device_unused_fallback_key_types`, the format is slightly different +from the client-server API to better map the appservice's user namespace users to the counts. Users +in the namespace without keys or which have unchanged keys since the last transaction can be omitted +(more details on this later on). Note that fallback keys are described in +[MSC2732](https://github.com/matrix-org/matrix-doc/pull/2732) as of writing. Like MSC2409, any user the appservice would be considered "interested" in (user in the appservice's namespace, or sharing a room with an appservice user/namespaced room) would qualify for the device @@ -61,21 +68,22 @@ If valid, that device ID should be assumed as being used for that request. For m means updating the "last seen IP" and "last seen timestamp" for the device, however for some endpoints it means interacting with that device (such as when uploading keys). -### Optimization: when to send OTKs +### Optimization: when to send OTKs/fallback keys As mentioned above, in order to keep the transaction byte size down the server can (and should) exclude -OTK counts when they haven't changed since the last transaction. Appservices however should be tolerable -of the server over-communicating the counts as a quick/cheap approach would be to *always* include the -counts for all known users rather than trying to detect changes. +OTK counts and unused fallback keys when they haven't changed since the last transaction. Appservices +however should be tolerable of the server over-communicating the counts as a quick/cheap approach would +be to *always* include the OTK counts/unused fallback keys for all known users rather than trying to +detect changes. As a middle ground, servers might be interested in an algorithm which doesn't detect changes between transactions but does attempt to reduce traffic. If the appservice is about to receive an event or message typically associated with encryption, the counts for the affected users could be included. This would result in the following rules: -* If an `m.room.encrypted` event is being included in the transaction's `events`, include OTK counts for - all appservice users which reside in that room. +* If an `m.room.encrypted` event is being included in the transaction's `events`, include OTK counts and + unused fallback key types for all appservice users which reside in that room. * If an appservice user is receiving a to-device message in the transaction's `to_device` array, include - OTK counts for that user. + OTK counts and unused fallback key types for that user. This approach has the advantage of typically minimal changes to the internals of the homeserver, works similar to `/sync`, and reduces noisy traffic in the transaction sending. This additionally still honours From 9893a5fb16a040e1527303fbfd926f787f2a1a54 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 23 Nov 2021 22:26:44 -0700 Subject: [PATCH 09/12] Document appservice transaction retries and handling --- proposals/3202-encrypted-appservices.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index 37ba646b867..ba710be19af 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -59,6 +59,13 @@ Like MSC2409, any user the appservice would be considered "interested" in (user namespace, or sharing a room with an appservice user/namespaced room) would qualify for the device list changes section. +Note that it's typical for clients to pause sync loops when processing device list changes to avoid +a scenario where they are unable to decrypt/encrypt a message from/to a particular device. Appservices +are expected to mirror this by ensuring the transaction request does not complete until processing +is complete. In the worst case, the server will time out the request and retry it verbatim, so +appservices might wish to track which device list changes in which transaction they already processed +or keep processing transactions in the background while retries are attempted. + In order to allow the appservice to masquerade as its users, an extension to the existing [identity assertion](https://matrix.org/docs/spec/application_service/r0.1.2#identity-assertion) ability is proposed. To compliment the (optional) `user_id` when using an `as_token` as an access From 208decb32d3185a491c008a9ac003c20a53d3863 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 23 Nov 2021 22:27:30 -0700 Subject: [PATCH 10/12] Update unstable prefixing --- proposals/3202-encrypted-appservices.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index ba710be19af..dac11cdb333 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -142,6 +142,7 @@ While this MSC is not considered stable for implementation, implementations shou as a prefix to the fields on the `/transactions` endpoint. For example: * `device_lists` becomes `org.matrix.msc3202.device_lists` * `device_one_time_keys_count` becomes `org.matrix.msc3202.device_one_time_keys_count` +* `device_unused_fallback_key_types` becomes `org.matrix.msc3202.device_unused_fallback_key_types` Appservices which support encryption but never see these fields (ie: server is not implementing this in an unstable capacity) should be fine, though encryption might not function properly for them. It is the From f875ffee86f3d71a9af2b6589451edd426be62e6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 23 Mar 2023 16:18:04 -0600 Subject: [PATCH 11/12] Fix naming of `device_one_time_key_counts` to match CS API --- proposals/3202-encrypted-appservices.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index dac11cdb333..36d87b124c5 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -29,7 +29,7 @@ defining a new set of keys on the appservice `/transactions` endpoint, similar t "changed": ["@alice:example.org"], "left": ["@bob:example.com"] }, - "device_one_time_keys_count": { + "device_one_time_key_counts": { "@_irc_bob:example.org": { "DEVICEID": { "curve25519": 10, @@ -49,7 +49,7 @@ These fields are heavily inspired by [the extensions to /sync](https://matrix.or in the client-server API. All the new fields can be omitted if there are no changes for the appservice to handle. For -`device_one_time_keys_count` and `device_unused_fallback_key_types`, the format is slightly different +`device_one_time_key_counts` and `device_unused_fallback_key_types`, the format is slightly different from the client-server API to better map the appservice's user namespace users to the counts. Users in the namespace without keys or which have unchanged keys since the last transaction can be omitted (more details on this later on). Note that fallback keys are described in @@ -141,7 +141,7 @@ all the users in its namespace. While this MSC is not considered stable for implementation, implementations should use `org.matrix.msc3202.` as a prefix to the fields on the `/transactions` endpoint. For example: * `device_lists` becomes `org.matrix.msc3202.device_lists` -* `device_one_time_keys_count` becomes `org.matrix.msc3202.device_one_time_keys_count` +* `device_one_time_key_counts` becomes `org.matrix.msc3202.device_one_time_key_counts` * `device_unused_fallback_key_types` becomes `org.matrix.msc3202.device_unused_fallback_key_types` Appservices which support encryption but never see these fields (ie: server is not implementing this in an From 47d20802ecb3fb37a96caabe25099413bd853a67 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 23 Mar 2023 16:19:59 -0600 Subject: [PATCH 12/12] Actually, *this* matches the CS API --- proposals/3202-encrypted-appservices.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/3202-encrypted-appservices.md b/proposals/3202-encrypted-appservices.md index 36d87b124c5..dac11cdb333 100644 --- a/proposals/3202-encrypted-appservices.md +++ b/proposals/3202-encrypted-appservices.md @@ -29,7 +29,7 @@ defining a new set of keys on the appservice `/transactions` endpoint, similar t "changed": ["@alice:example.org"], "left": ["@bob:example.com"] }, - "device_one_time_key_counts": { + "device_one_time_keys_count": { "@_irc_bob:example.org": { "DEVICEID": { "curve25519": 10, @@ -49,7 +49,7 @@ These fields are heavily inspired by [the extensions to /sync](https://matrix.or in the client-server API. All the new fields can be omitted if there are no changes for the appservice to handle. For -`device_one_time_key_counts` and `device_unused_fallback_key_types`, the format is slightly different +`device_one_time_keys_count` and `device_unused_fallback_key_types`, the format is slightly different from the client-server API to better map the appservice's user namespace users to the counts. Users in the namespace without keys or which have unchanged keys since the last transaction can be omitted (more details on this later on). Note that fallback keys are described in @@ -141,7 +141,7 @@ all the users in its namespace. While this MSC is not considered stable for implementation, implementations should use `org.matrix.msc3202.` as a prefix to the fields on the `/transactions` endpoint. For example: * `device_lists` becomes `org.matrix.msc3202.device_lists` -* `device_one_time_key_counts` becomes `org.matrix.msc3202.device_one_time_key_counts` +* `device_one_time_keys_count` becomes `org.matrix.msc3202.device_one_time_keys_count` * `device_unused_fallback_key_types` becomes `org.matrix.msc3202.device_unused_fallback_key_types` Appservices which support encryption but never see these fields (ie: server is not implementing this in an