cloudflare / sslconfig

Cloudflare's Internet facing SSL configuration
BSD 3-Clause "New" or "Revised" License
1.3k stars 132 forks source link

Browsers won't negotiate chacha20 #48

Closed zxcvbn4038 closed 7 years ago

zxcvbn4038 commented 7 years ago

I'm using Nginx + openresty/1.11.2.1 + OpenSSL 1.0.2j + Cloudflare dynamic TLS record size + Cloudflare chacha20 patch (updated for current openssl)

openssl -ciphers includes these:

ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-CHACHA20-POLY1305-D ECDHE-RSA-CHACHA20-POLY1305-D DHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305-D PSK-CHACHA20-POLY1305

My nginx ssl config is:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256'; ssl_prefer_server_ciphers on;

I can connect with openssl s_client:

openssl s_client -cipher ECDHE-RSA-CHACHA20-POLY1305 -debug -connect 127.0.0.1:443

However, if I omit the -cipher then it will only negotiate an AES cipher.

Chrome 53 and Firefox 49 both support ChaCha20 but will only negotiate AES ciphers.

If I disable everything but chacha20:

ssl_ciphers 'EECDH+CHACHA20:EECDH+CHACHA20-draft';

Then neither browser will negotiate a connection because there is no common cipher.

I haven't seen an issue like this discussed anywhere else, I'm not sure what the issue is.

leonklingele commented 7 years ago

https://github.com/cloudflare/sslconfig/blob/acc5f83b5fdf2ee28ad7f6b6530f4152f2883601/patches/openssl__chacha20_poly1305_draft_and_rfc_ossl102g.patch#L4941

zxcvbn4038 commented 7 years ago

@leonklingele Are you suggesting Cloudflare put that line in the patch so that browsers can't negotiate with it?

leonklingele commented 7 years ago

No, it looks like ChaCha20 only is used iff it's client's most preferred cipher suite. If your CPU has AES-NI support (and AES-NI is enabled), your browser will most likely prefer AES over ChaCha because in that case AES performs much faster.

leonklingele commented 7 years ago

If I disable everything but chacha20 [..] Then neither browser will negotiate a connection because there is no common cipher. Sorry, I missed that one! This indeed seems to be (a different) bug in the Cloudflare patch as it is simply ignoring all ChaCha ciphersuites, even if they're the only suites supported on server-side.

You can simply remove the ChaCha-client-preference check to enforce negotiation of a ChaCha ciphersuite if it is advertised by the client: https://github.com/cloudflare/sslconfig/blob/acc5f83b5fdf2ee28ad7f6b6530f4152f2883601/patches/openssl__chacha20_poly1305_draft_and_rfc_ossl102g.patch#L4933-L4963

IMO the Cloudflare patch should honor SSL_OP_CIPHER_SERVER_PREFERENCE (which gets set via ssl_prefer_server_ciphers on;)

zxcvbn4038 commented 7 years ago

@leonklingele I can do that if needed, my hesitation is that this isn't discussed anywhere and I can't be the only one using this patch, so question is if I've done something wrong, or if this is the same for everyone and nobody else has noticed that chacha20 isn't being negotiated.

vkrasnov commented 7 years ago

When we first developed the patch, it was specifically for the Chrome Mobile browsers. They would advertise the ChaCha ciphers first, and GCM second. For them we wanted to use ChaCha, for everyone else we wanted to use GCM. This is a very specific kind of cipher equivalence tailored for us. If you want the normal negotiation, simply discard the changes in _ssl3_choosecipher.

zxcvbn4038 commented 7 years ago

Ok, going to make those changes and rebuild.

zxcvbn4038 commented 7 years ago

@vkrasnov @leonklingele Ok, did a rebuild of openssl with the changes you specified. I restarted nginx and verified by /proc/pid/maps that the right library was loaded by inode number.

I ran the test script form here http://securityevaluators.com/knowledge/blog/20151102-openssl_and_ciphers/ and got this output:

tls1:   ECDHE-RSA-AES256-SHA
tls1:   AES256-SHA
tls1:   ECDHE-RSA-AES128-SHA
tls1:   AES128-SHA
tls1_1: ECDHE-RSA-AES256-SHA
tls1_1: AES256-SHA
tls1_1: ECDHE-RSA-AES128-SHA
tls1_1: AES128-SHA
tls1_2: ECDHE-RSA-AES256-GCM-SHA384
tls1_2: ECDHE-RSA-AES256-SHA384
tls1_2: ECDHE-RSA-AES256-SHA
tls1_2: ECDHE-RSA-CHACHA20-POLY1305
tls1_2: ECDHE-RSA-CHACHA20-POLY1305-D
tls1_2: AES256-GCM-SHA384
tls1_2: AES256-SHA256
tls1_2: AES256-SHA
tls1_2: ECDHE-RSA-AES128-GCM-SHA256
tls1_2: ECDHE-RSA-AES128-SHA256
tls1_2: ECDHE-RSA-AES128-SHA
tls1_2: AES128-GCM-SHA256
tls1_2: AES128-SHA256
tls1_2: AES128-SHA

However I was unable to get either the browser (Chrome/Firefox) to negotiate a connection - even if chacha20 was the only choice.

zxcvbn4038 commented 7 years ago

Could the problem be that Chrome/Firefox want to negotiate:

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

And all we are offering is:

ECDHE-RSA-CHACHA20-POLY1305

i.e. without the SHA256?

leonklingele commented 7 years ago

Strange. Are you sure you haven't statically compiled nginx with OpenSSL? Why don't you use an official (unpatched) version of OpenSSL? The ChaCha suites are supported by OpenSSL 1.1.0+

vkrasnov commented 7 years ago

All negotiation issues solved in 1.0.2j version of the patch.

zxcvbn4038 commented 7 years ago

@vkrasnov Confirmed that I can negotiate a connection with the 1.0.2j version. Thank you!