Skip to content

SSL Handshake Error using node >= 8.6.0 #16196

@princjef

Description

@princjef
  • 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionIssues that look for answers.tlsIssues and PRs related to the tls subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions