-
-
Notifications
You must be signed in to change notification settings - Fork 33.4k
Description
- Version: 8.6.0 and 8.7.0 (works in 8.5.0)
- Platform: Windows 10 64 bit, MacOS High Sierra, all docker image variants
- Subsystem: https/crypto
Starting with node 8.6.0, whenever I try to make an https call to an nginx server that I'm running (be it through a library like request
or using https.request()
directly), I always get the following error:
Error: 101057795:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:openssl\ssl\s23_clnt.c:772
I'll admit up front that I'm not the most knowledgeable when it comes to security, but I'm able to talk to my server if I use node 8.5.0 (as well as several previous versions of node 6 and 8), all major web browsers and curl, so it seems like there's something special about more recent versions of node that's causing something strange to happen.
After some digging, I found that Node 8.5.0, Chrome, Firefox, and curl all communicate with my server using the ECDHE-RSA-AES256-GCM-SHA384
cipher, which is present on both the default list of TLS Ciphers and the list of ciphers my server accepts (see below).
However, when communicating using Node 8.6.0/8.7.0 and changing the accepted ciphers on the server to ALL
to get the request to complete, I see that cipher ends up being AES256-GCM-SHA384
instead. As far as I can tell (though I don't know much about SSL/TLS ciphers), the Node client and the nginx server are unable to agree on an ECDH curve, so ECDH is dropped from the cipher, which causes an impermissible cipher to be used (and subsequently rejected).
With that in mind, I'm also able to get the request to succeed with Node 8.7.0 if I drop the secp384r1
ECDH curve requirement from my nginx config, which drops it back to the default (auto
, I believe). When the ECDH curve requirement is removed, Node 8.7.0 completes the request using the same ECDHE-RSA-AES256-GCM-SHA384
cipher as everything else. So ultimately, this seems to be a change in the ECDH curves Node allows/supports.
Having poked around the commits that went into the 8.6.0 release, I believe this PR made the change that caused this scenario to break. What I'm less sure of is why that change broke it and whether support for the secp384r1
ECDH curve was removed intentionally or not. I'm not necessarily opposed to removing the secp384r1
configuration from my server, but I figure that it's probably best if I can follow the recommendations of https://cipherli.st/ if possible.
Thanks for your time and effort to look at this issue. I'd be more than happy to provide more information and/or test things out on my end. I would also love to help with a fix for this, but I'm afraid I'm not knowledgeable enough about security/crypto to really be able to understand what's going on at a code level.
For reference, here's the relevant information about the nginx server (most configuration is lifted from https://cipherli.st/):
- Version: openresty 1.11.2.5 (running from the openresty:1.11.2.5-xenial docker image)
- OpenSSL Version: 1.0.2
Configuration
http {
# ...
server {
# ...
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
}
}
When