mirror of
https://github.com/nodejs/node-v0.x-archive.git
synced 2026-01-10 07:28:10 -05:00
tls,crypto: revert recent cipher lists changes
Revert "disable RC4, add --cipher-list command line switch" and "tls: make --enable-legacy-cipher-list=val less verbose" This reverts commitf9291a9449andb5737bb977. There is still some work to be done to guarantee secure defaults and a smooth upgrade path for v0.12.x users. Before this work is finished, we want to be able to release new versions of v0.12.x. So instead of waiting for these changes to be ready to ship, revert them and integrate them when they're ready to be shipped. Conflicts: src/node.cc Reviewed-By: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/joyent/node/pull/25296
This commit is contained in:
@@ -134,75 +134,6 @@ 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-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:
|
||||
!RC4:!MD5:!aNULL
|
||||
|
||||
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
|
||||
|
||||
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()
|
||||
|
||||
@@ -213,12 +144,6 @@ 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])
|
||||
|
||||
@@ -252,7 +177,7 @@ automatically set as a listener for the [secureConnection][] event. The
|
||||
prioritize the non-CBC cipher.
|
||||
|
||||
Defaults to
|
||||
`ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL`.
|
||||
`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.
|
||||
|
||||
@@ -262,7 +187,10 @@ automatically set as a listener for the [secureConnection][] event. The
|
||||
of OpenSSL. Note that it is still possible for a TLS v1.2 client
|
||||
to negotiate a weaker cipher unless `honorCipherOrder` is enabled.
|
||||
|
||||
`RC4` is explicitly switched off by default due to known vulnerabilities.
|
||||
`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.
|
||||
|
||||
**NOTE**: Previous revisions of this section suggested `AES256-SHA` as an
|
||||
acceptable cipher. Unfortunately, `AES256-SHA` is a CBC cipher and therefore
|
||||
|
||||
12
lib/tls.js
12
lib/tls.js
@@ -19,8 +19,6 @@
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
var _crypto = process.binding('crypto');
|
||||
|
||||
var net = require('net');
|
||||
var url = require('url');
|
||||
var util = require('util');
|
||||
@@ -35,14 +33,16 @@ exports.CLIENT_RENEG_WINDOW = 600;
|
||||
|
||||
exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024;
|
||||
|
||||
exports.DEFAULT_CIPHERS = _crypto.DEFAULT_CIPHER_LIST;
|
||||
|
||||
exports.getLegacyCiphers = _crypto.getLegacyCiphers;
|
||||
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_ECDH_CURVE = 'prime256v1';
|
||||
|
||||
exports.getCiphers = function() {
|
||||
var names = _crypto.getSSLCiphers();
|
||||
var names = process.binding('crypto').getSSLCiphers();
|
||||
// Drop all-caps names in favor of their lowercase aliases,
|
||||
var ctx = {};
|
||||
names.forEach(function(name) {
|
||||
|
||||
42
src/node.cc
42
src/node.cc
@@ -2936,9 +2936,6 @@ 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"
|
||||
" val = v0.10.38, v0.10.39, or v0.12.2\n"
|
||||
"\n"
|
||||
"Environment variables:\n"
|
||||
#ifdef _WIN32
|
||||
@@ -2956,9 +2953,6 @@ 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=val\n"
|
||||
" val = v0.10.38, v0.10.39, or v0.12.2\n"
|
||||
"\n"
|
||||
"Documentation can be found at http://nodejs.org/\n");
|
||||
}
|
||||
@@ -2998,7 +2992,6 @@ 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] == '-') {
|
||||
@@ -3054,20 +3047,6 @@ 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;
|
||||
@@ -3435,27 +3414,6 @@ 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.
|
||||
|
||||
13
src/node.h
13
src/node.h
@@ -223,19 +223,6 @@ NODE_EXTERN void RunAtExit(Environment* env);
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define NODE_DEFINE_STRING_CONSTANT(target, constant) \
|
||||
do { \
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent(); \
|
||||
v8::Local<v8::String> constant_name = \
|
||||
v8::String::NewFromUtf8(isolate, #constant); \
|
||||
v8::Local<v8::String> constant_value = \
|
||||
v8::String::NewFromUtf8(isolate, constant); \
|
||||
v8::PropertyAttribute constant_attributes = \
|
||||
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); \
|
||||
(target)->ForceSet(constant_name, constant_value, constant_attributes); \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Used to be a macro, hence the uppercase name.
|
||||
template <typename TypeName>
|
||||
inline void NODE_SET_METHOD(const TypeName& recv,
|
||||
|
||||
@@ -77,7 +77,6 @@ namespace node {
|
||||
|
||||
bool SSL2_ENABLE = false;
|
||||
bool SSL3_ENABLE = false;
|
||||
const char * DEFAULT_CIPHER_LIST = DEFAULT_CIPHER_LIST_HEAD;
|
||||
|
||||
namespace crypto {
|
||||
|
||||
@@ -4852,26 +4851,6 @@ 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 : "<string conversion failed>";
|
||||
}
|
||||
|
||||
void DefaultCiphers(const v8::FunctionCallbackInfo<v8::Value>& 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<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
||||
@@ -5192,8 +5171,6 @@ void InitCrypto(Handle<Object> 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
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include "v8.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdh.h>
|
||||
@@ -60,40 +59,10 @@
|
||||
# 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_HEAD "ECDHE-RSA-AES128-SHA256:" \
|
||||
"DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:"\
|
||||
"!RC4:!MD5:!aNULL"
|
||||
|
||||
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 {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
namespace node {
|
||||
|
||||
extern bool SSL2_ENABLE;
|
||||
extern bool SSL3_ENABLE;
|
||||
extern const char * DEFAULT_CIPHER_LIST;
|
||||
|
||||
namespace crypto {
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
// 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'].forEach(function(ver) {
|
||||
doTest(tls.getLegacyCiphers(ver), ver, 2);
|
||||
doTest(tls.getLegacyCiphers(ver), ver, 3);
|
||||
});
|
||||
@@ -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[1]);
|
||||
assert.equal(cipher.name, cipher_list[0]);
|
||||
assert(cipher_version_pattern.test(cipher.version));
|
||||
client.end();
|
||||
server.close();
|
||||
|
||||
Reference in New Issue
Block a user