Browse Source

Merge remote-tracking branch 'joyent/v0.10' into v0.10

v0.10.34-release
Fedor Indutny 10 years ago
parent
commit
d435f4b3eb
  1. 3
      AUTHORS
  2. 23
      ChangeLog
  3. 1
      deps/uv/AUTHORS
  4. 13
      deps/uv/ChangeLog
  5. 1
      deps/uv/config-unix.mk
  6. 13
      deps/uv/src/unix/linux-core.c
  7. 115
      deps/uv/src/unix/stream.c
  8. 2
      deps/uv/src/version.c
  9. 1
      deps/uv/src/win/error.c
  10. 2
      deps/uv/test/test-list.h
  11. 47
      deps/uv/test/test-osx-select.c
  12. 1
      deps/uv/uv.gyp
  13. 22
      doc/api/tls.markdown
  14. 1
      lib/_stream_readable.js
  15. 1
      lib/_stream_writable.js
  16. 3
      lib/assert.js
  17. 38
      lib/crypto.js
  18. 1
      lib/dgram.js
  19. 1
      lib/fs.js
  20. 1
      lib/http.js
  21. 1
      lib/net.js
  22. 1
      lib/readline.js
  23. 20
      lib/tls.js
  24. 1
      lib/zlib.js
  25. 24
      src/node_crypto.cc
  26. 2
      src/node_version.h
  27. 1
      test/external/ssl-options/.gitignore
  28. 15
      test/external/ssl-options/package.json
  29. 729
      test/external/ssl-options/test.js
  30. 53
      test/simple/test-tls-disable-ssl2.js
  31. 53
      test/simple/test-tls-disable-ssl3.js
  32. 55
      test/simple/test-tls-enable-ssl2.js
  33. 55
      test/simple/test-tls-enable-ssl3.js
  34. 131
      test/simple/test-tls-honorcipherorder-secureOptions.js

3
AUTHORS

@ -515,3 +515,6 @@ Kevin Simper <kevin.simper@gmail.com>
Jackson Tian <shyvo1987@gmail.com> Jackson Tian <shyvo1987@gmail.com>
Tristan Berger <tristan.berger@gmail.com> Tristan Berger <tristan.berger@gmail.com>
Mathias Schreck <schreck.mathias@googlemail.com> Mathias Schreck <schreck.mathias@googlemail.com>
Calvin Metcalf <cmetcalf@appgeo.com>
Matthew Fitzsimmons <matt@fitzage.com>
Swaagie <info@martijnswaagman.nl>

23
ChangeLog

@ -1,4 +1,25 @@
2014.09.16, Version 0.10.32 (Stable) 2014.10.20, Version 0.10.33 (Stable)
* openssl: Update to 1.0.1j (Addressing multiple CVEs)
* uv: Update to v0.10.29
* child_process: properly support optional args (cjihrig)
* crypto: Disable autonegotiation for SSLv2/3 by default (Fedor Indutny,
Timothy J Fontaine, Alexis Campailla)
This is a behavior change, by default we will not allow the negotiation to
SSLv2 or SSLv3. If you want this behavior, run Node.js with either
`--enable-ssl2` or `--enable-ssl3` respectively.
This does not change the behavior for users specifically requesting
`SSLv2_method` or `SSLv3_method`. While this behavior is not advised, it is
assumed you know what you're doing since you're specifically asking to use
these methods.
2014.09.16, Version 0.10.32 (Stable), 0fe0d121551593c23a565db8397f85f17bb0f00e
* npm: Update to 1.4.28 * npm: Update to 1.4.28

1
deps/uv/AUTHORS

@ -130,3 +130,4 @@ David Capello <davidcapello@gmail.com>
Paul Tan <pyokagan@gmail.com> Paul Tan <pyokagan@gmail.com>
Javier Hernández <jhernandez@emergya.com> Javier Hernández <jhernandez@emergya.com>
Tonis Tiigi <tonistiigi@gmail.com> Tonis Tiigi <tonistiigi@gmail.com>
Michael Hudson-Doyle <michael.hudson@linaro.org>

13
deps/uv/ChangeLog

@ -1,4 +1,15 @@
2014.07.32, Version 0.10.28 (Stable) 2014.10.21, Version 0.10.29 (Stable)
Changes since version 0.10.28:
* darwin: allocate enough space for select() hack (Fedor Indutny)
* linux: try epoll_pwait if epoll_wait is missing (Michael Hudson-Doyle)
* windows: map ERROR_INVALID_DRIVE to UV_ENOENT (Saúl Ibarra Corretgé)
2014.07.32, Version 0.10.28 (Stable), 9c14b616f5fb84bfd7d45707bab4bbb85894443e
Changes since version 0.10.27: Changes since version 0.10.27:

1
deps/uv/config-unix.mk

@ -85,6 +85,7 @@ ifeq (__clang__,$(shell sh -c "$(CC) -dM -E - </dev/null | grep -ow __clang__"))
CFLAGS += -Wno-dollar-in-identifier-extension CFLAGS += -Wno-dollar-in-identifier-extension
endif endif
CPPFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 CPPFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
CPPFLAGS += -D_DARWIN_UNLIMITED_SELECT=1
LDFLAGS += -framework Foundation \ LDFLAGS += -framework Foundation \
-framework CoreServices \ -framework CoreServices \
-framework ApplicationServices -framework ApplicationServices

13
deps/uv/src/unix/linux-core.c

@ -138,6 +138,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int fd; int fd;
int op; int op;
int i; int i;
static int no_epoll_wait;
if (loop->nfds == 0) { if (loop->nfds == 0) {
assert(ngx_queue_empty(&loop->watcher_queue)); assert(ngx_queue_empty(&loop->watcher_queue));
@ -184,10 +185,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
count = 48; /* Benchmarks suggest this gives the best throughput. */ count = 48; /* Benchmarks suggest this gives the best throughput. */
for (;;) { for (;;) {
if (!no_epoll_wait) {
nfds = uv__epoll_wait(loop->backend_fd, nfds = uv__epoll_wait(loop->backend_fd,
events, events,
ARRAY_SIZE(events), ARRAY_SIZE(events),
timeout); timeout);
if (nfds == -1 && errno == ENOSYS) {
no_epoll_wait = 1;
continue;
}
} else {
nfds = uv__epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
NULL);
}
/* Update loop->time unconditionally. It's tempting to skip the update when /* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the

115
deps/uv/src/unix/stream.c

@ -53,6 +53,10 @@ struct uv__stream_select_s {
int fake_fd; int fake_fd;
int int_fd; int int_fd;
int fd; int fd;
fd_set* sread;
size_t sread_sz;
fd_set* swrite;
size_t swrite_sz;
}; };
#endif /* defined(__APPLE__) */ #endif /* defined(__APPLE__) */
@ -131,8 +135,6 @@ static void uv__stream_osx_select(void* arg) {
uv_stream_t* stream; uv_stream_t* stream;
uv__stream_select_t* s; uv__stream_select_t* s;
char buf[1024]; char buf[1024];
fd_set sread;
fd_set swrite;
int events; int events;
int fd; int fd;
int r; int r;
@ -153,17 +155,17 @@ static void uv__stream_osx_select(void* arg) {
break; break;
/* Watch fd using select(2) */ /* Watch fd using select(2) */
FD_ZERO(&sread); memset(s->sread, 0, s->sread_sz);
FD_ZERO(&swrite); memset(s->swrite, 0, s->swrite_sz);
if (uv_is_readable(stream)) if (uv_is_readable(stream))
FD_SET(fd, &sread); FD_SET(fd, s->sread);
if (uv_is_writable(stream)) if (uv_is_writable(stream))
FD_SET(fd, &swrite); FD_SET(fd, s->swrite);
FD_SET(s->int_fd, &sread); FD_SET(s->int_fd, s->sread);
/* Wait indefinitely for fd events */ /* Wait indefinitely for fd events */
r = select(max_fd + 1, &sread, &swrite, NULL, NULL); r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL);
if (r == -1) { if (r == -1) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
@ -177,7 +179,7 @@ static void uv__stream_osx_select(void* arg) {
continue; continue;
/* Empty socketpair's buffer in case of interruption */ /* Empty socketpair's buffer in case of interruption */
if (FD_ISSET(s->int_fd, &sread)) if (FD_ISSET(s->int_fd, s->sread))
while (1) { while (1) {
r = read(s->int_fd, buf, sizeof(buf)); r = read(s->int_fd, buf, sizeof(buf));
@ -198,12 +200,12 @@ static void uv__stream_osx_select(void* arg) {
/* Handle events */ /* Handle events */
events = 0; events = 0;
if (FD_ISSET(fd, &sread)) if (FD_ISSET(fd, s->sread))
events |= UV__POLLIN; events |= UV__POLLIN;
if (FD_ISSET(fd, &swrite)) if (FD_ISSET(fd, s->swrite))
events |= UV__POLLOUT; events |= UV__POLLOUT;
assert(events != 0 || FD_ISSET(s->int_fd, &sread)); assert(events != 0 || FD_ISSET(s->int_fd, s->sread));
if (events != 0) { if (events != 0) {
ACCESS_ONCE(int, s->events) = events; ACCESS_ONCE(int, s->events) = events;
@ -283,6 +285,10 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
int ret; int ret;
int kq; int kq;
int old_fd; int old_fd;
int max_fd;
size_t sread_sz;
size_t swrite_sz;
int err;
kq = kqueue(); kq = kqueue();
if (kq == -1) { if (kq == -1) {
@ -306,30 +312,52 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
return 0; return 0;
/* At this point we definitely know that this fd won't work with kqueue */ /* At this point we definitely know that this fd won't work with kqueue */
s = malloc(sizeof(*s));
if (s == NULL) /*
return uv__set_artificial_error(stream->loop, UV_ENOMEM); * Create fds for io watcher and to interrupt the select() loop.
* NOTE: do it ahead of malloc below to allocate enough space for fd_sets
*/
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
return uv__set_sys_error(stream->loop, errno);
max_fd = *fd;
if (fds[1] > max_fd)
max_fd = fds[1];
sread_sz = (max_fd + NBBY) / NBBY;
swrite_sz = sread_sz;
s = malloc(sizeof(*s) + sread_sz + swrite_sz);
if (s == NULL) {
err = uv__set_artificial_error(stream->loop, UV_ENOMEM);
goto failed_malloc;
}
s->events = 0; s->events = 0;
s->fd = *fd; s->fd = *fd;
s->sread = (fd_set*) ((char*) s + sizeof(*s));
s->sread_sz = sread_sz;
s->swrite = (fd_set*) ((char*) s->sread + sread_sz);
s->swrite_sz = swrite_sz;
if (uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb)) { err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb);
SAVE_ERRNO(free(s)); if (err)
return uv__set_sys_error(stream->loop, errno); goto failed_async_init;
}
s->async.flags |= UV__HANDLE_INTERNAL; s->async.flags |= UV__HANDLE_INTERNAL;
uv__handle_unref(&s->async); uv__handle_unref(&s->async);
if (uv_sem_init(&s->close_sem, 0)) err = uv_sem_init(&s->close_sem, 0);
goto fatal1; if (err != 0) {
err = uv__set_sys_error(stream->loop, UV_UNKNOWN);
if (uv_sem_init(&s->async_sem, 0)) goto failed_close_sem_init;
goto fatal2; }
/* Create fds for io watcher and to interrupt the select() loop. */ err = uv_sem_init(&s->async_sem, 0);
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) if (err != 0) {
goto fatal3; err = uv__set_sys_error(stream->loop, UV_UNKNOWN);
goto failed_async_sem_init;
}
s->fake_fd = fds[0]; s->fake_fd = fds[0];
s->int_fd = fds[1]; s->int_fd = fds[1];
@ -339,26 +367,37 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
stream->select = s; stream->select = s;
*fd = s->fake_fd; *fd = s->fake_fd;
if (uv_thread_create(&s->thread, uv__stream_osx_select, stream)) err = uv_thread_create(&s->thread, uv__stream_osx_select, stream);
goto fatal4; if (err != 0) {
err = uv__set_sys_error(stream->loop, UV_UNKNOWN);
goto failed_thread_create;
}
return 0; return 0;
fatal4: failed_thread_create:
s->stream = NULL; s->stream = NULL;
stream->select = NULL; stream->select = NULL;
*fd = old_fd; *fd = old_fd;
close(s->fake_fd);
close(s->int_fd);
s->fake_fd = -1;
s->int_fd = -1;
fatal3:
uv_sem_destroy(&s->async_sem); uv_sem_destroy(&s->async_sem);
fatal2:
failed_async_sem_init:
uv_sem_destroy(&s->close_sem); uv_sem_destroy(&s->close_sem);
fatal1:
failed_close_sem_init:
close(fds[0]);
close(fds[1]);
uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
return uv__set_sys_error(stream->loop, errno); return err;
failed_async_init:
free(s);
failed_malloc:
close(fds[0]);
close(fds[1]);
return err;
} }
#endif /* defined(__APPLE__) */ #endif /* defined(__APPLE__) */

2
deps/uv/src/version.c

@ -34,7 +34,7 @@
#define UV_VERSION_MAJOR 0 #define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 10 #define UV_VERSION_MINOR 10
#define UV_VERSION_PATCH 28 #define UV_VERSION_PATCH 29
#define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_IS_RELEASE 1

1
deps/uv/src/win/error.c

@ -128,6 +128,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case ERROR_DIRECTORY: return UV_ENOENT; case ERROR_DIRECTORY: return UV_ENOENT;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_INVALID_NAME: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT;
case ERROR_INVALID_DRIVE: return UV_ENOENT;
case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT; case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
case ERROR_MOD_NOT_FOUND: return UV_ENOENT; case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT; case ERROR_PATH_NOT_FOUND: return UV_ENOENT;

2
deps/uv/test/test-list.h

@ -232,6 +232,7 @@ TEST_DECLARE (closed_fd_events)
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
TEST_DECLARE (osx_select) TEST_DECLARE (osx_select)
TEST_DECLARE (osx_select_many_fds)
#endif #endif
HELPER_DECLARE (tcp4_echo_server) HELPER_DECLARE (tcp4_echo_server)
HELPER_DECLARE (tcp6_echo_server) HELPER_DECLARE (tcp6_echo_server)
@ -468,6 +469,7 @@ TASK_LIST_START
#ifdef __APPLE__ #ifdef __APPLE__
TEST_ENTRY (osx_select) TEST_ENTRY (osx_select)
TEST_ENTRY (osx_select_many_fds)
#endif #endif
TEST_ENTRY (fs_file_noent) TEST_ENTRY (fs_file_noent)

47
deps/uv/test/test-osx-select.c

@ -79,4 +79,51 @@ TEST_IMPL(osx_select) {
return 0; return 0;
} }
TEST_IMPL(osx_select_many_fds) {
int r;
int fd;
size_t i;
size_t len;
const char* str;
struct sockaddr_in addr;
uv_tty_t tty;
uv_tcp_t tcps[1500];
addr = uv_ip4_addr("127.0.0.1", 0);
for (i = 0; i < ARRAY_SIZE(tcps); i++) {
r = uv_tcp_init(uv_default_loop(), &tcps[i]);
ASSERT(r == 0);
r = uv_tcp_bind(&tcps[i], addr);
ASSERT(r == 0);
uv_unref((uv_handle_t*) &tcps[i]);
}
fd = open("/dev/tty", O_RDONLY);
ASSERT(fd >= 0);
r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
ASSERT(r == 0);
/* Emulate user-input */
str = "got some input\n"
"with a couple of lines\n"
"feel pretty happy\n";
for (i = 0, len = strlen(str); i < len; i++) {
r = ioctl(fd, TIOCSTI, str + i);
ASSERT(r == 0);
}
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(read_count == 3);
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* __APPLE__ */ #endif /* __APPLE__ */

1
deps/uv/uv.gyp

@ -194,6 +194,7 @@
}, },
'defines': [ 'defines': [
'_DARWIN_USE_64_BIT_INODE=1', '_DARWIN_USE_64_BIT_INODE=1',
'_DARWIN_UNLIMITED_SELECT=1',
] ]
}], }],
[ 'OS!="mac"', { [ 'OS!="mac"', {

22
doc/api/tls.markdown

@ -48,15 +48,19 @@ 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 `--enable-ssl3` flag respectively. In future versions of Node.js SSLv2 and
SSLv3 will not be compiled in by default. SSLv3 will not be compiled in by default.
This means that without having one or both of those flags set on the command There is a way to force node into using SSLv3 or SSLv2 only mode by explicitly
line, Node.js will **throw** if you explicitly set the `secureProtocol` to specifying `secureProtocol` to `'SSLv3_method'` or `'SSLv2_method'`.
`SSLv3_method` or similar. However the default protocol method Node.js uses is
`SSLv23_method` which would be more accurately named `AutoNegotiate_method`. The default protocol method Node.js uses is `SSLv23_method` which would be more
This method will try and negotiate from the highest level down to whatever the accurately named `AutoNegotiate_method`. This method will try and negotiate
client supports. To provide a secure default, Node.js (since v0.10.33) from the highest level down to whatever the client supports. To provide a
explicitly disables the use of SSLv3 and SSLv2 by setting the `secureOptions` secure default, Node.js (since v0.10.33) explicitly disables the use of SSLv3
to be `SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2` (again, unless you have passed and SSLv2 by setting the `secureOptions` to be
`--enable-ssl3` or `--enable-ssl2`). `SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2` (again, unless you have passed
`--enable-ssl3`, or `--enable-ssl2`, or `SSLv3_method` as `secureProtocol`).
If you have set `securityOptions` to anything, we will not override your
options.
The ramifications of this behavior change: The ramifications of this behavior change:

1
lib/_stream_readable.js

@ -24,6 +24,7 @@ Readable.ReadableState = ReadableState;
var EE = require('events').EventEmitter; var EE = require('events').EventEmitter;
var Stream = require('stream'); var Stream = require('stream');
var Buffer = require('buffer').Buffer;
var util = require('util'); var util = require('util');
var StringDecoder; var StringDecoder;

1
lib/_stream_writable.js

@ -28,6 +28,7 @@ Writable.WritableState = WritableState;
var util = require('util'); var util = require('util');
var Stream = require('stream'); var Stream = require('stream');
var Buffer = require('buffer').Buffer;
util.inherits(Writable, Stream); util.inherits(Writable, Stream);

3
lib/assert.js

@ -24,6 +24,7 @@
// UTILITY // UTILITY
var util = require('util'); var util = require('util');
var b = require('buffer');
var pSlice = Array.prototype.slice; var pSlice = Array.prototype.slice;
// 1. The assert module provides functions that throw // 1. The assert module provides functions that throw
@ -144,7 +145,7 @@ function _deepEqual(actual, expected) {
if (actual === expected) { if (actual === expected) {
return true; return true;
} else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { } else if (b.Buffer.isBuffer(actual) && b.Buffer.isBuffer(expected)) {
if (actual.length != expected.length) return false; if (actual.length != expected.length) return false;
for (var i = 0; i < actual.length; i++) { for (var i = 0; i < actual.length; i++) {

38
lib/crypto.js

@ -61,6 +61,31 @@ var StringDecoder = require('string_decoder').StringDecoder;
var CONTEXT_DEFAULT_OPTIONS = undefined; var CONTEXT_DEFAULT_OPTIONS = undefined;
function getSecureOptions(secureProtocol, secureOptions) {
if (CONTEXT_DEFAULT_OPTIONS === undefined) {
CONTEXT_DEFAULT_OPTIONS = 0;
if (!binding.SSL3_ENABLE)
CONTEXT_DEFAULT_OPTIONS |= constants.SSL_OP_NO_SSLv3;
if (!binding.SSL2_ENABLE)
CONTEXT_DEFAULT_OPTIONS |= constants.SSL_OP_NO_SSLv2;
}
if (secureOptions === undefined) {
if (secureProtocol === undefined ||
secureProtocol === 'SSLv23_method' ||
secureProtocol === 'SSLv23_server_method' ||
secureProtocol === 'SSLv23_client_method') {
secureOptions |= CONTEXT_DEFAULT_OPTIONS;
}
}
return secureOptions;
}
exports._getSecureOptions = getSecureOptions;
function Credentials(secureProtocol, flags, context) { function Credentials(secureProtocol, flags, context) {
if (!(this instanceof Credentials)) { if (!(this instanceof Credentials)) {
return new Credentials(secureProtocol, flags, context); return new Credentials(secureProtocol, flags, context);
@ -82,18 +107,7 @@ function Credentials(secureProtocol, flags, context) {
} }
} }
if (CONTEXT_DEFAULT_OPTIONS === undefined) { flags = getSecureOptions(secureProtocol, flags);
CONTEXT_DEFAULT_OPTIONS = 0;
if (!binding.SSL3_ENABLE)
CONTEXT_DEFAULT_OPTIONS |= constants.SSL_OP_NO_SSLv3;
if (!binding.SSL2_ENABLE)
CONTEXT_DEFAULT_OPTIONS |= constants.SSL_OP_NO_SSLv2;
}
if (flags === undefined)
flags = CONTEXT_DEFAULT_OPTIONS;
this.context.setOptions(flags); this.context.setOptions(flags);
} }

1
lib/dgram.js

@ -22,6 +22,7 @@
var assert = require('assert'); var assert = require('assert');
var util = require('util'); var util = require('util');
var events = require('events'); var events = require('events');
var Buffer = require('buffer').Buffer;
var UDP = process.binding('udp_wrap').UDP; var UDP = process.binding('udp_wrap').UDP;

1
lib/fs.js

@ -31,6 +31,7 @@ var pathModule = require('path');
var binding = process.binding('fs'); var binding = process.binding('fs');
var constants = process.binding('constants'); var constants = process.binding('constants');
var fs = exports; var fs = exports;
var Buffer = require('buffer').Buffer;
var Stream = require('stream').Stream; var Stream = require('stream').Stream;
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;

1
lib/http.js

@ -24,6 +24,7 @@ var net = require('net');
var Stream = require('stream'); var Stream = require('stream');
var timers = require('timers'); var timers = require('timers');
var url = require('url'); var url = require('url');
var Buffer = require('buffer').Buffer;
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var FreeList = require('freelist').FreeList; var FreeList = require('freelist').FreeList;
var HTTPParser = process.binding('http_parser').HTTPParser; var HTTPParser = process.binding('http_parser').HTTPParser;

1
lib/net.js

@ -25,6 +25,7 @@ var timers = require('timers');
var util = require('util'); var util = require('util');
var assert = require('assert'); var assert = require('assert');
var cares = process.binding('cares_wrap'); var cares = process.binding('cares_wrap');
var Buffer = require('buffer').Buffer;
var cluster; var cluster;
function noop() {} function noop() {}

1
lib/readline.js

@ -29,6 +29,7 @@ var kHistorySize = 30;
var kBufSize = 10 * 1024; var kBufSize = 10 * 1024;
var util = require('util'); var util = require('util');
var Buffer = require('buffer').Buffer;
var inherits = require('util').inherits; var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;

20
lib/tls.js

@ -26,6 +26,7 @@ var url = require('url');
var events = require('events'); var events = require('events');
var stream = require('stream'); var stream = require('stream');
var assert = require('assert').ok; var assert = require('assert').ok;
var Buffer = require('buffer').Buffer;
var constants = require('constants'); var constants = require('constants');
var Timer = process.binding('timer_wrap').Timer; var Timer = process.binding('timer_wrap').Timer;
@ -1145,7 +1146,12 @@ function Server(/* [options], listener */) {
// constructor call // constructor call
net.Server.call(this, function(socket) { net.Server.call(this, function(socket) {
var creds = crypto.createCredentials(null, sharedCreds.context); var connOps = {
secureProtocol: self.secureProtocol,
secureOptions: self.secureOptions
};
var creds = crypto.createCredentials(connOps, sharedCreds.context);
var pair = new SecurePair(creds, var pair = new SecurePair(creds,
true, true,
@ -1239,11 +1245,16 @@ Server.prototype.setOptions = function(options) {
if (options.secureProtocol) this.secureProtocol = options.secureProtocol; if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
if (options.crl) this.crl = options.crl; if (options.crl) this.crl = options.crl;
if (options.ciphers) this.ciphers = options.ciphers; if (options.ciphers) this.ciphers = options.ciphers;
var secureOptions = options.secureOptions || 0;
var secureOptions = crypto._getSecureOptions(options.secureProtocol,
options.secureOptions);
if (options.honorCipherOrder) { if (options.honorCipherOrder) {
secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE; secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE;
} }
if (secureOptions) this.secureOptions = secureOptions;
this.secureOptions = secureOptions;
if (options.NPNProtocols) convertNPNProtocols(options.NPNProtocols, this); if (options.NPNProtocols) convertNPNProtocols(options.NPNProtocols, this);
if (options.SNICallback) { if (options.SNICallback) {
this.SNICallback = options.SNICallback; this.SNICallback = options.SNICallback;
@ -1326,6 +1337,9 @@ exports.connect = function(/* [port, host], options, cb */) {
}; };
options = util._extend(defaults, options || {}); options = util._extend(defaults, options || {});
options.secureOptions = crypto._getSecureOptions(options.secureProtocol,
options.secureOptions);
var socket = options.socket ? options.socket : new net.Stream(); var socket = options.socket ? options.socket : new net.Stream();
var sslcontext = crypto.createCredentials(options); var sslcontext = crypto.createCredentials(options);

1
lib/zlib.js

@ -23,6 +23,7 @@ var Transform = require('_stream_transform');
var binding = process.binding('zlib'); var binding = process.binding('zlib');
var util = require('util'); var util = require('util');
var Buffer = require('buffer').Buffer;
var assert = require('assert').ok; var assert = require('assert').ok;
// zlib doesn't provide these, so kludge them in following the same // zlib doesn't provide these, so kludge them in following the same

24
src/node_crypto.cc

@ -238,24 +238,6 @@ 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) { Handle<Value> SecureContext::Init(const Arguments& args) {
HandleScope scope; HandleScope scope;
@ -268,42 +250,36 @@ Handle<Value> SecureContext::Init(const Arguments& args) {
if (strcmp(*sslmethod, "SSLv2_method") == 0) { if (strcmp(*sslmethod, "SSLv2_method") == 0) {
#ifndef OPENSSL_NO_SSL2 #ifndef OPENSSL_NO_SSL2
if (MaybeThrowSSL2()) return Undefined();
method = SSLv2_method(); method = SSLv2_method();
#else #else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled"))); return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif #endif
} else if (strcmp(*sslmethod, "SSLv2_server_method") == 0) { } else if (strcmp(*sslmethod, "SSLv2_server_method") == 0) {
#ifndef OPENSSL_NO_SSL2 #ifndef OPENSSL_NO_SSL2
if (MaybeThrowSSL2()) return Undefined();
method = SSLv2_server_method(); method = SSLv2_server_method();
#else #else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled"))); return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif #endif
} else if (strcmp(*sslmethod, "SSLv2_client_method") == 0) { } else if (strcmp(*sslmethod, "SSLv2_client_method") == 0) {
#ifndef OPENSSL_NO_SSL2 #ifndef OPENSSL_NO_SSL2
if (MaybeThrowSSL2()) return Undefined();
method = SSLv2_client_method(); method = SSLv2_client_method();
#else #else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled"))); return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif #endif
} else if (strcmp(*sslmethod, "SSLv3_method") == 0) { } else if (strcmp(*sslmethod, "SSLv3_method") == 0) {
#ifndef OPENSSL_NO_SSL3 #ifndef OPENSSL_NO_SSL3
if (MaybeThrowSSL3()) return Undefined();
method = SSLv3_method(); method = SSLv3_method();
#else #else
return ThrowException(Exception::Error(String::New("SSLv3 methods disabled"))); return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
#endif #endif
} else if (strcmp(*sslmethod, "SSLv3_server_method") == 0) { } else if (strcmp(*sslmethod, "SSLv3_server_method") == 0) {
#ifndef OPENSSL_NO_SSL3 #ifndef OPENSSL_NO_SSL3
if (MaybeThrowSSL3()) return Undefined();
method = SSLv3_server_method(); method = SSLv3_server_method();
#else #else
return ThrowException(Exception::Error(String::New("SSLv3 methods disabled"))); return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));
#endif #endif
} else if (strcmp(*sslmethod, "SSLv3_client_method") == 0) { } else if (strcmp(*sslmethod, "SSLv3_client_method") == 0) {
#ifndef OPENSSL_NO_SSL3 #ifndef OPENSSL_NO_SSL3
if (MaybeThrowSSL3()) return Undefined();
method = SSLv3_client_method(); method = SSLv3_client_method();
#else #else
return ThrowException(Exception::Error(String::New("SSLv3 methods disabled"))); return ThrowException(Exception::Error(String::New("SSLv3 methods disabled")));

2
src/node_version.h

@ -24,7 +24,7 @@
#define NODE_MAJOR_VERSION 0 #define NODE_MAJOR_VERSION 0
#define NODE_MINOR_VERSION 10 #define NODE_MINOR_VERSION 10
#define NODE_PATCH_VERSION 33 #define NODE_PATCH_VERSION 34
#define NODE_VERSION_IS_RELEASE 0 #define NODE_VERSION_IS_RELEASE 0

1
test/external/ssl-options/.gitignore

@ -0,0 +1 @@
node_modules/

15
test/external/ssl-options/package.json

@ -0,0 +1,15 @@
{
"name": "ssl-options-tests",
"version": "1.0.0",
"description": "",
"main": "test.js",
"scripts": {
"test": "node test.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"async": "^0.9.0",
"debug": "^2.1.0"
}
}

729
test/external/ssl-options/test.js

@ -0,0 +1,729 @@
var tls = require('tls');
var fs = require('fs');
var path = require('path');
var fork = require('child_process').fork;
var assert = require('assert');
var constants = require('constants');
var os = require('os');
var async = require('async');
var debug = require('debug')('test-node-ssl');
var common = require('../../common');
var SSL2_COMPATIBLE_CIPHERS = 'RC4-MD5';
var CMD_LINE_OPTIONS = [ null, "--enable-ssl2", "--enable-ssl3" ];
var SERVER_SSL_PROTOCOLS = [
null,
'SSLv2_method', 'SSLv2_server_method',
'SSLv3_method', 'SSLv3_server_method',
'TLSv1_method', 'TLSv1_server_method',
'SSLv23_method','SSLv23_server_method'
];
var CLIENT_SSL_PROTOCOLS = [
null,
'SSLv2_method', 'SSLv2_client_method',
'SSLv3_method', 'SSLv3_client_method',
'TLSv1_method', 'TLSv1_client_method',
'SSLv23_method','SSLv23_client_method'
];
var SECURE_OPTIONS = [
null,
0,
constants.SSL_OP_NO_SSLv2,
constants.SSL_OP_NO_SSLv3,
constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3
];
function xtend(source) {
var clone = {};
for (var property in source) {
if (source.hasOwnProperty(property)) {
clone[property] = source[property];
}
}
return clone;
}
function isAutoNegotiationProtocol(sslProtocol) {
assert(sslProtocol === null || typeof sslProtocol === 'string');
return sslProtocol == null ||
sslProtocol === 'SSLv23_method' ||
sslProtocol === 'SSLv23_client_method' ||
sslProtocol === 'SSLv23_server_method';
}
function isSameSslProtocolVersion(serverSecureProtocol, clientSecureProtocol) {
assert(serverSecureProtocol === null || typeof serverSecureProtocol === 'string');
assert(clientSecureProtocol === null || typeof clientSecureProtocol === 'string');
if (serverSecureProtocol === clientSecureProtocol) {
return true;
}
var serverProtocolPrefix = '';
if (serverSecureProtocol)
serverProtocolPrefix = serverSecureProtocol.split('_')[0];
var clientProtocolPrefix = '';
if (clientSecureProtocol)
clientProtocolPrefix = clientSecureProtocol.split('_')[0];
if (serverProtocolPrefix === clientProtocolPrefix) {
return true;
}
return false;
}
function secureProtocolsCompatible(serverSecureProtocol, clientSecureProtocol) {
if (isAutoNegotiationProtocol(serverSecureProtocol) ||
isAutoNegotiationProtocol(clientSecureProtocol)) {
return true;
}
if (isSameSslProtocolVersion(serverSecureProtocol,
clientSecureProtocol)) {
return true;
}
return false;
}
function isSsl3Protocol(secureProtocol) {
assert(secureProtocol === null || typeof secureProtocol === 'string');
return secureProtocol === 'SSLv3_method' ||
secureProtocol === 'SSLv3_client_method' ||
secureProtocol === 'SSLv3_server_method';
}
function isSsl2Protocol(secureProtocol) {
assert(secureProtocol === null || typeof secureProtocol === 'string');
return secureProtocol === 'SSLv2_method' ||
secureProtocol === 'SSLv2_client_method' ||
secureProtocol === 'SSLv2_server_method';
}
function secureProtocolCompatibleWithSecureOptions(secureProtocol, secureOptions, cmdLineOption) {
if (secureOptions == null) {
if (isSsl2Protocol(secureProtocol) &&
(!cmdLineOption || cmdLineOption.indexOf('--enable-ssl2') === -1)) {
return false;
}
if (isSsl3Protocol(secureProtocol) &&
(!cmdLineOption || cmdLineOption.indexOf('--enable-ssl3') === -1)) {
return false;
}
} else {
if (secureOptions & constants.SSL_OP_NO_SSLv2 && isSsl2Protocol(secureProtocol)) {
return false;
}
if (secureOptions & constants.SSL_OP_NO_SSLv3 && isSsl3Protocol(secureProtocol)) {
return false;
}
}
return true;
}
function testSetupsCompatible(serverSetup, clientSetup) {
debug('Determing test result for:');
debug(serverSetup);
debug(clientSetup);
/*
* If the protocols specified by the client and server are
* not compatible (e.g SSLv2 vs SSLv3), then the test should fail.
*/
if (!secureProtocolsCompatible(serverSetup.secureProtocol,
clientSetup.secureProtocol)) {
debug('secureProtocols not compatible! server secureProtocol: ' +
serverSetup.secureProtocol + ', client secureProtocol: ' +
clientSetup.secureProtocol);
return false;
}
/*
* If the client's options are not compatible with the server's protocol,
* then the test should fail. Same if server's options are not compatible
* with the client's protocol.
*/
if (!secureProtocolCompatibleWithSecureOptions(serverSetup.secureProtocol,
clientSetup.secureOptions,
clientSetup.cmdLine) ||
!secureProtocolCompatibleWithSecureOptions(clientSetup.secureProtocol,
serverSetup.secureOptions,
serverSetup.cmdLine)) {
debug('Secure protocol not compatible with secure options!');
return false;
}
if (isSsl2Protocol(serverSetup.secureProtocol) ||
isSsl2Protocol(clientSetup.secureProtocol)) {
/*
* It seems that in order to be able to use SSLv2, at least the server
* *needs* to advertise at least one cipher compatible with it.
*/
if (serverSetup.ciphers !== SSL2_COMPATIBLE_CIPHERS) {
return false;
}
/*
* If only either one of the client or server specify SSLv2 as their
* protocol, then *both* of them *need* to advertise at least one cipher
* that is compatible with SSLv2.
*/
if ((!isSsl2Protocol(serverSetup.secureProtocol) || !isSsl2Protocol(clientSetup.secureProtocol)) &&
(clientSetup.ciphers !== SSL2_COMPATIBLE_CIPHERS || serverSetup.ciphers !== SSL2_COMPATIBLE_CIPHERS)) {
return false;
}
}
return true;
}
function sslSetupMakesSense(cmdLineOption, secureProtocol, secureOption) {
if (isSsl2Protocol(secureProtocol)) {
if (secureOption & constants.SSL_OP_NO_SSLv2 ||
(secureOption == null && (!cmdLineOption || cmdLineOption.indexOf('--enable-ssl2') === -1))) {
return false;
}
}
if (isSsl3Protocol(secureProtocol)) {
if (secureOption & constants.SSL_OP_NO_SSLv3 ||
(secureOption == null && (!cmdLineOption || cmdLineOption.indexOf('--enable-ssl3') === -1))) {
return false;
}
}
return true;
}
function createTestsSetups() {
var serversSetup = [];
var clientsSetup = [];
CMD_LINE_OPTIONS.forEach(function (cmdLineOption) {
SERVER_SSL_PROTOCOLS.forEach(function (serverSecureProtocol) {
SECURE_OPTIONS.forEach(function (secureOption) {
if (sslSetupMakesSense(cmdLineOption,
serverSecureProtocol,
secureOption)) {
var serverSetup = {
cmdLine: cmdLineOption,
secureProtocol: serverSecureProtocol,
secureOptions: secureOption
};
serversSetup.push(serverSetup);
if (isSsl2Protocol(serverSecureProtocol)) {
var setupWithSsl2Ciphers = xtend(serverSetup);
setupWithSsl2Ciphers.ciphers = SSL2_COMPATIBLE_CIPHERS;
serversSetup.push(setupWithSsl2Ciphers);
}
}
});
});
CLIENT_SSL_PROTOCOLS.forEach(function (clientSecureProtocol) {
SECURE_OPTIONS.forEach(function (secureOption) {
if (sslSetupMakesSense(cmdLineOption,
clientSecureProtocol,
secureOption)) {
var clientSetup = {
cmdLine: cmdLineOption,
secureProtocol: clientSecureProtocol,
secureOptions: secureOption
};
clientsSetup.push(clientSetup);
if (isSsl2Protocol(clientSecureProtocol)) {
var setupWithSsl2Ciphers = xtend(clientSetup);
setupWithSsl2Ciphers.ciphers = SSL2_COMPATIBLE_CIPHERS;
clientsSetup.push(setupWithSsl2Ciphers);
}
}
});
});
});
var testSetups = [];
var testId = 0;
serversSetup.forEach(function (serverSetup) {
clientsSetup.forEach(function (clientSetup) {
var testSetup = {
server: serverSetup,
client: clientSetup,
ID: testId++
};
var successExpected = false;
if (testSetupsCompatible(serverSetup, clientSetup)) {
successExpected = true;
}
testSetup.successExpected = successExpected;
testSetups.push(testSetup);
});
});
return testSetups;
}
function runServer(port, secureProtocol, secureOptions, ciphers) {
debug('Running server!');
debug('port: ' + port);
debug('secureProtocol: ' + secureProtocol);
debug('secureOptions: ' + secureOptions);
debug('ciphers: ' + ciphers);
var keyPath = path.join(common.fixturesDir, 'agent.key');
var certPath = path.join(common.fixturesDir, 'agent.crt');
var key = fs.readFileSync(keyPath).toString();
var cert = fs.readFileSync(certPath).toString();
var server = new tls.Server({ key: key,
cert: cert,
ca: [],
ciphers: ciphers,
secureProtocol: secureProtocol,
secureOptions: secureOptions
});
server.listen(port, function() {
process.on('message', function onChildMsg(msg) {
if (msg === 'close') {
server.close();
process.exit(0);
}
});
process.send('server_listening');
});
server.on('error', function onServerError(err) {
debug('Server error: ' + err);
process.exit(1);
});
server.on('clientError', function onClientError(err) {
debug('Client error on server: ' + err);
process.exit(1);
});
}
function runClient(port, secureProtocol, secureOptions, ciphers) {
debug('Running client!');
debug('port: ' + port);
debug('secureProtocol: ' + secureProtocol);
debug('secureOptions: ' + secureOptions);
debug('ciphers: ' + ciphers);
var con = tls.connect(port,
{
rejectUnauthorized: false,
secureProtocol: secureProtocol,
secureOptions: secureOptions
},
function() {
// TODO jgilli: test that sslProtocolUsed is at least as "secure" as
// "secureProtocol"
/*
* var sslProtocolUsed = con.getVersion();
* debug('Protocol used: ' + sslProtocolUsed);
*/
process.send('client_done');
});
con.on('error', function(err) {
debug('Client could not connect:' + err);
process.exit(1);
});
}
function stringToSecureOptions(secureOptionsString) {
assert(typeof secureOptionsString === 'string');
var secureOptions;
var optionStrings = secureOptionsString.split('|');
optionStrings.forEach(function (option) {
if (option === 'SSL_OP_NO_SSLv2') {
secureOptions |= constants.SSL_OP_NO_SSLv2;
}
if (option === 'SSL_OP_NO_SSLv3') {
secureOptions |= constants.SSL_OP_NO_SSLv3;
}
if (option === '0') {
secureOptions = 0;
}
});
return secureOptions;
}
function processTestCmdLineOptions(argv){
var options = {};
argv.forEach(function (arg) {
var key;
var value;
var keyValue = arg.split(':');
var key = keyValue[0];
if (keyValue.length == 2 && keyValue[1].length > 0) {
value = keyValue[1];
if (key === 'secureOptions') {
value = stringToSecureOptions(value);
}
if (key === 'port') {
value = +value;
}
}
options[key] = value;
});
return options;
}
function checkTestExitCode(testSetup, serverExitCode, clientExitCode) {
if (testSetup.successExpected) {
if (serverExitCode === 0 && clientExitCode === 0) {
debug('Test succeeded as expected!');
return true;
}
} else {
if (serverExitCode !== 0 || clientExitCode !== 0) {
debug('Test failed as expected!');
return true;
}
}
return false;
}
function secureOptionsToString(secureOptions) {
var secureOptsString = '';
if (secureOptions & constants.SSL_OP_NO_SSLv2) {
secureOptsString += 'SSL_OP_NO_SSLv2';
}
if (secureOptions & constants.SSL_OP_NO_SSLv3) {
secureOptsString += '|SSL_OP_NO_SSLv3';
}
if (secureOptions === 0) {
secureOptsString = '0';
}
return secureOptsString;
}
function forkTestProcess(processType, testSetup, port) {
var argv = [ processType ];
if (testSetup.secureProtocol) {
argv.push('secureProtocol:' + testSetup.secureProtocol);
} else {
argv.push('secureProtocol:');
}
argv.push('secureOptions:' + secureOptionsToString(testSetup.secureOptions));
if (testSetup.ciphers) {
argv.push('ciphers:' + testSetup.ciphers);
} else {
argv.push('ciphers:');
}
argv.push('port:' + port);
var forkOptions;
if (testSetup.cmdLine) {
forkOptions = {
execArgv: [ testSetup.cmdLine ]
}
}
return fork(process.argv[1],
argv,
forkOptions);
}
function runTest(testSetup, testDone) {
var clientSetup = testSetup.client;
var serverSetup = testSetup.server;
assert(clientSetup);
assert(serverSetup);
debug('Starting new test on port: ' + testSetup.port);
debug('client setup:');
debug(clientSetup);
debug('server setup:');
debug(serverSetup);
debug('Success expected:' + testSetup.successExpected);
var serverExitCode;
var clientStarted = false;
var clientExitCode;
var serverChild = forkTestProcess('server', serverSetup, testSetup.port);
assert(serverChild);
serverChild.on('message', function onServerMsg(msg) {
if (msg === 'server_listening') {
debug('Starting client!');
clientStarted = true;
var clientChild = forkTestProcess('client', clientSetup, testSetup.port);
assert(clientChild);
clientChild.on('exit', function onClientExited(exitCode) {
debug('Client exited with code:' + exitCode);
clientExitCode = exitCode;
if (serverExitCode != null) {
var err;
if (!checkTestExitCode(testSetup, serverExitCode, clientExitCode))
err = new Error("Test failed!");
return testDone(err);
} else {
if (serverChild.connected) {
serverChild.send('close');
}
}
});
clientChild.on('message', function onClientMsg(msg) {
if (msg === 'client_done' && serverChild.connected) {
serverChild.send('close');
}
})
}
});
serverChild.on('exit', function onServerExited(exitCode) {
debug('Server exited with code:' + exitCode);
serverExitCode = exitCode;
if (clientExitCode != null || !clientStarted) {
var err;
if (!checkTestExitCode(testSetup, serverExitCode, clientExitCode))
err = new Error("Test failed!");
return testDone(err);
}
});
}
function usage() {
console.log('Usage: test-node-ssl [-j N] [--list-tests] [-s startIndex] ' +
'[-e endIndex] [-o outputFile]');
process.exit(1);
}
function processDriverCmdLineOptions(argv) {
var options = {
parallelTests: 1
};
for (var i = 1; i < argv.length; ++i) {
if (argv[i] === '-j') {
var nbParallelTests = +argv[i + 1];
if (!nbParallelTests) {
usage();
} else {
options.parallelTests = argv[++i];
}
}
if (argv[i] === '-s') {
var start = +argv[i + 1];
if (!start) {
usage();
} else {
options.start = argv[++i];
}
}
if (argv[i] === '-e') {
var end = +argv[i + 1];
if (!end) {
usage();
} else {
options.end = argv[++i];
}
}
if (argv[i] === '--list-tests') {
options.listTests = true;
}
if (argv[i] === '-o') {
var outputFile = argv[i + 1];
if (!outputFile) {
usage();
} else {
options.outputFile = argv[++i];
}
}
}
return options;
}
function outputTestResult(test, err, output) {
output.write(os.EOL);
output.write('Test:' + os.EOL);
output.write(JSON.stringify(test, null, " "));
output.write(os.EOL);
output.write('Result:');
output.write(err ? 'failure' : 'success');
output.write(os.EOL);
}
var agentType = process.argv[2];
if (agentType === 'client' || agentType === 'server') {
var options = processTestCmdLineOptions(process.argv);
debug('secureProtocol: ' + options.secureProtocol);
debug('secureOptions: ' + options.secureOptions);
debug('ciphers:' + options.ciphers);
debug('port:' + options.port);
if (agentType === 'client') {
runClient(options.port,
options.secureProtocol,
options.secureOptions,
options.ciphers);
} else if (agentType === 'server') {
runServer(options.port,
options.secureProtocol,
options.secureOptions,
options.ciphers);
}
} else {
var driverOptions = processDriverCmdLineOptions(process.argv);
debug('Tests driver options:');
debug(driverOptions);
/*
* This is the tests driver process.
*
* It forks itself twice for each test. Each of the two forked processees are
* respectfully used as an SSL client and an SSL server. The client and
* server setup their SSL connection as generated by the "createTestsSetups"
* function. Once both processes have exited, the tests driver process
* compare both client and server exit codes with the expected test result
* of the test setup. If they match, the test is successful, otherwise it
* failed.
*/
var testSetups = createTestsSetups();
if (driverOptions.listTests) {
console.log(testSetups);
process.exit(0);
}
var testOutput = process.stdout;
if (driverOptions.outputFile) {
testOutput = fs.createWriteStream(driverOptions.outputFile)
.on('error', function onError(err) {
console.error(err);
process.exit(1);
});
}
debug('Tests setups:');
debug('Number of tests: ' + testSetups.length);
debug(JSON.stringify(testSetups, null, " "));
debug();
var nbTestsStarted = 0;
function runTests(tests, callback) {
var nbTests = tests.length;
if (nbTests === 0) {
return callback();
}
var error;
var nbTestsDone = 0;
debug('Starting new batch of tests...');
var port = common.PORT;
async.each(tests, function (test, testDone) {
test.port = port++;
++nbTestsStarted;
debug('Starting test nb: ' + nbTestsStarted);
runTest(test, function onTestDone(err) {
++nbTestsDone;
if (err && error === undefined) {
error = new Error('Test with ID ' + test.ID + ' failed: ' + err);
}
outputTestResult(test, err, testOutput);
if (nbTestsDone === nbTests)
return testDone(error);
return testDone();
});
}, function testsDone(err, results) {
if (err) {
assert(false,
"At least one test in the most recent batch failed: " + err);
}
return callback(err);
});
}
function runAllTests(allTests, allTestsDone) {
if (allTests.length === 0) {
return allTestsDone();
}
return runTests(allTests.splice(0, driverOptions.parallelTests),
runAllTests.bind(global, allTests, allTestsDone));
}
runAllTests(testSetups.slice(driverOptions.start, driverOptions.end),
function allDone(err) {
console.log('All tests done!');
});
}

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

@ -1,53 +0,0 @@
// 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
test/simple/test-tls-disable-ssl3.js

@ -1,53 +0,0 @@
// 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
test/simple/test-tls-enable-ssl2.js

@ -1,55 +0,0 @@
// 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');
}

55
test/simple/test-tls-enable-ssl3.js

@ -1,55 +0,0 @@
// 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');
}

131
test/simple/test-tls-honorcipherorder-secureOptions.js

@ -0,0 +1,131 @@
// 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 nconns = 0;
var SSL_Method = 'SSLv23_method';
var localhost = '127.0.0.1';
var opCipher = process.binding('constants').SSL_OP_CIPHER_SERVER_PREFERENCE;
/*
* This test is to make sure we are preserving secureOptions that are passed
* to the server.
*
* Also that if honorCipherOrder is passed we are preserving that in the
* options.
*
* And that if we are passing in secureOptions no new options (aside from the
* honorCipherOrder case) are added to the secureOptions
*/
process.on('exit', function() {
assert.equal(nconns, 6);
});
function test(honorCipherOrder, clientCipher, expectedCipher, secureOptions, 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',
secureOptions: secureOptions,
honorCipherOrder: !!honorCipherOrder
};
var server = tls.createServer(soptions, function(cleartextStream) {
nconns++;
});
if (!!honorCipherOrder) {
assert.strictEqual(server.secureOptions & opCipher, opCipher, 'we should preserve cipher preference');
}
if (secureOptions) {
var expectedSecureOpts = secureOptions;
if (!!honorCipherOrder) expectedSecureOpts |= opCipher;
assert.strictEqual(server.secureOptions & expectedSecureOpts,
expectedSecureOpts, 'we should preserve secureOptions');
assert.strictEqual(server.secureOptions & ~expectedSecureOpts,
0,
'we should not add extra options');
}
server.listen(common.PORT, localhost, function() {
var coptions = {
rejectUnauthorized: false,
secureProtocol: SSL_Method
};
if (clientCipher) {
coptions.ciphers = clientCipher;
}
var client = tls.connect(common.PORT, localhost, coptions, function() {
var cipher = client.getCipher();
client.end();
server.close();
assert.equal(cipher.name, expectedCipher);
if (cb) cb();
});
});
}
test1();
function test1() {
// Client has the preference of cipher suites by default
test(false, 'DES-CBC-SHA:RC4-SHA:AES256-SHA','DES-CBC-SHA', 0, test2);
}
function test2() {
// Server has the preference of cipher suites where AES256-SHA is in
// the first.
test(true, 'DES-CBC-SHA:RC4-SHA:AES256-SHA', 'AES256-SHA', 0, test3);
}
function test3() {
// Server has the preference of cipher suites. RC4-SHA is given
// higher priority over DES-CBC-SHA among client cipher suites.
test(true, 'DES-CBC-SHA:RC4-SHA', 'RC4-SHA', 0, test4);
}
function test4() {
// As client has only one cipher, server has no choice in regardless
// of honorCipherOrder.
test(true, 'DES-CBC-SHA', 'DES-CBC-SHA', 0, test5);
}
function test5() {
test(false,
'DES-CBC-SHA',
'DES-CBC-SHA',
process.binding('constants').SSL_OP_SINGLE_DH_USE, test6);
}
function test6() {
test(true,
'DES-CBC-SHA',
'DES-CBC-SHA',
process.binding('constants').SSL_OP_SINGLE_DH_USE);
}
Loading…
Cancel
Save