Given that this issue is related to Node.js, there is one simple method to deal with your issue without actually digging to much into it:
Put a web proxy in front of your Node.js process and let it handle the complete SSL connection. In the Node.js code itself, you would only send a request to a local HTTP server.
Example configuration with nginx (inside the http directive):
server {
listen 8080;
location / {
resolver 8.8.8.8;
proxy_pass https://www.howsmyssl.com$uri$is_args&args;
proxy_ssl_protocols TLSv1.2;
proxy_ssl_ciphers AESGCM:!aNULL;
}
}
And change the nodejs to:
var request = require('request');
var options = {
url: 'http://localhost:8080/a/check'
};
request(options, function (error, response, body){
if (!error) {
console.log(body);
}
else {
console.log(error);
}
});
Unfortunately though I actually did this, and the result was the same:
{"given_cipher_suites":["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_DH_DSS_WITH_AES_256_GCM_SHA384","TLS_DHE_DSS_WITH_AES_256_GCM_SHA384","TLS_DH_RSA_WITH_AES_256_GCM_SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_DH_DSS_WITH_AES_128_GCM_SHA256","TLS_DHE_DSS_WITH_AES_128_GCM_SHA256","TLS_DH_RSA_WITH_AES_128_GCM_SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_EMPTY_RENEGOTIATION_INFO_SCSV"],"ephemeral_keys_supported":true,"session_ticket_supported":true,"tls_compression_supported":false,"unknown_cipher_suite_supported":false,"beast_vuln":false,"able_to_detect_n_minus_one_splitting":false,"insecure_cipher_suites":{},"tls_version":"TLS 1.2","rating":"Probably Okay"}
This basically means that its probably standard OpenSSL behavior.
There are options which can be set in OpenSSL using SSL_CTX_set_options
Especially interesting here is the SECURE RENEGOTIATION section and this option:
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
Allow legacy insecure renegotiation between OpenSSL and unpatched clients or servers. See the SECURE RENEGOTIATION section for more details.
I am not certain though if this actually prevents the renegotiation cipher from being send.
If this option is actually correct, there might be a way to either patch Node.js to use that option or recompile OpenSSL with that option.
There would of course also be the option to use an old unpatched version.
From my understanding though TLS_EMPTY_RENEGOTIATION_INFO_SCSV
is not related to POODLE, but from an older fix:
CVE-2009-3555 (OpenSSL advisory) 5th November 2009:
Implement RFC5746 to address vulnerabilities in SSL/TLS renegotiation.
Fixed in OpenSSL 0.9.8m (Affected 0.9.8l, 0.9.8k, 0.9.8j, 0.9.8i, 0.9.8h, 0.9.8g, 0.9.8f, 0.9.8e, 0.9.8d, 0.9.8c, 0.9.8b, 0.9.8a, 0.9.8)
Modern Node.js comes with a statically linked OpenSSL however and does not support OpenSSL 0.9.8, so you would need an older version of Node.js regardless... or use the nginx stuff with an unpatched OpenSSL...
This is kind of where I am stuck.
Its not really an complete answer, but I think its at least worth to share.
To sum it up though, I think if you want to do this without recompiling use nginx with and unpatched OpenSSL, and configure multiple servers, one for each client you want to mimic.
If you require this to be soley done in node, your best bet is to patch OpenSSL there directly and recompile node.
{min-TLS,max-TLS}
version pair. Instead,TLS_FALLBACK_SCS
works over time, so it would apply with consecutive connections, and not a single connection attempt in a vacuum. – Interjoinrequest
npm module depends on Node.js'tls
package which handles the TLS connection via openssl. @Interjoin you may be right that it is insecure, however, I'd still like to disable it for a test case, and don't care about the security implications at this time. – Deweydewhirst