Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

crypto: allow runtime opt in using SSLv2/SSLv3 #8555

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@ parser.add_option("--systemtap-includes",
dest="systemtap_includes",
help=optparse.SUPPRESS_HELP)

parser.add_option("--ssl2",
parser.add_option("--without-ssl2",
action="store_true",
dest="ssl2",
help="Enable SSL v2")
help="Disable SSL v2")

parser.add_option("--ssl3",
parser.add_option("--without-ssl3",
action="store_true",
dest="ssl3",
help="Enable SSL v3")
help="Disable SSL v3")

parser.add_option("--shared-zlib",
action="store_true",
Expand Down Expand Up @@ -625,10 +625,10 @@ def configure_openssl(o):
if options.without_ssl:
return

if not options.ssl2:
if options.ssl2:
o['defines'] += ['OPENSSL_NO_SSL2=1']

if not options.ssl3:
if options.ssl3:
o['defines'] += ['OPENSSL_NO_SSL3=1']

if options.shared_openssl:
Expand Down
4 changes: 2 additions & 2 deletions doc/api/https.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
12 changes: 7 additions & 5 deletions doc/api/tls.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
11 changes: 10 additions & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -125,7 +126,6 @@ static Persistent<String> enter_symbol;
static Persistent<String> exit_symbol;
static Persistent<String> disposed_symbol;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irrelevant change?


static bool print_eval = false;
static bool force_repl = false;
static bool trace_deprecation = false;
Expand Down Expand Up @@ -2543,6 +2543,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
Expand Down Expand Up @@ -2576,6 +2578,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);
Expand Down Expand Up @@ -3045,6 +3053,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");

Expand Down
54 changes: 54 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;

Expand All @@ -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) {
Expand Down Expand Up @@ -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();
}
Expand Down
4 changes: 4 additions & 0 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
53 changes: 53 additions & 0 deletions test/simple/test-tls-disable-ssl2.js
Original file line number Diff line number Diff line change
@@ -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');
}
53 changes: 53 additions & 0 deletions test/simple/test-tls-disable-ssl3.js
Original file line number Diff line number Diff line change
@@ -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');
}
Loading