Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSC1680: cross-signing #1681

Closed
wants to merge 11 commits into from
Closed

MSC1680: cross-signing #1681

wants to merge 11 commits into from

Conversation

uhoreg
Copy link
Member

@uhoreg uhoreg commented Sep 20, 2018

corresponding revocation. If Device A can construct a directed path in this
graph starting from a device it has verified and ending at Device B, consisting
only of devices owned by either Device A's owner or Device B's owner, then it
may treat Device B as trusted. Device A may do so automatically, or after
Copy link
Member

Choose a reason for hiding this comment

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

Hm. There's something about the idea of the assertion DAG spanning multiple users which feels wrong here - the idea of User A publicly publishing that they have verified one of User B's devices is a very strong metadata leak.

Or is the idea that the cross-user attestations aren't published, but are kept personal to a given user (albeit trusted on their server?)

prompting the user, or may allow the user to disable this functionality
completely.

TODO: should Device A then publish an attestation for Device B?
Copy link
Member

Choose a reason for hiding this comment

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

our verification mechanisms are symmetrical so presumably the signing graph shouldn't actually be directional? (and could also be cyclic unless we explicitly stop cycles...)

Copy link
Member Author

Choose a reason for hiding this comment

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

The verification mechanisms are symmetrical, but the attestations are directed, as one device of the pair might not publish their attestation.

I should probably also spell out that the graph, although is directed, is not necessarily acyclic, unlike every other time that "directed graphs" are mentioned in Matrix.

Copy link
Member

Choose a reason for hiding this comment

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

i'm failing to think of a reason why you wouldn't publish symmetrical attestations between your own devices. and (unless i'm misunderstanding everything), you shouldn't be ever publishing attestations about other people's devices to anyone but yourself?

Copy link
Member Author

Choose a reason for hiding this comment

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

The attestation graph has to be directed, otherwise a malicious user could create a fake device under Alice's account and publish an attestation for one of her other devices, and trick the other devices into thinking that the trust is mutual.

- `attestations` (`[Attestation]` (see below)): The published attestations or
revocations for the device. This array MUST only include the attestations or
revocations that come from devices belonging to the user calling the
endpoint, or belonging to the user that the attestation is about.
Copy link
Member

Choose a reason for hiding this comment

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

To preserve metadata privacy, I think this needs to be constrained further (as per https://github.com/matrix-org/matrix-doc/pull/1681/files#r219310880): If Alice is wondering which of Bob's devices she should trust, she should see only the attestations she's made (including those about others' devices)... and only the attestations that Bob has made about Bob's own devices.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, this is probably a bit confusing because I'm just plopping an addition in, with no context whatsoever, and so it probably would benefit from an example, which I'll add to the doc. But the basic idea is that the attestations array is in the context of one of Bob's devices, and so only contains attestations about that device. So when Alice queries the information on Bob's devices, then it will return Bob's device, and attestations made about that device made by Alice's devices and Bob's devices, but not any attestations made by Carol about Bob's devices.

As a result of this, attestations made by Alice never need to leave Alice's server, which I think addresses your first comment.

Copy link
Member

Choose a reason for hiding this comment

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

i'm not sure, as in your model Bob's attestations about Alice's devices get published to Alice here (and thus leave his server). Surely Alice should only care about her attestations about Bob's devices (and how Bob has cross-signed his own devices), rather than Bob revealing unnecessarily which of his devices has attested to Alice?

Or perhaps this doesn't matter much given Alice's server will already know about her attestations about Bob, and we're not trying to encrypt the attestations on the server.

revocations that come from devices belonging to the user calling the
endpoint, or belonging to the user that the attestation is about.

TODO: `keys/query` may need to include devices that have been logged out, in
Copy link
Member

Choose a reason for hiding this comment

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

Are you saying that we should distinguish between devices which were logged out but are still trustable versus ones which were logged out but whose trust should be explicitly revoked? This feels like we could end up with three classes of logouts:

  • soft-logout (where the device doesn't delete any data, is still trusted, but the user needs to be reauthenticated as a precaution after doing something like changing their password)
  • trusted-hard-logout (where the device destroys all local data and logs out the user... but its attestations are still trusted)
  • untrusted-hard-logout (same, but attestations now revoked).

I wonder if this is overengineered - do we really need the trusted-hard-logout state? It feels that if you have abandoned a device and logged it out, its attestations may not be worth very much any more, even if they seemed okay at the time...

Copy link
Member Author

Choose a reason for hiding this comment

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

Are you saying that we should distinguish between devices which were logged out but are still trustable versus ones which were logged out but whose trust should be explicitly revoked?

Yes, that's the idea. I'm not sure if it's needed, but it's something that we were thinking about when we were brainstorming. I think the situation we were thinking of was where Bob cycles through devices very quickly. So Alice verifies Bob's Osborne 2. The following week, Bob replaces his Osborne 2 with a Dynabook, and the week after, Bob replaces is Dynabook with a PADD. Alice logs on for the first time since verifying Bob's Osborne 2, and is unable to trust Bob's PADD, because the Dynabook and Osborne 2 are logged out.

- `device_id` (string): Required. The ID of the device that has been verified.
- `keys` ({string: string}): Required. The public identity keys that have been
verified. Note that this does not have to be the full set of device keys.
For example, this might only contain the `ed25519` key, whereas the device
Copy link
Member

Choose a reason for hiding this comment

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

For simplicity, shouldn't we mandate this only includes the ed25519 key? (or whatever we actually verify when we do QR or interactive text based verification)?

Copy link
Member Author

Choose a reason for hiding this comment

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

For simplicity, shouldn't we mandate this only includes the ed25519 key?

Yeah, we should probably say that somewhere, but I'm not sure where is the best place. The idea is that, some time in the future, we may no longer be using ed25519, so we need to be able to sign other types of keys here.

Copy link
Member

Choose a reason for hiding this comment

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

sure, but the important thing is that we're attesting the device's signing key rather than the identity key (whatever curve that might use)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup. Wording suggestions welcome. 😉

@ara4n
Copy link
Member

ara4n commented Sep 20, 2018

this is looking super-promising to me, modulo the general metadata privacy thing i've highlighted in the comments.

Something that I thought about a bit in the past was whether we should consider storing the attestations encrypted on the server (a bit like we do e2e keys) to protect their metadata - e.g. have Alice store her attestations in a general encrypted store that only her clients have the keys to, but then use PKI to let Bob selectively decrypt whichever keys he needs to follow the cross-signing DAG. Thus avoid the servers spying on which user is attesting to whom.

However, given the server can just inspect the network traffic or room metadata to see who's talking to who, i'm not sure this buys us much other than overengineering. But just wanted to note it down for posterity as a random idea.

@uhoreg
Copy link
Member Author

uhoreg commented Sep 21, 2018

Pushed new version, which should make things clearer.

Regarding encrypting the attestations, I think it would be really hard to do properly, since you don't know in advance what devices will need to decrypt it, as new devices will be created after the attestation is published. It seems like it would make things a lot more complicated.

Device B as trusted. Device A may do so automatically, or after prompting the
user, or may allow the user to disable this functionality completely.

TODO: should Device A then publish an attestation for Device B?
Copy link
Contributor

@jcgruenhage jcgruenhage Sep 21, 2018

Choose a reason for hiding this comment

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

The client could prompt the user whether it should do it or not.

Copy link
Member

Choose a reason for hiding this comment

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

Need to ensure this is presented in a friendly way to non-techies though.

One way in which key verification has historically been addressed is through a
web-of-trust system: if Alice trusts Bob, and Bob trusts Carol, then Alice may
trust Carol even though Alice is unable to verify Carol's key directly.
Cross-signing can be seen as a limited web-of-trust, in which one device can
Copy link
Contributor

Choose a reason for hiding this comment

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

That would make working in encrypted work chats with lots of people a bit complicated.. Where does this limitation come from? As long as the users know how the trust is established, going over multiple users should be okay IMO

Copy link
Member Author

Choose a reason for hiding this comment

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

Normal web-of-trusts (webs-of-trust?) are a bit tricky, because you need to determine how much you trust other people to have verified other people. For example, cryptogeek Alice might be very strict about checking identities, and may have verified Bob's device, but might not trust Bob to have properly verified Carol's identity, or may not trust him to not be maliciously signing fake devices for other people, so will not trust Bob's attestations. However, Bob, knowing how much of a paranoid cryptogeek Alice is, and knowing that she's a whitehat, might have no problems trusting Alice's attestations.

In the case of cross-signing, we make the assumption that people are generally sane and will only verify their own devices only they actually belong to them, as signing a fake device will harm themselves.

It may be possible that we implement a more extended web-of-trust later on, but for now, I think it's better to keep it simpler.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about still saying a device is unverified, but showing the user a dag of attestations from themselves to the other device? The more different paths there are, and the shorter they are, the more trustworthy a device would be. I think it's fine to limit cross signing to own devices for now, but I'm not sure that is a limitation that should be made at the protocol level instead of the UX level.

Copy link
Member

Choose a reason for hiding this comment

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

A more advanced WoT trust like that would be satisfying, but I do worry about the users who just verify devices because they like how the green lock looks, without actually checking it.

I also don't want to verify my mother's devices meaning that I trust all the random trust decisions she's making.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't want to verify my peers random devices either, but that just means I have to live with all the yellow exclamation marks.. As I said, I'd limit that via UX, but I wouldn't want to have a more advanced WoT blocked by protocol decisions worrying about what some users might do to avoid bad UX (because honestly, verifying devices to get green locks sounds like bad UX to me)

Copy link
Member

Choose a reason for hiding this comment

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

yeah, the big concern here for me is the fact that it broadcasts metadata to all users on the network. Just because you’ve verified Lenin’s keys doesn’t mean that I want you know that I have too...

Copy link
Contributor

Choose a reason for hiding this comment

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

I am not saying we should publish any attestations for devices of other people here, I am just saying we shouldn't forbid that in the protocol, so that a more generalized WoT would be a client side extension, not a server side one.

Copy link
Member Author

Choose a reason for hiding this comment

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

It needs server-side changes anyways, since the server needs to control what attestations it shows to users, and what attestations it forwards to other server, so it can't be a purely client-side extension.

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought the query endpoint would be used to query the attestations published by a user? Filtering out any that try to do attestations for devices not controlled by that user is something the client could do.

Copy link
Member Author

Choose a reason for hiding this comment

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

The query endpoint is used to query the attestations made about the device/user, not made by the device/user.

proposals/1680-cross-signing.md Show resolved Hide resolved
Alice's devices or by Bob's other devices.

TODO: `keys/query` may need to include devices that have been logged out, in
order to avoid unexpectedly breaking trust chains, so we may want to recommend
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably include old devices (and the point when they were removed) anyway, for people who scroll back up. We might even want to store attestations from the new devices signing that the old device was trusted in some timeframe, so that new devices can read history and know that it's okay.

@erikjohnston
Copy link
Member

Hey, sorry for not getting to look at this sooner, and sorry for the wall of text. This does look like an entirely sensible way of implementing cross signing.

However, a few thoughts I've had while reading through this are:

  • How does this work with recovering an account (via the backup)? If you've lost all your devices then you won't be able to verify your new device, even though you've got all the backed up E2E keys.
  • As noted we'll need to be careful removing a device, since removing edges may disconnect the graph. This can easily happen if you e.g. a) register on an ipad, b) login and verify on a laptop and then c) login on a phone and verify against the laptop, at which point logging out of the laptop will break the graph. However keeping around the attestations for logged out devices that are still needed to keep the graph connected feels like it could easily end up causing old users have large attestation graphs.
  • Asymmetric attestations are going to cause all manner of confusion if they're allowed to happen, since if user A on their different devices each verify different devices of user B's, A will see different state on each of their devices. You can probably ensure that all of user A's devices trust the same devices, but you would still have the same problem across different users.
  • In this model a user is verifying a particular device, which may very well be a fairly ephemeral concept depending on how often they change devices/relogin etc. This makes it difficult to try and verify a particular user. If two users try and check that they've verified the same "user" of a third account, they can't simply compare the key they've individually verified (indeed, the two users may only partially agree about which devices should be verified due to the asymmetry). Similarly, when users want to publish their keys on e.g. their website, they would need to pick a device and ensure that they keep the website up to date whenever they change that device.
  • Requiring clients to do graph algorithms in the presence of cycles feels like quite a burden. Yes, end to end is quite complicated anyway, but this feels like quite a large potential foot gun.

Broadly I'm worried that while this will certainly work (and in some ways quite an intuitive and elegant way of doing so), it also locks us into a fairly convoluted verification model from a UX perspective (and potentially a security perspective).


I wonder if we can tweak the model slightly and have a master identity key for the user, which is then used to sign device keys? This would make things a lot simpler, except that we'd need to a) figure out where the master key is stored and b) ensure that users can update their master key.

Storage of the master key could be done in a number of ways (or any combination of):

  1. Included in the key backup to the server. Though we may instead want to use the master key to encrypt the backup.
  2. Give all verified devices a copy of the master key, this feels a little icky but probably fine for most use cases and allows the UX to be seamless.
  3. Have the user store it manually, e.g. print it out and store it on a safe, or use a hardware key. This would allow users to keep their identity (i.e. other users won't need to reverify them) if they lose or logout of all their devices.

(If the master key is only ever stored off device, this would allow a very secure setup where an attacker would need access to the hard copy of the key before they could hijack the account).


TL;DR: This definitely feels like the right direction for solving the problem via cross signing, but has unfortunately made me doubt whether this really is the right way to go in terms of final UX.

@uhoreg
Copy link
Member Author

uhoreg commented Dec 11, 2018

Thanks for the review, @erikjohnston.

How does this work with recovering an account (via the backup)? If you've lost all your devices then you won't be able to verify your new device, even though you've got all the backed up E2E keys.

There have been thoughts about being able to have a virtual device (whose key gets stored (encrypted) server-side) which is persistent and that can be used for cross-signing. So all of a user's real devices can sign the virtual device and (if they fetch and decrypt the keys from the server) vice versa. I think that this is similar to your "master identity key" idea.

As noted we'll need to be careful removing a device, since removing edges may disconnect the graph.

Yup. That's kind of similar the question at https://github.com/matrix-org/matrix-doc/pull/1681/files#diff-63d9ae063d120a03159774aff2c55af5R63, but a client could decide that once a device trusted via cross-signing, it could be permanently marked as "trusted".

Requiring clients to do graph algorithms in the presence of cycles feels like quite a burden.

I don't think it ends up being too bad. Cycles can be handled as just marking a node as "visited", and not re-visiting an already-visited node. The graph search algorithm gets slightly long (implementation in js-sdk here: https://github.com/matrix-org/matrix-js-sdk/pull/795/files#diff-fa4472db829c5a59596c29a2f43e8f9cR1243) but I wouldn't characterize it as being too difficult. (Though, having done graduate studies in graph theory, I may not be the best judge of what's "difficult".)

I wonder if we can tweak the model slightly and have a master identity key for the user, which is then used to sign device keys?

I'd be worried about having a single immutable master key that couldn't be removed, but having a virtual device that could be revoked and re-created like a normal device when needed, I think would work well. (It might also help with receiving encrypted messages when the user has no devices logged in.)

@erikjohnston
Copy link
Member

How does this work with recovering an account (via the backup)? If you've lost all your devices then you won't be able to verify your new device, even though you've got all the backed up E2E keys.

There have been thoughts about being able to have a virtual device (whose key gets stored (encrypted) server-side) which is persistent and that can be used for cross-signing. So all of a user's real devices can sign the virtual device and (if they fetch and decrypt the keys from the server) vice versa. I think that this is similar to your "master identity key" idea.

Yup, though you would need to special case the virtual device everywhere to ensure nothing gets confused and thinks its an actual device (e.g. you don't want users seeing it on the device lists and deleting it).

As noted we'll need to be careful removing a device, since removing edges may disconnect the graph.

Yup. That's kind of similar the question at https://github.com/matrix-org/matrix-doc/pull/1681/files#diff-63d9ae063d120a03159774aff2c55af5R63, but a client could decide that once a device trusted via cross-signing, it could be permanently marked as "trusted".

That doesn't really help when new users want to verify the devices though.

Requiring clients to do graph algorithms in the presence of cycles feels like quite a burden.

I don't think it ends up being too bad. Cycles can be handled as just marking a node as "visited", and not re-visiting an already-visited node. The graph search algorithm gets slightly long (implementation in js-sdk here: https://github.com/matrix-org/matrix-js-sdk/pull/795/files#diff-fa4472db829c5a59596c29a2f43e8f9cR1243) but I wouldn't characterize it as being too difficult. (Though, having done graduate studies in graph theory, I may not be the best judge of what's "difficult".)

It just strikes me as one of those things that is easy to just get wrong without really noticing, and a bug here would undermine the entire security of the system.

I wonder if we can tweak the model slightly and have a master identity key for the user, which is then used to sign device keys?

I'd be worried about having a single immutable master key that couldn't be removed, but having a virtual device that could be revoked and re-created like a normal device when needed, I think would work well. (It might also help with receiving encrypted messages when the user has no devices logged in.)

There's no reason why you couldn't mutate or revoke the master key in similar ways as you are proposing for attestations. TBH I'm more comfortable with the security around revoking the master key than individual attestations, as if you revoke the master key everyone will see that you have been compromised and should reverify against the new key. OTOH, if one of your verified device's are compromised you need to ensure that you revoke every single attestation that leads to that device, and hope that other users haven't verified against that compromised device (though I guess in practice here you'd just rely on the server doing the right thing when you hit /logout/all). Nonetheless, it becomes subtle trying to differentiate between "this device has been logged out nicely" vs "the device was logged out due to being compromised".

@richvdh richvdh changed the title MSC: cross-signing MSC1680: cross-signing Dec 12, 2018
Copy link
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

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

I've re-skimmed this but it feels like it is being superceded by MSC1756 (which generally does feel nicer), so I haven't paid it too much attention. I assume someone will put me right if that is an error...

TODO: `keys/query` may need to include devices that have been logged out, in
order to avoid unexpectedly breaking trust chains, so we may want to recommend
that devices remain in the result for *n* days after they log out? However, we
don't want to other devices to continue to encrypt for that device, so maybe
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
don't want to other devices to continue to encrypt for that device, so maybe
don't want other devices to continue to encrypt for that device, so maybe

know each other. In order to address this, clients may give users the option
of whether to publish attestations or not.

A malicious hommeserver is able to prevent distribution of revocations. For
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
A malicious hommeserver is able to prevent distribution of revocations. For
A malicious homeserver is able to prevent distribution of revocations. For


#### Additions to `GET /_matrix/client/r0/keys/changes`

This proposal will change the [`GET /_matrix/client/r0/keys/changes`](GET
Copy link
Member

Choose a reason for hiding this comment

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

broken link here

@anoadragon453 anoadragon453 added proposal A matrix spec change proposal and removed T-Core labels Jan 4, 2019
@uhoreg
Copy link
Member Author

uhoreg commented Jan 18, 2019

Dropping this in favour of #1756

@uhoreg uhoreg closed this Jan 18, 2019
@uhoreg uhoreg added the abandoned A proposal where the author/shepherd is not responsive label Jan 18, 2019
@richvdh richvdh removed the proposal A matrix spec change proposal label Mar 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
abandoned A proposal where the author/shepherd is not responsive proposal-pr
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants