mirror of https://github.com/lukechilds/node.git
Browse Source
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. Backport-PR-URL: https://github.com/nodejs/node/pull/12468 PR-URL: https://github.com/nodejs/node/pull/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>v6.x
Sam Roberts
8 years ago
committed by
Myles Borins
4 changed files with 181 additions and 118 deletions
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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(); |
|||
}); |
|||
}); |
|||
|
@ -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(); |
|||
}); |
|||
|
@ -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(); |
|||
}); |
|||
|
Loading…
Reference in new issue