Compare commits

...

5 commits

Author SHA1 Message Date
famfo 6f31da839a
Merge 8947eaf0b2 into fafd11f809 2026-04-21 21:26:04 +01:00
timedout fafd11f809
Clarify how multiple signatures should be handled during verification (#2341)
Signed-off-by: timedout <git@nexy7574.co.uk>
2026-04-21 21:24:28 +01:00
famfo 8947eaf0b2
f 2026-04-12 03:26:22 +02:00
famfo 8424acd0e1
f 2026-04-03 23:24:39 +02:00
famfo 113315248d
s2s/query: clarify profile behaviour and API responses
Signed-off-by: famfo <famfo@famfo.xyz>
2026-03-22 12:41:15 +01:00
4 changed files with 67 additions and 45 deletions

View file

@ -0,0 +1 @@
Clarify the behaviour and response format of `GET /_matrix/federation/v1/query/profile`.

View file

@ -0,0 +1 @@
Clarify how multiple signatures should be handled during signature verification. Contributed by @nexy7574.

View file

@ -1484,34 +1484,30 @@ the Policy Server for a signature too.
When a server receives an event over federation from another server, the When a server receives an event over federation from another server, the
receiving server should check the hashes and signatures on that event. receiving server should check the hashes and signatures on that event.
First the signature is checked. The event is redacted following the First the signatures are checked. The event is redacted following the
[redaction [redaction algorithm](/client-server-api#redactions), and
algorithm](/client-server-api#redactions), and the resultant object is checked for signatures from the originating
the resultant object is checked for a signature from the originating
server, following the algorithm described in [Checking for a server, following the algorithm described in [Checking for a
signature](/appendices#checking-for-a-signature). Note that this signature](/appendices#checking-for-a-signature). Note that this
step should succeed whether we have been sent the full event or a step should succeed whether we have been sent the full event or a
redacted copy. redacted copy.
The signatures expected on an event are: For room versions 3 and later, unless the event is a 3rd party invite, only the
signature(s) from the originating server (the server the `sender` belongs to)
are required for verification. Room versions 1 and 2 also require that a
signature is present from the domain in the `event_id`, if it differs from the
originating server. If a signature is from an unknown or expired key, it is
skipped.
- The `sender`'s server, unless the invite was created as a result of If the event is a 3rd party invite, the sender must already match the 3rd party
3rd party invite. The sender must already match the 3rd party invite, and the server which actually sends the event may be a different
invite, and the server which actually sends the event may be a server.
different server.
- For room versions 1 and 2, the server which created the `event_id`.
Other room versions do not track the `event_id` over federation and
therefore do not need a signature from those servers.
If the signature is found to be valid, the expected content hash is Only signatures from known server keys are validated here. Any unknown keys are ignored.
calculated as described below. The content hash in the `hashes` property In particular, the [policy server key](#validating-policy-server-signatures) is not
of the received event is base64-decoded, and the two are compared for expected to be published and therefore should be skipped at this stage.
equality. Additionally, any keys that are known to have expired prior to the event's
`origin_server_ts` are ignored.
If the hash check fails, then it is assumed that this is because we have
only been given a redacted version of the event. To enforce this, the
receiving server should use the redacted copy it calculated rather than
the full copy it received.
{{% boxes/note %}} {{% boxes/note %}}
{{% added-in v="1.18" %}} {{% added-in v="1.18" %}}
@ -1519,6 +1515,16 @@ Events sent in rooms with [Policy Servers](#policy-servers) have [additional](#v
signature validation requirements. signature validation requirements.
{{% /boxes/note %}} {{% /boxes/note %}}
If all signatures from known unexpired keys from the originating server(s) are
found to be valid, the expected content hash is calculated as described below.
The content hash in the `hashes` property of the received event is base64-decoded,
and the two are compared for equality.
If the hash check fails, then it is assumed that this is because we have
only been given a redacted version of the event. To enforce this, the
receiving server should use the redacted copy it calculated rather than
the full copy it received.
### Calculating the reference hash for an event ### Calculating the reference hash for an event
The *reference hash* of an event covers the essential fields of an The *reference hash* of an event covers the essential fields of an

View file

@ -111,22 +111,26 @@ paths:
summary: Query for profile information about a given user summary: Query for profile information about a given user
description: |- description: |-
Performs a query to get profile information, such as a display name or avatar, Performs a query to get profile information, such as a display name or avatar,
for a given user. Homeservers should only query profiles for users that belong for a given user. Homeservers MUST only query profiles for users that belong
to the target server (identified by the [server name](/appendices/#server-name) to the target server (identified by the [server name](/appendices/#server-name)
in the user ID). in the user ID).
Servers may wish to cache the response to this query to avoid requesting the Responding servers MAY:
information too often. - Include arbitrary key/value pairs in the profile in addition to the
specified pairs.
- Deny profile look-up over federation by responding with 403 and an error code of
`M_FORBIDDEN`.
- Omit certain key/value pairs in the response.
Servers MAY deny profile look-up over federation by responding with 403 and an Requesting servers MAY wish to cache the response to this query to avoid requesting the
error code of `M_FORBIDDEN`. information too often.
operationId: queryProfile operationId: queryProfile
security: security:
- signedRequest: [] - signedRequest: []
parameters: parameters:
- in: query - in: query
name: user_id name: user_id
description: The user ID to query. Must be a user local to the receiving homeserver. description: The user ID to query. MUST be a user local to the receiving homeserver.
required: true required: true
example: "@someone:example.org" example: "@someone:example.org"
schema: schema:
@ -134,24 +138,26 @@ paths:
- in: query - in: query
name: field name: field
description: |- description: |-
The field to query. If specified, the server will only return the given field The field of the profile to query. If specified, the server MUST only return the
in the response. If not specified, the server will return the full profile for given field in the response. If not specified, the server MUST return the full,
the user. public, profile for the user.
Defined values are `displayname`, `avatar_url` and `m.tz`. In addition to these
servers MAY allow users to set additional key/value pairs.
schema: schema:
type: string type: string
enum:
- displayname
- avatar_url
responses: responses:
"200": "200":
description: |- description: |-
The profile for the user. If a `field` is specified in the request, only the The profile for the user. If a `field` is specified in the request, the response
matching field should be included in the response. If no `field` was specified, MUST only include the specified `field`. If no `field` was specified, the response
the response should include the fields of the user's profile that can be made SHOULD include all of the fields of the user's profile, which can be made public.
public, such as the display name and avatar.
If a field in the user's profile can't be made public over the federation, the
responding server MAY choose to exclude it in the response.
If the user does not have a particular field set on their profile, the server If the user does not have a particular field set on their profile, the server
should exclude it from the response body or give it the value `null`. MUST either exclude it from the response body or give it the value `null`.
content: content:
application/json: application/json:
schema: schema:
@ -160,20 +166,28 @@ paths:
displayname: displayname:
type: string type: string
description: |- description: |-
The display name of the user. May be omitted if the user does not have a The display name of the user. MUST either be omitted or set to `null` if
display name set. the user does not have a display name set.
example: John Doe example: John Doe
avatar_url: avatar_url:
type: string type: string
description: |- description: |-
The avatar URL for the user's avatar. May be omitted if the user does not The avatar URL for the user's avatar. MUST either be omitted or set to
have an avatar set. `null` if the user does not have an avatar set.
example: mxc://matrix.org/MyC00lAvatar example: mxc://example.org/MyC00lAvatar
m.tz:
type: string
description: The name of the user's time zone. The name SHOULD be registered in
the [IANA Time Zone Database](https://www.iana.org/time-zones). Requesting
servers MUST tolerate invalid or unknown values.
x-addedInMatrixVersion: "1.16"
additionalProperties:
description: Additional profile fields.
examples: examples:
response: response:
value: { value: {
"displayname": "John Doe", "displayname": "John Doe",
"avatar_url": "mxc://matrix.org/MyC00lAvatar" "avatar_url": "mxc://example.org/MyC00lAvatar"
} }
"403": "403":
x-addedInMatrixVersion: "1.12" x-addedInMatrixVersion: "1.12"
@ -190,7 +204,7 @@ paths:
"error": "Profile lookup over federation is disabled on this homeserver" "error": "Profile lookup over federation is disabled on this homeserver"
} }
"404": "404":
description: The user does not exist or does not have a profile. description: The user does not exist, does not have a profile or the queried field does not exist.
content: content:
application/json: application/json:
schema: schema: