mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-01-01 05:28:38 +01:00
simplify protocol by embedding Alice's key in Bob's QR code
This commit is contained in:
parent
10b6fd6c8e
commit
332b5605c1
|
|
@ -16,14 +16,10 @@ Proposal
|
|||
--------
|
||||
|
||||
When Alice and Bob meet in person to verify keys, Alice will scan a QR code
|
||||
generated by Bob's device. This easily allows Alice to verify Bob's key, but
|
||||
does not give Bob any information about Alice's key in order to verify it. We
|
||||
can add a secret key to the QR code, which Alice's device can use to MAC her
|
||||
key to send to Bob. In order to ensure that an attacker, who manages to also
|
||||
scan the QR code, is unable to send a false device key to Bob, Bob's device now
|
||||
sends to Alice's device what it thinks is her key, signed by his key. Since
|
||||
Alice has verified Bob's key via the QR code, Alice's device verifies that the
|
||||
key send by Bob matches her key, and that his signature is valid.
|
||||
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:
|
||||
|
||||
|
|
@ -40,25 +36,26 @@ Example flow:
|
|||
`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`).
|
||||
5. Alice scans Bob's QR code.
|
||||
6. Alice's device ensures that the user ID in the QR code is the same as the
|
||||
expected user ID (which it knows because it is the recipient of her
|
||||
`m.key.verification.request` message). At this point, Alice's device has
|
||||
now verified Bob's key.
|
||||
6. Alice's device ensures that:
|
||||
- the user ID in the QR code is the same as the expected user ID (which it
|
||||
knows because it is the recipient of her `m.key.verification.request`
|
||||
message),
|
||||
- Bob's keys encoded in the QR code match the keys 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.
|
||||
Otherwise, at this point, Alice's device has now verified Bob's key, and her
|
||||
device will display a message saying that all is well.
|
||||
7. Alice's device sends a `m.key.verification.start` message with `method` set
|
||||
to `m.reciprocate.v1` to Bob (see below).
|
||||
8. Bob's device fetches Alice's public key, checks it against what was received
|
||||
in the `m.key.verification.start` message, signs it, and sends it to Alice
|
||||
in a `m.key.verification.check_own_key` message (see below). Bob's device
|
||||
displays a message saying that Alice wants him to verify her key, and
|
||||
presents a button for him to press /after/ Alice's device says that things
|
||||
match.
|
||||
9. Alice's device receives the `m.key.verification.check_own_key` message,
|
||||
checks Bob's signature, and checks that the key is the same as her device
|
||||
key, as well as checking that the rest of the contents match the expected
|
||||
values. Alice's device displays whether the verification was successful or
|
||||
not.
|
||||
10. Bob sees Alice's device confirm that the key matches, and presses the button
|
||||
8. Upon receipt of the `m.key.verification.start` message, Bob's device
|
||||
presents a button for him to press /after/ he has checked that Alice's
|
||||
device says that things match.
|
||||
9. 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.
|
||||
10. Both devices send an `m.key.verification.done` message.
|
||||
|
||||
### Verification methods
|
||||
|
||||
|
|
@ -84,40 +81,38 @@ This proposal defines three verification methods that can be used in
|
|||
|
||||
The QR codes to be displayed and scanned using this format will encode URLs of
|
||||
the form:
|
||||
`https://matrix.to/#/<user-id>?request=<event-id>&action=verify&key_<keyid>=<key-in-base64>...&verification_algorithms=<algorithm>&verification_key=<random-key-in-base64>`
|
||||
`https://matrix.to/#/<user-id>?request=<event-id>&action=verify&key_<keyid>=<key-in-base64>...&verification_algorithms=<algorithm>&verification_key=<random-key-in-base64>&other_user_key=<master-key-in-base64>`
|
||||
(when `matrix:` URLs are specced, this will be used instead).
|
||||
|
||||
The `request`, `verification_algorithm`, and `verification_key` parameters are
|
||||
only present if this QR code is related to a key verification request event.
|
||||
`verification_algorithms` is a comma-separated list of hashing algorithms that
|
||||
can be used for verifying the keys of the user who scanned the QR code;
|
||||
currently, only `hmac-sha256` is defined, which is HMAC using SHA-256 as the
|
||||
hash. `verification_key` is a random single-use shared secret, with a length
|
||||
depending on the `verification_algorithm`; for `hmac-sha256`, it must be at
|
||||
least 256-bits long (43 characters when base64-encoded).
|
||||
- `request`: is the event ID of the associated verification request event.
|
||||
- `key_<key_id>`: each key that the user wants verified will have an entry of
|
||||
this form, where the value is the key in unpadded base64. The QR code should
|
||||
contain at least the user's master cross-signing key.
|
||||
- `secret`: is a random single-use shared secret in unpadded base64. It must be
|
||||
at least 256-bits long (43 characters when base64-encoded).
|
||||
- `other_user_key`: the other user's master cross-signing key, in unpadded
|
||||
base64. In other words, if Alice is displaying the QR code, this would be
|
||||
the copy of Bob's master cross-signing key that Alice has.
|
||||
|
||||
The QR codes to be displayed and scanned, which are not a part of an in-person
|
||||
verification (for example, for printing on business cards), will encode URLs of
|
||||
the form:
|
||||
`https://matrix.to/#/<user-id>?&action=verify&key_<keyid>=<key-in-base64>...`
|
||||
In this case, only the user scanning the QR code will verify the key of the
|
||||
user whose QR code was scanned; bi-directional verification is not possible.
|
||||
|
||||
### Message types
|
||||
|
||||
#### `m.key.verification.start`
|
||||
|
||||
Alice's device tells Bob's device that his key is verified, and asks it to
|
||||
verify her keys. The request is MAC'ed using the verification algorithm and
|
||||
verification key from the QR code.
|
||||
Alice's device tells Bob's device that the keys are verified. The request is
|
||||
MAC'ed using the verification algorithm and verification key from the QR code.
|
||||
|
||||
message contents:
|
||||
|
||||
- `method`: `m.reciprocate.v1`
|
||||
- `m.relates_to`: as per [key verification framework](https://github.com/matrix-org/matrix-doc/pull/2241)
|
||||
- `keys`: a map of key ID to key in unpadded base64
|
||||
- `signatures`: MAC of the message contents, formed as in [Signing
|
||||
JSON](https://matrix.org/docs/spec/appendices#signing-json), with the chosen
|
||||
verification algorithm as the signing algorithm. The key ID depends on the
|
||||
verification algorithm; for `hmac-sha256`, it is the SHA-256 hash of the
|
||||
verification key. The MAC is calculated similarly to Signed JSON:
|
||||
1. The `unsigned` and `signatures` keys are removed, and the contents are
|
||||
encoded as canonical JSON.
|
||||
2. The encoded object is then MAC'ed using the verification key according to the
|
||||
selected algorithm, and the MAC is encoded in unpadded base64.
|
||||
- `secret`: the shared secret from the QR code
|
||||
|
||||
Example:
|
||||
|
||||
|
|
@ -128,50 +123,13 @@ Example:
|
|||
"rel_type": "m.reference",
|
||||
"event_id": "!event_id_of_verification_request"
|
||||
},
|
||||
"keys": {
|
||||
"ed25519:ODRMFSSXPK": "5YaK7EA3HvtPWr+B0jXFXJ9UidyJ4I9PWpT03xCCJrY",
|
||||
},
|
||||
"signatures": {
|
||||
"@alice:example.com": {
|
||||
"hmac-sha256:key+id": "mac+of+message+in+unpadded+base64"
|
||||
}
|
||||
}
|
||||
"secret": "shared+secret"
|
||||
}
|
||||
```
|
||||
|
||||
Note that this message could be sent by either Alice or Bob. That is, it can
|
||||
be sent by either the sender or the recipient of the
|
||||
`m.key.verification.request` message.
|
||||
|
||||
#### `m.key.verification.check_own_key`
|
||||
|
||||
Tells Alice's device what Bob's device thinks her key is.
|
||||
|
||||
message contents:
|
||||
|
||||
- `m.relates_to`: as per [key verification framework](https://github.com/matrix-org/matrix-doc/pull/2241)
|
||||
- `keys`: A map of key IDs to the key that Bob's device has. Must be the same
|
||||
as the `keys` property from the `m.key.verification.start` event.
|
||||
- `signatures`: signature of the mesage contents, signed using Bob's key
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.reference",
|
||||
"event_id": "!event_id_of_verification_request"
|
||||
},
|
||||
"keys": {
|
||||
"ed25519:ODRMFSSXPK": "5YaK7EA3HvtPWr+B0jXFXJ9UidyJ4I9PWpT03xCCJrY",
|
||||
},
|
||||
"signatures": {
|
||||
"@bob:example.com": {
|
||||
"ed25519:bobs+key+id": "signature+of+message"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
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
|
||||
|
||||
|
|
@ -181,8 +139,12 @@ 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)
|
||||
- `m.invalid_signature`: The signature of the
|
||||
`m.key.verification.check_own_key` message was incorrect.
|
||||
|
||||
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
|
||||
----------------------
|
||||
|
|
@ -194,28 +156,19 @@ needed for devices that are unable to scan QR codes. One such method is
|
|||
Security Considerations
|
||||
-----------------------
|
||||
|
||||
Step 6 in the example flow is to ensure that Bob does not present a QR code
|
||||
claiming to be Carol's key. Without this check, Bob will be able to trick
|
||||
Alice into verifying a key under his control, and evesdropping on Alice's
|
||||
communications with Carol.
|
||||
The first check in Step 6 in the example flow is to ensure that Bob does not
|
||||
present a QR code claiming to be Carol's key. Without this check, Bob will be
|
||||
able to trick Alice into verifying a key under his control, and evesdropping on
|
||||
Alice's communications with Carol.
|
||||
|
||||
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. However, users have a tendency to click on buttons without reading
|
||||
what the screen says. This is partially mitigated by having Alice's device
|
||||
send her keys MAC'ed with a shared secret. But this relies on the shared
|
||||
secret actually being secret, which may not be the case if an attacker is able
|
||||
to view the QR code, which limits the possible attackers to people who are
|
||||
physically present when Alice and Bob verify. This can also be addressed by
|
||||
allowing Bob to easily undo the verification if Alice's device subsequently
|
||||
gives an error.
|
||||
|
||||
One potential attack involves an attacker preventing the
|
||||
`m.key.verification.check_own_key` message from reaching Alice, and hoping that
|
||||
Bob blindly clicks on the "Verify" button without waiting for Alice's device to
|
||||
check that the key is correct. In this case, Alice's device will not display
|
||||
an error message saying that the key is incorrect, the users may assume that the
|
||||
absence of an error message means that everything is OK. To prevent this,
|
||||
Alice's device should display an error message if it does not receive a
|
||||
`m.key.verification.check_own_key` message as a response to its
|
||||
`m.key.verification.start` message after a reasonable amount of time.
|
||||
button (step 9 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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue