xmtp / libxmtp

LibXMTP is a shared library encapsulating the core functionality of the XMTP messaging protocol, such as cryptography, networking, and language bindings.
MIT License
43 stars 19 forks source link

MLS support in libxmtp? #259

Closed neekolas closed 11 months ago

neekolas commented 1 year ago

Is your feature request related to a problem?

If we are going to be using MLS for group chats, it may make the most sense to use MLS for 1:1 interactions as well.

Describe the solution to the problem

There are five main areas where we would need to extend OpenMLS to support our needs, in addition to a huge number of more mundane tasks to actually implement MLS.

Commit conflict resolution

The IETF spec describes conflict resolution in this section.

Applications MUST have an established way to resolve conflicting Commit messages for the same epoch. They can do this either by preventing conflicting messages from occurring in the first place, or by developing rules for deciding which Commit out of several sent in an epoch will be canonical. The approach chosen MUST minimize the amount of time that forked or previous group states are kept in memory, and promptly delete them once they're no longer necessary to ensure forward secrecy.

The generation of Commit messages MUST NOT modify a client's state, since the client doesn't know at that time whether the changes implied by the Commit message will conflict with another Commit or not. Similarly, the Welcome message corresponding to a Commit MUST NOT be delivered to a new joiner until it's clear that the Commit has been accepted.

In XMTP, we don't have the luxury of a strongly consistent datastore for a delivery service. Given our architecture, it makes the most sense for conflict resolution to happen on the client. This could be accomplished in one of two ways:

  1. All clients wanting to modify the group tree (add/remove members, key updates, or re-init of group encryption state) would be responsible for validating that no other commits had arrived in the same epoch through polling the network for new messages for a specified time period. They would then deterministically resolve any conflicts that appear if new messages were found, and possibly generate a new commit against the updated ratchet tree. Any recipient would also need to take the same approach if they received a commit that was less than N seconds old. Any messages sent in this waiting period would need to be queued and only sent after a new group state was resolved.
  2. We create a system for resolving conflicts after-the-fact, which would involve keeping local copies of previous epochs group state for some period of time. If newer commit messages appear, the group state could be rolled back and the new commits could be applied with conflicts resolved.

All potential changes should be broadcast to the network as Proposals before creating a commit, to make conflicts rarer and make resolution easier.

Group metadata

OpenMLS does not offer out-of-the-box functionality for storing application-level metadata for a group. Sending that metadata as a message in the channel is not really an option, given we want this metadata to be available to all joiners of the group. If we want to migrate XMTP V2 conversations with a conversationId or metadata, this is strictly necessary to preserve that data. We may also want to include metadata for group chats to store information such as the group name, token gating rules, or any other information we would need to construct XMTP-specific rules on the network.

MLS offers user-configurable extensions that can be applied to the GroupInfo object, so we would just need to plug into that framework and add whatever extensions we feel are necessary.

Deniability/non-repudiation

MLS was designed as a group chat protocol and defaults to enabling non-repudiation for all messages sent in a conversation. It does this by signing messages with the sender's SigningKey. For 1:1 chats, we have previously expressed support for choosing deniability over non-repudiation for user privacy reasons. We would need to modify OpenMLS to allow groups to be configured for either deniability or non-repudiation, and enable "deniability-mode" for all 1:1 chats. The most obvious way to achieve deniability is to disable message signing.

The main challenge here is compatibility with our authentication system. We need to authenticate wallet ownership of identities, and the way I am currently doing this in the demo branch is by using the wallet to sign the signing key. That signature becomes part of the installation's identity. If the signing key is not used in regular message sending, we don't have a chain of signatures going from each message back to the wallet. It's possible that we could just use the signing key to sign "welcome messages" and then not sign any messages after the welcome was processed. While that's the point of deniability, we'd need more investigation to ensure that messages could never be inserted into the conversation from non-members.

Key package of last resort

MLS and Olm both require the use of one-time-keys. These must be deleted immediately after use to provide FS. There is one important difference: Olm has the concept of a "fallback key" that can be used if no one time prekeys are available. In MLS, there is no fallback. If an installation is out of Key Packages, there is no way to add them to a new group. This can be an attack vector for a targeted DOS if we don't have tight limits on requests for an installations Key Packages or offer an alternative if there are no key packages available.

MLS does offer some guidance here around a "last resort" KeyPackage. None of this is implemented in OpenMLS to my knowledge, so we would need to figure this out ourselves.

KeyPackages are intended to be used only once. That is, once a KeyPackage has been used to introduce the corresponding client to a group, it SHOULD be deleted from the KeyPackage publication system. Reuse of KeyPackages can lead to replay attacks.

An application MAY allow for reuse of a "last resort" KeyPackage in order to prevent denial-of-service attacks. Since a KeyPackage is needed to add a client to a new group, an attacker could prevent a client being added to new groups by exhausting all available KeyPackages. To prevent such a denial-of-service attack, the KeyPackage publication system SHOULD rate-limit KeyPackage requests, especially if not authenticated.

New installation discovery

When a user adds a new installation, it is expected that new messages will begin being delivered to that installation. Past messages can be synced via Message Backups, and is out of scope for this discussion. With MLS groups, we will need some mechanism for discovering new installations for each user in the group. With 1:1 groups, this can work the same way as with Double Ratchet (the client periodically checks the network for new installations). In larger groups, we may want to enable an API to do these lookups in bulk for performance reasons. Checking if any one of the 1000 members in a large group has added a new installation would be a very expensive operation to do on the client.

Other work

Describe the uses cases for the feature

No response

Additional details

No response

neekolas commented 11 months ago

Closing the issue. Work is in progress and can be tracked in this project board https://github.com/orgs/xmtp/projects/11