Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
test: cover tls multi-identity option mixtures
Prove that cert and key options do not have to be ordered, and that the
pfx option can be used at the same time as the cert/key option
(which was claimed to be impossible by some pre-existing documentation).
  • Loading branch information
sam-github committed Sep 11, 2017
commit c4d269fd44ac2f4e1c65411f0deb36c52e7a5891
178 changes: 147 additions & 31 deletions test/parallel/test-tls-multi-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,168 @@

'use strict';
const common = require('../common');

// Test multi-identity ('key')/multi-algorithm scenarios.

if (!common.hasCrypto)
common.skip('missing crypto');

const assert = require('assert');
const tls = require('tls');
const fs = require('fs');

const options = {
// Key is ordered as ec, rsa, cert is ordered as rsa, ec.
test({
key: [
fs.readFileSync(`${common.fixturesDir}/keys/ec-key.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ec10-key.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/agent1-key.pem`),
],
cert: [
fs.readFileSync(`${common.fixturesDir}/keys/agent1-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ec10-cert.pem`)
],
eccCN: 'agent10.example.com',
client: { ca: [
fs.readFileSync(`${common.fixturesDir}/keys/ca5-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ca1-cert.pem`)
]},
});

// Key and cert are ordered as ec, rsa.
test({
key: [
fs.readFileSync(`${common.fixturesDir}/keys/ec10-key.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/agent1-key.pem`),
],
cert: [
fs.readFileSync(`${common.fixturesDir}/keys/agent1-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ec-cert.pem`)
]
};
fs.readFileSync(`${common.fixturesDir}/keys/ec10-cert.pem`),
],
eccCN: 'agent10.example.com',
client: { ca: [
fs.readFileSync(`${common.fixturesDir}/keys/ca5-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ca1-cert.pem`),
]},
});

// Key, cert, and pfx options can be used simultaneously.
test({
key: [
fs.readFileSync(`${common.fixturesDir}/keys/ec-key.pem`),
],
cert: [
fs.readFileSync(`${common.fixturesDir}/keys/ec-cert.pem`),
],
pfx: fs.readFileSync(`${common.fixturesDir}/keys/agent1.pfx`),
passphrase: 'sample',
client: { ca: [
fs.readFileSync(`${common.fixturesDir}/keys/ec-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ca1-cert.pem`),
]},
});

// Key and cert with mixed algorithms, and cert chains with intermediate CAs
test({
key: [
fs.readFileSync(`${common.fixturesDir}/keys/ec10-key.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/agent10-key.pem`),
],
cert: [
fs.readFileSync(`${common.fixturesDir}/keys/agent10-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ec10-cert.pem`),
],
rsaCN: 'agent10.example.com',
eccCN: 'agent10.example.com',
client: { ca: [
fs.readFileSync(`${common.fixturesDir}/keys/ca2-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ca5-cert.pem`),
]},
});

// Key and cert with mixed algorithms, and cert chains with intermediate CAs,
// using PFX for EC.
test({
key: [
fs.readFileSync(`${common.fixturesDir}/keys/agent10-key.pem`),
],
cert: [
fs.readFileSync(`${common.fixturesDir}/keys/agent10-cert.pem`),
],
pfx: fs.readFileSync(`${common.fixturesDir}/keys/ec10.pfx`),
passphrase: 'sample',
rsaCN: 'agent10.example.com',
eccCN: 'agent10.example.com',
client: { ca: [
fs.readFileSync(`${common.fixturesDir}/keys/ca2-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ca5-cert.pem`),
]},
});

// Key and cert with mixed algorithms, and cert chains with intermediate CAs,
// using PFX for RSA.
test({
key: [
fs.readFileSync(`${common.fixturesDir}/keys/ec10-key.pem`),
],
cert: [
fs.readFileSync(`${common.fixturesDir}/keys/ec10-cert.pem`),
],
pfx: fs.readFileSync(`${common.fixturesDir}/keys/agent10.pfx`),
passphrase: 'sample',
rsaCN: 'agent10.example.com',
eccCN: 'agent10.example.com',
client: { ca: [
fs.readFileSync(`${common.fixturesDir}/keys/ca2-cert.pem`),
fs.readFileSync(`${common.fixturesDir}/keys/ca5-cert.pem`),
]},
});

const ciphers = [];
function test(options) {
const rsaCN = options.rsaCN || 'agent1';
const eccCN = options.eccCN || 'agent2';
const clientTrustRoots = options.client.ca;
delete options.rsaCN;
delete options.eccCN;
delete options.client;
const server = tls.createServer(options, function(conn) {
conn.end('ok');
}).listen(0, common.mustCall(connectWithEcdsa));

const server = tls.createServer(options, function(conn) {
conn.end('ok');
}).listen(0, function() {
const ecdsa = tls.connect(this.address().port, {
ciphers: 'ECDHE-ECDSA-AES256-GCM-SHA384',
rejectUnauthorized: false
}, function() {
ciphers.push(ecdsa.getCipher());
function connectWithEcdsa() {
const ecdsa = tls.connect(this.address().port, {
ciphers: 'ECDHE-ECDSA-AES256-GCM-SHA384',
rejectUnauthorized: true,
ca: clientTrustRoots,
checkServerIdentity: (_, c) => assert.strictEqual(c.subject.CN, eccCN),
}, common.mustCall(function() {
assert.deepStrictEqual(ecdsa.getCipher(), {
name: 'ECDHE-ECDSA-AES256-GCM-SHA384',
version: 'TLSv1/SSLv3'
});
assert.strictEqual(ecdsa.getPeerCertificate().subject.CN, eccCN);
// XXX(sam) certs don't currently include EC key info, so depend on
// absence of RSA key info to indicate key is EC.
assert(!ecdsa.getPeerCertificate().exponent, 'not cert for an RSA key');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not worry about to check peerCert of ECC attribute. It is enough to confirm that ECDSA cipher has been established if ECC cert is surely working. But this check does not have harm.

ecdsa.end();
connectWithRsa();
}));
}

function connectWithRsa() {
const rsa = tls.connect(server.address().port, {
ciphers: 'ECDHE-RSA-AES256-GCM-SHA384',
rejectUnauthorized: false
}, function() {
ciphers.push(rsa.getCipher());
ecdsa.end();
rejectUnauthorized: true,
ca: clientTrustRoots,
checkServerIdentity: (_, c) => assert.strictEqual(c.subject.CN, rsaCN),
}, common.mustCall(function() {
assert.deepStrictEqual(rsa.getCipher(), {
name: 'ECDHE-RSA-AES256-GCM-SHA384',
version: 'TLSv1/SSLv3'
});
assert.strictEqual(rsa.getPeerCertificate().subject.CN, rsaCN);
assert(rsa.getPeerCertificate().exponent, 'cert for an RSA key');
rsa.end();
server.close();
});
});
});

process.on('exit', function() {
assert.deepStrictEqual(ciphers, [{
name: 'ECDHE-ECDSA-AES256-GCM-SHA384',
version: 'TLSv1/SSLv3'
}, {
name: 'ECDHE-RSA-AES256-GCM-SHA384',
version: 'TLSv1/SSLv3'
}]);
});
}));
}
}