Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any benefit in including the P-384 curve in the Modern suite? #190

Closed
zofrex opened this issue May 9, 2017 · 10 comments
Closed
Labels
wiki guidelines Issue related to Mozilla's Server Side TLS Guidelines

Comments

@zofrex
Copy link

zofrex commented May 9, 2017

I am using the recommended settings of the modern suite, and testing via SSLLabs there isn't a single client that can connect and uses prime256v1 – everything either isn't connecting at all or uses secp384r1 or secp521r1.

Is there any client of note that supports TLS 1.2 and the ciphers in the Modern suite but doesn't support secp384r1?

@ekr
Copy link

ekr commented Jun 19, 2018

Is there some reason to favor P-384 over P-256?

@zofrex
Copy link
Author

zofrex commented Jun 20, 2018

I assume bigger numbers are better? I have no more robust reasoning than that 😅

@nshopik
Copy link

nshopik commented Jun 20, 2018

Its same reason most browsers prefer cipher suites with AES-128 first and then try AES-256. Performance/battery usage, balanced approach

@cmoore1776
Copy link

Is there some reason to favor P-384 over P-256?

I suggest you look over https://safecurves.cr.yp.to/ In short, they are both potentially unsafe for exactly the same reasons:

  1. Both have coefficients generated by hashing an unexplained seed that could have been chosen by NSA specifically for a weakness that only they know about

  2. Neither support a Montgomery ladder, meaning it can take different amounts of time to perform point multiplication on different parts of the curve, thus making it more vulnerable to side channel attacks

  3. Neither is "complete", a term for indicating that standardized ECC formulas will work for every rational point on the curve, without exception. If a curve is not complete, the standard formulas don't work, and so whatever implements them needs to properly use error checking to make sure the point addition is accurate. This opens the curve up more opportunities for manipulation by an attacker if error checking is poorly implemented.

  4. Neither have Elligator maps, which are tools used to represent points on the curve in such a way that they are essentially indistinguishable from random strings. This makes the fact that you are using these curves more visible to an attacker who may wish to censor you, or collect and analyze enough data until a weakness is found.

@ekr
Copy link

ekr commented Sep 16, 2018

@shamelesscookie: yes, i'm aware of these points but they're not really relevant to the question at hand here, which is whether we should support P-384 for clients we're already going to use NIST curves for (probably because they don't support any non-NIST EC at all).

In addition, point 4 is not applicable to TLS, because the TLS handshake negotiates the curve being used in the clear.

@tomato42
Copy link
Member

to answer the question in the subject: in the current openssl (1.1.1) P-256 (aka prime256v1, aka secp256r1) is over an order of magnitude faster than P-384 for Diffie-Hellman: 18535 op/s vs 1333 op/s (on a 4GHz frequency locked i7 4790K); P-521 is actually faster than P-384 now, it manages 3008 op/s; but P-521 support is not as widespread as P-384

at the same time, there are no attacks that have significantly weakened P-256, it still is considered to be at the full 128 bit level of security (2^128 work factor) the same one as AES-128 and SHA-256 are

then we have the problem of long-term secrets, even if CAs have root certificates with P-384 curve, intermediate certificates are P-256, so using anything bigger doesn't really increase security

so to reiterate ekr's question: are there any reasons to remove P-256 and replace it with P-384?

@gene1wood gene1wood added the wiki guidelines Issue related to Mozilla's Server Side TLS Guidelines label Apr 10, 2019
@gene1wood
Copy link
Collaborator

Given the rationale above it sounds like there's not an appetite for this change

@zofrex
Copy link
Author

zofrex commented Apr 11, 2019

Thank you everyone who contributed to the discussion, there's lots of really good info here!

Given the points made above I think the original question is maybe not the most pertinent now. Given the points that P-256 is secure enough, and that P-384 is an order of magnitude slower, I think the relevant question might now be:

Is there any benefit in including the P-384 curve in the Modern suite?

The discussion here really answered well the question of whether P-384 should be used over P-256 in theory, but I want to draw attention to the fact that in practice, browsers are picking 384 when both are available (at least according to SSL Labs' simulation of handshakes). If P-256 is good enough, and significantly faster than P-384, would it make sense to remove P-384 from the list so that browsers pick P-256 instead?

@tomato42
Copy link
Member

because P-384 is part of the (deprecated, but enshrined in code) Suite B so it is the most widely deployed curve other than P-256. If it is widely deployed and enabled, in case of ECC breakthrough that significantly weakens those curves, but does not break them completely, we have a way to switch to the more secure curve right away - it won't require configuration changes on both servers and clients to align before we'll be able to switch to it.

@gene1wood gene1wood reopened this Apr 11, 2019
@gene1wood gene1wood changed the title Is there any benefit in including the prime256v1 curve in the Modern suite? Is there any benefit in including the P-384 curve in the Modern suite? Apr 11, 2019
@zofrex
Copy link
Author

zofrex commented Apr 11, 2019

That makes sense to me. Thanks!

On the very original point:

testing via SSLLabs there isn't a single client that can connect and uses prime256v1 – everything either isn't connecting at all or uses secp384r1 or secp521r1

This was due to having the protocols in the wrong order – secp521r1:secp384r1:prime256v1 instead of prime256v1:secp384r1:secp521r1. I'm now seeing usage of P-256 even with P-384 permitted. That seems like it achieves both goals of being fast but allowing client-only upgrades to P-384 later if needed.

I think that means this is settled after all? Thanks again everyone who contributed.

emilazy added a commit to emilazy/nixpkgs that referenced this issue Mar 22, 2020
Previously, the NixOS ACME module defaulted to using P-384 for
TLS certificates. I believe that this is a mistake, and that we
should use P-256 instead, despite it being theoretically
cryptographically weaker.

The security margin of a 256-bit elliptic curve cipher is substantial;
beyond a certain level, more bits in the key serve more to slow things
down than add meaningful protection. It's much more likely that ECDSA
will be broken entirely, or some fatal flaw will be found in the NIST
curves that makes them all insecure, than that the security margin
will be reduced enough to put P-256 at risk but not P-384. It's also
inconsistent to target a curve with a 192-bit security margin when our
recommended nginx TLS configuration allows 128-bit AES. [This Stack
Exchange answer][pornin] by cryptographer Thomas Pornin conveys the
general attitude among experts:

> Use P-256 to minimize trouble. If you feel that your manhood is
> threatened by using a 256-bit curve where a 384-bit curve is
> available, then use P-384: it will increases your computational and
> network costs (a factor of about 3 for CPU, a few extra dozen bytes
> on the network) but this is likely to be negligible in practice (in a
> SSL-powered Web server, the heavy cost is in "Web", not "SSL").

[pornin]: https://security.stackexchange.com/a/78624

While the NIST curves have many flaws (see [SafeCurves][safecurves]),
P-256 and P-384 are no different in this respect; SafeCurves gives
them the same rating. The only NIST curve Bernstein [thinks better of,
P-521][bernstein] (see "Other standard primes"), isn't usable for Web
PKI (it's [not supported by BoringSSL by default][boringssl] and hence
[doesn't work in Chromium/Chrome][chromium], and Let's Encrypt [don't
support it either][letsencrypt]).

[safecurves]: https://safecurves.cr.yp.to/
[bernstein]: https://blog.cr.yp.to/20140323-ecdsa.html
[boringssl]: https://boringssl.googlesource.com/boringssl/+/e9fc3e547e557492316932b62881c3386973ceb2
[chromium]: https://bugs.chromium.org/p/chromium/issues/detail?id=478225
[letsencrypt]: https://letsencrypt.org/docs/integration-guide/#supported-key-algorithms

So there's no real benefit to using P-384; what's the cost? In the
Stack Exchange answer I linked, Pornin estimates a factor of 3×
CPU usage, which wouldn't be so bad; unfortunately, this is wildly
optimistic in practice, as P-256 is much more common and therefore
much better optimized. [This GitHub comment][openssl] measures the
performance differential for raw Diffie-Hellman operations with OpenSSL
1.1.1 at a whopping 14× (even P-521 fares better!); [Caddy disables
P-384 by default][caddy] due to Go's [lack of accelerated assembly
implementations][crypto/elliptic] for it, and the difference there seems
even more extreme: [this golang-nuts post][golang-nuts] measures the key
generation performance differential at 275×. It's unlikely to be the
bottleneck for anyone, but I still feel kind of bad for anyone having
lego generate hundreds of certificates and sign challenges with them
with performance like that...

[openssl]: mozilla/server-side-tls#190 (comment)
[caddy]: https://github.com/caddyserver/caddy/blob/2cab475ba516fa725d012f53ca417c3e039607de/modules/caddytls/values.go#L113-L124
[crypto/elliptic]: https://github.com/golang/go/tree/2910c5b4a01a573ebc97744890a07c1a3122c67a/src/crypto/elliptic
[golang-nuts]: https://groups.google.com/forum/#!topic/golang-nuts/nlnJkBMMyzk

In conclusion, there's no real reason to use P-384 in general: if you
don't care about Web PKI compatibility and want to use a nicer curve,
then Ed25519 or P-521 are better options; if you're a NIST-fearing
paranoiac, you should use good old RSA; but if you're a normal person
running a web server, then you're best served by just using P-256. Right
now, NixOS makes an arbitrary decision between two equally-mediocre
curves that just so happens to slow down ECDH key agreement for every
TLS connection by over an order of magnitude; this commit fixes that.

Unfortunately, it seems like existing P-384 certificates won't get
migrated automatically on renewal without manual intervention, but
that's a more general problem with the existing ACME module (see NixOS#81634;
I know @yegortimoshenko is working on this). To migrate your
certificates manually, run:

    $ sudo find /var/lib/acme/.lego/certificates -type f -delete
    $ sudo find /var/lib/acme -name '*.pem' -delete
    $ sudo systemctl restart 'acme-*.service' nginx.service

(No warranty. If it breaks, you get to keep both pieces. But it worked
for me.)
emilazy added a commit to emilazy/nixpkgs that referenced this issue May 24, 2020
Previously, the NixOS ACME module defaulted to using P-384 for
TLS certificates. I believe that this is a mistake, and that we
should use P-256 instead, despite it being theoretically
cryptographically weaker.

The security margin of a 256-bit elliptic curve cipher is substantial;
beyond a certain level, more bits in the key serve more to slow things
down than add meaningful protection. It's much more likely that ECDSA
will be broken entirely, or some fatal flaw will be found in the NIST
curves that makes them all insecure, than that the security margin
will be reduced enough to put P-256 at risk but not P-384. It's also
inconsistent to target a curve with a 192-bit security margin when our
recommended nginx TLS configuration allows 128-bit AES. [This Stack
Exchange answer][pornin] by cryptographer Thomas Pornin conveys the
general attitude among experts:

> Use P-256 to minimize trouble. If you feel that your manhood is
> threatened by using a 256-bit curve where a 384-bit curve is
> available, then use P-384: it will increases your computational and
> network costs (a factor of about 3 for CPU, a few extra dozen bytes
> on the network) but this is likely to be negligible in practice (in a
> SSL-powered Web server, the heavy cost is in "Web", not "SSL").

[pornin]: https://security.stackexchange.com/a/78624

While the NIST curves have many flaws (see [SafeCurves][safecurves]),
P-256 and P-384 are no different in this respect; SafeCurves gives
them the same rating. The only NIST curve Bernstein [thinks better of,
P-521][bernstein] (see "Other standard primes"), isn't usable for Web
PKI (it's [not supported by BoringSSL by default][boringssl] and hence
[doesn't work in Chromium/Chrome][chromium], and Let's Encrypt [don't
support it either][letsencrypt]).

[safecurves]: https://safecurves.cr.yp.to/
[bernstein]: https://blog.cr.yp.to/20140323-ecdsa.html
[boringssl]: https://boringssl.googlesource.com/boringssl/+/e9fc3e547e557492316932b62881c3386973ceb2
[chromium]: https://bugs.chromium.org/p/chromium/issues/detail?id=478225
[letsencrypt]: https://letsencrypt.org/docs/integration-guide/#supported-key-algorithms

So there's no real benefit to using P-384; what's the cost? In the
Stack Exchange answer I linked, Pornin estimates a factor of 3×
CPU usage, which wouldn't be so bad; unfortunately, this is wildly
optimistic in practice, as P-256 is much more common and therefore
much better optimized. [This GitHub comment][openssl] measures the
performance differential for raw Diffie-Hellman operations with OpenSSL
1.1.1 at a whopping 14× (even P-521 fares better!); [Caddy disables
P-384 by default][caddy] due to Go's [lack of accelerated assembly
implementations][crypto/elliptic] for it, and the difference there seems
even more extreme: [this golang-nuts post][golang-nuts] measures the key
generation performance differential at 275×. It's unlikely to be the
bottleneck for anyone, but I still feel kind of bad for anyone having
lego generate hundreds of certificates and sign challenges with them
with performance like that...

[openssl]: mozilla/server-side-tls#190 (comment)
[caddy]: https://github.com/caddyserver/caddy/blob/2cab475ba516fa725d012f53ca417c3e039607de/modules/caddytls/values.go#L113-L124
[crypto/elliptic]: https://github.com/golang/go/tree/2910c5b4a01a573ebc97744890a07c1a3122c67a/src/crypto/elliptic
[golang-nuts]: https://groups.google.com/forum/#!topic/golang-nuts/nlnJkBMMyzk

In conclusion, there's no real reason to use P-384 in general: if you
don't care about Web PKI compatibility and want to use a nicer curve,
then Ed25519 or P-521 are better options; if you're a NIST-fearing
paranoiac, you should use good old RSA; but if you're a normal person
running a web server, then you're best served by just using P-256. Right
now, NixOS makes an arbitrary decision between two equally-mediocre
curves that just so happens to slow down ECDH key agreement for every
TLS connection by over an order of magnitude; this commit fixes that.

Unfortunately, it seems like existing P-384 certificates won't get
migrated automatically on renewal without manual intervention, but
that's a more general problem with the existing ACME module (see NixOS#81634;
I know @yegortimoshenko is working on this). To migrate your
certificates manually, run:

    $ sudo find /var/lib/acme/.lego/certificates -type f -delete
    $ sudo find /var/lib/acme -name '*.pem' -delete
    $ sudo systemctl restart 'acme-*.service' nginx.service

(No warranty. If it breaks, you get to keep both pieces. But it worked
for me.)

(cherry picked from commit 62e34d1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wiki guidelines Issue related to Mozilla's Server Side TLS Guidelines
Projects
None yet
Development

No branches or pull requests

6 participants