mozilla / ssl-config-generator

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

Lower SECLEVEL in `old` config for OpenSSL 3.x compatibility #256

Closed gstrauss closed 1 day ago

gstrauss commented 1 month ago

Updates to support OpenSSL 3.x

Resolves #188 Tracked in #260

TESTING: https://test-3x--mozsslconf-dev.netlify.app/#openssl=3.3.3&config=old&server=postgresql

gstrauss commented 1 month ago

For DH parameters code review, I checked all servers which had .hbs configs containing {{#if output.usesDhe}}. I downloaded the source code and checked the history to find supported versions.

lighttpd - no change; does the right things with the appropriate versions

apache - small changes to do the right things with appropriate versions postfix - small changes to do the right things with appropriate versions redis - small changes to do the right things with appropriate versions

coturn - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto dovecot - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto exim - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto haproxy - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto nginx - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto postgresql - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto proftpd - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto squid - no change; does not call SSL_CTX_set_dh_auto/SSL_set_dh_auto

There are some apps, such as stunnel and postgresql, which use built-in 2048-bit pregenerated DH params, if none is otherwise configured. Some other servers many support DH params included in certificate PEM file. This PR does not review bit sizes of DH params as that is out of scope for this PR -- which is focused on upgrading the OpenSSL version supported by ssl-config-generator. Besides, best practices in modern configs no longer use DHE.

gstrauss commented 1 month ago

RFE: I would like to discussion renaming "Old" config to "Insecure", because that is what it is. It provides obscurity over clear-text, but is not considered "secure" by modern specifications. It fails all modern security standards and so the remaining value is compatibility with ancient devices and possibly historical verification of now-obsolete older security standards.

For TLSv1 and TLSv1.1 (also no longer considered secure), @SECLEVEL=0 in the cipher list should suffice. Another alternative would be suggesting modifications to /etc/ssl/openssl.cnf or /etc/pki/tls/openssl.cnf, but I think modifying the cipher string scopes SECLEVEL=0 to the app, which is better than suggesting lowering the OpenSSL library security for all apps on the system using openssl.

janbrasna commented 1 month ago

I will be addressing this gradually, mostly looking into some template options to avoid the repetition, TBD…

I would like to discussion renaming "Old" config to "Insecure", because that is what it is. It provides obscurity over clear-text, but is not considered "secure" by modern specifications.

That name is a term within the org: https://infosec.mozilla.org/guidelines/risk/scoring_and_other_levels.html#recommended-configuration-states

A lot of effort went (back in the day) to make this config usable, not having anything directly compromised etc., so it's still a nudge above "insecure" in the scoring (yellow, grade "D" to "D-"); basically anything moved out of old in the past decade can be deemed insecure (red, grade "F") in comparison. I believe the rationale below the list still stands. (The issue is none of that is directly visible in the UI here, that is definitely a deficiency.)

Given the specs are due for update anyways, I can see some old cleanup and demotions from intermediate in the cards eventually… so no need to re-label it with catastrophic badges, it only needs to move the suites along gradually.

For TLSv1 and TLSv1.1 (also no longer considered secure), @SECLEVEL=0 in the cipher list should suffice.

There will be some servers that won't know how to support that (individual keys for ciphers instead of the cipher string; will need to look into the implementations), but happy to have old configs on 3+ only as a best effort, if documented as such…

Do we also want to map when a server doesn't support 3+? (Does it still happen today?)

This PR does not review bit sizes of DH params as that is out of scope for this PR

I'm actually comfortable with letting intermediate fail to apply on <80 bits — that's a reminder for the consumer they're not careful with the key size as instructed.

gstrauss commented 1 month ago

In the future, if we do consider renaming the profiles, I would like to propose including a date in the spec. Even if only a year, "modern-2020" is much more descriptive than the current almost 5-year old (!) "modern", which I do not consider modern.

For TLSv1 and TLSv1.1 (also no longer considered secure), @SECLEVEL=0 in the cipher list should suffice.

There will be some servers that won't know how to support that (individual keys for ciphers instead of the cipher string; will need to look into the implementations), but happy to have old configs on 3+ only as a best effort, if documented as such…

Most of the app templates join the cipher list with ':'. The ones that do not are awselb caddy go jetty traefik, so we'll have to look to see how they handle (or not) @SECLEVEL=0. I was trying to avoid creating a new variable for @SECLEVEL=0 that had to be pasted onto the cipher list and have code added to each and every src/templates/partials/*.hbs for addition to the cipher lists (where applicable).

Do we also want to map when a server doesn't support 3+? (Does it still happen today?)

Unlikely. All versions of OpenSSL earlier than openssl 3.0.0 are EOL and not supported by the OpenSSL Foundation, though paid Premium Support is still available from the OpenSSL Corporation for some older openssl versions.

gstrauss commented 1 month ago

This PR does not review bit sizes of DH params as that is out of scope for this PR

I'm actually comfortable with letting intermediate fail to apply on <80 bits — that's a reminder for the consumer they're not careful with the key size as instructed.

The default SECLEVEL=2, and we should retain that. At SECLEVEL=1, TLSv1 and TLSv1.1 are disabled, so if the Old config needs them, those who need it must use SECLEVEL=0

gstrauss commented 1 month ago

To address your review comment about apps that do not pass a ':'-separated cipher string to openssl, I pushed a change to avoid adding @SECLEVEL=0 to the cipher list for ['awselb','caddy','go','jetty','traefik']. We'll need to add a comment in each of this .hbs files that @SECLEVEL=0 will need to be configured in openssl.cnf unless there is a different way that these apps expose to configure the security level in their config files. (not done yet)

gstrauss commented 1 month ago

['awselb','caddy','go','jetty','traefik'] all are configured usesOpenssl: false, so I removed that unnecessary check.

I also reconsidered and change the form['config'].value === 'old' test to protocols.includes('TLSv1.1') since SECLEVEL=0 is needed by OpenSSL 3 for TLSv1 and TLSv1.1 used by the Old configuration.

gstrauss commented 1 month ago

@janbrasna I think this is ready for commit. Please give this priority for re-review. Thanks!

I feel it would be negligent to unnecessarily delay recommending configs supporting OpenSSL 3.x. On the other hand, if there are are few bugs that turn up in specific apps for Old configuration -- which we want to discourage anyway due to low security -- then those are bugs and can be fixed.

gstrauss commented 1 month ago

I incorporated the changes in #257 and updated the Apache version here.

gstrauss commented 1 month ago

Ready for review again with the changes from #257. The last few pushes were whitespace cleanup.

janbrasna commented 1 month ago

I will also try to document what info should be added upstream, to the recommendation contents, as a rationale for the choices we're making to support OpenSSL 3. (I will add it to the #260 epic where I intend to track things even spanning the actual repos…)

I'm thinking about a review meeting to go through some of the things, TBD, I'll put together a list/backlog for that to see how much we have left that I'd like to discuss before confirming any decisions.

(I have more questions than actual time to even ask them — some of the issues are solving themselves over time, I'm not sure about Tomcat impact (if you can try to find out it won't trip over the seclevel in cipherstring as it does some own parsing before passing anything on…), will have more questions about the seclevel bit-strength threshold wrt our other output values than just the protocols etc. …)

What's mostly unknown to me are the os-level specifics that can differ for folks, e.g.:

"This may have more implications than just re-enabling TLSv1.0 and 1.1 (or rather: SHA1 and MD5 signature algorithms, used by these protocols) though, depending on the OpenSSL version. See man SSL_CTX_set_security_level(3) on the same machine." — https://github.com/mozilla/ssl-config-generator/issues/188#issuecomment-1534798621

Can you think of any wild differences among versions or distros/defaults?

I would love for this to be first released as "opt-in" — say by skipping the 3.x version in configs.js now, we can ask people to manually test 3.x configs by punching in the version (or via permalink), before settling on that as the new default for anyone and everyone. Mainly to verify we're still good on 1.1.1 not bringing any regressions to the existing logic, and giving it few weeks for feedback before flipping that switch. (If it is long overdue, long+14d overdue doesn't make much difference.)

gstrauss commented 1 month ago

I'm not sure about Tomcat impact

No impact. Tomcat is configured in src/js/config.js with usesOpenssl: false and that is checked before adding SECLEVEL=0

"This may have more implications than just re-enabling TLSv1.0 and 1.1 ...

Can you think of any wild differences among versions or distros/defaults?

From a practical perspective, it does not matter since it is required to support TLSv1 and TLSv1.1, and if the Old config provides support for TLSv1 and TLSv1.1, then SECLEVEL=0 must be set if OpenSSL 3.x is used.

I would love for this to be first released as "opt-in" — say by skipping the 3.x version in configs.js now

Ok. I will push momentarily with that commit removed.

janbrasna commented 1 month ago

This PR does not review bit sizes of DH params as that is out of scope for this PR

I'm actually comfortable with letting intermediate fail to apply on <80 bits — that's a reminder for the consumer they're not careful with the key size as instructed.

The default SECLEVEL=2, and we should retain that. At SECLEVEL=1, TLSv1 and TLSv1.1 are disabled, so if the Old config needs them, those who need it must use SECLEVEL=0

Ah right, I meant <112 bits, sorry. That kinda enforces the RSA and DHE keys length 2048b+ for us, so I'm not sure there's anything to review as that's on par with the recommendations (and good it's actually enforced now) — did you mean anything beyond that?

gstrauss commented 1 month ago

My earlier comment was addressing the poster's recommendation to use at least ffdhe3072. That is not in scope for this PR and will be addressed in the future with specification review. :)

gstrauss commented 1 month ago

verify exim doesn't need removal of +no_ssl* flags

I verified the exim code.

decide on tomcat (that may or may not use openssl implementation…)

src/js/configs.js specifies usesOpenssl: false

gstrauss commented 1 month ago

review all use of output.usesDhe, output.dhCommand, output.dhParamSize

I did review this. Please be more specific for what you/I might look.

gstrauss commented 1 month ago

I wrote:

My earlier comment was addressing the poster's recommendation to use at least ffdhe3072. That is not in scope for this PR and will be addressed in the future with specification review. :)

I should note that some servers hard-code ffdhe2048. stunnel is one. I think postgresql was another. (I was not keeping track as I quickly reviewed source code for calls to SSL_CTX_set_dh_auto() or SSL_set_dh_auto().)

lighttpd is a third, but lighttpd only uses ffdhe2048 if openssl version is too old. The reason I have not updated lighttpd is because if you're on an ancient system and using an ancient openssl version, you are probably on an underpowered system and you likely have many other system security risks more important than DHE bit length. If this is a concern, you should, of course, configure lighttpd with your own appropriate DHParameters.

gstrauss commented 1 month ago

A large amount of time is being spent on DHParameters, even though modern security recommendations do not include ciphers which require them. I do not think we would be spending time on this if the Mozilla TLS recommendations were reviewed and updated.

Note: https://developers.cloudflare.com/ssl/edge-certificates/additional-options/cipher-suites/recommendations/ recommends ECDHE and does not recommend any DHE ciphers, even for Legacy. (If TLSv1 and TLSv1.1 are needed, then weaker ciphers are made available for such Legacy use.)

gstrauss commented 1 month ago

add an AND helper for conditional blocks only (not) matching two values

That is an underlying code change which has not effect on the output. It should not be part of this PR and should be tested and rolled out separately, in a separate PR.

decide on tomcat (that may or may not use openssl implementation…)

As already stated, this is not an issue with the current code which sets usesOpenssl: false. If you want to change that for Tomcat, that IS NOT PART OF THIS PR and should not block this PR.

verify oraclehttp support

https://docs.oracle.com/middleware/12213/webtier/administer-ohs/GUID-C76BCA2A-9C28-4D16-9758-9346FBCF7512.htm#HSADM1016

I don't have access to test oraclehttp, but if someone reports an issue with the Old config and SECLEVEL=0, then we can add code to oraclehttp.hbs to filter out SECLEVEL=0. Please remember that this is for the Old config; the Old config is old and people are strongly discouraged from using it.


@janbrasna Please focus on the "minimum viable product" to approve this PR so that it can be deployed for testing. This PR does not bump the openssl version, so you'll continue to have plenty of time for turd polishing for the Old config after this PR is merged and deployed. Please move as many of your testing concerns as you can from this PR to #263

polarathene commented 1 month ago

recommendation to use at least ffdhe3072

2048-bit is still plenty, using the hashrate of the bitcoin global network in 2024 I did some napkin math (see near end of comment for 2048-bit math) which calculated 54,000 years, but that was just against the entropy with the hashrate as operations. I don't have math on me from old notes for GFNS which also requires considerable resources beyond CPU at this scale, but IIRC the attack cost should be higher... thus really not pragmatic / worthwhile.

TLS 1.3 also supports ffdhe2048 as a minimum IIRC and that's auto-negotiated? Usually you only see a desire to use more because the user does not understand the math, or some regulation compliance has raised the bar without adequate justification (presumably as a precaution or external perception/expectation).

gstrauss commented 2 weeks ago

Rebased on master.

After discussion in meeting, I have removed the dh_auto changes from this PR. (Note, this also removed the update to Apache version). Removing the dh_auto changes from this PR preserve the existing behavior for Intermediate to explicitly set 2048-bit DHE key. TLSv1.3 uses RFC7919 negotiation to select Group, and whether or not and how to configure Groups (Curves) will be a separate discussion from this PR. In the ssl-config-generator, usesDhe is not set for TLSv1.3.

The remaining commit in this PR sets @SECLEVEL=0 for "Old" config to support TLSv1 and TLSv1.1 for OpenSSL 3.x. (SECLEVEL=1 would be minimum needed for 1024-bit DHE key used by "Old" config.)

gstrauss commented 1 week ago

I have incorporated the two changes: 1) test usesOpenssl !== false and 2) if (ciphers[0] === '@SECLEVEL=0') ciphers.shift(); unconditionally.

janbrasna commented 1 week ago

I'm not sure about Tomcat impact

No impact. Tomcat is configured in src/js/config.js with usesOpenssl: false and that is checked before adding SECLEVEL=0

Which doesn't change whether folks end up using OpenSSL or JSSE. I don't have enough working knowledge to infer how the connectors configure own OPENSSL_CONF or the context from its own jdk/jre java.security properties or -Djdk.* args at env/startup etc. — I'm more looking at this whether we need to start listing some caveats when we don't know if such profile can be supported fully (like we do in caddy comments)

A large amount of time is being spent on DHParameters

Because it's the most sensitive setting in the current outputs, and of the added value features we provide translating the guidelines into the configs.

even though modern security recommendations do not include ciphers which require them

Which is not true. All TLSv1.3 suites include them by default (even though they don't "advertise" the fact in the IANA naming, but it's defined directly in the RFC).

janbrasna commented 1 week ago

recommendation to use at least ffdhe3072

2048-bit is still plenty

@polarathene Ah, that came from someone who got bad rating from an automated test unrelated to these configs, it was grading against Dutch Internet Standards Platform, but that probably evaluates the government recommendations wrong anyways, as only 1024 should fail, 2048 is still allowed even after years of updates to their specs, although noted to "phase out" — but they have no instructions attached as to what that is supposed to mean, i.e. it's still listed nonetheless. (I'd see the requirement for 3072 more as a bug in the automation tool TBH.)

We still reflect what is in the current recommendations, and will try to do so even for RFC7919 groups, if we end up restricting them in the configs. (See #270 …)

polarathene commented 1 week ago

We still reflect what is in the current recommendations, and will try to do so even for RFC7919 groups, if we end up restricting them in the configs.

Yeah, I mentioned some reasons for why someone might feel the need to use a higher key/group size but as per the napkin math, I really don't see it being necessary.

Given that TLS 1.3 will handle many connections these days and IIRC a client or server may restrict it's ability to only negotiate with a cipher using FFDHE 2048-bit, since TLS 1.3 doesn't allow you to exclude that (not since I last checked anyway?) it'd be accepted 🤔

Since it's a static group for any such TLS 1.3 connection negotiated with it, someone with the resources could attack that for an advantage. At which point some policy goes into place to forbid/change it, but as per the math I linked earlier it's not very pragmatic to pull that off:

Besides... what if someone has the equivalent of that global bitcoin hashrate of 750 EH/sec against RSA-2048 (110-bit)???:

# 110-bit (RSA 2048-bit) operations processed at a rate of 750EH/sec
# divided by seconds in a thousand years (approx), provides thousand of years required
( ((2^110) / 750e18) / (60*60*24*365*1e3)) ) ~= 54.88

54,000 years!!! Panic! The LetsEncrypt certificate with 90 days of validity is in danger! Quick bump it up to RSA 3072-bit!

Don't try to bring in quantum computing either. For similar reasons to why the math for RSA above isn't valid (GNFS), there are certain resource requirements that offset the advantages you see parroted around.

The link provides more context/info for that, but you need an awfully large amount of computation and advancement to bring that attack into the realm of possibility, as covered in another part of my napkin math reference:

Also for the 750 EH/sec, we don't have the best data on power usage, but it's estimated at 170 TW hours of electricity per year. More than Ukraine outputs annually. At just 10x the size of current network, the power output would be nearing that of India, 30x would surpass the USA and 200x the entire planets output. To support 1000x the bitcoin network size requires producing more energy that you're going to get how?

The power required is sufficient to boil all the oceans on the planet, it's not something you can do stealthily even if we could compute an attack within our lifetimes.


Unfortunately we have silly articles like this 2024 Forbes one encouraging 3072-bit and citing quantum compute risks:

While these key sizes are currently deemed secure against brute force attacks by computers, they may not provide security against quantum computers. For instance, a quantum computer employing Shor's algorithm might potentially crack a 2048-bit RSA key within eight hours.

Which to anyone who knows better this is nonsense. We are a long way off having the necessary qubits (the hardware you see marketed these days tends to be a lot lower in actual qubits since many are used for error correction). While the compute time could go down, it doesn't magically mess with physics, the entropy is still there and the resource cost just shifts, time is only one resource to take into consideration.

NIST Recommendations: The National Institute of Standards and Technology (NIST) explicitly recommends the use of 3072-bit keys as part of their guidelines for quantum cryptography. Following these guidelines ensures compliance with recognized standards and industry best practices.

RSA keys, not FFDHE group parameters but close enough compute wise IIRC 😅

That's the sort of thing that'll make a push for bumping it up, regardless of the math. That increase is smaller than RSA 1024-bit to 2048-bit too (NIST has their own document on equivalent symmetric security strength).

gstrauss commented 1 day ago

If someone is using "Old", then the priority is not "best security practices"; the priority is compatibility with out-of-date, end-of-life, and/or unmaintained devices (or all of the above). TLSv1.2 was released in 2008, over 16 years ago. TLSv1.0 and TLSv1.1 have been formally deprecated since March 2021 in RFC8996. Hello! As I write this, over 3 1/2 years (!) has passed since March 2021 when RFC8996 was published.

Therefore, I am committing this change as proposed over two weeks ago. This change is small, and setting SECLEVEL=0 is required for OpenSSL 3.x to support TLSv1.0 and TLSv1.1 protocols.

Follow-ups for https://github.com/mozilla/ssl-config-generator/pull/256#issuecomment-2458504186 in #270 "Explicitly configure curves/groups from the guidelines"

oraclehttp and Tomcat are marked in ssl-config-generator src/js/configs.js with usesOpenssl: false and are out-of-scope for the changes propsed in this PR.

@janbrasna, your additions to the TODO list are out-of-scope for this PR. Please handle elsewhere:

TODO/OQ:

  • [x] ~consider AND helper for conditional blocks only (not) matching two values~
  • [x] move oraclehttp from mod_ssl to mod_ossl
  • [ ] look into tomcat seclevel options (for both apr/openssl implementation and java policy?)
  • [ ] how does e.g. BoringSSL like that (should not matter when it doesn't support some weak ciphers at all?)
gstrauss commented 1 day ago

libressl supports @SECLEVEL. BoringSSL does not recognize @SECLEVEL. While both try to provide some level of compatibility with common OpenSSL interfaces, neither are OpenSSL. libressl has its own version numbers. BoringSSL is Google-specific and the source code README.md very explicitly states: (https://boringssl.googlesource.com/boringssl)

BoringSSL is a fork of OpenSSL that is designed to meet Google's needs.

Although BoringSSL is an open source project, it is not intended for general
use, as OpenSSL is. We don't recommend that third parties depend upon it. Doing
so is likely to be frustrating because there are no guarantees of API or ABI
stability.