Spec SAS verification and the common key verification framework

Reference implementations:
* 94f664e725
* https://github.com/matrix-org/matrix-react-sdk/pull/2461
* https://github.com/matrix-org/matrix-js-sdk/pull/818
* https://github.com/matrix-org/matrix-react-sdk/pull/2596
* https://github.com/matrix-org/matrix-js-sdk/pull/837

Proposals:
* [MSC1717](https://github.com/matrix-org/matrix-doc/pull/1717)
* [MSC1267](https://github.com/matrix-org/matrix-doc/issues/1267)

No alterations to either proposal have been made intentionally here.
This commit is contained in:
Travis Ralston 2019-06-04 12:41:30 -06:00
parent 9cb60fa468
commit a3364ff357
20 changed files with 847 additions and 3 deletions

View file

@ -396,8 +396,8 @@ recommended that clients provide mechanisms by which the user can see:
Ed25519 signing key for each device, again encoded using unpadded Base64.
Alice can then meet Bob in person, or contact him via some other trusted
medium, and ask him to read out the Ed25519 key shown on his device. She
compares this with the value shown for his device on her client.
medium, and use `SAS Verification`_ or ask him to read out the Ed25519 key
shown on his device, comparing it to the one shown on Alice's device.
Device verification may reach one of several conclusions. For example:
@ -423,6 +423,327 @@ Device verification may reach one of several conclusions. For example:
decrypted by such a device. For the Olm protocol, this is documented at
https://matrix.org/git/olm/about/docs/signing.rst.
Key verification framework
~~~~~~~~~~~~~~~~~~~~~~~~~~
Verifying keys manually by reading out the Ed25519 key is not very user friendly,
and can lead to errors. In order to help mitigate errors, and to make the process
eaiser for users, some verification methods are supported by the specification.
The methods all use a common framework for negotiating the key verification.
To use this framework, Alice's client would send ``m.key.verification.request``
events to Bob's devices. All of the ``to_device`` messages sent to Bob MUST have
the same ``transaction_id`` to indicate they are part of the same request. This
allows Bob to reject the request on one device, and have it apply to all of his
devices. Similarly, it allows Bob to process the verification on one device without
having to involve all of his devices.
When Bob's device receives a ``m.key.verification.request``, it should prompt Bob
to verify keys with Alice using one of the supported methods in the request. If
Bob's device does not understand any of the methods, it should not cancel the request
as one of his other devices may support the request. Instead, Bob's device should
tell Bob that an unsupported method was used for starting key verification. The
prompt for Bob to accept/reject Alice's request (or the unsupported method prompt)
should be automatically dismissed 10 minutes after the ``timestamp`` field or 2
minutes after Bob's client receives the message, whichever comes first, if Bob
does not interact with the prompt. The prompt should additionally be hidden if
an appropriate ``m.key.verification.cancel`` message is received.
If Bob rejects the request, Bob's client must send a ``m.key.verification.cancel``
message to Alice's device. Upon receipt, Alice's device should tell her that Bob
does not want to verify her device and send ``m.key.verification.cancel`` messages
to all of Bob's devices to notify them that the request was rejected.
If Bob accepts the request, Bob's device starts the key verification process by
sending a ``m.key.verification.start`` message to Alice's device. Upon receipt
of this message, Alice's device should send a ``m.key.verification.cancel`` message
to all of Bob's other devices to indicate the process has been started. The start
message must use the same ``transaction_id`` from the original key verification
request if it is in response to the request. The start message can be sent indepdently
of any request.
Individual verification methods may add additional steps, events, and properties to
the verification messages. Event types for methods defined in this specification must
be under the ``m.key.verification`` namespace and any other event types must be namespaced
according to the Java package naming convention.
Any of Alice's or Bob's devices can cancel the key verification request or process
at any time with a ``m.key.verification.cancel`` message to all applicable devices.
This framework yields the following handshake, assuming both Alice and Bob each have
2 devices, Bob's first device accepts the key verification request, and Alice's second
device initiates the request. Note how Alice's first device is not involved in the
request or verification process.
::
+---------------+ +---------------+ +-------------+ +-------------+
| AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 |
+---------------+ +---------------+ +-------------+ +-------------+
| | | |
| | m.key.verification.request | |
| |---------------------------------->| |
| | | |
| | m.key.verification.request | |
| |-------------------------------------------------->|
| | | |
| | m.key.verification.start | |
| |<----------------------------------| |
| | | |
| | m.key.verification.cancel | |
| |-------------------------------------------------->|
| | | |
After the handshake, the verification process begins.
{{m_key_verification_request_event}}
{{m_key_verification_start_event}}
{{m_key_verification_cancel_event}}
.. _`SAS Verification`:
Short Authentication String (SAS) verification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SAS verification is a user-friendly key verification process built off the common
framework outlined above. SAS verification is intended to be a highly interactive
process for users, and as such exposes verfiication methods which are easier for
users to use.
The verification process is heavily inspired by Phil Zimmerman's ZRTP key agreement
handshake. A key part of key agreement in ZRTP is the hash commitment: the party that
begins the Diffie-Hellman key sharing sends a hash of their part of the Diffie-Hellman
exchange, and does not send their part of the Diffie-Hellman exchange until they have
received the other party's part. Thus an attacker essentially only has one attempt to
attack the Diffie-Hellman exchange, and hence we can verify fewer bits while still
achieving a high degree of security: if we verify n bits, then an attacker has a 1 in
2\ :sup:`n` chance of success. For example, if we verify 40 bits, then an attacker has
a 1 in 1,099,511,627,776 chance (or less than 1 in 1012 chance) of success. A failed
attack would result in a mismatched Short Authentication String, alerting users to the
attack.
The verification process takes place over `to-device`_ messages in two phases:
1. Key agreement phase (based on `ZRTP key agreement <https://tools.ietf.org/html/rfc6189#section-4.4.1>`_).
#. Key verification phase (based on HMAC).
The process between Alice and Bob verifying each other would be:
.. |AlicePublicKey| replace:: :math:`K_{A}^{public}`
.. |AlicePrivateKey| replace:: :math:`K_{A}^{private}`
.. |AliceCurve25519| replace:: :math:`K_{A}^{private}K_{A}^{public}`
.. |BobPublicKey| replace:: :math:`K_{B}^{public}`
.. |BobPrivateKey| replace:: :math:`K_{B}^{private}`
.. |BobCurve25519| replace:: :math:`K_{B}^{private}K_{B}^{public}`
.. |AliceBobCurve25519| replace:: :math:`K_{A}^{private}K_{B}^{public}`
.. |BobAliceCurve25519| replace:: :math:`K_{B}^{private}K_{A}^{public}`
.. |AliceBobECDH| replace:: :math:`ECDH(K_{A}^{private},K_{B}^{public})`
1. Alice and Bob establish a secure connection, likely meeting in-person. "Secure"
here means that either party cannot be impersonated, not explicit secrecy.
#. Alice and Bob communicate which devices they'd like to verify with each other.
#. Alice selects Bob's device from the device list and begins verification.
#. Alice's client ensures it has a copy of Bob's device key.
#. Alice's device sends Bob's device a ``m.key.verification.start`` message.
#. Bob's device receives the message and selects a key agreement protocol, hash
algorithm, message authentication code, and SAS method supported by Alice's
device.
#. Bob's device ensures it has a copy of Alice's device key.
#. Bob's device creates an ephemeral Curve25519 key pair (|BobCurve25519|), and
calculates the hash (using the chosen algorithm) of the public key |BobPublicKey|.
#. Bob's device replies to Alice's device with a ``m.key.verification.accept`` message.
#. Alice's device receives Bob's message and stores the commitment hash for later use.
#. Alice's device creates an ephemeral Curve25519 key pair (|AliceCurve25519|) and
replies to Bob's device with a ``m.key.verification.key``, sending only the public
key |AlicePublicKey|.
#. Bob's device receives Alice's message and replies with its own ``m.key.verification.key``
message containing its public key |BobPublicKey|.
#. Alice's device receives Bob's message and verifies the commitment hash from earlier
matches the hash of the key Bob's device just sent and the content of Alice's
``m.key.verification.start`` message.
#. Both Alice and Bob's devices perform an Elliptic-curve Diffie-Hellman (|AliceBobECDH|),
using the result as the shared secret.
#. Both Alice and Bob's devices display a SAS to their users, which is derived
from the shared key using one of the methods in this section. If multiple SAS
methods are available, clients should allow the users to select a method.
#. Alice and Bob compare the strings shown by their devices, and tell their devices if
they match or not.
#. Assuming they match, Alice and Bob's devices calculate the HMAC of their own device
and a comma-separated sorted list of of the key IDs that they wish the other user
to verify. HMAC is defined in RFC 2104, and SHA-256 as the hash function. The key for
the HMAC is different for each item and is calculated by generating 32 bytes (256 bits)
using `the key verification HKDF <#SAS-HKDF>`_.
#. Alice's device sends Bob's device a ``m.key.verification.mac`` message containing the
MAC of Alice's device keys and the MAC of her key IDs to be verified. Bob's device does
the same for Bob's device keys and key IDs concurrently with Alice.
#. When the other device receives the ``m.key.verification.mac`` message, the device
calculates the HMAC of its copies of the other device's keys given in the message,
as well as the HMAC of the comma-seperated, sorted, list of key IDs in the message.
The device compares these with the HMAC values given in the message, and if everything
matches then the device keys are verified.
The wire protocol looks like the following between Alice and Bob's devices::
+-------------+ +-----------+
| AliceDevice | | BobDevice |
+-------------+ +-----------+
| |
| m.key.verification.start |
|-------------------------------->|
| |
| m.key.verification.accept |
|<--------------------------------|
| |
| m.key.verification.key |
|-------------------------------->|
| |
| m.key.verification.key |
|<--------------------------------|
| |
| m.key.verification.mac |
|-------------------------------->|
| |
| m.key.verification.mac |
|<--------------------------------|
| |
Error and exception handling
<<<<<<<<<<<<<<<<<<<<<<<<<<<<
At any point the interactive verfication can go wrong. The following describes what
to do when an error happens:
* Alice or Bob can cancel the verification at any time. A ``m.key.verification.cancel``
message must be sent to signify the cancelation.
* The verification can time out. Clients should time out a verification that does not
complete within 5 minutes. Additionally, clients should expire a ``transaction_id``
which goes unused for 5 minutes after having last sent/received it. The client should
inform the user that the verification timed out, and send an appropriate ``m.key.verification.cancel``
message to the other device.
* When the same device attempts to intiate multiple verification attempts, cancel all
attempts with that device.
* When a device receives an unknown ``transaction_id``, it should send an appropriate
``m.key.verfication.cancel`` message to the other device indicating as such. This
does not apply for inbound ``m.key.verification.start`` or ``m.key.verification.cancel``
messages.
* If the two devices do not share a common key share, hash, HMAC, or SAS method then
the device should notify the other device with an appropriate ``m.key.verification.cancel``
message.
* If the user claims the Short Authentication Strings do not match, the device should
send an appropriate ``m.key.verification.cancel`` message to the other device.
* If the device receives a message out of sequence or that it was not expecting, it should
notify the other device with an appropriate ``m.key.verification.cancel`` message.
Verification messages specific to SAS
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Building off the common framework, the following events are involved in SAS verification.
The ``m.key.verification.cancel`` event is unchanged, however the following error codes
are used in addition to those already specified:
* ``m.unknown_method``: The devices are unable to agree on the key agreement, hash, MAC,
or SAS method.
* ``m.mismatched_commitment``: The hash commitment did not match.
* ``m.mismatched_sas``: The SAS did not match.
{{m_key_verification_start_m_sas_v1_event}}
{{m_key_verification_accept_event}}
{{m_key_verification_key_event}}
{{m_key_verification_mac_event}}
.. _`SAS-HKDF`:
HKDF calculation
<<<<<<<<<<<<<<<<
In all of the SAS methods, HKDF is as defined in RFC 5869 and uses the previously
agreed upon hash function for the hash function. The shared secret is supplied
as the input keying material. No salt is used, and the input parameter is the
concatenation of:
* The string ``MATRIX_KEY_VERIFICATION_SAS``.
* The Matrix ID of the user who sent the ``m.key.verification.start`` message.
* The Device ID of the device which sent the ``m.key.verification.start`` message.
* The Matrix ID of the user who sent the ``m.key.verification.accept`` message.
* The Device ID of the device which sent the ``m.key.verification.accept`` message.
* The ``transaction_id`` being used.
HKDF is used over the plain shared secret as it results in a harder attack
as well as more uniform data to work with.
For verification of each party's device keys, HKDF is as defined in RFC 5869 and
uses SHA-256 as the hash function. The shared secret is supplied as the input keying
material. No salt is used, and in the input parameter is the concatenation of:
* The string ``MATRIX_KEY_VERIFICATION_MAC``.
* The Matrix ID of the user whose key is being MAC-ed.
* The Device ID of the device sending the MAC.
* The Matrix ID of the other user.
* The Device ID of the device receiving the MAC.
* The ``transaction_id`` being used.
* The Key ID of the key being MAC-ed, or the string ``KEY_IDS`` if the item
being MAC-ed is the list of key IDs.
SAS method: ``decimal``
<<<<<<<<<<<<<<<<<<<<<<<
Generate 5 bytes using `HKDF <#SAS-HKDF>`_ then take sequences of 13 bits to
convert to decimal numbers (resulting in 3 numbers between 0 and 8191 inclusive
each). Add 1000 to each calculated number.
The bitwise operations to get the numbers given the 5 bytes
:math:`B_{0}, B_{1}, B_{2}, B_{3}, B_{4}` would be:
* First: :math:`(B_{0} \ll 5 | B_{1} \gg 3) + 1000`
* Second: :math:`(B_{1} \& 0x7 | B_{2} \ll 2 | B_{3} \gg 6) + 1000`
* Third: :math:`((B_{3} \& 0x3F) \ll 7 | B_{4} \gg 1) + 1000`
The digits are displayed to the user either with an appropriate separator,
such as dashes, or with the numbers on individual lines.
SAS method: ``emoji``
<<<<<<<<<<<<<<<<<<<<<
Generate 6 bytes using `HKDF <#SAS-HKDF>`_ then split the first 42 bits into
7 groups of 6 bits, similar to how one would base64 encode something. Convert
each group of 6 bits to a number and use the following table to get the corresponding
emoji:
{{sas_emoji_table}}
.. Note::
This table is available as JSON at
https://github.com/matrix-org/matrix-doc/blob/master/data-definitions/sas-emoji.json
.. admonition:: Rationale
The emoji above were chosen to:
* Be recognisable without colour.
* Be recognisable at a small size.
* Be recognisable by most cultures.
* Be distinguishable from each other.
* Easily described by a few words.
* Avoid symbols with negative connotations.
* Be likely similar across multiple platforms.
Clients SHOULD show the emoji with the descriptions from the table, or appropriate
translation of those descriptions. Client authors SHOULD collaborate to create a
common set of translations for all languages.
.. section name changed, so make sure that old links keep working
.. _key-sharing: