diff --git a/proposals/1543-qr_code_key_verification.md b/proposals/1543-qr_code_key_verification.md new file mode 100644 index 00000000..ce620d92 --- /dev/null +++ b/proposals/1543-qr_code_key_verification.md @@ -0,0 +1,297 @@ +Bi-directional Key verification using QR codes +============================================== + +Problem/Background +------------------ + +Key verification is essential in ensuring that end-to-end encrypted messages +cannot be read by unauthorized parties. Traditionally, key verification is +done by comparing long strings. To save users from the tedium of reading out +long strings, some systems allow one party to verify the other party by +scanning a QR code; by doing this twice, both parties can verify each other. +In this proposal, we present a method for both parties to verify each other by +only scanning one QR code. + +Proposal +-------- + +When Alice and Bob meet in person to verify keys, Alice will scan a QR code +generated by Bob's device. The QR code will encode both Bob's key as well as what Bob +thinks Alice's key is. When Alice scans the QR code, she will ensure that the +keys match what is expected, in which case, she relays this information to Bob, +who can then tell his device that the keys match. + +### Example flow + +1. Alice and Bob meet in person, and want to verify each other's keys. +2. Alice requests a key verification through her device by sending an + `m.key.verification.request` message (see + [MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241)), with + `m.qr_code.show.v1`, `m.qr_code.scan.v1`, and `m.reciprocate.v1` listed in + `methods`, and Bob responds with a `m.key.verification.ready` message. +3. Alice's client displays a QR code that Bob is able to scan, and an option to + scan Bob's QR code. +4. Bob's client prompts Bob to verify Alice's key. The prompt includes a QR + code that Alice can scan (if the `m.key.verification.request` message listed + `m.qr_code.scan.v1`), and an option to scan Alice's QR code (if the + `m.key.verification.request` message listed `m.qr_code.show.v1`). The QR + code encodes: + - Bob's master cross-signing public key, + - what Bob thinks Alice's master cross-signing public key is, + - a random shared secret. +5. Alice scans Bob's QR code. +6. Alice's device ensures that: + - Bob's key encoded in the QR code matches the key that she already has for + Bob, and + - Alice's cross-signing key matches the cross-signing key encoded in the QR + code. + + If any of these checks fail, Alice's device displays an error message + indicating that the code is incorrect, and sends a + `m.key.verification.cancel` message to Bob's device. + + Otherwise, at this point: + - Alice's device has now verified Bob's key, and + - Alice's device knows that Bob has the correct key for her. + + Thus for Bob to verify Alice's key, Alice needs to tell Bob that he has the + right key. +7. Alice's device displays a message saying that all is well. This message + tells Alice that she has the right key for Bob, and tells Bob that he has + the right key for Alice. +8. Alice's device sends a `m.key.verification.start` message with `method` set + to `m.reciprocate.v1` to Bob (see below). The message includes the shared + secret from the QR code. This signals to Bob's device that Alice has + scanned Bob's QR code. + + This message is merely a signal for Bob's device to proceed to the next + step, and is not used for verification purposes. +9. Upon receipt of the `m.key.verification.start` message, Bob's device ensures + that the shared secret matches. + + If the shared secret does not match, it should display an error message + indicating that an attack was attempted. (This does not affect Alice's + verification of Bob's keys.) + + If the shared secret does match, it asks Bob to confirm that Alice + has scanned the QR code. +10. Bob sees Alice's device confirm that the key matches, and presses the button + on his device to indicate that Alice's key is verified. + + Bob's verification of Alice's key hinges on Alice telling Bob the result of + her scan. Since the QR code includes what Bob thinks Alice's key is, + Alice's device can check whether Bob has the right key for her. Alice has + no motivation to lie about the result, as getting Bob to trust an incorrect + key would only affect communications between herself and Bob. Thus Alice + telling Bob that the code was scanned successfully is sufficient for Bob to + trust Alice's key, under the assumption that this communication is done + over a trusted medium (such as in-person). +11. Both devices send an `m.key.verification.done` message. + +This flow allows Alice to verify Bob's key, and Bob to verify Alice's key. +Alice verifies Bob's key because she can trust the QR code that Bob displays +for her, as this is done over a trusted medium. Bob verifies Alice's key +because Alice can trust the QR code that Bob displays, and Bob can trust Alice +to tell him the result of the verification. + +#### Self-verification + +QR codes can also be used by a user to verify their own devices. These examples +shows Alice verifying two devices, one of them (Osborne2) having cross-signing +already set up, and the other one (Dynabook) having just logged in. + +In the first example, Osborne2 scans Dynabook: + +1. Alice logs into her new Dynabook and wants other users to be able to trust + it via cross-signing, and to trust other devices via cross-signing. +2. Dynabook retrieves Alice's public cross-signing key from the server, and + displays a QR code that encodes: + - Dynabook's device key, + - what it thinks Alice's master key is, and + - a random shared secret. + + Note that in this case, the QR code does not include Alice's master key in a + `key_` parameter, since Dynabook does not know whether it is trusted + or not. +3. Osborne2 scans the QR code displayed by Dynabook. At this point, Osborne2 + knows Dynabook's device key and can sign it with the self-signing key and + upload the signature, and can trust Dynabook for sending secrets via SSSS. + It also knows that Dynabook has the correct cross-signing key. +4. Osborne2 tells Alice that the scan was successful, and sends the + `reciprocate` message containing the shared secret. +5. Upon receipt of the `reciprocate` message, Dynabook (after checking the + shared secret) confirms with Alice that she successfully scanned the QR + code. +6. Alice confirms. +7. Dynabook now knows that it can trust Alice's cross-signing keys that it + fetched from the server. + +In the second example, Dynabook scans Osborne2: + +1. Alice logs into her new Dynabook and wants other users to be able to trust + it via cross-signing, and to trust other devices via cross-signing. +2. Osborne2 notices that Dynabook is a new device. Osborne2 fetches Dynabook's + identity key and displays a QR code that encodes: + - what it thinks Dynabook's key is, + - Alice's master key, and + - a random shared secret. +3. Dynabook scans the QR code shown by Osborne2. At this point, Dynabook knows + Alice's cross-signing key, and so it can trust it to sign other devices. It + also knows that Osborne2 as the correct key for it. +4. Dynabook tells Alice that the scan is successful, and sends the + `reciprocate` message containing the shared secret. +5. Upon receipt of the `reciprocate` message, Osborne2 (after checking the + shared secret) confirms with Alice that she successfully scanned the QR + code. +6. Alice confirms. +7. Osborne2 now knows that it has the correct device key for Dynabook, and can + sign it with the self-signing key and upload the signature. Osborne2 can + also trust Dynabook for sending secrets via SSSS. + +### Verification methods + +This proposal defines three verification methods that can be used in +`m.key.verification.request` messages (see +[MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241)). + +- `m.qr_code.show.v2`: means that the sender of the + `m.key.verification.request` message can show a QR code that the recipient + can scan. If the recipient can scan the QR code, it should allow the user to + do so. This method is never sent as part of a `m.key.verification.start` + message. +- `m.qr_code.scan.v2`: means that the sender of the + `m.key.verification.request` message can scan a QR code displayed by the + recipient. If the recipient can display a QR code, it should allow the user + to display it so that the sender can scan it. This method is never sent as + part of a `m.key.verification.start` message. +- `m.reciprocate.v1`: means that the sender can participate in a reciprocal + verification, either as initiator or responder, as described in the [Message + types](#message-types) section below. + +### QR code format + +The QR codes to be displayed and scanned using this format will encode binary +strings in the general form: + +- the ASCII string "MATRIX" +- one byte indicating the QR code version (must be `0x02`) +- one byte indicating the QR code verification mode. May be one of the + following values: + - `0x00` verifying another user with cross-signing + - `0x01` self-verifying in which the current device does trust the master key + - `0x02` self-verifying in which the current device does not yet trust the + master key +- the event ID or `transaction_id` of the associated verification + request event, encoded as: + - two bytes in network byte order (big-endian) indicating the length in + bytes of the ID as a UTF-8 string + - the ID as a UTF-8 string +- the first key, as 32 bytes. The key to use depends on the mode field: + - if `0x00` or `0x01`, then the current user's own master cross-signing public key + - if `0x02`, then the current device's device key +- the second key, as 32 bytes. The key to use depends on the mode field: + - if `0x00`, then what the device thinks the other user's master + cross-signing key is + - if `0x01`, then what the device thinks the other device's device key is + - if `0x02`, then what the device thinks the user's master cross-signing key + is +- a random shared secret, as a byte string. It is suggested to use a secret + that is about 8 bytes long. Note: as we do not share the length of the + secret, and it is not a fixed size, clients will just use the remainder of + binary string as the shared secret. + +For example, if Alice displays a QR code encoding the following binary string: + +``` + "MATRIX" |ver|mode| len | event ID + 4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ... +| user's cross-signing key | other user's cross-signing key | shared secret + 00 01 02 03 04 05 06 07 ... 10 11 12 13 14 15 16 17 ... 20 21 22 23 24 25 26 27 +``` + +this indicates that Alice is verifying another user (say Bob), in response to +the request from event "$ABCD...", her cross-signing key is +`0001020304050607...` (which is "AAECAwQFBg..." in base64), she thinks that +Bob's cross-signing key is `1011121314151617...` (which is "EBESExQVFh..." in +base64), and the shared secret is `2021222324252627` (which is "ICEiIyQlJic" in +base64). + +### Message types + +#### `m.key.verification.start` + +Alice's device tells Bob's device that the QR code has been scanned. + +message contents: + +- `method`: `m.reciprocate.v1` +- `m.relates_to`: as per [key verification framework](https://github.com/matrix-org/matrix-doc/pull/2241) +- `secret`: the shared secret from the QR code, encoded using unpadded base64 + +Example: + +```json +{ + "method": "m.reciprocate.v1", + "m.relates_to": { + "rel_type": "m.reference", + "event_id": "$event_id_of_verification_request" + }, + "secret": "shared+secret" +} +``` + +Note that this message could be sent by either the sender or the recipient of +the `m.key.verification.request` message, depending on which user scanned the +QR code. + +### Cancellation + +In addition to the cancellation codes specified in [the spec for +`m.key.verification.cancel`](https://matrix.org/docs/spec/client_server/r0.5.0#m-key-verification-cancel), +the following cancellation codes may be used: + +- `m.qr_code.invalid`: The QR code is invalid (e.g. it is not a URL of the + required form) + +The verification can also be cancelled with the error codes: + +- `m.key_mismatch`: if the QR code has keys that do not match the expected + value +- `m.user_mismatch`: if the QR code is for a different user from what was expected + +Tradeoffs/Alternatives +---------------------- + +Other methods of verifying keys, which do not require scanning QR codes, are +needed for devices that are unable to scan QR codes. One such method is +[MSC1267](https://github.com/matrix-org/matrix-doc/issues/1267). Since the key +verification framework allows for multiple methods to be supported, clients can +allow users to use different methods depending on their capability. + +Rather than embedding the keys in the QR codes directly, the two clients could +perform an exchange similar to +[MSC1267](https://github.com/matrix-org/matrix-doc/issues/1267), and encoding +the Short Authentication String code in the QR code. However, this means that +the clients must exchange several messages before they can verify each other, +which would delay showing the QR codes. This proposal is also simpler to +implement. + +This proposal does not support the case of asynchronous verification, such as +printing a QR code on a business card for others to scan. That may be address +in a separate MSC. + +Security Considerations +----------------------- + +The security of verifying Alice's key depends on Bob not hitting the "Verified" +button (step 10 in the example flow) until after Alice's device indicates +success or failure. Users have a tendency to click on buttons without reading +what the screen says, but this is partially mitigated by the fact that it is +unlikely that Bob will be interacting with the device while Alice is scanning +and Alice's device will display the verification results immediately upon +scanning. Also, Bob's device will not display the button until it receives the +`m.key.verification.start` message that contains the shared secret from the QR +code, which means that an attacker would need to be physically present while +Alice and Bob verify. This issue can also be addressed by allowing Bob to +easily undo the verification if Alice's device displays an error.