Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions proposals/4350-appservice-encryption-impersonation.md
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation requirements:

  • Bridge or other appservice making use of impersonation
  • Client that validates impersonation requirements
  • Server that exposes signatures properly

Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# MSC4350: Permitting encryption impersonation for appservices
Bridges that currently support end-to-bridge encryption do so by creating a
single encryption identity for the bridge bot and using that identity to send
and receive keys. The single identity method is much more efficient than
creating separate identities for each ghost user, but has the downside of not
being technically correct, as it abuses a lack of validation in where e2ee keys
come from.

Fixing the lack of validation is planned as a part of [MSC4153]. However, just
adding validation without creating any exceptions would force bridges to either
use the inefficient method of redundant crypto identities or simply turn
encryption off, neither of which are good options.

In addition to ghost users, some bridges have the concept of "double puppeting",
where the bridge is given access to send messages as a real Matrix user instead
of an appservice ghost.

[MSC4153]: https://github.com/matrix-org/matrix-spec-proposals/pull/4153

## Proposal
The proposed solution is defining special device metadata to indicate that
another user is allowed to cryptographically impersonate the owner of the
device.

The device keys object, which is written by `/keys/upload` and read by
`/keys/query`, gets a new optional `impersonator` field. The field contains a
full device keys object, excluding `signatures`.

The device owned by the ghost user (or real Matrix user in case of double
puppeting) with the `impersonator` field will be referred to as the
"impersonatable" device, while the bridge bot's device is the "impersonator"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the "impersonatable device" has no keys, in what way is it a device being impersonated? Rather, I believe "impersonatable device" is a bit of a misnomer; it is simply a way for a user to specify a foreign device that is allowed to impersonate them. It is the user being impersonated, not any specific device of theirs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah need to figure out some better terms. The impersonator is the bridge bot's device which is obvious enough, but I'm not sure what to call the device entry that points at the impersonator without it being confusable with the impersonator itself.

device.

The `algorithms` and `keys` fields are still present and required, but MUST be
an empty list and an empty object respectively when an impersonator is defined.
Because there are no keys, `signatures` will not include a signature from the
device itself. Instead, there MUST be a signature from the user/device
combination defined in the `impersonator` field.

The lack of keys is used to signal that the impersonatable device can't receive
keys on its own. Instead, the impersonator user should be a member of the room
to receive keys the standard way.

### Client behavior
Following the rules of [MSC4153], an impersonated message is considered to be
from a "non-cross-signed device" if:

* the user specified in `impersonator` is not a member of the room
* the device specified in `impersonator` is not cross-signed itself
* the user who owns the impersonatable device has cross-signing keys and the
impersonatable device is not signed by the user's self-signing key

If there are no cross-signing keys on the user, messages are trusted with just
the device signature. This means ghost users owned by the appservice will not be
required to upload cross-signing keys at all, reducing the amount of keys that
need to be managed.

If any of the above conditions match, clients should behave as they do with
other non-cross-signed messages under [MSC4153]. If not, then the impersonated
message is trusted and should be displayed as usual. Clients MAY still choose to
display an indication that the message is from an impersonator device.

The requirement for cross-signing means that bridges will have to get double
puppeting devices verified, either by asking for the user's recovery key, or
having the user upload a signature themselves.

To help verify double puppeting sessions, clients can offer a button to easily
cross-sign impersonatable devices. When offering such a button, clients SHOULD
prominently display the impersonator user ID and make it clear that the bot will
be able to send messages as the user. Clients MAY also suggest or require that
the impersonator device is marked as verified before the impersonatable device
can be signed. However, interactive verification SHOULD NOT be required, as it
doesn't make much sense when the other party is a bot.

### Server behavior
When `impersonator` is present in device keys, servers MUST include signatures
from the impersonator user in `/keys/query` responses both in the C-S and S-S
APIs regardless of who is querying the keys.

### Example
<details>
<summary>Bridge ghost device keys</summary>

```jsonc
{
"algorithms": [],
"device_id": "ZVYTEW6WS0",
"impersonator": {
"algorithms": [
"m.olm.v1.curve25519-aes-sha2",
"m.megolm.v1.aes-sha2"
],
"device_id": "JLAFKJWSCS",
"keys": {
"curve25519:JLAFKJWSCS": "[bridge-device-curve25519-key]",
"ed25519:JLAFKJWSCS": "[bridge-device-ed25519-key]"
},
"user_id": "@bridgebot:example.com"
},
"keys": {},
"signatures": {
"@bridgebot:example.com": {
"ed25519:JLAFKJWSCS": "[signature-from-bridge-device]"
}
},
"user_id": "@bridge_123456:example.com"
}
```

</details>
<details>
<summary>Double puppeting device keys, note the added cross-signing signature</summary>

```jsonc
{
"algorithms": [],
"device_id": "S9ON0B1TCA",
"impersonator": {
"algorithms": [
"m.olm.v1.curve25519-aes-sha2",
"m.megolm.v1.aes-sha2"
],
"device_id": "JLAFKJWSCS",
"keys": {
"curve25519:JLAFKJWSCS": "[bridge-device-curve25519-key]",
"ed25519:JLAFKJWSCS": "[bridge-device-ed25519-key]"
},
"user_id": "@bridgebot:example.com"
},
"keys": {},
"signatures": {
"@bridgebot:example.com": {
"ed25519:JLAFKJWSCS": "[signature-from-bridge-device]"
},
"@user:example.com": {
"ed25519:selfsigningkey": "[signature-from-user-cross-signing-key]"
}
},
"user_id": "@user:example.com"
}
```

</details>

## Potential issues
The approach taken by this MSC assumes that the bridge bot will be present in
all rooms (see alternative below).

## Alternatives
### Send room keys to impersonator devices
To remove the requirement for the bridge bot being a member of all rooms, we
could define that clients must send keys to any impersonator devices in the
room. However, we prefer an explicit bot membership over a hidden key sharing
mechanism. Additionally, there would need to be a way to turn off sending
message keys to impersonator devices to avoid the bridge receiving message keys
in all encrypted rooms when using double puppeting.

### Disable encryption
As mentioned in the introduction, bridges could simply not use encryption. This
is not considered an acceptable alternative, as there are valid reasons to use
encryption with bridges, where disabling it would reduce privacy.

### Separate encryption identities for all ghosts
The other option is creating separate full encryption identities for each ghost.
However, that would require a lot more key management for bridges, plus it would
require users' devices to encrypt every megolm session for every ghost
separately even though all the ghosts are in the same bridge process.

[MSC4261](https://github.com/matrix-org/matrix-spec-proposals/pull/4261) could
be used to avoid receiving keys for the ghost users, but it would still require
the bridge to create Olm sessions between each ghost and recipient device to
share keys to users.

## Security considerations
The requirement to cross-sign the impersonatable device could be bypassed by a
malicious server that hides the user's cross-signing keys. However, hiding
cross-signing will also prevent other devices of that user from working under
[MSC4153] (as other clients will stop encrypting messages to all the user's real
devices), so it should be easily noticeable.

## Unstable prefix
`fi.mau.msc4350.impersonator` should be used instead of `impersonator` in
device metadata.

## Dependencies
This MSC builds on [MSC4153]. While this proposal would technically work without
4153, some security properties assume that 4153 is accepted either before or at
the same time as this MSC.