mozilla / ssl-config-generator

Mozilla SSL Configuration Generator
https://ssl-config.mozilla.org/
Mozilla Public License 2.0
358 stars 59 forks source link

Explicitly set list of allowed TLSv1.3 ciphersuites for nginx Modern/Intermediate/Old configurations #124

Open makhomed opened 3 years ago

makhomed commented 3 years ago

nginx starting from version 1.19.4 has ability to configure TLSv1.3 ciphersuites.

nginx directive ssl_conf_command documentation nginx directive ssl_conf_command commit description

For example:

ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;

OpenSSL has implemented support for five TLSv1.3 ciphersuites as follows:

But last two as I understand are primarily for embebbed microcontrollers with low cpu power and low battery capacity and they are not very safe, and probabbly should be disabled by default for the Modern/Intermediate/Old nginx configurations.

Maybe it will be good idea to add such setting to Modern/Intermediate/Old configuration examples?

ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;

Maybe commented out for older nginx versions and not commented for versions of nginx 1.19.4 and above.

Directive ssl_conf_command Ciphersuites used in nginx for configuring TLSv1.3 ciphers.

Directive ssl_ciphers used in nginx for configuring TLSv1.2/TLSv1.1/TLSv1/SSLv3/SSLv2 ciphers.

This is OpenSSL library limitation, so this is the main reason, why we need two different directives for configuring set of nginx ciphers/ciphersuites.

tomato42 commented 3 years ago

first, TLS_AES_128_CCM_SHA256 is safe, there is no reason to forbid it outside of the fact it's much slower than Chacha or AES-GCM on big systems second, TLS_AES_128_CCM_8_SHA256 indeed has weaker integrity protections than the current standard (64bit vs 128bit), but that requires an online attack with 64bit work factor, so you shouldn't use it unless you have to

that being said, openssl upstream does disable both CCM ciphers by default, and I know of no environments that override it, so why exactly we need to specify those ciphers explicitly?

makhomed commented 3 years ago

first, TLS_AES_128_CCM_SHA256 is safe, there is no reason to forbid it outside of the fact it's much slower than Chacha or AES-GCM on big systems

If it much slower - this also is good reason to disable it by default.

second, TLS_AES_128_CCM_8_SHA256 indeed has weaker integrity protections than the current standard (64bit vs 128bit), but that requires an online attack with 64bit work factor, so you shouldn't use it unless you have to

Quote from Transport Layer Security version 1.3 in Red Hat Enterprise Linux 8 article:

TLS_AES_128_CCM_8_SHA256 – but it is only weak against online attacks on data integrity, not data confidentiality. This cipher is disabled by default by all core crypto libraries in RHEL, including when the system is using the LEGACY crypto policy mode.

And yes, TLS_AES_128_CCM_8_SHA256 is disabled by DEFAULT in the RHEL 8 crypto-policies setup. (and in LEGACY policy it disabled too) See /etc/crypto-policies/back-ends/.config/ for details.

that being said, openssl upstream does disable both CCM ciphers by default, and I know of no environments that override it, so why exactly we need to specify those ciphers explicitly?

Check openssl ciphers | grep TLS_AES_128_CCM_8_SHA256 - cipher TLS_AES_128_CCM_8_SHA256 is not enabled by default.

From security point of view - there is no reasons to enable TLS_AES_128_CCM_8_SHA256 and TLS_AES_128_CCM_SHA256 ciphers by default. It might be better to approach this question from the other side - what could be the real reasons for the modern web to leave enabled these two ciphers (TLS_AES_128_CCM_8_SHA256 and TLS_AES_128_CCM_SHA256) ?

You ask the reason for these two ciphers to be disabled?

1) Browsers does not support TLS_AES_128_CCM_8_SHA256 and TLS_AES_128_CCM_SHA256 ciphers. For example, list of ciphers, supported by Firefox and list of ciphers, supported by Chrome.

2) From security point of view, these two ciphers TLS_AES_128_CCM_8_SHA256 and TLS_AES_128_CCM_SHA256, should/must be disabled by default to minimize and reduce possible attack surface.

tomato42 commented 3 years ago

Quote from Transport Layer Security version 1.3 in Red Hat Enterprise Linux 8 article:

yes, I'm familiar with my work :)

that being said, openssl upstream does disable both CCM ciphers by default, and I know of no environments that override it, so why exactly we need to specify those ciphers explicitly?

Check openssl ciphers | grep TLS_AES_128_CCM_8_SHA256 - cipher TLS_AES_128_CCM_8_SHA256 is not enabled by default.

yes, that's what I said, if you don't mess with openssl settings, it will not advertise TLS_AES_128_CCM_8_SHA256 or TLS_AES_128_CCM_SHA256

From security point of view - there is no reasons to enable TLS_AES_128_CCM_8_SHA256 and TLS_AES_128_CCM_SHA256 ciphers by default. It might be better to approach this question from the other side - what could be the real reasons for the modern web to leave enabled these two ciphers (TLS_AES_128_CCM_8_SHA256 and TLS_AES_128_CCM_SHA256) ?

You ask the reason for these two ciphers to be disabled?

no, I'm asking for a reason to explicitly disable them, when

a). they have always been disabled b). there are no plans to enable them

makhomed commented 3 years ago

that being said, openssl upstream does disable both CCM ciphers by default, and I know of no environments that override it, so why exactly we need to specify those ciphers explicitly?

There are many environments, where TLS_AES_128_CCM_SHA256 cipher is enabled by default.

For example: RHEL 8, CentOS 8, CentOS Stream 8, Fedora Server 33, and so on.

# grep -R TLS_AES_128_CCM_SHA256 /etc/crypto-policies
/etc/crypto-policies/back-ends/.config/python/policygenerators/openssl.py:              'AES-128-CCM':'TLS_AES_128_CCM_SHA256',
/etc/crypto-policies/back-ends/.config/DEFAULT/opensslcnf.txt:Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
/etc/crypto-policies/back-ends/.config/FIPS/opensslcnf.txt:Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
/etc/crypto-policies/back-ends/.config/LEGACY/opensslcnf.txt:Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
/etc/crypto-policies/back-ends/.config/back-ends/DEFAULT/opensslcnf.config:Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
/etc/crypto-policies/back-ends/.config/back-ends/FIPS/opensslcnf.config:Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
/etc/crypto-policies/back-ends/.config/back-ends/LEGACY/opensslcnf.config:Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
/etc/crypto-policies/back-ends/opensslcnf.config:Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256

Check openssl ciphers | grep TLS_AES_128_CCM_8_SHA256 - cipher TLS_AES_128_CCM_8_SHA256 is not enabled by default.

yes, that's what I said, if you don't mess with openssl settings, it will not advertise TLS_AES_128_CCM_8_SHA256 or TLS_AES_128_CCM_SHA256

I don't touch openssl settings, but TLS_AES_128_CCM_SHA256 is enabled by default, check openssl ciphers | grep TLS_AES_128_CCM_SHA256 on the RHEL 8 or Fedora Server 33.

And many servers in the internet have TLS_AES_128_CCM_SHA256 cipher enabled by default, see for example, https://www.ssllabs.com/ssltest/analyze.html?d=access.redhat.com Even TLS_AES_128_CCM_8_SHA256 currently is enabled for the site access.redhat.com:

image

You ask the reason for these two ciphers to be disabled?

no, I'm asking for a reason to explicitly disable them, when

a). they have always been disabled b). there are no plans to enable them

Many operating systems have at least TLS_AES_128_CCM_SHA256 enabled by default.

So we should explicitly enable in nginx 1.19.4 and above only required set of TLSv1.3 ciphers:

ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;
tomato42 commented 3 years ago

yes, in RHEL-8 TLS_AES_128_CCM_SHA256 is indeed enabled by default, my mistake, sorry

but like I said, it's not an insecure cipher, and while it is slower, it's not very slow, on my machine I get over 1.2GiB/s for openssl speed -evp aes-128-ccm, 4.7GiB/ for aes-128-gcm and 2.1GiB/s for chacha20-poly1305, so it's not like an attacker needs an order of magnitude smaller botnet to DDoS a server that has CCM cipher enabled vs one that doesn't, it's not 3DES

while yes, browsers don't enable CCM ciphers, web is not only pages viewed by humans, it's also APIs, APIs that can be used by IoT devices or over slow links

finally, indeed CCM is another cipher suite, so you can argue it's increasing the attack surface, that being said it uses very little code in addition to GCM and Cacha20 ciphers, they all are AEAD constructs, used like a black box by the TLS layer

TLS_AES_128_CCM_8_SHA256 being enabled on access.redhat.com seems like an oversight, I'll report it internally

makhomed commented 3 years ago

RHEL-8 TLS_AES_128_CCM_SHA256

but like I said, it's not an insecure cipher

But why this cipher is disabled by default on google.com, youtube.com, microsoft.com and many other sites in the internet?

Maybe for minimizing and reducing possible attack surface?

while yes, browsers don't enable CCM ciphers, web is not only pages viewed by humans, it's also APIs, APIs that can be used by IoT devices or over slow links

Are you sure, what a general-purpose server provides API for IoT devices in the internet? Many you know of such sites?

Did you read recommendations from https://wiki.mozilla.org/Security/Server_Side_TLS page ?

Modern compatibility Cipher suites (TLS 1.3): TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

Intermediate compatibility (recommended) Cipher suites (TLS 1.3): TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

Old backward compatibility Cipher suites (TLS 1.3): TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

Can you find recommendations to enable CCM ciphers on the https://wiki.mozilla.org/Security/Server_Side_TLS page ?

As I understand, https://ssl-config.mozilla.org/ site should 1:1 reflect configuration recommendations from the wiki https://wiki.mozilla.org/Security/Server_Side_TLS

@april, can you confirm, what https://ssl-config.mozilla.org/ site should 1:1 reflect configuration recommendations from the wiki https://wiki.mozilla.org/Security/Server_Side_TLS ?

finally, indeed CCM is another cipher suite, so you can argue it's increasing the attack surface, that being said it uses very little code in addition to GCM and Cacha20 ciphers, they all are AEAD constructs, used like a black box by the TLS layer

Now you are arguing not with me, now you are arguing with https://wiki.mozilla.org/Security/Server_Side_TLS page.

april commented 3 years ago

Yes, the two sites (SSL Configuration Generator, Server Side TLS) are a mirror of each other.

That said, the SSL Configuration Generator generally doesn't manually set TLS 1.3 ciphers (nor do many servers allow it), so if CCM is enabled in the underlying crypto libraries for TLS 1.3, then it will get enabled on servers.

It's not generally enabled by default for most systems, and there is not much reason to enable it by default. People whose clients are embedded systems with low-power ICs that lack crypto acceleration will know to enable it on both ends. This is a small enough group of people to not manually discuss it in a document for general purpose servers.

tomato42 commented 3 years ago

yes, I'm familiar with the https://wiki.mozilla.org/Security/Server_Side_TLS page

I'm saying that the omission of TLS 1.3 ciphers from ssl-config-generator is intentional, exactly because you can't really misconfigure TLS 1.3 server ciphers the reason why Server_Side_TLS page lists TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 is because that's the OpenSSL default, not because we decided to disallow CCM (i.e. just like you won't find recommendation to enable it, you won't find recommendation to disable it)

april commented 3 years ago

We also don't list CCM because we don't want people going out of their way to enable them when they're rarely needed. It's often not easy to do so, and by listing them it makes it seem mandatory.

makhomed commented 3 years ago

We also don't list CCM because we don't want people going out of their way to enable them when they're rarely needed. It's often not easy to do so, and by listing them it makes it seem mandatory.

So, adding CCM ciphers to the list of recommended ciphers at the wiki https://wiki.mozilla.org/Security/Server_Side_TLS page is bad idea.

So, at least with the issue https://github.com/mozilla/server-side-tls/issues/279 situation is clear now.

That said, the SSL Configuration Generator generally doesn't manually set TLS 1.3 ciphers (nor do many servers allow it), so if CCM is enabled in the underlying crypto libraries for TLS 1.3, then it will get enabled on servers.

This issue is only about nginx, not about other servers. nginx 1.19.4 and above allow to configure TLS 1.3 ciphers.

It's not generally enabled by default for most systems, and there is not much reason to enable it by default.

RHEL 8, CentOS 8, CentOS Stream 8, Fedora Server 33 - all these distros are enable TLS_AES_128_CCM_SHA256 by default.

People whose clients are embedded systems with low-power ICs that lack crypto acceleration will know to enable it on both ends. This is a small enough group of people to not manually discuss it in a document for general purpose servers.

That is reason why I am propose exlicitly enable by default in the nginx only recommended by https://wiki.mozilla.org/Security/Server_Side_TLS page ciphers.

Directive ssl_conf_command added to nginx recently, and many people don't know how to configure TLSv1.3 ciphers in the nginx.

Summary, known reasons why TLS 1.3 ciphers should be configured explicitly in the nginx:

  1. Because browsers does not support CCM ciphers.
  2. Because OpenSSL library by default disable CCM ciphers.
  3. Because "people whose clients are embedded systems with low-power ICs that lack crypto acceleration will know to enable it on both ends. This is a small enough group of people to not manually discuss it in a document for general purpose servers."
  4. Because RHEL 8, CentOS 8, CentOS Stream 8, Fedora Server 33 - all these distros are enable TLS_AES_128_CCM_SHA256 by default.
  5. To provide example how to configure TLS 1.3 ciphers in the nginx. // Mainly for the people from (3)
  6. To minimize attack surface by default. // Look at (1), (2), (3) and (4) for details

Summary, known reasons why TLS 1.3 ciphers should NOT be configured explicitly in the nginx:

None.

I'm saying that the omission of TLS 1.3 ciphers from ssl-config-generator is intentional, exactly because you can't really misconfigure TLS 1.3 server ciphers

You remember TLS_AES_128_CCM_8_SHA256 enabled on the site access.redhat.com? "CCM_8 has weak integrity guarantees so we shouldn't enable them by default, those are useful only for specific environments".

tomato42 commented 3 years ago

There are reasons to not explicitly configure this in nginx:

  1. it limits the configuration to versions of nginx that support that configuration option
  2. it makes people think that this setting is important, when that's not the case
  3. it complicates the config generator for little to no gain to security

tangentially: if you use RHEL 8, Fedora, or any of the derived distributions, you shouldn't specify cipher suites in the configuration files anyway, you should use cryptographic policies

I'm saying that the omission of TLS 1.3 ciphers from ssl-config-generator is intentional, exactly because you can't really misconfigure TLS 1.3 server ciphers

You remember TLS_AES_128_CCM_8_SHA256 enabled on the site access.redhat.com? "CCM_8 has weak integrity guarantees so we shouldn't enable them by default, those are useful only for specific environments".

both things can be true at the same time

should you enable CCM_8 when you don't have a reason to? no is your server exploitable if you configure it to enable CCM_8? also no

I used "shouldn't use" instead of "MUST NOT use" deliberately

makhomed commented 3 years ago

There are reasons to not explicitly configure this in nginx:

  1. it limits the configuration to versions of nginx that support that configuration option
  2. it makes people think that this setting is important, when that's not the case
  3. it complicates the config generator for little to no gain to security

This is true right now, because it is no known vulnerabilities in the CCM ciphers at the current moment of time.

But can you guarantee that there are no vulnerabilities in the CCM ciphers and will never be found?

Imagine that in the future some vulnerabilities will be found in CCM ciphers - disabling CCM ciphers will become important at that point in time, but can you then quickly change the settings on all servers connected to the Internet?

Do you know the exact reason why the OpenSSL developers disabled CCM ciphers by default?

Maybe this reason is important and it makes sense for us to take it into account?

I google for "why CCM ciphers disabled by default" and found, what CCM ciphers has some disadvantages, compared to GCM ciphers:

"To minimize attack surface by default" - it is important reason, from my point of view.

For older nginx versions this settings can be provided commented out with description, what this setting will work in nginx starting from version 1.19.4, something like this:

# Directive ssl_conf_command exist in nginx version 1.19.4 and above.
# ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;

tangentially: if you use RHEL 8, Fedora, or any of the derived distributions, you shouldn't specify cipher suites in the configuration files anyway, you should use cryptographic policies

As I understand from the file /etc/crypto-policies/back-ends/.config/policies/FUTURE.pol FUTURE policy allow to use CCM cipher: tls_cipher = AES-256-GCM AES-256-CCM CHACHA20-POLY1305, so I can't use FUTURE policy to disable CCM ciphers. Also FUTURE policy forces me to use at least 3072 bit openssh public key for connecting to server - this is not convenient for me because my public key right now is 2048 bit in size.

May be you are talking about FIPS policy with OSPP module enabled to disable CCM ciphers? But FIPS policy disable TLS_CHACHA20_POLY1305_SHA256 cipher and OSPP module disable TLS 1.3 protocol - this is not desirable behaviour, so I can't use FIPS policy with OSPP module to disable CCM ciphers.

Also I can't find NO-CCM policy module, so I can't use cryptographic policies for disabling CCM ciphers in nginx.

As for me - it is far more simple just to put in the nginx config:

ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;

and as result - CCM cipher will be disabled and I can clearly see which ciphers are enabled for TLS 1.3 protocol in nginx.

zDEFz commented 3 years ago

Finally, that made me get an A with 100/100/100 ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;

With TLS 1.2 enabled it will be an A+, but with less cipher strength...

https://www.ssllabs.com/ssltest/analyze.html?d=stat.def0.de&hideResults=on

DaAwesomeP commented 1 year ago

Hello,

It does not always seem possible to enforce TLS v1.3 and specific TLS v1.3 ciphers in Nginx. I think I may be running into two Nginx bugs, but I am not sure. This is Nginx 1.22.1 from the official Nginx mainline APT repo and OpenSSL 1.1.1n on Debian 11.

  1. Nginx seems to only look at one configuration of ssl_protocols even if they are configured in server blocks and not in the http block. I have one server with intermediate SSL and one server with modern SSL, but Nginx is serving both TLS v1.2 and v1.3 for both of them. This is contrary to the documentation which says that it is definitely supported in server blocks.

    server {
     # intermediate configuration
     ssl_protocols TLSv1.2 TLSv1.3;
     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;
     ssl_prefer_server_ciphers off;
    }
    server {
     # modern configuration
     ssl_protocols TLSv1.3;
     # no change in behavior with or without the following line
     ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;
     ssl_prefer_server_ciphers off;
    }
  2. Nginx seems to be ignoring my ssl_conf_command Ciphersuites configuration. When I run SSL Labs on the modern config above it says it basically says I have ALL v1.2 and v1.3 ciphers enabled. When I change the Ciphersuites line to ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256; there is no change in the supported ciphers.

Has anyone else run into these issues?

makhomed commented 1 year ago

This is not nginx bugs. Bugs are in your configuration and expectations.

  1. You tries to set different ssl_protocols in name-based virtual servers. This will not work, because OpenSSL fixes protocol before the name is known. At the same time, in different IP-based (or port-based) virtual servers are quite possible use different ssl_protocols.

More about this is here:

https://trac.nginx.org/nginx/ticket/676 https://mailman.nginx.org/pipermail/nginx/2014-November/045738.html

This and other nuances of applying configuration for name-based virtual servers are documented here:

http://nginx.org/en/docs/http/server_names.html#virtual_server_selection

  1. As for TLSv1.3 Ciphersuites, their OpenSSL, apparently, too selects immediately when the connection is established, and accordingly it is pointless to set them in name-based virtual servers, it is necessary set in the default server.
DaAwesomeP commented 1 year ago

@makhomed Thank you very much for the thorough explanation and pointers! I understand now my incorrect assumptions. I apologize for the slightly off-topic comment.