From 1b1fe536557184731123c1054a0b6146737d0ed7 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 30 Mar 2015 09:56:01 -0700 Subject: [PATCH 1/5] tls: more secure defaults Port of io.js commit: https://github.com/iojs/io.js/commit/77f35861d0217273b9e478f5d35bd7d8e47 Original commit message: This updates the default cipher suite to an more secure list, which prefers strong ciphers with Forward Secrecy. Additionally, it enables `honorCipherOrder` by default. Noteable effect of this change is that the insecure RC4 ciphers are disabled and that Chrome negotiates a more secure ECDHE cipher. Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny PR-URL: https://github.com/iojs/io.js/pull/826 --- doc/api/tls.markdown | 44 +++++++++++++------------------ lib/_tls_wrap.js | 6 ++--- lib/tls.js | 23 ++++++++++++---- test/simple/test-tls-dhe.js | 1 + test/simple/test-tls-getcipher.js | 2 +- 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index 410d88300c8e..ab4656a9eedc 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -25,8 +25,10 @@ To create a self-signed certificate with the CSR, do this: Alternatively you can send the CSR to a Certificate Authority for signing. -(TODO: docs on creating a CA, for now interested users should just look at -`test/fixtures/keys/Makefile` in the Node source code) +For Perfect Forward Secrecy, it is required to generate Diffie-Hellman +parameters: + + openssl dhparam -outform PEM -out dhparam.pem 2048 To create .pfx or .p12, do this: @@ -170,31 +172,20 @@ automatically set as a listener for the [secureConnection][] event. The - `crl` : Either a string or list of strings of PEM encoded CRLs (Certificate Revocation List) - - `ciphers`: A string describing the ciphers to use or exclude. - - To mitigate [BEAST attacks] it is recommended that you use this option in - conjunction with the `honorCipherOrder` option described below to - prioritize the non-CBC cipher. - - Defaults to - `ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL`. - Consult the [OpenSSL cipher list format documentation] for details - on the format. - - `ECDHE-RSA-AES128-SHA256`, `DHE-RSA-AES128-SHA256` and - `AES128-GCM-SHA256` are TLS v1.2 ciphers and used when node.js is - linked against OpenSSL 1.0.1 or newer, such as the bundled version - of OpenSSL. Note that it is still possible for a TLS v1.2 client - to negotiate a weaker cipher unless `honorCipherOrder` is enabled. + - `ciphers`: A string describing the ciphers to use or exclude, separated by + `:`. The default cipher suite is: - `RC4` is used as a fallback for clients that speak on older version of - the TLS protocol. `RC4` has in recent years come under suspicion and - should be considered compromised for anything that is truly sensitive. - It is speculated that state-level actors possess the ability to break it. + ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256: + DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256: + HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA - **NOTE**: Previous revisions of this section suggested `AES256-SHA` as an - acceptable cipher. Unfortunately, `AES256-SHA` is a CBC cipher and therefore - susceptible to [BEAST attacks]. Do *not* use it. + The default cipher suite prefers ECDHE and DHE ciphers for Perfect Forward + secrecy, while offering *some* backward compatibility. Old clients which + rely on insecure and deprecated RC4 or DES-based ciphers (like Internet + Explorer 6) aren't able to complete the handshake with the default + configuration. If you absolutely must support these clients, the + [TLS recommendations] may offer a compatible cipher suite. For more details + on the format, see the [OpenSSL cipher list format documentation]. - `ecdhCurve`: A string describing a named curve to use for ECDH key agreement or false to disable ECDH. @@ -212,7 +203,7 @@ automatically set as a listener for the [secureConnection][] event. The times out. - `honorCipherOrder` : When choosing a cipher, use the server's preferences - instead of the client preferences. + instead of the client preferences. Default: `true`. Although, this option is disabled by default, it is *recommended* that you use this option in conjunction with the `ciphers` option to mitigate @@ -853,5 +844,6 @@ The numeric representation of the local port. [ECDHE]: https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman [asn1.js]: http://npmjs.org/package/asn1.js [OCSP request]: http://en.wikipedia.org/wiki/OCSP_stapling +[TLS recommendations]: https://wiki.mozilla.org/Security/Server_Side_TLS [SSL_CTX_set_options]: https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html [CVE-2014-3566]: https://access.redhat.com/articles/1232123 diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index f4ee762eed4d..378f6053278c 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -735,10 +735,10 @@ Server.prototype.setOptions = function(options) { secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE; } - if (options.honorCipherOrder) - this.honorCipherOrder = true; + if (options.honorCipherOrder !== undefined) + this.honorCipherOrder = !!options.honorCipherOrder; else - this.honorCipherOrder = false; + this.honorCipherOrder = true; this.secureOptions = secureOptions; diff --git a/lib/tls.js b/lib/tls.js index 7aad494b1e0d..58f80bba8b12 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -35,11 +35,24 @@ exports.CLIENT_RENEG_WINDOW = 600; exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024; -exports.DEFAULT_CIPHERS = - // TLS 1.2 - 'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' + - // TLS 1.0 - 'RC4:HIGH:!MD5:!aNULL'; +exports.DEFAULT_CIPHERS = [ + 'ECDHE-RSA-AES256-SHA384', + 'DHE-RSA-AES256-SHA384', + 'ECDHE-RSA-AES256-SHA256', + 'DHE-RSA-AES256-SHA256', + 'ECDHE-RSA-AES128-SHA256', + 'DHE-RSA-AES128-SHA256', + 'HIGH', + '!aNULL', + '!eNULL', + '!EXPORT', + '!DES', + '!RC4', + '!MD5', + '!PSK', + '!SRP', + '!CAMELLIA' +].join(':'); exports.DEFAULT_ECDH_CURVE = 'prime256v1'; diff --git a/test/simple/test-tls-dhe.js b/test/simple/test-tls-dhe.js index 3975c5ed40a3..8844f8527998 100644 --- a/test/simple/test-tls-dhe.js +++ b/test/simple/test-tls-dhe.js @@ -47,6 +47,7 @@ function test(keylen, expectedCipher, cb) { var options = { key: key, cert: cert, + ciphers: ciphers, dhparam: loadDHParam(keylen) }; diff --git a/test/simple/test-tls-getcipher.js b/test/simple/test-tls-getcipher.js index 22a280e58743..8fb9d528731d 100644 --- a/test/simple/test-tls-getcipher.js +++ b/test/simple/test-tls-getcipher.js @@ -49,7 +49,7 @@ server.listen(common.PORT, '127.0.0.1', function() { rejectUnauthorized: false }, function() { var cipher = client.getCipher(); - assert.equal(cipher.name, cipher_list[0]); + assert.equal(cipher.name, cipher_list[1]); assert(cipher_version_pattern.test(cipher.version)); client.end(); server.close(); From 12c3a57e53cd7514e4206d0cbe67b9a3405a5614 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 2 Apr 2015 16:21:03 -0700 Subject: [PATCH 2/5] tls: command-line switch and envar cipher-list override Add command line switches and environment variables to override the default cipher suite in tls.js `--cipher-list` and `NODE_CIPHER_LIST` can be used to completely override the default cipher list with a given value. `--enable-legacy-cipher-list` and `NODE_LEGACY_CIPHER_LIST` can be used to reset the default cipher list back to a known legacy value shipped in prior Node.js releases A new `getLegacyCiphers` method on the tis module allows programmatic access to the old cipher list defaults. --- doc/api/tls.markdown | 81 +++++++++++++++++++++++++++++ lib/tls.js | 25 +++------ src/node.cc | 47 +++++++++++++++++ src/node.h | 12 +++++ src/node_crypto.cc | 23 ++++++++ src/node_crypto.h | 42 +++++++++++++++ test/simple/test-tls-cipher-list.js | 69 ++++++++++++++++++++++++ 7 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 test/simple/test-tls-cipher-list.js diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index ab4656a9eedc..fb4533076da6 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -136,6 +136,81 @@ the character "E" appended to the traditional abbreviations): Ephemeral methods may have some performance drawbacks, because key generation is expensive. +## Modifying the Default Cipher Suite + +Node.js is built with a default suite of enabled and disabled ciphers. +Currently, the default cipher suite is: + + ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256: + DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256: + HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA + +This default can be overridden entirely using the `--cipher-list` command line +switch or `NODE_CIPHER_LIST` environment variable. For instance: + + node --cipher-list=ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384 + +Setting the environment variable would have the same effect: + + NODE_CIPHER_LIST=ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384 + +CAUTION: The default cipher suite has been carefully selected to reflect current +security best practices and risk mitigation. Changing the default cipher suite +can have a significant impact on the security of an application. The +`--cipher-list` and `NODE_CIPHER_LIST` options should only be used if +absolutely necessary. + +### Using Legacy Default Cipher Suite ### + +It is possible for the built-in default cipher suite to change from one release +of Node.js to another. For instance, v0.10.38 uses a different default than +v0.12.2. Such changes can cause issues with applications written to assume +certain specific defaults. To help buffer applications against such changes, +the `--enable-legacy-cipher-list` command line switch or `NODE_LEGACY_CIPHER_LIST` +environment variable can be set to specify a specific preset default: + + # Use the v0.10.38 defaults + node --enable-legacy-cipher-list=v0.10.38 + // or + NODE_LEGACY_CIPHER_LIST=v0.10.38 + + # Use the v0.12.2 defaults + node --enable-legacy-cipher-list=v0.12.2 + // or + NODE_LEGACY_CIPHER_LIST=v0.12.2 + +Currently, the values supported for the `enable-legacy-cipher-list` switch and +`NODE_LEGACY_CIPHER_LIST` environment variable include: + + v0.10.38 - To enable the default cipher suite used in v0.10.38 + + ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH + + v0.10.39 - To enable the default cipher suite used in v0.10.39 + + ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH + + v0.12.2 - To enable the default cipher suite used in v0.12.2 + + ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4: + HIGH:!MD5:!aNULL + + v.0.12.3 - To enable the default cipher suite used in v0.12.3 + + ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH: + !RC4:!MD5:!aNULL + +These legacy cipher suites are also made available for use via the +`getLegacyCiphers()` method: + + var tls = require('tls'); + console.log(tls.getLegacyCiphers('v0.10.38')); + +CAUTION: Changes to the default cipher suite are typically made in order to +strengthen the default security for applications running within Node.js. +Reverting back to the defaults used by older releases can weaken the security +of your applications. The legacy cipher suites should only be used if absolutely +necessary. ## tls.getCiphers() @@ -146,6 +221,12 @@ Example: var ciphers = tls.getCiphers(); console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...] +## tls.getLegacyCiphers(version) + +Returns the legacy default cipher suite for the specified Node.js release. + +Example: + var cipher_suite = tls.getLegacyCiphers('v0.10.38'); ## tls.createServer(options[, secureConnectionListener]) diff --git a/lib/tls.js b/lib/tls.js index 58f80bba8b12..aebafc1bd936 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -21,6 +21,8 @@ 'use strict'; +var _crypto = process.binding('crypto'); + var net = require('net'); var url = require('url'); var util = require('util'); @@ -35,29 +37,14 @@ exports.CLIENT_RENEG_WINDOW = 600; exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024; -exports.DEFAULT_CIPHERS = [ - 'ECDHE-RSA-AES256-SHA384', - 'DHE-RSA-AES256-SHA384', - 'ECDHE-RSA-AES256-SHA256', - 'DHE-RSA-AES256-SHA256', - 'ECDHE-RSA-AES128-SHA256', - 'DHE-RSA-AES128-SHA256', - 'HIGH', - '!aNULL', - '!eNULL', - '!EXPORT', - '!DES', - '!RC4', - '!MD5', - '!PSK', - '!SRP', - '!CAMELLIA' -].join(':'); +exports.DEFAULT_CIPHERS = _crypto.DEFAULT_CIPHER_LIST; exports.DEFAULT_ECDH_CURVE = 'prime256v1'; +exports.getLegacyCiphers = _crypto.getLegacyCiphers; + exports.getCiphers = function() { - var names = process.binding('crypto').getSSLCiphers(); + var names = _crypto.getSSLCiphers(); // Drop all-caps names in favor of their lowercase aliases, var ctx = {}; names.forEach(function(name) { diff --git a/src/node.cc b/src/node.cc index c8dfe041214f..f34af73bfa38 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2929,6 +2929,12 @@ static void PrintHelp() { #endif " --enable-ssl2 enable ssl2\n" " --enable-ssl3 enable ssl3\n" + " --cipher-list=val specify the default TLS cipher list\n" + " --enable-legacy-cipher-list=val \n" + " set to v0.10.38 to use the v0.10.38 list,\n" + " set to v0.10.39 to use the v0.10.39 list.\n" + " set to v0.12.2 to use the v0.12.2 list.\n" + " set to v0.12.3 to use the v0.12.3 list.\n" "\n" "Environment variables:\n" #ifdef _WIN32 @@ -2946,6 +2952,12 @@ static void PrintHelp() { " (will extend linked-in data)\n" #endif #endif + "NODE_CIPHER_LIST Override the default TLS cipher list\n" + "NODE_LEGACY_CIPHER_LIST\n" + " Set to v0.10.38 to use the v0.10.38 list,\n" + " Set to v0.10.39 to use the v0.10.39 list.\n" + " Set to v0.12.2 to use the v0.12.2 list.\n" + " Set to v0.12.3 to use the v0.12.3 list.\n" "\n" "Documentation can be found at http://nodejs.org/\n"); } @@ -2985,6 +2997,7 @@ static void ParseArgs(int* argc, unsigned int new_argc = 1; new_v8_argv[0] = argv[0]; new_argv[0] = argv[0]; + bool using_legacy_cipher_list = false; unsigned int index = 1; while (index < nargs && argv[index][0] == '-') { @@ -3040,6 +3053,20 @@ static void ParseArgs(int* argc, } else if (strcmp(arg, "--v8-options") == 0) { new_v8_argv[new_v8_argc] = "--help"; new_v8_argc += 1; + } else if (strncmp(arg, "--cipher-list=", 14) == 0) { + if (!using_legacy_cipher_list) { + DEFAULT_CIPHER_LIST = arg + 14; + } + } else if (strncmp(arg, "--enable-legacy-cipher-list=", 28) == 0) { + // use the original v0.10.x/v0.12.x cipher lists + const char * legacy_list = legacy_cipher_list(arg+28); + if (legacy_list != NULL) { + using_legacy_cipher_list = true; + DEFAULT_CIPHER_LIST = legacy_list; + } else { + fprintf(stderr, "Error: An unknown legacy cipher list was specified\n"); + exit(9); + } #if defined(NODE_HAVE_I18N_SUPPORT) } else if (strncmp(arg, "--icu-data-dir=", 15) == 0) { icu_data_dir = arg + 15; @@ -3402,6 +3429,26 @@ void Init(int* argc, } } + const char * cipher_list = getenv("NODE_CIPHER_LIST"); + if (cipher_list != NULL) { + DEFAULT_CIPHER_LIST = cipher_list; + } + // Allow the NODE_LEGACY_CIPHER_LIST envar to override the other + // cipher list options. NODE_LEGACY_CIPHER_LIST=v0.10.38 will use + // the cipher list from v0.10.38, NODE_LEGACY_CIPHER_LIST=v0.12.2 will + // use the cipher list from v0.12.2 + const char * leg_cipher_id = getenv("NODE_LEGACY_CIPHER_LIST"); + if (leg_cipher_id != NULL) { + const char * leg_cipher_list = + legacy_cipher_list(leg_cipher_id); + if (leg_cipher_list != NULL) { + DEFAULT_CIPHER_LIST = leg_cipher_list; + } else { + fprintf(stderr, "Error: An unknown legacy cipher list was specified\n"); + exit(9); + } + } + #if defined(NODE_HAVE_I18N_SUPPORT) if (icu_data_dir == NULL) { // if the parameter isn't given, use the env variable. diff --git a/src/node.h b/src/node.h index 38356ac44fe0..9e11c5c3bd29 100644 --- a/src/node.h +++ b/src/node.h @@ -223,6 +223,18 @@ NODE_EXTERN void RunAtExit(Environment* env); } \ while (0) +#define NODE_DEFINE_STRING_CONSTANT(target, constant) \ + do { \ + v8::Isolate* isolate = v8::Isolate::GetCurrent(); \ + v8::Local constant_name = \ + v8::String::NewFromUtf8(isolate, #constant); \ + v8::Local constant_value = \ + v8::String::NewFromUtf8(isolate, constant); \ + v8::PropertyAttribute constant_attributes = \ + static_cast(v8::ReadOnly | v8::DontDelete); \ + (target)->ForceSet(constant_name, constant_value, constant_attributes); \ + } while (0) + // Used to be a macro, hence the uppercase name. template inline void NODE_SET_METHOD(const TypeName& recv, diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 03650a98c61f..327bfce13159 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -77,6 +77,7 @@ namespace node { bool SSL2_ENABLE = false; bool SSL3_ENABLE = false; +const char * DEFAULT_CIPHER_LIST = DEFAULT_CIPHER_LIST_HEAD; namespace crypto { @@ -4851,6 +4852,26 @@ static void array_push_back(const TypeName* md, ctx->arr->Set(ctx->arr->Length(), OneByteString(ctx->env()->isolate(), from)); } +// borrowed from v8 +// (see http://v8.googlecode.com/svn/trunk/samples/shell.cc) +const char* ToCString(const String::Utf8Value& value) { + return *value ? *value : ""; +} + +void DefaultCiphers(const v8::FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args.GetIsolate()); + HandleScope scope(env->isolate()); + v8::String::Utf8Value key(args[0]); + const char * list = legacy_cipher_list(ToCString(key)); + if (list != NULL) { + args.GetReturnValue().Set( + v8::String::NewFromUtf8(args.GetIsolate(), list)); + } else { + args.GetReturnValue().Set( + v8::String::NewFromUtf8(args.GetIsolate(), + DEFAULT_CIPHER_LIST_HEAD)); + } +} void GetCiphers(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); @@ -5171,6 +5192,8 @@ void InitCrypto(Handle target, NODE_DEFINE_CONSTANT(target, SSL3_ENABLE); NODE_DEFINE_CONSTANT(target, SSL2_ENABLE); + NODE_DEFINE_STRING_CONSTANT(target, DEFAULT_CIPHER_LIST); + NODE_SET_METHOD(target, "getLegacyCiphers", DefaultCiphers); } } // namespace crypto diff --git a/src/node_crypto.h b/src/node_crypto.h index 0a4c34a1f338..fde33f374fa7 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -38,6 +38,7 @@ #include "v8.h" +#include #include #include #include @@ -59,10 +60,51 @@ # define NODE__HAVE_TLSEXT_STATUS_CB #endif // !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) +#define DEFAULT_CIPHER_LIST_V10_38 "ECDHE-RSA-AES128-SHA256:" \ + "AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH" + +#define DEFAULT_CIPHER_LIST_V10_39 "ECDHE-RSA-AES128-SHA256:" \ + "AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH" + +#define DEFAULT_CIPHER_LIST_V12_2 "ECDHE-RSA-AES128-SHA256:" \ + "DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:" \ + "HIGH:!MD5:!aNULL" + +#define DEFAULT_CIPHER_LIST_V12_3 "ECDHE-RSA-AES128-SHA256:" \ + "DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:"\ + "!RC4:!MD5:!aNULL" + +#define DEFAULT_CIPHER_LIST_HEAD "ECDHE-RSA-AES256-SHA384:" \ + "DHE-RSA-AES256-SHA384:" \ + "ECDHE-RSA-AES256-SHA256:" \ + "DHE-RSA-AES256-SHA256:" \ + "ECDHE-RSA-AES128-SHA256:" \ + "DHE-RSA-AES128-SHA256:" \ + "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:" \ + "!PSK:!SRP:!CAMELLIA" + +static inline const char * legacy_cipher_list(const char * ver) { + if (ver == NULL) { + return NULL; + } + if (strncmp(ver, "v0.10.38", 8) == 0) { + return DEFAULT_CIPHER_LIST_V10_38; + } else if (strncmp(ver, "v0.10.39", 8) == 0) { + return DEFAULT_CIPHER_LIST_V10_39; + } else if (strncmp(ver, "v0.12.2", 7) == 0) { + return DEFAULT_CIPHER_LIST_V12_2; + } else if (strncmp(ver, "v0.12.3", 7) == 0) { + return DEFAULT_CIPHER_LIST_V12_3; + } else { + return NULL; + } +} + namespace node { extern bool SSL2_ENABLE; extern bool SSL3_ENABLE; +extern const char * DEFAULT_CIPHER_LIST; namespace crypto { diff --git a/test/simple/test-tls-cipher-list.js b/test/simple/test-tls-cipher-list.js new file mode 100644 index 000000000000..38f6f02cda53 --- /dev/null +++ b/test/simple/test-tls-cipher-list.js @@ -0,0 +1,69 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var spawn = require('child_process').spawn; +var assert = require('assert'); +var tls = require('tls'); + +function doTest(checklist, env, useswitch) { + var options; + if (env && useswitch === 1) { + options = {env:env}; + } + var args = ['-e', 'console.log(require(\'tls\').DEFAULT_CIPHERS)']; + + switch(useswitch) { + case 1: + // Test --cipher-test + args.unshift('--cipher-list=' + env); + break; + case 2: + // Test --enable-legacy-cipher-list + args.unshift('--enable-legacy-cipher-list=' + env); + break; + case 3: + // Test NODE_LEGACY_CIPHER_LIST + if (env) options = {env:{"NODE_LEGACY_CIPHER_LIST": env}}; + break; + default: + // Test NODE_CIPHER_LIST + if (env) options = {env:env}; + } + + var out = ''; + spawn(process.execPath, args, options). + stdout. + on('data', function(data) { + out += data; + }). + on('end', function() { + assert.equal(out.trim(), checklist); + }); +} + +doTest(tls.DEFAULT_CIPHERS); // test the default +doTest('ABC', {'NODE_CIPHER_LIST':'ABC'}); // test the envar +doTest('ABC', 'ABC', 1); // test the --cipher-list switch + +['v0.10.38', 'v0.10.39', 'v0.12.2', 'v0.12.3'].forEach(function(ver) { + doTest(tls.getLegacyCiphers(ver), ver, 2); + doTest(tls.getLegacyCiphers(ver), ver, 3); +}); From 9329464299363a99b63ef378c3ab478a172d3099 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 6 Apr 2015 11:39:09 -0700 Subject: [PATCH 3/5] tls: make --enable-legacy-cipher-list less verbose Based on commit feedback, make the PrintHelp for --enable-legacy-cipher-list less verbose. --- src/node.cc | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/node.cc b/src/node.cc index f34af73bfa38..f1fb749b5afc 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2931,10 +2931,7 @@ static void PrintHelp() { " --enable-ssl3 enable ssl3\n" " --cipher-list=val specify the default TLS cipher list\n" " --enable-legacy-cipher-list=val \n" - " set to v0.10.38 to use the v0.10.38 list,\n" - " set to v0.10.39 to use the v0.10.39 list.\n" - " set to v0.12.2 to use the v0.12.2 list.\n" - " set to v0.12.3 to use the v0.12.3 list.\n" + " val = v0.10.38, v0.10.39, v0.12.2 or v0.12.3\n" "\n" "Environment variables:\n" #ifdef _WIN32 @@ -2953,11 +2950,8 @@ static void PrintHelp() { #endif #endif "NODE_CIPHER_LIST Override the default TLS cipher list\n" - "NODE_LEGACY_CIPHER_LIST\n" - " Set to v0.10.38 to use the v0.10.38 list,\n" - " Set to v0.10.39 to use the v0.10.39 list.\n" - " Set to v0.12.2 to use the v0.12.2 list.\n" - " Set to v0.12.3 to use the v0.12.3 list.\n" + "NODE_LEGACY_CIPHER_LIST=val\n" + " val = v0.10.38, v0.10.39, v0.12.2 or v0.12.3\n" "\n" "Documentation can be found at http://nodejs.org/\n"); } From 09160f572153327ee5cf9372e42312e3a11ac484 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 6 Apr 2015 11:47:21 -0700 Subject: [PATCH 4/5] tls: pass in isolate with define string constant + style nits Per the commit feedback, fix up style nits and pass in the isolate with the NODE_DEFINE_STRING_CONSTANT macro. --- src/node.h | 3 +-- src/node_crypto.cc | 3 ++- src/node_crypto.h | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/node.h b/src/node.h index 9e11c5c3bd29..e42713b5ba61 100644 --- a/src/node.h +++ b/src/node.h @@ -223,9 +223,8 @@ NODE_EXTERN void RunAtExit(Environment* env); } \ while (0) -#define NODE_DEFINE_STRING_CONSTANT(target, constant) \ +#define NODE_DEFINE_STRING_CONSTANT(isolate, target, constant) \ do { \ - v8::Isolate* isolate = v8::Isolate::GetCurrent(); \ v8::Local constant_name = \ v8::String::NewFromUtf8(isolate, #constant); \ v8::Local constant_value = \ diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 327bfce13159..143e09f1d299 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -5192,7 +5192,8 @@ void InitCrypto(Handle target, NODE_DEFINE_CONSTANT(target, SSL3_ENABLE); NODE_DEFINE_CONSTANT(target, SSL2_ENABLE); - NODE_DEFINE_STRING_CONSTANT(target, DEFAULT_CIPHER_LIST); + + NODE_DEFINE_STRING_CONSTANT(env->isolate(), target, DEFAULT_CIPHER_LIST); NODE_SET_METHOD(target, "getLegacyCiphers", DefaultCiphers); } diff --git a/src/node_crypto.h b/src/node_crypto.h index fde33f374fa7..b9f266f75fd9 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -74,13 +74,13 @@ "DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:"\ "!RC4:!MD5:!aNULL" -#define DEFAULT_CIPHER_LIST_HEAD "ECDHE-RSA-AES256-SHA384:" \ - "DHE-RSA-AES256-SHA384:" \ - "ECDHE-RSA-AES256-SHA256:" \ - "DHE-RSA-AES256-SHA256:" \ - "ECDHE-RSA-AES128-SHA256:" \ - "DHE-RSA-AES128-SHA256:" \ - "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:" \ +#define DEFAULT_CIPHER_LIST_HEAD "ECDHE-RSA-AES256-SHA384:" \ + "DHE-RSA-AES256-SHA384:" \ + "ECDHE-RSA-AES256-SHA256:" \ + "DHE-RSA-AES256-SHA256:" \ + "ECDHE-RSA-AES128-SHA256:" \ + "DHE-RSA-AES128-SHA256:" \ + "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:" \ "!PSK:!SRP:!CAMELLIA" static inline const char * legacy_cipher_list(const char * ver) { From a9f8196d01f807af8abec1bf54ed3cf8e8246c66 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 8 Apr 2015 12:23:38 -0700 Subject: [PATCH 5/5] test: fixing a few nits in the test typo and unnecessary options init --- test/simple/test-tls-cipher-list.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/simple/test-tls-cipher-list.js b/test/simple/test-tls-cipher-list.js index 38f6f02cda53..8e54d8d36a41 100644 --- a/test/simple/test-tls-cipher-list.js +++ b/test/simple/test-tls-cipher-list.js @@ -25,14 +25,11 @@ var tls = require('tls'); function doTest(checklist, env, useswitch) { var options; - if (env && useswitch === 1) { - options = {env:env}; - } var args = ['-e', 'console.log(require(\'tls\').DEFAULT_CIPHERS)']; switch(useswitch) { case 1: - // Test --cipher-test + // Test --cipher-list args.unshift('--cipher-list=' + env); break; case 2: