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

Commit

Permalink
crypto: allow runtime opt in using SSLv2/SSLv3
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tjfontaine committed Oct 16, 2014
1 parent c1f4aac commit d601c76
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 7 deletions.
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
10 changes: 10 additions & 0 deletions 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 @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");

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');
}
55 changes: 55 additions & 0 deletions test/simple/test-tls-enable-ssl2.js
Original file line number Diff line number Diff line change
@@ -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');
}
Loading

0 comments on commit d601c76

Please sign in to comment.