update with user-signing and self-signing keys

pull/977/head
Hubert Chathi 6 years ago
parent c0b0db9a55
commit f4fe318a85

@ -1,4 +1,4 @@
# Cross-signing devices with master keys # Cross-signing devices with device signing keys
## Background ## Background
@ -8,186 +8,159 @@ this user must then verify each key on each of their devices. If Alice has *n*
devices, and Bob has *m* devices, then for Alice to be able to communicate with devices, and Bob has *m* devices, then for Alice to be able to communicate with
Bob on any of their devices, this involves *n×m* key verifications. Bob on any of their devices, this involves *n×m* key verifications.
One way to addresss this is for each user to use a "master key" for their One way to address this is for each user to use a device signing key to signs
identity which signs all of their devices. Thus another user who wishes to all of their devices. Thus another user who wishes to verify their identity
verify their identity only needs to verify their master, key and can use the only needs to verify the device signing key and can use the signatures created
master key to verify their devices. by the device signing key to verify their devices.
[MSC1680](https://github.com/matrix-org/matrix-doc/issues/1680) presents a [MSC1680](https://github.com/matrix-org/matrix-doc/issues/1680) presents a
different solution to the problem. different solution to the problem. A comparison between this proposal and
MSC1680 is presented below.
## Proposal ## Proposal
Each user has a "master identity key" that is used to sign their devices, and Each user has a self-signing key pair that is used to sign their own devices,
is signed by all of their devices. When one user (Alice) verifies another and a user-signing key pair that is used to sign other users' signing keys. A
user's (Bob's) identity, Alice will sign Bob's master identity key with her user's user-signing key is also signed by their own self-signing key. When one
master identity key. (This will mean that verification methods will need to be user (e.g. Alice) verifies another user's (Bob's) identity, Alice will sign
modified to pass along the master identity key.) Alice's device will trust Bob's self-signing key with her user-signing key. (This will mean that
Bob's device if: verification methods will need to be modified to pass along the self-signing
identity key.) Alice's device will trust Bob's device if:
- Alice's device is using a master identity key that has signed Bob's master
identity key, - Alice's device is using a self-signing key that has signed her user-signing key,
- Bob's master identity key has signed Bob's device, and - Alice's user-signing key has signed Bob's self-signing key, and
- none of those signatures have been revoked. - Bob's self-signing key has signed Bob's device key.
If Alice believes that her master identity key has been compromised, she can ### Key security
revoke it and create a new one. This means that all trust involving Alice
(i.e. Alice trusting other people and other people trusting Alice) needs to A user's private half of their user-signing key pair may be kept unlocked on a
start from scratch. device, but their self-signing key should not; the private half of the
self-signing key pair should only be stored encrypted, requiring a passphrase
The master identity key's private key can be stored encrypted on the server to access. By keeping the user-signing key unlocked, Alice can verify Bob's
(possibly along with the megolm key backup). Clients may or may not want to identity and distribute signatures to all her devices without needing to enter
store a copy of the private key locally. Doing so would mean that an attacker a passphrase to decrypt the key.
who steals a device has access to the private key, and so can forge trusted
devices until the user notices and resets their master key. However, not doing If a user's device is compromised, they can issue a new user-signing key,
so means that when the user verifies another user, they will need to re-fetch signed by their self-signing key, rendering the old user-signing key useless.
the private key, which means that they will need to re-enter their recovery If they are certain that the old user-signing key has not yet been used by an
key to decrypt it. attacker, then they may also reissue signatures made by the old user-signing
key by using the new user-signing key. Otherwise, they will need to re-verify
When a user logs in with a new device, they will fetch and decrypt the private the other users.
master key, sign the new device's key with the master key, and sign the master
key with the device's key. If a user's self-signing key is compromised, then the user will need to issue
both a new self-signing key and a new device-signing key. The user may sign
Users will only be allowed to see signatures made by their own master identity their new self-signing key with their old self-signing key, allowing other
key, or signatures made by other users' master identity keys on their own users who have verified the old self-signing key to automatically trust the new
devices. self-signing key if they wish to. Otherwise, the users will need to re-verify
each other.
The private halves of the user-signing key pair and self-signing key pair may
be stored encrypted on the server (possibly along with the megolm key backup)
so that they may be retrieved by new devices. FIXME: explain how to do this
### Signature distribution
Currently, users will only be allowed to see signatures made by their own
self-signing or user-signing keys, or signatures made by other users'
self-signing keys about their own devices. This is done in order to preserve
the privacy of social connections. Future proposals may define mechanisms for
distributing signatures to other users in order to allow for other web-of-trust
use cases.
### API description ### API description
#### Possible API 1 Public keys for the self-signing and user-signing keys are uploaded to the
servers using `/keys/device_signing/upload`. This endpoint requires [UI
Auth](https://matrix.org/docs/spec/client_server/r0.4.0.html#user-interactive-authentication-api).
Use the same API as MSC1680, but with additions. `POST /keys/device_signing/upload`
API to create new virtual device:
`POST /devices/create`
returns
``` json ``` json
{ {
"device_id": "ABCDEFG" "self_signing_key": {
} "user_id": "@alice:example.com",
``` "usage": ["self_signing"],
"keys": {
The server should not allow any client to use this device ID when logging in or "ed25519:base64+self+signing+public+key": "base64+self+signing+public+key",
registering; if a client tries to log in using this device ID, then the server }
must respond with an error. (FIXME: what error?) },
"user_signing_key": {
Send public key using `/keys/upload` as a normal device, but with a special
"algorithms" list:
`POST /keys/upload`
``` json
{
"device_keys": {
"user_id": "@alice:example.com", "user_id": "@alice:example.com",
"device_id": "ABCDEFG",
"algorithms": ["m.master"],
"keys": { "keys": {
"ed25519:ABCDEFG": "base64+public+key" "ed25519:base64+device+signing+public+key": "base64+device+signing+public+key",
}, },
"usage": ["user_signing"],
"signatures": { "signatures": {
"@alice:example.com": { "@alice:example.com": {
"ed25519:ABCDEFG": "base64+self+signature" "ed25519:base64+self+signing+public+key": "base64+signature"
} }
} }
} }
} }
``` ```
(This may require changes in what `device_id`s are accepted by `/keys/upload`.) In order to ensure that there will be no collisions in the `signatures`
property, the server must respond with an error (FIXME: what error?) if any of
Attestations/revocations will be uploaded and retrieved as described in the uploaded public keys match an existing device ID for the user. Similarly,
MSC1680. Creating a new master key would involve revoking the old master key if a user attempts to log in specifying a device ID matching one of the signing
by sending a signed revocation and deleting the device using `DELETE keys, the server must respond with an error (FIXME: what error?).
/devices/{deviceId}`, and then creating a new master key.
Private master key could be stored as part of the key backup (MSC1219), maybe If a user-signing key is uploaded, it must be signed by the current
as a special room ID + session ID, or possibly in the `auth_data` for the self-signing key (or the self-signing key that is included in the request)
backup version (the latter would mean that changing the master key would
require creating a new backup version, which may be what users need to do
anyways). Or the private master key could be stored in account data,
e.g. `/user/{userId}/account_data/m.master.{deviceId}`.
#### Possible API 2 If a previous self-signing key exists, then the new self-signing key must have
a `replaces` property whose value is the previous public self-signing key.
Otherwise the server must respond with an error (FIXME: what error?). The new
self-signing key may also be signed with the old self-signing key.
Treat master key separately from normal devices and adding special handling for FIXME: document `usage` property
them. This might result in a nicer API, but make the implementation more
complicated. For example, the server could automatically add master key
signatures into a device's `signatures` field, rather than shipping the
attestations separately.
Send public key using `/keys/upload`, under the `master_key` property. After uploading self-signing and user-signing keys, they will be included under
(Alternatively, could use a special endpoint, like `/keys/master/upload`.) the `/keys/query` endpoint under the `self_signing_key` and `user_signing_key`
properties, respectively. The `user_signing_key` will only be included when a
user requests their own keys.
`POST /keys/upload` `POST /keys/query`
``` json ``` json
{ {
"master_key": { "device_keys": {
"user_id": "@alice:example.com", "@alice:example.com": []
"key_id": "ABCDEFG", },
"algorithm": "ed25519", "token": "string"
"key": "base64+public+key",
"signatures": {
"@alice:example.com": {
"ed25519:ABCDEFG": "base64+self+signature"
}
}
}
} }
``` ```
The key ID must be unique within the scope of a given user, and must not match response:
any device ID. This is required so that there will be no collisions in the
`signatures` property.
(FIXME: how do we make sure that the key ID doesn't collide with an existing
device ID? Just send an error and let the client retry?)
The server should not allow any client to use the key ID as their device ID
when logging in or registering; if a client tries to log in using this device
ID, then the server must respond with an error. (FIXME: what error?)
Uploading a new master key should invalidate any previous master key.
After uploading a master key, it will be included under the `/keys/query`
endpoint under the `master_key` property.
`GET /keys/query`
``` json ``` json
{ {
"failures": {}, "failures": {},
"master_key": { "device_keys": {
"@alice:example.com": {
"user_id": "@alice:example.com",
"key_id": "ABCDEFG",
"algorithm": "ed25519",
"key": "base64+public+key",
"signatures": {
"@alice:example.com": { "@alice:example.com": {
"ed25519:ABCDEFG": "base64+self+signature" // ...
} }
},
"self_signing_key": {
"@alice:example.com": {
"user_id": "@alice:example.com",
"usage": ["self_signing"],
"keys": {
"ed25519:base64+self+signing+public+key": "base64+self+signing+public+key"
} }
} }
} }
} }
``` ```
Signatures can be uploaded using `/keys/upload`, under the `signatures` Signatures of keys can be uploaded using `/keys/signatures/upload`.
property. (Alternatively, could use a special endpoint, like
`/keys/signatures/upload`.)
For example, Alice signs one of her devices (HIJKLMN), and Bob's master key. For example, Alice signs one of her devices (HIJKLMN), and Bob's self-signing key.
`POST /keys/upload` `POST /keys/signatures/upload`
``` json ``` json
{ {
"signatures": {
"@alice:example.com": { "@alice:example.com": {
"HIJKLMN": { "HIJKLMN": {
"user_id": "@alice:example.com", "user_id": "@alice:example.com",
@ -202,21 +175,21 @@ For example, Alice signs one of her devices (HIJKLMN), and Bob's master key.
}, },
"signatures": { "signatures": {
"@alice:example.com": { "@alice:example.com": {
"ed25519:ABCDEFG": "base64+signature+of+HIJKLMN" "ed25519:base64+user+signing+public+key": "base64+signature+of+HIJKLMN"
} }
} }
} }
}, },
"@bob:example.com": { "@bob:example.com": {
"OPQRSTU": { "bobs+base64+self+signing+public+key": {
"user_id": "@bob:example.com", "user_id": "@bob:example.com",
"key_id": "OPQRSTU", "keys": {
"algorithm": "ed25519", "ed25519:bobs+base64+self+signing+public+key": "bobs+base64+self+signing+public+key"
"key": "base64+ed25519+key", },
"usage": ["self_signing"],
"signatures": { "signatures": {
"@alice:example.com": { "@alice:example.com": {
"ed25519:ABCDEFG": "base64+signature+of+OPQRSTU" "ed25519:base64+user+signing+public+key": "base64+signature+of+bobs+self+signing+key"
}
} }
} }
} }
@ -228,7 +201,18 @@ After Alice uploads a signature for her own devices, her signature will be
included in the results of the `/keys/query` request when *anyone* requests her included in the results of the `/keys/query` request when *anyone* requests her
keys: keys:
`GET /keys/query` `POST /keys/query`
``` json
{
"device_keys": {
"@alice:example.com": []
},
"token": "string"
}
```
response:
``` json ``` json
{ {
@ -249,7 +233,7 @@ keys:
"signatures": { "signatures": {
"@alice:example.com": { "@alice:example.com": {
"ed25519:HIJKLMN": "base64+self+signature", "ed25519:HIJKLMN": "base64+self+signature",
"ed25519:ABCDEFG": "base64+signature+of+HIJKLMN" "ed25519:base64+user+signing+public+key": "base64+signature+of+HIJKLMN"
} }
}, },
"unsigned": { "unsigned": {
@ -258,41 +242,40 @@ keys:
} }
} }
}, },
"master_keys": { "self_signing_key": {
"@alice:example.com": {
"user_id": "@alice:example.com", "user_id": "@alice:example.com",
"key_id": "ABCDEFG", "usage": ["self_signing"],
"algorithm": "ed25519", "keys": {
"key": "base64+public+key", "ed25519:base64+self+signing+public+key": "base64+self+signing+public+key",
"signatures": {
"@alice:example.com": {
"ed25519:ABCDEFG": "base64+self+signature"
}
}
} }
} }
} }
``` ```
After Alice uploads a signature for Bob's master key, her signature will be After Alice uploads a signature for Bob's user-signing key, her signature will
included in the results of the `/keys/query` request when Alice requests Bob's be included in the results of the `/keys/query` request when Alice requests
key: Bob's key:
`GET /keys/query` `GET /keys/query`
``` json ``` json
{ {
"failures": {}, "failures": {},
"master_key": { "device_keys": {
"@bob:example.com": {
// ...
}
},
"self_signing_key": {
"@bob:example.com": { "@bob:example.com": {
"user_id": "@bob:example.com", "user_id": "@bob:example.com",
"key_id": "OPQRSTU", "keys": {
"algorithm": "ed25519", "ed25519:bobs+base64+self+signing+public+key": "bobs+base64+self+signing+public+key"
"key": "base64+ed25519+key", },
"usage": ["self_signing"],
"signatures": { "signatures": {
"@alice:example.com": { "@alice:example.com": {
"ed25519:OPQRSTU": "base64+self+signature+OPQRSTU", "ed25519:base64+user+signing+public+key": "base64+signature+of+bobs+self+signing+key"
"ed25519:ABCDEFG": "base64+signature+of+OPQRSTU"
} }
} }
} }
@ -300,6 +283,8 @@ key:
} }
``` ```
FIXME: s2s stuff
## Comparison with MSC1680 ## Comparison with MSC1680
MSC1680 suffers from the fact that the attestation graph may be arbitrarily MSC1680 suffers from the fact that the attestation graph may be arbitrarily
@ -323,8 +308,8 @@ look like:
If Bob replaces his Dynabook without re-verifying with Alice, this will split If Bob replaces his Dynabook without re-verifying with Alice, this will split
the graph and Alice will not be able to verify Bob's other devices. In the graph and Alice will not be able to verify Bob's other devices. In
contrast, in this proposal, Alice and Bob's master keys directly sign each contrast, in this proposal, Alice and Bob sign each other's self-signing key
other, and the attestation graph would look like: with their user-signing keys, and the attestation graph would look like:
![](images/1756-graph2.dot.png) ![](images/1756-graph2.dot.png)
@ -337,12 +322,16 @@ devices, as there may be stale attestations and revocations lingering around.
(This also relates to the question of whether a revocation should only revoke (This also relates to the question of whether a revocation should only revoke
the signature created previously by the device making the attestation, or the signature created previously by the device making the attestation, or
whether it should be a statement that the device should not be trusted at all.) whether it should be a statement that the device should not be trusted at all.)
In contrast, with this proposal, there is a clear way to rebuild the In contrast, with this proposal, if a device is stolen, then only the
attestation graph: create a new master identity key, and re-verify all devices user-signing key must be re-issued.
with it.
## Security considerations ## Security considerations
This proposal relies on servers to communicate when self-signing or
user-signing keys are deleted and replaced. An attacker who is able to both
steal a user's device and control their homeserver could prevent that device
from being marked as untrusted.
## Conclusion ## Conclusion
This proposal presents an alternative cross-signing mechanism to MSC1680. This proposal presents an alternative cross-signing mechanism to MSC1680.

@ -1,13 +1,18 @@
graph { digraph {
A1 [label="A's PDP-11"] A1 [label="A's PDP-11"]
AM [label="A's master key"]
A2 [label="A's Osborne 2"] A2 [label="A's Osborne 2"]
AS [label="A's self-signing key"]
AU [label="A's user-signing key"]
BU [label="B's user-signing key"]
BS [label="B's self-signing key"]
B1 [label="B's Dynabook"] B1 [label="B's Dynabook"]
BM [label="B's master key"]
B2 [label="B's VAX"] B2 [label="B's VAX"]
A1 -- AM AS -> A1
AM -- A2 AS -> A2
AM -- BM AS -> AU
B1 -- BM AU -> BS
BM -- B2 BS -> BU
BU -> AS
BS -> B1
BS -> B2
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Loading…
Cancel
Save