Looking for more detailed crypto info

I have looked at the documentation on the block exchange protocol and it raises some questions. Specifically, it is quite vague about what cipher suite is actually being used in the negotiation. In fact, parts seem almost intentionally vague:

“A strong cipher suite SHALL be used, with “strong cipher suite” being defined as being without known weaknesses”

“Strong = !weak” doesn’t seem very specific for a protocol definition. And…

Examples of strong cipher suites are given at the end of this document. This is not to be taken as an exhaustive list

Where can I go for the exhaustive list? Is there more in-depth documentation on this?

Also, I am curious if there has been any discussion about implementing a pre-shared key system a la wireguard.

Nowadays it’s typically the TLS 1.3 suites, which are not configurable from our side. The spec is intentionally vague because this changes over time.

No that I’m aware. Note, of course, that the goals and constraints for wireguard are quite different from our own.

1 Like

Is there any way in configuration to mandate (or forbid) ciphersuites and/or particular curves within ciphersuites?

The outcome (vpn vs file sync) is very different. The security goal is the same, is it not?

Modern syncthing versions will by default only negotiate TLSv1.3 (on sync connections). The go standard library does not allow applications to configure ciphersuites on TLSv1.3, and that’s a good thing (1,2,3,4). For the key exchange (EC curves), syncthing also relies on the choices made by the Go cryptographers.

There are no configuration options for this. The goals are different in terms of implementation – Wireguard is a kernel implementation, keeping a small footprint and avoiding dependencies is key. For our crypto implementation, avoiding “innovation” and trusting a more vetted approach, i.e., Go’s TLS library, is better.

There is no way in go’s implementation to, say, prevent the use of secp256r1?

If so, that’s not a feature.

Edit: Never mind. If it’s 1.3 only I’m much happier.

Edit2: I would still be happier if ST would consider a PSK, and a way to lock out TLS 1.2.

Ciphersuite and signature algorithm groups / key exchange groups don’t really relate to each other (especially in TLS 1.3). They’re negotiated independently (and I was specifically talking about the former).

Two recent syncthing versions will always choose x25519 as the kex, as both will support that and it has the highest preference. The certificates are usually P-384, unless your instance is from a very old syncthing version (in which case your cert will be RSA).

AFAIK golang does not support PSK in TLS at all, and I would be pretty devastated if syncthing were to move away from the well-engineered, audited and maintained goland TLS library just for PSKs (which are not worth it anway IMHO). As for TLSv1.2, as already stated syncthing does not negotiate TLSv1.2 on sync connections unless insecureAllowOldTLSVersions is set. GUI connections are a different topic.

2 Likes

I still remember the mile long topics when we turned off TLS 1.2 by default. shudders

2 Likes

I won’t try and convince you to change your mind personally about PSKs. I like them because they are a security backup. And they are well accepted and received in the community for the same reason. You don’t need to personally like them or find them useful to accept the above.

You don’t need to use go (or anyone else’s) TLS mechanism for a PSK. Once the TLS channel is open and you’re ready to send data through it, you just pre-encrypt that data with the PSK before you send it. ChaCha20 or another good, fast stream cipher. You don’t even need to add anything to Syncthing’s own negotiation.

What does this bring us (i.e., what scenario / attack does it prevent)?

PSKs - if implemented correctly - has some benefits for - as of today - theoretical attack scenarios, for example:

  • If today’s NIST ECDSA curves are backdoored, PSKs may prevent a (state level) attacker from snooping at data, as the PSK is not backdoored.
  • If quantum computers with sufficient computing capability are/can be built, (EC)DHE key exchanges can be broken. If PSKs are used for key derivation (in addition to ECDHE) [TLSv1.3 has this as an optional feature] they can assist in keeping the connection secure. Note that it is currently assumed that large symmetric algorithms like AES-256 will remain secure against quantum computers, at least initially.
1 Like

Honestly, for scenarios where TLS itself is conceptually broken, Syncthing is quite low on my list of worries. It’s not something I think we should try to mitigate.

(I understand that there will be actors and situations where the opposite is true. WireGuard may well be one of them.)

1 Like

Before I go on to #3, I just want to add to #2 that this is something that is being taken seriously elsewhere. OpsnSSH has implemented post-quantum algos, and it’s the default now. And my understanding is that post-quantum security was the driving factor behind PSKs in WireGuard. I personally don’t think that lattice algos like sntrup761 are ready for prime time yet. So this is why I think a PSK in ST is the way to go.

  1. And not the least is that it is an added layer of protection against TLS implementation errors. TLS is a monster. If I were to print out all the CERT vulnerability reports for the various implementations of SSL/TLS since inception, I could wallpaper most of Canada. This is, I think, close to being literally true. To think that, yup, this time THIS is the one, that TLS 1.3 as implemented in go is the one that is rock solid secure is, I think, an exercise in hubris. It’s a not a matter of if, but when.

And the fact is, it’s not difficult. It’s not reinventing the wheel. I don’t know ST’s code all that well, but if it has single functions for sending and receiving over the TLS link, then I can’t think of how implementing a PSK is more than 50 or 100 lines of code. And 99% of that will be UI and key setup.

I have a hard time understanding why this is anything but a no-brainer.

If that’s your concern though, why not just run WireGuard between your devices? That gets you the security you need in an additional layer, it’s literally what it’s made for?

2 Likes

Syncthing’s particular strength and its best value added is that it is one-stop-shopping. If “use a separate VPN” is the official answer to what to do to get a security margin, my assertion is that this requirement diminishes Syncthing’s value added to the community.

I considered Wireguard, but I’ll prolly stick with using the poor man’s PSK that ST has now, which is untrusted folders. In a star configuration, if I make the central hub untrusted, and all the nodes trusted, then it’s something akin to a PSK for all nodes. I only lose the ability for the hub to use the files without added work.

Perhaps you’d consider extending your untrusted folder paradigm just a little so that it will do the same thing with all devices being trusted, so that it’s just transmitted with the extra encryption. It will still leak a little information to “listeners” who see through the TLS for some reason or other, but only file sizes I think. That’s a pretty acceptable level of leakage for the “backup” security.

1 Like

Perhaps you’d also consider allowing the user to override the AES/CHACHA20 choice. On platforms without AESNI, it might be nice to all the user to specify AES anyway. For many people, the speed of AES on non AESNI systems still far exceeds their connection speed. Since the use of chacha20 for untrusted encryption is set, it would be nice to force a different primitive for the OTW encryption. It would makes that poor man’s PSK a better backup.

First of all, this is - again - a golang choice, as the go TLS implementation sets the ciphersuites and their preference not syncthing.

Second, this would actually decrease security because the S/W implementations of AES in go are not constant-time implementations and as such may be vulnerable to timing side-channel attacks. Only the H/W accelerated implementations are constant time, hence go will try to avoid the usage of AES if no device support is present.

Additionally, this again brings up the cryptographic design principle I mentioned earlier: “Have one joint and keep it well oiled”. The old days of having cryptographic mechanisms where everything was adjustable is no longer state of the art. Modern, secure implementations only allow configuration where necessary, so adding choices everywhere “oh, you want to replace primitive X with Y? Sure, here you go” are exactly the things that cause vulnerability issues.

3 Likes

I spent some time going over golang and educated myself on its TLS. This “bug report” was particularly enlightening. I understand Syncthing a bit better now.

I’m going to respond out of order a bit…

This is a good principle and one I wholeheartedly agree with. It’s just not being applied here.

The shift you are speaking of has been driven by two things. First, by poor implementations of large crypto libraries supporting large standards. I say poor, but really it’s driven by the natural law (basically of entropy) that states the larger the library, the more likely there is to have a security-affecting bug somewhere.

The second driver is the fact that some standards are overlarge, have been made by standards bodies that have had suspect motives and/or were not fully competent, and have been very slow to react to the cryptographic realities in the wild. They therefore contain primitives that are at best suspect.

Wireguard, who is the poster child for that principle of “Have one joint and keep it well oiled”, started as a 1:1 protocol (one source of client talking to one source of server, or in this case, one source of client/server). They weren’t trying to leverage into an existing many:many and interoperate with existing clients or servers, so they had the luxury of doing it exactly the right way. They selected cryptographic primitives which are above reproach in their design, security, and openness. They implemented them in small, tight code, which is easily vetted. I have nothing but good things to say about Wireguard.

It is applying…

…100% properly.

go TLS is not one joint

Go TLS is not one joint because TLS is not one joint. TLS is itself the poster child for both drivers I mention above. It is large, over complex, and it includes (even 1.3) suspect primitives. The go TLS maintainers indicate they will not allow crypto selectability because they state “All supported cipher suites are safe”. But if they are all safe, then selectability isn’t an issue, is it? They say they will keep you safe by making all the decisions for you. And they state that if one of their decisions turns out to be bad, they will just patch it.

Of course, for Syncthing this means that if a bug in go TLS is found, or if one of their primitives turns out to be weak, or one of their decisions turns out to be suboptimal, then it has to be reported, go TLS has to patch it, Syncthing has to recompile, then it has to be disted out. Which is no mean problem in the case of Linux distros.

Is there any other SSL implementation that bars crypto suite selection? OpenSSL and wolfSSL both allow it.

go TLS is not well oiled

That was an oh my God moment. There have been constant time software techniques and implementations of AES for over a decade. For both main methods (table lookup and straight calculation). Good ones which are as well optimized as constant-time can be.

I don’t see why. All I have to say is I’m really happy for ST’s untrusted feature now, because it is using hard-coded chacha20, and I hope it gets extended to include untrusted connections.