Enable TLS1.0 in Nginx, getting SNI errors, additional cert

I am testing my cert setup with:

https://www.ssllabs.com/ssltest/analyze.html?d=www.apkfiles.com

First... I don't understand why and how it gets the "additional" cert from server (.tntcode.net), that is a default hostname I set for that server, and I think this additional cert might cause some of the problems:

The problems I have are:

Android 2.3.7 No SNI, Incorrect certificate because this client doesn't support SNI,
RSA 2048 (SHA256) | TLS 1.0 | TLS_RSA_WITH_AES_128_CBC_SHA

This site works only in browsers with SNI support

In my nginx conf I have:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

And the ciphers I tried were these:

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:PSK-AES128-CBC-SHA";

And these, based on the Mozilla tool:

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA;
ssl_prefer_server_ciphers on;

The site should support those older devices like Android 2.3.7 that shows the TLS1.0 error.
And I see Google.com can create that handshake without the error.

1 Like

Hi @adrianTNT,

I agree with SSL Labs in this case. The point of SNI is to allow a server to choose the appropriate certificate from among several certificates that it may possess in order to answer incoming TLS connections to a shared server. Without SNI, the server doesn’t know which site the client wanted to connect to, so it returns the default certificate.

That is the expected behavior of any site, and in the case of your site, the default certificate covers only *.tntcode.net, which doesn’t match www.apkfiles.com.

The only way to fix this to support non-SNI-capable clients is to add multiple names onto the same certificate. Let’s Encrypt will allow you to do this; you could, for example, get a single certificate for both *.tntcode.net and *.apkfiles.com. If that certificate is presented as the default one, clients will realize that it’s valid for either domain, and not reject it.

Otherwise, you will need to give up support for non-SNI-aware clients, or use a separate IP address for each domain name.

1 Like

Hi @schoen
It doesn’t make sense to me, maybe you can explain differently, but … when someone opens the site, nginx will serve the specified cert based on the hostname requested, as I set in nginx.conf, it returns the *.apkfiles.com cert for www.apkfiles.com , I still don’t get how server would end up including the .tntcode.net one. And why that one and not another domain cert I have on the server (around 4) ?
Is it related to how data would be encrypted and server needs to route traffic without seeing the traffic contents ? Or I am way off already ? :slight_smile:

That is SNI.
If the client doesn't support SNI, then NO hostname is requested - basically requestinh only as HTTPS://IP/

That must be the cert in the "DEFAULT" vhost config, which is served when there is no matched hostname.

2 Likes

with no sni sent by client, server doesn’t know which site it want to visit, so it just throws default one(*.tntcode.net) as default.

By the way, your current cert doesn’t cover base domains (apkfiles.com or tntcode.net) so if user visit by that domain it will see cert error.

2 Likes

There are two ways the hostname is requested in HTTPS: once at the TLS level (using SNI), and once at the HTTP level (using the Host: header). Virtual hosts or virtual servers are typically selected by web server applications using the Host: header, but certificates have to be selected using the SNI method because they have to match in older to complete the TLS negotiation.

That means that when there is no SNI, there is no "hostname requested" from the point of view of choosing a certificate. Although the server could rely on the Host: header in HTTP, that comes later on, and the TLS negotiation is already supposed to be complete before that happens!

Yes, that's also a pretty reasonable way to think about it. In order for the encryption to get set up, the virtual host has to be selected. It would be possible for a load balancer to use the SNI field to route different TLS connections to different backends, even without being able to see inside the encryption (for example, without possessing the private keys for the different services). However, in that case the load balancer wouldn't know what to do if an inbound connection with no SNI arrived.

1 Like

So in the end, for an old client like ‘Android 2.3.7’ (without SNI) I have no way to setup a https connection without a dedicated IP ? I still don’t get it 100% :slight_smile:
(I mean without the load balancer complications).

Is that why I remember some years ago you needed a dedicated IP for https ? Because clients were older ?

1 Like

By the way, your current cert doesn’t cover base domains (apkfiles.com or tntcode.net) so if user visit by that domain it will see cert error.

I didn't notice that because I had a redirect setup (from apkfiles.com to www.apkfiles.com) and browsers didn't complain before redirect.

Edit: when requesting a new cert, I had to do it like: -d *.apkfiles.com -d apkfiles.com

[...]

I tested a site that is behind cloudflare, cloudflare doesn't use dedicated IP (for most clients), and the old Android client doesn't show an error:

Android 2.3.7 No SNI RSA 2048 (SHA256) TLS 1.0 TLS_RSA_WITH_AES_128_CBC_SHA No FS

1 Like

ah, it’s because you redirect http://apkfiles.com to https://www.apkfiles.com
try https://apkfiles.com it will show error, but as default is plane http, I don’t think you will have to do anything.

and cloudflare status like 100 sites in one certificate by alternative names.

2 Likes

I forgot about multiple domains in same cert. I might do that too eventually.
Are there performance issues if I use same cert for around 30 different domains ? I assume cert string is same size (e.g download time), but clients would need to go trough a longer domain list to process/verify ?

1 Like

Clients are also doing a whole bunch of cryptography; scanning a list of 30 domains isn’t a big deal.

Certificates do contain the complete list of names covered. They do take time to download. But there are already kilobytes of overhead; adding one more probably isn’t a big deal.

1 Like

I added all domains under same cert and seems to work fine, just that it list all my domains to anyone looking at the cert.

Anyway, it works with both these sets of ciphers, can anyone advise on which ones to use ?

using ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

mozilla tool recommendation:

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA;

digital ocean recommendation:

ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

Ssllabs shows more secure ciphers in mozilla's version, but I assume server is a bit faster with less protocols, is that correct ? :confused:
Both these get same overall score and the Handshake Simulation test shows same results for different clients.
Thanks for the help guys :grimacing:

1 Like

Turn off anything you don't use.

Not really relevant.
Speed (as in throughput and encryption/decryption) happens after negotiation.
Negotiation is generally controlled by the server preference order (top down or left to right if you are reading through the ssl_ciphers list).
The client need only parse it once (happens almost instantly) to "understand" which cipher to use.

To "test" your actual encryption/decryption speeds (which can vary from CPUs and O/Ses), you may need to run some openssl tests or download a large file from a client while forcing the use of different ciphers.

2 Likes

Got it. Thanks.
I was more worried about user’s performance, because on main site, most of them are on mobile phones and some of them should be older generation.

1 Like

That is an insecure cipher list. CBC3 & 3DES have vulnerabilities that can be exploited. I also suggest killing all protocols below TLSv1.2. If you have to go as low as TLSv1.0, force this Cipher list:

ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AESCCM:!SHA1

I also want to point out that the test you are looking at is a simulated client/browser on an android 2.3.7 device, which is super old and several years past EOL. SNI was not a thing back then, and the error disappears with cloudflare if you use their SSL front-end service because they handle the browser encryption while your LE cert on the server will handle your server to cloudflare encryption.

So then you need to ask yourself, will you really have anyone accessing your site from an old android 2.3.7 device? More than likely not, so you don’t need to worry about being able to support that client.

EDIT:
Let me clarify that Android is currently on 9 (Pie). 2.3.7 is not older, it’s ancient… . 3.x was Honeycomb, 4.0 was Ice Cream Sandwich, 4.2.2 JellyBean, 4.4 KitKat, 5.0 Lollipop, 6.0 Marshmallow, 7.0 Nougat, 8.0 Oreo.

1 Like

It's hard to know which ciphers you use in this case because it's dependent on what visitors to your site try to negotiate with you. You could log that if you wanted to, but web servers normally don't log it by default. Mozilla is trying to make informed recommendations here based on security and compatibility considerations.

1 Like

Totally agreed; especially in this case, anyone assuming that he actually knows what he is using [or not] is likely suffering form hallucinations.
But the statement is there for all that may read it (not just for him).
And it should be read to imply (contrapositive?):
“if you are certain about what you don’t use, then turn those things off”.
Or ridiculously reduced to:
% !{use} : #
[conciseness sometimes complicates understandability]

1 Like

I agree with that for computing in general, but I think it's unlikely that most people have informed individual opinions about ciphersuite selection at the moment, so most people have ended up following some authority on this point—which isn't surprising because the landscape is so complicated.

1 Like

Sad… but true.

1 Like

The landscape is complicated because it is constantly changing. BEAST, POODLE & all its variations, CBC & 3DES zero-length vulnerabilities. Then you have IDS/IPS/WAF services that can’t decrypt DH Ciphers, which limits you to 2 ciphers on TLSv1.2, and kills your browser compatibility unless you allow for TLSv1.0 & 1.1. It’s definitely an area you need to have the patience to keep up with.