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'); 24const fixtures = require('../common/fixtures'); 25if (!common.hasCrypto) 26 common.skip('missing crypto'); 27 28// Disable strict server certificate validation by the client 29process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; 30 31common.expectWarning( 32 'Warning', 33 'Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to \'0\' ' + 34 'makes TLS connections and HTTPS requests insecure by disabling ' + 35 'certificate verification.' 36); 37 38const assert = require('assert'); 39const https = require('https'); 40 41function read(fname) { 42 return fixtures.readKey(fname); 43} 44 45// key1 is signed by ca1. 46const key1 = read('agent1-key.pem'); 47const cert1 = read('agent1-cert.pem'); 48 49// key2 has a self signed cert 50const key2 = read('agent2-key.pem'); 51const cert2 = read('agent2-cert.pem'); 52 53// key3 is signed by ca2. 54const key3 = read('agent3-key.pem'); 55const cert3 = read('agent3-cert.pem'); 56 57const ca1 = read('ca1-cert.pem'); 58const ca2 = read('ca2-cert.pem'); 59 60// Different agents to use different CA lists. 61// this api is beyond bad. 62const agent0 = new https.Agent(); 63const agent1 = new https.Agent({ ca: [ca1] }); 64const agent2 = new https.Agent({ ca: [ca2] }); 65const agent3 = new https.Agent({ ca: [ca1, ca2] }); 66 67const options1 = { 68 key: key1, 69 cert: cert1 70}; 71 72const options2 = { 73 key: key2, 74 cert: cert2 75}; 76 77const options3 = { 78 key: key3, 79 cert: cert3 80}; 81 82const server1 = server(options1); 83const server2 = server(options2); 84const server3 = server(options3); 85 86let listenWait = 0; 87 88server1.listen(0, listening()); 89server2.listen(0, listening()); 90server3.listen(0, listening()); 91 92const responseErrors = {}; 93let pending = 0; 94 95 96function server(options) { 97 const s = https.createServer(options, handler); 98 s.requests = []; 99 s.expectCount = 0; 100 return s; 101} 102 103function handler(req, res) { 104 this.requests.push(req.url); 105 res.statusCode = 200; 106 res.setHeader('foo', 'bar'); 107 res.end('hello, world\n'); 108} 109 110function listening() { 111 listenWait++; 112 return () => { 113 listenWait--; 114 if (listenWait === 0) { 115 allListening(); 116 } 117 }; 118} 119 120function makeReq(path, port, error, host, ca) { 121 pending++; 122 const options = { port, path, ca }; 123 124 if (!ca) { 125 options.agent = agent0; 126 } else { 127 if (!Array.isArray(ca)) ca = [ca]; 128 if (ca.includes(ca1) && ca.includes(ca2)) { 129 options.agent = agent3; 130 } else if (ca.includes(ca1)) { 131 options.agent = agent1; 132 } else if (ca.includes(ca2)) { 133 options.agent = agent2; 134 } else { 135 options.agent = agent0; 136 } 137 } 138 139 if (host) { 140 options.headers = { host }; 141 } 142 const req = https.get(options); 143 const server = port === server1.address().port ? server1 : 144 port === server2.address().port ? server2 : 145 port === server3.address().port ? server3 : 146 null; 147 if (!server) throw new Error(`invalid port: ${port}`); 148 server.expectCount++; 149 150 req.on('response', common.mustCall((res) => { 151 assert.strictEqual(res.connection.authorizationError, error); 152 responseErrors[path] = res.connection.authorizationError; 153 pending--; 154 if (pending === 0) { 155 server1.close(); 156 server2.close(); 157 server3.close(); 158 } 159 res.resume(); 160 })); 161} 162 163function allListening() { 164 // Ok, ready to start the tests! 165 const port1 = server1.address().port; 166 const port2 = server2.address().port; 167 const port3 = server3.address().port; 168 169 // server1: host 'agent1', signed by ca1 170 makeReq('/inv1', port1, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); 171 makeReq('/inv1-ca1', port1, 'ERR_TLS_CERT_ALTNAME_INVALID', 172 null, ca1); 173 makeReq('/inv1-ca1ca2', port1, 'ERR_TLS_CERT_ALTNAME_INVALID', 174 null, [ca1, ca2]); 175 makeReq('/val1-ca1', port1, null, 'agent1', ca1); 176 makeReq('/val1-ca1ca2', port1, null, 'agent1', [ca1, ca2]); 177 makeReq('/inv1-ca2', port1, 178 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', 'agent1', ca2); 179 180 // server2: self-signed, host = 'agent2' 181 // doesn't matter that thename matches, all of these will error. 182 makeReq('/inv2', port2, 'DEPTH_ZERO_SELF_SIGNED_CERT'); 183 makeReq('/inv2-ca1', port2, 'DEPTH_ZERO_SELF_SIGNED_CERT', 184 'agent2', ca1); 185 makeReq('/inv2-ca1ca2', port2, 'DEPTH_ZERO_SELF_SIGNED_CERT', 186 'agent2', [ca1, ca2]); 187 188 // server3: host 'agent3', signed by ca2 189 makeReq('/inv3', port3, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); 190 makeReq('/inv3-ca2', port3, 'ERR_TLS_CERT_ALTNAME_INVALID', null, ca2); 191 makeReq('/inv3-ca1ca2', port3, 'ERR_TLS_CERT_ALTNAME_INVALID', 192 null, [ca1, ca2]); 193 makeReq('/val3-ca2', port3, null, 'agent3', ca2); 194 makeReq('/val3-ca1ca2', port3, null, 'agent3', [ca1, ca2]); 195 makeReq('/inv3-ca1', port3, 196 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', 'agent1', ca1); 197 198} 199 200process.on('exit', () => { 201 assert.strictEqual(server1.requests.length, server1.expectCount); 202 assert.strictEqual(server2.requests.length, server2.expectCount); 203 assert.strictEqual(server3.requests.length, server3.expectCount); 204}); 205