Merge pull request #2072 from matrix-org/travis/1.0/msc1717-msc1267-sas-verification
Spec SAS verification and the common key verification framework
This commit is contained in:
commit
4b6e2cc956
20 changed files with 850 additions and 15 deletions
1
changelogs/client_server/newsfragments/2072.feature
Normal file
1
changelogs/client_server/newsfragments/2072.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add interactive device verification, including a common framework for device verification.
|
66
data-definitions/sas-emoji.json
Normal file
66
data-definitions/sas-emoji.json
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
[
|
||||||
|
{"number": 0, "emoji": "🐶", "description": "Dog", "unicode": "U+1F436"},
|
||||||
|
{"number": 1, "emoji": "🐱", "description": "Cat", "unicode": "U+1F431"},
|
||||||
|
{"number": 2, "emoji": "🦁", "description": "Lion", "unicode": "U+1F981"},
|
||||||
|
{"number": 3, "emoji": "🐎", "description": "Horse", "unicode": "U+1F40E"},
|
||||||
|
{"number": 4, "emoji": "🦄", "description": "Unicorn", "unicode": "U+1F984"},
|
||||||
|
{"number": 5, "emoji": "🐷", "description": "Pig", "unicode": "U+1F437"},
|
||||||
|
{"number": 6, "emoji": "🐘", "description": "Elephant", "unicode": "U+1F418"},
|
||||||
|
{"number": 7, "emoji": "🐰", "description": "Rabbit", "unicode": "U+1F430"},
|
||||||
|
{"number": 8, "emoji": "🐼", "description": "Panda", "unicode": "U+1F43C"},
|
||||||
|
{"number": 9, "emoji": "🐓", "description": "Rooster", "unicode": "U+1F413"},
|
||||||
|
{"number": 10, "emoji": "🐧", "description": "Penguin", "unicode": "U+1F427"},
|
||||||
|
{"number": 11, "emoji": "🐢", "description": "Turtle", "unicode": "U+1F422"},
|
||||||
|
{"number": 12, "emoji": "🐟", "description": "Fish", "unicode": "U+1F41F"},
|
||||||
|
{"number": 13, "emoji": "🐙", "description": "Octopus", "unicode": "U+1F419"},
|
||||||
|
{"number": 14, "emoji": "🦋", "description": "Butterfly", "unicode": "U+1F98B"},
|
||||||
|
{"number": 15, "emoji": "🌷", "description": "Flower", "unicode": "U+1F337"},
|
||||||
|
{"number": 16, "emoji": "🌳", "description": "Tree", "unicode": "U+1F333"},
|
||||||
|
{"number": 17, "emoji": "🌵", "description": "Cactus", "unicode": "U+1F335"},
|
||||||
|
{"number": 18, "emoji": "🍄", "description": "Mushroom", "unicode": "U+1F344"},
|
||||||
|
{"number": 19, "emoji": "🌏", "description": "Globe", "unicode": "U+1F30F"},
|
||||||
|
{"number": 20, "emoji": "🌙", "description": "Moon", "unicode": "U+1F319"},
|
||||||
|
{"number": 21, "emoji": "☁️", "description": "Cloud", "unicode": "U+2601U+FE0F"},
|
||||||
|
{"number": 22, "emoji": "🔥", "description": "Fire", "unicode": "U+1F525"},
|
||||||
|
{"number": 23, "emoji": "🍌", "description": "Banana", "unicode": "U+1F34C"},
|
||||||
|
{"number": 24, "emoji": "🍎", "description": "Apple", "unicode": "U+1F34E"},
|
||||||
|
{"number": 25, "emoji": "🍓", "description": "Strawberry", "unicode": "U+1F353"},
|
||||||
|
{"number": 26, "emoji": "🌽", "description": "Corn", "unicode": "U+1F33D"},
|
||||||
|
{"number": 27, "emoji": "🍕", "description": "Pizza", "unicode": "U+1F355"},
|
||||||
|
{"number": 28, "emoji": "🎂", "description": "Cake", "unicode": "U+1F382"},
|
||||||
|
{"number": 29, "emoji": "❤️", "description": "Heart", "unicode": "U+2764U+FE0F"},
|
||||||
|
{"number": 30, "emoji": "😀", "description": "Smiley", "unicode": "U+1F600"},
|
||||||
|
{"number": 31, "emoji": "🤖", "description": "Robot", "unicode": "U+1F916"},
|
||||||
|
{"number": 32, "emoji": "🎩", "description": "Hat", "unicode": "U+1F3A9"},
|
||||||
|
{"number": 33, "emoji": "👓", "description": "Glasses", "unicode": "U+1F453"},
|
||||||
|
{"number": 34, "emoji": "🔧", "description": "Spanner", "unicode": "U+1F527"},
|
||||||
|
{"number": 35, "emoji": "🎅", "description": "Santa", "unicode": "U+1F385"},
|
||||||
|
{"number": 36, "emoji": "👍", "description": "Thumbs Up", "unicode": "U+1F44D"},
|
||||||
|
{"number": 37, "emoji": "☂️", "description": "Umbrella", "unicode": "U+2602U+FE0F"},
|
||||||
|
{"number": 38, "emoji": "⌛", "description": "Hourglass", "unicode": "U+231B"},
|
||||||
|
{"number": 39, "emoji": "⏰", "description": "Clock", "unicode": "U+23F0"},
|
||||||
|
{"number": 40, "emoji": "🎁", "description": "Gift", "unicode": "U+1F381"},
|
||||||
|
{"number": 41, "emoji": "💡", "description": "Light Bulb", "unicode": "U+1F4A1"},
|
||||||
|
{"number": 42, "emoji": "📕", "description": "Book", "unicode": "U+1F4D5"},
|
||||||
|
{"number": 43, "emoji": "✏️", "description": "Pencil", "unicode": "U+270FU+FE0F"},
|
||||||
|
{"number": 44, "emoji": "📎", "description": "Paperclip", "unicode": "U+1F4CE"},
|
||||||
|
{"number": 45, "emoji": "✂️", "description": "Scissors", "unicode": "U+2702U+FE0F"},
|
||||||
|
{"number": 46, "emoji": "🔒", "description": "Lock", "unicode": "U+1F512"},
|
||||||
|
{"number": 47, "emoji": "🔑", "description": "Key", "unicode": "U+1F511"},
|
||||||
|
{"number": 48, "emoji": "🔨", "description": "Hammer", "unicode": "U+1F528"},
|
||||||
|
{"number": 49, "emoji": "☎️", "description": "Telephone", "unicode": "U+260EU+FE0F"},
|
||||||
|
{"number": 50, "emoji": "🏁", "description": "Flag", "unicode": "U+1F3C1"},
|
||||||
|
{"number": 51, "emoji": "🚂", "description": "Train", "unicode": "U+1F682"},
|
||||||
|
{"number": 52, "emoji": "🚲", "description": "Bicycle", "unicode": "U+1F6B2"},
|
||||||
|
{"number": 53, "emoji": "✈️", "description": "Aeroplane", "unicode": "U+2708U+FE0F"},
|
||||||
|
{"number": 54, "emoji": "🚀", "description": "Rocket", "unicode": "U+1F680"},
|
||||||
|
{"number": 55, "emoji": "🏆", "description": "Trophy", "unicode": "U+1F3C6"},
|
||||||
|
{"number": 56, "emoji": "⚽", "description": "Ball", "unicode": "U+26BD"},
|
||||||
|
{"number": 57, "emoji": "🎸", "description": "Guitar", "unicode": "U+1F3B8"},
|
||||||
|
{"number": 58, "emoji": "🎺", "description": "Trumpet", "unicode": "U+1F3BA"},
|
||||||
|
{"number": 59, "emoji": "🔔", "description": "Bell", "unicode": "U+1F514"},
|
||||||
|
{"number": 60, "emoji": "⚓", "description": "Anchor", "unicode": "U+2693"},
|
||||||
|
{"number": 61, "emoji": "🎧", "description": "Headphones", "unicode": "U+1F3A7"},
|
||||||
|
{"number": 62, "emoji": "📁", "description": "Folder", "unicode": "U+1F4C1"},
|
||||||
|
{"number": 63, "emoji": "📌", "description": "Pin", "unicode": "U+1F4CC"}
|
||||||
|
]
|
12
event-schemas/examples/m.key.verification.accept
Normal file
12
event-schemas/examples/m.key.verification.accept
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"type": "m.key.verification.accept",
|
||||||
|
"content": {
|
||||||
|
"transaction_id": "S0meUniqueAndOpaqueString",
|
||||||
|
"method": "m.sas.v1",
|
||||||
|
"key_agreement_protocol": "curve25519",
|
||||||
|
"hash": "sha256",
|
||||||
|
"message_authentication_code": "hkdf-hmac-sha256",
|
||||||
|
"short_authentication_string": ["decimal", "emoji"],
|
||||||
|
"commitment": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
|
||||||
|
}
|
||||||
|
}
|
8
event-schemas/examples/m.key.verification.cancel
Normal file
8
event-schemas/examples/m.key.verification.cancel
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"type": "m.key.verification.cancel",
|
||||||
|
"content": {
|
||||||
|
"transaction_id": "S0meUniqueAndOpaqueString",
|
||||||
|
"code": "m.user",
|
||||||
|
"reason": "User rejected the key verification request"
|
||||||
|
}
|
||||||
|
}
|
7
event-schemas/examples/m.key.verification.key
Normal file
7
event-schemas/examples/m.key.verification.key
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "m.key.verification.key",
|
||||||
|
"content": {
|
||||||
|
"transaction_id": "S0meUniqueAndOpaqueString",
|
||||||
|
"key": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
|
||||||
|
}
|
||||||
|
}
|
10
event-schemas/examples/m.key.verification.mac
Normal file
10
event-schemas/examples/m.key.verification.mac
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"type": "m.key.verification.mac",
|
||||||
|
"content": {
|
||||||
|
"transaction_id": "S0meUniqueAndOpaqueString",
|
||||||
|
"keys": "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA",
|
||||||
|
"mac": {
|
||||||
|
"ed25519:ABCDEF": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
event-schemas/examples/m.key.verification.request
Normal file
11
event-schemas/examples/m.key.verification.request
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"type": "m.key.verification.request",
|
||||||
|
"content": {
|
||||||
|
"from_device": "AliceDevice2",
|
||||||
|
"transaction_id": "S0meUniqueAndOpaqueString",
|
||||||
|
"methods": [
|
||||||
|
"m.sas.v1"
|
||||||
|
],
|
||||||
|
"timestamp": 1559598944869
|
||||||
|
}
|
||||||
|
}
|
8
event-schemas/examples/m.key.verification.start
Normal file
8
event-schemas/examples/m.key.verification.start
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"type": "m.key.verification.start",
|
||||||
|
"content": {
|
||||||
|
"from_device": "BobDevice1",
|
||||||
|
"transaction_id": "S0meUniqueAndOpaqueString",
|
||||||
|
"method": "m.sas.v1"
|
||||||
|
}
|
||||||
|
}
|
12
event-schemas/examples/m.key.verification.start$m.sas.v1
Normal file
12
event-schemas/examples/m.key.verification.start$m.sas.v1
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"type": "m.key.verification.start",
|
||||||
|
"content": {
|
||||||
|
"from_device": "BobDevice1",
|
||||||
|
"transaction_id": "S0meUniqueAndOpaqueString",
|
||||||
|
"method": "m.sas.v1",
|
||||||
|
"key_agreement_protocols": ["curve25519"],
|
||||||
|
"hashes": ["sha256"],
|
||||||
|
"message_authentication_codes": ["hkdf-hmac-sha256"],
|
||||||
|
"short_authentication_string": ["decimal", "emoji"]
|
||||||
|
}
|
||||||
|
}
|
64
event-schemas/schema/m.key.verification.accept
Normal file
64
event-schemas/schema/m.key.verification.accept
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
---
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
Accepts a previously sent ``m.key.verification.start`` messge. Typically sent as a
|
||||||
|
`to-device`_ event.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An opaque identifier for the verification process. Must be the same as
|
||||||
|
the one used for the ``m.key.verification.start`` message.
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
enum: ["m.sas.v1"]
|
||||||
|
description: |-
|
||||||
|
The verification method to use.
|
||||||
|
key_agreement_protocol:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The key agreement protocol the device is choosing to use, out of the
|
||||||
|
options in the ``m.key.verification.start`` message.
|
||||||
|
hash:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The hash method the device is choosing to use, out of the options in
|
||||||
|
the ``m.key.verification.start`` message.
|
||||||
|
message_authentication_code:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The message authentication code the device is choosing to use, out of
|
||||||
|
the options in the ``m.key.verification.start`` message.
|
||||||
|
short_authentication_string:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
The SAS methods both devices involved in the verification process
|
||||||
|
understand. Must be a subset of the options in the ``m.key.verification.start``
|
||||||
|
message.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
enum: ["decimal", "emoji"]
|
||||||
|
commitment:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The hash (encoded as unpadded base64) of the concatenation of the device's
|
||||||
|
ephemeral public key (encoded as unpadded base64) and the canonical JSON
|
||||||
|
representation of the ``m.key.verification.start`` message.
|
||||||
|
required:
|
||||||
|
- transaction_id
|
||||||
|
- method
|
||||||
|
- key_agreement_protocol
|
||||||
|
- hash
|
||||||
|
- message_authentication_code
|
||||||
|
- short_authentication_string
|
||||||
|
- commitment
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.key.verification.accept
|
||||||
|
type: string
|
||||||
|
type: object
|
70
event-schemas/schema/m.key.verification.cancel
Normal file
70
event-schemas/schema/m.key.verification.cancel
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
---
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
Cancels a key verification process/request. Typically sent as a `to-device`_ event.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The opaque identifier for the verification process/request.
|
||||||
|
reason:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A human readable description of the ``code``. The client should only rely on this
|
||||||
|
string if it does not understand the ``code``.
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
# Note: this is not an enum because we go into detail about the different
|
||||||
|
# error codes. If we made this an enum, we'd be repeating information.
|
||||||
|
# Also, we can't put a real bulleted list in here because the HTML2RST parser
|
||||||
|
# cuts the text at weird points, breaking the list completely.
|
||||||
|
description: |-
|
||||||
|
The error code for why the process/request was cancelled by the user. Error
|
||||||
|
codes should use the Java package naming convention if not in the following
|
||||||
|
list:
|
||||||
|
|
||||||
|
``m.user``: The user cancelled the verification.
|
||||||
|
|
||||||
|
``m.timeout``: The verification process timed out. Verification processes
|
||||||
|
can define their own timeout parameters.
|
||||||
|
|
||||||
|
``m.unknown_transaction``: The device does not know about the given transaction
|
||||||
|
ID.
|
||||||
|
|
||||||
|
``m.unknown_method``: The device does not know how to handle the requested
|
||||||
|
method. This should be sent for ``m.key.verification.start`` messages and
|
||||||
|
messages defined by individual verification processes.
|
||||||
|
|
||||||
|
``m.unexpected_message``: The device received an unexpected message. Typically
|
||||||
|
raised when one of the parties is handling the verification out of order.
|
||||||
|
|
||||||
|
``m.key_mismatch``: The key was not verified.
|
||||||
|
|
||||||
|
``m.user_mismatch``: The expected user did not match the user verified.
|
||||||
|
|
||||||
|
``m.invalid_message``: The message received was invalid.
|
||||||
|
|
||||||
|
``m.accepted``: A ``m.key.verification.request`` was accepted by a different
|
||||||
|
device. The device receiving this error can ignore the verification request.
|
||||||
|
|
||||||
|
Clients should be careful to avoid error loops. For example, if a device sends
|
||||||
|
an incorrect message and the client returns ``m.invalid_message`` to which it
|
||||||
|
gets an unexpected response with ``m.unexpected_message``, the client should not
|
||||||
|
respond again with ``m.unexpected_message`` to avoid the other device potentially
|
||||||
|
sending another error response.
|
||||||
|
|
||||||
|
.. The above blank line is important for RST.
|
||||||
|
required:
|
||||||
|
- transaction_id
|
||||||
|
- code
|
||||||
|
- reason
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.key.verification.cancel
|
||||||
|
type: string
|
||||||
|
type: object
|
28
event-schemas/schema/m.key.verification.key
Normal file
28
event-schemas/schema/m.key.verification.key
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
Sends the ephemeral public key for a device to the partner device. Typically sent as a
|
||||||
|
`to-device`_ event.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An opaque identifier for the verification process. Must be the same as
|
||||||
|
the one used for the ``m.key.verification.start`` message.
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The device's ephemeral public key, encoded as unpadded base64.
|
||||||
|
required:
|
||||||
|
- transaction_id
|
||||||
|
- key
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.key.verification.key
|
||||||
|
type: string
|
||||||
|
type: object
|
38
event-schemas/schema/m.key.verification.mac
Normal file
38
event-schemas/schema/m.key.verification.mac
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
Sends the MAC of a device's key to the partner device. Typically sent as a
|
||||||
|
`to-device`_ event.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An opaque identifier for the verification process. Must be the same as
|
||||||
|
the one used for the ``m.key.verification.start`` message.
|
||||||
|
mac:
|
||||||
|
type: object
|
||||||
|
description: |-
|
||||||
|
A map of the key ID to the MAC of the key, using the algorithm in the
|
||||||
|
verification process. The MAC is encoded as unpadded base64.
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: The key's MAC, encoded as unpadded base64.
|
||||||
|
keys:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The MAC of the comma-separated, sorted, list of key IDs given in the ``mac``
|
||||||
|
property, encoded as unpadded base64.
|
||||||
|
required:
|
||||||
|
- transaction_id
|
||||||
|
- mac
|
||||||
|
- keys
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.key.verification.mac
|
||||||
|
type: string
|
||||||
|
type: object
|
43
event-schemas/schema/m.key.verification.request
Normal file
43
event-schemas/schema/m.key.verification.request
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
Requests a key verification with another user's devices. Typically sent as a
|
||||||
|
`to-device`_ event.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
from_device:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The device ID which is initiating the request.
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An opaque identifier for the verification request. Must be unique
|
||||||
|
with respect to the devices involved.
|
||||||
|
methods:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
The verification methods supported by the sender.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
timestamp:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: |-
|
||||||
|
The POSIX timestamp in milliseconds for when the request was made. If
|
||||||
|
the request is in the future by more than 5 minutes or more than 10
|
||||||
|
minutes in the past, the message should be ignored by the receiver.
|
||||||
|
required:
|
||||||
|
- from_device
|
||||||
|
- transaction_id
|
||||||
|
- methods
|
||||||
|
- timestamp
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.key.verification.request
|
||||||
|
type: string
|
||||||
|
type: object
|
39
event-schemas/schema/m.key.verification.start
Normal file
39
event-schemas/schema/m.key.verification.start
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
Begins a key verification process. Typically sent as a `to-device`_ event.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
from_device:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The device ID which is initiating the process.
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An opaque identifier for the verification process. Must be unique
|
||||||
|
with respect to the devices involved. Must be the same as the
|
||||||
|
``transaction_id`` given in the ``m.key.verification.request``
|
||||||
|
if this process is originating from a request.
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The verification method to use.
|
||||||
|
next_method:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
Optional method to use to verify the other user's key with. Applicable
|
||||||
|
when the ``method`` chosen only verifies one user's key.
|
||||||
|
required:
|
||||||
|
- from_device
|
||||||
|
- transaction_id
|
||||||
|
- method
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.key.verification.start
|
||||||
|
type: string
|
||||||
|
type: object
|
69
event-schemas/schema/m.key.verification.start$m.sas.v1
Normal file
69
event-schemas/schema/m.key.verification.start$m.sas.v1
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
---
|
||||||
|
allOf:
|
||||||
|
- $ref: core-event-schema/event.yaml
|
||||||
|
|
||||||
|
description: |-
|
||||||
|
Begins a SAS key verification process. Typically sent as a `to-device`_ event.
|
||||||
|
properties:
|
||||||
|
content:
|
||||||
|
properties:
|
||||||
|
from_device:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The device ID which is initiating the process.
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An opaque identifier for the verification process. Must be unique
|
||||||
|
with respect to the devices involved. Must be the same as the
|
||||||
|
``transaction_id`` given in the ``m.key.verification.request``
|
||||||
|
if this process is originating from a request.
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
enum: ["m.sas.v1"]
|
||||||
|
description: |-
|
||||||
|
The verification method to use. Must be ``m.sas.v1``.
|
||||||
|
key_agreement_protocols:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
The key agreement protocols the sending device understands. Must
|
||||||
|
include at least ``curve25519``.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
hashes:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
The hash methods the sending device understands. Must include at least
|
||||||
|
``sha256``.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
message_authentication_codes:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
The message authentication codes that the sending device understands.
|
||||||
|
Must include at least ``hkdf-hmac-sha256``.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
short_authentication_string:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
The SAS methods the sending device (and the sending device's user)
|
||||||
|
understands. Must include at least ``decimal``. Optionally can include
|
||||||
|
``emoji``.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
enum: ["decimal", "emoji"]
|
||||||
|
required:
|
||||||
|
- from_device
|
||||||
|
- transaction_id
|
||||||
|
- method
|
||||||
|
- key_agreement_protocols
|
||||||
|
- hashes
|
||||||
|
- message_authentication_codes
|
||||||
|
- short_authentication_string
|
||||||
|
type: object
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- m.key.verification.start
|
||||||
|
type: string
|
||||||
|
type: object
|
|
@ -52,7 +52,7 @@ func main() {
|
||||||
|
|
||||||
walker := makeWalker(dir, w)
|
walker := makeWalker(dir, w)
|
||||||
paths := []string{"api", "changelogs", "event-schemas", "scripts",
|
paths := []string{"api", "changelogs", "event-schemas", "scripts",
|
||||||
"specification"}
|
"specification", "schemas", "data-definitions"}
|
||||||
|
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
filepath.Walk(path.Join(dir, p), walker)
|
filepath.Walk(path.Join(dir, p), walker)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import inspect
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -225,3 +226,19 @@ class MatrixSections(Sections):
|
||||||
examples=swagger_def['examples'],
|
examples=swagger_def['examples'],
|
||||||
title_kind=subtitle_title_char)
|
title_kind=subtitle_title_char)
|
||||||
return rendered
|
return rendered
|
||||||
|
|
||||||
|
def render_sas_emoji_table(self):
|
||||||
|
emoji = self.units.get("sas_emoji")
|
||||||
|
rendered = ".. csv-table::\n"
|
||||||
|
rendered += " :header: \"Number\", \"Emoji\", \"Unicode\", \"Description\"\n"
|
||||||
|
rendered += " :widths: 10, 10, 15, 20\n"
|
||||||
|
rendered += "\n"
|
||||||
|
for row in emoji:
|
||||||
|
rendered += " %d, \"%s\", \"``%s``\", \"%s\"\n" % (
|
||||||
|
row['number'],
|
||||||
|
row['emoji'],
|
||||||
|
row['unicode'],
|
||||||
|
row['description'],
|
||||||
|
)
|
||||||
|
rendered += "\n"
|
||||||
|
return rendered
|
||||||
|
|
|
@ -59,6 +59,8 @@ TARGETS = os.path.join(matrix_doc_dir, "specification/targets.yaml")
|
||||||
ROOM_EVENT = "core-event-schema/room_event.yaml"
|
ROOM_EVENT = "core-event-schema/room_event.yaml"
|
||||||
STATE_EVENT = "core-event-schema/state_event.yaml"
|
STATE_EVENT = "core-event-schema/state_event.yaml"
|
||||||
|
|
||||||
|
SAS_EMOJI_JSON = os.path.join(matrix_doc_dir, "data-definitions/sas-emoji.json")
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# a yaml Loader which loads mappings into OrderedDicts instead of regular
|
# a yaml Loader which loads mappings into OrderedDicts instead of regular
|
||||||
|
@ -1088,3 +1090,21 @@ class MatrixUnits(Units):
|
||||||
"string": git_version,
|
"string": git_version,
|
||||||
"revision": git_commit
|
"revision": git_commit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def load_sas_emoji(self):
|
||||||
|
with open(SAS_EMOJI_JSON, 'r', encoding='utf-8') as sas_json:
|
||||||
|
emoji = json.load(sas_json)
|
||||||
|
|
||||||
|
# Verify the emoji matches the unicode
|
||||||
|
for c in emoji:
|
||||||
|
e = c['emoji']
|
||||||
|
logger.info("Checking emoji %s (%s)", e, c['description'])
|
||||||
|
u = re.sub(r'U\+([0-9a-fA-F]+)', lambda m: chr(int(m.group(1), 16)), c['unicode'])
|
||||||
|
if e != u:
|
||||||
|
raise Exception("Emoji %s should be %s not %s" % (
|
||||||
|
c['description'],
|
||||||
|
repr(e),
|
||||||
|
c['unicode'],
|
||||||
|
))
|
||||||
|
|
||||||
|
return emoji
|
||||||
|
|
|
@ -384,20 +384,10 @@ man-in-the-middle. This verification process requires an out-of-band channel:
|
||||||
there is no way to do it within Matrix without trusting the administrators of
|
there is no way to do it within Matrix without trusting the administrators of
|
||||||
the homeservers.
|
the homeservers.
|
||||||
|
|
||||||
In Matrix, the basic process for device verification is for Alice to verify
|
In Matrix, verification works by Alice meeting Bob in person, or contacting him
|
||||||
that the public Ed25519 signing key she received via ``/keys/query`` for Bob's
|
via some other trusted medium, and use `SAS Verification`_ to interactively
|
||||||
device corresponds to the private key in use by Bob's device. For now, it is
|
verify Bob's devices. Alice and Bob may also read aloud their unpadded base64
|
||||||
recommended that clients provide mechanisms by which the user can see:
|
encoded Ed25519 public key, as returned by ``/keys/query``.
|
||||||
|
|
||||||
1. The public part of their device's Ed25519 signing key, encoded using
|
|
||||||
`unpadded Base64`_.
|
|
||||||
|
|
||||||
2. The list of devices in use for each user in a room, along with the public
|
|
||||||
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.
|
|
||||||
|
|
||||||
Device verification may reach one of several conclusions. For example:
|
Device verification may reach one of several conclusions. For example:
|
||||||
|
|
||||||
|
@ -423,6 +413,328 @@ Device verification may reach one of several conclusions. For example:
|
||||||
decrypted by such a device. For the Olm protocol, this is documented at
|
decrypted by such a device. For the Olm protocol, this is documented at
|
||||||
https://matrix.org/git/olm/about/docs/signing.rst.
|
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}`
|
||||||
|
.. |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 out-of-band connection, such as meeting
|
||||||
|
in-person or a video call. "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 keys
|
||||||
|
and a comma-separated sorted list of of the key IDs that they wish the other user
|
||||||
|
to verify, using SHA-256 as the hash function. HMAC is defined in [RFC 2104](https://tools.ietf.org/html/rfc2104).
|
||||||
|
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 cancellation.
|
||||||
|
* The verification can time out. Clients should time out a verification that does not
|
||||||
|
complete within 10 minutes. Additionally, clients should expire a ``transaction_id``
|
||||||
|
which goes unused for 10 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, the receipient
|
||||||
|
should 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](https://tools.ietf.org/html/rfc5869)
|
||||||
|
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.
|
||||||
|
|
||||||
|
.. admonition:: Rationale
|
||||||
|
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) \ll 10 | 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
|
.. section name changed, so make sure that old links keep working
|
||||||
.. _key-sharing:
|
.. _key-sharing:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue