From 0a36fb29ae99c1a8f3c20599c0d17c5aad9b2da4 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Mon, 28 Nov 2016 11:55:29 -0800 Subject: [PATCH] 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). Backport-PR-URL: https://github.com/nodejs/node/pull/25501 PR-URL: https://github.com/nodejs/node/pull/24374 Reviewed-By: Daniel Bevenius Reviewed-By: Ben Noordhuis Reviewed-By: Franziska Hinkelmann --- test/parallel/test-tls-multi-key.js | 176 +++++++++++++++++++++++----- 1 file changed, 146 insertions(+), 30 deletions(-) diff --git a/test/parallel/test-tls-multi-key.js b/test/parallel/test-tls-multi-key.js index 8c0722f858c748..8ccc0d32d93757 100644 --- a/test/parallel/test-tls-multi-key.js +++ b/test/parallel/test-tls-multi-key.js @@ -21,6 +21,9 @@ 'use strict'; const common = require('../common'); + +// Test multi-identity ('key')/multi-algorithm scenarios. + if (!common.hasCrypto) common.skip('missing crypto'); @@ -28,45 +31,158 @@ const fixtures = require('../common/fixtures'); const assert = require('assert'); const tls = require('tls'); -const options = { +// Key is ordered as ec, rsa, cert is ordered as rsa, ec. +test({ key: [ - fixtures.readKey('ec-key.pem'), + fixtures.readKey('ec10-key.pem'), + fixtures.readKey('agent1-key.pem'), + ], + cert: [ + fixtures.readKey('agent1-cert.pem'), + fixtures.readKey('ec10-cert.pem'), + ], + eccCN: 'agent10.example.com', + client: { ca: [ + fixtures.readKey('ca5-cert.pem'), + fixtures.readKey('ca1-cert.pem'), + ] }, +}); + +// Key and cert are ordered as ec, rsa. +test({ + key: [ + fixtures.readKey('ec10-key.pem'), fixtures.readKey('agent1-key.pem'), ], cert: [ fixtures.readKey('agent1-cert.pem'), + fixtures.readKey('ec10-cert.pem'), + ], + eccCN: 'agent10.example.com', + client: { ca: [ + fixtures.readKey('ca5-cert.pem'), + fixtures.readKey('ca1-cert.pem'), + ] }, +}); + +// Key, cert, and pfx options can be used simultaneously. +test({ + key: [ + fixtures.readKey('ec-key.pem'), + ], + cert: [ fixtures.readKey('ec-cert.pem'), - ] -}; + ], + pfx: fixtures.readKey('agent1.pfx'), + passphrase: 'sample', + client: { ca: [ + fixtures.readKey('ec-cert.pem'), + fixtures.readKey('ca1-cert.pem'), + ] }, +}); -const ciphers = []; +// Key and cert with mixed algorithms, and cert chains with intermediate CAs +test({ + key: [ + fixtures.readKey('ec10-key.pem'), + fixtures.readKey('agent10-key.pem'), + ], + cert: [ + fixtures.readKey('agent10-cert.pem'), + fixtures.readKey('ec10-cert.pem'), + ], + rsaCN: 'agent10.example.com', + eccCN: 'agent10.example.com', + client: { ca: [ + fixtures.readKey('ca2-cert.pem'), + fixtures.readKey('ca5-cert.pem'), + ] }, +}); + +// Key and cert with mixed algorithms, and cert chains with intermediate CAs, +// using PFX for EC. +test({ + key: [ + fixtures.readKey('agent10-key.pem'), + ], + cert: [ + fixtures.readKey('agent10-cert.pem'), + ], + pfx: fixtures.readKey('ec10.pfx'), + passphrase: 'sample', + rsaCN: 'agent10.example.com', + eccCN: 'agent10.example.com', + client: { ca: [ + fixtures.readKey('ca2-cert.pem'), + fixtures.readKey('ca5-cert.pem'), + ] }, +}); + +// Key and cert with mixed algorithms, and cert chains with intermediate CAs, +// using PFX for RSA. +test({ + key: [ + fixtures.readKey('ec10-key.pem'), + ], + cert: [ + fixtures.readKey('ec10-cert.pem'), + ], + pfx: fixtures.readKey('agent10.pfx'), + passphrase: 'sample', + rsaCN: 'agent10.example.com', + eccCN: 'agent10.example.com', + client: { ca: [ + fixtures.readKey('ca2-cert.pem'), + fixtures.readKey('ca5-cert.pem'), + ] }, +}); + +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'); + 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' - }]); -}); + })); + } +}