From a8910fe323d0d1772de6d7cce74c055fdbfa888f Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 12 May 2020 17:24:06 -0400 Subject: [PATCH 1/9] 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 ------------------------ From f97b394591aa04dafcdc354fd8a460757ffc6a92 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 12 May 2020 18:14:56 -0400 Subject: [PATCH 2/9] add changelogs --- changelogs/client_server/newsfragments/2536.feature | 1 + changelogs/client_server/newsfragments/2536.new | 1 + changelogs/server_server/newsfragments/2536.feature | 7 +++++++ 3 files changed, 9 insertions(+) create mode 100644 changelogs/client_server/newsfragments/2536.feature create mode 100644 changelogs/client_server/newsfragments/2536.new create mode 100644 changelogs/server_server/newsfragments/2536.feature diff --git a/changelogs/client_server/newsfragments/2536.feature b/changelogs/client_server/newsfragments/2536.feature new file mode 100644 index 00000000..57c9359b --- /dev/null +++ b/changelogs/client_server/newsfragments/2536.feature @@ -0,0 +1 @@ +Add cross-signing properties to the response of ``POST /keys/query`` diff --git a/changelogs/client_server/newsfragments/2536.new b/changelogs/client_server/newsfragments/2536.new new file mode 100644 index 00000000..57d45ab6 --- /dev/null +++ b/changelogs/client_server/newsfragments/2536.new @@ -0,0 +1 @@ +``POST /keys/device_signing/upload`` and ``POST /keys/signatures/upload`` diff --git a/changelogs/server_server/newsfragments/2536.feature b/changelogs/server_server/newsfragments/2536.feature new file mode 100644 index 00000000..3668672b --- /dev/null +++ b/changelogs/server_server/newsfragments/2536.feature @@ -0,0 +1,7 @@ +Add cross-signing: + +- Add properties to the response of ``GET /user/keys`` and ``GET + /user/devices/{userId}``. +- The ``m.device_list_update`` EDU is sent when a device gets a new signature. +- A new ``m.signing_key_update`` EDU is sent when a user's cross-signing keys + are changed. From 67edc3e2294417d2b7a1d5a0c3fdc45128780bbc Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 29 May 2020 17:25:07 -0400 Subject: [PATCH 3/9] add clarifications and diagrams --- api/client-server/cross_signing.yaml | 5 ++ .../modules/end_to_end_encryption.rst | 79 ++++++++++++++++--- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/api/client-server/cross_signing.yaml b/api/client-server/cross_signing.yaml index ba98ee33..15f3be2c 100644 --- a/api/client-server/cross_signing.yaml +++ b/api/client-server/cross_signing.yaml @@ -136,6 +136,11 @@ paths: The signatures to be published. schema: type: object + title: Signatures + additionalProperties: + type: object + additionalProperties: + type: object example: { "@alice:example.com": { "HIJKLMN": { diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 35ed688d..1dda3375 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -739,19 +739,20 @@ 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. +Rather than requiring Alice to verify each of Bob's devices with each of her +own devices and vice versa, the cross-signing feature allows users sign their +device keys such 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: +Each user has three ed25519 keys pairs for cross-signing: -* a master key that serves as the user's identity in cross-signing and signs +* a master key (MSK) 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. +* a user-signing key (USK) -- only visible to the user that it belongs to -- + that signs other users' master keys, and +* a self-signing key (SSK) 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 @@ -775,6 +776,64 @@ trust Bob's device if: - Bob's master key has signed Bob's self-signing key, and - Bob's self-signing key has signed Bob's device key. +The following diagram illustrates how keys are signed: + +.. code:: + + +------------------+ .................. +----------------+ + | +--------------+ | .................. : | +------------+ | + | | v v v : : v v v | | + | | +-----------+ : : +-----------+ | | + | | | Alice MSK | : : | Bob MSK | | | + | | +-----------+ : : +-----------+ | | + | | | : : : : | | | + | | +--+ :... : : ...: +--+ | | + | | v v : : v v | | + | | +-----------+ ............. : : ............. +-----------+ | | + | | | Alice SSK | : Alice USK : : : : Bob USK : | Bob SSK | | | + | | +-----------+ :...........: : : :...........: +-----------+ | | + | | | ... | : : : : | ... | | | + | | V V :........: :........: V V | | + | | +---------+ -+ +---------+ -+ | | + | | | Devices | ...| | Devices | ...| | | + | | +---------+ -+ +---------+ -+ | | + | | | ... | | ... | | | + | +------+ | | +----+ | + +----------------+ +--------------+ + +.. based on https://jcg.re/blog/quick-overview-matrix-cross-signing/ + +In the diagram, boxes represent keys and lines represent signatures with the +arrows pointing from the signing key to the key being signed. Dotted boxes and +lines represent keys and signatures that are only visible to the user who +created them. + +The following diagram illustrates Alice's view, hiding the keys and signatures +that she cannot see: + +.. code:: + + +------------------+ +----------------+ +----------------+ + | +--------------+ | | | | +------------+ | + | | v v | v v v | | + | | +-----------+ | +-----------+ | | + | | | Alice MSK | | | Bob MSK | | | + | | +-----------+ | +-----------+ | | + | | | | | | | | + | | +--+ +--+ | +--+ | | + | | v v | v | | + | | +-----------+ +-----------+ | +-----------+ | | + | | | Alice SSK | | Alice USK | | | Bob SSK | | | + | | +-----------+ +-----------+ | +-----------+ | | + | | | ... | | | | ... | | | + | | V V +--------+ V V | | + | | +---------+ -+ +---------+ -+ | | + | | | Devices | ...| | Devices | ...| | | + | | +---------+ -+ +---------+ -+ | | + | | | ... | | ... | | | + | +------+ | | +----+ | + +----------------+ +--------------+ + 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 From be01eebf8fb6cd708e47cb0ecb74ec47728a7a7d Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Mon, 15 Jun 2020 12:56:49 -0400 Subject: [PATCH 4/9] use the right key ID --- api/client-server/cross_signing.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/client-server/cross_signing.yaml b/api/client-server/cross_signing.yaml index 15f3be2c..655456b4 100644 --- a/api/client-server/cross_signing.yaml +++ b/api/client-server/cross_signing.yaml @@ -174,7 +174,7 @@ paths: } }, "@bob:example.com": { - "bobs+base64+self+signing+public+key": { + "bobs+base64+master+public+key": { "user_id": "@bob:example.com", "keys": { "ed25519:bobs+base64+master+public+key": "bobs+base64+master+public+key" From efebba62dedb266c578b5b642c817e139d31feb2 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Mon, 15 Jun 2020 18:38:47 -0400 Subject: [PATCH 5/9] result may also include signatures --- api/client-server/keys.yaml | 4 +++- api/server-server/user_keys.yaml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/api/client-server/keys.yaml b/api/client-server/keys.yaml index 7b5e9875..77434ea3 100644 --- a/api/client-server/keys.yaml +++ b/api/client-server/keys.yaml @@ -240,7 +240,9 @@ paths: 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``. + ``/keys/device_signing/upload``, along with the signatures + uploaded via ``/keys/signatures/upload`` that the requesting user + is allowed to see. additionalProperties: allOf: - $ref: definitions/cross_signing_key.yaml diff --git a/api/server-server/user_keys.yaml b/api/server-server/user_keys.yaml index ae8ccd7e..c7cf6b76 100644 --- a/api/server-server/user_keys.yaml +++ b/api/server-server/user_keys.yaml @@ -184,7 +184,9 @@ paths: 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``. + ``/keys/device_signing/upload``, along with the signatures + uploaded via ``/keys/signatures/upload`` that the user is + allowed to see. additionalProperties: allOf: - $ref: ../client-server/definitions/cross_signing_key.yaml From 902444ceb5b2a79135816ae193c81792bf239151 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 19 Jun 2020 21:40:46 -0400 Subject: [PATCH 6/9] Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- api/client-server/cross_signing.yaml | 8 ++++---- specification/modules/end_to_end_encryption.rst | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/api/client-server/cross_signing.yaml b/api/client-server/cross_signing.yaml index 655456b4..219e4b3e 100644 --- a/api/client-server/cross_signing.yaml +++ b/api/client-server/cross_signing.yaml @@ -52,16 +52,16 @@ paths: - $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 + Optional. The user\'s self-signing key. Must be signed by + the accompanying master key, 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 + Optional. The user\'s user-signing key. Must be signed by + the accompanying master key, or by the user\'s most recently uploaded master key if no master key is included in the request. allOf: diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index acd05411..28e85159 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -754,18 +754,18 @@ Cross-signing ~~~~~~~~~~~~~ Rather than requiring Alice to verify each of Bob's devices with each of her -own devices and vice versa, the cross-signing feature allows users sign their +own devices and vice versa, the cross-signing feature allows users to sign their device keys such 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. -Each user has three ed25519 keys pairs for cross-signing: +Each user has three ed25519 key pairs for cross-signing: * a master key (MSK) that serves as the user's identity in cross-signing and signs their other cross-signing keys; * a user-signing key (USK) -- only visible to the user that it belongs to -- - that signs other users' master keys, and + that signs other users' master keys; and * a self-signing key (SSK) 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 @@ -863,9 +863,11 @@ 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. +the operating system), then clients must not store the private part. + +If a user's client sees that any other user has changed their master key, that +client must notify the user about the change before allowing communication +between the users to continue. 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 From c8e816d854587309614a0f7f82b8b4e47e3de4e8 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 19 Jun 2020 22:22:03 -0400 Subject: [PATCH 7/9] Add link to MSC in changelog entries. --- changelogs/client_server/newsfragments/2536.feature | 2 +- changelogs/client_server/newsfragments/2536.new | 2 +- changelogs/server_server/newsfragments/2536.feature | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/changelogs/client_server/newsfragments/2536.feature b/changelogs/client_server/newsfragments/2536.feature index 57c9359b..1006ff52 100644 --- a/changelogs/client_server/newsfragments/2536.feature +++ b/changelogs/client_server/newsfragments/2536.feature @@ -1 +1 @@ -Add cross-signing properties to the response of ``POST /keys/query`` +Add cross-signing properties to the response of ``POST /keys/query`` per [MSC1756](https://github.com/matrix-org/matrix-doc/pull/1756). diff --git a/changelogs/client_server/newsfragments/2536.new b/changelogs/client_server/newsfragments/2536.new index 57d45ab6..88cb6703 100644 --- a/changelogs/client_server/newsfragments/2536.new +++ b/changelogs/client_server/newsfragments/2536.new @@ -1 +1 @@ -``POST /keys/device_signing/upload`` and ``POST /keys/signatures/upload`` +Add ``POST /keys/device_signing/upload`` and ``POST /keys/signatures/upload`` per [MSC1756](https://github.com/matrix-org/matrix-doc/pull/1756). diff --git a/changelogs/server_server/newsfragments/2536.feature b/changelogs/server_server/newsfragments/2536.feature index 3668672b..62a66562 100644 --- a/changelogs/server_server/newsfragments/2536.feature +++ b/changelogs/server_server/newsfragments/2536.feature @@ -5,3 +5,5 @@ Add cross-signing: - The ``m.device_list_update`` EDU is sent when a device gets a new signature. - A new ``m.signing_key_update`` EDU is sent when a user's cross-signing keys are changed. + +per [MSC1756](https://github.com/matrix-org/matrix-doc/pull/1756). From a5ebedc131c15f2017532c73102b86eb1ca98170 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 16 Oct 2020 18:36:02 -0400 Subject: [PATCH 8/9] apply suggestions from review --- api/client-server/cross_signing.yaml | 19 +++++--- api/client-server/login.yaml | 10 +++-- .../event-schemas/m.signing_key_update.yaml | 44 +++++++++---------- .../modules/end_to_end_encryption.rst | 14 +++--- 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/api/client-server/cross_signing.yaml b/api/client-server/cross_signing.yaml index 219e4b3e..91407954 100644 --- a/api/client-server/cross_signing.yaml +++ b/api/client-server/cross_signing.yaml @@ -107,19 +107,28 @@ paths: example: {} 400: description: |- - The input was invalid in some way. This can include one of the + 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. + * ``M_INVALID_SIGNATURE``: For example, the self-signing or + user-signing key had an incorrect signature. + * ``M_MISSING_PARAM``: No master key is available. schema: type: object example: { "errcode": "M_INVALID_SIGNATURE", "error": "Invalid signature" } + 403: + description: |- + The public key of one of the keys is the same as one of the user\'s + device IDs or the request is unauthorized. + schema: + type: object + example: { + "errcode": "M_FORBIDDEN", + "error": "Key ID in use" + } "/keys/signatures/upload": post: summary: Upload cross-signing signatures. diff --git a/api/client-server/login.yaml b/api/client-server/login.yaml index f6c92638..6e38705a 100644 --- a/api/client-server/login.yaml +++ b/api/client-server/login.yaml @@ -123,8 +123,10 @@ paths: type: string description: |- ID of the client device. If this does not correspond to a - known client device, a new device will be created. The server - will auto-generate a device_id if this is not specified. + known client device, a new device will be created. The given + device ID must not be the same as a `cross-signing key ID + <#cross-signing>`_. The server will auto-generate a device_id + if this is not specified. initial_device_display_name: type: string description: |- @@ -195,7 +197,9 @@ paths: 403: description: |- The login attempt failed. This can include one of the following error codes: - * ``M_FORBIDDEN``: The provided authentication data was incorrect. + * ``M_FORBIDDEN``: The provided authentication data was incorrect + or the requested device ID is the same as a cross-signing key + ID. * ``M_USER_DEACTIVATED``: The user has been deactivated. examples: application/json: { 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 index db75f1ed..e372483a 100644 --- a/api/server-server/definitions/event-schemas/m.signing_key_update.yaml +++ b/api/server-server/definitions/event-schemas/m.signing_key_update.yaml @@ -37,32 +37,28 @@ allOf: 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" - } - } - } + $ref: ../../../client-server/definitions/cross_signing_key.yaml + example: { + "user_id": "@alice:example.com", + "usage": ["master"], + "keys": { + "ed25519:base64+master+public+key": "base64+master+public+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", - } + $ref: ../../../client-server/definitions/cross_signing_key.yaml + 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 diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 28e85159..f45ac889 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -848,13 +848,13 @@ that she cannot see: | +------+ | | +----+ | +----------------+ +--------------+ -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. +`Verification methods <#device-verification>`_ 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 <<<<<<<<<<<<<<<<<<<<<<<<<< From c56c6a2e2ba784ad775f8fd82c7c69c8b3c68d9f Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 15 Dec 2020 12:35:02 -0500 Subject: [PATCH 9/9] Update api/client-server/cross_signing.yaml Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- api/client-server/cross_signing.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/client-server/cross_signing.yaml b/api/client-server/cross_signing.yaml index 91407954..f1a0cc41 100644 --- a/api/client-server/cross_signing.yaml +++ b/api/client-server/cross_signing.yaml @@ -122,7 +122,7 @@ paths: 403: description: |- The public key of one of the keys is the same as one of the user\'s - device IDs or the request is unauthorized. + device IDs, or the request is not authorized for any other reason. schema: type: object example: {