Improve the server key exchange portion of the s2s specification
Most of the text has been shuffled into the swagger definitions to bring it closer to where it matters. This also attempts to clarify what is out in the wild. Most importantly, the first version of the key exchange is outright removed from the specification. Other research points/questions are: * What is a "Key ID"? *1241156c82/synapse/rest/key/v2/local_key_resource.py (L81-L83)
*1241156c82/synapse/rest/key/v2/local_key_resource.py (L88-L91)
* Returning a cached response if the server throws a 400, 500, or otherwise not-offline status code *1241156c82/synapse/rest/key/v2/remote_key_resource.py (L227-L229)
* `minimum_valid_until_ts` default * This branch of the ladder:1241156c82/synapse/rest/key/v2/remote_key_resource.py (L192)
* Returning empty arrays when querying offline/no servers * Queried by hand against matrix.org as a notary server with a fake domain name to query * Returning all keys even when querying for specific keys * Queried by hand using matrix.org as a notary server against a server publishing multiple keys. The examples and descriptions were also improved as part of this commit.
This commit is contained in:
parent
b0744aa1e9
commit
8e97b0ca81
7 changed files with 143 additions and 149 deletions
|
@ -20,50 +20,60 @@ properties:
|
|||
server_name:
|
||||
type: string
|
||||
description: DNS name of the homeserver.
|
||||
required: true # TODO: Verify
|
||||
required: true
|
||||
example: "example.org"
|
||||
verify_keys:
|
||||
type: object
|
||||
description: Public keys of the homeserver for verifying digital signatures.
|
||||
required: true # TODO: Verify
|
||||
description: |-
|
||||
Public keys of the homeserver for verifying digital signatures.
|
||||
|
||||
The object's key is the algorithm and version combined (``ed25519`` being the
|
||||
algorithm and ``abc123`` being the version in the example below). Together,
|
||||
this forms the Key ID.
|
||||
required: true
|
||||
additionalProperties:
|
||||
type: object
|
||||
title: Verify Key
|
||||
example: {
|
||||
"ed25519:auto2": {
|
||||
"key": "Base+64+Encoded+Signature+Verification+Key"
|
||||
"ed25519:abc123": {
|
||||
"key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA=="
|
||||
}
|
||||
}
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: The key
|
||||
description: The `Unpadded Base64`_ encoded key.
|
||||
required: true
|
||||
example: "Base+64+Encoded+Signature+Verification+Key"
|
||||
example: "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA=="
|
||||
old_verify_keys:
|
||||
type: object
|
||||
description: The public keys that the server used to use and when it stopped using them.
|
||||
description: |-
|
||||
The public keys that the server used to use and when it stopped using them.
|
||||
|
||||
The object's key is the algorithm and version combined (``ed25519`` being the
|
||||
algorithm and ``0ldK3y`` being the version in the example below). Together,
|
||||
this forms the Key ID.
|
||||
additionalProperties:
|
||||
type: object
|
||||
title: Old Verify Key
|
||||
example: {
|
||||
"ed25519:auto1": {
|
||||
"ed25519:0ldK3y": {
|
||||
"expired_ts": 922834800000,
|
||||
"key": "Base+64+Encoded+Signature+Verification+Key"
|
||||
"key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg=="
|
||||
}
|
||||
}
|
||||
properties:
|
||||
expired_ts:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The expiration time.
|
||||
description: POSIX timestamp for when this key expired.
|
||||
required: true
|
||||
example: 922834800000
|
||||
key:
|
||||
type: string
|
||||
description: The key.
|
||||
description: The `Unpadded Base64`_ encoded key.
|
||||
required: true
|
||||
example: "Base+64+Encoded+Signature+Verification+Key"
|
||||
example: "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg=="
|
||||
signatures:
|
||||
type: object
|
||||
description: Digital signatures for this object signed using the ``verify_keys``.
|
||||
|
@ -72,7 +82,7 @@ properties:
|
|||
title: Signed Server
|
||||
example: {
|
||||
"example.org": {
|
||||
"ad25519:auto2": "Base+64+Encoded+Signature+Verification+Key"
|
||||
"ad25519:abc123": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU="
|
||||
}
|
||||
}
|
||||
additionalProperties:
|
||||
|
@ -87,10 +97,12 @@ properties:
|
|||
properties:
|
||||
sha256:
|
||||
type: string
|
||||
description: The encoded fingerprint.
|
||||
example: Base+64+Encoded+SHA-256-Fingerprint
|
||||
description: The `Unpadded Base64`_ encoded fingerprint
|
||||
example: "VGhpcyBpcyBoYXNoIHdoaWNoIHNob3VsZCBiZSBieXRlcw=="
|
||||
valid_until_ts:
|
||||
type: integer
|
||||
format: int64
|
||||
description: POSIX timestamp when the list of valid keys should be refreshed.
|
||||
description: |-
|
||||
POSIX timestamp when the list of valid keys should be refreshed. Keys used beyond this
|
||||
timestamp are no longer valid.
|
||||
example: 1052262000000
|
||||
|
|
|
@ -15,13 +15,13 @@ type: object
|
|||
description: Server keys
|
||||
example: {
|
||||
"server_keys": [{
|
||||
$ref: "../examples/server_key.json"
|
||||
$ref: "../examples/server_key_notary_signed.json"
|
||||
}]
|
||||
}
|
||||
properties:
|
||||
server_keys:
|
||||
type: array
|
||||
title: Server Keys
|
||||
description: The server keys.
|
||||
description: The queried server's keys, signed by the notary server.
|
||||
items:
|
||||
$ref: "keys.yaml"
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
{
|
||||
"server_name": "example.org",
|
||||
"verify_keys": {
|
||||
"ed25519:auto2": {
|
||||
"key": "Base+64+Encoded+Signature+Verification+Key"
|
||||
"ed25519:abc123": {
|
||||
"key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA=="
|
||||
}
|
||||
},
|
||||
"old_verify_keys": {
|
||||
"ed25519:auto1": {
|
||||
"ed25519:0ldk3y": {
|
||||
"expired_ts": 922834800000,
|
||||
"key": "Base+64+Encoded+Old+Verify+Key"
|
||||
"key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg=="
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"example.org": {
|
||||
"ed25519:auto2": "Base+64+Encoded+Signature"
|
||||
"ed25519:auto2": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU="
|
||||
}
|
||||
},
|
||||
"tls_fingerprints": [{
|
||||
"sha256": "Base+64+Encoded+SHA-256-Fingerprint"
|
||||
"sha256": "VGhpcyBpcyBoYXNoIHdoaWNoIHNob3VsZCBiZSBieXRlcw=="
|
||||
}],
|
||||
"valid_until_ts": 1052262000000
|
||||
}
|
11
api/server-server/examples/server_key_notary_signed.json
Normal file
11
api/server-server/examples/server_key_notary_signed.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"$ref": "server_key.json",
|
||||
"signatures": {
|
||||
"example.org": {
|
||||
"ed25519:abc123": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU="
|
||||
},
|
||||
"notary.server.com": {
|
||||
"ed25519:010203": "VGhpcyBpcyBhbm90aGVyIHNpZ25hdHVyZQ=="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,49 +25,60 @@ produces:
|
|||
paths:
|
||||
"/query/{serverName}/{keyId}":
|
||||
get:
|
||||
summary: Retrieve a server key.
|
||||
description: Retrieve a server key.
|
||||
operationId: perspectivesKeyQuery
|
||||
summary: Query for another server's keys
|
||||
description: |-
|
||||
Query for another server's keys. The receiving (notary) server must
|
||||
sign the keys returned by the queried server.
|
||||
operationId: getQueryKeys
|
||||
parameters:
|
||||
- in: path
|
||||
name: serverName
|
||||
type: string
|
||||
description: Server name.
|
||||
description: The server's DNS name to query
|
||||
required: true
|
||||
x-example: matrix.org
|
||||
- in: path
|
||||
name: keyId
|
||||
type: string
|
||||
description: Key ID.
|
||||
required: true
|
||||
x-example: TODO # No examples in spec so far
|
||||
description: |-
|
||||
The key ID to look up. If omitted or empty, all the server's keys
|
||||
are to be queried for.
|
||||
required: false
|
||||
x-example: "ed25519:abc123"
|
||||
- in: query
|
||||
name: minimum_valid_until_ts
|
||||
type: integer
|
||||
format: int64
|
||||
description: Minimum Valid Until Milliseconds.
|
||||
required: true # TODO: Verify
|
||||
description: |-
|
||||
A millisecond POSIX timestamp indicating when the returned certificates
|
||||
will need to be valid until to be useful to the requesting server.
|
||||
|
||||
If not supplied, the current time as determined by the notary server is used.
|
||||
required: false
|
||||
x-example: 1234567890
|
||||
responses:
|
||||
200:
|
||||
description: The keys for the server
|
||||
description: |-
|
||||
The keys for the server, or an empty array if the server could not be reached
|
||||
and no cached keys were available.
|
||||
schema:
|
||||
$ref: "definitions/keys_query_response.yaml"
|
||||
"/query":
|
||||
post:
|
||||
summary: Retrieve a server key
|
||||
description: Retrieve a server key.
|
||||
operationId: bulkPerspectivesKeyQuery
|
||||
summary: Query for several server's keys
|
||||
description: |-
|
||||
Query for keys from multiple servers in a batch format. The receiving (notary)
|
||||
server must sign the keys returned by the queried servers.
|
||||
operationId: postQueryKeys
|
||||
parameters:
|
||||
- in: body
|
||||
name: body
|
||||
schema:
|
||||
type: object
|
||||
# TODO: Improve example
|
||||
example: {
|
||||
"server_keys": {
|
||||
"{server_name}": {
|
||||
"{key_id}": {
|
||||
"example.org": {
|
||||
"ed25519:abc123": {
|
||||
"minimum_valid_until_ts": 1234567890
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +87,16 @@ paths:
|
|||
properties:
|
||||
server_keys:
|
||||
type: object
|
||||
description: The query criteria.
|
||||
description: |-
|
||||
The query criteria. The outer ``string`` key on the object is the
|
||||
server name (eg: ``matrix.org``). The inner ``string`` key is the
|
||||
Key ID to query for the particular server. If no key IDs are given
|
||||
to be queried, the notary server should query for all keys. If no
|
||||
servers are given, the notary server must return an empty ``server_keys``
|
||||
array in the response.
|
||||
|
||||
The notary server may return multiple keys regardless of the Key IDs
|
||||
given.
|
||||
additionalProperties:
|
||||
type: object
|
||||
name: ServerName
|
||||
|
@ -84,16 +104,25 @@ paths:
|
|||
additionalProperties:
|
||||
type: object
|
||||
title: Query Criteria
|
||||
description: The server keys to query.
|
||||
description: The server key IDs to query.
|
||||
properties:
|
||||
minimum_valid_until_ts:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Minimum Valid Until MS.
|
||||
description: |-
|
||||
A millisecond POSIX timestamp indicating when the returned
|
||||
certificates will need to be valid until to be useful to the
|
||||
requesting server.
|
||||
|
||||
If not supplied, the current time as determined by the notary
|
||||
server is used.
|
||||
example: 1234567890
|
||||
required: ['server_keys']
|
||||
responses:
|
||||
200:
|
||||
description: The keys for the server.
|
||||
description: |-
|
||||
The keys for the queried servers, signed by the notary server. Servers which
|
||||
are offline and have no cached keys will not be included in the result. This
|
||||
may result in an empty array.
|
||||
schema:
|
||||
$ref: "definitions/keys_query_response.yaml"
|
||||
|
|
|
@ -25,18 +25,38 @@ produces:
|
|||
paths:
|
||||
"/server/{keyId}":
|
||||
get:
|
||||
summary: Get the server's key
|
||||
description: Get the server's key.
|
||||
summary: Get the homeserver's public key(s)
|
||||
description: |-
|
||||
Gets the homeserver's published TLS fingerprints and signing keys.
|
||||
The homeserver may have any number of active keys and may have a
|
||||
number of old keys. Homeservers SHOULD return a single JSON object
|
||||
listing all of its keys, regardless of the ``keyId`` path argument.
|
||||
This is to reduce the number of round trips needed to discover the
|
||||
relevant keys for a homeserver.
|
||||
|
||||
Intermediate notary servers should cache a response for half of its
|
||||
lifetime to avoid serving a stale response. Originating servers should
|
||||
avoid returning responses that expire in less than an hour to avoid
|
||||
repeated reqests for a certificate that is about to expire. Requesting
|
||||
servers should limit how frequently they query for certificates to
|
||||
avoid flooding a server with requests.
|
||||
|
||||
If the server fails to respond to this request, intermediate notary
|
||||
servers should continue to return the last response they received
|
||||
from the server so that the signatures of old events can still be
|
||||
checked.
|
||||
operationId: getServerKey
|
||||
parameters:
|
||||
- in: path
|
||||
name: keyId
|
||||
type: string
|
||||
description: Key ID
|
||||
description: |-
|
||||
The key ID to look up. If omitted or empty, all server keys are
|
||||
to be returned.
|
||||
required: false
|
||||
x-example: TODO # No examples in the spec so far
|
||||
x-example: "ed25519:abc123"
|
||||
responses:
|
||||
200:
|
||||
description: The server's keys.
|
||||
description: The homeserver's keys
|
||||
schema:
|
||||
$ref: "definitions/keys.yaml"
|
||||
|
|
|
@ -106,15 +106,17 @@ Server implementation
|
|||
Retrieving Server Keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Version 2
|
||||
+++++++++
|
||||
.. NOTE::
|
||||
There was once a "version 1" of the key exchange. It has been removed from the
|
||||
specification due to lack of significance. It may be reviewed `here
|
||||
<https://github.com/matrix-org/matrix-doc/blob/51faf8ed2e4a63d4cfd6d23183698ed169956cc0/specification/server_server_api.rst#232version-1>`_.
|
||||
|
||||
Each homeserver publishes its public keys under ``/_matrix/key/v2/server/``.
|
||||
Homeservers query for keys by either getting ``/_matrix/key/v2/server/``
|
||||
Each homeserver publishes its public keys under ``/_matrix/key/v2/server/{keyId}`.
|
||||
Homeservers query for keys by either getting ``/_matrix/key/v2/server/{keyId}``
|
||||
directly or by querying an intermediate notary server using a
|
||||
``/_matrix/key/v2/query`` API. Intermediate notary servers query the
|
||||
``/_matrix/key/v2/server/`` API on behalf of another server and sign the
|
||||
response with their own key. A server may query multiple notary servers to
|
||||
``/_matrix/key/v2/query/{serverName}/{keyId}`` API. Intermediate notary servers
|
||||
query the ``/_matrix/key/v2/server/{keyId}`` API on behalf of another server and
|
||||
sign the response with their own key. A server may query multiple notary servers to
|
||||
ensure that they all report the same public keys.
|
||||
|
||||
This approach is borrowed from the `Perspectives Project`_, but modified to
|
||||
|
@ -126,113 +128,33 @@ server by querying other servers.
|
|||
.. _Perspectives Project: https://web.archive.org/web/20170702024706/https://perspectives-project.org/
|
||||
|
||||
Publishing Keys
|
||||
^^^^^^^^^^^^^^^
|
||||
+++++++++++++++
|
||||
|
||||
Homeservers publish the allowed TLS fingerprints and signing keys in a JSON
|
||||
object at ``/_matrix/key/v2/server/{key_id}``. The response contains a list of
|
||||
``verify_keys`` that are valid for signing federation requests made by the
|
||||
server and for signing events. It contains a list of ``old_verify_keys`` which
|
||||
homeserver and for signing events. It contains a list of ``old_verify_keys`` which
|
||||
are only valid for signing events. Finally the response contains a list of TLS
|
||||
certificate fingerprints to validate any connection made to the server.
|
||||
|
||||
A server may have multiple keys active at a given time. A server may have any
|
||||
number of old keys. It is recommended that servers return a single JSON
|
||||
response listing all of its keys whenever any ``key_id`` is requested to reduce
|
||||
the number of round trips needed to discover the relevant keys for a server.
|
||||
However a server may return different responses for a different ``key_id``.
|
||||
|
||||
The ``tls_certificates`` field contains a list of hashes of the X.509 TLS
|
||||
certificates currently used by the server. The list must include SHA-256 hashes
|
||||
for every certificate currently in use by the server. These fingerprints are
|
||||
valid until the millisecond POSIX timestamp in ``valid_until_ts``.
|
||||
|
||||
The ``verify_keys`` can be used to sign requests and events made by the server
|
||||
until the millisecond POSIX timestamp in ``valid_until_ts``. If a homeserver
|
||||
receives an event with a ``origin_server_ts`` after the ``valid_until_ts`` then
|
||||
it should request that ``key_id`` for the originating server to check whether
|
||||
the key has expired.
|
||||
|
||||
The ``old_verify_keys`` can be used to sign events with an ``origin_server_ts``
|
||||
before the ``expired_ts``. The ``expired_ts`` is a millisecond POSIX timestamp
|
||||
of when the originating server stopped using that key.
|
||||
|
||||
Intermediate notary servers should cache a response for half of its remaining
|
||||
lifetime to avoid serving a stale response. Originating servers should avoid
|
||||
returning responses that expire in less than an hour to avoid repeated requests
|
||||
for a certificate that is about to expire. Requesting servers should limit how
|
||||
frequently they query for certificates to avoid flooding a server with
|
||||
requests.
|
||||
|
||||
If a server goes offline intermediate notary servers should continue to return
|
||||
the last response they received from that server so that the signatures of old
|
||||
events sent by that server can still be checked.
|
||||
certificate fingerprints to validate any connection made to the homeserver.
|
||||
|
||||
{{keys_server_ss_http_api}}
|
||||
|
||||
|
||||
Querying Keys Through Another Server
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
++++++++++++++++++++++++++++++++++++
|
||||
|
||||
Servers may offer a query API ``/_matrix/key/v2/query/`` for getting the keys
|
||||
for another server. This API can be used to GET a list of JSON objects for a
|
||||
given server or to POST a bulk query for a number of keys from a number of
|
||||
servers. Either way the response is a list of JSON objects containing the
|
||||
JSON published by the server under ``/_matrix/key/v2/server/`` signed by
|
||||
both the originating server and by this server.
|
||||
Servers may query another server's keys through a notary server. The notary
|
||||
server may be another homeserver. The notary server will retrieve keys from
|
||||
the queried servers through use of the ``/_matrix/key/v2/server/{keyId}``
|
||||
API. The notary server will additionally sign the response from the queried
|
||||
server before returning the results.
|
||||
|
||||
The ``minimum_valid_until_ts`` is a millisecond POSIX timestamp indicating
|
||||
when the returned certificate will need to be valid until to be useful to the
|
||||
requesting server. This can be set using the maximum ``origin_server_ts`` of
|
||||
a batch of events that a requesting server is trying to validate. This allows
|
||||
an intermediate notary server to give a prompt cached response even if the
|
||||
originating server is offline.
|
||||
|
||||
This API can return keys for servers that are offline by using cached responses
|
||||
taken from when the server was online. Keys can be queried from multiple
|
||||
servers to mitigate against DNS spoofing.
|
||||
Notary servers can return keys for servers that are offline or having issues
|
||||
serving their own keys by using cached responses. Keys can be queried from
|
||||
multiple servers to mitigate against DNS spoofing.
|
||||
|
||||
{{keys_query_ss_http_api}}
|
||||
|
||||
Version 1
|
||||
+++++++++
|
||||
.. WARNING::
|
||||
Version 1 of key distribution is obsolete.
|
||||
|
||||
|
||||
Homeservers publish their TLS certificates and signing keys in a JSON object
|
||||
at ``/_matrix/key/v1``.
|
||||
|
||||
==================== =================== ======================================
|
||||
Key Type Description
|
||||
==================== =================== ======================================
|
||||
``server_name`` String DNS name of the homeserver.
|
||||
``verify_keys`` Object Public keys of the homeserver for
|
||||
verifying digital signatures.
|
||||
``signatures`` Object Digital signatures for this object
|
||||
signed using the ``verify_keys``.
|
||||
``tls_certificate`` String The X.509 TLS certificate used by this
|
||||
this server encoded as `Unpadded Base64`_.
|
||||
==================== =================== ======================================
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"server_name": "example.org",
|
||||
"signatures": {
|
||||
"example.org": {
|
||||
"ed25519:auto": "Base+64+Encoded+Signature"
|
||||
}
|
||||
},
|
||||
"tls_certificate": "Base+64+Encoded+DER+Encoded+X509+TLS+Certificate",
|
||||
"verify_keys": {
|
||||
"ed25519:auto": "Base+64+Encoded+Signature+Verification+Key"
|
||||
}
|
||||
}
|
||||
|
||||
When fetching the keys for a server the client should check that the TLS
|
||||
certificate in the JSON matches the TLS server certificate for the connection
|
||||
and should check that the JSON signatures are correct for the supplied
|
||||
``verify_keys``.
|
||||
|
||||
Transactions
|
||||
------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue