Merge pull request #1423 from turt2live/travis/s2s/keys

Improve the server key exchange portion of the s2s specification
pull/977/head
Travis Ralston 6 years ago committed by GitHub
commit b96ee3e393
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -20,50 +20,62 @@ properties:
server_name: server_name:
type: string type: string
description: DNS name of the homeserver. description: DNS name of the homeserver.
required: true # TODO: Verify required: true
example: "example.org" example: "example.org"
verify_keys: verify_keys:
type: object type: object
description: Public keys of the homeserver for verifying digital signatures. description: |-
required: true # TODO: Verify 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. The version must have characters matching the regular
expression ``[a-zA-Z0-9_]``.
required: true
additionalProperties: additionalProperties:
type: object type: object
title: Verify Key title: Verify Key
example: { example: {
"ed25519:auto2": { "ed25519:abc123": {
"key": "Base+64+Encoded+Signature+Verification+Key" "key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA"
} }
} }
properties: properties:
key: key:
type: string type: string
description: The key description: The `Unpadded Base64`_ encoded key.
required: true required: true
example: "Base+64+Encoded+Signature+Verification+Key" example: "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA"
old_verify_keys: old_verify_keys:
type: object 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. The version must have characters matching the regular
expression ``[a-zA-Z0-9_]``.
additionalProperties: additionalProperties:
type: object type: object
title: Old Verify Key title: Old Verify Key
example: { example: {
"ed25519:auto1": { "ed25519:0ldK3y": {
"expired_ts": 922834800000, "expired_ts": 1532645052628,
"key": "Base+64+Encoded+Signature+Verification+Key" "key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg"
} }
} }
properties: properties:
expired_ts: expired_ts:
type: integer type: integer
format: int64 format: int64
description: The expiration time. description: POSIX timestamp in milliseconds for when this key expired.
required: true required: true
example: 922834800000 example: 1532645052628
key: key:
type: string type: string
description: The key. description: The `Unpadded Base64`_ encoded key.
required: true required: true
example: "Base+64+Encoded+Signature+Verification+Key" example: "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg"
signatures: signatures:
type: object type: object
description: Digital signatures for this object signed using the ``verify_keys``. description: Digital signatures for this object signed using the ``verify_keys``.
@ -72,7 +84,7 @@ properties:
title: Signed Server title: Signed Server
example: { example: {
"example.org": { "example.org": {
"ad25519:auto2": "Base+64+Encoded+Signature+Verification+Key" "ad25519:abc123": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU"
} }
} }
additionalProperties: additionalProperties:
@ -80,17 +92,19 @@ properties:
name: Encoded Signature Verification Key name: Encoded Signature Verification Key
tls_fingerprints: tls_fingerprints:
type: array type: array
description: Hashes of X.509 TLS certificates used by this server encoded as `Unpadded Base64`_. description: Hashes of X.509 TLS certificates used by this server.
items: items:
type: object type: object
title: TLS Fingerprint title: TLS Fingerprint
properties: properties:
sha256: sha256:
type: string type: string
description: The encoded fingerprint. description: The `Unpadded Base64`_ encoded fingerprint.
example: Base+64+Encoded+SHA-256-Fingerprint example: "VGhpcyBpcyBoYXNoIHdoaWNoIHNob3VsZCBiZSBieXRlcw"
valid_until_ts: valid_until_ts:
type: integer type: integer
format: int64 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 example: 1052262000000

@ -15,13 +15,13 @@ type: object
description: Server keys description: Server keys
example: { example: {
"server_keys": [{ "server_keys": [{
$ref: "../examples/server_key.json" $ref: "../examples/server_key_notary_signed.json"
}] }]
} }
properties: properties:
server_keys: server_keys:
type: array type: array
title: Server Keys title: Server Keys
description: The server keys. description: The queried server's keys, signed by the notary server.
items: items:
$ref: "keys.yaml" $ref: "keys.yaml"

@ -1,23 +1,23 @@
{ {
"server_name": "example.org", "server_name": "example.org",
"verify_keys": { "verify_keys": {
"ed25519:auto2": { "ed25519:abc123": {
"key": "Base+64+Encoded+Signature+Verification+Key" "key": "VGhpcyBzaG91bGQgYmUgYSByZWFsIGVkMjU1MTkgcGF5bG9hZA"
} }
}, },
"old_verify_keys": { "old_verify_keys": {
"ed25519:auto1": { "ed25519:0ldk3y": {
"expired_ts": 922834800000, "expired_ts": 1532645052628,
"key": "Base+64+Encoded+Old+Verify+Key" "key": "VGhpcyBzaG91bGQgYmUgeW91ciBvbGQga2V5J3MgZWQyNTUxOSBwYXlsb2FkLg"
} }
}, },
"signatures": { "signatures": {
"example.org": { "example.org": {
"ed25519:auto2": "Base+64+Encoded+Signature" "ed25519:auto2": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU"
} }
}, },
"tls_fingerprints": [{ "tls_fingerprints": [{
"sha256": "Base+64+Encoded+SHA-256-Fingerprint" "sha256": "VGhpcyBpcyBoYXNoIHdoaWNoIHNob3VsZCBiZSBieXRlcw"
}], }],
"valid_until_ts": 1052262000000 "valid_until_ts": 1652262000000
} }

@ -0,0 +1,11 @@
{
"$ref": "server_key.json",
"signatures": {
"example.org": {
"ed25519:abc123": "VGhpcyBzaG91bGQgYWN0dWFsbHkgYmUgYSBzaWduYXR1cmU"
},
"notary.server.com": {
"ed25519:010203": "VGhpcyBpcyBhbm90aGVyIHNpZ25hdHVyZQ"
}
}
}

@ -25,49 +25,61 @@ produces:
paths: paths:
"/query/{serverName}/{keyId}": "/query/{serverName}/{keyId}":
get: get:
summary: Retrieve a server key. summary: Query for another server's keys
description: Retrieve a server key. description: |-
Query for another server's keys. The receiving (notary) server must
sign the keys returned by the queried server.
operationId: perspectivesKeyQuery operationId: perspectivesKeyQuery
parameters: parameters:
- in: path - in: path
name: serverName name: serverName
type: string type: string
description: Server name. description: The server's DNS name to query
required: true required: true
x-example: matrix.org x-example: matrix.org
- in: path - in: path
name: keyId name: keyId
type: string type: string
description: Key ID. description: |-
required: true **Deprecated**. Servers should not use this parameter and instead
x-example: TODO # No examples in spec so far opt to return all keys, not just the requested one. The key ID to
look up.
required: false
x-example: "ed25519:abc123"
- in: query - in: query
name: minimum_valid_until_ts name: minimum_valid_until_ts
type: integer type: integer
format: int64 format: int64
description: Minimum Valid Until Milliseconds. description: |-
required: true # TODO: Verify A millisecond POSIX timestamp in milliseconds 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 x-example: 1234567890
responses: responses:
200: 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: schema:
$ref: "definitions/keys_query_response.yaml" $ref: "definitions/keys_query_response.yaml"
"/query": "/query":
post: post:
summary: Retrieve a server key summary: Query for several server's keys
description: Retrieve a server key. 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: bulkPerspectivesKeyQuery operationId: bulkPerspectivesKeyQuery
parameters: parameters:
- in: body - in: body
name: body name: body
schema: schema:
type: object type: object
# TODO: Improve example
example: { example: {
"server_keys": { "server_keys": {
"{server_name}": { "example.org": {
"{key_id}": { "ed25519:abc123": {
"minimum_valid_until_ts": 1234567890 "minimum_valid_until_ts": 1234567890
} }
} }
@ -76,7 +88,16 @@ paths:
properties: properties:
server_keys: server_keys:
type: object 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: additionalProperties:
type: object type: object
name: ServerName name: ServerName
@ -84,16 +105,25 @@ paths:
additionalProperties: additionalProperties:
type: object type: object
title: Query Criteria title: Query Criteria
description: The server keys to query. description: The server key IDs to query.
properties: properties:
minimum_valid_until_ts: minimum_valid_until_ts:
type: integer type: integer
format: int64 format: int64
description: Minimum Valid Until MS. description: |-
A millisecond POSIX timestamp in milliseconds 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 example: 1234567890
required: ['server_keys'] required: ['server_keys']
responses: responses:
200: 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: schema:
$ref: "definitions/keys_query_response.yaml" $ref: "definitions/keys_query_response.yaml"

@ -25,18 +25,37 @@ produces:
paths: paths:
"/server/{keyId}": "/server/{keyId}":
get: get:
summary: Get the server's key summary: Get the homeserver's public key(s)
description: Get the server's key. 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.
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 operationId: getServerKey
parameters: parameters:
- in: path - in: path
name: keyId name: keyId
type: string type: string
description: Key ID description: |-
**Deprecated**. Servers should not use this parameter and instead
opt to return all keys, not just the requested one. The key ID to
look up.
required: false required: false
x-example: TODO # No examples in the spec so far x-example: "ed25519:abc123"
deprecated: true
responses: responses:
200: 200:
description: The server's keys. description: The homeserver's keys
schema: schema:
$ref: "definitions/keys.yaml" $ref: "definitions/keys.yaml"

@ -106,15 +106,17 @@ Server implementation
Retrieving Server Keys 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/``. Each homeserver publishes its public keys under ``/_matrix/key/v2/server/{keyId}``.
Homeservers query for keys by either getting ``/_matrix/key/v2/server/`` Homeservers query for keys by either getting ``/_matrix/key/v2/server/{keyId}``
directly or by querying an intermediate notary server using a directly or by querying an intermediate notary server using a
``/_matrix/key/v2/query`` API. Intermediate notary servers query the ``/_matrix/key/v2/query/{serverName}/{keyId}`` API. Intermediate notary servers
``/_matrix/key/v2/server/`` API on behalf of another server and sign the query the ``/_matrix/key/v2/server/{keyId}`` API on behalf of another server and
response with their own key. A server may query multiple notary servers to sign the response with their own key. A server may query multiple notary servers to
ensure that they all report the same public keys. ensure that they all report the same public keys.
This approach is borrowed from the `Perspectives Project`_, but modified to 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/ .. _Perspectives Project: https://web.archive.org/web/20170702024706/https://perspectives-project.org/
Publishing Keys Publishing Keys
^^^^^^^^^^^^^^^ +++++++++++++++
Homeservers publish the allowed TLS fingerprints and signing keys in a JSON 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 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 ``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 are only valid for signing events. Finally the response contains a list of TLS
certificate fingerprints to validate any connection made to the server. certificate fingerprints to validate any connection made to the homeserver.
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.
{{keys_server_ss_http_api}} {{keys_server_ss_http_api}}
Querying Keys Through Another Server 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.
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.
{{keys_query_ss_http_api}}
Version 1
+++++++++
.. WARNING::
Version 1 of key distribution is obsolete.
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.
Homeservers publish their TLS certificates and signing keys in a JSON object Notary servers can return keys for servers that are offline or having issues
at ``/_matrix/key/v1``. serving their own keys by using cached responses. Keys can be queried from
multiple servers to mitigate against DNS spoofing.
==================== =================== ======================================
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
{ {{keys_query_ss_http_api}}
"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 Transactions
------------ ------------

Loading…
Cancel
Save