summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy J Fontaine <tjfontaine@gmail.com>2014-10-15 13:56:40 -0700
committerTimothy J Fontaine <tjfontaine@gmail.com>2014-10-15 17:36:05 -0700
commitd601c76f4d728dd7adfa2fbbed2fe86de2e6b479 (patch)
treea6c96f48352b90269d5cc8bf4eba30025d9192fa
parentc1f4aacc75c0a64a81a2be8d6a3a23aa21a31b15 (diff)
downloadnode-d601c76f4d728dd7adfa2fbbed2fe86de2e6b479.tar.gz
crypto: allow runtime opt in using SSLv2/SSLv3
This change disables SSLv2/SSLv3 use by default, and introduces a command line flag to opt into using SSLv2/SSLv3. SSLv2 and SSLv3 are considered unsafe, and should only be used in situations where compatibility with other components is required and they cannot be upgrade to support newer forms of TLS.
-rw-r--r--doc/api/https.markdown4
-rw-r--r--doc/api/tls.markdown12
-rw-r--r--doc/node.16
-rw-r--r--src/node.cc10
-rw-r--r--src/node_crypto.cc54
-rw-r--r--src/node_crypto.h4
-rw-r--r--test/simple/test-tls-disable-ssl2.js53
-rw-r--r--test/simple/test-tls-disable-ssl3.js53
-rw-r--r--test/simple/test-tls-enable-ssl2.js55
-rw-r--r--test/simple/test-tls-enable-ssl3.js55
10 files changed, 299 insertions, 7 deletions
diff --git a/doc/api/https.markdown b/doc/api/https.markdown
index 8f608b1a7..e5023c3ec 100644
--- a/doc/api/https.markdown
+++ b/doc/api/https.markdown
@@ -126,8 +126,8 @@ The following options from [tls.connect()][] can also be specified. However, a
the list of supplied CAs. An `'error'` event is emitted if verification
fails. Verification happens at the connection level, *before* the HTTP
request is sent. Default `true`.
-- `secureProtocol`: The SSL method to use, e.g. `SSLv3_method` to force
- SSL version 3. The possible values depend on your installation of
+- `secureProtocol`: The SSL method to use, e.g. `TLSv1_method` to force
+ TLS version 1. The possible values depend on your installation of
OpenSSL and are defined in the constant [SSL_METHODS][].
In order to specify these options, use a custom `Agent`.
diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown
index 3c2fe6ea6..918ee4435 100644
--- a/doc/api/tls.markdown
+++ b/doc/api/tls.markdown
@@ -40,11 +40,13 @@ To create .pfx or .p12, do this:
## Protocol support
-Node.js is compiled without SSL2/SSL3 protocol support by default. These
-protocols are insecure and could be easily compromised as was shown by
-[CVE-2014-3566][]. However, in some situations, it may cause
-problems with legacy clients/servers (such as Internet Explorer 6). If you do
-really wish to use them, please rebuild node.js with `./configure --with-ssl3`.
+Node.js is compiled with SSLv2 and SSLv3 protocol support by default, but these
+protocols are **disabled**. They are considered insecure and could be easily
+compromised as was shown by [CVE-2014-3566][]. However, in some situations, it
+may cause problems with legacy clients/servers (such as Internet Explorer 6).
+If you wish to enable SSLv2 or SSLv3, run node with the `--enable-ssl2` or
+`--enable-ssl3` flag respectively. In future versions of Node.js SSLv2 and
+SSLv3 will not be compiled in by default.
## Client-initiated renegotiation attack mitigation
diff --git a/doc/node.1 b/doc/node.1
index a381dcf33..ab5fa73b2 100644
--- a/doc/node.1
+++ b/doc/node.1
@@ -62,6 +62,12 @@ and servers.
--max-stack-size=val set max v8 stack size (bytes)
+ --enable-ssl2 enable ssl2 in crypto, tls, and https
+ modules
+
+ --enable-ssl3 enable ssl3 in crypto, tls, and https
+ modules
+
.SH ENVIRONMENT VARIABLES
diff --git a/src/node.cc b/src/node.cc
index 42239730e..18c743fc2 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -82,6 +82,7 @@ typedef int mode_t;
#include "node_script.h"
#include "v8_typed_array.h"
+#include "node_crypto.h"
#include "util.h"
using namespace v8;
@@ -2543,6 +2544,8 @@ static void PrintHelp() {
" --trace-deprecation show stack traces on deprecations\n"
" --v8-options print v8 command line options\n"
" --max-stack-size=val set max v8 stack size (bytes)\n"
+ " --enable-ssl2 enable ssl2\n"
+ " --enable-ssl3 enable ssl3\n"
"\n"
"Environment variables:\n"
#ifdef _WIN32
@@ -2576,6 +2579,12 @@ static void ParseArgs(int argc, char **argv) {
p = 1 + strchr(arg, '=');
max_stack_size = atoi(p);
argv[i] = const_cast<char*>("");
+ } else if (strcmp(arg, "--enable-ssl2") == 0) {
+ SSL2_ENABLE = true;
+ argv[i] = const_cast<char*>("");
+ } else if (strcmp(arg, "--enable-ssl3") == 0) {
+ SSL3_ENABLE = true;
+ argv[i] = const_cast<char*>("");
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
PrintHelp();
exit(0);
@@ -3045,6 +3054,7 @@ static char **copy_argv(int argc, char **argv) {
return argv_copy;
}
+
int Start(int argc, char *argv[]) {
const char* replaceInvalid = getenv("NODE_INVALID_UTF8");
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index 075a2e3b1..e56544d1c 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -69,10 +69,14 @@ const char* root_certs[] = {
NULL
};
+bool SSL2_ENABLE = false;
+bool SSL3_ENABLE = false;
+
namespace crypto {
using namespace v8;
+
// Forcibly clear OpenSSL's error stack on return. This stops stale errors
// from popping up later in the lifecycle of crypto operations where they
// would cause spurious failures. It's a rather blunt method, though.
@@ -234,6 +238,24 @@ Handle<Value> SecureContext::New(const Arguments& args) {
}
+bool MaybeThrowSSL3() {
+ if (!SSL3_ENABLE) {
+ ThrowException(Exception::Error(String::New("SSLv3 is considered unsafe, see node --help")));
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool MaybeThrowSSL2() {
+ if (!SSL2_ENABLE) {
+ ThrowException(Exception::Error(String::New("SSLv2 is considered unsafe, see node --help")));
+ return true;
+ } else {
+ return false;
+ }
+}
+
Handle<Value> SecureContext::Init(const Arguments& args) {
HandleScope scope;
@@ -246,28 +268,46 @@ Handle<Value> SecureContext::Init(const Arguments& args) {
if (strcmp(*sslmethod, "SSLv2_method") == 0) {
#ifndef OPENSSL_NO_SSL2
+ if (MaybeThrowSSL2()) return Undefined();
method = SSLv2_method();
#else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif
} else if (strcmp(*sslmethod, "SSLv2_server_method") == 0) {
#ifndef OPENSSL_NO_SSL2
+ if (MaybeThrowSSL2()) return Undefined();
method = SSLv2_server_method();
#else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif
} else if (strcmp(*sslmethod, "SSLv2_client_method") == 0) {
#ifndef OPENSSL_NO_SSL2
+ if (MaybeThrowSSL2()) return Undefined();
method = SSLv2_client_method();
#else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif
} else if (strcmp(*sslmethod, "SSLv3_method") == 0) {
+#ifndef OPENSSL_NO_SSL3
+ if (MaybeThrowSSL3()) return Undefined();
method = SSLv3_method();
+#else
+ return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
+#endif
} else if (strcmp(*sslmethod, "SSLv3_server_method") == 0) {
+#ifndef OPENSSL_NO_SSL3
+ if (MaybeThrowSSL3()) return Undefined();
method = SSLv3_server_method();
+#else
+ return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
+#endif
} else if (strcmp(*sslmethod, "SSLv3_client_method") == 0) {
+#ifndef OPENSSL_NO_SSL3
+ if (MaybeThrowSSL3()) return Undefined();
method = SSLv3_client_method();
+#else
+ return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
+#endif
} else if (strcmp(*sslmethod, "SSLv23_method") == 0) {
method = SSLv23_method();
} else if (strcmp(*sslmethod, "SSLv23_server_method") == 0) {
@@ -295,6 +335,20 @@ Handle<Value> SecureContext::Init(const Arguments& args) {
SSL_CTX_sess_set_get_cb(sc->ctx_, GetSessionCallback);
SSL_CTX_sess_set_new_cb(sc->ctx_, NewSessionCallback);
+ int options = 0;
+
+#ifndef OPENSSL_NO_SSL2
+ if (!SSL2_ENABLE)
+ options |= SSL_OP_NO_SSLv2;
+#endif
+
+#ifndef OPENSSL_NO_SSL3
+ if (!SSL3_ENABLE)
+ options |= SSL_OP_NO_SSLv3;
+#endif
+
+ SSL_CTX_set_options(sc->ctx_, options);
+
sc->ca_store_ = NULL;
return True();
}
diff --git a/src/node_crypto.h b/src/node_crypto.h
index b12638e00..54b9b88e4 100644
--- a/src/node_crypto.h
+++ b/src/node_crypto.h
@@ -44,6 +44,10 @@
#define EVP_F_EVP_DECRYPTFINAL 101
namespace node {
+
+extern bool SSL2_ENABLE;
+extern bool SSL3_ENABLE;
+
namespace crypto {
static X509_STORE* root_cert_store;
diff --git a/test/simple/test-tls-disable-ssl2.js b/test/simple/test-tls-disable-ssl2.js
new file mode 100644
index 000000000..4da38efe2
--- /dev/null
+++ b/test/simple/test-tls-disable-ssl2.js
@@ -0,0 +1,53 @@
+// 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 common = require('../common');
+var assert = require('assert');
+var tls = require('tls');
+var fs = require('fs');
+
+var SSL_Method = 'SSLv2_method';
+var localhost = '127.0.0.1';
+
+function test(honorCipherOrder, clientCipher, expectedCipher, cb) {
+ var soptions = {
+ secureProtocol: SSL_Method,
+ key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'),
+ cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'),
+ ciphers: 'AES256-SHA:RC4-SHA:DES-CBC-SHA',
+ honorCipherOrder: !!honorCipherOrder
+ };
+
+ var server;
+
+ assert.throws(function() {
+ server = tls.createServer(soptions, function(cleartextStream) {
+ nconns++;
+ });
+ }, /SSLv2 is considered unsafe/);
+}
+
+test1();
+
+function test1() {
+ // Client has the preference of cipher suites by default
+ test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA');
+}
diff --git a/test/simple/test-tls-disable-ssl3.js b/test/simple/test-tls-disable-ssl3.js
new file mode 100644
index 000000000..9d514852c
--- /dev/null
+++ b/test/simple/test-tls-disable-ssl3.js
@@ -0,0 +1,53 @@
+// 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 common = require('../common');
+var assert = require('assert');
+var tls = require('tls');
+var fs = require('fs');
+
+var SSL_Method = 'SSLv3_method';
+var localhost = '127.0.0.1';
+
+function test(honorCipherOrder, clientCipher, expectedCipher, cb) {
+ var soptions = {
+ secureProtocol: SSL_Method,
+ key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'),
+ cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'),
+ ciphers: 'AES256-SHA:RC4-SHA:DES-CBC-SHA',
+ honorCipherOrder: !!honorCipherOrder
+ };
+
+ var server;
+
+ assert.throws(function() {
+ server = tls.createServer(soptions, function(cleartextStream) {
+ nconns++;
+ });
+ }, /SSLv3 is considered unsafe/);
+}
+
+test1();
+
+function test1() {
+ // Client has the preference of cipher suites by default
+ test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA');
+}
diff --git a/test/simple/test-tls-enable-ssl2.js b/test/simple/test-tls-enable-ssl2.js
new file mode 100644
index 000000000..5d1fca4cb
--- /dev/null
+++ b/test/simple/test-tls-enable-ssl2.js
@@ -0,0 +1,55 @@
+// 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.
+
+// Flags: --enable-ssl2
+
+var common = require('../common');
+var assert = require('assert');
+var tls = require('tls');
+var fs = require('fs');
+
+var SSL_Method = 'SSLv2_method';
+var localhost = '127.0.0.1';
+
+function test(honorCipherOrder, clientCipher, expectedCipher, cb) {
+ var soptions = {
+ secureProtocol: SSL_Method,
+ key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'),
+ cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'),
+ ciphers: 'AES256-SHA:RC4-SHA:DES-CBC-SHA',
+ honorCipherOrder: !!honorCipherOrder
+ };
+
+ var server;
+
+ assert.doesNotThrow(function() {
+ server = tls.createServer(soptions, function(cleartextStream) {
+ nconns++;
+ });
+ }, /SSLv2 Disabled/);
+}
+
+test1();
+
+function test1() {
+ // Client has the preference of cipher suites by default
+ test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA');
+}
diff --git a/test/simple/test-tls-enable-ssl3.js b/test/simple/test-tls-enable-ssl3.js
new file mode 100644
index 000000000..b85e65198
--- /dev/null
+++ b/test/simple/test-tls-enable-ssl3.js
@@ -0,0 +1,55 @@
+// 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.
+
+// Flags: --enable-ssl3
+
+var common = require('../common');
+var assert = require('assert');
+var tls = require('tls');
+var fs = require('fs');
+
+var SSL_Method = 'SSLv3_method';
+var localhost = '127.0.0.1';
+
+function test(honorCipherOrder, clientCipher, expectedCipher, cb) {
+ var soptions = {
+ secureProtocol: SSL_Method,
+ key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'),
+ cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'),
+ ciphers: 'AES256-SHA:RC4-SHA:DES-CBC-SHA',
+ honorCipherOrder: !!honorCipherOrder
+ };
+
+ var server;
+
+ assert.doesNotThrow(function() {
+ server = tls.createServer(soptions, function(cleartextStream) {
+ nconns++;
+ });
+ }, /SSLv3 Disabled/);
+}
+
+test1();
+
+function test1() {
+ // Client has the preference of cipher suites by default
+ test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA');
+}