1 var common = require('../common');
3 if (!common.opensslCli) {
4 console.error('Skipping because node compiled without OpenSSL CLI.');
8 // This is a rather complex test which sets up various TLS servers with node
9 // and connects to them using the 'openssl s_client' command line utility
10 // with various keys. Depending on the certificate authority and other
11 // parameters given to the server, the various clients are
13 // - accepted and "unauthorized", or
14 // - accepted and "authorized".
17 [{ title: 'Do not request certs. Everyone is unauthorized.',
19 rejectUnauthorized: false,
23 [{ name: 'agent1', shouldReject: false, shouldAuth: false },
24 { name: 'agent2', shouldReject: false, shouldAuth: false },
25 { name: 'agent3', shouldReject: false, shouldAuth: false },
26 { name: 'nocert', shouldReject: false, shouldAuth: false }
30 { title: 'Allow both authed and unauthed connections with CA1',
32 rejectUnauthorized: false,
36 [{ name: 'agent1', shouldReject: false, shouldAuth: true },
37 { name: 'agent2', shouldReject: false, shouldAuth: false },
38 { name: 'agent3', shouldReject: false, shouldAuth: false },
39 { name: 'nocert', shouldReject: false, shouldAuth: false }
43 { title: 'Do not request certs at connection. Do that later',
45 rejectUnauthorized: false,
49 [{ name: 'agent1', shouldReject: false, shouldAuth: true },
50 { name: 'agent2', shouldReject: false, shouldAuth: false },
51 { name: 'agent3', shouldReject: false, shouldAuth: false },
52 { name: 'nocert', shouldReject: false, shouldAuth: false }
56 { title: 'Allow only authed connections with CA1',
58 rejectUnauthorized: true,
62 [{ name: 'agent1', shouldReject: false, shouldAuth: true },
63 { name: 'agent2', shouldReject: true },
64 { name: 'agent3', shouldReject: true },
65 { name: 'nocert', shouldReject: true }
69 { title: 'Allow only authed connections with CA1 and CA2',
71 rejectUnauthorized: true,
73 CAs: ['ca1-cert', 'ca2-cert'],
75 [{ name: 'agent1', shouldReject: false, shouldAuth: true },
76 { name: 'agent2', shouldReject: true },
77 { name: 'agent3', shouldReject: false, shouldAuth: true },
78 { name: 'nocert', shouldReject: true }
83 { title: 'Allow only certs signed by CA2 but not in the CRL',
85 rejectUnauthorized: true,
91 { name: 'agent1', shouldReject: true, shouldAuth: false },
92 { name: 'agent2', shouldReject: true, shouldAuth: false },
93 { name: 'agent3', shouldReject: false, shouldAuth: true },
94 // Agent4 has a cert in the CRL.
95 { name: 'agent4', shouldReject: true, shouldAuth: false },
96 { name: 'nocert', shouldReject: true }
102 var constants = require('constants');
103 var assert = require('assert');
104 var fs = require('fs');
105 var tls = require('tls');
106 var spawn = require('child_process').spawn;
109 function filenamePEM(n) {
110 return require('path').join(common.fixturesDir, 'keys', n + '.pem');
114 function loadPEM(n) {
115 return fs.readFileSync(filenamePEM(n));
119 var serverKey = loadPEM('agent2-key');
120 var serverCert = loadPEM('agent2-cert');
123 function runClient(options, cb) {
125 // Client can connect in three ways:
126 // - Self-signed cert
127 // - Certificate, but not signed by CA.
128 // - Certificate signed by CA.
130 var args = ['s_client', '-connect', '127.0.0.1:' + common.PORT];
133 console.log(' connecting with', options.name);
135 switch (options.name) {
139 args.push(filenamePEM('agent1-key'));
141 args.push(filenamePEM('agent1-cert'));
146 // This is also the key-cert pair that the server will use.
148 args.push(filenamePEM('agent2-key'));
150 args.push(filenamePEM('agent2-cert'));
156 args.push(filenamePEM('agent3-key'));
158 args.push(filenamePEM('agent3-cert'));
162 // Signed by CA2 (rejected by ca2-crl)
164 args.push(filenamePEM('agent4-key'));
166 args.push(filenamePEM('agent4-cert'));
170 // Do not send certificate
174 throw new Error('Unknown agent name');
177 // To test use: openssl s_client -connect localhost:8000
178 var client = spawn(common.opensslCli, args);
186 client.stdout.setEncoding('utf8');
187 client.stdout.on('data', function(d) {
190 if (!goodbye && /_unauthed/g.test(out)) {
191 console.error(' * unauthed');
193 client.stdin.end('goodbye\n');
198 if (!goodbye && /_authed/g.test(out)) {
199 console.error(' * authed');
201 client.stdin.end('goodbye\n');
207 //client.stdout.pipe(process.stdout);
209 client.on('exit', function(code) {
210 //assert.equal(0, code, options.name +
211 // ": s_client exited with error code " + code);
212 if (options.shouldReject) {
213 assert.equal(true, rejected, options.name +
214 ' NOT rejected, but should have been');
216 assert.equal(false, rejected, options.name +
217 ' rejected, but should NOT have been');
218 assert.equal(options.shouldAuth, authed);
227 var successfulTests = 0;
228 function runTest(testIndex) {
229 var tcase = testCases[testIndex];
232 console.error("Running '%s'", tcase.title);
234 var cas = tcase.CAs.map(loadPEM);
236 var crl = tcase.crl ? loadPEM(tcase.crl) : null;
238 var serverOptions = {
243 requestCert: tcase.requestCert,
244 rejectUnauthorized: tcase.rejectUnauthorized
250 * If renegotiating - session might be resumed and openssl won't request
251 * client's certificate (probably because of bug in the openssl)
253 if (tcase.renegotiate) {
254 serverOptions.secureOptions =
255 constants.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
258 var renegotiated = false;
259 var server = tls.Server(serverOptions, function handleConnection(c) {
260 if (tcase.renegotiate && !renegotiated) {
262 setTimeout(function() {
263 console.error('- connected, renegotiating');
264 c.write('\n_renegotiating\n');
265 return c.renegotiate({
267 rejectUnauthorized: false
270 c.write('\n_renegotiated\n');
279 console.error('- authed connection: ' +
280 c.getPeerCertificate().subject.CN);
281 c.write('\n_authed\n');
283 console.error('- unauthed connection: %s', c.authorizationError);
284 c.write('\n_unauthed\n');
288 function runNextClient(clientIndex) {
289 var options = tcase.clients[clientIndex];
291 runClient(options, function() {
292 runNextClient(clientIndex + 1);
297 runTest(testIndex + 1);
301 server.listen(common.PORT, function() {
303 console.error('TLS server running on port ' + common.PORT);
314 process.on('exit', function() {
315 assert.equal(successfulTests, testCases.length);