The original MSC1228 proposal does a fairly good job of trying to decouple identities from MXIDs but there are some pitfalls which don't necessarily help us in creating portable accounts. This proposal is an alternate model that should hopefully enable account portability.
The goals of this proposal are:
- To enable account portability by breaking the link between a user identity and a specific homeserver;
- To allow breaking the link between temporary and permanent user identities at a later date, e.g. as a part of a data deletion request.
This proposal includes specifications to:
- To give a user a single cryptographic User Identity Key (herein referred to as a "UIK"), which they will use as part of a cryptographic challenge login;
- To give a user one or more User Delegated Keys (herein referred to as a "UDK"), which will optionally represent a user within a room;
- To allow users to attest one or more UDKs using their UIK;
- To remove Matrix IDs (MXIDs) and server names from events, similar to MSC1228;
- To allow a user to attest to one or more server-provided MXIDs mapped to their UIK.
Current issues:
- UDKs, if owned by the server, mean that a user who wants to join a room from multiple homeservers, e.g. in a P2P world, will have to join from each server individually and potentially appear in the room more than once (unless the client can deduplicate users based on UIK attestations)
The UIK is an ed25519 public key which represents a user entity. The user will use this UIK to perform a challenge-response login to a homeserver and will become the "one true identity".
The UDK is prefixed with a version byte, then URL-safe base64-encoded, and then
prefixed with the ~
sigil. The version byte for ed25519 is 0x01
.
The UDK is an ed25519 key which represents a user identity within a given room. These keys are generated and stored by the server when a user joins a room:
- The user requests to join a room;
- The server generates a UDK and sends it to the client;
- The client signs a UDK attestation using their UIK - this forms the link between the UDK and the UIK;
- The server generates the membership event, including the attestation, and sends it into the room/to federated servers.
The UDK is prefixed with a version byte, then URL-safe base64-encoded, and then
prefixed with the ^
sigil. The version byte for ed25519 is 0x01
.
An attestation will include the UDK that is being attested to, and an expiry time. The attestation will be valid for events that fall inclusive of any of these ranges.
The attestation will take a format similar to this:
"attestation": {
"content": {
"identity": ~uik_that_is_attesting",
"delegate": "^udk_that_is_being_attested",
"server_name": "example.com",
"expires": 15895491111111
},
"signatures": {
"example.com": {
"ed25519:auto": "homeserver_signature"
},
"~uik_that_is_attesting": {
"ed25519": "uik_signature"
}
}
}
The attestation contains a "server_name"
field which contains the name of the server
that manages the UDK. This is necessary as, without this, other servers in the room
will not be able to work out where to route messages for this UDK.
The attestation "content"
key will then be canonicalised and signed, once by the UIK
and then once by the homeserver that issued the UDK.
The attestation will be valid from the point that it is sent (in effect, from the
"origin_server_ts"
timestamp) up until the "expires"
timestamp.
Since there may be multiple membership state events with renewals over time, event validity is based on the attestation in the room state at (before) the event. If the attestation has expired in the room state at (before) the event, the attestation is considered invalid.
Authorisation rules will be updated to include an extra clause: that events should only be accepted for a specific UDK as long as there is:
- A valid attestation at the time for the UDK;
- The attestation has not expired at the time that the event was sent.
This prevents servers from continuing to impersonate the user after the attestation as expired - necessary since the server owns and maintains the UDK keypair.
Some thought needs to be given on how to ban a UIK so that generating new UDKs is not an effective measure for evading bans.
A membership event including an attestation may look something like this:
{
"auth_events": [ ... ],
"prev_events": [ ... ],
"content": {
"avatar_url": "mxc://here/is/neilalexander.png",
"displayname": "neilalexander",
"membership": "join",
"attestation": {
"content": {
"identity": ~uik_that_is_attesting",
"delegate": "^udk_that_is_being_attested",
"server_name": "example.com",
"expires": 15895491111111
},
"signatures": {
"example.com": {
"ed25519:auto": "homeserver_signature"
},
"~uik_that_is_attesting": {
"ed25519": "uik_signature"
}
}
}
},
"origin_server_ts": 1589549295296,
"sender": "^udk_that_is_being_attested",
"signatures": {
"^udk_that_is_being_attested": "signature_as_signed_by_udk"
},
"hashes": {
"sha256": ...,
}
"state_key": "^udk_that_is_being_attested",
"type": "m.room.member",
"unsigned": {
"age": 25,
},
"event_id": "$eventid",
"room_id": "!roomid"
}
Note that there is no MXID in the "sender"
and "state_key"
fields, nor in the
"signatures"
field of the event itself - these are now referencing the UDKs. The
attestation provides us with a link to a UIK and also to the homeserver by its
signature.
A membership event must include an attestation - the "identity"
key may have been
banned. Requiring an attestation helps us to prevent ban evasion.
At any time, the UIK holder can issue new attestations by sending updated membership state events with a new attestation. This can be done either before or after the validity of the previous attestation has expired.
To remove an attestation, the membership event which introduced the attestation should be redacted. All events covered by this attestation will no longer be linked to the original UIK for the covered range.
Public keys as identifiers may enable some portability but they aren't user-friendly and somewhat difficult to put on a business card. For this, it is necessary to be able to allow users to maintain MXID mappings much as they have today.
However, a homeserver returning a UIK for an MXID should ideally imply that the server actually has some kind of association with the user and that the user is resident, rather than third-party servers gratuitously providing MXID mappings for users that they may not otherwise be aware of.
Therefore, an MXID mapping should also be attested by the UIK. To do this, the user should create an attestation for the desired mappings and then submit it to the homeserver.
For things like invites, direct messages etc, it is not possible to know what the UDK will be before a homeserver generates one to join the room. Therefore these endpoints should be updated to use either:
- A UIK in combination with a previously-known resident server name;
- A MXID, from which a response will contain the UIK and a resident server name.
In these instances, you are addressing "the user" rather than a UDK.
needs more isaacs/github#243 :'(