Android and TLS1.2

Thanks again for the confirmation. I guess that confirms the “solution” is to disable TLS on 4.x and 7.0.

1 Like

A unix socket isn’t an option? Seems like syncthing already supports it.

No idea, after all it’s android not linux (meaning there will be gotchas and problems all the way). In any case it’s definitely nothing to be consider for 0.10.18.

In any case it’s definitely nothing to be consider for 0.10.18.

For sure but it might be worth to check it for future releases. The android library seems to have support for them and it looks like connections to sockets in the filesystem namespace are possible. (read: non-public socket which can be guarded by filesystem permissions).

A first test would be to start the daemon with unix socket enabled pointing to a location in the private storage of the app.

1 Like

Can you test whether https://github.com/syncthing/syncthing-android/pull/1281 works on 7.0? And/or https is still working on other android versions. The apk can be downloaded here: https://build.syncthing.net/repository/download/SyncthingAndroid_Build/34898:id/apk/debug/app-debug.apk

I already commented yesterday on the github issue, just confirming it here:

The proposed pull request works as intended. However, I think this solution should rather be a temporary workaround instead of a permanent one. We’ve already seen a few suggestions on this thread proposing possible solutions.

If anyone has ideas on how the current situation can be improved, I’m open to hear them. I have some Java experience and would write some code if needed.

1 Like

Seems like it’s possible to use Volley with okhttp by providing a custom HttpStack:

Hi, I’m currently working to find a more a accurate solution to the Android app’s TLS problem. To shed some light, I’ve made a comparison between what an android virtual device (emulator) 7.0 supports less than one with 5.1.

Android 7.0

Summary

SSL_RSA_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_RC4_128_MD5 SSL_RSA_WITH_RC4_128_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_EMPTY_RENEGOTIATION_INFO_SCSV TLS_FALLBACK_SCSV TLS_PSK_WITH_AES_128_CBC_SHA TLS_PSK_WITH_AES_256_CBC_SHA TLS_PSK_WITH_RC4_128_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384

Android 5.1

Summary

SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 SSL_DH_anon_WITH_3DES_EDE_CBC_SHA SSL_DH_anon_WITH_DES_CBC_SHA SSL_DH_anon_WITH_RC4_128_MD5 SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_DES_CBC_SHA SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_RSA_WITH_DES_CBC_SHA SSL_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_RSA_EXPORT_WITH_RC4_40_MD5 SSL_RSA_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_DES_CBC_SHA SSL_RSA_WITH_NULL_MD5 SSL_RSA_WITH_NULL_SHA SSL_RSA_WITH_RC4_128_MD5 SSL_RSA_WITH_RC4_128_SHA TLS_DH_anon_WITH_AES_128_CBC_SHA TLS_DH_anon_WITH_AES_128_CBC_SHA256 TLS_DH_anon_WITH_AES_128_GCM_SHA256 TLS_DH_anon_WITH_AES_256_CBC_SHA TLS_DH_anon_WITH_AES_256_CBC_SHA256 TLS_DH_anon_WITH_AES_256_GCM_SHA384 TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 TLS_DHE_DSS_WITH_AES_256_CBC_SHA TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA TLS_ECDH_anon_WITH_AES_128_CBC_SHA TLS_ECDH_anon_WITH_AES_256_CBC_SHA TLS_ECDH_anon_WITH_NULL_SHA TLS_ECDH_anon_WITH_RC4_128_SHA TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDH_ECDSA_WITH_NULL_SHA TLS_ECDH_ECDSA_WITH_RC4_128_SHA TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_RSA_WITH_AES_128_CBC_SHA TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDH_RSA_WITH_AES_256_CBC_SHA TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDH_RSA_WITH_NULL_SHA TLS_ECDH_RSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_NULL_SHA TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_NULL_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_EMPTY_RENEGOTIATION_INFO_SCSV TLS_FALLBACK_SCSV TLS_PSK_WITH_3DES_EDE_CBC_SHA TLS_PSK_WITH_AES_128_CBC_SHA TLS_PSK_WITH_AES_256_CBC_SHA TLS_PSK_WITH_RC4_128_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_NULL_SHA256

Ciphers, Android 7.0 doesn’t support but 5.1 does support:

Summary

SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 SSL_DH_anon_WITH_3DES_EDE_CBC_SHA SSL_DH_anon_WITH_DES_CBC_SHA SSL_DH_anon_WITH_RC4_128_MD5 SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_DES_CBC_SHA SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_RSA_WITH_DES_CBC_SHA SSL_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_RSA_EXPORT_WITH_RC4_40_MD5 SSL_RSA_WITH_DES_CBC_SHA SSL_RSA_WITH_NULL_MD5 SSL_RSA_WITH_NULL_SHA TLS_DH_anon_WITH_AES_128_CBC_SHA TLS_DH_anon_WITH_AES_128_CBC_SHA256 TLS_DH_anon_WITH_AES_128_GCM_SHA256 TLS_DH_anon_WITH_AES_256_CBC_SHA TLS_DH_anon_WITH_AES_256_CBC_SHA256 TLS_DH_anon_WITH_AES_256_GCM_SHA384 TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 TLS_DHE_DSS_WITH_AES_256_CBC_SHA TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA TLS_ECDH_anon_WITH_AES_128_CBC_SHA TLS_ECDH_anon_WITH_AES_256_CBC_SHA TLS_ECDH_anon_WITH_NULL_SHA TLS_ECDH_anon_WITH_RC4_128_SHA TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDH_ECDSA_WITH_NULL_SHA TLS_ECDH_ECDSA_WITH_RC4_128_SHA TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_RSA_WITH_AES_128_CBC_SHA TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDH_RSA_WITH_AES_256_CBC_SHA TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDH_RSA_WITH_NULL_SHA TLS_ECDH_RSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_ECDSA_WITH_NULL_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_NULL_SHA TLS_PSK_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_NULL_SHA256

So my question is: Which one are mandatory the app should look for on the Android OS that they are supported to guarantee a successful handshake with Syncthing Web UI and REST API?

I’ve optimized the test code further to only analyze differences in regard to TLSv1.2 between Android 5.1 and Android 7.0. Those are missing on 7.0:

So looking at the posts above, this yellow curves seem to the be “the problem for Syncthing” on Android 7.0:

image

Okay, still something seems weird. SSLEngine on Android 7.0 reports those also to be available:

image

How to detect the missing curves? Any ideas @Nummer378 @Bt90 ?

Sorry, calling getSupportedCiphers() leads to nowhere. Just compared what SSLEngine on Android 6.0 reports and compared to 7.0. Conclusion: Android 7.0 reports to support everything 6.0 supports plus those ciphers: image

The problem that we’ve discovered on 7.0 is not that the specific ECDSA ciphers are not available, but that they’re partly broken on 7.0:

These links https://community.letsencrypt.org/t/warning-android-7-0-clients-not-browsers-can-only-use-curve-prime256v1/23212 , https://issuetracker.google.com/issues/37122132 - I’ve posted them previously - are stating that in the default TLS implementation of 7.0 every elliptic curve except prime256 is broken.

This affects both ECDHE key agreements and ECDSA signing - both can only be performed with P-256, but syncthing requires P-521 - this curve is not working in the buggy implementation and thus any ECDHE or ECDSA handshake will fail, even though the cipher is supported in theory.

This however is an issue, because: New installs of syncthing generate a ECC certificate with P-521. That means we can only use a suite which uses ECDSA signing with P-521 (the handshake is signed with the key from the certificate). Since the TLS client however is not capable of using this curve, it can’t properly verify the signature, nor generate a signature on it’s own.

Therefore there is simply no cipher which syncthing allows (on new installs) that works in 7.0.

I’ve played around a little with unix sockets, and I’ve come to the conclusion that unix sockets are not an easy solution - there’s no native URL handler for unix sockets, it will likely require pretty big code changes in the URL stuff. Plus I’ve no idea how to get unix sockets working in the webview, so it’s definetly not an easy solution either.

2 Likes

While all this is shitty, it’s also an argument for changing the default to P256 for a negligible, currently unknown (?) loss of crypto strength. We’re not so married to another curve that this can’t be changed as I’m not aware of any known weakness with P256 today.

(P256 is also hardware accelerated on a lot of hardware, which the other curves are not. This doesn’t matter for syncthing which only does infrequent handshakes, but it would matter for the discovery servers.)

1 Like

May I ask what the current status is on this for Syncthing App, Syncthing Lite and Syncthing-Fork?

The current release notes for Syncthing app say “Fallback to http if https with TLS 1.2 is unavailable (#1255)” On the other two apps there is no mention of this issue.

What are the implications of this for android users? If connections are made with http, does this mean that blocks are transferred unencrypted? Does that mean the relay servers can read the content of the blocks? Is it still safe to use relay servers in this situation?

This is almost a non-issue. It was an issue that the app didn’t work at all due to missing/faulty tls on android, but disabling tls on the api locally comes with a small risk (the only known scenario to me is you installing an app that specifically targets syncthing to get access to your shared data, which is unlikely to put iy mildly). connections/transfers have nothing to do with that and are always encrypted.

It’s not on the fork’s changelog as it was already solved in december '18.

So “fallback to http” only affects local calls to API on the device itself and not any external connections; “local calls to API” being calls to the Event API and REST API, which allow the Syncthing core service to be controlled from the GUI wrapper. All outgoing connections are TLS encrypted, regardless of this issue.

Good to hear that Syncthing-Fork has been fixed.

What about Syncthing-Lite?!

Syncthing Lite has a much bigger problem, as it doesn’t work on 7.0 at all (supposedly, due to the same issue). As far as I know, no fix is in coming any time soon, since there’s not much development happening in ST Lite at all.

Soo, it’s been a few months and I would like to come back to @calmh’s proposal of changing the default elliptic curve for the certificate(s).

I have been thinking back and forth with this and I would like to share my final thoughts on this here.

First a clarification: I previously stated in March that Syncthing generates a ECDSA certificate with P-521: This is incorrect. Syncthing generates the cert with P-384, but prefers P-521 for the Diffie-Hellman. We need to differentiate between curves used in the cert and curves supported in the ECDHE handshake.

Summing up some things about elliptic curves:

  • Curve P-521 is dead. Really dead. It has practically never been used and quite a few implementations, including Chrome removed supported for P-521 in 2015. The NSA never even included it in their “Suite B” paper, which started some discussions about the topic in 2013.

  • Syncthing certificate(s) use P-384, so let’s talk about P-384: This curve is more supported, but is still not the most ideal curve:

    • P-384 (and P-256) are both NIST curves engineered by the NSA. There have and will probably always be discussions whether the NSA has backdoors in these curves. I don’t know which position to support in this regard.

    • The website SaveCurves (authors: Daniel J. Bernstein and Tanja Lange) both list possible issues with the NIST curves P-384 and P-256 (both fail the SafeCurves requirements).

  • On the other hand, curves like P-384 and P-256 are not considered generally unsafe (especially P-256 is the most common curve):

    • Mozilla has recently updated their recommendations for server side TLS. Regarding elliptic curves there haven’t been much changes: They still recommend P-256 for certificates because it’s the most supported. They say however that they don’t prefer P-384 (which syncthing uses) over P-256, because of “negligable improvements to security” (and probably hard- and software support).

    • The major change on Mozilla’s recommendations was however that they started to include (and prefer) curve Curve25519 in the ECDHE list: This curve passes the SafeCurves requirements from the website above, which the NIST curves do not. The major issue with this curve is that it is too new (standardized in 2016 in RFC 7748) and support is only there in modern enviroments.

      • Another fact: Curve25519 is used in GPG, Signal, WhatsApp, Tor, I2P and iOS (and others).

Syncthing currently prefers the following curves in the ECDHE handshake (in order): P-521, P-384, P-256.

The curves 256 and 384 should already cover 99% (or more) of ECC implementations. I think it would only be reasonable to replace P-521 with Curve25519, because P-521 is dead and the other curve could even offer more security (even though the bitlength is smaller).

For the certificate the decision is harder:

Currently, P-384 is used. This has pretty much the same security as P-256, but P-256 definetly has a greater support. The Android issue which this post was originally about showed that Android 7.0 only supported P-256. Changing syncthing’s default curve in certificates to this would solve this issue (mostly) and would also follow best practices found in the world wide web (almost every ECDSA cert found in the wild is P-256, some are Curve25519).

Switching from 384 to 256 sounds therefore reasonable, but could result in a security loss - altough experts say this should be negligible. If security is top priority, Curve25519 should be preferred. But this doesn’t solve the compatibility issues (and might even worse them).

The third option is the easiest one: Since there are no real security vulnerabilities, just staying with P-384 is also a solution.

Edit 2: I haven’t looked at the elliptic curve support in Go, so I don’t what’s currently possible in Go and what not. I just assumed Go behaves similar to a modern web browser - those support all curves named (except for our dead friend P-521).

Edit: Sorry, accidentally posted this while I was still writing.

2 Likes

I am very sorry for reviving the old topic, but I have a related question, and I though it might be acceptable to ask is it here.

On Android 4.4, I have this spammed in the logs:

2020-04-25 03:49:58 Exiting backoff state.
2020-04-25 03:49:58 Relay listener (dynamic+https://relays.syncthing.net/endpoint) starting
2020-04-25 03:49:58 Listen (BEP/relay): Get https://relays.syncthing.net/endpoint: dial tcp: lookup relays.syncthing.net on [::1]:53: read udp [::1]:57529->[::1]:53: read: connection refused
2020-04-25 03:49:58 Relay listener (dynamic+https://relays.syncthing.net/endpoint) shutting down
2020-04-25 03:49:58 c.S.listenerSupervisor: Failed service 'dynamic+https://relays.syncthing.net/endpoint' (1.000000 failures of 2.000000), restarting: true, error: "{dynamic+https://relays.syncthing.net/endpoint dynamic+https://relays.syncthing.net/endpoint} returned unexpectedly", stacktrace: [unknown stack trace]
2020-04-25 03:49:58 Relay listener (dynamic+https://relays.syncthing.net/endpoint) starting
2020-04-25 03:49:58 Listen (BEP/relay): Get https://relays.syncthing.net/endpoint: dial tcp: lookup relays.syncthing.net on [::1]:53: read udp [::1]:47089->[::1]:53: read: connection refused
2020-04-25 03:49:58 Relay listener (dynamic+https://relays.syncthing.net/endpoint) shutting down
2020-04-25 03:49:58 c.S.listenerSupervisor: Failed service 'dynamic+https://relays.syncthing.net/endpoint' (1.999879 failures of 2.000000), restarting: true, error: "{dynamic+https://relays.syncthing.net/endpoint dynamic+https://relays.syncthing.net/endpoint} returned unexpectedly", stacktrace: [unknown stack trace]
2020-04-25 03:49:58 Relay listener (dynamic+https://relays.syncthing.net/endpoint) starting
2020-04-25 03:49:58 Listen (BEP/relay): Get https://relays.syncthing.net/endpoint: dial tcp: lookup relays.syncthing.net on [::1]:53: read udp [::1]:44681->[::1]:53: read: connection refused
2020-04-25 03:49:58 Relay listener (dynamic+https://relays.syncthing.net/endpoint) shutting down
2020-04-25 03:49:58 Entering the backoff state.
2020-04-25 03:49:58 c.S.listenerSupervisor: Failed service 'dynamic+https://relays.syncthing.net/endpoint' (2.999652 failures of 2.000000), restarting: false, error: "{dynamic+https://relays.syncthing.net/endpoint dynamic+https://relays.syncthing.net/endpoint} returned unexpectedly", stacktrace: [unknown stack trace]

and also:

I am guessing that the problem is the lack of support for TLS 1.2 in the old version of Android. My question then is - should I disable both relays and global discovery? They seem not to be working anyway, and I also hope to reduce the log spam this way.

It seems your dns servers don’t return an address for those hostnames. Could be an issue with dns server, could be your government blocking stuff. Nothing todo with tls

1 Like