|
|
|
@ -17,58 +17,41 @@ 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.
|
|
|
|
|
However, Bob's device can now send to Alice's device what it thinks is her key
|
|
|
|
|
(signed by his key, so that Alice can verify that the message actually came
|
|
|
|
|
from his device), and Alice's device can do the verification on behalf of Bob
|
|
|
|
|
and display the result.
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
Example flow 1:
|
|
|
|
|
|
|
|
|
|
1. Alice and Bob meet in person, and want to verify each other's keys.
|
|
|
|
|
2. Bob tells his device to display a QR code. Bob's device displays a
|
|
|
|
|
QR code as specified below.
|
|
|
|
|
3. Alice scans the QR code.
|
|
|
|
|
4. Alice's device ensures that the user ID in the QR code is the same as the
|
|
|
|
|
expected user ID. This can be done by prompting Alice with the user ID, or
|
|
|
|
|
can be done automatically if the device already knows what user ID to
|
|
|
|
|
expect. At this point, Alice's device has now verified Bob's key.
|
|
|
|
|
5. Alice's device sends a `m.key.verification.start` message with `method` set
|
|
|
|
|
to `m.reciprocate.v1` as a to-device message to Bob's device (using the user
|
|
|
|
|
ID and device ID from the QR code.)
|
|
|
|
|
6. Bob's device fetches Alice's public key, signs it, and sends it to Alice's
|
|
|
|
|
device in a `m.key.verification.check_own_key` to-device 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.
|
|
|
|
|
7. 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.
|
|
|
|
|
8. 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.
|
|
|
|
|
|
|
|
|
|
Example flow 2:
|
|
|
|
|
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 MSC1717).
|
|
|
|
|
3. Bob responds by sending an `m.key.verification.start` message with `method`
|
|
|
|
|
set to `m.qr_code.scan.v1` and `next_method` set to `m.reciprocate.v1`.
|
|
|
|
|
4. Bob's device displays a QR code as specified below.
|
|
|
|
|
5. Alice scans the QR code.
|
|
|
|
|
`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`.
|
|
|
|
|
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`).
|
|
|
|
|
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.
|
|
|
|
|
7. Alice's device sends a `m.key.verification.start` message with `method` set
|
|
|
|
|
to `m.reciprocate.v1` to Bob's device.
|
|
|
|
|
8. Bob's device fetches Alice's public key, signs it, and sends it to Alice's
|
|
|
|
|
device in a `m.key.verification.check_own_key` to-device 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.
|
|
|
|
|
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
|
|
|
|
@ -77,32 +60,88 @@ Example flow 2:
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
### 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.v1`: 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.v1`: 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 URLs of
|
|
|
|
|
the form:
|
|
|
|
|
`https://matrix.to/#/<user-id>?device=<device-id>&action=verify&key_<keyid>=<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>`
|
|
|
|
|
(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).
|
|
|
|
|
|
|
|
|
|
### Message types
|
|
|
|
|
|
|
|
|
|
#### `m.key.verification.start`
|
|
|
|
|
|
|
|
|
|
Begins a key verification process.
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
message contents:
|
|
|
|
|
|
|
|
|
|
- `method`: the verification method to use. For this method, this must be one of:
|
|
|
|
|
- `m.qr_code.show.v1` to request that the other device show a QR code that
|
|
|
|
|
can be scanned
|
|
|
|
|
- `m.qr_code.scan.v1` to request that the other device scan a QR code
|
|
|
|
|
- `m.reciprocate.v1` to tell the other device that its key has been verified,
|
|
|
|
|
and to request that it verify this device's key in turn
|
|
|
|
|
- `from_device`: the ID of the device that Alice is using
|
|
|
|
|
- `transaction_id`: an identifier for the transaction. Must be unique on
|
|
|
|
|
Alice's device.
|
|
|
|
|
- `next_method` (only if `method` is `m.qr_code.show.v1` or `m.qr_code.scan.v1`)
|
|
|
|
|
- `keys_ids`: (only if `method` is `m.reciprocate.v1`) array of key IDs to verify.
|
|
|
|
|
- `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.
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"method": "m.reciprocate.v1",
|
|
|
|
|
"m.relates_to": {
|
|
|
|
|
"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"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
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`
|
|
|
|
|
|
|
|
|
@ -110,16 +149,35 @@ Tells Alice's device what Bob's device thinks her key is.
|
|
|
|
|
|
|
|
|
|
message contents:
|
|
|
|
|
|
|
|
|
|
- `keys`: A map of key IDs to the key that Bob's device has
|
|
|
|
|
- `transaction_id`: the transaction ID from the `m.key.verification.start`
|
|
|
|
|
message
|
|
|
|
|
- `signatures`: signature of the keys and transaction ID, signed using Bob's
|
|
|
|
|
key
|
|
|
|
|
- `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"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Cancellation
|
|
|
|
|
|
|
|
|
|
In addition to the cancellation codes specified in MSC1717, the following
|
|
|
|
|
cancellation codes may be used:
|
|
|
|
|
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)
|
|
|
|
@ -131,36 +189,33 @@ 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). These methods
|
|
|
|
|
are not exclusive to each other.
|
|
|
|
|
[MSC1267](https://github.com/matrix-org/matrix-doc/issues/1267).
|
|
|
|
|
|
|
|
|
|
Security Considerations
|
|
|
|
|
-----------------------
|
|
|
|
|
|
|
|
|
|
Step 4 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.
|
|
|
|
|
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 until after Alice's device indicates success. However, users have a
|
|
|
|
|
tendency to click on buttons without reading what the screen says. This might
|
|
|
|
|
be addressed by:
|
|
|
|
|
|
|
|
|
|
- allowing Bob to easily undo the verification if Alice's device subsequently
|
|
|
|
|
gives an error
|
|
|
|
|
- posing Bob a dummy question that he cannot answer until after Alice's device
|
|
|
|
|
displays the check results. For example: "Does Alice's device show a cat or
|
|
|
|
|
a dog?" Alice's device will show one or the other after it has checked the
|
|
|
|
|
key received from Bob, forcing Bob to wait for the check to complete.
|
|
|
|
|
(Whether a cat or a dog is displayed could be keyed to, for example, a bit in
|
|
|
|
|
the transaction ID.)
|
|
|
|
|
- (possibly other ways)
|
|
|
|
|
|
|
|
|
|
Other Issues
|
|
|
|
|
------------
|
|
|
|
|
|
|
|
|
|
Conclusion
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
|
|
This proposal presents a method for bi-directional key verification by scanning
|
|
|
|
|
a QR code and a very simplified out-of-band verification.
|
|
|
|
|
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.
|
|
|
|
|