From a8910fe323d0d1772de6d7cce74c055fdbfa888f Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 12 May 2020 17:24:06 -0400 Subject: [PATCH] initial spec for cross-signing --- api/client-server/cross_signing.yaml | 210 ++++++++++++++++++ .../definitions/cross_signing_key.yaml | 55 +++++ api/client-server/keys.yaml | 70 +++++- .../event-schemas/m.device_list_update.yaml | 4 +- .../event-schemas/m.signing_key_update.yaml | 68 ++++++ api/server-server/user_devices.yaml | 34 +++ api/server-server/user_keys.yaml | 44 ++++ .../modules/end_to_end_encryption.rst | 90 +++++++- specification/server_server_api.rst | 2 + 9 files changed, 572 insertions(+), 5 deletions(-) create mode 100644 api/client-server/cross_signing.yaml create mode 100644 api/client-server/definitions/cross_signing_key.yaml create mode 100644 api/server-server/definitions/event-schemas/m.signing_key_update.yaml diff --git a/api/client-server/cross_signing.yaml b/api/client-server/cross_signing.yaml new file mode 100644 index 00000000..ba98ee33 --- /dev/null +++ b/api/client-server/cross_signing.yaml @@ -0,0 +1,210 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +swagger: '2.0' +info: + title: "Matrix Client-Server Cross Signing API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% +consumes: + - application/json +produces: + - application/json +securityDefinitions: + $ref: definitions/security.yaml +paths: + "/keys/device_signing/upload": + post: + summary: Upload cross-signing keys. + description: |- + Publishes cross-signing keys for the user. + + This API endpoint uses the `User-Interactive Authentication API`_. + operationId: uploadCrossSigningKeys + security: + - accessToken: [] + parameters: + - in: body + name: keys + description: |- + The keys to be published. + schema: + type: object + properties: + master_key: + description: |- + Optional. The user\'s master key. + allOf: + - $ref: definitions/cross_signing_key.yaml + self_signing_key: + description: |- + Optional. The user\'s self-signing key. Must be signed with + the accompanied master, or by the user\'s most recently + uploaded master key if no master key is included in the + request. + allOf: + - $ref: definitions/cross_signing_key.yaml + user_signing_key: + description: |- + Optional. The user\'s user-signing key. Must be signed with + the accompanied master, or by the user\'s most recently + uploaded master key if no master key is included in the + request. + allOf: + - $ref: definitions/cross_signing_key.yaml + example: { + "master_key": { + "user_id": "@alice:example.com", + "usage": ["master"], + "keys": { + "ed25519:base64+master+public+key": "base64+master+public+key", + } + }, + "self_signing_key": { + "user_id": "@alice:example.com", + "usage": ["self_signing"], + "keys": { + "ed25519:base64+self+signing+public+key": "base64+self+signing+master+public+key", + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+master+public+key": "signature+of+self+signing+key" + } + } + }, + "user_signing_key": { + "user_id": "@alice:example.com", + "usage": ["user_signing"], + "keys": { + "ed25519:base64+user+signing+public+key": "base64+user+signing+master+public+key", + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+master+public+key": "signature+of+user+signing+key" + } + } + } + } + responses: + 200: + description: The provided keys were successfully uploaded. + schema: + type: object + example: {} + 400: + description: |- + The input was invalid in some way. This can include one of the + following error codes: + + * ``M_INVALID_SIGNATURE``: The self-signing or user-signing key + had an incorrect signature + * ``M_FORBIDDEN``: The public key of one of the keys is the same as + one of the user\'s device IDs. + schema: + type: object + example: { + "errcode": "M_INVALID_SIGNATURE", + "error": "Invalid signature" + } + "/keys/signatures/upload": + post: + summary: Upload cross-signing signatures. + description: |- + Publishes cross-signing signatures for the user. The request body is a + map from user ID to key ID to signed JSON object. + operationId: uploadCrossSigningSignatures + security: + - accessToken: [] + parameters: + - in: body + name: signatures + description: |- + The signatures to be published. + schema: + type: object + example: { + "@alice:example.com": { + "HIJKLMN": { + "user_id": "@alice:example.com", + "device_id": "HIJKLMN", + "algorithms": [ + "m.olm.curve25519-aes-sha256", + "m.megolm.v1.aes-sha" + ], + "keys": { + "curve25519:HIJKLMN": "base64+curve25519+key", + "ed25519:HIJKLMN": "base64+ed25519+key" + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+self+signing+public+key": "base64+signature+of+HIJKLMN" + } + } + }, + "base64+master+public+key": { + "user_id": "@alice:example.com", + "usage": ["master"], + "keys": { + "ed25519:base64+master+public+key": "base64+master+public+key" + }, + "signatures": { + "@alice:example.com": { + "ed25519:HIJKLMN": "base64+signature+of+master+key" + } + } + } + }, + "@bob:example.com": { + "bobs+base64+self+signing+public+key": { + "user_id": "@bob:example.com", + "keys": { + "ed25519:bobs+base64+master+public+key": "bobs+base64+master+public+key" + }, + "usage": ["master"], + "signatures": { + "@alice:example.com": { + "ed25519:base64+user+signing+public+key": "base64+signature+of+bobs+master+key" + } + } + } + } + } + responses: + 200: + description: The provided signatures were processed. + schema: + type: object + properties: + failures: + type: object + description: |- + A map from user ID to key ID to an error for any signatures + that failed. If a signature was invalid, the ``errcode`` will + be set to ``M_INVALID_SIGNATURE``. + additionalProperties: + type: object + additionalProperties: + type: object + title: Error + example: { + "@alice:example.com": { + "HIJKLMN": { + "errcode": "M_INVALID_SIGNATURE", + "error": "Invalid signature" + } + } + } diff --git a/api/client-server/definitions/cross_signing_key.yaml b/api/client-server/definitions/cross_signing_key.yaml new file mode 100644 index 00000000..aa8dea2e --- /dev/null +++ b/api/client-server/definitions/cross_signing_key.yaml @@ -0,0 +1,55 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +title: CrossSigningKey +description: Cross signing key +properties: + user_id: + type: string + description: |- + The ID of the user the key belongs to. + example: "@alice:example.com" + usage: + type: array + description: |- + What the key is used for. + items: + type: string + enum: ["master", "self_signing", "user_signing"] + keys: + type: object + additionalProperties: + type: string + description: |- + The public key. The object must have exactly one property, whose name is + in the form ``:``, and whose value + is the unpadded base64 public key. + example: + "ed25519:alice+base64+public+key": "alice+base64+public+key" + signatures: + type: object + title: Signatures + description: |- + Signatures of the key, calculated using the process described at `Signing + JSON`_. Optional for the master key. Other keys must be signed by the + user\'s master key. + example: { + "@alice:example.com": { + "ed25519:alice+base64+master+key": "signature+of+key" + } + } +required: + - user_id + - usage + - keys diff --git a/api/client-server/keys.yaml b/api/client-server/keys.yaml index 69e39def..b4b19854 100644 --- a/api/client-server/keys.yaml +++ b/api/client-server/keys.yaml @@ -1,5 +1,6 @@ # Copyright 2016 OpenMarket Ltd # Copyright 2018 New Vector Ltd +# Copyright 2020 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -233,7 +234,74 @@ paths: "device_display_name": "Alice's mobile phone" } } - + master_keys: + type: object + description: |- + Information on the master cross-signing keys of the queried users. + A map from user ID, to master key information. For each key, the + information returned will be the same as uploaded via + ``/keys/device_signing/upload``. + additionalProperties: + allOf: + - $ref: definitions/cross_signing_key.yaml + example: { + "@alice:example.com": { + "user_id": "@alice:example.com", + "usage": ["master"], + "keys": { + "ed25519:base64+master+public+key": "base64+master+public+key", + } + } + } + self_signing_keys: + type: object + description: |- + Information on the self-signing keys of the queried users. A map + from user ID, to self-signing key information. For each key, the + information returned will be the same as uploaded via + ``/keys/device_signing/upload``. + additionalProperties: + allOf: + - $ref: definitions/cross_signing_key.yaml + example: { + "@alice:example.com": { + "user_id": "@alice:example.com", + "usage": ["self_signing"], + "keys": { + "ed25519:base64+self+signing+public+key": "base64+self+signing+master+public+key", + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+master+public+key": "signature+of+self+signing+key" + } + } + } + } + user_signing_keys: + type: object + description: |- + Information on the user-signing key of the user making the + request, if they queried their own device information. A map + from user ID, to user-signing key information. The + information returned will be the same as uploaded via + ``/keys/device_signing/upload``. + additionalProperties: + allOf: + - $ref: definitions/cross_signing_key.yaml + example: { + "@alice:example.com": { + "user_id": "@alice:example.com", + "usage": ["user_signing"], + "keys": { + "ed25519:base64+user+signing+public+key": "base64+user+signing+master+public+key", + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+master+public+key": "signature+of+user+signing+key" + } + } + } + } tags: - End-to-end encryption "/keys/claim": diff --git a/api/server-server/definitions/event-schemas/m.device_list_update.yaml b/api/server-server/definitions/event-schemas/m.device_list_update.yaml index d511bfae..ba22aace 100644 --- a/api/server-server/definitions/event-schemas/m.device_list_update.yaml +++ b/api/server-server/definitions/event-schemas/m.device_list_update.yaml @@ -1,4 +1,5 @@ # Copyright 2018 New Vector Ltd +# Copyright 2020 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,7 +18,8 @@ title: m.device_list_update description: |- An EDU that lets servers push details to each other when one of their users adds a new device to their account, required for E2E encryption to correctly - target the current set of devices for a given user. + target the current set of devices for a given user. This event will also be + sent when an existing device gets a new cross-signing signature. # FIXME: It's very unclear why we have this API surface for synchronising # device lists, rather than just using a room (which could also be used for diff --git a/api/server-server/definitions/event-schemas/m.signing_key_update.yaml b/api/server-server/definitions/event-schemas/m.signing_key_update.yaml new file mode 100644 index 00000000..db75f1ed --- /dev/null +++ b/api/server-server/definitions/event-schemas/m.signing_key_update.yaml @@ -0,0 +1,68 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type: object +title: m.signing_key_update +description: |- + An EDU that lets servers push details to each other when one of their users + updates their cross-signing keys. +allOf: + - $ref: ../edu.yaml + - type: object + properties: + edu_type: + type: enum + enum: ['m.signing_key_update'] + description: The string ``m.signing_update``. + example: "m.signing_key_update" + content: + type: object + description: The updated signing keys. + title: Signing Key Update + properties: + user_id: + type: string + description: The user ID whose cross-signing keys have changed. + example: "@alice:example.com" + master_key: + type: object + allOf: + - $ref: ../../../client-server/definitions/cross_signing_key.yaml + # FIXME: why isn't the doc generator picking up this example? + - example: { + "user_id": "@alice:example.com", + "usage": ["self_signing"], + "keys": { + "ed25519:base64+self+signing+public+key": "base64+self+signing+master+public+key", + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+master+public+key": "signature+of+self+signing+key" + } + } + } + self_signing_key: + type: object + allOf: + - $ref: ../../../client-server/definitions/cross_signing_key.yaml + # FIXME: why isn't the doc generator picking up this example? + - example: { + "user_id": "@alice:example.com", + "usage": ["master"], + "keys": { + "ed25519:base64+master+public+key": "base64+master+public+key", + } + } + required: + - user_id diff --git a/api/server-server/user_devices.yaml b/api/server-server/user_devices.yaml index 362f9baa..6bff54c0 100644 --- a/api/server-server/user_devices.yaml +++ b/api/server-server/user_devices.yaml @@ -1,4 +1,5 @@ # Copyright 2018 New Vector Ltd +# Copyright 2020 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -81,4 +82,37 @@ paths: description: Optional display name for the device. example: "Alice's Mobile Phone" required: ['device_id', 'keys'] + master_key: + type: object + description: |- + The user\'s master cross-signing key. + allOf: + - $ref: ../client-server/definitions/cross_signing_key.yaml + # FIXME: why isn't the doc generator picking up this example? + - example: { + "user_id": "@alice:example.com", + "usage": ["master"], + "keys": { + "ed25519:base64+master+public+key": "base64+master+public+key", + } + } + self_signing_keys: + type: object + description: |- + The user\'s self-signing key. + allOf: + - $ref: ../client-server/definitions/cross_signing_key.yaml + # FIXME: why isn't the doc generator picking up this example? + - example: { + "user_id": "@alice:example.com", + "usage": ["self_signing"], + "keys": { + "ed25519:base64+self+signing+public+key": "base64+self+signing+master+public+key", + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+master+public+key": "signature+of+self+signing+key" + } + } + } required: ['user_id', 'stream_id', 'devices'] diff --git a/api/server-server/user_keys.yaml b/api/server-server/user_keys.yaml index 93237d80..9c11ca84 100644 --- a/api/server-server/user_keys.yaml +++ b/api/server-server/user_keys.yaml @@ -1,4 +1,5 @@ # Copyright 2018 New Vector Ltd +# Copyright 2020 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -171,6 +172,49 @@ paths: type: string description: The display name which the user set on the device. + master_keys: + type: object + description: |- + Information on the master cross-signing keys of the queried users. + A map from user ID, to master key information. For each key, the + information returned will be the same as uploaded via + ``/keys/device_signing/upload``. + additionalProperties: + allOf: + - $ref: ../client-server/definitions/cross_signing_key.yaml + example: { + "@alice:example.com": { + "user_id": "@alice:example.com", + "usage": ["master"], + "keys": { + "ed25519:base64+master+public+key": "base64+master+public+key", + } + } + } + self_signing_keys: + type: object + description: |- + Information on the self-signing keys of the queried users. A map + from user ID, to self-signing key information. For each key, the + information returned will be the same as uploaded via + ``/keys/device_signing/upload``. + additionalProperties: + allOf: + - $ref: ../client-server/definitions/cross_signing_key.yaml + example: { + "@alice:example.com": { + "user_id": "@alice:example.com", + "usage": ["self_signing"], + "keys": { + "ed25519:base64+self+signing+public+key": "base64+self+signing+master+public+key", + }, + "signatures": { + "@alice:example.com": { + "ed25519:base64+master+public+key": "signature+of+self+signing+key" + } + } + } + } required: ['device_keys'] examples: application/json: { diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 4b433f17..35ed688d 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -1,5 +1,5 @@ .. Copyright 2016 OpenMarket Ltd -.. Copyright 2019 The Matrix.org Foundation C.I.C. +.. Copyright 2019-2020 The Matrix.org Foundation C.I.C. .. .. Licensed under the Apache License, Version 2.0 (the "License"); .. you may not use this file except in compliance with the License. @@ -736,6 +736,88 @@ translation of those descriptions. Client authors SHOULD collaborate to create a common set of translations for all languages. +Cross-signing +~~~~~~~~~~~~~ + +Rather than requiring Alice to verify each of Bob's devices will each of her +own devices and vice versa, Matrix allows users to cross-sign their keys so +that Alice and Bob only need to verify once. With cross-signing, each user has +a set of cross-signing keys that are used to sign their own device keys and +other users' keys, and can be used to trust device keys that were not verified +directly. + +With cross-signing, each user has three cross-signing ed25519 keys pairs: + +* a master key that serves as the user's identity in cross-signing and signs + their other cross-signing keys; +* a user-signing key that signs other users' master keys, and +* a self-signing key that signs the user's own device keys. + +The master key may also be used to sign other items such as the backup key. The +master key may also be signed by the user's own device keys to aid in migrating +from device verifications: if Alice's device had previously verified Bob's +device and Bob's device has signed his master key, then Alice's device can +trust Bob's master key, and she can sign it with her user-signing key. + +Users upload their cross-signing keys to the server using `POST +/_matrix/client/r0/keys/device_signing/upload`_. When Alice uploads new +cross-signing keys, her user ID will appear in the ``changed`` property of the +``device_lists`` field of the ``/sync`` of response of all users who share an +encrypted room with her. When Bob sees Alice's user ID in his ``/sync``, he +will call `POST /_matrix/client/r0/keys/query`_ to retrieve Alice's device and +cross-signing keys. + +If Alice has a device and wishes to send an encrypted message to Bob, she can +trust Bob's device if: + +- Alice's device is using a master key that has signed her user-signing key, +- Alice's user-signing key has signed Bob's master key, +- Bob's master key has signed Bob's self-signing key, and +- Bob's self-signing key has signed Bob's device key. + +Verification methods can be used to verify a user's master key by using the +master public key, encoded using unpadded base64, as the device ID, and +treating it as a normal device. For example, if Alice and Bob verify each other +using SAS, Alice's ``m.key.verification.mac`` message to Bob may include +``"ed25519:alices+master+public+key": "alices+master+public+key"`` in the ``mac`` +property. Servers therefore must ensure that device IDs will not collide with +cross-signing public keys. + +Key and signature security +<<<<<<<<<<<<<<<<<<<<<<<<<< + +A user's master key could allow an attacker to impersonate that user to other +users, or other users to that user. Thus clients must ensure that the private +part of the master key is treated securely. If clients do not have a secure +means of storing the master key (such as a secret storage system provided by +the operating system), then clients must not store the private part. If a user +changes their master key, clients of users that they communicate with must +notify their users about the change. + +A user's user-signing and self-signing keys are intended to be easily +replaceable if they are compromised by re-issuing a new key signed by the +user's master key and possibly by re-verifying devices or users. However, +doing so relies on the user being able to notice when their keys have been +compromised, and it involves extra work for the user, and so although clients +do not have to treat the private parts as sensitively as the master key, +clients should still make efforts to store the private part securely, or not +store it at all. Clients will need to balance the security of the keys with +the usability of signing users and devices when performing key verification. + +To avoid leaking of social graphs, servers will only allow users to see: + +* signatures made by the user's own master, self-signing or user-signing keys, +* signatures made by the user's own devices about their own master key, +* signatures made by other users' self-signing keys about their respective + devices, +* signatures made by other users' master keys about their respective + self-signing key, or +* signatures made by other users' devices about their respective master keys. + +Users will not be able to see signatures made by other users' user-signing keys. + +{{cross_signing_cs_http_api}} + .. section name changed, so make sure that old links keep working .. _key-sharing: @@ -1124,7 +1206,8 @@ device_lists DeviceLists Optional. Information on e2e device updates. Note: ========= ========= ============================================= Parameter Type Description ========= ========= ============================================= -changed [string] List of users who have updated their device identity keys, +changed [string] List of users who have updated their device identity or + cross-signing keys, or who now share an encrypted room with the client since the previous sync response. left [string] List of users with whom we do not share any encrypted rooms @@ -1134,7 +1217,8 @@ left [string] List of users with whom we do not share any encrypted rooms .. NOTE:: For optimal performance, Alice should be added to ``changed`` in Bob's sync only - when she adds a new device, or when Alice and Bob now share a room but didn't + when she updates her devices or cross-signing keys, or when Alice and Bob now + share a room but didn't share any room previously. However, for the sake of simpler logic, a server may add Alice to ``changed`` when Alice and Bob share a new room, even if they previously already shared a room. diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 655a8cfc..61308a09 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -1026,6 +1026,8 @@ through to federation, and have the response also be proxied through to the clie {{user_keys_ss_http_api}} +{{definition_ss_event_schemas_m_signing_key_update}} + Send-to-device messaging ------------------------