@@ -31,15 +31,16 @@ test("outdated ignores private modules", function (t) {
function () {
npm.install(".", function (err) {
t.ifError(err, "install success")
bumpLocalPrivate()
npm.outdated(function (er, d) {
t.ifError(er, "outdated success")
t.deepEqual(d, [[
path.resolve(__dirname, "outdated-private"),
"underscore",
"1.3.1",
"1.3.1",
"1.5.1",
"file:underscore"
"1.5.1",
"underscore@1.5.1"
]])
s.close()
})
@@ -70,6 +71,12 @@ var pjLocalPrivate = JSON.stringify({
private : true
}, null, 2) + "\n"

var pjLocalPrivateBumped = JSON.stringify({
name : "local-private",
version : "1.1.0",
private : true
}, null, 2) + "\n"

var pjScopedLocalPrivate = JSON.stringify({
name : "@scoped/another-local-private",
version : "1.0.0",
@@ -95,6 +102,10 @@ function bootstrap () {
fs.writeFileSync(path.resolve(pkgLocalUnderscore, "package.json"), pjLocalUnderscore)
}

function bumpLocalPrivate () {
fs.writeFileSync(path.resolve(pkgLocalPrivate, "package.json"), pjLocalPrivateBumped)
}

function cleanup () {
process.chdir(osenv.tmpdir())
rimraf.sync(pkg)
@@ -0,0 +1,88 @@
var common = require('../common-tap.js')
var fs = require('fs')
var path = require('path')

var mkdirp = require('mkdirp')
var osenv = require('osenv')
var rimraf = require('rimraf')
var test = require('tap').test

var npm = require('../../lib/npm.js')

var pkg = path.resolve(__dirname, 'version-message-config')
var cache = path.resolve(pkg, 'cache')
var npmrc = path.resolve(pkg, '.npmrc')
var packagePath = path.resolve(pkg, 'package.json')

var json = { name: 'blah', version: '0.1.2' }

var configContents = 'sign-git-tag=false\nmessage=":bookmark: %s"\n'

test('npm version <semver> with message config', function (t) {
setup()

npm.load({ prefix: pkg, userconfig: npmrc }, function () {
var git = require('../../lib/utils/git.js')

common.makeGitRepo({ path: pkg }, function (er) {
t.ifErr(er, 'git bootstrap ran without error')

common.npm([
'config',
'set',
'tag-version-prefix',
'q'
], { cwd: pkg, env: { PATH: process.env.PATH } },
function (err, code, stdout, stderr) {
t.ifError(err, 'npm config ran without issue')
t.notOk(code, 'exited with a non-error code')
t.notOk(stderr, 'no error output')

common.npm(
[
'version',
'patch',
'--loglevel', 'silent'
// package config is picked up from env
],
{ cwd: pkg, env: { PATH: process.env.PATH } },
function (err, code, stdout, stderr) {
t.ifError(err, 'npm version ran without issue')
t.notOk(code, 'exited with a non-error code')
t.notOk(stderr, 'no error output')

git.whichAndExec(
['tag'],
{ cwd: pkg, env: process.env },
function (er, tags, stderr) {
t.ok(tags.match(/q0\.1\.3/g), 'tag was created by version' + tags)
t.end()
}
)
}
)
})
})
})
})

test('cleanup', function (t) {
cleanup()
t.end()
})

function cleanup () {
// windows fix for locked files
process.chdir(osenv.tmpdir())

rimraf.sync(pkg)
}

function setup () {
cleanup()
mkdirp.sync(cache)
process.chdir(pkg)

fs.writeFileSync(packagePath, JSON.stringify(json), 'utf8')
fs.writeFileSync(npmrc, configContents, 'ascii')
}
@@ -0,0 +1,82 @@
var fs = require('graceful-fs')
var http = require('http')
var path = require('path')

var mkdirp = require('mkdirp')
var osenv = require('osenv')
var rimraf = require('rimraf')
var test = require('tap').test

var pkg = path.join(__dirname, 'npm-test-unpublish-config')
var fixturePath = path.join(pkg, 'fixture_npmrc')

var common = require('../common-tap.js')

var json = {
name: 'npm-test-unpublish-config',
version: '1.2.3',
publishConfig: { registry: common.registry }
}

test('setup', function (t) {
mkdirp.sync(pkg)

fs.writeFileSync(
path.join(pkg, 'package.json'),
JSON.stringify(json), 'utf8'
)
fs.writeFileSync(
fixturePath,
'//localhost:1337/:_authToken = beeeeeeeeeeeeef\n' +
'registry = http://lvh.me:4321/registry/path\n'
)

t.end()
})

test('cursory test of unpublishing with config', function (t) {
var child
http.createServer(function (req, res) {
t.pass('got request on the fakey fake registry')
this.close()
res.statusCode = 500
res.end(JSON.stringify({
error: 'shh no tears, only dreams now'
}))
child.kill()
t.end()
}).listen(common.port, function () {
t.pass('server is listening')

child = common.npm(
[
'--userconfig', fixturePath,
'--loglevel', 'silent',
'--force',
'unpublish'
],
{
cwd: pkg,
stdio: 'inherit',
env: {
'npm_config_cache_lock_stale': 1000,
'npm_config_cache_lock_wait': 1000,
HOME: process.env.HOME,
Path: process.env.PATH,
PATH: process.env.PATH,
USERPROFILE: osenv.home()
}
},
function (err, code) {
t.ifError(err, 'publish command finished successfully')
t.notOk(code, 'npm install exited with code 0')
}
)
})
})

test('cleanup', function (t) {
process.chdir(osenv.tmpdir())
rimraf.sync(pkg)
t.end()
})
@@ -134,75 +134,6 @@ the character "E" appended to the traditional abbreviations):
Ephemeral methods may have some performance drawbacks, because key generation
is expensive.

## Modifying the Default Cipher Suite

Node.js is built with a default suite of enabled and disabled ciphers.
Currently, the default cipher suite is:

ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:
!RC4:!MD5:!aNULL

This default can be overridden entirely using the `--cipher-list` command line
switch or `NODE_CIPHER_LIST` environment variable. For instance:

node --cipher-list=ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384

Setting the environment variable would have the same effect:

NODE_CIPHER_LIST=ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384

CAUTION: The default cipher suite has been carefully selected to reflect current
security best practices and risk mitigation. Changing the default cipher suite
can have a significant impact on the security of an application. The
`--cipher-list` and `NODE_CIPHER_LIST` options should only be used if
absolutely necessary.

### Using Legacy Default Cipher Suite ###

It is possible for the built-in default cipher suite to change from one release
of Node.js to another. For instance, v0.10.38 uses a different default than
v0.12.2. Such changes can cause issues with applications written to assume
certain specific defaults. To help buffer applications against such changes,
the `--enable-legacy-cipher-list` command line switch or `NODE_LEGACY_CIPHER_LIST`
environment variable can be set to specify a specific preset default:

# Use the v0.10.38 defaults
node --enable-legacy-cipher-list=v0.10.38
// or
NODE_LEGACY_CIPHER_LIST=v0.10.38

# Use the v0.12.2 defaults
node --enable-legacy-cipher-list=v0.12.2
// or
NODE_LEGACY_CIPHER_LIST=v0.12.2

Currently, the values supported for the `enable-legacy-cipher-list` switch and
`NODE_LEGACY_CIPHER_LIST` environment variable include:

v0.10.38 - To enable the default cipher suite used in v0.10.38

ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH

v0.10.39 - To enable the default cipher suite used in v0.10.39

ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH

v0.12.2 - To enable the default cipher suite used in v0.12.2

ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:
HIGH:!MD5:!aNULL

These legacy cipher suites are also made available for use via the
`getLegacyCiphers()` method:

var tls = require('tls');
console.log(tls.getLegacyCiphers('v0.10.38'));

CAUTION: Changes to the default cipher suite are typically made in order to
strengthen the default security for applications running within Node.js.
Reverting back to the defaults used by older releases can weaken the security
of your applications. The legacy cipher suites should only be used if absolutely
necessary.

## tls.getCiphers()

@@ -213,12 +144,6 @@ Example:
var ciphers = tls.getCiphers();
console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...]

## tls.getLegacyCiphers(version)

Returns the legacy default cipher suite for the specified Node.js release.

Example:
var cipher_suite = tls.getLegacyCiphers('v0.10.38');

## tls.createServer(options[, secureConnectionListener])

@@ -252,17 +177,20 @@ automatically set as a listener for the [secureConnection][] event. The
prioritize the non-CBC cipher.

Defaults to
`ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL`.
`ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL`.
Consult the [OpenSSL cipher list format documentation] for details
on the format.

`ECDHE-RSA-AES128-SHA256`, `DHE-RSA-AES128-SHA256` and
`AES128-GCM-SHA256` are TLS v1.2 ciphers and used when node.js is
`AES128-GCM-SHA256` are TLS v1.2 ciphers and used when Node.js is
linked against OpenSSL 1.0.1 or newer, such as the bundled version
of OpenSSL. Note that it is still possible for a TLS v1.2 client
to negotiate a weaker cipher unless `honorCipherOrder` is enabled.

`RC4` is explicitly switched off by default due to known vulnerabilities.
`RC4` is used as a fallback for clients that speak on older version of
the TLS protocol. `RC4` has in recent years come under suspicion and
should be considered compromised for anything that is truly sensitive.
It is speculated that state-level actors possess the ability to break it.

**NOTE**: Previous revisions of this section suggested `AES256-SHA` as an
acceptable cipher. Unfortunately, `AES256-SHA` is a CBC cipher and therefore
@@ -413,6 +341,20 @@ Creates a new client connection to the given `port` and `host` (old API) or
- `path`: Creates unix socket connection to path. If this option is
specified, `host` and `port` are ignored.

- `ciphers`: A string describing the ciphers to use or exclude.

Defaults to
`ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL`.
Consult the [OpenSSL cipher list format documentation] for details
on the format.

The full list of available ciphers can be obtained via [tls.getCiphers][].

`ECDHE-RSA-AES128-SHA256`, `DHE-RSA-AES128-SHA256` and
`AES128-GCM-SHA256` are TLS v1.2 ciphers and used when Node.js is
linked against OpenSSL 1.0.1 or newer, such as the bundled version
of OpenSSL.

- `pfx`: A string or `Buffer` containing the private key, certificate and
CA certs of the client in PFX or PKCS12 format.

@@ -907,6 +849,7 @@ The numeric representation of the local port.

[OpenSSL cipher list format documentation]: http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT
[BEAST attacks]: http://blog.ivanristic.com/2011/10/mitigating-the-beast-attack-on-tls.html
[tls.getCiphers]: #tls_tls_getciphers
[tls.createServer]: #tls_tls_createserver_options_secureconnectionlistener
[tls.createSecurePair]: #tls_tls_createsecurepair_credentials_isserver_requestcert_rejectunauthorized
[tls.TLSSocket]: #tls_class_tls_tlssocket
@@ -949,7 +949,7 @@ REPLServer.prototype.convertToContext = function(cmd) {
function isRecoverableError(e) {
return e &&
e.name === 'SyntaxError' &&
/^(Unexpected end of input|Unexpected token :)/.test(e.message);
/^(Unexpected end of input|Unexpected token)/.test(e.message);
}

function Recoverable(err) {
@@ -19,8 +19,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var _crypto = process.binding('crypto');

var net = require('net');
var url = require('url');
var util = require('util');
@@ -35,14 +33,16 @@ exports.CLIENT_RENEG_WINDOW = 600;

exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024;

exports.DEFAULT_CIPHERS = _crypto.DEFAULT_CIPHER_LIST;

exports.getLegacyCiphers = _crypto.getLegacyCiphers;
exports.DEFAULT_CIPHERS =
// TLS 1.2
'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' +
// TLS 1.0
'RC4:HIGH:!MD5:!aNULL';

exports.DEFAULT_ECDH_CURVE = 'prime256v1';

exports.getCiphers = function() {
var names = _crypto.getSSLCiphers();
var names = process.binding('crypto').getSSLCiphers();
// Drop all-caps names in favor of their lowercase aliases,
var ctx = {};
names.forEach(function(name) {
@@ -2936,9 +2936,6 @@ static void PrintHelp() {
#endif
" --enable-ssl2 enable ssl2\n"
" --enable-ssl3 enable ssl3\n"
" --cipher-list=val specify the default TLS cipher list\n"
" --enable-legacy-cipher-list=val \n"
" val = v0.10.38, v0.10.39, or v0.12.2\n"
"\n"
"Environment variables:\n"
#ifdef _WIN32
@@ -2956,9 +2953,6 @@ static void PrintHelp() {
" (will extend linked-in data)\n"
#endif
#endif
"NODE_CIPHER_LIST Override the default TLS cipher list\n"
"NODE_LEGACY_CIPHER_LIST=val\n"
" val = v0.10.38, v0.10.39, or v0.12.2\n"
"\n"
"Documentation can be found at http://nodejs.org/\n");
}
@@ -2998,7 +2992,6 @@ static void ParseArgs(int* argc,
unsigned int new_argc = 1;
new_v8_argv[0] = argv[0];
new_argv[0] = argv[0];
bool using_legacy_cipher_list = false;

unsigned int index = 1;
while (index < nargs && argv[index][0] == '-') {
@@ -3054,20 +3047,6 @@ static void ParseArgs(int* argc,
} else if (strcmp(arg, "--v8-options") == 0) {
new_v8_argv[new_v8_argc] = "--help";
new_v8_argc += 1;
} else if (strncmp(arg, "--cipher-list=", 14) == 0) {
if (!using_legacy_cipher_list) {
DEFAULT_CIPHER_LIST = arg + 14;
}
} else if (strncmp(arg, "--enable-legacy-cipher-list=", 28) == 0) {
// use the original v0.10.x/v0.12.x cipher lists
const char * legacy_list = legacy_cipher_list(arg+28);
if (legacy_list != NULL) {
using_legacy_cipher_list = true;
DEFAULT_CIPHER_LIST = legacy_list;
} else {
fprintf(stderr, "Error: An unknown legacy cipher list was specified\n");
exit(9);
}
#if defined(NODE_HAVE_I18N_SUPPORT)
} else if (strncmp(arg, "--icu-data-dir=", 15) == 0) {
icu_data_dir = arg + 15;
@@ -3435,27 +3414,6 @@ void Init(int* argc,
}
}

const char * cipher_list = getenv("NODE_CIPHER_LIST");
if (cipher_list != NULL) {
DEFAULT_CIPHER_LIST = cipher_list;
}
// Allow the NODE_LEGACY_CIPHER_LIST envar to override the other
// cipher list options. NODE_LEGACY_CIPHER_LIST=v0.10.38 will use
// the cipher list from v0.10.38, NODE_LEGACY_CIPHER_LIST=v0.12.2 will
// use the cipher list from v0.12.2
const char * leg_cipher_id = getenv("NODE_LEGACY_CIPHER_LIST");
if (leg_cipher_id != NULL) {
const char * leg_cipher_list =
legacy_cipher_list(leg_cipher_id);
if (leg_cipher_list != NULL) {
DEFAULT_CIPHER_LIST = leg_cipher_list;
} else {
fprintf(stderr, "Error: An unknown legacy cipher list was specified\n");
exit(9);
}
}


#if defined(NODE_HAVE_I18N_SUPPORT)
if (icu_data_dir == NULL) {
// if the parameter isn't given, use the env variable.
@@ -223,19 +223,6 @@ NODE_EXTERN void RunAtExit(Environment* env);
} \
while (0)

#define NODE_DEFINE_STRING_CONSTANT(target, constant) \
do { \
v8::Isolate* isolate = v8::Isolate::GetCurrent(); \
v8::Local<v8::String> constant_name = \
v8::String::NewFromUtf8(isolate, #constant); \
v8::Local<v8::String> constant_value = \
v8::String::NewFromUtf8(isolate, constant); \
v8::PropertyAttribute constant_attributes = \
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); \
(target)->ForceSet(constant_name, constant_value, constant_attributes); \
} while (0)


// Used to be a macro, hence the uppercase name.
template <typename TypeName>
inline void NODE_SET_METHOD(const TypeName& recv,
@@ -77,7 +77,6 @@ namespace node {

bool SSL2_ENABLE = false;
bool SSL3_ENABLE = false;
const char * DEFAULT_CIPHER_LIST = DEFAULT_CIPHER_LIST_HEAD;

namespace crypto {

@@ -4852,26 +4851,6 @@ static void array_push_back(const TypeName* md,
ctx->arr->Set(ctx->arr->Length(), OneByteString(ctx->env()->isolate(), from));
}

// borrowed from v8
// (see http://v8.googlecode.com/svn/trunk/samples/shell.cc)
const char* ToCString(const String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}

void DefaultCiphers(const v8::FunctionCallbackInfo<v8::Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope scope(env->isolate());
v8::String::Utf8Value key(args[0]);
const char * list = legacy_cipher_list(ToCString(key));
if (list != NULL) {
args.GetReturnValue().Set(
v8::String::NewFromUtf8(args.GetIsolate(), list));
} else {
args.GetReturnValue().Set(
v8::String::NewFromUtf8(args.GetIsolate(),
DEFAULT_CIPHER_LIST_HEAD));
}
}

void GetCiphers(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
@@ -5192,8 +5171,6 @@ void InitCrypto(Handle<Object> target,

NODE_DEFINE_CONSTANT(target, SSL3_ENABLE);
NODE_DEFINE_CONSTANT(target, SSL2_ENABLE);
NODE_DEFINE_STRING_CONSTANT(target, DEFAULT_CIPHER_LIST);
NODE_SET_METHOD(target, "getLegacyCiphers", DefaultCiphers);
}

} // namespace crypto
@@ -38,7 +38,6 @@

#include "v8.h"

#include <string.h>
#include <openssl/ssl.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
@@ -60,40 +59,10 @@
# define NODE__HAVE_TLSEXT_STATUS_CB
#endif // !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb)

#define DEFAULT_CIPHER_LIST_V10_38 "ECDHE-RSA-AES128-SHA256:" \
"AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH"

#define DEFAULT_CIPHER_LIST_V10_39 "ECDHE-RSA-AES128-SHA256:" \
"AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH"

#define DEFAULT_CIPHER_LIST_V12_2 "ECDHE-RSA-AES128-SHA256:" \
"DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:" \
"HIGH:!MD5:!aNULL"

#define DEFAULT_CIPHER_LIST_HEAD "ECDHE-RSA-AES128-SHA256:" \
"DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:"\
"!RC4:!MD5:!aNULL"

static inline const char * legacy_cipher_list(const char * ver) {
if (ver == NULL) {
return NULL;
}
if (strncmp(ver, "v0.10.38", 8) == 0) {
return DEFAULT_CIPHER_LIST_V10_38;
} else if (strncmp(ver, "v0.10.39", 8) == 0) {
return DEFAULT_CIPHER_LIST_V10_39;
} else if (strncmp(ver, "v0.12.2", 7) == 0) {
return DEFAULT_CIPHER_LIST_V12_2;
} else {
return NULL;
}
}

namespace node {

extern bool SSL2_ENABLE;
extern bool SSL3_ENABLE;
extern const char * DEFAULT_CIPHER_LIST;

namespace crypto {

@@ -24,7 +24,7 @@

#define NODE_MAJOR_VERSION 0
#define NODE_MINOR_VERSION 12
#define NODE_PATCH_VERSION 3
#define NODE_PATCH_VERSION 4

#define NODE_VERSION_IS_RELEASE 0

@@ -6,7 +6,6 @@ test-cluster-basic : PASS,FLAKY

[$system==win32]
test-timers-first-fire : PASS,FLAKY
test-tls-server-verify : PASS,FLAKY

[$system==linux]
test-fs-readfile-error : PASS,FLAKY
@@ -41,7 +41,7 @@ var ret = spawnSync('sleep', ['1']);
var stop = process.hrtime(start);
assert.strictEqual(ret.status, 0, 'exit status should be zero');
console.log('sleep exited', stop);
assert.strictEqual(stop[0], 1, 'sleep should not take longer or less than 1 second');
assert.ok(stop[0] >= 1, 'sleep should not take less than 1 second');

// Error test when command does not exist
var ret_err = spawnSync('command_does_not_exist');

This file was deleted.

@@ -19,51 +19,35 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var spawn = require('child_process').spawn;
/*
* This is a regression test for https://github.com/joyent/node/issues/8874.
*/
var common = require('../common');
var assert = require('assert');
var tls = require('tls');

function doTest(checklist, env, useswitch) {
var options;
if (env && useswitch === 1) {
options = {env:env};
}
var args = ['-e', 'console.log(require(\'tls\').DEFAULT_CIPHERS)'];
var spawn = require('child_process').spawn;
// use -i to force node into interactive mode, despite stdout not being a TTY
var args = [ '-i' ];
var child = spawn(process.execPath, args);

switch(useswitch) {
case 1:
// Test --cipher-test
args.unshift('--cipher-list=' + env);
break;
case 2:
// Test --enable-legacy-cipher-list
args.unshift('--enable-legacy-cipher-list=' + env);
break;
case 3:
// Test NODE_LEGACY_CIPHER_LIST
if (env) options = {env:{"NODE_LEGACY_CIPHER_LIST": env}};
break;
default:
// Test NODE_CIPHER_LIST
if (env) options = {env:env};
}
var input = 'var foo = "bar\\\nbaz"';
// Match '...' as well since it marks a multi-line statement
var expectOut = /^> ... undefined\n/;

var out = '';
spawn(process.execPath, args, options).
stdout.
on('data', function(data) {
out += data;
}).
on('end', function() {
assert.equal(out.trim(), checklist);
});
}
child.stderr.setEncoding('utf8');
child.stderr.on('data', function(c) {
throw new Error('child.stderr be silent');
});

doTest(tls.DEFAULT_CIPHERS); // test the default
doTest('ABC', {'NODE_CIPHER_LIST':'ABC'}); // test the envar
doTest('ABC', 'ABC', 1); // test the --cipher-list switch
child.stdout.setEncoding('utf8');
var out = '';
child.stdout.on('data', function(c) {
out += c;
});

['v0.10.38', 'v0.10.39', 'v0.12.2'].forEach(function(ver) {
doTest(tls.getLegacyCiphers(ver), ver, 2);
doTest(tls.getLegacyCiphers(ver), ver, 3);
child.stdout.on('end', function() {
assert(expectOut.test(out));
console.log('ok');
});

child.stdin.end(input);
@@ -49,7 +49,7 @@ server.listen(common.PORT, '127.0.0.1', function() {
rejectUnauthorized: false
}, function() {
var cipher = client.getCipher();
assert.equal(cipher.name, cipher_list[1]);
assert.equal(cipher.name, cipher_list[0]);
assert(cipher_version_pattern.test(cipher.version));
client.end();
server.close();
@@ -141,17 +141,17 @@ var serverKey = loadPEM('agent2-key');
var serverCert = loadPEM('agent2-cert');


function runClient(options, cb) {
function runClient(prefix, port, options, cb) {

// Client can connect in three ways:
// - Self-signed cert
// - Certificate, but not signed by CA.
// - Certificate signed by CA.

var args = ['s_client', '-connect', '127.0.0.1:' + common.PORT];
var args = ['s_client', '-connect', '127.0.0.1:' + port];


console.log(' connecting with', options.name);
console.log(prefix + ' connecting with', options.name);

switch (options.name) {
case 'agent1':
@@ -192,7 +192,7 @@ function runClient(options, cb) {
break;

default:
throw new Error('Unknown agent name');
throw new Error(prefix + 'Unknown agent name');
}

// To test use: openssl s_client -connect localhost:8000
@@ -209,15 +209,15 @@ function runClient(options, cb) {
out += d;

if (!goodbye && /_unauthed/g.test(out)) {
console.error(' * unauthed');
console.error(prefix + ' * unauthed');
goodbye = true;
client.stdin.end('goodbye\n');
authed = false;
rejected = false;
}

if (!goodbye && /_authed/g.test(out)) {
console.error(' * authed');
console.error(prefix + ' * authed');
goodbye = true;
client.stdin.end('goodbye\n');
authed = true;
@@ -228,15 +228,17 @@ function runClient(options, cb) {
//client.stdout.pipe(process.stdout);

client.on('exit', function(code) {
//assert.equal(0, code, options.name +
//assert.equal(0, code, prefix + options.name +
// ": s_client exited with error code " + code);
if (options.shouldReject) {
assert.equal(true, rejected, options.name +
assert.equal(true, rejected, prefix + options.name +
' NOT rejected, but should have been');
} else {
assert.equal(false, rejected, options.name +
assert.equal(false, rejected, prefix + options.name +
' rejected, but should NOT have been');
assert.equal(options.shouldAuth, authed);
assert.equal(options.shouldAuth, authed, prefix +
options.name + ' authed is ' + authed +
' but should have been ' + options.shouldAuth);
}

cb();
@@ -246,11 +248,12 @@ function runClient(options, cb) {

// Run the tests
var successfulTests = 0;
function runTest(testIndex) {
function runTest(port, testIndex) {
var prefix = testIndex + ' ';
var tcase = testCases[testIndex];
if (!tcase) return;

console.error("Running '%s'", tcase.title);
console.error(prefix + "Running '%s'", tcase.title);

var cas = tcase.CAs.map(loadPEM);

@@ -281,7 +284,7 @@ function runTest(testIndex) {
if (tcase.renegotiate && !renegotiated) {
renegotiated = true;
setTimeout(function() {
console.error('- connected, renegotiating');
console.error(prefix + '- connected, renegotiating');
c.write('\n_renegotiating\n');
return c.renegotiate({
requestCert: true,
@@ -297,39 +300,55 @@ function runTest(testIndex) {

connections++;
if (c.authorized) {
console.error('- authed connection: ' +
console.error(prefix + '- authed connection: ' +
c.getPeerCertificate().subject.CN);
c.write('\n_authed\n');
} else {
console.error('- unauthed connection: %s', c.authorizationError);
console.error(prefix + '- unauthed connection: %s', c.authorizationError);
c.write('\n_unauthed\n');
}
});

function runNextClient(clientIndex) {
var options = tcase.clients[clientIndex];
if (options) {
runClient(options, function() {
runClient(prefix + clientIndex + ' ', port, options, function() {
runNextClient(clientIndex + 1);
});
} else {
server.close();
successfulTests++;
runTest(testIndex + 1);
runTest(port, nextTest++);
}
}

server.listen(common.PORT, function() {
server.listen(port, function() {
if (tcase.debug) {
console.error('TLS server running on port ' + common.PORT);
console.error(prefix + 'TLS server running on port ' + port);
} else {
runNextClient(0);
if (tcase.renegotiate) {
runNextClient(0);
} else {
var clientsCompleted = 0;
for(var i = 0; i < tcase.clients.length; i++){
runClient(prefix + i + ' ', port, tcase.clients[i], function() {
clientsCompleted++;
if(clientsCompleted == tcase.clients.length){
server.close();
successfulTests++;
runTest(port, nextTest++);
}
});
}
}
}
});
}


runTest(0);
var nextTest = 0;
runTest(common.PORT, nextTest++);
runTest(common.PORT + 1, nextTest++);


process.on('exit', function() {