• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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';
23
24const common = require('../common');
25
26if (!common.opensslCli)
27  common.skip('node compiled without OpenSSL CLI.');
28
29if (!common.hasCrypto)
30  common.skip('missing crypto');
31
32if (common.isWindows)
33  common.skip('test does not work on Windows'); // ...but it should!
34
35const net = require('net');
36const assert = require('assert');
37const fixtures = require('../common/fixtures');
38const tls = require('tls');
39const spawn = require('child_process').spawn;
40
41const useIPv4 = !common.hasIPv6;
42
43test1();
44
45// simple/test-tls-securepair-client
46function test1() {
47  test('keys/rsa_private.pem', 'keys/rsa_cert.crt', null, test2);
48}
49
50// simple/test-tls-ext-key-usage
51function test2() {
52  function check(pair) {
53    // "TLS Web Client Authentication"
54    assert.strictEqual(pair.cleartext.getPeerCertificate().ext_key_usage.length,
55                       1);
56    assert.strictEqual(pair.cleartext.getPeerCertificate().ext_key_usage[0],
57                       '1.3.6.1.5.5.7.3.2');
58  }
59  test('keys/agent4-key.pem', 'keys/agent4-cert.pem', check);
60}
61
62function test(keyPath, certPath, check, next) {
63  const key = fixtures.readSync(keyPath).toString();
64  const cert = fixtures.readSync(certPath).toString();
65
66  const server = spawn(common.opensslCli, ['s_server',
67                                           '-accept', 0,
68                                           '-cert', fixtures.path(certPath),
69                                           '-key', fixtures.path(keyPath),
70                                           ...(useIPv4 ? ['-4'] : []),
71  ]);
72  server.stdout.pipe(process.stdout);
73  server.stderr.pipe(process.stdout);
74
75
76  let state = 'WAIT-ACCEPT';
77
78  let serverStdoutBuffer = '';
79  server.stdout.setEncoding('utf8');
80  server.stdout.on('data', function(s) {
81    serverStdoutBuffer += s;
82    console.log(state);
83    switch (state) {
84      case 'WAIT-ACCEPT': {
85        const matches = serverStdoutBuffer.match(/ACCEPT .*?:(\d+)/);
86        if (matches) {
87          const port = matches[1];
88          state = 'WAIT-HELLO';
89          startClient(port);
90        }
91        break;
92      }
93      case 'WAIT-HELLO':
94        if (/hello/.test(serverStdoutBuffer)) {
95
96          // End the current SSL connection and exit.
97          // See s_server(1ssl).
98          server.stdin.write('Q');
99
100          state = 'WAIT-SERVER-CLOSE';
101        }
102        break;
103
104      default:
105        break;
106    }
107  });
108
109
110  const timeout = setTimeout(function() {
111    server.kill();
112    process.exit(1);
113  }, 5000);
114
115  let gotWriteCallback = false;
116  let serverExitCode = -1;
117
118  server.on('exit', function(code) {
119    serverExitCode = code;
120    clearTimeout(timeout);
121    if (next) next();
122  });
123
124
125  function startClient(port) {
126    const s = new net.Stream();
127
128    const sslcontext = tls.createSecureContext({ key, cert });
129    sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
130
131    const pair = tls.createSecurePair(sslcontext, false);
132
133    assert.ok(pair.encrypted.writable);
134    assert.ok(pair.cleartext.writable);
135
136    pair.encrypted.pipe(s);
137    s.pipe(pair.encrypted);
138
139    s.connect(port);
140
141    s.on('connect', function() {
142      console.log('client connected');
143      setTimeout(function() {
144        pair.cleartext.write('hello\r\n', function() {
145          gotWriteCallback = true;
146        });
147      }, 500);
148    });
149
150    pair.on('secure', function() {
151      console.log('client: connected+secure!');
152      console.log('client pair.cleartext.getPeerCertificate(): %j',
153                  pair.cleartext.getPeerCertificate());
154      console.log('client pair.cleartext.getCipher(): %j',
155                  pair.cleartext.getCipher());
156      if (check) check(pair);
157    });
158
159    pair.cleartext.on('data', function(d) {
160      console.log('cleartext: %s', d.toString());
161    });
162
163    s.on('close', function() {
164      console.log('client close');
165    });
166
167    pair.encrypted.on('error', function(err) {
168      console.log(`encrypted error: ${err}`);
169    });
170
171    s.on('error', function(err) {
172      console.log(`socket error: ${err}`);
173    });
174
175    pair.on('error', function(err) {
176      console.log(`secure error: ${err}`);
177    });
178  }
179
180
181  process.on('exit', function() {
182    assert.strictEqual(serverExitCode, 0);
183    assert.strictEqual(state, 'WAIT-SERVER-CLOSE');
184    assert.ok(gotWriteCallback);
185  });
186}
187