mirror of
https://github.com/syncthing/syncthing.git
synced 2026-04-08 16:38:03 -04:00
Create syncthing-device-ids(7)
This commit is contained in:
@@ -1,28 +1,28 @@
|
||||
########################
|
||||
Understanding Device IDs
|
||||
########################
|
||||
========================
|
||||
|
||||
Every device is identified by a device ID. The device ID is used for
|
||||
address resolution, authentication and authorization. The term "device
|
||||
ID" could interchangably have been "key ID" since the device ID is a
|
||||
direct properties of the public key in use.
|
||||
Description
|
||||
-----------
|
||||
|
||||
Every device is identified by a device ID. The device ID is used for address
|
||||
resolution, authentication and authorization. The term "device ID" could
|
||||
interchangably have been "key ID" since the device ID is a direct properties of
|
||||
the public key in use.
|
||||
|
||||
Keys
|
||||
====
|
||||
----
|
||||
|
||||
To understand device IDs we need to look at the underlying mechanisms.
|
||||
At first startup, Syncthing will create an public/private key pair.
|
||||
To understand device IDs we need to look at the underlying mechanisms. At first
|
||||
startup, Syncthing will create an public/private key pair.
|
||||
|
||||
Currently this is a 3072 bit RSA key. The keys are saved in the form of
|
||||
the private key (``key.pem``) and a self signed certificate
|
||||
(``cert.pem``). The self signing part doesn't actually add any security
|
||||
or functionality as far as Syncthing is concerned but it enables the use
|
||||
of the keys in a standard TLS exchange.
|
||||
Currently this is a 3072 bit RSA key. The keys are saved in the form of the
|
||||
private key (``key.pem``) and a self signed certificate (``cert.pem``). The self
|
||||
signing part doesn't actually add any security or functionality as far as
|
||||
Syncthing is concerned but it enables the use of the keys in a standard TLS
|
||||
exchange.
|
||||
|
||||
The typical certificate will look something like this, inspected with
|
||||
``openssl x509``:
|
||||
|
||||
::
|
||||
``openssl x509``::
|
||||
|
||||
Certificate:
|
||||
Data:
|
||||
@@ -58,28 +58,26 @@ The typical certificate will look something like this, inspected with
|
||||
88:7e:e2:61:aa:4c:02:e3:64:b0:da:70:3a:cd:1c:3d:86:db:
|
||||
df:54:b9:4e:be:1b
|
||||
|
||||
We can see here that the certificate is little more than a container for
|
||||
the public key; the serial number is zero and the Issuer and Subject are
|
||||
both "syncthing" where a qualified name might otherwise be expected.
|
||||
We can see here that the certificate is little more than a container for the
|
||||
public key; the serial number is zero and the Issuer and Subject are both
|
||||
"syncthing" where a qualified name might otherwise be expected.
|
||||
|
||||
An advanced user could replace the ``key.pem`` and ``cert.pem`` files
|
||||
with a keypair generated directly by the ``openssl`` utility or other
|
||||
mechanism.
|
||||
An advanced user could replace the ``key.pem`` and ``cert.pem`` files with a
|
||||
keypair generated directly by the ``openssl`` utility or other mechanism.
|
||||
|
||||
Device IDs
|
||||
==========
|
||||
----------
|
||||
|
||||
To form a device ID the SHA-256 hash of the certificate data in DER form
|
||||
is calculated. This means the hash covers all information under the
|
||||
To form a device ID the SHA-256 hash of the certificate data in DER form is
|
||||
calculated. This means the hash covers all information under the
|
||||
``Certificate:`` section above.
|
||||
|
||||
The hashing results in a 256 bit hash, which we encode using base32.
|
||||
Base32 encodes five bits per character, so we need 256 / 5 = 51.2
|
||||
characters to encode the device ID. This becomes 52 characters in
|
||||
practice, but 52 characters of base32 would decode to 260 bits which is
|
||||
not an whole number of bytes. The base32 encoding adds padding to 280
|
||||
bits (the next multiple of both 5 and 8 bits) so the resulting ID looks
|
||||
something like
|
||||
The hashing results in a 256 bit hash, which we encode using base32. Base32
|
||||
encodes five bits per character, so we need 256 / 5 = 51.2 characters to encode
|
||||
the device ID. This becomes 52 characters in practice, but 52 characters of
|
||||
base32 would decode to 260 bits which is not an whole number of bytes. The
|
||||
base32 encoding adds padding to 280 bits (the next multiple of both 5 and 8
|
||||
bits) so the resulting ID looks something like
|
||||
``MFZWI3DBONSGYYLTMRWGC43ENRQXGZDMMFZWI3DBONSGYYLTMRWA====``.
|
||||
|
||||
The padding (``====``) is stripped away, the device ID split in four
|
||||
@@ -90,13 +88,12 @@ grouped with dashes, resulting in the final value:
|
||||
``MFZWI3D-BONSGYC-YLTMRWG-C43ENR5 -QXGZDMM-FZWI3DP-BONSGYY-LTMRWAD``.
|
||||
|
||||
Connection Establishment
|
||||
========================
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
So now we know what device IDs are, here's how they are used in
|
||||
Syncthing. When you add a device ID to the syncthing configuration,
|
||||
Syncthing will attempt to connect to that device. The first thing we
|
||||
need to do is figure out the IP and port to connect to. There's three
|
||||
possibilities here;
|
||||
So now we know what device IDs are, here's how they are used in Syncthing. When
|
||||
you add a device ID to the syncthing configuration, Syncthing will attempt to
|
||||
connect to that device. The first thing we need to do is figure out the IP and
|
||||
port to connect to. There's three possibilities here;
|
||||
|
||||
- The IP and port can be set statically in the configuration. The IP
|
||||
can equally well be a hostname, so if you have a static IP or a
|
||||
@@ -114,10 +111,10 @@ possibilities here;
|
||||
any local announcements the global discovery server will be queried
|
||||
for an address.
|
||||
|
||||
Once we have and address and port a TCP connection is established and a
|
||||
TLS handshake performed. As part of the handshake both devices present
|
||||
their certificates. Once the handshake has completed and the peer
|
||||
certificate is known, the following steps are performed.
|
||||
Once we have and address and port a TCP connection is established and a TLS
|
||||
handshake performed. As part of the handshake both devices present their
|
||||
certificates. Once the handshake has completed and the peer certificate is
|
||||
known, the following steps are performed.
|
||||
|
||||
#. Calculate the remote device ID by using the process above on the
|
||||
received certificate.
|
||||
@@ -169,27 +166,26 @@ here:
|
||||
more probable than the SHA-256 collision. Briefly stated, if you
|
||||
find SHA-256 collisions scary then your priorities are wrong.
|
||||
|
||||
It's also worth noting that the property of SHA-256 that we are using is
|
||||
not simply collision resistance but resistance to a preimage attack.
|
||||
I.e. even if you can find two messages that result in a hash collision
|
||||
that doesn't help you attack Syncthing (or TLS in general). You need to
|
||||
create a message that hashes to exactly the hash that my certificate
|
||||
already has or you won't get in.
|
||||
It's also worth noting that the property of SHA-256 that we are using is not
|
||||
simply collision resistance but resistance to a preimage attack. I.e. even if
|
||||
you can find two messages that result in a hash collision that doesn't help you
|
||||
attack Syncthing (or TLS in general). You need to create a message that hashes
|
||||
to exactly the hash that my certificate already has or you won't get in.
|
||||
|
||||
Note also that it's not good enough to find a random blob of bits that
|
||||
happen to have the same hash as my certificate. You need to create a
|
||||
valid DER- encoded, signed certificate that has the same hash as mine.
|
||||
The difficulty of this is staggeringly far beyond the already staggering
|
||||
difficulty of finding a SHA-256 collision.
|
||||
Note also that it's not good enough to find a random blob of bits that happen to
|
||||
have the same hash as my certificate. You need to create a valid DER- encoded,
|
||||
signed certificate that has the same hash as mine. The difficulty of this is
|
||||
staggeringly far beyond the already staggering difficulty of finding a SHA-256
|
||||
collision.
|
||||
|
||||
Problems and Vulnerabilities
|
||||
============================
|
||||
----------------------------
|
||||
|
||||
As far as I know, these are the issues or potential issues with the
|
||||
above mechanism.
|
||||
|
||||
Discovery Spoofing
|
||||
------------------
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Currently, neither the local nor global discovery mechanism is protected
|
||||
by crypto. This means that any device can in theory announce itself for
|
||||
@@ -217,13 +213,13 @@ It's something we might want to look at at some point, but not a huge
|
||||
problem as I see it.
|
||||
|
||||
Long Device IDs are Painful
|
||||
---------------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's a mouthful to read over the phone, annoying to type into an SMS or
|
||||
even into a computer. And it needs to be done twice, once for each side.
|
||||
It's a mouthful to read over the phone, annoying to type into an SMS or even
|
||||
into a computer. And it needs to be done twice, once for each side.
|
||||
|
||||
This isn't a vulnerability as such, but a user experience problem. There
|
||||
are various possible solutions;
|
||||
This isn't a vulnerability as such, but a user experience problem. There are
|
||||
various possible solutions:
|
||||
|
||||
- Use shorter device IDs with verification based on the full ID ("You
|
||||
entered MFZWI3; I found and connected to a device with the ID
|
||||
|
||||
Reference in New Issue
Block a user