From 456beb61b0fd31f3992252f19d41be88732dd35d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Fri, 5 Sep 2025 15:46:47 +0100 Subject: [PATCH] Make rendezvous API more like rests of Client-Server API --- proposals/4108-oidc-qr-login.md | 374 +++++++++++++--------------- proposals/images/4108-qr-mode03.png | Bin 921 -> 809 bytes proposals/images/4108-qr-mode04.png | Bin 917 -> 816 bytes 3 files changed, 169 insertions(+), 205 deletions(-) diff --git a/proposals/4108-oidc-qr-login.md b/proposals/4108-oidc-qr-login.md index 8009811a0..22f669eb4 100644 --- a/proposals/4108-oidc-qr-login.md +++ b/proposals/4108-oidc-qr-login.md @@ -36,183 +36,163 @@ end-to-end confidentiality nor authenticity by itself---these are layered on top Suppose that Device A wants to establish communications with Device B. Device A can do so by creating a _rendezvous session_ via a `POST /_matrix/client/v1/rendezvous` call to an appropriate homeserver. Its response includes -an HTTP _rendezvous URL_ which should be shared out-of-band with Device B. (This URL may be located on a different -domain to the initial `POST`.) +an _rendezvous ID_ which, along with the server name, should be shared out-of-band with Device B. -The rendezvous URL points to an arbitrary data resource (the "payload"), which is initially populated using data from -A's initial `POST` request. There are no restrictions on the payload itself, but the rendezvous server SHOULD impose a -maximum size limit. +The rendezvous ID points to an arbitrary data resource (the "payload") on the homeserver, which is initially populated +using data from A's initial `POST` request. The payload is a string which the homeserver must enforce a maximum length on. -Anyone who is able to reach the rendezvous URL - including: Device A; Device B; or a third party; - can then "receive" -the payload by polling via a `GET` request, and "send" a new a new payload by making a `PUT` request. +Anyone who is able to reach the homeserver and has the rendezvous ID - including: Device A; Device B; or a third party; - +can then "receive" the payload by polling via a `GET` request, and "send" a new a new payload by making a `PUT` request. -In this way, Device A and Device B can communicate by repeatedly inspecting and updating the payload at the rendezvous URL. +In this way, Device A and Device B can communicate by repeatedly inspecting and updating the payload at the rendezvous session. #### The send mechanism -Every send request MUST include an `If-Match` header whose value is the `ETag` header in the last `GET` -response seen by the requester. (The initiating device may also use the `ETag` supplied in the initial `POST` response -to immediately update the payload.) Sends will succeed only if the supplied `ETag` matches the server's current +Every send request MUST include an `sequence_token` value whose value is the `sequence_token` from the last `GET` +response seen by the requester. (The initiating device may also use the `sequence_token` supplied in the initial `POST` response +to immediately update the payload.) Sends will succeed only if the supplied `sequence_token` matches the server's current revision of the payload. This prevents concurrent writes to the payload. -The `ETag` header is standard, described by [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-etag). In this -proposal we only accept strong, single-valued `ETag` values; anything else constitutes a malformed request. - n.b. Once a new payload has been sent there is no mechanism to retrieve previous payloads. #### Expiry -The rendezvous session (i.e. the payload) SHOULD expire after a period of time communicated to clients via the `Expires` -header. After this point, any further attempts to query or update the payload MUST fail. The rendezvous session can be -manually expired with a `DELETE` call to the rendezvous session. +The rendezvous session (i.e. the payload) SHOULD expire after a period of time communicated to clients via the +`expires_ts` field on the `POST` and `GET` response bodies. After this point, any further attempts to query or update +the payload MUST fail. The rendezvous session can be manually expired with a `DELETE` call to the rendezvous session. ####  API -##### Common HTTP response headers - -- `ETag` - required, ETag for the current payload at the rendezvous session as per [RFC7232](https://httpwg.org/specs/rfc7232.html#header.etag) -- `Expires` - required, the expiry time of the rendezvous as per [RFC7234](https://httpwg.org/specs/rfc7234.html#header.expires) -- `Last-Modified` - required, the last modified date of the payload as per [RFC7232](https://httpwg.org/specs/rfc7232.html#header.last-modified) -- `Cache-Control` - required, `no-store` as per [RFC7234](https://httpwg.org/specs/rfc7234.html#header.cache-control) -- `Pragma` - required, `no-cache` as per [RFC7234](https://httpwg.org/specs/rfc7234.html#header.pragma) - ##### Create a rendezvous session and send initial payload: `POST /_matrix/client/v1/rendezvous` This would be part of the Client-Server API. -HTTP request headers: - -- `Content-Length` - required -- `Content-Type` - required, must be `text/plain` - -HTTP request body: +Request body is `application/json` with contents: -- any data up to maximum size allowed by the server +|Field|Type|| +|-|-|-| +|`data`|required `string`|The data payload to be sent| -HTTP response codes, and Matrix error codes: +For example: -- `201 Created` - rendezvous session created -- `400 Bad Request` (``M_MISSING_PARAM``) - either `Content-Length` and/or `Content-Type` was not provided. -- `400 Bad Request` (`M_INVALID_PARAM`) - an invalid `Content-Type` was given. -- `403 Forbidden` (``M_FORBIDDEN``) - forbidden by server policy -- `413 Payload Too Large` (``M_TOO_LARGE``) - the supplied payload is too large -- `429 Too Many Requests` (``M_UNKNOWN``) - the request has been rate limited -- `307 Temporary Redirect` - if the request should be served from somewhere else specified in the `Location` response header +```http +POST /_matrix/client/v1/rendezvous HTTP/1.1 +Content-Type: application/json -n.b. the [`307 Temporary Redirect`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307) response code has been -chosen explicitly for the behaviour of ensuring that the method and body will not change whilst the user-agent follows -the redirect. For this reason, no other `30x` response codes are allowed. +{ + "data": "initial data" +} +``` -HTTP response headers for `201 Created`: +HTTP response codes, and Matrix error codes: -- `Content-Type`- required, application/json -- common headers as defined above +- `200 OK` - rendezvous session created +- `413 Payload Too Large` (`M_TOO_LARGE`) - the supplied payload is too large +- `429 Too Many Requests` (`M_LIMIT_EXCEEDED`) - the request has been rate limited -HTTP response body for `201 Created`: +Response body for `200 OK` is `application/json` with contents: -- a JSON object with a single key `url` whose value is the absolute URL of the rendezvous session +|Field|Type|| +|-|-|-| +|`id`|required `string`|Opaque identifier for the rendezvous session| +|`sequence_token`|required `string`|The token opaque token to identify if the payload has changed| +|`expires_ts`|required `integer`|The timestamp (in milliseconds since the epoch) at which the rendezvous session will expire| Example response: ```http -HTTP 201 Created +HTTP 200 OK Content-Type: application/json -ETag: VmbxF13QDusTgOCt8aoa0d2PQcnBOXeIxEqhw5aQ03o= -Expires: Wed, 07 Sep 2022 14:28:51 GMT -Last-Modified: Wed, 07 Sep 2022 14:27:51 GMT -Cache-Control: no-store -Pragma: no-cache { - "url": "http://example.org/abcdEFG12345" + "id": "abcdEFG12345", + "sequence_token": "VmbxF13QDusTgOCt8aoa0d2PQcnBOXeIxEqhw5aQ03o=", + "expires_ts": 1662560931000 } ``` -##### Send a payload to the rendezvous session: `PUT ` +##### Send a payload to the rendezvous session: `PUT /_matrix/client/v1/{rendezvousId}` -HTTP request headers: +Request body is `application/json` with contents: -- `Content-Length` - required -- `Content-Type` - required, must be `text/plain` -- `If-Match` - required. The ETag of the last payload seen by the requesting device. +|Field|Type|| +|-|-|-| +|`sequence_token`|required `string`|The value of `sequence_token` from the last payload seen by the requesting device.| +|`data`|required `string`|The data payload to be sent.| -HTTP request body: +For example: -- any data up to maximum size allowed by the server +```http +PUT /_matrix/client/v1/rendezvous/abcdEFG12345 HTTP/1.1 +Content-Type: application/json + +{ + "sequence_token": "VmbxF13QDusTgOCt8aoa0d2PQcnBOXeIxEqhw5aQ03o=", + "data": "new data" +} +``` HTTP response codes, and Matrix error codes: -- `202 Accepted` - payload updated -- `400 Bad Request` (`M_MISSING_PARAM`) - a required header was not provided. -- `400 Bad Request` (`M_INVALID_PARAM`) - a malformed -[`ETag`](https://github.com/matrix-org/matrix-spec-proposals/blob/hughns/simple-rendezvous-capability/proposals/3886-simple-rendezvous-capability.md#the-update-mechanism) -header was provided or invalid `Content-Type`. -- `404 Not Found` (`M_NOT_FOUND`) - rendezvous session URL is not valid (it could have expired) -- `412 Precondition Failed` (`M_CONCURRENT_WRITE`, a new error code) - when the ETag does not match +- `200 OK` - payload updated +- `404 Not Found` (`M_NOT_FOUND`) - rendezvous session ID is not valid (it could have expired) +- `409 Conflict` (`M_CONCURRENT_WRITE`, a new error code) - when the `sequence_token` does not match - `413 Payload Too Large` (`M_TOO_LARGE`) - the supplied payload is too large - `429 Too Many Requests` (`M_UNKNOWN`) - the request has been rate limited -HTTP response headers for `202 Accepted` and `412 Precondition Failed`: +The response body for `200 OK` is `application/json` with contents: -- common headers as defined above +|Field|Type|| +|-|-|-| +|`sequence_token`|required `string`|The token opaque token to identify if the payload has changed| -##### Receive a payload from the rendezvous session: `GET ` +For example: -HTTP request headers: +```http +HTTP 200 OK +Content-Type: application/json -- `If-None-Match` - optional, as per [RFC7232](https://httpwg.org/specs/rfc7232.html#header.if-none-match) server will -only return data if given ETag does not match +{ + "sequence_token": "VmbxF13QDusTgOCt8aoa0d2PQcnBOXeIxEqhw5aQ03o=" +} +``` + +##### Receive a payload from the rendezvous session: `GET /_matrix/client/v1/{rendezvousId}` HTTP response codes, and Matrix error codes: - `200 OK` - payload returned -- `304 Not Modified` - when `If-None-Match` is supplied and the ETag matched the existing payload -- `404 Not Found` (`M_NOT_FOUND`) - rendezvous session URL is not valid (it could have expired) +- `404 Not Found` (`M_NOT_FOUND`) - rendezvous session ID is not valid (it could have expired) - `429 Too Many Requests` (`M_UNKNOWN`) - the request has been rate limited -HTTP response headers for `200 OK`: - -- `Content-Type` - required, `text/plain` -- common headers as defined above - -HTTP response headers for `304 Not Modified`: - -- common headers as defined above - -HTTP response body for `200 OK`:: +Response body for `200 OK` is `application/json` with contents: -- The payload last set for this rendezvous session, either via the creation POST request or a subsequent PUT request, up -to the maximum size allowed by the server. - -Example responses: +|Field|Type|| +|-|-|-| +|`data`|required `string`|The data payload from the last POST or PUT.| +|`sequence_token`|required `string`|The token opaque token to identify if the payload has changed| +|`expires_ts`|required `integer`|The timestamp (in milliseconds since the epoch) at which the rendezvous session will expire| ```http HTTP 200 OK -Content-Type: text/plain -ETag: VmbxF13QDusTgOCt8aoa0d2PQcnBOXeIxEqhw5aQ03o= -Expires: Wed, 07 Sep 2022 14:28:51 GMT -Last-Modified: Wed, 07 Sep 2022 14:27:51 GMT -Cache-Control: no-store -Pragma: no-cache - -foo -``` +Content-Type: application/json -```http -HTTP 304 Not Modified -ETag: VmbxF13QDusTgOCt8aoa0d2PQcnBOXeIxEqhw5aQ03o= -Expires: Wed, 07 Sep 2022 14:28:51 GMT -Last-Modified: Wed, 07 Sep 2022 14:27:51 GMT -Cache-Control: no-store -Pragma: no-cache +{ + "data": "data from the previous POST/PUT", + "sequence_token": "VmbxF13QDusTgOCt8aoa0d2PQcnBOXeIxEqhw5aQ03o=", + "expires_ts": 1662560931000 +} ``` -##### Cancel a rendezvous session: `DELETE ` +A future optimisation could be allow the client to "long-poll" by sending the previous `sequence_token` as a query parameter +and then the server returns when the is new data or some timeout has passed. + +##### Cancel a rendezvous session: `DELETE /_matrix/client/v1/{rendezvousId}` HTTP response codes: -- `204 No Content` - rendezvous session cancelled -- `404 Not Found` (`M_NOT_FOUND`) - rendezvous session URL is not valid (it could have expired) +- `200 OK` - rendezvous session cancelled +- `404 Not Found` (`M_NOT_FOUND`) - rendezvous session ID is not valid (it could have expired) - `429 Too Many Requests` (`M_UNKNOWN`) - the request has been rate limited ##### Authentication @@ -222,9 +202,14 @@ described later. ##### Maximum payload size -The server enforce a maximum payload size of 4KB. +The server MUST enforce a maximum payload size of 4KB. -###### Maximum duration of a rendezvous +##### `sequence_token` values + +The `sequence_token` values should be unique to the rendezvous session and the last modified time so that two clients can +distinguish between identical payloads sent by either client. + +##### Maximum duration of a rendezvous The rendezvous session needs to persist for the duration of the login including allowing the user another time to confirm that the secure channel has been established and complete any extra homeserver mandated login steps such as MFA. @@ -236,34 +221,6 @@ The server MUST enforce a timeout on each rendezvous. When picking a value to us - the minimum timeout SHOULD be 120 seconds for usability - the maximum timeout SHOULD be 300 seconds for security -###### ETags - -The ETag generated should be unique to the rendezvous session and the last modified time so that two clients can -distinguish between identical payloads sent by either client. - -In order to make sure that no intermediate caches manipulate the ETags, the rendezvous server MUST include the HTTP -`Cache-Control` response header with a value of `no-store` and `Pragma` response header with a value of `no-cache`. - -###### CORS - -For the `POST /_matrix/client/v1/rendezvous` API endpoint, in addition to the standard Client-Server API [CORS](https://spec.matrix.org/v1.4/client-server-api/#web-browser-clients) -headers, the ETag response header should also be allowed by exposing the following CORS header: - -```http -Access-Control-Expose-Headers: ETag -``` - -To support usage from web browsers the rendezvous URLs should allow CORS requests from any origin and expose the headers -which aren't on the CORS [request header](https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header) and -[response header](https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_response_header) safelists: - -```http -Access-Control-Allow-Headers: If-Match,If-None-Match -Access-Control-Allow-Methods: GET, PUT, DELETE -Access-Control-Allow-Origin: * -Access-Control-Expose-Headers: ETag -``` - ##### Choice of server Ultimately it will be up to the Matrix client implementation to decide which rendezvous server to use. @@ -277,63 +234,59 @@ of preference: #### Example API usage -n.b. This example demonstrates how the 307 response can be used to delegate the rendezvous session to a different server. - ```mermaid sequenceDiagram participant A as Device A participant HS as Homeserver - participant R as Rendezvous Server
https://rz.example.com participant B as Device B Note over A: Device A determines which rendezvous server to use - A->>+HS: POST /_matrix/client/v1/rendezvous
Content-Type: text/plain
"Hello from A" - HS->>-A: 307 Temporary Redirect
Location: https://rz.example.com/foo - A->>+R: POST /foo
Content-Type: text/plain
"Hello from A" - R->>-A: 201 Created
ETag: 1
{"url":"https://rz.example.com/abc-def-123-456"} + A->>+HS: POST /_matrix/client/v1/rendezvous
{"data":"Hello from A"} + HS->>-A: 200 OK
{"id":"abc-def-123-456","sequence_token": "1", "expires_ts": 1234567} - A-->>B: Rendezvous URL shared out of band as QR code: e.g. https://rz.example.com/abc-def-123-456 + A-->>B: Rendezvous ID and homeserver shared out of band as QR code: e.g. id=abc-def-123-456 servername=example.com - Note over A: Device A starts polling for new payloads at the
rendezvous session using the returned ETag + Note over A: Device A starts polling for new payloads at the
rendezvous session using the returned `sequence_token` activate A - B->>+R: GET /abc-def-123-456 - R->>-B: 200 OK
ETag: 1
Content-Type: text/plain
"Hello from A" + Note over B: Device B resolves the servername to the homeserver + B->>+HS: GET /_matrix/client/v1/rendezvous/abc-def-123-456 + HS->>-B: 200 OK
{"sequence_token": "1", "data": "Hello from A"} loop Device A polls the rendezvous session for a new payload - A->>+R: GET /abc-def-123-456
If-None-Match: 1 + A->>+HS: GET /_matrix/client/v1/rendezvous/abc-def-123-456 alt is not modified - R->>-A: 304 Not Modified + HS->>-A: 200 OK
{"sequence_token": "1", "data": "Hello from A", "expires_ts": 1234567} end end note over B: Device B sends a new payload - B->>+R: PUT /abc-def-123-456
If-Match: 1
Content-Type: text/plain
"Hello from B" - R->>-B: 202 Accepted
ETag: 2 + B->>+HS: PUT /_matrix/client/v1/rendezvous/abc-def-123-456
{"sequence_token": "1", "data": "Hello from B"} + HS->>-B: 200 OK
{"sequence_token": "2"} - Note over B: Device B starts polling for new payloads at the
rendezvous session using the new ETag + Note over B: Device B starts polling for new payloads at the
rendezvous session using the new `sequence_token` activate B loop Device B polls the rendezvous session for a new payload - B->>+R: GET /abc-def-123-456
If-None-Match: 2 + B->>+HS: GET /_matrix/client/v1/rendezvous/abc-def-123-456 alt is not modified - R->>-B: 304 Not Modified + HS->>-B: 200 OK
{"sequence_token": "2", "data": "Hello from A", "expires_ts": 1234567} end end note over A: Device A then receives the new payload opt modified - R->>A: 200 OK
ETag: 2
Content-Type: text/plain
"Hello from B" + HS->>A: 200 OK
{"sequence_token": "2", "data": "Hello from B", "expires_ts": 1234567} end deactivate A note over A: Device A sends a new payload - A->>+R: PUT /abc-def-123-456
If-None-Match: 2
Content-Type: text/plain
"Hello again from A" - R->>-A: 202 Accepted
ETag: 3 + A->>+HS: PUT /_matrix/client/v1/rendezvous/abc-def-123-456
{"sequence_token": "2", "data": "Hello again from A"} + HS->>-A: 200 OK
{"sequence_token": "3"} note over B: Device B then receives the new payload opt modified - R->>B: 200 OK
ETag: 3
Content-Type: text/plain
... + HS->>B: 200 OK
{"sequence_token": "3", "data": "Hello again from B", "expires_ts": 1234567} end deactivate B @@ -373,14 +326,12 @@ Mitigations that are included in this proposal: - the low maximum payload size - restricted allowed content type - the rendezvous session should be short-lived -- the ability for the rendezvous session to be hosted on a different domain to the homeserver (via -the `307 Temporary Redirect` response behaviour) ### Secure channel The above rendezvous session is insecure, providing no confidentiality nor authenticity against the rendezvous server or -even arbitrary network participants which possess the rendezvous session URL. To provide a secure channel on -top of this insecure rendezvous session transport, we propose the following scheme. +even arbitrary network participants which possess the rendezvous session ID and server name. +To provide a secure channel on top of this insecure rendezvous session transport, we propose the following scheme. This scheme is essentially [ECIES](https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme#Formal_description_of_ECIES) instantiated with X25519, HKDF-SHA256 for the KDF and ChaCha20-Poly1305 (as specified by @@ -418,17 +369,17 @@ separate deterministic, monotonically-incrementing nonce is used for each sender 2. **Create rendezvous session** Device G creates a rendezvous session by making a `POST` request (as described previously) to the nominated homeserver -with an empty payload. It parses the **url** received. +with an empty payload. It parses the **ID** received. 3. **Initial key exchange** Device G displays a QR code containing: - Its public key **Gp** -- The insecure rendezvous session **URL** +- The insecure rendezvous session **ID** - An indicator (the **intent**) to say if this is a new device which wishes to "initiate" a login, or an existing device that wishes to "reciprocate" a login -- If the intent is to reciprocate a login, then the Matrix homeserver **[server name](https://spec.matrix.org/v1.15/appendices/#server-name)** +- the Matrix homeserver **[server name](https://spec.matrix.org/v1.15/appendices/#server-name)** To get a good trade-off between visual compactness and high level of error correction we use a binary mode QR with a similar structure to that of the existing Device Verification QR code encoding described in [Client-Server @@ -436,7 +387,7 @@ API](https://spec.matrix.org/v1.9/client-server-api/#qr-code-format). This is defined in detail in a separate section of this proposal. -Device S scans and parses the QR code to obtain **Gp**, the rendezvous session **URL**, **intent** and optionally the Matrix homeserver +Device S scans and parses the QR code to obtain **Gp**, the rendezvous session **ID**, **intent** and the Matrix homeserver **[server name](https://spec.matrix.org/v1.15/appendices/#server-name)**. At this point Device S should check that the received intent matches what the user has asked to do on the device. @@ -481,8 +432,7 @@ Nonce_S := Nonce_S + 1 LoginInitiateMessage := UnpaddedBase64(TaggedCiphertext) || "|" || UnpaddedBase64(Sp) ``` -Device S then sends the **LoginInitiateMessage** as the payload to the rendezvous session using a `PUT` request with -`Content-Type` header set to `text/plain`. +Device S then sends the **LoginInitiateMessage** as the `data` payload to the rendezvous session using a `PUT` request. 5. **Device G confirms** @@ -506,8 +456,7 @@ Nonce_G := Nonce_G + 1 LoginOkMessage := UnpaddedBase64Encode(TaggedCiphertext) ``` -Device G sends **LoginOkMessage** as the payload via `PUT` request with `Content-Type` header set to `text/plain` to the -insecure rendezvous session. +Device G sends **LoginOkMessage** as the `data` payload via a `PUT` request to the insecure rendezvous session. 6. **Verification by Device S** @@ -570,48 +519,47 @@ The sequence diagram for the above is as follows: ```mermaid sequenceDiagram participant G as Device G - participant Z as Homeserver with embedded Rendezvous Server
matrix.example.com + participant Z as Homeserver participant S as Device S note over G,S: 1) Devices G and S each generate an ephemeral Curve25519 key pair activate G note over G: 2) Device G creates a rendezvous session as follows - G->>+Z: POST /_matrix/client/v1/rendezvous - Z->>-G: 201 Created
ETag: 1
{"url": "https://matrix.example.com/_synapse/client/rendezvous/abc-def"} + G->>+Z: POST /_matrix/client/v1/rendezvous
{"data": ""} + Z->>-G: 200 OK
{"id": "abc-def", "sequence_token": "1", "expires_ts": 1234567} - note over G: 3) Device G generates and displays a QR code containing
its ephemeral public key and the rendezvous session URL + note over G: 3) Device G generates and displays a QR code containing:
its ephemeral public key, the rendezvous session ID, the server name G-->>S: Device S scans the QR code shown by Device G deactivate G activate S - note over S: Device S validates QR scanned and the rendezvous session URL + note over S: Device S validates QR scanned and the rendezvous session ID - S->>+Z: GET /_synapse/client/rendezvous/abc-def - Z->>-S: 200 OK
ETag: 1 + S->>+Z: GET /_matrix/client/v1/rendezvous/abc-def + Z->>-S: 200 OK
{"sequence_token": "1", "expires_ts": 1234567, "data": ""} note over S: 4) Device S computes SH, EncKey_S, EncKey_G and LoginInitiateMessage.
It sends LoginInitiateMessage via the rendezvous session - S->>+Z: PUT /_synapse/client/rendezvous/abc-def
If-Match: 1
Body: LoginInitiateMessage - Z->>-S: 202 Accepted
ETag: 2 + S->>+Z: PUT /_matrix/client/v1/rendezvous/abc-def
{"sequence_token": "1", "data": ""} + Z->>-S: 200 OK
{"sequence_token": "2"} deactivate S - G->>+Z: GET /_synapse/client/rendezvous/abc-def
If-None-Match: 1 + G->>+Z: GET /_matrix/client/v1/rendezvous/abc-def activate G - Z->>-G: 200 OK
ETag: 2
Body: Data - + Z->>-G: 200 OK
{"sequence_token": "2", "expires_ts": 1234567, "data": ""} note over G: 5) Device G attempts to parse Data as LoginInitiateMessage after calculating SH, EncKey_S and EncKey_G note over G: Device G checks that the plaintext matches MATRIX_QR_CODE_LOGIN_INITIATE note over G: Device G computes LoginOkMessage and sends to the rendezvous session - G->>+Z: PUT /_synapse/client/rendezvous/abc-def
If-Match: 2
Body: LoginOkMessage - Z->>-G: 202 Accepted
ETag: 3 + G->>+Z: PUT /_matrix/client/v1/rendezvous/abc-def
{"sequence_token": "2", "data": ""} + Z->>-G: 200 OK
{"sequence_token": "3"} deactivate G activate S - S->>+Z: GET /_synapse/client/rendezvous/abc-def
If-None-Match: 2 - Z->>-S: 200 OK
ETag: 3
Body: Data + S->>+Z: GET /_matrix/client/v1/rendezvous/abc-def + Z->>-S: 200 OK
{"sequence_token": "3", "expires_ts": 1234567, "data": ""} note over S: 6) Device S attempts to parse Data as LoginOkMessage note over S: Device S checks that the plaintext matches MATRIX_QR_CODE_LOGIN_OK @@ -1379,53 +1327,69 @@ The QR codes to be displayed and scanned using this format will encode binary st - `0x03` a new device wishing to initiate a login and self-verify - `0x04` an existing device wishing to reciprocate the login of a new device and self-verify that other device - the ephemeral Curve25519 public key, as 32 bytes -- the rendezvous session URL encoded as: - - two bytes in network byte order (big-endian) indicating the length in bytes of the rendezvous session URL as a UTF-8 +- the rendezvous session ID encoded as: + - two bytes in network byte order (big-endian) indicating the length in bytes of the rendezvous session ID as a UTF-8 string - - the rendezvous session URL as a UTF-8 string -- If the QR code intent/mode is `0x04` then the [server name](https://spec.matrix.org/v1.15/appendices/#server-name) of the homeserver encoded as: + - the rendezvous session ID as a UTF-8 string +- the [server name](https://spec.matrix.org/v1.15/appendices/#server-name) of the homeserver encoded as: - two bytes in network byte order (big-endian) indicating the length in bytes of the server name as a UTF-8 string - the server name as a UTF-8 string -For example, if Alice displays a QR code encoding the following binary string: - -This indicates that Alice is a new device that wishes to initiate a login using her ephemeral public key of -`0001020304050607...` (which is `AAECAwQFBg…` in base64), via the rendezvous session at URL `https:/…`. - #### Example for QR code generated on new device A full example for a new device using ephemeral public key `2IZoarIZe3gOMAqdSiFHSAcA15KfOasxueUUNwJI7Ws` (base64 -encoded) at rendezvous session `https://rendezvous.lab.element.dev/e8da6355-550b-4a32-a193-1619d9830668` is as follows: +encoded) at rendezvous session ID `e8da6355-550b-4a32-a193-1619d9830668` on homeserver +`matrix.org` is as follows: (Whitespace is for readability only) ``` 4D 41 54 52 49 58 02 03 d8 86 68 6a b2 19 7b 78 0e 30 0a 9d 4a 21 47 48 07 00 d7 92 9f 39 ab 31 b9 e5 14 37 02 48 ed 6b -00 47 -68 74 74 70 73 3a 2f 2f 72 65 6e 64 65 7a 76 6f 75 73 2e 6c 61 62 2e 65 6c 65 6d 65 6e 74 2e 64 65 76 2f 65 38 64 61 36 33 35 35 2d 35 35 30 62 2d 34 61 33 32 2d 61 31 39 33 2d 31 36 31 39 64 39 38 33 30 36 36 38 +00 24 +65 38 64 61 36 33 35 35 2D 35 35 30 62 2D 34 61 33 32 2D 61 31 39 33 2D 31 36 31 39 64 39 38 33 30 36 36 38 +00 0A +6d 61 74 72 69 78 2e 6f 72 67 ``` Which looks as follows as a QR with error correction level Q: + ![Example QR for mode 0x03](images/4108-qr-mode03.png) #### Example for QR code generated on existing device A full example for an existing device using ephemeral public key `2IZoarIZe3gOMAqdSiFHSAcA15KfOasxueUUNwJI7Ws` (base64 -encoded), at rendezvous session `https://rendezvous.lab.element.dev/e8da6355-550b-4a32-a193-1619d9830668` on homeserver +encoded), at rendezvous session ID `e8da6355-550b-4a32-a193-1619d9830668` on homeserver `matrix.org` is as follows: (Whitespace is for readability only) ``` 4D 41 54 52 49 58 02 04 d8 86 68 6a b2 19 7b 78 0e 30 0a 9d 4a 21 47 48 07 00 d7 92 9f 39 ab 31 b9 e5 14 37 02 48 ed 6b -00 47 -68 74 74 70 73 3a 2f 2f 72 65 6e 64 65 7a 76 6f 75 73 2e 6c 61 62 2e 65 6c 65 6d 65 6e 74 2e 64 65 76 2f 65 38 64 61 36 33 35 35 2d 35 35 30 62 2d 34 61 33 32 2d 61 31 39 33 2d 31 36 31 39 64 39 38 33 30 36 36 38 +00 24 +65 38 64 61 36 33 35 35 2D 35 35 30 62 2D 34 61 33 32 2D 61 31 39 33 2D 31 36 31 39 64 39 38 33 30 36 36 38 00 0A 6d 61 74 72 69 78 2e 6f 72 67 ``` Which looks as follows as a QR with error correction level Q: + ![Example QR for mode 0x04](images/4108-qr-mode04.png) ### Discoverability of the capability diff --git a/proposals/images/4108-qr-mode03.png b/proposals/images/4108-qr-mode03.png index 4e1a629f17d2a711eb724b615c60a25e2ff2390c..f7c459e69d041215ce01bd7382a83d12f9e360ba 100644 GIT binary patch delta 768 zcmV+b1ONP)2dM@jiBL{Q4GJ0x0000DNk~Le00021000210RsR403#;;T9F|)e*(Kn zL_t(YiRG6;uB$K%MU5C_1{;W!ZDf`$!3GN5K-p4e*+!&n0A?9P_+QgLy*Kz@`eynN zqUf{=vAMo>iT`@g@5VdP63goCgZO3mh}7xv!EK`Q3jD;4Z(Rb><7ns9AE|%V>zZi3 zg_r8Km`BcI?YF!55fG~-lI8gxf9AF%UIVU{d|tkTS779OPWJo!ehmtI9pyA_iTq4$ z{3(e4#wX>43s*$h29sx&Z?t$1j*}f@zXm&a_cHjE8gpt0ZlHq1Px7dqZ{R5F&504{ zoM@?b(c?4F2>DbRf|Z-tW<5USRTEKJ1J3sFH0tqbEE(!z>lpIscjNdDe|Cq2NaV{i z<_@{PgArDquxiM2FFoq<9tdw9`XvM3g$>(9k56*D&r?7vu#<<2 ze=?}U!Ol#us5!#zP+K2Cf2i<7&`Xuu-4{-IFz=qG!zjv^*bL-c zj#^&+9ilHR9+u;7V0?0g03iW81&khf)MNBCc-1WKe{09&&d&yQSTY2& zM0^AV^;|!VQHL>wVd|+^m|xyKqwVyVt79=v1d82(z3Wnk&yWd$CR8@E4&Tko4SelU zCQ6Tz;??(u9`B|NvMQdy;y0f@ufsTwms$Se*-H? zL_t(oh3%I;j^sEDg;`MG%)WpDT|=3!OD5`e}CwI{^f~ia^pm2@5XnrsjEa*!86w-p6_sFzK&qGP#0G5FwUL^ zSwj3elsa`vzVNlh@y+M##vzVse?E156kZAO&E8cd=Q`ncJYP&R(JTJ0LlZ~+-`M28 zetyoSiQ{v->+a~qc6Ap=`_m^){3hz1EF~J3U~}Q^*=H-qLymSOllknuO>`Ym!xPmZ zobNLB&K~i34jP^#lEt62lq(0jdviSbw(>+c!Ac&thWhT=cF=GnyGc))f8Cu+xYq7M zk16==&K|YmaVR)PwCFc}D^J*4xVY5bGlH+4xo9}z6VVVPcu)2wvpw~1<;h=LvDoMA z$GNk2$J^(@X zPaf@!u7JLo9SRWfH4V?Pf07ezT)T>;+wtzLf+NS(KR4Hzt%%m)I28PLL>^fi=q*;U zMe1}Mk*|#jn?zTO|WY%ybxI1|CI53KDIMVdw+sbpOGd3BY#K~s4gRJ2!OG`AnKgq!y&o^s0 zHiqG9iIO!J9O(GblV)Bnn6(5anIDpLmsN17zf_Mfe6nnq*PnB2;ao6t!Xo7@kJ!>@ zPHW{T+5|g$8h)3#f6;#Zx|K6#D%1_8FZr(C?%%nwjVI_E;Tcl|L2>~$C!sUFbC%INUxyc41YwXFcFv|;=|oET;}1x2jeKsCQ}VYVpi~H zK8Ki8%;)4~$WI@?Yvn=oKRtcEllb)~Uj>(j#H|sr#c@a(M|B((gSWyWk3yLGe(6jj zN4_5A!oUyp#$_?T=BqZ2`Y)nvk}vLWPmmN1|5N`j|DF6Fc-by`AI33y00000NkvXX Hu0mjfo9?xk diff --git a/proposals/images/4108-qr-mode04.png b/proposals/images/4108-qr-mode04.png index b01ee1e3672f4a71d14c35a58647679c87c3b632..829ee0032017c28c6b73c49e032ac1e6ba982a0b 100644 GIT binary patch delta 775 zcmV+i1Ni)v2e1YqiBL{Q4GJ0x0000DNk~Le00021000210RsR403#;;T9F|)e*(fu zL_t(YiRG6u?xZ{n#f?&=g9}8;HPYouCU{}$gTt!Wn_ zgno=5cI@{&#Q%BFzl~3#B_69YFXCNui8RP@;WpE;d){#4+K@oxIGT`DNotFqYohQ7 zFV((d9(|swdOyW4k5~_27yq+o*Hk{zQsTZ#kMNnIW0c**WgG@*Q|-M#5Iu?0CUeXEJ+SUt}6ax^``hCB_m4UF{3aYd>&$cxfZH=f*lQaOSPA`SZ|Tz6FuEQ8IjChD^RZ&0dw5C!DD*a(vP8PDs+R>O67ph9JkMC(^xsiO^M$VYA5bMfP-g_OJqU z6;%ArpbR?`m>^LhLhW)$fA`LdaH+OLix8Ixfx%DgTaLNQWX}*p0=2x7WjVey`rAxV z?Sws7+-q5knZeLTxb`ZT{ryQ1z8qeb17t=+zabK4kmD2eQv2=c4o-R0Ur&=^Xw|N1 zh-UOhsmJcVQOYoUb=HkM+WI)1Ey+H>rPmAIjS?`k$LNtKIfke8e;TYA-7qD4-3yfA zo*{@O;v-a$;(8mS3}Xtbs?@G7yR%y~gB){(yY|uPa#$VMw=ZS*@_luMp;c}4(A~T| zz&%ica*qxz#j8_Aj!)f2Y7=~*KhN{+^D>O1V8{CGgK&?H%^=608M*iOXa0gA{B{xv z?lZDh7wjm)NzhMfU3-9GK^i^)7028Gt-7amDgM|<9|qwDqc#sQW6!DgCH47*A7I9? zz^lf%fk7M7<+prfxaXVI3XwpAR#@CORWkfP|E2z6{0phaYDJ-luW$eW002ovPDHLk FV1fbSeMkTR delta 877 zcmV-z1Cso(29*aPiBL{Q4GJ0x0000DNk~Le0002D0002D0RsR40BWFJ+>s$Se*-5; zL_t(oh3%Iy&a65Ng^eiE!3H8_8|kv8VFL_ofZ0;IY$H-O09}d*-{YD2?|sEWYzp(fB5jc5!N3M)0CXsgZP#5z_bz#=}#WIIP$+>lmGbr zK9??z>-Oa|G_cz|0(Zabq>JB#N??$a>@&Kn^8VguFXvdU9!%u_M6|N0=+f3O4bJcLHPX0JADh&du+(m4$?Qg$yb9V3hf&yE8k-tI3D*}W^L-xl# zy{#l_I3r^L?N&B8nn%Bk=f_8SIXB4K9!Chm_Lj|0zw~m5$xZe_e-Jk~2#Udy*YGnm zf^9R2&YGsZLm*B0wnaFD}{uZlW% zqP+%%>J%LDlE;`Qdh)`2o}ecx&KMyi(zmj?Lkva3Wgf2ZeYdA^hi+FHp|VCr7+e zPApR~e9e@f`Kpg2|EqzrNxU2}@rsw=Gr00000NkvXXu0mjf Dd`PbF