From bb48c61be82230c860164eaf99bc3db0616b0ed0 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 11:34:25 +0100 Subject: [PATCH 01/17] Proposal to allow sign in and E2EE set up via QR code --- proposals/yyyy-sign-in-with-qr.md | 472 ++++++++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 proposals/yyyy-sign-in-with-qr.md diff --git a/proposals/yyyy-sign-in-with-qr.md b/proposals/yyyy-sign-in-with-qr.md new file mode 100644 index 00000000000..ff91ec67b07 --- /dev/null +++ b/proposals/yyyy-sign-in-with-qr.md @@ -0,0 +1,472 @@ +# MSCyyyy: Protocol to use an existing Matrix client session to complete login and setup of E2EE via QR code + +This MSC proposes a method to allow an existing Matrix authenticated client/device to sign in a new device and handle +E2EE set up (mutual device verification; setup of cross-signing if used; connecting to room key backups if used). + +There are currently two use cases for this proposal: + +- allowing a user to login and setup E2EE on an additional Matrix client by means of scanning a QR code +- a mechanism to facilitate the launching of advanced E2EE aware "widgets" which are acting as full Matrix clients + +## Secure channel prerequisite + +This proposal relies on a secure "rendezvous" channel having been established between the two devices. (see dependencies +section) + +The initiation of a secure channel could be via sharing a QR code or be through some other means. + +By way of example this is what the QR for an X25519 based rendezvous via HTTP looks like in the Element Web +[prototype](https://pr9303--matrix-react-sdk.netlify.app/) where the code was generated on the new device: + +```json +{ + "rendezvous": { + "algorithm": "m.rendezvous.v1.curve25519-aes-sha256", + "key": "2IZoarIZe3gOMAqdSiFHSAcA15KfOasxueUUNwJI7Ws=", + "transport": { + "type": "http.v1", + "uri": "https://rendezvous.lab.element.dev/e8da6355-550b-4a32-a193-1619d9830668" + } + }, + "intent": "login.start" +} +``` + +This proposal should also work with a to_device based channel too. + +Furthermore it should be adaptable to work with OIDC based authentication in future. + +## Proposal + +Once a secure channel is established the following protocol can be used. The initial steps of the secure channel setup are +only included for completeness: + +```mermaid +sequenceDiagram + participant A as New device wanting to sign in + participant B as Existing device already signed in + participant HS as Homeserver +Note over A,B: Devices establish secure rendezvous and derive
confirmation code from shared key. e.g. 1234-5678-9012
The intention of the initiator (generator of the scanned code) was encoded in the scanned code + + alt Code was scanned on new device + rect rgb(240,240,240) + Note over A,B: These are from MSC3886 + B->>A: Rendezvous set up and ECDH public key encoded in QR + A->>B: New device responds with ECDH public key + end + Note over B: 1. Check compatibility of intents + alt Incompatible + B->>A: 2. {"type":"m.login.finish", "intent": "login.start"} + A->>A: Cancel rendezvous + end + else Code was scanned on existing device + rect rgb(240,240,240) + Note over A,B: These are from MSC3886 + A->>B: Rendezvous set up and ECDH public key encoded in QR + B->>A: New device responds with ECDH public key + end + Note over A: 1. Check compatibility of intents + alt Incompatible + A->>B: 2. {"type":"m.login.finish", "intent": "login.reciprocate"} + B->>B: Cancel rendezvous + end + A->>B: 3. {"type":"m.login.progress"} + end + + Note over B: 4. Determine if MSC3882 is available: + B->>+HS: POST /versions + HS-->>-B: supported features + alt no protocol available + B->>A: 5. {"type":"m.login.finish", "outcome":"unsupported"} + else + B->>A: 6. {"type":"m.login.progress", "protocols":["login_token"]} + end + + Note over A: 7. Check that suitable protocol available + A->>B: 10. {"type":"m.login.progress", "protocol": "login_token"} + + Note over A,B: 8. Confirmation code should be displayed on both devices e.g 1234-5678-9012 + + Note over B: 9. User asked to approve or deny login + + alt User declined + B->>A: 10. {"type":"m.login.finish", "outcome":"declined"} + else User approved + + B->>+HS: 11. POST /login/token + HS-->>-B: {"login_token": "abcdefghijkl", "expires_in": 30} + + B->>A: 12. {"type": "m.login.progress", "login_token": "abcdefghijkl","homeserver": "https://matrix-client.matrix.org"} + + A->>+HS: 13. POST /login {"type": "m.login.token", "login_token": "abcdefghijkl"} + HS-->>-A: {"access_token": "asdsad", "device_id": "AAABBBCCC"} + + alt no-E2EE + A->>B: 14. {"type": "m.login.finish", "outcome": "success"} + else E2EE + + Note over A: E2EE device keys generated and uploaded to HS as normal + + A->>B: 15. { "type": "m.login.progress", "outcome": "success"
"device_key": "zxcxzcxzc",
"device_id": "AAABBBCCC"} + + loop Timeout of 10 seconds + B->>B: 16. Wait for new device to come online + end + + Note over B: 17. check that device key from Homeserver vs received in 15 match + B->>B: 18a. Mark new device (AAABBBCCC) as verified locally + + alt Cross-signing active + B->>B: 18b. Sign new device + B->>HS: 18b. Upload signature + B->>A: 19a. { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef",
"master_key": } + else No cross-signing + B->>A: 19b. { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef" } + end + + Note over A: 20. Check that verifying_device_id and verifying_device_key match data from Homeserver + A->>A: 21. Mark existing device (XXXYYYZZZ) as verified locally + A->>A: 22. If master_key was received then mark as trusted + alt Cross-signing active + A->>HS: m.secret.request for MSK/USK/SSK private keys from existing device XXXYYYZZZ + HS->>B: m.secret.request + B->>HS: m.secret.send + HS->>A: m.secret.send + A->>A: Check and store received private keys locally + end + + A->>HS: m.secret.request for m.megolm_backup.v1 key + HS->>B: m.secret.request + B->>HS: m.secret.send + HS->>A: m.secret.send with key if known + A->>A: Connect to key backup + end + end +``` + +1. The scanning device determines if the intents are compatible. + +The `intent` is either: + +- `login.start` - the device/client wishes to sign in +- `login.reciprocate` - the device/client wishes to sign in another device + +2. If they are not compatible then the client sends a payload to indicate that it isn't compatible: + +```json +{ + "type": "m.login.finish", + "intent": "" +} +``` + +Both side can then clean up the rendezvous and provide feedback to the user. + +3. In the case that the new device scanned the code an empty progress payload is sent so that the the existing device +knows it can proceed + +```json +{ + "type": "m.login.progress" +} +``` + +4. The existing device determines if the homeserver has sufficient capabilites to support the request (i.e. support for MSC3882). + +5. If it doesn't then it responds with the following and closes the rendezvous: + +```json +{ + "type": "m.login.finish", + "outcome": "unsupported" +} +``` + +6. Otherwise, the existing device acknowleges the request and indicates the protocols available: + +```json +{ + "type": "m.login.progress", + "protocols": ["login_token"] +} +``` + +7. The new device can then choose whether to proceed with a protocol at this point. If so it sends: + +```json +{ + "type": "m.login.progress", + "protocol": "login_token" +} +``` + +It could decline with something like: + +```json +{ + "type": "m.login.finish", + "outcome": "unsupported" +} +``` + +8. A 12 numerical digit confirmation code derived from the shared key used by the rendezvous channel must be displayed +on both devices. + +9. On the existing device the user must be prompted to approve the new login along with the confirmation code visible. + +10. If the user declines the request: + +```json +{ + "type": "m.login.finish", + "outcome": "declined" +} +``` + +11. The existing device calls `POST /login/token` as per MSC3882 to obtain a `login_token`. n.b. If the homeserver +responds with UIA challenge then the existing device must complete UIA. + +12. The existing device then sends the login token to the new device along with the homeserver to use it with: + +```json +{ + "type": "m.login.progress", + "login_token": "abcdefghijkl", + "homeserver": "https://matrix-client.matrix.org" +} +``` + +13. New device calls `POST /login` to redeem the `login_token`. +e.g. `{ "type": "m.login.token", "login_token": }` + +New device informs existing device of outcome and if E2EE is to be setup then includes device ID and keys: + +14. No E2EE: + +```json +{ + "type": "m.login.finish", + "outcome": "success" +} +``` + +15. With E2EE: + +```json +{ + "type": "m.login.progress", + "outcome": "success", + "device_id": "AAABBBCCC", + "device_key": "zxcxzcxzc" +} +``` + +16. If doing E2EE then existing device then waits for up to X seconds for the `device_id` to become visible. + +17. If the device is visible within the time period then the existing device must first check that the `device_id` and +`device_key` match those provided by the homeserver. + +18a. Assuming they match then locally mark the device as verified. + +18b. If cross signing is in use then cross-sign the new device and upload signature to Homeserver. + +19. The existing device notified the new device that verification has been completed on its end: + +```json + "type": "m.login.finish", + "outcome": "verified", + "verifying_device_id": "XXXYYYZZZ", + "verifying_device_key": "abcdefgh" +``` + +If cross-signing is in use then the public part of the master signing key `master_key` should be included: + +```json + "type": "m.login.finish", + "outcome": "verified", + "verifying_device_id": "XXXYYYZZZ", + "verifying_device_key": "abcdefgh", + "master_key": "mmmmmmmm" +``` + +20. The new device checks that `verifying_device_id` and `verifying_device_key` match those from the Homeserver + +21. If they do match then locally mark the existing device as verified. + +22. If the `master_key` was received then mark it as trusted + +23. Request 4x secrets be gossiped from existing device and set them up as per normal verification + +### Anticipated errors + +- Neither device is already signed in +- Both devices are already signed in + +### Cancellation + +The new device could cancel the process at any time by sending: + +```json +{ + "type": "m.login.finish", + "outcome": "cancelled" +} +``` + +### OIDC variant + +It is anticipated that a variant of this would work with OIDC in future identified by a different `protocol` value. + +To be clear, it is not proposed that a OIDC protocol is defined at this time, but instead this is included here to help +get comfortable that this proposal is reasonably future proof. + +Whilst not fully thought through it could work like this: + +```mermaid +sequenceDiagram + participant A as New device
wanting to sign in + participant B as Existing device
already signed in + participant OP as OIDC Provider + participant HS as Homeserver + rect rgb(240,240,240,0.5) + Note over A,B: These steps are same as login.token flow + alt Code was scanned on new device + B->>A: Rendezvous set up and ECDH public key encoded in QR + A->>B: New device responds with ECDH public key + Note over B: 1. Check compatibility of intents + alt Incompatible + B->>A: 2. {"type":"m.login.finish", "intent": "login.start"} + A->>A: Cancel rendezvous + end + else Code was scanned on existing device + A->>B: Rendezvous set up and ECDH public key encoded in QR + B->>A: New device responds with ECDH public key + Note over A: 1. Check compatibility of intents + alt Incompatible + A->>B: 2. {"type":"m.login.finish", "intent": "login.reciprocate"} + B->>B: Cancel rendezvous + end + A->>B: 3. {"type":"m.login.progress"} + end + end + Note over B: 4. Determine if login_token is available: + B->>+HS: POST /versions + HS-->>-B: check supported features for MSC3882 + Note over B: Determine if device authorization grant is available + B->>+OP: GET /.well-known/openid-configuration + OP->>-B: 200 OK {..., "grant_types_supported": ["urn:ietf:params:oauth:grant-type:device_code", ...]} + alt no protocol available + B->>A: 5. {"type":"m.login.finish", "outcome":"unsupported"} + else + Note over B: n.b. that the homeserver is needed to determine the OIDC provider + B->>A: 6. {"type":"m.login.progress", "protocols":["login_token, "device_authorization_grant], "homeserver": "matrix-client.matrix.org"} + end + + Note over A: 7. Check that suitable protocol available + A->>B: 10. {"type":"m.login.progress", "protocol": "device_authorization_grant"} + + alt no protocol available + B->>A: {"type":"m.login.finish", "outcome":"unsupported", "homeserver": "https://matrix-client.matrix.org"} + else login_token + note over A: Continue as before + else device_authorization_grant + Note over A: Device checks that it can communicate
with the OP. Completing dynamic registration if needed + A->>+HS: GET /.well-known/matrix/client + HS-->>-A: 200 OK {..., "m.authentication": {"issuer": "id.matrix.org"}} + A->>+OP: GET /.well-known/openid-configuration + OP->>-A: 200 OK {..., "device_authorization_endpoint": "https://id.matrix.org/auth/device", ...} + Note over A: Device now knows the OP and what the endpoint is, so then attempts to start the login + A->>+OP: POST /auth/device client_id=xyz&scope=urn:matrix:api:*... + OP->>-A: 200 OK {"user_code": "123456", "verification_url_complete": "https://id.matrix.org/device/abcde", "expires_in": 120, "device_code": "XYZ", "interval": 1} + + Note over A: At this point A finally gets back to B to tell it what it wants to do: + + B->>A: {"type": "m.login.progress", "protocol": "device_authorization_grant", "device_authorization_grant": {"verification_url_complete": "https://id.matrix.org/device/abcde"}} + par + Note over A: Device shows the user_code: 1-2-3-4-5-6
and says follow instructions on other device + loop Poll for result at interval seconds. This is standard OIDC stuff: + A->>OP: POST /token client_id=xyz&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=XYZ + alt pending + OP-->>A: 400 Bad Request {"error": "authorization_pending"} + else granted + OP-->>A: 200 OK {"access_token": "...", "token_type": "Bearer", ...} + else denied + OP-->>A: 400 Bad Request {"error": "authorization_declined"} + else expired + OP-->>A: 400 Bad Request {"error": "expired_token"} + end + end + and + Note over B: Device opens verification_url_complete in native browser: + rect rgb(240,240,240,0.5) + B->>OP: GET https://id.matrix.org/device/abcde + OP->>B: consent screen including the user_code + B->>OP: POST /allow or /deny + end + Note over B: browser closed, possibly redirected back to app + end + + Note over A: Device now has an access_token and can start to talk to the homeserver + + Note over A: n.b. the device might already know the device_id due to the way OIDC works. If not then introspect: + A->>HS: GET /whoami + HS->>A: 200 OK {"device_id": "AAABBBCCC"} + + A->>B: { "type": "m.login.progress", "outcome": "success"
"device_key": "zxcxzcxzc",
"device_id": "AAABBBCCC"} + + Note over A,B: 8. Confirmation code should be displayed on both devices e.g 1234-5678-9012 + + Note over B: 9. User asked to approve or deny setup of E2EE on new device + + alt declined + Note over B: or can the OP tell the existing device the outcome? + B->>A: {"type":"m.login.finish", "outcome":"declined"} + else approved + Note over A,B: Do E2EE steps as before: (just showing comms between A and B) + + alt Cross-signing active + B->>A: { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef",
"master_key": } + else No cross-signing + B->>A: { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef" } + end + + end + end +``` + +A UX complication here is that there are two codes that the user needs to see: the rendezvous checksum; the OIDC device +authorization grant code. + +### Usage for launching a new client on a single device + +There are two scenarios in mind: + +1. Showing a "widget" within an existing Matrix client embedded as an iframe/WebView +2. "Popping out"/launching a new Matrix client from inside of an existing Matrix client + +It could be that the two are go hand-in-hand: a widget could be visible in embedded mode and a button offered to "open +in new window". When clicked a new browser (or native?) window would be opened which would be signed in and set up for +E2EE as before. + +## Potential issues + +Please also refer to the dependent MSCs. + +## Alternatives + +Please also refer to the dependent MSCs. + +## Security considerations + +Please also refer to the dependent MSCs. + +## Unstable prefix + +It probably makes sense to use an unstable protocol name like `org.matrix.mscYYYY.login_token`. + +## Dependencies + +- [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882) to obtain a `m.login.token` +- A secure rendezvous channel such as: + - [MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886) + [MSC3903](https://github.com/matrix-org/matrix-spec-proposals/pull/3903) to do X25519 over HTTP + - Or in future guest rendezvous via to_device messaging From 75f26e82cae1a21c276f6a057f76c07abce9666d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 11:35:12 +0100 Subject: [PATCH 02/17] MSC3906 --- proposals/{yyyy-sign-in-with-qr.md => 3906-sign-in-with-qr.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename proposals/{yyyy-sign-in-with-qr.md => 3906-sign-in-with-qr.md} (99%) diff --git a/proposals/yyyy-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md similarity index 99% rename from proposals/yyyy-sign-in-with-qr.md rename to proposals/3906-sign-in-with-qr.md index ff91ec67b07..6e89803ebd6 100644 --- a/proposals/yyyy-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -1,4 +1,4 @@ -# MSCyyyy: Protocol to use an existing Matrix client session to complete login and setup of E2EE via QR code +# MSC3906: Protocol to use an existing Matrix client session to complete login and setup of E2EE via QR code This MSC proposes a method to allow an existing Matrix authenticated client/device to sign in a new device and handle E2EE set up (mutual device verification; setup of cross-signing if used; connecting to room key backups if used). From cf316fdcbae8acd7c52e05f88704bfc0a784bf95 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 11:37:05 +0100 Subject: [PATCH 03/17] Spelling --- proposals/3906-sign-in-with-qr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 6e89803ebd6..2aa3b432b0b 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -171,7 +171,7 @@ knows it can proceed } ``` -4. The existing device determines if the homeserver has sufficient capabilites to support the request (i.e. support for MSC3882). +4. The existing device determines if the homeserver has sufficient capabilities to support the request (i.e. support for MSC3882). 5. If it doesn't then it responds with the following and closes the rendezvous: @@ -182,7 +182,7 @@ knows it can proceed } ``` -6. Otherwise, the existing device acknowleges the request and indicates the protocols available: +6. Otherwise, the existing device acknowledges the request and indicates the protocols available: ```json { From a15566dec31c4d185c19fdae8ed0f4f39e9ca446 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 13 Oct 2022 11:45:34 +0100 Subject: [PATCH 04/17] Fix diagram box colours --- proposals/3906-sign-in-with-qr.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 2aa3b432b0b..1859c49dbd4 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -49,7 +49,7 @@ sequenceDiagram Note over A,B: Devices establish secure rendezvous and derive
confirmation code from shared key. e.g. 1234-5678-9012
The intention of the initiator (generator of the scanned code) was encoded in the scanned code alt Code was scanned on new device - rect rgb(240,240,240) + rect rgba(240,240,240,0.5) Note over A,B: These are from MSC3886 B->>A: Rendezvous set up and ECDH public key encoded in QR A->>B: New device responds with ECDH public key @@ -60,7 +60,7 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c A->>A: Cancel rendezvous end else Code was scanned on existing device - rect rgb(240,240,240) + rect rgba(240,240,240,0.5) Note over A,B: These are from MSC3886 A->>B: Rendezvous set up and ECDH public key encoded in QR B->>A: New device responds with ECDH public key @@ -328,7 +328,7 @@ sequenceDiagram participant B as Existing device
already signed in participant OP as OIDC Provider participant HS as Homeserver - rect rgb(240,240,240,0.5) + rect rgba(240,240,240,0.5) Note over A,B: These steps are same as login.token flow alt Code was scanned on new device B->>A: Rendezvous set up and ECDH public key encoded in QR @@ -398,7 +398,7 @@ sequenceDiagram end and Note over B: Device opens verification_url_complete in native browser: - rect rgb(240,240,240,0.5) + rect rgba(240,240,240,0.5) B->>OP: GET https://id.matrix.org/device/abcde OP->>B: consent screen including the user_code B->>OP: POST /allow or /deny From caf6067282c646329acf55d1eb5a19fc20989c64 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 17 Oct 2022 16:31:53 +0100 Subject: [PATCH 05/17] Unstable protocol name --- proposals/3906-sign-in-with-qr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 1859c49dbd4..e370863bf45 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -462,7 +462,7 @@ Please also refer to the dependent MSCs. ## Unstable prefix -It probably makes sense to use an unstable protocol name like `org.matrix.mscYYYY.login_token`. +Whilst in development the unstable protocol name of `org.matrix.msc3906.login_token` should be used. ## Dependencies From 2c305cb68593bfa91129ec1547182afc3c6c3564 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 14 Feb 2023 18:13:05 +0000 Subject: [PATCH 06/17] Update MSC3903 protocol version reference --- proposals/3906-sign-in-with-qr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index e370863bf45..7c7ea045de9 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -21,7 +21,7 @@ By way of example this is what the QR for an X25519 based rendezvous via HTTP lo ```json { "rendezvous": { - "algorithm": "m.rendezvous.v1.curve25519-aes-sha256", + "algorithm": "m.rendezvous.v2.curve25519-aes-sha256", "key": "2IZoarIZe3gOMAqdSiFHSAcA15KfOasxueUUNwJI7Ws=", "transport": { "type": "http.v1", From a04a6c0c4424949f9855a1f047052949fa432d73 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Tue, 14 Feb 2023 18:23:20 +0000 Subject: [PATCH 07/17] Make reference to unstable http.v1 transport type --- proposals/3906-sign-in-with-qr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 7c7ea045de9..9f7904d4d6f 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -462,7 +462,7 @@ Please also refer to the dependent MSCs. ## Unstable prefix -Whilst in development the unstable protocol name of `org.matrix.msc3906.login_token` should be used. +Whilst in development the unstable protocol name of `org.matrix.msc3906.login_token` and the unstable transport type of `org.matrix.msc3886.http.v1` should be used. ## Dependencies From 1c1d9c1bdcfd56091e8bedb984a152ebf5b01f38 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 1 Mar 2023 15:52:53 +0000 Subject: [PATCH 08/17] Clarification on secret sharing after verification --- proposals/3906-sign-in-with-qr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 9f7904d4d6f..50568ce22e8 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -295,7 +295,7 @@ If cross-signing is in use then the public part of the master signing key `maste 22. If the `master_key` was received then mark it as trusted -23. Request 4x secrets be gossiped from existing device and set them up as per normal verification +23. The new device requests that the verifying device share the `m.cross_signing.master`, `m.cross_signing.user_signing`, `m.cross_signing.self_signing`, `m.megolm_backup.v1` secrets by sending [`m.secret.request` device events](https://spec.matrix.org/v1.6/client-server-api/#sharing) ### Anticipated errors From 1a36555dd13a08bad76adde5e27d9725e0d50834 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 1 Mar 2023 17:05:02 +0000 Subject: [PATCH 09/17] Update description of verification logic This now matches the client implementations that were reviewed in October 2022. --- proposals/3906-sign-in-with-qr.md | 59 +++++++++++++++++++------------ 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 50568ce22e8..93c56f58330 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -113,7 +113,7 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c B->>B: 16. Wait for new device to come online end - Note over B: 17. check that device key from Homeserver vs received in 15 match + Note over B: 17. check that device key from homeserver vs received in 15 match B->>B: 18a. Mark new device (AAABBBCCC) as verified locally alt Cross-signing active @@ -124,22 +124,21 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c B->>A: 19b. { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef" } end - Note over A: 20. Check that verifying_device_id and verifying_device_key match data from Homeserver - A->>A: 21. Mark existing device (XXXYYYZZZ) as verified locally - A->>A: 22. If master_key was received then mark as trusted - alt Cross-signing active - A->>HS: m.secret.request for MSK/USK/SSK private keys from existing device XXXYYYZZZ + Note over A: 20. Check that verifying_device_id and verifying_device_key match data from homeserver. If no match then abort + A->>A: 21. If master_key was received then mark as trusted + alt `master_key` was received + Note over A: 21a. Check that it matches the master key
received from the homeserver. If it does not match then abort the process reporting a security error to the user. + A->>A: 21b. Mark master key as trusted + end + A->>A: 22. Mark existing device (XXXYYYZZZ) as verified locally + + A->>HS: m.secret.requests for MSK/USK/SSK/backup secrets from existing device XXXYYYZZZ + loop HS->>B: m.secret.request B->>HS: m.secret.send HS->>A: m.secret.send - A->>A: Check and store received private keys locally + A->>A: Check and store received secret locally end - - A->>HS: m.secret.request for m.megolm_backup.v1 key - HS->>B: m.secret.request - B->>HS: m.secret.send - HS->>A: m.secret.send with key if known - A->>A: Connect to key backup end end ``` @@ -263,14 +262,18 @@ New device informs existing device of outcome and if E2EE is to be setup then in 16. If doing E2EE then existing device then waits for up to X seconds for the `device_id` to become visible. -17. If the device is visible within the time period then the existing device must first check that the `device_id` and -`device_key` match those provided by the homeserver. +17. If the device is visible within the time period then the existing device +must first check that the `device_id` and `device_key` match those provided by +the homeserver. If they do not match then abort the process reporting a security +error to the user. -18a. Assuming they match then locally mark the device as verified. +18a. Mark the new device as locally verified on existing device -18b. If cross signing is in use then cross-sign the new device and upload signature to Homeserver. +18b. If cross-signing is in use then cross-sign the new device and upload +signature to homeserver. -19. The existing device notified the new device that verification has been completed on its end: +19. The existing device notified the new device that verification has been +completed on its end: ```json "type": "m.login.finish", @@ -289,13 +292,23 @@ If cross-signing is in use then the public part of the master signing key `maste "master_key": "mmmmmmmm" ``` -20. The new device checks that `verifying_device_id` and `verifying_device_key` match those from the Homeserver +20. The new device checks that `verifying_device_id` and `verifying_device_key` +match those received from the homeserver. If they do not match then abort the +process reporting a security error to the user. + +21a. If the `master_key` was received then check that it matches the master key +received from the homeserver. If it does not match then abort the process +reporting a security error to the user. -21. If they do match then locally mark the existing device as verified. +21b. If it matched the new device marks the `master_key` as locally trusted. -22. If the `master_key` was received then mark it as trusted +22. Only after the above security checks, only now should the new device mark +the verifying device as locally verified. -23. The new device requests that the verifying device share the `m.cross_signing.master`, `m.cross_signing.user_signing`, `m.cross_signing.self_signing`, `m.megolm_backup.v1` secrets by sending [`m.secret.request` device events](https://spec.matrix.org/v1.6/client-server-api/#sharing) +23. The new device requests that the verifying device share the +`m.cross_signing.master`, `m.cross_signing.user_signing`, +`m.cross_signing.self_signing`, `m.megolm_backup.v1` secrets by sending +[`m.secret.request` device events](https://spec.matrix.org/v1.6/client-server-api/#sharing) ### Anticipated errors @@ -327,7 +340,7 @@ sequenceDiagram participant A as New device
wanting to sign in participant B as Existing device
already signed in participant OP as OIDC Provider - participant HS as Homeserver + participant HS as rect rgba(240,240,240,0.5) Note over A,B: These steps are same as login.token flow alt Code was scanned on new device From 75ea5c54ac4381781dc19a34ae22a2c283344b5d Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 1 Mar 2023 17:10:21 +0000 Subject: [PATCH 10/17] Line length --- proposals/3906-sign-in-with-qr.md | 100 ++++++++++++++++++------------ 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 93c56f58330..13718d8ea1d 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -1,22 +1,28 @@ # MSC3906: Protocol to use an existing Matrix client session to complete login and setup of E2EE via QR code -This MSC proposes a method to allow an existing Matrix authenticated client/device to sign in a new device and handle -E2EE set up (mutual device verification; setup of cross-signing if used; connecting to room key backups if used). +This MSC proposes a method to allow an existing Matrix authenticated +client/device to sign in a new device and handle E2EE set up (mutual device +verification; setup of cross-signing if used; connecting to room key backups if used). There are currently two use cases for this proposal: -- allowing a user to login and setup E2EE on an additional Matrix client by means of scanning a QR code -- a mechanism to facilitate the launching of advanced E2EE aware "widgets" which are acting as full Matrix clients +- allowing a user to login and setup E2EE on an additional Matrix client by means +of scanning a QR code +- a mechanism to facilitate the launching of advanced E2EE aware "widgets" which +are acting as full Matrix clients ## Secure channel prerequisite -This proposal relies on a secure "rendezvous" channel having been established between the two devices. (see dependencies -section) +This proposal relies on a secure "rendezvous" channel having been established +between the two devices. (see dependencies section) -The initiation of a secure channel could be via sharing a QR code or be through some other means. +The initiation of a secure channel could be via sharing a QR code or be through +some other means. -By way of example this is what the QR for an X25519 based rendezvous via HTTP looks like in the Element Web -[prototype](https://pr9303--matrix-react-sdk.netlify.app/) where the code was generated on the new device: +By way of example this is what the QR for an X25519 based rendezvous via HTTP +looks like in the Element Web +[prototype](https://pr9303--matrix-react-sdk.netlify.app/) where the code was +generated on the new device: ```json { @@ -38,8 +44,8 @@ Furthermore it should be adaptable to work with OIDC based authentication in fut ## Proposal -Once a secure channel is established the following protocol can be used. The initial steps of the secure channel setup are -only included for completeness: +Once a secure channel is established the following protocol can be used. The +initial steps of the secure channel setup are only included for completeness: ```mermaid sequenceDiagram @@ -150,7 +156,8 @@ The `intent` is either: - `login.start` - the device/client wishes to sign in - `login.reciprocate` - the device/client wishes to sign in another device -2. If they are not compatible then the client sends a payload to indicate that it isn't compatible: +2. If they are not compatible then the client sends a payload to indicate that +it isn't compatible: ```json { @@ -161,8 +168,8 @@ The `intent` is either: Both side can then clean up the rendezvous and provide feedback to the user. -3. In the case that the new device scanned the code an empty progress payload is sent so that the the existing device -knows it can proceed +3. In the case that the new device scanned the code an empty progress payload +is sent so that the the existing device knows it can proceed: ```json { @@ -170,7 +177,8 @@ knows it can proceed } ``` -4. The existing device determines if the homeserver has sufficient capabilities to support the request (i.e. support for MSC3882). +4. The existing device determines if the homeserver has sufficient capabilities +to support the request (i.e. support for MSC3882). 5. If it doesn't then it responds with the following and closes the rendezvous: @@ -181,7 +189,8 @@ knows it can proceed } ``` -6. Otherwise, the existing device acknowledges the request and indicates the protocols available: +6. Otherwise, the existing device acknowledges the request and indicates the +protocols available: ```json { @@ -190,7 +199,8 @@ knows it can proceed } ``` -7. The new device can then choose whether to proceed with a protocol at this point. If so it sends: +7. The new device can then choose whether to proceed with a protocol at this +point. If so it sends: ```json { @@ -208,10 +218,11 @@ It could decline with something like: } ``` -8. A 12 numerical digit confirmation code derived from the shared key used by the rendezvous channel must be displayed -on both devices. +8. A 12 numerical digit confirmation code derived from the shared key used by +the rendezvous channel must be displayed on both devices. -9. On the existing device the user must be prompted to approve the new login along with the confirmation code visible. +9. On the existing device the user must be prompted to approve the new login +along with the confirmation code visible. 10. If the user declines the request: @@ -222,10 +233,12 @@ on both devices. } ``` -11. The existing device calls `POST /login/token` as per MSC3882 to obtain a `login_token`. n.b. If the homeserver -responds with UIA challenge then the existing device must complete UIA. +11. The existing device calls `POST /login/token` as per MSC3882 to obtain a +`login_token`. n.b. If the homeserver responds with UIA challenge then the +existing device must complete UIA. -12. The existing device then sends the login token to the new device along with the homeserver to use it with: +12. The existing device then sends the login token to the new device along with +the homeserver to use it with: ```json { @@ -238,7 +251,8 @@ responds with UIA challenge then the existing device must complete UIA. 13. New device calls `POST /login` to redeem the `login_token`. e.g. `{ "type": "m.login.token", "login_token": }` -New device informs existing device of outcome and if E2EE is to be setup then includes device ID and keys: +New device informs existing device of outcome and if E2EE is to be setup then +includes device ID and keys: 14. No E2EE: @@ -260,7 +274,8 @@ New device informs existing device of outcome and if E2EE is to be setup then in } ``` -16. If doing E2EE then existing device then waits for up to X seconds for the `device_id` to become visible. +16. If doing E2EE then existing device then waits for up to X seconds for the +`device_id` to become visible. 17. If the device is visible within the time period then the existing device must first check that the `device_id` and `device_key` match those provided by @@ -282,7 +297,8 @@ completed on its end: "verifying_device_key": "abcdefgh" ``` -If cross-signing is in use then the public part of the master signing key `master_key` should be included: +If cross-signing is in use then the public part of the master signing key +`master_key` should be included: ```json "type": "m.login.finish", @@ -328,10 +344,12 @@ The new device could cancel the process at any time by sending: ### OIDC variant -It is anticipated that a variant of this would work with OIDC in future identified by a different `protocol` value. +It is anticipated that a variant of this would work with OIDC in future +identified by a different `protocol` value. -To be clear, it is not proposed that a OIDC protocol is defined at this time, but instead this is included here to help -get comfortable that this proposal is reasonably future proof. +To be clear, it is not proposed that a OIDC protocol is defined at this time, +but instead this is included here to help get comfortable that this proposal is +reasonably future proof. Whilst not fully thought through it could work like this: @@ -447,8 +465,8 @@ sequenceDiagram end ``` -A UX complication here is that there are two codes that the user needs to see: the rendezvous checksum; the OIDC device -authorization grant code. +A UX complication here is that there are two codes that the user needs to see: +the rendezvous checksum; the OIDC device authorization grant code. ### Usage for launching a new client on a single device @@ -457,9 +475,10 @@ There are two scenarios in mind: 1. Showing a "widget" within an existing Matrix client embedded as an iframe/WebView 2. "Popping out"/launching a new Matrix client from inside of an existing Matrix client -It could be that the two are go hand-in-hand: a widget could be visible in embedded mode and a button offered to "open -in new window". When clicked a new browser (or native?) window would be opened which would be signed in and set up for -E2EE as before. +It could be that the two are go hand-in-hand: a widget could be visible in +embedded mode and a button offered to "open in new window". When clicked a new +browser (or native?) window would be opened which would be signed in and set up +for E2EE as before. ## Potential issues @@ -475,11 +494,16 @@ Please also refer to the dependent MSCs. ## Unstable prefix -Whilst in development the unstable protocol name of `org.matrix.msc3906.login_token` and the unstable transport type of `org.matrix.msc3886.http.v1` should be used. +Whilst in development the unstable protocol name of +`org.matrix.msc3906.login_token` and the unstable transport type of +`org.matrix.msc3886.http.v1` should be used. ## Dependencies -- [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882) to obtain a `m.login.token` +- [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882) to +obtain a `m.login.token` - A secure rendezvous channel such as: - - [MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886) + [MSC3903](https://github.com/matrix-org/matrix-spec-proposals/pull/3903) to do X25519 over HTTP - - Or in future guest rendezvous via to_device messaging + - [MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886) + +[MSC3903](https://github.com/matrix-org/matrix-spec-proposals/pull/3903) to do +X25519 over HTTP + - Or in future a guest rendezvous via to_device messaging From 87b0d7581b828b8cc99fe3760cd71728fe57f5a1 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 1 Mar 2023 17:15:23 +0000 Subject: [PATCH 11/17] White space --- proposals/3906-sign-in-with-qr.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 13718d8ea1d..a081db45c5f 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -274,7 +274,7 @@ includes device ID and keys: } ``` -16. If doing E2EE then existing device then waits for up to X seconds for the +16. If doing E2EE then existing device then waits for up to X seconds for the `device_id` to become visible. 17. If the device is visible within the time period then the existing device @@ -348,7 +348,7 @@ It is anticipated that a variant of this would work with OIDC in future identified by a different `protocol` value. To be clear, it is not proposed that a OIDC protocol is defined at this time, -but instead this is included here to help get comfortable that this proposal is +but instead this is included here to help get comfortable that this proposal is reasonably future proof. Whilst not fully thought through it could work like this: @@ -473,7 +473,8 @@ the rendezvous checksum; the OIDC device authorization grant code. There are two scenarios in mind: 1. Showing a "widget" within an existing Matrix client embedded as an iframe/WebView -2. "Popping out"/launching a new Matrix client from inside of an existing Matrix client +2. "Popping out"/launching a new Matrix client from inside of an existing Matrix +client It could be that the two are go hand-in-hand: a widget could be visible in embedded mode and a button offered to "open in new window". When clicked a new From 35debfe998c8ce4801dc097a40ec7fd7f2911583 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 1 Mar 2023 17:58:15 +0000 Subject: [PATCH 12/17] Define v2 of proposal incorporating review feedback de-duplicate payload types finish=>failure+reason, declined add flow field to specify algorithm --- proposals/3906-sign-in-with-qr.md | 123 +++++++++++++++++------------- 1 file changed, 70 insertions(+), 53 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index a081db45c5f..7d7c7faf9ea 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -34,18 +34,35 @@ generated on the new device: "uri": "https://rendezvous.lab.element.dev/e8da6355-550b-4a32-a193-1619d9830668" } }, + "flow": "m.setup.additional_device.v2", "intent": "login.start" } ``` -This proposal should also work with a to_device based channel too. +This proposal should also work with a to_device based transport channel too. Furthermore it should be adaptable to work with OIDC based authentication in future. +The purpose of the `flow` field is to allow for future extensions such as updated +flow semantics or other flows entirely. + ## Proposal -Once a secure channel is established the following protocol can be used. The -initial steps of the secure channel setup are only included for completeness: +This proposal defines the `m.setup.additional_device.v2` flow that is to be +used once a secure channel has been established. + +The following `intent` values are defined: + +- `login.start` - a device with this intent is a new device that wishes to be +set up +- `login.reciprocate` - a device with this intent is already set up and is able +to facilitate set up of a new device + +The the intents to be compatible one device must have the `login.start` intent +and the other device must have the `login.reciprocate` intent. + + +The initial steps of the secure channel setup are only included for completeness: ```mermaid sequenceDiagram @@ -60,10 +77,10 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c B->>A: Rendezvous set up and ECDH public key encoded in QR A->>B: New device responds with ECDH public key end - Note over B: 1. Check compatibility of intents + Note over A: 1. Check compatibility of intents alt Incompatible - B->>A: 2. {"type":"m.login.finish", "intent": "login.start"} - A->>A: Cancel rendezvous + A->>B: 2. {"type":"m.login.failure", "reason": "incompatible_intent", "intent": "login.start"} + B->>B: Cancel rendezvous end else Code was scanned on existing device rect rgba(240,240,240,0.5) @@ -71,10 +88,10 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c A->>B: Rendezvous set up and ECDH public key encoded in QR B->>A: New device responds with ECDH public key end - Note over A: 1. Check compatibility of intents + Note over B: 1. Check compatibility of intents alt Incompatible - A->>B: 2. {"type":"m.login.finish", "intent": "login.reciprocate"} - B->>B: Cancel rendezvous + B->>A: 2. {"type":"m.login.failure", "reason": "incompatible_intent", "intent": "login.reciprocate"} + A->>A: Cancel rendezvous end A->>B: 3. {"type":"m.login.progress"} end @@ -83,37 +100,37 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c B->>+HS: POST /versions HS-->>-B: supported features alt no protocol available - B->>A: 5. {"type":"m.login.finish", "outcome":"unsupported"} + B->>A: 5. {"type":"m.login.failure", "reason":"unsupported"} else - B->>A: 6. {"type":"m.login.progress", "protocols":["login_token"]} + B->>A: 6. {"type":"m.login.protocols", "protocols":["login_token"]} end Note over A: 7. Check that suitable protocol available - A->>B: 10. {"type":"m.login.progress", "protocol": "login_token"} + A->>B: 10. {"type":"m.login.protocol", "protocol": "login_token"} Note over A,B: 8. Confirmation code should be displayed on both devices e.g 1234-5678-9012 Note over B: 9. User asked to approve or deny login alt User declined - B->>A: 10. {"type":"m.login.finish", "outcome":"declined"} + B->>A: 10. {"type":"m.login.declined"} else User approved B->>+HS: 11. POST /login/token HS-->>-B: {"login_token": "abcdefghijkl", "expires_in": 30} - B->>A: 12. {"type": "m.login.progress", "login_token": "abcdefghijkl","homeserver": "https://matrix-client.matrix.org"} + B->>A: 12. {"type": "m.login.approved", "login_token": "abcdefghijkl","homeserver": "https://matrix-client.matrix.org"} A->>+HS: 13. POST /login {"type": "m.login.token", "login_token": "abcdefghijkl"} HS-->>-A: {"access_token": "asdsad", "device_id": "AAABBBCCC"} alt no-E2EE - A->>B: 14. {"type": "m.login.finish", "outcome": "success"} + A->>B: 14. {"type": "m.login.success"} else E2EE Note over A: E2EE device keys generated and uploaded to HS as normal - A->>B: 15. { "type": "m.login.progress", "outcome": "success"
"device_key": "zxcxzcxzc",
"device_id": "AAABBBCCC"} + A->>B: 15. { "type": "m.login.success",
"device_key": "zxcxzcxzc",
"device_id": "AAABBBCCC"} loop Timeout of 10 seconds B->>B: 16. Wait for new device to come online @@ -125,9 +142,9 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c alt Cross-signing active B->>B: 18b. Sign new device B->>HS: 18b. Upload signature - B->>A: 19a. { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef",
"master_key": } + B->>A: 19a. { "type": "m.login.verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef",
"master_key": } else No cross-signing - B->>A: 19b. { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef" } + B->>A: 19b. { "type": "m.login.verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef" } end Note over A: 20. Check that verifying_device_id and verifying_device_key match data from homeserver. If no match then abort @@ -161,7 +178,8 @@ it isn't compatible: ```json { - "type": "m.login.finish", + "type": "m.login.failure", + "reason": "incompatible_intent", "intent": "" } ``` @@ -184,8 +202,8 @@ to support the request (i.e. support for MSC3882). ```json { - "type": "m.login.finish", - "outcome": "unsupported" + "type": "m.login.failure", + "reason": "unsupported" } ``` @@ -194,7 +212,7 @@ protocols available: ```json { - "type": "m.login.progress", + "type": "m.login.protocols", "protocols": ["login_token"] } ``` @@ -204,7 +222,7 @@ point. If so it sends: ```json { - "type": "m.login.progress", + "type": "m.login.protocol", "protocol": "login_token" } ``` @@ -213,8 +231,8 @@ It could decline with something like: ```json { - "type": "m.login.finish", - "outcome": "unsupported" + "type": "m.login.failure", + "reason": "unsupported" } ``` @@ -228,8 +246,7 @@ along with the confirmation code visible. ```json { - "type": "m.login.finish", - "outcome": "declined" + "type": "m.login.declined", } ``` @@ -242,7 +259,7 @@ the homeserver to use it with: ```json { - "type": "m.login.progress", + "type": "m.login.approved", "login_token": "abcdefghijkl", "homeserver": "https://matrix-client.matrix.org" } @@ -258,8 +275,7 @@ includes device ID and keys: ```json { - "type": "m.login.finish", - "outcome": "success" + "type": "m.login.success", } ``` @@ -267,8 +283,7 @@ includes device ID and keys: ```json { - "type": "m.login.progress", - "outcome": "success", + "type": "m.login.success", "device_id": "AAABBBCCC", "device_key": "zxcxzcxzc" } @@ -291,8 +306,7 @@ signature to homeserver. completed on its end: ```json - "type": "m.login.finish", - "outcome": "verified", + "type": "m.login.verified", "verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdefgh" ``` @@ -301,8 +315,7 @@ If cross-signing is in use then the public part of the master signing key `master_key` should be included: ```json - "type": "m.login.finish", - "outcome": "verified", + "type": "m.login.verified", "verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdefgh", "master_key": "mmmmmmmm" @@ -337,8 +350,8 @@ The new device could cancel the process at any time by sending: ```json { - "type": "m.login.finish", - "outcome": "cancelled" + "type": "m.login.failure", + "reason": "cancelled" } ``` @@ -366,7 +379,7 @@ sequenceDiagram A->>B: New device responds with ECDH public key Note over B: 1. Check compatibility of intents alt Incompatible - B->>A: 2. {"type":"m.login.finish", "intent": "login.start"} + B->>A: 2. {"type":"m.login.failure", "reason": "incompatible_intent", "intent": "login.start"} A->>A: Cancel rendezvous end else Code was scanned on existing device @@ -374,7 +387,7 @@ sequenceDiagram B->>A: New device responds with ECDH public key Note over A: 1. Check compatibility of intents alt Incompatible - A->>B: 2. {"type":"m.login.finish", "intent": "login.reciprocate"} + A->>B: 2. {"type":"m.login.failure", "reason": "incompatible_intent", "intent": "login.reciprocate"} B->>B: Cancel rendezvous end A->>B: 3. {"type":"m.login.progress"} @@ -387,17 +400,15 @@ sequenceDiagram B->>+OP: GET /.well-known/openid-configuration OP->>-B: 200 OK {..., "grant_types_supported": ["urn:ietf:params:oauth:grant-type:device_code", ...]} alt no protocol available - B->>A: 5. {"type":"m.login.finish", "outcome":"unsupported"} + B->>A: 5. {"type":"m.login.failure", "reason":"unsupported"} else Note over B: n.b. that the homeserver is needed to determine the OIDC provider - B->>A: 6. {"type":"m.login.progress", "protocols":["login_token, "device_authorization_grant], "homeserver": "matrix-client.matrix.org"} + B->>A: 6. {"type":"m.login.protocols", "protocols":["login_token, "device_authorization_grant], "homeserver": "matrix-client.matrix.org"} end Note over A: 7. Check that suitable protocol available - A->>B: 10. {"type":"m.login.progress", "protocol": "device_authorization_grant"} - alt no protocol available - B->>A: {"type":"m.login.finish", "outcome":"unsupported", "homeserver": "https://matrix-client.matrix.org"} + B->>A: {"type":"m.login.failure", "reason":"unsupported", "homeserver": "https://matrix-client.matrix.org"} else login_token note over A: Continue as before else device_authorization_grant @@ -412,7 +423,7 @@ sequenceDiagram Note over A: At this point A finally gets back to B to tell it what it wants to do: - B->>A: {"type": "m.login.progress", "protocol": "device_authorization_grant", "device_authorization_grant": {"verification_url_complete": "https://id.matrix.org/device/abcde"}} + B->>A: {"type": "m.login.protocol", "protocol": "device_authorization_grant", "device_authorization_grant": {"verification_url_complete": "https://id.matrix.org/device/abcde"}} par Note over A: Device shows the user_code: 1-2-3-4-5-6
and says follow instructions on other device loop Poll for result at interval seconds. This is standard OIDC stuff: @@ -443,7 +454,7 @@ sequenceDiagram A->>HS: GET /whoami HS->>A: 200 OK {"device_id": "AAABBBCCC"} - A->>B: { "type": "m.login.progress", "outcome": "success"
"device_key": "zxcxzcxzc",
"device_id": "AAABBBCCC"} + A->>B: { "type": "m.login.success",
"device_key": "zxcxzcxzc",
"device_id": "AAABBBCCC"} Note over A,B: 8. Confirmation code should be displayed on both devices e.g 1234-5678-9012 @@ -451,14 +462,14 @@ sequenceDiagram alt declined Note over B: or can the OP tell the existing device the outcome? - B->>A: {"type":"m.login.finish", "outcome":"declined"} + B->>A: {"type":"m.login.declined"} else approved Note over A,B: Do E2EE steps as before: (just showing comms between A and B) alt Cross-signing active - B->>A: { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef",
"master_key": } + B->>A: { "type": "m.login.verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef",
"master_key": } else No cross-signing - B->>A: { "type": "m.login.finish", "outcome": "verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef" } + B->>A: { "type": "m.login.verified",
"verifying_device_id": "XXXYYYZZZ", "verifying_device_key": "abcdef" } end end @@ -495,9 +506,15 @@ Please also refer to the dependent MSCs. ## Unstable prefix -Whilst in development the unstable protocol name of -`org.matrix.msc3906.login_token` and the unstable transport type of -`org.matrix.msc3886.http.v1` should be used. +Whilst in development the following unstable names should be used: + +- `org.matrix.msc3906.setup.additional_device.v2` for the +`m.setup.additional_device.v2` flow +- `org.matrix.msc3906.login_token` for the `login_token` login protocol +- `org.matrix.msc3886.http.v1` for the `http.v1` transport type + +n.b. a previous version of this spec did not include the `flow` field and may be +referred to as `v1` in early implementations. ## Dependencies From c7906ba1df3c9598362709b79b7d1ab548729814 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 2 Mar 2023 09:50:15 +0000 Subject: [PATCH 13/17] Add note about doing server side support check ahead of time --- proposals/3906-sign-in-with-qr.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 7d7c7faf9ea..146f22581e1 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -196,7 +196,8 @@ is sent so that the the existing device knows it can proceed: ``` 4. The existing device determines if the homeserver has sufficient capabilities -to support the request (i.e. support for MSC3882). +to support the request (i.e. support for MSC3882). To present the best UX it is recommended +that the client checks the capabilities before offering the ability to generate or scan a QR code. 5. If it doesn't then it responds with the following and closes the rendezvous: From 3b48ed182efbccc8a659b93602b894c6b2706e87 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Thu, 9 Mar 2023 22:50:54 +0000 Subject: [PATCH 14/17] Apply suggestions from code review Co-authored-by: Hubert Chathi --- proposals/3906-sign-in-with-qr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 146f22581e1..1fda3350ae4 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -58,7 +58,7 @@ set up - `login.reciprocate` - a device with this intent is already set up and is able to facilitate set up of a new device -The the intents to be compatible one device must have the `login.start` intent +For the intents to be compatible one device must have the `login.start` intent and the other device must have the `login.reciprocate` intent. @@ -267,7 +267,7 @@ the homeserver to use it with: ``` 13. New device calls `POST /login` to redeem the `login_token`. -e.g. `{ "type": "m.login.token", "login_token": }` +e.g. `{ "type": "m.login.token", "token": }` New device informs existing device of outcome and if E2EE is to be setup then includes device ID and keys: From 4eeaccdb3c8c3cc3177621c9e116f7006e273e87 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 5 Apr 2023 09:56:38 -0400 Subject: [PATCH 15/17] Update proposals/3906-sign-in-with-qr.md Co-authored-by: Hubert Chathi --- proposals/3906-sign-in-with-qr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 1fda3350ae4..0de6090dca8 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -106,7 +106,7 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c end Note over A: 7. Check that suitable protocol available - A->>B: 10. {"type":"m.login.protocol", "protocol": "login_token"} + A->>B: 7. {"type":"m.login.protocol", "protocol": "login_token"} Note over A,B: 8. Confirmation code should be displayed on both devices e.g 1234-5678-9012 From d12196ff2b0dcf60d1c5c92323d33d54910fb8e9 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 5 Apr 2023 15:00:16 +0100 Subject: [PATCH 16/17] Clarifications and updates to MSC3882 --- proposals/3906-sign-in-with-qr.md | 59 ++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 0de6090dca8..9ab684b2ab2 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -86,7 +86,7 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c rect rgba(240,240,240,0.5) Note over A,B: These are from MSC3886 A->>B: Rendezvous set up and ECDH public key encoded in QR - B->>A: New device responds with ECDH public key + B->>A: Existing device responds with ECDH public key end Note over B: 1. Check compatibility of intents alt Incompatible @@ -97,15 +97,15 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c end Note over B: 4. Determine if MSC3882 is available: - B->>+HS: POST /versions - HS-->>-B: supported features + B->>+HS: GET /capabilities + HS-->>-B: supported capabilities alt no protocol available B->>A: 5. {"type":"m.login.failure", "reason":"unsupported"} - else + else send available protocols B->>A: 6. {"type":"m.login.protocols", "protocols":["login_token"]} end - Note over A: 7. Check that suitable protocol available + Note over A: Check that suitable protocol available A->>B: 7. {"type":"m.login.protocol", "protocol": "login_token"} Note over A,B: 8. Confirmation code should be displayed on both devices e.g 1234-5678-9012 @@ -116,8 +116,8 @@ Note over A,B: Devices establish secure rendezvous and derive
confirmation c B->>A: 10. {"type":"m.login.declined"} else User approved - B->>+HS: 11. POST /login/token - HS-->>-B: {"login_token": "abcdefghijkl", "expires_in": 30} + B->>+HS: 11. POST /login/get_token + HS-->>-B: {"login_token": "abcdefghijkl", "expires_in_ms": 30000} B->>A: 12. {"type": "m.login.approved", "login_token": "abcdefghijkl","homeserver": "https://matrix-client.matrix.org"} @@ -189,6 +189,8 @@ Both side can then clean up the rendezvous and provide feedback to the user. 3. In the case that the new device scanned the code an empty progress payload is sent so that the the existing device knows it can proceed: +*New device => Existing device:* + ```json { "type": "m.login.progress" @@ -201,6 +203,8 @@ that the client checks the capabilities before offering the ability to generate 5. If it doesn't then it responds with the following and closes the rendezvous: +*Existing device => New device:* + ```json { "type": "m.login.failure", @@ -211,6 +215,8 @@ that the client checks the capabilities before offering the ability to generate 6. Otherwise, the existing device acknowledges the request and indicates the protocols available: +*Existing device => New device:* + ```json { "type": "m.login.protocols", @@ -221,6 +227,8 @@ protocols available: 7. The new device can then choose whether to proceed with a protocol at this point. If so it sends: +*New device => Existing device:* + ```json { "type": "m.login.protocol", @@ -230,6 +238,8 @@ point. If so it sends: It could decline with something like: +*New device => Existing device:* + ```json { "type": "m.login.failure", @@ -245,19 +255,23 @@ along with the confirmation code visible. 10. If the user declines the request: +*Existing device => New device:* + ```json { "type": "m.login.declined", } ``` -11. The existing device calls `POST /login/token` as per MSC3882 to obtain a +11. The existing device calls `POST /login/get_token` as per MSC3882 to obtain a `login_token`. n.b. If the homeserver responds with UIA challenge then the existing device must complete UIA. 12. The existing device then sends the login token to the new device along with the homeserver to use it with: +*Existing device => New device:* + ```json { "type": "m.login.approved", @@ -274,6 +288,8 @@ includes device ID and keys: 14. No E2EE: +*New device => Existing device:* + ```json { "type": "m.login.success", @@ -282,6 +298,8 @@ includes device ID and keys: 15. With E2EE: +*New device => Existing device:* + ```json { "type": "m.login.success", @@ -290,7 +308,12 @@ includes device ID and keys: } ``` -16. If doing E2EE then existing device then waits for up to X seconds for the +Fields: + +- `device_id` is the device ID of the new device. +- `device_key` is the base64 encoded Ed25519 key of the new device. + +16. If doing E2EE then existing device then waits for up to 10 seconds for the `device_id` to become visible. 17. If the device is visible within the time period then the existing device @@ -306,6 +329,8 @@ signature to homeserver. 19. The existing device notified the new device that verification has been completed on its end: +*Existing device => New device:* + ```json "type": "m.login.verified", "verifying_device_id": "XXXYYYZZZ", @@ -315,6 +340,8 @@ completed on its end: If cross-signing is in use then the public part of the master signing key `master_key` should be included: +*Existing device => New device:* + ```json "type": "m.login.verified", "verifying_device_id": "XXXYYYZZZ", @@ -322,6 +349,12 @@ If cross-signing is in use then the public part of the master signing key "master_key": "mmmmmmmm" ``` +Fields: + +- `verifying_device_id` is the device ID for the existing device. +- `verifying_device_key` is the base64 encoded Ed25519 key of the existing device. +- `master_key` is the base64 encoded public part of the master signing key. + 20. The new device checks that `verifying_device_id` and `verifying_device_key` match those received from the homeserver. If they do not match then abort the process reporting a security error to the user. @@ -349,6 +382,8 @@ the verifying device as locally verified. The new device could cancel the process at any time by sending: +*New device => Existing device:* + ```json { "type": "m.login.failure", @@ -395,8 +430,8 @@ sequenceDiagram end end Note over B: 4. Determine if login_token is available: - B->>+HS: POST /versions - HS-->>-B: check supported features for MSC3882 + B->>+HS: GET /capabilities + HS-->>-B: check supported capabilities for MSC3882 Note over B: Determine if device authorization grant is available B->>+OP: GET /.well-known/openid-configuration OP->>-B: 200 OK {..., "grant_types_supported": ["urn:ietf:params:oauth:grant-type:device_code", ...]} @@ -420,7 +455,7 @@ sequenceDiagram OP->>-A: 200 OK {..., "device_authorization_endpoint": "https://id.matrix.org/auth/device", ...} Note over A: Device now knows the OP and what the endpoint is, so then attempts to start the login A->>+OP: POST /auth/device client_id=xyz&scope=urn:matrix:api:*... - OP->>-A: 200 OK {"user_code": "123456", "verification_url_complete": "https://id.matrix.org/device/abcde", "expires_in": 120, "device_code": "XYZ", "interval": 1} + OP->>-A: 200 OK {"user_code": "123456", "verification_url_complete": "https://id.matrix.org/device/abcde", "expires_in_ms": 120000, "device_code": "XYZ", "interval": 1} Note over A: At this point A finally gets back to B to tell it what it wants to do: From 1cdcaa92ace120e2bde78fd97c281daba7a37bf8 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 5 Apr 2023 17:00:04 +0100 Subject: [PATCH 17/17] Propose stable m.setup.addition_device flow name --- proposals/3906-sign-in-with-qr.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/proposals/3906-sign-in-with-qr.md b/proposals/3906-sign-in-with-qr.md index 9ab684b2ab2..3c845abf6cd 100644 --- a/proposals/3906-sign-in-with-qr.md +++ b/proposals/3906-sign-in-with-qr.md @@ -34,7 +34,7 @@ generated on the new device: "uri": "https://rendezvous.lab.element.dev/e8da6355-550b-4a32-a193-1619d9830668" } }, - "flow": "m.setup.additional_device.v2", + "flow": "m.setup.additional_device", "intent": "login.start" } ``` @@ -48,7 +48,7 @@ flow semantics or other flows entirely. ## Proposal -This proposal defines the `m.setup.additional_device.v2` flow that is to be +This proposal defines the `m.setup.additional_device` flow that is to be used once a secure channel has been established. The following `intent` values are defined: @@ -545,7 +545,8 @@ Please also refer to the dependent MSCs. Whilst in development the following unstable names should be used: - `org.matrix.msc3906.setup.additional_device.v2` for the -`m.setup.additional_device.v2` flow +`m.setup.additional_device` flow (the `v2` is to distinguish from an earlier +revision of the proposal) - `org.matrix.msc3906.login_token` for the `login_token` login protocol - `org.matrix.msc3886.http.v1` for the `http.v1` transport type