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

Commit d601c76

Browse files
committed
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.
1 parent c1f4aac commit d601c76

10 files changed

+299
-7
lines changed

doc/api/https.markdown

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ The following options from [tls.connect()][] can also be specified. However, a
126126
the list of supplied CAs. An `'error'` event is emitted if verification
127127
fails. Verification happens at the connection level, *before* the HTTP
128128
request is sent. Default `true`.
129-
- `secureProtocol`: The SSL method to use, e.g. `SSLv3_method` to force
130-
SSL version 3. The possible values depend on your installation of
129+
- `secureProtocol`: The SSL method to use, e.g. `TLSv1_method` to force
130+
TLS version 1. The possible values depend on your installation of
131131
OpenSSL and are defined in the constant [SSL_METHODS][].
132132

133133
In order to specify these options, use a custom `Agent`.

doc/api/tls.markdown

+7-5
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ To create .pfx or .p12, do this:
4040

4141
## Protocol support
4242

43-
Node.js is compiled without SSL2/SSL3 protocol support by default. These
44-
protocols are insecure and could be easily compromised as was shown by
45-
[CVE-2014-3566][]. However, in some situations, it may cause
46-
problems with legacy clients/servers (such as Internet Explorer 6). If you do
47-
really wish to use them, please rebuild node.js with `./configure --with-ssl3`.
43+
Node.js is compiled with SSLv2 and SSLv3 protocol support by default, but these
44+
protocols are **disabled**. They are considered insecure and could be easily
45+
compromised as was shown by [CVE-2014-3566][]. However, in some situations, it
46+
may cause problems with legacy clients/servers (such as Internet Explorer 6).
47+
If you wish to enable SSLv2 or SSLv3, run node with the `--enable-ssl2` or
48+
`--enable-ssl3` flag respectively. In future versions of Node.js SSLv2 and
49+
SSLv3 will not be compiled in by default.
4850

4951

5052
## Client-initiated renegotiation attack mitigation

doc/node.1

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ and servers.
6262

6363
--max-stack-size=val set max v8 stack size (bytes)
6464

65+
--enable-ssl2 enable ssl2 in crypto, tls, and https
66+
modules
67+
68+
--enable-ssl3 enable ssl3 in crypto, tls, and https
69+
modules
70+
6571

6672
.SH ENVIRONMENT VARIABLES
6773

src/node.cc

+10
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ typedef int mode_t;
8282
#include "node_script.h"
8383
#include "v8_typed_array.h"
8484

85+
#include "node_crypto.h"
8586
#include "util.h"
8687

8788
using namespace v8;
@@ -2543,6 +2544,8 @@ static void PrintHelp() {
25432544
" --trace-deprecation show stack traces on deprecations\n"
25442545
" --v8-options print v8 command line options\n"
25452546
" --max-stack-size=val set max v8 stack size (bytes)\n"
2547+
" --enable-ssl2 enable ssl2\n"
2548+
" --enable-ssl3 enable ssl3\n"
25462549
"\n"
25472550
"Environment variables:\n"
25482551
#ifdef _WIN32
@@ -2576,6 +2579,12 @@ static void ParseArgs(int argc, char **argv) {
25762579
p = 1 + strchr(arg, '=');
25772580
max_stack_size = atoi(p);
25782581
argv[i] = const_cast<char*>("");
2582+
} else if (strcmp(arg, "--enable-ssl2") == 0) {
2583+
SSL2_ENABLE = true;
2584+
argv[i] = const_cast<char*>("");
2585+
} else if (strcmp(arg, "--enable-ssl3") == 0) {
2586+
SSL3_ENABLE = true;
2587+
argv[i] = const_cast<char*>("");
25792588
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
25802589
PrintHelp();
25812590
exit(0);
@@ -3045,6 +3054,7 @@ static char **copy_argv(int argc, char **argv) {
30453054
return argv_copy;
30463055
}
30473056

3057+
30483058
int Start(int argc, char *argv[]) {
30493059
const char* replaceInvalid = getenv("NODE_INVALID_UTF8");
30503060

src/node_crypto.cc

+54
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,14 @@ const char* root_certs[] = {
6969
NULL
7070
};
7171

72+
bool SSL2_ENABLE = false;
73+
bool SSL3_ENABLE = false;
74+
7275
namespace crypto {
7376

7477
using namespace v8;
7578

79+
7680
// Forcibly clear OpenSSL's error stack on return. This stops stale errors
7781
// from popping up later in the lifecycle of crypto operations where they
7882
// would cause spurious failures. It's a rather blunt method, though.
@@ -234,6 +238,24 @@ Handle<Value> SecureContext::New(const Arguments& args) {
234238
}
235239

236240

241+
bool MaybeThrowSSL3() {
242+
if (!SSL3_ENABLE) {
243+
ThrowException(Exception::Error(String::New("SSLv3 is considered unsafe, see node --help")));
244+
return true;
245+
} else {
246+
return false;
247+
}
248+
}
249+
250+
bool MaybeThrowSSL2() {
251+
if (!SSL2_ENABLE) {
252+
ThrowException(Exception::Error(String::New("SSLv2 is considered unsafe, see node --help")));
253+
return true;
254+
} else {
255+
return false;
256+
}
257+
}
258+
237259
Handle<Value> SecureContext::Init(const Arguments& args) {
238260
HandleScope scope;
239261

@@ -246,28 +268,46 @@ Handle<Value> SecureContext::Init(const Arguments& args) {
246268

247269
if (strcmp(*sslmethod, "SSLv2_method") == 0) {
248270
#ifndef OPENSSL_NO_SSL2
271+
if (MaybeThrowSSL2()) return Undefined();
249272
method = SSLv2_method();
250273
#else
251274
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
252275
#endif
253276
} else if (strcmp(*sslmethod, "SSLv2_server_method") == 0) {
254277
#ifndef OPENSSL_NO_SSL2
278+
if (MaybeThrowSSL2()) return Undefined();
255279
method = SSLv2_server_method();
256280
#else
257281
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
258282
#endif
259283
} else if (strcmp(*sslmethod, "SSLv2_client_method") == 0) {
260284
#ifndef OPENSSL_NO_SSL2
285+
if (MaybeThrowSSL2()) return Undefined();
261286
method = SSLv2_client_method();
262287
#else
263288
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
264289
#endif
265290
} else if (strcmp(*sslmethod, "SSLv3_method") == 0) {
291+
#ifndef OPENSSL_NO_SSL3
292+
if (MaybeThrowSSL3()) return Undefined();
266293
method = SSLv3_method();
294+
#else
295+
return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
296+
#endif
267297
} else if (strcmp(*sslmethod, "SSLv3_server_method") == 0) {
298+
#ifndef OPENSSL_NO_SSL3
299+
if (MaybeThrowSSL3()) return Undefined();
268300
method = SSLv3_server_method();
301+
#else
302+
return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
303+
#endif
269304
} else if (strcmp(*sslmethod, "SSLv3_client_method") == 0) {
305+
#ifndef OPENSSL_NO_SSL3
306+
if (MaybeThrowSSL3()) return Undefined();
270307
method = SSLv3_client_method();
308+
#else
309+
return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
310+
#endif
271311
} else if (strcmp(*sslmethod, "SSLv23_method") == 0) {
272312
method = SSLv23_method();
273313
} else if (strcmp(*sslmethod, "SSLv23_server_method") == 0) {
@@ -295,6 +335,20 @@ Handle<Value> SecureContext::Init(const Arguments& args) {
295335
SSL_CTX_sess_set_get_cb(sc->ctx_, GetSessionCallback);
296336
SSL_CTX_sess_set_new_cb(sc->ctx_, NewSessionCallback);
297337

338+
int options = 0;
339+
340+
#ifndef OPENSSL_NO_SSL2
341+
if (!SSL2_ENABLE)
342+
options |= SSL_OP_NO_SSLv2;
343+
#endif
344+
345+
#ifndef OPENSSL_NO_SSL3
346+
if (!SSL3_ENABLE)
347+
options |= SSL_OP_NO_SSLv3;
348+
#endif
349+
350+
SSL_CTX_set_options(sc->ctx_, options);
351+
298352
sc->ca_store_ = NULL;
299353
return True();
300354
}

src/node_crypto.h

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
#define EVP_F_EVP_DECRYPTFINAL 101
4545

4646
namespace node {
47+
48+
extern bool SSL2_ENABLE;
49+
extern bool SSL3_ENABLE;
50+
4751
namespace crypto {
4852

4953
static X509_STORE* root_cert_store;

test/simple/test-tls-disable-ssl2.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
var common = require('../common');
23+
var assert = require('assert');
24+
var tls = require('tls');
25+
var fs = require('fs');
26+
27+
var SSL_Method = 'SSLv2_method';
28+
var localhost = '127.0.0.1';
29+
30+
function test(honorCipherOrder, clientCipher, expectedCipher, cb) {
31+
var soptions = {
32+
secureProtocol: SSL_Method,
33+
key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'),
34+
cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'),
35+
ciphers: 'AES256-SHA:RC4-SHA:DES-CBC-SHA',
36+
honorCipherOrder: !!honorCipherOrder
37+
};
38+
39+
var server;
40+
41+
assert.throws(function() {
42+
server = tls.createServer(soptions, function(cleartextStream) {
43+
nconns++;
44+
});
45+
}, /SSLv2 is considered unsafe/);
46+
}
47+
48+
test1();
49+
50+
function test1() {
51+
// Client has the preference of cipher suites by default
52+
test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA');
53+
}

test/simple/test-tls-disable-ssl3.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
var common = require('../common');
23+
var assert = require('assert');
24+
var tls = require('tls');
25+
var fs = require('fs');
26+
27+
var SSL_Method = 'SSLv3_method';
28+
var localhost = '127.0.0.1';
29+
30+
function test(honorCipherOrder, clientCipher, expectedCipher, cb) {
31+
var soptions = {
32+
secureProtocol: SSL_Method,
33+
key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'),
34+
cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'),
35+
ciphers: 'AES256-SHA:RC4-SHA:DES-CBC-SHA',
36+
honorCipherOrder: !!honorCipherOrder
37+
};
38+
39+
var server;
40+
41+
assert.throws(function() {
42+
server = tls.createServer(soptions, function(cleartextStream) {
43+
nconns++;
44+
});
45+
}, /SSLv3 is considered unsafe/);
46+
}
47+
48+
test1();
49+
50+
function test1() {
51+
// Client has the preference of cipher suites by default
52+
test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA');
53+
}

test/simple/test-tls-enable-ssl2.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
// Flags: --enable-ssl2
23+
24+
var common = require('../common');
25+
var assert = require('assert');
26+
var tls = require('tls');
27+
var fs = require('fs');
28+
29+
var SSL_Method = 'SSLv2_method';
30+
var localhost = '127.0.0.1';
31+
32+
function test(honorCipherOrder, clientCipher, expectedCipher, cb) {
33+
var soptions = {
34+
secureProtocol: SSL_Method,
35+
key: fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'),
36+
cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'),
37+
ciphers: 'AES256-SHA:RC4-SHA:DES-CBC-SHA',
38+
honorCipherOrder: !!honorCipherOrder
39+
};
40+
41+
var server;
42+
43+
assert.doesNotThrow(function() {
44+
server = tls.createServer(soptions, function(cleartextStream) {
45+
nconns++;
46+
});
47+
}, /SSLv2 Disabled/);
48+
}
49+
50+
test1();
51+
52+
function test1() {
53+
// Client has the preference of cipher suites by default
54+
test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA');
55+
}

0 commit comments

Comments
 (0)