You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
matrix-spec-proposals/proposals/1543-qr_code_key_verificati...

9.8 KiB

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. 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.

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), 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 (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 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).

  • 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 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>?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

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: m.reciprocate.v1
  • m.relates_to: as per key verification framework
  • keys: a map of key ID to key in unpadded base64
  • signatures: MAC of the message contents, formed as in 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:

{
  "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

Tells Alice's device what Bob's device thinks her key is.

message contents:

  • m.relates_to: as per key verification framework
  • 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:

{
  "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 the spec for 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)
  • m.invalid_signature: The signature of the m.key.verification.check_own_key message was incorrect.

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.

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 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.