Merge 7d56dc0b5d into e9f0f31d27
commit
ee7d6c9381
@ -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