To sum up Nutomic’s answer: The class SyncthingTrustManager is a clever thing (Zillode told me he originally contributed it). It loads syncthing’s web ui https cert from the flat files in the app’s private dir and verifies if the service reached at https://:8384 is really the right syncthing instance having that cert.
Which cipher is that, which would be used instead [assuming that syncthing go accepts it]? I would guess that there should be plenty of (secure) fallback options, the list of cipher suites is not that small.
On another side: Google writes that the ProviderInstaller from Google Play services can bring support for TLSv1.2 to old Android versions, even back to Android 2.3. But I suppose that requires the Google Play services being available, which may not be the case on all Androids. But it could be used, if available.
So yeah, this affects both ECDHE exchanges as well as ECC certificates. The syncthing https certificates are probably ECC? Otherwise, if the certificate is not a problem a fallback to something like DHE-RSA-AES256-GCM-SHA384 or DHE-RSA-AES128-GCM-SHA256 would be totally fine, as long as >= 2048 bit numbers are used in DH and RSA.
It justs feels wrong to say “sorry, but TLS 1.2 doesn’t work on Android 7.0, an OS which is has a market share of 18.1% worldwide.”
The syncthing native/go is the server in this configuration. In TLS, the client sends a list of “what it can do” and the server then responds with “what to do”, meaning it selects the cipher suite which is to be used. Generally the server should select whatever is considered most secure. If some cipher is broken on the client side, the client should not offer this suite to prevent it from being selected. If the server is unsatisfied with the list of available cipher suites send by the client, the handshake will fail.
I probably need more data on this: Is the syncthing https server restrictive with ciphers? I would assume Go allows anything that is not totally broken, as that is the usual configuration. Sometimes developers apply additional restrictions on the list of allowable ciphers to further increase security. If the syncthing server offers some kind of fallback without elliptic curves, the client just needs to support it too.
My first impression is that only the client side (Android, Java) needs a littlebit of tweaking in case elliptic curves are problematic.
$ nmap --script ssl-enum-ciphers -p 8384 127.0.0.1
Starting Nmap 7.60 ( https://nmap.org ) at 2019-02-25 23:15 CET
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00010s latency).
PORT STATE SERVICE
8384/tcp open marathontp
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp521r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp521r1) - A
| TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (secp521r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp521r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp521r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp521r1) - A
| TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
| TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
| cipher preference: server
|_ least strength: A
Nmap done: 1 IP address (1 host up) scanned in 0.47 seconds
Yeah, my freshly generated certificate is also fully ECC.
This is indeed a problem, because this definetly requires ECC working on Android. So there’s either a solution to get ECC working reliably on all supported Android versions, or there must be a fallback to not use TLS for API communication.
I didn’t try okhttp yet as the existing code in EventProcessor is a tender child because it fires an ongoing https request to read events and it has been to be carefully checked if another library can do it as well without draining much battery. Android 7 currently has its market share but some time in the future it will die out as Google might cut support for important cloud apps as they did on 4.x already.
I don’t think any time should be spent on 4.x - just disable TLS. Using such an outdated system has much higher security implications than someone targeting Syncthing to get control over data, that’s anyway accessible to any app with data access permissions. For 7.0 I’d try to get confirmation on the one report we have and if it really doesn’t work, just disable it as well - at least in a first step. Something more elaborate can be done later on if anyone feels like it.
I believe that there might be two entirely different problems on Android 7.0 - Altough I haven’t verified this yet.
There’s currently one user which apparently only has TLS 1.0 support. This is really strange and at this point I have no explanation for it - it may be related to a very specific setup, or it’s caused by another issue.
The second issue that may arise when TLS 1.2 is enabled on Android 7.0 is that the handshake will fail, due to incompatible cipher suites. Right now, this problem is entirely hypothetical, so it may not exist at all.
Looking at the link you send, there are indeed ciphers with RSA (some for signing only and some for signing and secret transport [no PFS]). But if my TLS understanding is correct, these ciphers can only be used when the certificate is RSA. This is likely the case for older syncthing installs, but as I showed above it is not the case for new installs - those use ECDSA and therefore the ciphers with RSA signing cannot be used.
This explains the image I posted above - only ciphers with ECDSA signing are available. This effectively kills everything that is not fully ECC with PFS.
And that constellation is, according to known bugs, unsupported on Android 7.0 because the elliptic curve used doesn’t work.
I tried to verify this in an Android emulator, but the Chrome browser inbuild has it’s own TLS stack which is not affected by the issue. And in the Syncthing-Fork app I can’t force TLS, it seems to always fall back to HTTP. Maybe @Catfriend1 can do a test build with TLS forced, which can then be tested on 7.0, to see whether this issue actually exists or if all of this was just noise.
I’ve bad news: I can reproduce the issue with “unsupported, maximum protocol version” error. The recently updated syncthing app doesn’t work at all on my Android 7.0 emulator.
Right now, I’m collecting data. I will edit this post once I have some more factual information.
The issue with elliptic curves being problematic on Android 7.0 is documented in different places, see my links in earlier posts for examples - if you google further you find about a dozen reports with TLS handshake erors with Android 7.0.
On the Android side: I’ve installed the official/standard/non-fork Syncthing app on an Android 7.0 emulator. The app has recently been updated to bundle syncthing v1.0.1.
The following happens after install:
After going through the standard setup wizard, a window appears saying something like “generating keypairs” (forgot the exact message). This window never disappears but just stays on forever. I assume that is because the app cannot communicate with the syncthing API.
After forcibly stopping the app and re-opening it, a window “loading” appears and never disappears. After some time, a note reading “Syncthing is taking very long to load. Use the logs to check for any errors”.
Clicking OPEN LOG shows a lot error messages, always repeating the same three messages. These are:
<Date> W/SyncthingNativeCode( 2743):<Date>http: TLS handshake error from 127.0.0.1:<increasing port number>: remote error: tls: illegal parameter
<Date> W/SyncthingNativeCode( 2743):<Date>http: TLS handshake error from 127.0.0.1:<increasing port number>: remote error: tls: client offered an unsupported, maximum protcol version of 302
<Date> W/SyncthingNativeCode( 2743):<Date>http: TLS handshake error from 127.0.0.1:<increasing port number>: remote error: tls: client offered an unsupported, maximum protcol version of 301
The messages repeat in this order. I’m still trying to figure out how to properly debug TLS on android, but my current theory is this:
The Android client attempts a TLS 1.2 connection, but fails due to the discussed ECC problem.
Due to TLS 1.2 failing with a cipher problem, the client attempts a reversion to TLS 1.1 [by pretending that it only supports the older standard] and then TLS 1.0, which obviously fails because the server only allows TLS 1.2. Such client-initated fallbacks are probably implemented as workarounds for version intolerance (https://timtaubert.de/blog/2016/09/tls-version-intolerance/).
This causes communication between the syncthing app and the syncthing native to fail completly.