mozilla/cipherscan

ecdsa-with-SHA256 cert trips warning about key size

tycho opened this issue · 17 comments

tycho commented

My host uses a certificate with a 256-bit ECC public/private key. analyze.py doesn't appreciate this:

hostname:443 has bad ssl/tls

Things that are bad:
* don't use a public key smaller than 2048 bits

The warning seems to only make sense for RSA certificates.

Perhaps the warning should only trigger if conn['sigalg'][0] contains 'RSA', as in sha256WithRSAEncryption?

diff --git a/analyze.py b/analyze.py
index e519a6f..021f52d 100755
--- a/analyze.py
+++ b/analyze.py
@@ -59,7 +59,7 @@ def is_fubar(results):
             has_ssl2 = True
             logging.debug('SSLv2 is in the list of fubar protocols')
             fubar = True
-        if int(conn['pubkey'][0]) < 2048:
+        if int(conn['pubkey'][0]) < 2048 and 'RSA' in conn['sigalg'][0]:
             has_wrong_pubkey = True
             logging.debug(conn['pubkey'][0] + ' is a fubar pubkey size')
             fubar = True

sorry for the delay, could you check the master branch now? I believe it got fixed by f5ad580

tycho commented

Seems confused about some sizes still, but different ones:

$ python2 ./analyze.py -t www.uplinklabs.net
www.uplinklabs.net:443 has obscure or unknown ssl/tls

Changes needed to match the old level:
* enable TLSv1
* enable SSLv3
* add cipher DES-CBC3-SHA
* use a certificate with sha1WithRSAEncryption signature
* use DHE of 1024bits and ECC of 160bits

Changes needed to match the intermediate level:
* consider enabling TLSv1
* add cipher AES128-SHA
* use a certificate signed with sha256WithRSAEncryption
* consider using DHE of at least 2048bits and ECC of at least 256bits

Changes needed to match the modern level:
* remove cipher ECDHE-ECDSA-AES256-SHA
* remove cipher ECDHE-ECDSA-AES128-SHA
* disable TLSv1.1
* use DHE of at least 2048bits and ECC of at least 256bits

Looking at the last line of the "modern" suggestions, I don't know why that message is there:

$ ./cipherscan www.uplinklabs.net
.....................
Target: www.uplinklabs.net:443

prio  ciphersuite                    protocols        pfs                 curves
1     ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2          ECDH,P-521,521bits  secp521r1,secp384r1
2     ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2          ECDH,P-521,521bits  secp521r1,secp384r1
3     ECDHE-ECDSA-AES256-SHA384      TLSv1.2          ECDH,P-521,521bits  secp521r1,secp384r1
4     ECDHE-ECDSA-AES128-SHA256      TLSv1.2          ECDH,P-521,521bits  secp521r1,secp384r1
5     ECDHE-ECDSA-AES256-SHA         TLSv1.1,TLSv1.2  ECDH,P-521,521bits  secp521r1,secp384r1
6     ECDHE-ECDSA-AES128-SHA         TLSv1.1,TLSv1.2  ECDH,P-521,521bits  secp521r1,secp384r1

Certificate: trusted, 384 bits, ecdsa-with-SHA256 signature
TLS ticket lifetime hint: 300
NPN protocols: None
OCSP stapling: supported
Cipher ordering: server
Curves ordering: server - fallback: no
Server supports secure renegotiation
Server supported compression methods: NONE
TLS Tolerance: yes

Intolerance to:
 SSL 3.254           : absent
 TLS 1.0             : PRESENT
 TLS 1.1             : absent
 TLS 1.2             : absent
 TLS 1.3             : absent
 TLS 1.4             : absent

This shows up in the debug log:

DEBUG:root:ECDH,P-521,521bits is not a good PFS parameter for the modern configuration

It looks like it's calling has_good_pfs() with must_match set to True, which means the message should read "exactly 256bits" instead of "at least 256bits". Seems like "must_match" should go away...

no, that's exactly the behaviour we want, for "modern" level you need to support P-256, if you don't support it, you're not at the modern level

though the message is a bit confusing...

tycho commented

Uhm, my server does support P-256. It just also supports P-521 and others. Do I need to deliberately reduce the security and only support P-256?

tycho commented

Oh, I see, in ECDHParameters, not Curves. Still seems silly to require a lower-strength curve for that...

tycho commented

I set ECDHParameters to prime256v1 and it still sees P-521, which is the first one listed in my Curves list. Hmm.

the curves column lists only two: secp521r1,secp384r1, it should list 3: secp521r1,secp384r1,prime256v1

tycho commented

Yeah, I don't get why it doesn't. My Apache config is this right now:

SSLOpenSSLConfCmd ECDHParameters prime256v1
SSLOpenSSLConfCmd Curves X25519:secp521r1:secp384r1:prime256v1
SSLOpenSSLConfCmd DHParameters "/etc/ssl/dhparams-4096.pem"

Incidentally the OpenSSL version used in cipherscan doesn't recognize X25519, but that's kind of expected.

can you connect to that server using?:

openssl s_client -curves prime256v1 -connect hostname.example.com:443\
 -servername hostname.example.com

Also, I think that ECDHParameters and Curves conflict with each-other; only Curves should be used with new openssl (that ECDHParameters was necessary for 1.0.2, IIRC)

tycho commented

Yep, you're right. Curves takes precedence over ECDHParameters.

I get this, when explicitly setting the curve:

$ ./openssl s_client -curves prime256v1 -connect www.uplinklabs.net:443 -servername www.uplinklabs.net
WARNING: can't open config file: /usr/local/ssl/openssl.cnf
CONNECTED(00000003)
140571701110464:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:769:
[...]

That's presumably because the s_client -curves parameter imposes a restriction on the server key type as well (which in my case is a secp384r1 key)?

If I comment out the Curves line (I already removed ECDHParameters, so that's gone too), then cipherscan appears to be happier:

prio  ciphersuite                    protocols  pfs                 curves
1     ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2    ECDH,P-256,256bits  prime256v1,secp521r1,secp384r1
2     ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2    ECDH,P-256,256bits  prime256v1,secp521r1,secp384r1
3     ECDHE-ECDSA-AES256-SHA384      TLSv1.2    ECDH,P-256,256bits  prime256v1,secp521r1,secp384r1
4     ECDHE-ECDSA-AES128-SHA256      TLSv1.2    ECDH,P-256,256bits  prime256v1,secp521r1,secp384r1

I can also explicitly set the SSLOpenSSLConfCmd Curves line to prime256v1:secp521r1:secp384r1 and the output looks like the above. So apparently having prime256v1 listed last somehow prevents cipherscan from discovering it? That seems strange.

That's presumably because the s_client -curves parameter imposes a restriction on the server key type as well (which in my case is a secp384r1 key)?

I don't honestly remember, I did have discussion with openssl devels that this would be bad (as in, if that's your only cert, just send it, don't make a decision for the client, but if you have multiple certificates, pick the one that will fit the limits advertised in ClientHello), but don't remember what was the outcome, or when was it implemented

(also, that -curves sets what curves client advertises support for, it does not limit the ones it will accept for certs; in your example it's the server that refuses to process the connection)

I can also explicitly set the SSLOpenSSLConfCmd Curves line to prime256v1:secp521r1:secp384r1 and the output looks like the above.

then leave it as such :)
that shows that the server supports only the curves you listed in config, and those are the secure curves, so that's good, you may want to just add x25519 there and put the P-256 last

tycho commented

Why does listing prime256v1 last in Curves make it undiscoverable by cipherscan? It was already in the list at the end, but cipherscan only saw secp521r1,secp384r1 for some reason.

undiscoverable or unnegotiable?

are you able to negotiate P-256 when it's put last in server settings by manipulating -curves in s_client?

tycho commented

I don't know. The s_client test seems unable to tell us anything useful because I get this whenever I try using the -curves prime256v1 arguments, regardless of where the curve is placed in the curve list:

139995147781824:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:769:

The difference I've been observing is that when I place prime256v1 early in the curvelist, cipherscan discovers it, and when it's late in the curvelist, it doesn't.

tycho commented

Also, I just noticed something.

I have a few different certificates/keys on the same physical host with different hostnames. I noticed that one with an RSA4096 key discovers prime256v1 regardless of early/late position in the curve list:

prio  ciphersuite                  protocols  pfs                 curves
1     ECDHE-RSA-AES256-GCM-SHA384  TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1,prime256v1
2     ECDHE-RSA-AES128-GCM-SHA256  TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1,prime256v1
3     ECDHE-RSA-AES128-SHA256      TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1,prime256v1
4     ECDHE-RSA-AES256-SHA384      TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1,prime256v1

But on the hostname with the secp384r1 key, it doesn't if prime256v1 is late:

prio  ciphersuite                    protocols  pfs                 curves
1     ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1
2     ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1
3     ECDHE-ECDSA-AES256-SHA384      TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1
4     ECDHE-ECDSA-AES128-SHA256      TLSv1.2    ECDH,P-521,521bits  secp521r1,secp384r1

I don't know. The s_client test seems unable to tell us anything useful because I get this whenever I try using the -curves prime256v1 arguments, regardless of where the curve is placed in the curve list

that actually tells us that openssl still has the problematic behaviour, I'll file a bug for this

cipherscan can detect prime256v1 when it's early, because it sends all, and then starts removing them one by one based on what server picks

ah, so it's not fixed, see openssl/openssl#2237