Skip to content

Commit

Permalink
test: move common tls connect setup into fixtures
Browse files Browse the repository at this point in the history
TLS connection setup boilerplate is common to many TLS tests, factor it
into a test fixture so tests are clearer to read and faster to write.

PR-URL: nodejs#10389
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
  • Loading branch information
sam-github committed Apr 17, 2017
1 parent fd97d25 commit 8db0443
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 118 deletions.
101 changes: 101 additions & 0 deletions test/fixtures/tls-connect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// One shot call to connect a TLS client and server based on options to
// tls.createServer() and tls.connect(), so assertions can be made on both ends
// of the connection.
'use strict';

const common = require('../common');
const fs = require('fs');
const join = require('path').join;
const tls = require('tls');
const util = require('util');

module.exports = exports = checkCrypto;

function checkCrypto() {
if (!common.hasCrypto) {
common.skip('missing crypto');
process.exit(0);
}
return exports;
}

exports.assert = require('assert');
exports.debug = util.debuglog('test');
exports.tls = tls;

// Pre-load keys from common fixtures for ease of use by tests.
const keys = exports.keys = {
agent1: load('agent1', 'ca1'),
agent2: load('agent2', 'agent2'),
agent3: load('agent3', 'ca2'),
agent4: load('agent4', 'ca2'),
agent5: load('agent5', 'ca2'),
agent6: load('agent6', 'ca1'),
agent7: load('agent7', 'fake-cnnic-root'),
ec: load('ec', 'ec'),
};

function load(cert, issuer) {
issuer = issuer || cert; // Assume self-signed if no issuer
const id = {
key: read(cert + '-key.pem'),
cert: read(cert + '-cert.pem'),
ca: read(issuer + '-cert.pem'),
};
return id;
}

function read(file) {
return fs.readFileSync(join(common.fixturesDir, 'keys', file), 'binary');
}

exports.connect = function connect(options, callback) {
callback = common.mustCall(callback);

const server = {};
const client = {};
const pair = {
server: server,
client: client,
};

tls.createServer(options.server, function(conn) {
server.conn = conn;
conn.pipe(conn);
maybeCallback()
}).listen(0, function() {
server.server = this;

const optClient = util._extend({
port: this.address().port,
}, options.client);

tls.connect(optClient)
.on('secureConnect', function() {
client.conn = this;
maybeCallback();
})
.on('error', function(err) {
client.err = err;
client.conn = this;
maybeCallback();
});
});

function maybeCallback() {
if (!callback)
return;
if (server.conn && (client.conn || client.err)) {
const err = pair.client.err || pair.server.err;
callback(err, pair, cleanup);
callback = null;

function cleanup() {
if (server.server)
server.server.close();
if (client.conn)
client.conn.end();
}
}
}
}
78 changes: 33 additions & 45 deletions test/parallel/test-tls-addca.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,50 @@
'use strict';
const common = require('../common');
const fs = require('fs');

if (!common.hasCrypto) {
common.skip('missing crypto');
return;
}
const tls = require('tls');

function filenamePEM(n) {
return require('path').join(common.fixturesDir, 'keys', n + '.pem');
}
// Adding a CA certificate to contextWithCert should not also add it to
// contextWithoutCert. This is tested by trying to connect to a server that
// depends on that CA using contextWithoutCert.

function loadPEM(n) {
return fs.readFileSync(filenamePEM(n));
}
const join = require('path').join;
const {
assert, connect, keys, tls
} = require(join(common.fixturesDir, 'tls-connect'))();

const caCert = loadPEM('ca1-cert');
const contextWithoutCert = tls.createSecureContext({});
const contextWithCert = tls.createSecureContext({});
// Adding a CA certificate to contextWithCert should not also add it to
// contextWithoutCert. This is tested by trying to connect to a server that
// depends on that CA using contextWithoutCert.
contextWithCert.context.addCACert(caCert);
contextWithCert.context.addCACert(keys.agent1.ca);

const serverOptions = {
key: loadPEM('agent1-key'),
cert: loadPEM('agent1-cert'),
key: keys.agent1.key,
cert: keys.agent1.cert,
};
const server = tls.createServer(serverOptions, function() {});

const clientOptions = {
port: undefined,
ca: [caCert],
ca: [keys.agent1.ca],
servername: 'agent1',
rejectUnauthorized: true,
};

function startTest() {
// This client should fail to connect because it doesn't trust the CA
// This client should fail to connect because it doesn't trust the CA
// certificate.
clientOptions.secureContext = contextWithoutCert;

connect({
client: clientOptions,
server: serverOptions,
}, function(err, pair, cleanup) {
assert(err);
assert.strictEqual(err.message, 'unable to verify the first certificate');
cleanup();

// This time it should connect because contextWithCert includes the needed CA
// certificate.
clientOptions.secureContext = contextWithoutCert;
clientOptions.port = server.address().port;
const client = tls.connect(clientOptions, common.fail);
client.on('error', common.mustCall(() => {
client.destroy();

// This time it should connect because contextWithCert includes the needed
// CA certificate.
clientOptions.secureContext = contextWithCert;
const client2 = tls.connect(clientOptions, common.mustCall(() => {
client2.destroy();
server.close();
}));
client2.on('error', (e) => {
console.log(e);
});
}));
}

server.listen(0, startTest);
clientOptions.secureContext = contextWithCert;
connect({
client: clientOptions,
server: serverOptions,
}, function(err, pair, cleanup) {
assert.ifError(err);
cleanup();
});
});
48 changes: 18 additions & 30 deletions test/parallel/test-tls-connect-secure-context.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,25 @@
'use strict';
const common = require('../common');

if (!common.hasCrypto) {
common.skip('missing crypto');
return;
}
const tls = require('tls');
// Verify connection with explicitly created client SecureContext.

const fs = require('fs');
const path = require('path');
const join = require('path').join;
const {
assert, connect, keys, tls
} = require(join(common.fixturesDir, 'tls-connect'))();

const keysDir = path.join(common.fixturesDir, 'keys');

const ca = fs.readFileSync(path.join(keysDir, 'ca1-cert.pem'));
const cert = fs.readFileSync(path.join(keysDir, 'agent1-cert.pem'));
const key = fs.readFileSync(path.join(keysDir, 'agent1-key.pem'));

const server = tls.createServer({
cert: cert,
key: key
}, function(c) {
c.end();
}).listen(0, function() {
const secureContext = tls.createSecureContext({
ca: ca
});

const socket = tls.connect({
secureContext: secureContext,
connect({
client: {
servername: 'agent1',
port: this.address().port
}, common.mustCall(function() {
server.close();
socket.end();
}));
secureContext: tls.createSecureContext({
ca: keys.agent1.ca,
}),
},
server: {
cert: keys.agent1.cert,
key: keys.agent1.key,
},
}, function(err, pair, cleanup) {
assert.ifError(err);
return cleanup();
});
72 changes: 29 additions & 43 deletions test/parallel/test-tls-peer-certificate.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,39 @@
'use strict';
const common = require('../common');
const assert = require('assert');

if (!common.hasCrypto) {
common.skip('missing crypto');
return;
}
const tls = require('tls');
// Verify that detailed getPeerCertificate() return value has all certs.

const fs = require('fs');
const util = require('util');
const join = require('path').join;
const {
assert, connect, debug, keys
} = require(join(common.fixturesDir, 'tls-connect'))();

const options = {
key: fs.readFileSync(join(common.fixturesDir, 'keys', 'agent1-key.pem')),
cert: fs.readFileSync(join(common.fixturesDir, 'keys', 'agent1-cert.pem')),
ca: [ fs.readFileSync(join(common.fixturesDir, 'keys', 'ca1-cert.pem')) ]
};
connect({
client: {rejectUnauthorized: false},
server: keys.agent1,
}, function(err, pair, cleanup) {
assert.ifError(err);
const socket = pair.client.conn;
let peerCert = socket.getPeerCertificate();
assert.ok(!peerCert.issuerCertificate);

const server = tls.createServer(options, function(cleartext) {
cleartext.end('World');
});
server.listen(0, common.mustCall(function() {
const socket = tls.connect({
port: this.address().port,
rejectUnauthorized: false
}, common.mustCall(function() {
let peerCert = socket.getPeerCertificate();
assert.ok(!peerCert.issuerCertificate);
peerCert = socket.getPeerCertificate(true);
debug('peerCert:\n', peerCert);

// Verify that detailed return value has all certs
peerCert = socket.getPeerCertificate(true);
assert.ok(peerCert.issuerCertificate);
assert.ok(peerCert.issuerCertificate);
assert.strictEqual(peerCert.subject.emailAddress, 'ry@tinyclouds.org');
assert.strictEqual(peerCert.serialNumber, '9A84ABCFB8A72AC0');
assert.strictEqual(peerCert.exponent, '0x10001');
assert.strictEqual(
peerCert.fingerprint,
'8D:06:3A:B3:E5:8B:85:29:72:4F:7D:1B:54:CD:95:19:3C:EF:6F:AA'
);
assert.deepStrictEqual(peerCert.infoAccess['OCSP - URI'],
[ 'http://ocsp.nodejs.org/' ]);

console.error(util.inspect(peerCert));
assert.strictEqual(peerCert.subject.emailAddress, 'ry@tinyclouds.org');
assert.strictEqual(peerCert.serialNumber, '9A84ABCFB8A72AC0');
assert.strictEqual(peerCert.exponent, '0x10001');
assert.strictEqual(
peerCert.fingerprint,
'8D:06:3A:B3:E5:8B:85:29:72:4F:7D:1B:54:CD:95:19:3C:EF:6F:AA'
);
assert.deepStrictEqual(peerCert.infoAccess['OCSP - URI'],
[ 'http://ocsp.nodejs.org/' ]);
const issuer = peerCert.issuerCertificate;
assert.strictEqual(issuer.issuerCertificate, issuer);
assert.strictEqual(issuer.serialNumber, '8DF21C01468AF393');

const issuer = peerCert.issuerCertificate;
assert.strictEqual(issuer.issuerCertificate, issuer);
assert.strictEqual(issuer.serialNumber, '8DF21C01468AF393');
server.close();
}));
socket.end('Hello');
}));
return cleanup();
});

0 comments on commit 8db0443

Please sign in to comment.