* SNI - to use one TLS server for multiple hostnames with different SSL
certificates.
+## Modifying the Default TLS Cipher suite
+
+Node.js is built with a default suite of enabled and disabled TLS ciphers.
+Currently, the default cipher suite is:
+
+ ECDHE-RSA-AES128-GCM-SHA256:
+ ECDHE-ECDSA-AES128-GCM-SHA256:
+ ECDHE-RSA-AES256-GCM-SHA384:
+ ECDHE-ECDSA-AES256-GCM-SHA384:
+ DHE-RSA-AES128-GCM-SHA256:
+ ECDHE-RSA-AES128-SHA256:
+ DHE-RSA-AES128-SHA256:
+ ECDHE-RSA-AES256-SHA384:
+ DHE-RSA-AES256-SHA384:
+ ECDHE-RSA-AES256-SHA256:
+ DHE-RSA-AES256-SHA256:
+ HIGH:
+ !aNULL:
+ !eNULL:
+ !EXPORT:
+ !DES:
+ !RC4:
+ !MD5:
+ !PSK:
+ !SRP:
+ !CAMELLIA
+
+This default can be overriden entirely using the `--tls-cipher-list` command
+line switch. For instance, the following makes
+`ECDHE-RSA-AES128-GCM-SHA256:!RC4` the default TLS cipher suite:
+
+ node --tls-cipher-list="ECDHE-RSA-AES128-GCM-SHA256:!RC4"
+
+Note that the default cipher suite included within Node.js 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 `--tls-cipher-list` switch should by used only if
+absolutely necessary.
## Perfect Forward Secrecy
- `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, seperated by
+ - `ciphers`: A string describing the ciphers to use or exclude, separated by
`:`. The default cipher suite is:
ECDHE-RSA-AES128-GCM-SHA256:
--v8-options print v8 command line options
+ --tls-cipher-list=list use an alternative default TLS cipher list
+ (available only when Node.js is built with
+ OpenSSL and crypto support enabled)
.SH ENVIRONMENT VARIABLES
const util = require('util');
const binding = process.binding('crypto');
const Buffer = require('buffer').Buffer;
+const constants = require('constants');
// Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations
// every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more
exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024;
-exports.DEFAULT_CIPHERS = [
- 'ECDHE-RSA-AES128-GCM-SHA256',
- 'ECDHE-ECDSA-AES128-GCM-SHA256',
- 'ECDHE-RSA-AES256-GCM-SHA384',
- 'ECDHE-ECDSA-AES256-GCM-SHA384',
- 'DHE-RSA-AES128-GCM-SHA256',
- 'ECDHE-RSA-AES128-SHA256',
- 'DHE-RSA-AES128-SHA256',
- 'ECDHE-RSA-AES256-SHA384',
- 'DHE-RSA-AES256-SHA384',
- 'ECDHE-RSA-AES256-SHA256',
- 'DHE-RSA-AES256-SHA256',
- 'HIGH',
- '!aNULL',
- '!eNULL',
- '!EXPORT',
- '!DES',
- '!RC4',
- '!MD5',
- '!PSK',
- '!SRP',
- '!CAMELLIA'
-].join(':');
+exports.DEFAULT_CIPHERS = constants.defaultCipherList;
exports.DEFAULT_ECDH_CURVE = 'prime256v1';
" --track-heap-objects track heap object allocations for heap "
"snapshots\n"
" --v8-options print v8 command line options\n"
+#if HAVE_OPENSSL
+ " --tls-cipher-list=val use an alternative default TLS cipher list\n"
+#endif
#if defined(NODE_HAVE_I18N_SUPPORT)
" --icu-data-dir=dir set ICU data load path to dir\n"
" (overrides NODE_ICU_DATA)\n"
} else if (strcmp(arg, "--v8-options") == 0) {
new_v8_argv[new_v8_argc] = "--help";
new_v8_argc += 1;
+#if HAVE_OPENSSL
+ } else if (strncmp(arg, "--tls-cipher-list=", 18) == 0) {
+ default_cipher_list = arg + 18;
+#endif
#if defined(NODE_HAVE_I18N_SUPPORT)
} else if (strncmp(arg, "--icu-data-dir=", 15) == 0) {
icu_data_dir = arg + 15;
using v8::Handle;
using v8::Object;
+#if HAVE_OPENSSL
+const char* default_cipher_list = DEFAULT_CIPHER_LIST_CORE;
+#endif
+
void DefineErrnoConstants(Handle<Object> target) {
#ifdef E2BIG
NODE_DEFINE_CONSTANT(target, E2BIG);
NODE_DEFINE_CONSTANT(target, UV_UDP_REUSEADDR);
}
+void DefineCryptoConstants(Handle<Object> target) {
+#if HAVE_OPENSSL
+ NODE_DEFINE_STRING_CONSTANT(target,
+ "defaultCoreCipherList",
+ DEFAULT_CIPHER_LIST_CORE);
+ NODE_DEFINE_STRING_CONSTANT(target,
+ "defaultCipherList",
+ default_cipher_list);
+#endif
+}
+
void DefineConstants(Handle<Object> target) {
DefineErrnoConstants(target);
DefineWindowsErrorConstants(target);
DefineOpenSSLConstants(target);
DefineSystemConstants(target);
DefineUVConstants(target);
+ DefineCryptoConstants(target);
}
} // namespace node
#include "node.h"
#include "v8.h"
+#if HAVE_OPENSSL
+#define DEFAULT_CIPHER_LIST_CORE "ECDHE-RSA-AES128-GCM-SHA256:" \
+ "ECDHE-ECDSA-AES128-GCM-SHA256:" \
+ "ECDHE-RSA-AES256-GCM-SHA384:" \
+ "ECDHE-ECDSA-AES256-GCM-SHA384:" \
+ "DHE-RSA-AES128-GCM-SHA256:" \
+ "ECDHE-RSA-AES128-SHA256:" \
+ "DHE-RSA-AES128-SHA256:" \
+ "ECDHE-RSA-AES256-SHA384:" \
+ "DHE-RSA-AES256-SHA384:" \
+ "ECDHE-RSA-AES256-SHA256:" \
+ "DHE-RSA-AES256-SHA256:" \
+ "HIGH:" \
+ "!aNULL:" \
+ "!eNULL:" \
+ "!EXPORT:" \
+ "!DES:" \
+ "!RC4:" \
+ "!MD5:" \
+ "!PSK:" \
+ "!SRP:" \
+ "!CAMELLIA"
+#endif
+
namespace node {
+
+#if HAVE_OPENSSL
+extern const char* default_cipher_list;
+#endif
+
void DefineConstants(v8::Handle<v8::Object> target);
} // namespace node
struct sockaddr;
+// Variation on NODE_DEFINE_CONSTANT that sets a String value.
+#define NODE_DEFINE_STRING_CONSTANT(target, name, constant) \
+ do { \
+ v8::Isolate* isolate = target->GetIsolate(); \
+ v8::Local<v8::String> constant_name = \
+ v8::String::NewFromUtf8(isolate, name); \
+ 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(isolate->GetCurrentContext(), \
+ constant_name, \
+ constant_value, \
+ constant_attributes); \
+ } while (0)
+
namespace node {
// Forward declaration
--- /dev/null
+'use strict';
+const common = require('../common');
+
+if (!common.hasCrypto) {
+ console.log('1..0 # Skipped: missing crypto');
+ return;
+}
+
+const assert = require('assert');
+const spawn = require('child_process').spawn;
+const defaultCoreList = require('constants').defaultCoreCipherList;
+
+function doCheck(arg, check) {
+ var out = '';
+ var arg = arg.concat([
+ '-pe',
+ 'require("constants").defaultCipherList'
+ ]);
+ spawn(process.execPath, arg, {}).
+ on('error', assert.fail).
+ stdout.on('data', function(chunk) {
+ out += chunk;
+ }).on('end', function() {
+ assert.equal(out.trim(), check);
+ }).on('error', assert.fail);
+}
+
+// test the default unmodified version
+doCheck([], defaultCoreList);
+
+// test the command line switch by itself
+doCheck(['--tls-cipher-list=ABC'], 'ABC');