1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23const common = require('../common'); 24 25// Test multi-identity ('key')/multi-algorithm scenarios. 26 27if (!common.hasCrypto) 28 common.skip('missing crypto'); 29 30const fixtures = require('../common/fixtures'); 31const assert = require('assert'); 32const tls = require('tls'); 33 34// Key is ordered as ec, rsa, cert is ordered as rsa, ec. 35test({ 36 key: [ 37 fixtures.readKey('ec10-key.pem'), 38 fixtures.readKey('agent1-key.pem'), 39 ], 40 cert: [ 41 fixtures.readKey('agent1-cert.pem'), 42 fixtures.readKey('ec10-cert.pem'), 43 ], 44 eccCN: 'agent10.example.com', 45 client: { ca: [ 46 fixtures.readKey('ca5-cert.pem'), 47 fixtures.readKey('ca1-cert.pem'), 48 ] }, 49}); 50 51// Key and cert are ordered as ec, rsa. 52test({ 53 key: [ 54 fixtures.readKey('ec10-key.pem'), 55 fixtures.readKey('agent1-key.pem'), 56 ], 57 cert: [ 58 fixtures.readKey('agent1-cert.pem'), 59 fixtures.readKey('ec10-cert.pem'), 60 ], 61 eccCN: 'agent10.example.com', 62 client: { ca: [ 63 fixtures.readKey('ca5-cert.pem'), 64 fixtures.readKey('ca1-cert.pem'), 65 ] }, 66}); 67 68// Key, cert, and pfx options can be used simultaneously. 69test({ 70 key: [ 71 fixtures.readKey('ec-key.pem'), 72 ], 73 cert: [ 74 fixtures.readKey('ec-cert.pem'), 75 ], 76 pfx: fixtures.readKey('agent1.pfx'), 77 passphrase: 'sample', 78 client: { ca: [ 79 fixtures.readKey('ec-cert.pem'), 80 fixtures.readKey('ca1-cert.pem'), 81 ] }, 82}); 83 84// Key and cert with mixed algorithms, and cert chains with intermediate CAs 85test({ 86 key: [ 87 fixtures.readKey('ec10-key.pem'), 88 fixtures.readKey('agent10-key.pem'), 89 ], 90 cert: [ 91 fixtures.readKey('agent10-cert.pem'), 92 fixtures.readKey('ec10-cert.pem'), 93 ], 94 rsaCN: 'agent10.example.com', 95 eccCN: 'agent10.example.com', 96 client: { ca: [ 97 fixtures.readKey('ca2-cert.pem'), 98 fixtures.readKey('ca5-cert.pem'), 99 ] }, 100}); 101 102// Key and cert with mixed algorithms, and cert chains with intermediate CAs, 103// using PFX for EC. 104test({ 105 key: [ 106 fixtures.readKey('agent10-key.pem'), 107 ], 108 cert: [ 109 fixtures.readKey('agent10-cert.pem'), 110 ], 111 pfx: fixtures.readKey('ec10.pfx'), 112 passphrase: 'sample', 113 rsaCN: 'agent10.example.com', 114 eccCN: 'agent10.example.com', 115 client: { ca: [ 116 fixtures.readKey('ca2-cert.pem'), 117 fixtures.readKey('ca5-cert.pem'), 118 ] }, 119}); 120 121// Key and cert with mixed algorithms, and cert chains with intermediate CAs, 122// using PFX for RSA. 123test({ 124 key: [ 125 fixtures.readKey('ec10-key.pem'), 126 ], 127 cert: [ 128 fixtures.readKey('ec10-cert.pem'), 129 ], 130 pfx: fixtures.readKey('agent10.pfx'), 131 passphrase: 'sample', 132 rsaCN: 'agent10.example.com', 133 eccCN: 'agent10.example.com', 134 client: { ca: [ 135 fixtures.readKey('ca2-cert.pem'), 136 fixtures.readKey('ca5-cert.pem'), 137 ] }, 138}); 139 140function test(options) { 141 const rsaCN = options.rsaCN || 'agent1'; 142 const eccCN = options.eccCN || 'agent2'; 143 const clientTrustRoots = options.client.ca; 144 delete options.rsaCN; 145 delete options.eccCN; 146 delete options.client; 147 const server = tls.createServer(options, function(conn) { 148 conn.end('ok'); 149 }).listen(0, common.mustCall(connectWithEcdsa)); 150 151 function connectWithEcdsa() { 152 const ecdsa = tls.connect(this.address().port, { 153 ciphers: 'ECDHE-ECDSA-AES256-GCM-SHA384', 154 rejectUnauthorized: true, 155 ca: clientTrustRoots, 156 checkServerIdentity: (_, c) => assert.strictEqual(c.subject.CN, eccCN), 157 }, common.mustCall(function() { 158 assert.deepStrictEqual(ecdsa.getCipher(), { 159 name: 'ECDHE-ECDSA-AES256-GCM-SHA384', 160 standardName: 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', 161 version: 'TLSv1.2' 162 }); 163 assert.strictEqual(ecdsa.getPeerCertificate().subject.CN, eccCN); 164 assert.strictEqual(ecdsa.getPeerCertificate().asn1Curve, 'prime256v1'); 165 ecdsa.end(); 166 connectWithRsa(); 167 })); 168 } 169 170 function connectWithRsa() { 171 const rsa = tls.connect(server.address().port, { 172 ciphers: 'ECDHE-RSA-AES256-GCM-SHA384', 173 rejectUnauthorized: true, 174 ca: clientTrustRoots, 175 checkServerIdentity: (_, c) => assert.strictEqual(c.subject.CN, rsaCN), 176 }, common.mustCall(function() { 177 assert.deepStrictEqual(rsa.getCipher(), { 178 name: 'ECDHE-RSA-AES256-GCM-SHA384', 179 standardName: 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', 180 version: 'TLSv1.2' 181 }); 182 assert.strictEqual(rsa.getPeerCertificate().subject.CN, rsaCN); 183 assert(rsa.getPeerCertificate().exponent, 'cert for an RSA key'); 184 rsa.end(); 185 server.close(); 186 })); 187 } 188} 189