Merge 7d56dc0b5d
into 72e694ba0b
commit
0c6fee1cab
@ -0,0 +1,144 @@
|
||||
# MSC3834: Opportunistic user key pinning (TOFU)
|
||||
|
||||
In the Matrix spec at present, there are no real provisions for
|
||||
properly authenticating devices belonging to other users, aside from
|
||||
the fairly rare cases where users actually take the time to verify
|
||||
each other out-of-band. Most clients encourage users to cross-sign
|
||||
their own devices, but this has little practical value for most users
|
||||
in the ecosystem at present, unless you're willing to verify all of
|
||||
your contacts or trust the user keys reported by homeservers.
|
||||
|
||||
The goal of this proposal is to establish a TOFU-style mechanism where
|
||||
users' signing keys are pinned when they're first encountered;
|
||||
internally, this will look similar to user verification, but will
|
||||
require no action on either user's part, and correspondingly will not
|
||||
be considered as high a level of trust. Nevertheless, this at least
|
||||
raises the bar for Mallory-in-the-middle attacks by malicious
|
||||
homeservers, as they can no longer quietly falsify signing keys for
|
||||
users who are already in contact with each other.
|
||||
|
||||
## Proposal
|
||||
|
||||
This proposal adds a fourth ed25519 keypair to a user's set of
|
||||
cross-signing keys: the TOFU Signing Key (TSK), identified by
|
||||
`m.cross_signing.tofu_signing`. This key will be uploaded and stored
|
||||
alongside the MSK, SSK, and USK; it will be published to the
|
||||
`keys/device_signing/upload` using the new optional field
|
||||
`tofu_signing_key`.
|
||||
|
||||
Whenever a user Alice and a user Bob are in a room together for the
|
||||
first time, Alice's device will automatically and silently cross-sign
|
||||
Bob's MSK using her TSK. This effectively pins Bob's MSK; in future
|
||||
interactions, Alice will be able to check that any device of Bob's is
|
||||
signed by Bob's SSK which is signed by the pinned MSK, confirming that
|
||||
the device really does belong to Bob as long as that very first
|
||||
interaction wasn't tampered with. If Alice's device later observes an
|
||||
MSK for Bob that differs from the one signed by her TSK, the device
|
||||
may warn Alice that Bob's key has changed, and could potentially
|
||||
refuse to share keys with devices that aren't signed under the
|
||||
original SSK/MSK until Alice chooses to accept the new key.
|
||||
|
||||
After a device signs one or several new MSKs with the TSK (on joining
|
||||
a new room, or observing a new member join a room), it should upload
|
||||
these new signatures to the homeserver via the
|
||||
`keys/signatures/upload` API endpoint. However, it is important to
|
||||
ensure that the homeserver cannot perform a denial-of-service attack
|
||||
on key pinning by simply dropping TOFU signatures. For this reason, a
|
||||
user's devices should periodically ask each other to confirm a hash of
|
||||
the complete set of all cross-signing signatures created by that
|
||||
user. At any point, a device may send any or all of the user's other
|
||||
devices an encrypted to-device message, with event type
|
||||
`m.signatures_hash_request` and no fields. When the device receives
|
||||
the message, it should reply with an encrypted to-device message with
|
||||
event type `m.signatures_hash` and one field `sha256`. This field
|
||||
contains a SHA256 hash of the canonical JSON encoding of the complete
|
||||
set of cross-signing signatures known to that device, in the format
|
||||
for uploading to `keys/signatures/upload`, excluding any unsigned
|
||||
fields - that is, a map from user ID, to key ID, to a signed JSON
|
||||
object for that key.
|
||||
|
||||
## Potential issues
|
||||
|
||||
If a client does choose to warn users every time a pinned MSK changes,
|
||||
users in many large rooms could be overwhelmed with warnings from
|
||||
random people losing their devices and performing key resets. There
|
||||
are several things clients can do to alleviate this. First, rather
|
||||
than popping up a warning immediately in a toast or dialog as soon as
|
||||
a key changes, clients should only warn the user when they actually
|
||||
open one of the rooms where the changed key is present. In addition,
|
||||
users should be given the option to automatically accept all future
|
||||
key changes in a particular room, and the option to accept all key
|
||||
changes globally if that's in line with the user's threat
|
||||
model. Clients could still display a small state-event-like message in
|
||||
room timelines notifying the user of a key change, or could simply
|
||||
accept all key changes silently.
|
||||
|
||||
## Security considerations
|
||||
|
||||
In the malicious homeserver scenario that this proposal aims to
|
||||
mitigate, the homeserver could attempt to simply exclude TSK
|
||||
signatures from its responses to key queries, preventing the
|
||||
propagation of pinned keys between devices, and possibly even causing
|
||||
a device to lose track of pinned keys over time. To prevent this,
|
||||
it's important that clients maintain a persistent record of TSK
|
||||
signatures without relying on the homeserver to store that
|
||||
information. Signatures must never be removed from this record, even
|
||||
if they aren't present in homeserver responses. However, if multiple
|
||||
valid signatures for the same key from the same TSK have been created
|
||||
due to race conditions, only the signature whose base64 representation
|
||||
comes first lexicographically should be kept.
|
||||
|
||||
When devices ask each other to confirm the hash of the set of
|
||||
cross-signing signatures, they may not receive a response; this could
|
||||
be because the other device is offline, it could be because the device
|
||||
is using an older version of the spec and doesn't understand the
|
||||
request, or it could be because the homeserver is performing a
|
||||
denial-of-service attack. If a device doesn't get a response, and does
|
||||
see other activity from the other device, it could possibly eventually
|
||||
display a warning encouraging the user to upgrade their other
|
||||
device. If the device observes too many missing key indices in its
|
||||
to-device Olm session, however, that may be a sign that the homeserver
|
||||
is dropping messages.
|
||||
|
||||
In this threat model, another thing the homeserver can do is falsely
|
||||
claim that the user's cross-signing keys have been reset by another
|
||||
device. For the most part, this simply amounts to a denial-of-service
|
||||
attack on cross-signing, which is difficult to prevent in
|
||||
general. However, it's important to note that if a formerly-verified
|
||||
device is told by the server that there's been a key reset, it must
|
||||
still hold onto its record of signatures created with the old TSK, and
|
||||
re-sign those with the new TSK once it has been able to confirm the
|
||||
new MSK as part of becoming re-verified.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
This proposal does not add any new API endpoints, but does add some
|
||||
new fields and message types to existing data structures. These field
|
||||
names and message types will be prefixed with `org.matrix.msc3834.v1`.
|
||||
Test implementations can identify the TSK as
|
||||
`org.matrix.msc3834.v1.cross_signing.tofu_signing`, use the optional
|
||||
field `org.matrix.msc3834.v1.tofu_signing_key` for the
|
||||
`keys/device_signing/upload` endpoint, and use the message types
|
||||
`org.matrix.msc3834.v1.signatures_hash_request` and
|
||||
`org.matrix.msc3834.v1.signatures_hash` for exchanging hashes of the
|
||||
set of cross-signing signatures.
|
||||
|
||||
## Migration notes
|
||||
|
||||
When a device with this functionality first comes online, if the user
|
||||
doesn't already have a TSK and if the device possesses the private
|
||||
MSK, it should create a new TSK, sign it with the MSK, and publish it
|
||||
to `keys/device_signing/upload`. This endpoint requires
|
||||
authentication, and therefore the user may need to be prompted for a
|
||||
password when they open their upgraded client. If the user already has
|
||||
server-side secret storage set up, the device should also store the
|
||||
private TSK encrypted in secret storage.
|
||||
|
||||
If the user does already have a TSK, devices should obtain the private
|
||||
key either from secret storage or by requesting the secret from other
|
||||
devices. In the event of a race condition where multiple devices have
|
||||
upgraded and created TSKs, the TSK whose base64 representation comes
|
||||
first lexicographically will take precedence. Once other devices have
|
||||
received the private key for the winning TSK, they should use it to
|
||||
re-sign and re-submit any TOFU signatures they've already created, and
|
||||
replace any signatures by the old TSK in their persistent records.
|
Loading…
Reference in New Issue