From e658b1707088887fe1d422a00c609cd1e92a4ab6 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Mon, 16 Dec 2019 15:47:03 -0500 Subject: [PATCH 01/19] initial version of spec for key backups --- .../definitions/key_backup_data.yaml | 50 ++ api/client-server/key_backup.yaml | 774 ++++++++++++++++++ .../modules/end_to_end_encryption.rst | 125 +++ 3 files changed, 949 insertions(+) create mode 100644 api/client-server/definitions/key_backup_data.yaml create mode 100644 api/client-server/key_backup.yaml diff --git a/api/client-server/definitions/key_backup_data.yaml b/api/client-server/definitions/key_backup_data.yaml new file mode 100644 index 00000000..5111a663 --- /dev/null +++ b/api/client-server/definitions/key_backup_data.yaml @@ -0,0 +1,50 @@ +# Copyright 2019 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: KeyBackupData +description: "The key data" +properties: + first_message_index: + description: |- + The index of the first message in the session that the key can decrypt. + type: integer + example: 1 + forwarded_count: + description: |- + The number of times this key has been forwarded. + type: integer + example: 0 + is_verified: + description: |- + Whether the device backing up the key was verified the device that the key + is from. + type: boolean + example: false + session_data: + description: |- + Algorithm-dependent data. See the documentation for the backup + algorithms in `Server-side key backups`_ for more information on the + expected format of the data. + type: object + example: { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" + } +required: + - first_message_index + - forwarded_count + - is_verified + - session_data diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml new file mode 100644 index 00000000..c55b8f27 --- /dev/null +++ b/api/client-server/key_backup.yaml @@ -0,0 +1,774 @@ +# Copyright 2019 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 Key Backup 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: + "/room_keys/version": + post: + summary: Create a new backup. + description: |- + Creates a new backup + operationId: postRoomKeysVersion + security: + - accessToken: [] + parameters: + - in: body + name: version + description: "The backup configuration" + schema: + type: object + properties: + algorithm: + description: The algorithm used for storing backups. + type: string + enum: ["m.megolm_backup.v1.curve25519-aes-sha2"] + example: "m.megolm_backup.v1.curve25519-aes-sha2" + auth_data: + description: |- + Algorithm-dependent data. See the documentation for the backup + algorithms in `Server-side key backups`_ for more information on the + expected format of the data. + type: object + example: { + "public_key": "abcdefg", + "signatures": { + "@alice:example.org": { + "ed25519:deviceid": "signature" + } + } + } + required: + - algorithm + - auth_data + responses: + 200: + description: + The version of the new backup. + schema: + type: object + properties: + version: + type: string + description: The backup version + example: "1" + required: + - version + tags: + - End-to-end encryption + "/room_keys/version/{version}": + get: + summary: Get information about an existing backup. + description: |- + Get information about an existing backup. + operationId: getRoomKeysVersion + security: + - accessToken: [] + parameters: + - in: path + type: string + name: version + description: |- + Optional. The backup version to get. If omitted, the current backup + is returned. + required: false + x-example: "1" + responses: + 200: + description: + The information about the requested backup. + schema: + type: object + properties: + algorithm: + type: string + description: The algorithm used for storing backups. + type: string + enum: ["m.megolm_backup.v1.curve25519-aes-sha2"] + example: "m.megolm_backup.v1.curve25519-aes-sha2" + auth_data: + description: |- + Algorithm-dependent data. See the documentation for the backup + algorithms in `Server-side key backups`_ for more information on the + expected format of the data. + type: object + example: { + "public_key": "abcdefg", + "signatures": { + "@alice:example.org": { + "ed25519:deviceid": "signature" + } + } + } + count: + description: The number of key stored in the backup. + type: integer + example: 42 + etag: + description: |- + An opaque string representing stored keys in the backup. + Clients can compare it with the ``etag`` value they received + in the request of their last key storage request. If not + equal, another client has modified the backup. + type: string + example: "anopaquestring" + version: + type: string + description: The backup version + example: "1" + required: + - algorithm + - auth_data + - count + - etag + - version + 404: + description: + The backup specified does not exist + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - End-to-end encryption + put: + summary: Update information about an existing backup. + description: |- + Update information about an existing backup. Only ``auth_data`` can be modified. + operationId: putRoomKeysVersion + security: + - accessToken: [] + parameters: + - in: path + type: string + name: version + description: |- + The backup version to update. + required: true + x-example: "1" + - in: body + name: version + description: "The backup configuration" + schema: + type: object + properties: + algorithm: + description: |- + The algorithm used for storing backups. Must be the same as + the algorithm currently used by the backup. + type: string + enum: ["m.megolm_backup.v1.curve25519-aes-sha2"] + example: "m.megolm_backup.v1.curve25519-aes-sha2" + auth_data: + description: |- + Algorithm-dependent data. See the documentation for the backup + algorithms in `Server-side key backups`_ for more information on the + expected format of the data. + type: object + example: { + "public_key": "abcdefg", + "signatures": { + "@alice:example.org": { + "ed25519:deviceid": "signature" + } + } + } + version: + description: |- + The backup version. If present, must be the same as the + version in the path parameter. + type: string + example: "1" + required: + - algorithm + - auth_data + responses: + 200: + description: The update succeeded + schema: + type: object + properties: {} + 404: + description: The backup specified does not exist + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - End-to-end encryption + "/room_keys/keys/{roomId}/{sessionId}": + put: + summary: Store a key in the backup + description: |- + Store a key in the backup. + operationId: postRoomKeysKeyRoomIdSessionId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup in which to store the key. Must be the current backup. + required: true + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the key is for. + required: true + x-example: "!roomid:example.org" + - in: path + type: string + name: sessionId + description: The ID of the megolm session that the key is for. + required: true + x-example: "sessionid" + - in: body + name: data + description: "The key data" + schema: + "$ref": "definitions/key_backup_data.yaml" + responses: + 200: + description: The update succeeded + schema: + type: object + properties: + etag: + description: |- + The new etag value representing stored keys in the backup. + See ``GET /room_keys/version/{version}`` for more details. + type: string + example: "abcdefg" + count: + description: The number of keys stored in the backup + type: integer + example: 10 + required: + - etag + - count + 403: + description: |- + The version specified does not match the current backup version. + The current version will be included in the ``current_version`` + field. + examples: + application/json: { + "errcode": "M_WRONG_ROOM_KEYS_VERSION", + "error": "Wrong backup version.", + "current_version": "42" + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - End-to-end encryption + get: + summary: Retrieve a key from the backup + description: |- + Retrieve a key from the backup. + operationId: getRoomKeysKeyRoomIdSessionId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup from which to retrieve the key + required: true + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the requested key is for. + required: true + x-example: "!roomid:example.org" + - in: path + type: string + name: sessionId + description: The ID of the megolm session whose key is requested. + required: true + x-example: "sessionid" + responses: + 200: + description: The key data + schema: + "$ref": "definitions/key_backup_data.yaml" + 404: + description: The key or backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Key not found." + } + schema: + "$ref": "definitions/errors/error.yaml" + delete: + summary: Delete a key from the backup + description: |- + Delete a key from the backup. + operationId: deleteRoomKeysKeyRoomIdSessionId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup from which to delete the key + required: true + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the specified key is for. + required: true + x-example: "!roomid:example.org" + - in: path + type: string + name: sessionId + description: The ID of the megolm session whose key is to be deleted. + required: true + x-example: "sessionid" + responses: + 200: + description: The update succeeded + schema: + type: object + properties: + etag: + description: |- + The new etag value representing stored keys in the backup. + See ``GET /room_keys/version/{version}`` for more details. + type: string + example: "abcdefg" + count: + description: The number of keys stored in the backup + type: integer + example: 10 + required: + - etag + - count + 404: + description: |- + The backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + "/room_keys/keys/{roomId}": + put: + summary: Store several keys in the backup for a given room. + description: |- + Store a key in the backup. + operationId: postRoomKeysKeyRoomId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup in which to store the keys. Must be the current backup. + required: true + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the keys are for. + required: true + x-example: "!roomid:example.org" + - in: body + description: "The backup data" + name: backupData + schema: + type: object + properties: + sessions: + type: object + description: |- + A map of session IDs to key data. + additionalProperties: + allOf: + - $ref: "definitions/key_backup_data.yaml" + example: { + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" + } + } + responses: + 200: + description: The update succeeded + schema: + type: object + properties: + etag: + description: |- + The new etag value representing stored keys in the backup. + See ``GET /room_keys/version/{version}`` for more details. + type: string + example: "abcdefg" + count: + description: The number of keys stored in the backup + type: integer + example: 10 + required: + - etag + - count + 403: + description: |- + The version specified does not match the current backup version. + The current version will be included in the ``current_version`` + field. + examples: + application/json: { + "errcode": "M_WRONG_ROOM_KEYS_VERSION", + "error": "Wrong backup version.", + "current_version": "42" + } + schema: + "$ref": "definitions/errors/error.yaml" + 404: + description: |- + The backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - End-to-end encryption + get: + summary: Retrieve the keys from the backup for a given room + description: |- + Retrieve the keys from the backup for a given room + operationId: getRoomKeysKeyRoomId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup from which to retrieve the key + required: true + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the requested key is for. + required: true + x-example: "!roomid:example.org" + responses: + 200: + description: |- + The key data. If no keys are found, then an object with an empty + ``sessions`` property will be returned (``{"sessions": {}}``). + schema: + type: object + properties: + sessions: + type: object + description: |- + A map of session IDs to key data. + additionalProperties: + allOf: + - $ref: "definitions/key_backup_data.yaml" + example: { + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" + } + } + 404: + description: |- + The backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + delete: + summary: Delete a key from the backup + description: |- + Delete a key from the backup. + operationId: deleteRoomKeysKeyRoomId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup from which to delete the key + required: true + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the specified key is for. + required: true + x-example: "!roomid:example.org" + responses: + 200: + description: The update succeeded + schema: + type: object + properties: + etag: + description: |- + The new etag value representing stored keys in the backup. + See ``GET /room_keys/version/{version}`` for more details. + type: string + example: "abcdefg" + count: + description: The number of keys stored in the backup + type: integer + example: 10 + required: + - etag + - count + 404: + description: |- + The backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + "/room_keys/keys": + put: + summary: Store several keys in the backup. + description: |- + Store several keys in the backup. + operationId: postRoomKeysKey + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup in which to store the keys. Must be the current backup. + required: true + x-example: "1" + - in: body + description: "The backup data" + name: backupData + schema: + type: object + properties: + rooms: + type: object + description: |- + A map of room IDs to session IDs to key data. + additionalProperties: + type: object + additionalProperties: + allOf: + - $ref: "definitions/key_backup_data.yaml" + example: { + "!room:example.org": { + "sessions": { + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" + } + } + } + } + responses: + 200: + description: The update succeeded + schema: + type: object + properties: + etag: + description: |- + The new etag value representing stored keys in the backup. + See ``GET /room_keys/version/{version}`` for more details. + type: string + example: "abcdefg" + count: + description: The number of keys stored in the backup + type: integer + example: 10 + required: + - etag + - count + 403: + description: |- + The version specified does not match the current backup version. + The current version will be included in the ``current_version`` + field. + examples: + application/json: { + "errcode": "M_WRONG_ROOM_KEYS_VERSION", + "error": "Wrong backup version.", + "current_version": "42" + } + schema: + "$ref": "definitions/errors/error.yaml" + 404: + description: |- + The backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - End-to-end encryption + get: + summary: Retrieve the keys from the backup for a given room + description: |- + Retrieve the keys from the backup for a given room + operationId: getRoomKeysKeyRoomId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup from which to retrieve the keys. If omitted, the keys are + retrieved from the current backup. + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the requested key is for. + required: true + x-example: "!roomid:example.org" + responses: + 200: + description: |- + The key data. If no keys are found, then an object with an empty + ``rooms`` property will be returned (``{"rooms": {}}``). + schema: + type: object + properties: + rooms: + type: object + description: |- + A map of room IDs to session IDs to key data. + additionalProperties: + type: object + additionalProperties: + allOf: + - $ref: "definitions/key_backup_data.yaml" + example: { + "!room:example.org": { + "sessions": { + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" + } + } + } + } + 404: + description: The backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version." + } + schema: + "$ref": "definitions/errors/error.yaml" + delete: + summary: Delete a key from the backup + description: |- + Delete a key from the backup. + operationId: deleteRoomKeysKeyRoomId + security: + - accessToken: [] + parameters: + - in: query + type: string + name: version + description: |- + The backup from which to delete the key + required: true + x-example: "1" + - in: path + type: string + name: roomId + description: The ID of the room that the specified key is for. + required: true + x-example: "!roomid:example.org" + responses: + 200: + description: The update succeeded + schema: + type: object + properties: + etag: + description: |- + The new etag value representing stored keys in the backup. + See ``GET /room_keys/version/{version}`` for more details. + type: string + example: "abcdefg" + count: + description: The number of keys stored in the backup + type: integer + example: 10 + required: + - etag + - count + 404: + description: |- + The backup was not found. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 7758e2c1..ce9ea4db 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -767,6 +767,126 @@ previously-received ``request`` message with the same ``request_id`` and A reasonable strategy is for a user's client to only send keys requested by the verified devices of the same user. +Server-side key backups +~~~~~~~~~~~~~~~~~~~~~~~ + +Devices may upload encrypted copies of keys to the server. When a device tries +to read a message that it does not have keys for, it may request the key from +the server and decrypt it. Backups are per-user, and users may replace backups +with new backups. + +In contrast with `Key requests`_, Server-side key backups do not require another +device to be online from which to request keys. However, as the session keys are +stored on the server encrypted, it requires users to enter a decryption key to +decrypt the session keys. + +To create a backup, a client will call ``POST /room_keys/version`` and define +how the keys are to be encrypted through the backup's ``auth_data``; other +clients can discover the backup by calling ``GET /room_keys/version``. Keys +are encrypted according to the backups ``auth_data`` and added to the backup by +calling ``PUT /room_keys/keys?version=$v`` or one of its variants, and can be +retrieved by calling ``GET /room_keys/keys?version=$v`` or one of its variants. +Backups can also be deleted using ``DELETE /room_keys/version``, or individual +keys can be deleted using ``DELETE /room_key/keys?version=$v`` or one of its +variants. + +Clients must only store keys in backups after they have ensured that the +``auth_data`` is trusted, either by checking the signatures on it, or by +deriving the public key from a private key that it obtained from a trusted +source. + +When a client uploads a key for a session that the server already has a key +for, the server will choose to either keep the existing key or replace it with +the new key based on the key metadata as follows: + +- if the keys have different values for ``is_verified``, then it will keep the + key that has ``is_verified`` set to ``true``; +- if they have the same values for ``is_verified``, then it will keep the key + with a lower ``first_message_index``; +- and finally, is ``is_verified`` and ``first_message_index`` are equal, then + it will keep the key with a lower ``forwarded_count``. + +Recovery key +<<<<<<<<<<<< + +If the recovery key (the private half of the backup encryption key) is +presented to the user to save, it is presented as a string constructed as +follows: + +1. The 256-bit curve25519 private key is prepended by the bytes ``0x8B`` and + ``0x01`` +2. All the bytes in the string above, including the two header bytes, are XORed + together to form a parity byte. This parity byte is appended to the byte + string. +3. The byte string is encoded using base58, using the same mapping as is used + for Bitcoin addresses. +4. A space should be added after every 4th character. + +When reading in a recovery key, clients must disregard whitespace, and perform +the reverse of steps 1 through 3. + +Backup algorithm: ``m.megolm_backup.v1.curve25519-aes-sha2`` +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +When a backup is created with the ``algorithm`` set to +``m.megolm_backup.v1.curve25519-aes-sha2``, the ``auth_data`` should have the +following format: + +``AuthData`` + +.. table:: + :widths: auto + + ========== =========== ====================================================== + Parameter Type Description + ========== =========== ====================================================== + public_key string Required. The curve25519 public key used to encrypt + the backups, encoded in unpadded base64. + signatures {string: Optional. Signatures of the ``auth_data``, as Signed + {string: JSON + string}} + ========== =========== ====================================================== + +The ``session_data`` field in the backups is constructed as follows: + +1. Encode the session key to be backed up as a JSON object with the properties: + + .. table:: + :widths: auto + + =============================== ======== ========================================= + Parameter Type Description + =============================== ======== ========================================= + algorithm string Required. The end-to-end message + encryption algorithm that the key is + for. Must be ``m.megolm.v1.aes-sha2``. + sender_key string Required. Unpadded base64-encoded + device curve25519 key. + sender_claimed_keys {string: Required. Object containing the + string} identity key for the sending device. + forwarding_curve25519_key_chain [string] Required. Zero or more curve25519 keys + for devices who forwarded the session key. + session_key string Required. Unpadded base64-encoded + session key in `session-sharing format + `_. + =============================== ======== ========================================= + +2. Generate an ephemeral curve25519 key, and perform an ECDH with the ephemeral + key and the backup's public key to generate a shared secret. The public + half of the ephemeral key, encoded using unpadded base64, becomes the ``ephemeral`` + property of the ``session_data``. +3. Using the shared secret, generate 80 bytes by performing an HKDF using + SHA-256 as the hash, with a salt of 32 bytes of 0, and with the empty string + as the info. The first 32 bytes are used as the AES key, the next 32 bytes + are used as the MAC key, and the last 16 bytes are used as the AES + initialization vector. +4. Stringify the JSON object, and encrypt it using AES-CBC-256 with PKCS#7 + padding. This encrypted data, encoded using unpadded base64, becomes the + ``ciphertext`` property of the ``session_data``. +5. Pass the raw encrypted data (prior to base64 encoding) through HMAC-SHA-256 + using the MAC key generated above. The first 8 bytes of the resulting MAC + are base64-encoded, and become the ``mac`` property of the ``session_data``. + Key exports ~~~~~~~~~~~ @@ -1089,6 +1209,11 @@ Key management API {{keys_cs_http_api}} +Key Backup API +~~~~~~~~~~~~~~ + +{{key_backup_cs_http_api}} + .. anchor for link from /sync api spec .. |device_lists_sync| replace:: End-to-end encryption From 59e337187b97fa5eb1a8349477577e12019331bd Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Mon, 16 Dec 2019 15:54:42 -0500 Subject: [PATCH 02/19] remove duplicated line --- api/client-server/key_backup.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index c55b8f27..5d7050a8 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -106,7 +106,6 @@ paths: algorithm: type: string description: The algorithm used for storing backups. - type: string enum: ["m.megolm_backup.v1.curve25519-aes-sha2"] example: "m.megolm_backup.v1.curve25519-aes-sha2" auth_data: From 4cde800ea10df3e34c359a6e878e1252bd81bdba Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Mon, 16 Dec 2019 17:25:20 -0500 Subject: [PATCH 03/19] fix validation errors --- api/client-server/key_backup.yaml | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index 5d7050a8..3663731e 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -92,9 +92,9 @@ paths: type: string name: version description: |- - Optional. The backup version to get. If omitted, the current backup - is returned. - required: false + The backup version to get. When an empty string, the trailing slash + is optional, and the current backup is returned. + required: true x-example: "1" responses: 200: @@ -678,12 +678,6 @@ paths: The backup from which to retrieve the keys. If omitted, the keys are retrieved from the current backup. x-example: "1" - - in: path - type: string - name: roomId - description: The ID of the room that the requested key is for. - required: true - x-example: "!roomid:example.org" responses: 200: description: |- @@ -736,12 +730,6 @@ paths: The backup from which to delete the key required: true x-example: "1" - - in: path - type: string - name: roomId - description: The ID of the room that the specified key is for. - required: true - x-example: "!roomid:example.org" responses: 200: description: The update succeeded From 90bf2b3b46c17d44c36472a3aebed8e6734f0c87 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Mon, 16 Dec 2019 17:40:05 -0500 Subject: [PATCH 04/19] add changelog --- changelogs/client_server/2387.new | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/client_server/2387.new diff --git a/changelogs/client_server/2387.new b/changelogs/client_server/2387.new new file mode 100644 index 00000000..a709a5fa --- /dev/null +++ b/changelogs/client_server/2387.new @@ -0,0 +1 @@ +Add key backup (``/room_keys/*``) endpoints. From a62c817745bc393a2023810ac502251b5a7f5d7c Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 17 Dec 2019 11:07:04 -0500 Subject: [PATCH 05/19] Apply suggestions from code review Co-Authored-By: Matthew Hodgson --- api/client-server/definitions/key_backup_data.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/client-server/definitions/key_backup_data.yaml b/api/client-server/definitions/key_backup_data.yaml index 5111a663..8f8de999 100644 --- a/api/client-server/definitions/key_backup_data.yaml +++ b/api/client-server/definitions/key_backup_data.yaml @@ -23,12 +23,12 @@ properties: example: 1 forwarded_count: description: |- - The number of times this key has been forwarded. + The number of times this key has been forwarded via key-sharing between devices. type: integer example: 0 is_verified: description: |- - Whether the device backing up the key was verified the device that the key + Whether the device backing up the key verified the device that the key is from. type: boolean example: false From 41072fcaa90d94ded06fe27c467ff652832a832b Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 7 Feb 2020 15:28:19 -0500 Subject: [PATCH 06/19] Apply suggestions from code review Co-Authored-By: Matthew Hodgson --- api/client-server/key_backup.yaml | 4 ++-- specification/modules/end_to_end_encryption.rst | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index 3663731e..b409dfbf 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -67,7 +67,7 @@ paths: responses: 200: description: - The version of the new backup. + The version id of the new backup. schema: type: object properties: @@ -123,7 +123,7 @@ paths: } } count: - description: The number of key stored in the backup. + description: The number of keys stored in the backup. type: integer example: 42 etag: diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index ce9ea4db..63690924 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -786,6 +786,7 @@ clients can discover the backup by calling ``GET /room_keys/version``. Keys are encrypted according to the backups ``auth_data`` and added to the backup by calling ``PUT /room_keys/keys?version=$v`` or one of its variants, and can be retrieved by calling ``GET /room_keys/keys?version=$v`` or one of its variants. +Keys can only be written to the most recently created version of the backup. Backups can also be deleted using ``DELETE /room_keys/version``, or individual keys can be deleted using ``DELETE /room_key/keys?version=$v`` or one of its variants. From e67ba0cd05e9021386253bace2be136f3cec0a11 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 20 Mar 2020 16:49:53 -0400 Subject: [PATCH 07/19] add note indicating similarity between key backup format and key exports also copy description of forwarding_curve25519_key_chain from key exports, since it's a better description --- specification/modules/end_to_end_encryption.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 63690924..a1ce68f6 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -861,12 +861,14 @@ The ``session_data`` field in the backups is constructed as follows: algorithm string Required. The end-to-end message encryption algorithm that the key is for. Must be ``m.megolm.v1.aes-sha2``. + forwarding_curve25519_key_chain [string] Required. Chain of Curve25519 keys + through which this session was + forwarded, via + `m.forwarded_room_key`_ events. sender_key string Required. Unpadded base64-encoded device curve25519 key. sender_claimed_keys {string: Required. Object containing the string} identity key for the sending device. - forwarding_curve25519_key_chain [string] Required. Zero or more curve25519 keys - for devices who forwarded the session key. session_key string Required. Unpadded base64-encoded session key in `session-sharing format `_. @@ -961,6 +963,9 @@ described as follows: session_key string Required. The key for the session. =============================== =========== ==================================== +This is similar to the format before encryption used for the session keys in +`Server-side key backups`_ but adds the ``room_id`` and ``session_id`` fields. + Example: .. code:: json From 30586ed98c6862f3822616cee79ad15a406591fa Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 20 Mar 2020 16:55:56 -0400 Subject: [PATCH 08/19] remove extra space --- specification/modules/end_to_end_encryption.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index a1ce68f6..6945ce42 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -868,7 +868,7 @@ The ``session_data`` field in the backups is constructed as follows: sender_key string Required. Unpadded base64-encoded device curve25519 key. sender_claimed_keys {string: Required. Object containing the - string} identity key for the sending device. + string} identity key for the sending device. session_key string Required. Unpadded base64-encoded session key in `session-sharing format `_. From e0b4a3c9121689e0ec1cbdf9351236d8004166d4 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 5 May 2020 17:02:16 -0400 Subject: [PATCH 09/19] Apply suggestions from code review Co-authored-by: Travis Ralston --- api/client-server/key_backup.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index b409dfbf..543a1992 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -31,14 +31,14 @@ paths: post: summary: Create a new backup. description: |- - Creates a new backup + Creates a new backup. operationId: postRoomKeysVersion security: - accessToken: [] parameters: - in: body name: version - description: "The backup configuration" + description: "The backup configuration." schema: type: object properties: @@ -73,7 +73,7 @@ paths: properties: version: type: string - description: The backup version + description: The backup version. example: "1" required: - version @@ -146,12 +146,12 @@ paths: - version 404: description: - The backup specified does not exist + The backup specified does not exist. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" tags: @@ -209,12 +209,12 @@ paths: - auth_data responses: 200: - description: The update succeeded + description: The update succeeded. schema: type: object properties: {} 404: - description: The backup specified does not exist + description: The backup specified does not exist. examples: application/json: { "errcode": "M_NOT_FOUND", @@ -226,7 +226,7 @@ paths: - End-to-end encryption "/room_keys/keys/{roomId}/{sessionId}": put: - summary: Store a key in the backup + summary: Store a key in the backup. description: |- Store a key in the backup. operationId: postRoomKeysKeyRoomIdSessionId @@ -254,12 +254,12 @@ paths: x-example: "sessionid" - in: body name: data - description: "The key data" + description: "The key data." schema: "$ref": "definitions/key_backup_data.yaml" responses: 200: - description: The update succeeded + description: The update succeeded. schema: type: object properties: From 8ff1c26ef22449fad5526a8861304a88826ae48d Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 5 May 2020 17:28:54 -0400 Subject: [PATCH 10/19] fix indentation --- .../definitions/key_backup_data.yaml | 8 +- api/client-server/key_backup.yaml | 142 +++++++++--------- 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/api/client-server/definitions/key_backup_data.yaml b/api/client-server/definitions/key_backup_data.yaml index 8f8de999..6a3b4042 100644 --- a/api/client-server/definitions/key_backup_data.yaml +++ b/api/client-server/definitions/key_backup_data.yaml @@ -39,10 +39,10 @@ properties: expected format of the data. type: object example: { - "ephemeral": "base64+ephemeral+key", - "ciphertext": "base64+ciphertext+of+JSON+data", - "mac": "base64+mac+of+ciphertext" - } + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" + } required: - first_message_index - forwarded_count diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index 543a1992..bdca769e 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -54,13 +54,13 @@ paths: expected format of the data. type: object example: { - "public_key": "abcdefg", - "signatures": { - "@alice:example.org": { - "ed25519:deviceid": "signature" - } + "public_key": "abcdefg", + "signatures": { + "@alice:example.org": { + "ed25519:deviceid": "signature" } } + } required: - algorithm - auth_data @@ -115,13 +115,13 @@ paths: expected format of the data. type: object example: { - "public_key": "abcdefg", - "signatures": { - "@alice:example.org": { - "ed25519:deviceid": "signature" - } + "public_key": "abcdefg", + "signatures": { + "@alice:example.org": { + "ed25519:deviceid": "signature" } } + } count: description: The number of keys stored in the backup. type: integer @@ -191,13 +191,13 @@ paths: expected format of the data. type: object example: { - "public_key": "abcdefg", - "signatures": { - "@alice:example.org": { - "ed25519:deviceid": "signature" - } + "public_key": "abcdefg", + "signatures": { + "@alice:example.org": { + "ed25519:deviceid": "signature" } } + } version: description: |- The backup version. If present, must be the same as the @@ -283,10 +283,10 @@ paths: field. examples: application/json: { - "errcode": "M_WRONG_ROOM_KEYS_VERSION", - "error": "Wrong backup version.", - "current_version": "42" - } + "errcode": "M_WRONG_ROOM_KEYS_VERSION", + "error": "Wrong backup version.", + "current_version": "42" + } schema: "$ref": "definitions/errors/error.yaml" tags: @@ -327,9 +327,9 @@ paths: description: The key or backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Key not found." - } + "errcode": "M_NOT_FOUND", + "error": "Key not found." + } schema: "$ref": "definitions/errors/error.yaml" delete: @@ -383,9 +383,9 @@ paths: The backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" "/room_keys/keys/{roomId}": @@ -424,12 +424,12 @@ paths: allOf: - $ref: "definitions/key_backup_data.yaml" example: { - "sessionid1": { - "ephemeral": "base64+ephemeral+key", - "ciphertext": "base64+ciphertext+of+JSON+data", - "mac": "base64+mac+of+ciphertext" - } + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" } + } responses: 200: description: The update succeeded @@ -467,9 +467,9 @@ paths: The backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" tags: @@ -511,20 +511,20 @@ paths: allOf: - $ref: "definitions/key_backup_data.yaml" example: { - "sessionid1": { - "ephemeral": "base64+ephemeral+key", - "ciphertext": "base64+ciphertext+of+JSON+data", - "mac": "base64+mac+of+ciphertext" - } + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" } + } 404: description: |- The backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" delete: @@ -572,9 +572,9 @@ paths: The backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" "/room_keys/keys": @@ -609,16 +609,16 @@ paths: allOf: - $ref: "definitions/key_backup_data.yaml" example: { - "!room:example.org": { - "sessions": { - "sessionid1": { - "ephemeral": "base64+ephemeral+key", - "ciphertext": "base64+ciphertext+of+JSON+data", - "mac": "base64+mac+of+ciphertext" - } + "!room:example.org": { + "sessions": { + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" } } } + } responses: 200: description: The update succeeded @@ -645,10 +645,10 @@ paths: field. examples: application/json: { - "errcode": "M_WRONG_ROOM_KEYS_VERSION", - "error": "Wrong backup version.", - "current_version": "42" - } + "errcode": "M_WRONG_ROOM_KEYS_VERSION", + "error": "Wrong backup version.", + "current_version": "42" + } schema: "$ref": "definitions/errors/error.yaml" 404: @@ -656,9 +656,9 @@ paths: The backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" tags: @@ -696,23 +696,23 @@ paths: allOf: - $ref: "definitions/key_backup_data.yaml" example: { - "!room:example.org": { - "sessions": { - "sessionid1": { - "ephemeral": "base64+ephemeral+key", - "ciphertext": "base64+ciphertext+of+JSON+data", - "mac": "base64+mac+of+ciphertext" - } + "!room:example.org": { + "sessions": { + "sessionid1": { + "ephemeral": "base64+ephemeral+key", + "ciphertext": "base64+ciphertext+of+JSON+data", + "mac": "base64+mac+of+ciphertext" } } } + } 404: description: The backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version." - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version." + } schema: "$ref": "definitions/errors/error.yaml" delete: @@ -754,8 +754,8 @@ paths: The backup was not found. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" From 5f3ee44cfbcfbdf625170788ad7fb8d91627d5fc Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 5 May 2020 18:09:17 -0400 Subject: [PATCH 11/19] add more suggestions from review --- api/client-server/key_backup.yaml | 14 ++++++++++---- specification/modules/end_to_end_encryption.rst | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index bdca769e..ae729d62 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -73,7 +73,7 @@ paths: properties: version: type: string - description: The backup version. + description: The backup version. This is an opaque string. example: "1" required: - version @@ -92,8 +92,10 @@ paths: type: string name: version description: |- - The backup version to get. When an empty string, the trailing slash - is optional, and the current backup is returned. + The backup version to get, as returned in the ``version`` parameter + of the response in `POST /_matrix/client/r0/room_keys/version`_ or + this endpoint. When an empty string, the trailing slash is + optional, and the current backup is returned. required: true x-example: "1" responses: @@ -168,7 +170,11 @@ paths: type: string name: version description: |- - The backup version to update. + The backup version to update, as returned in the ``version`` + parameter in the response of `POST + /_matrix/client/r0/room_keys/version`_ or `GET + /_matrix/client/r0/room_keys/version/{version}`_. Unlike with the + ``GET`` version of this endpoint, this may not be empty. required: true x-example: "1" - in: body diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 6945ce42..8e4b0739 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -819,8 +819,8 @@ follows: 2. All the bytes in the string above, including the two header bytes, are XORed together to form a parity byte. This parity byte is appended to the byte string. -3. The byte string is encoded using base58, using the same mapping as is used - for Bitcoin addresses. +3. The byte string is encoded using base58, using the same `mapping as is used + for Bitcoin addresses `_. 4. A space should be added after every 4th character. When reading in a recovery key, clients must disregard whitespace, and perform From 3d1c33ed1b0f788135d5e03cbf49dafa04919698 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 5 May 2020 18:09:35 -0400 Subject: [PATCH 12/19] move API definitions into backup section --- specification/modules/end_to_end_encryption.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 8e4b0739..48a2d6ca 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -890,6 +890,8 @@ The ``session_data`` field in the backups is constructed as follows: using the MAC key generated above. The first 8 bytes of the resulting MAC are base64-encoded, and become the ``mac`` property of the ``session_data``. +{{key_backup_cs_http_api}} + Key exports ~~~~~~~~~~~ @@ -1215,11 +1217,6 @@ Key management API {{keys_cs_http_api}} -Key Backup API -~~~~~~~~~~~~~~ - -{{key_backup_cs_http_api}} - .. anchor for link from /sync api spec .. |device_lists_sync| replace:: End-to-end encryption From 0145191d43d4c9021bc43ad3bb36caae468d6537 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 5 May 2020 20:00:45 -0400 Subject: [PATCH 13/19] add links to endpoints and add delete endpoint --- api/client-server/key_backup.yaml | 37 +++++++++++++++++++ .../modules/end_to_end_encryption.rst | 21 ++++++----- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index ae729d62..387621e6 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -230,6 +230,43 @@ paths: "$ref": "definitions/errors/error.yaml" tags: - End-to-end encryption + delete: + summary: Delete an existing key backup. + description: |- + Delete an existing key backup. Both the information about the backup, + as well as all key data related to the backup will be deleted. + operationId: deleteRoomKeysVersion + security: + - accessToken: [] + parameters: + - in: path + type: string + name: version + description: |- + The backup version to delete, as returned in the ``version`` + parameter in the response of `POST + /_matrix/client/r0/room_keys/version`_ or `GET + /_matrix/client/r0/room_keys/version/{version}`_. Unlike with the + ``GET`` version of this endpoint, this may not be empty. + required: true + x-example: "1" + responses: + 200: + description: The delete succeeded. + schema: + type: object + properties: {} + 404: + description: The backup specified does not exist. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - End-to-end encryption "/room_keys/keys/{roomId}/{sessionId}": put: summary: Store a key in the backup. diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 48a2d6ca..d6c87bc3 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -780,15 +780,18 @@ device to be online from which to request keys. However, as the session keys are stored on the server encrypted, it requires users to enter a decryption key to decrypt the session keys. -To create a backup, a client will call ``POST /room_keys/version`` and define -how the keys are to be encrypted through the backup's ``auth_data``; other -clients can discover the backup by calling ``GET /room_keys/version``. Keys -are encrypted according to the backups ``auth_data`` and added to the backup by -calling ``PUT /room_keys/keys?version=$v`` or one of its variants, and can be -retrieved by calling ``GET /room_keys/keys?version=$v`` or one of its variants. -Keys can only be written to the most recently created version of the backup. -Backups can also be deleted using ``DELETE /room_keys/version``, or individual -keys can be deleted using ``DELETE /room_key/keys?version=$v`` or one of its +To create a backup, a client will call `POST +/_matrix/client/r0/room_keys/version`_ and define how the keys are to be +encrypted through the backup's ``auth_data``; other clients can discover the +backup by calling `GET /_matrix/client/r0/room_keys/version/{version}`_, +setting ``{version}`` to the empty string. Keys are encrypted according to the +backups ``auth_data`` and added to the backup by calling `PUT +/_matrix/client/r0/room_keys/keys`_ or one of its variants, and can be +retrieved by calling `GET /_matrix/client/r0/room_keys/keys`_ or one of its +variants. Keys can only be written to the most recently created version of the +backup. Backups can also be deleted using `DELETE +/_matrix/client/r0/room_keys/version/{version}`_, or individual keys can be +deleted using `DELETE /_matrix/client/r0/room_keys/keys`_ or one of its variants. Clients must only store keys in backups after they have ensured that the From a896729ac2ec68b794cbf8ee3b8e29e3ccfb6078 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 6 May 2020 17:11:41 -0400 Subject: [PATCH 14/19] some more clarifications and indentation fixes --- api/client-server/key_backup.yaml | 24 ++++++++++++++----- .../modules/end_to_end_encryption.rst | 10 ++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index 387621e6..0f7ff25b 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -219,13 +219,25 @@ paths: schema: type: object properties: {} + 400: + description: |- + A parameter was incorrect. For example, the ``algorithm`` does not + match the current backup algorithm, or the ``version`` in the body + does not match the ``version`` in the path. + examples: + application/json: { + "errcode": "M_INVALID_PARAM", + "error": "Algorithm does not match" + } + schema: + "$ref": "definitions/errors/error.yaml" 404: description: The backup specified does not exist. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" tags: @@ -260,9 +272,9 @@ paths: description: The backup specified does not exist. examples: application/json: { - "errcode": "M_NOT_FOUND", - "error": "Unknown backup version" - } + "errcode": "M_NOT_FOUND", + "error": "Unknown backup version" + } schema: "$ref": "definitions/errors/error.yaml" tags: diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index d6c87bc3..8f26477a 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -846,9 +846,8 @@ following format: ========== =========== ====================================================== public_key string Required. The curve25519 public key used to encrypt the backups, encoded in unpadded base64. - signatures {string: Optional. Signatures of the ``auth_data``, as Signed - {string: JSON - string}} + signatures Signatures Optional. Signatures of the ``auth_data``, as Signed + JSON ========== =========== ====================================================== The ``session_data`` field in the backups is constructed as follows: @@ -870,8 +869,9 @@ The ``session_data`` field in the backups is constructed as follows: `m.forwarded_room_key`_ events. sender_key string Required. Unpadded base64-encoded device curve25519 key. - sender_claimed_keys {string: Required. Object containing the - string} identity key for the sending device. + sender_claimed_keys {string: Required. A map from algorithm name + string} (``ed25519``) to the identity key + for the sending device. session_key string Required. Unpadded base64-encoded session key in `session-sharing format `_. From 1bae8ea6333fbc78e1bed50dfde35ad0d7fa8bbf Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 13 May 2020 19:24:34 -0400 Subject: [PATCH 15/19] we actually don't support the GET /room_key/versions/ with trailing slash --- api/client-server/key_backup.yaml | 77 ++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index 0f7ff25b..2735c237 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -79,6 +79,74 @@ paths: - version tags: - End-to-end encryption + "/room_keys/version": + get: + summary: Get information about the latest backup version. + description: |- + Get information about the latest backup version. + operationId: getRoomKeysVersionCurrent + security: + - accessToken: [] + responses: + 200: + description: + The information about the backup. + schema: + type: object + properties: + algorithm: + type: string + description: The algorithm used for storing backups. + enum: ["m.megolm_backup.v1.curve25519-aes-sha2"] + example: "m.megolm_backup.v1.curve25519-aes-sha2" + auth_data: + description: |- + Algorithm-dependent data. See the documentation for the backup + algorithms in `Server-side key backups`_ for more information on the + expected format of the data. + type: object + example: { + "public_key": "abcdefg", + "signatures": { + "@alice:example.org": { + "ed25519:deviceid": "signature" + } + } + } + count: + description: The number of keys stored in the backup. + type: integer + example: 42 + etag: + description: |- + An opaque string representing stored keys in the backup. + Clients can compare it with the ``etag`` value they received + in the request of their last key storage request. If not + equal, another client has modified the backup. + type: string + example: "anopaquestring" + version: + type: string + description: The backup version + example: "1" + required: + - algorithm + - auth_data + - count + - etag + - version + 404: + description: + No backup exists. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "No current backup version" + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - End-to-end encryption "/room_keys/version/{version}": get: summary: Get information about an existing backup. @@ -94,8 +162,7 @@ paths: description: |- The backup version to get, as returned in the ``version`` parameter of the response in `POST /_matrix/client/r0/room_keys/version`_ or - this endpoint. When an empty string, the trailing slash is - optional, and the current backup is returned. + this endpoint. required: true x-example: "1" responses: @@ -173,8 +240,7 @@ paths: The backup version to update, as returned in the ``version`` parameter in the response of `POST /_matrix/client/r0/room_keys/version`_ or `GET - /_matrix/client/r0/room_keys/version/{version}`_. Unlike with the - ``GET`` version of this endpoint, this may not be empty. + /_matrix/client/r0/room_keys/version/{version}`_. required: true x-example: "1" - in: body @@ -258,8 +324,7 @@ paths: The backup version to delete, as returned in the ``version`` parameter in the response of `POST /_matrix/client/r0/room_keys/version`_ or `GET - /_matrix/client/r0/room_keys/version/{version}`_. Unlike with the - ``GET`` version of this endpoint, this may not be empty. + /_matrix/client/r0/room_keys/version/{version}`_. required: true x-example: "1" responses: From bd95568c8cb7ba69274aea2f049113c53dcbde31 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 13 May 2020 19:27:36 -0400 Subject: [PATCH 16/19] remove duplicate key --- api/client-server/key_backup.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index 2735c237..f4e83bae 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -79,7 +79,6 @@ paths: - version tags: - End-to-end encryption - "/room_keys/version": get: summary: Get information about the latest backup version. description: |- From fae1165e1cc7eda27140267c08e6ee8f124142a1 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 15 May 2020 12:17:37 -0400 Subject: [PATCH 17/19] spec what to do if you try to delete a backup that's already deleted --- api/client-server/key_backup.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index f4e83bae..1a79db31 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -328,12 +328,16 @@ paths: x-example: "1" responses: 200: - description: The delete succeeded. + description: |- + The delete succeeded, or the specified backup was previously + deleted. schema: type: object properties: {} 404: - description: The backup specified does not exist. + description: |- + The backup specified does not exist. If the backup was previously + deleted, the call should succeed rather than returning an error. examples: application/json: { "errcode": "M_NOT_FOUND", From 40c50c80ea4a8c26dfd20d766c995e11ee7837e1 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Mon, 1 Jun 2020 22:34:45 -0400 Subject: [PATCH 18/19] Apply suggestions from code review Co-authored-by: Travis Ralston --- api/client-server/key_backup.yaml | 2 +- specification/modules/end_to_end_encryption.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index 1a79db31..ffdafcf4 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -1,4 +1,4 @@ -# 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. diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 8f26477a..79228596 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -785,7 +785,7 @@ To create a backup, a client will call `POST encrypted through the backup's ``auth_data``; other clients can discover the backup by calling `GET /_matrix/client/r0/room_keys/version/{version}`_, setting ``{version}`` to the empty string. Keys are encrypted according to the -backups ``auth_data`` and added to the backup by calling `PUT +backup's ``auth_data`` and added to the backup by calling `PUT /_matrix/client/r0/room_keys/keys`_ or one of its variants, and can be retrieved by calling `GET /_matrix/client/r0/room_keys/keys`_ or one of its variants. Keys can only be written to the most recently created version of the From a36284810d7243061099402bc1fd3fa4ca7c9170 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 2 Jun 2020 16:25:31 -0400 Subject: [PATCH 19/19] more clarifications and fixes --- api/client-server/key_backup.yaml | 56 +++++++++++++++++++ .../modules/end_to_end_encryption.rst | 30 +++++----- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/api/client-server/key_backup.yaml b/api/client-server/key_backup.yaml index ffdafcf4..34dce118 100644 --- a/api/client-server/key_backup.yaml +++ b/api/client-server/key_backup.yaml @@ -77,6 +77,10 @@ paths: example: "1" required: - version + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption get: @@ -144,6 +148,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption "/room_keys/version/{version}": @@ -222,6 +230,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption put: @@ -305,6 +317,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption delete: @@ -345,6 +361,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption "/room_keys/keys/{roomId}/{sessionId}": @@ -412,6 +432,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption get: @@ -455,6 +479,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" delete: summary: Delete a key from the backup description: |- @@ -511,6 +539,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" "/room_keys/keys/{roomId}": put: summary: Store several keys in the backup for a given room. @@ -595,6 +627,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption get: @@ -650,6 +686,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" delete: summary: Delete a key from the backup description: |- @@ -700,6 +740,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" "/room_keys/keys": put: summary: Store several keys in the backup. @@ -784,6 +828,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" tags: - End-to-end encryption get: @@ -838,6 +886,10 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" delete: summary: Delete a key from the backup description: |- @@ -882,3 +934,7 @@ paths: } schema: "$ref": "definitions/errors/error.yaml" + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 79228596..eec40159 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -783,13 +783,12 @@ decrypt the session keys. To create a backup, a client will call `POST /_matrix/client/r0/room_keys/version`_ and define how the keys are to be encrypted through the backup's ``auth_data``; other clients can discover the -backup by calling `GET /_matrix/client/r0/room_keys/version/{version}`_, -setting ``{version}`` to the empty string. Keys are encrypted according to the -backup's ``auth_data`` and added to the backup by calling `PUT -/_matrix/client/r0/room_keys/keys`_ or one of its variants, and can be -retrieved by calling `GET /_matrix/client/r0/room_keys/keys`_ or one of its -variants. Keys can only be written to the most recently created version of the -backup. Backups can also be deleted using `DELETE +backup by calling `GET /_matrix/client/r0/room_keys/version`_. Keys are +encrypted according to the backup's ``auth_data`` and added to the backup by +calling `PUT /_matrix/client/r0/room_keys/keys`_ or one of its variants, and +can be retrieved by calling `GET /_matrix/client/r0/room_keys/keys`_ or one of +its variants. Keys can only be written to the most recently created version of +the backup. Backups can also be deleted using `DELETE /_matrix/client/r0/room_keys/version/{version}`_, or individual keys can be deleted using `DELETE /_matrix/client/r0/room_keys/keys`_ or one of its variants. @@ -823,7 +822,10 @@ follows: together to form a parity byte. This parity byte is appended to the byte string. 3. The byte string is encoded using base58, using the same `mapping as is used - for Bitcoin addresses `_. + for Bitcoin addresses + `_, + that is, using the alphabet + ``123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz``. 4. A space should be added after every 4th character. When reading in a recovery key, clients must disregard whitespace, and perform @@ -844,7 +846,7 @@ following format: ========== =========== ====================================================== Parameter Type Description ========== =========== ====================================================== - public_key string Required. The curve25519 public key used to encrypt + public_key string **Required.** The curve25519 public key used to encrypt the backups, encoded in unpadded base64. signatures Signatures Optional. Signatures of the ``auth_data``, as Signed JSON @@ -860,19 +862,19 @@ The ``session_data`` field in the backups is constructed as follows: =============================== ======== ========================================= Parameter Type Description =============================== ======== ========================================= - algorithm string Required. The end-to-end message + algorithm string **Required.** The end-to-end message encryption algorithm that the key is for. Must be ``m.megolm.v1.aes-sha2``. - forwarding_curve25519_key_chain [string] Required. Chain of Curve25519 keys + forwarding_curve25519_key_chain [string] **Required.** Chain of Curve25519 keys through which this session was forwarded, via `m.forwarded_room_key`_ events. - sender_key string Required. Unpadded base64-encoded + sender_key string **Required.** Unpadded base64-encoded device curve25519 key. - sender_claimed_keys {string: Required. A map from algorithm name + sender_claimed_keys {string: **Required.** A map from algorithm name string} (``ed25519``) to the identity key for the sending device. - session_key string Required. Unpadded base64-encoded + session_key string **Required.** Unpadded base64-encoded session key in `session-sharing format `_. =============================== ======== =========================================