Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDenys Otrishko <shishugi@gmail.com>2018-10-29 11:38:43 +0300
committerRuben Bridgewater <ruben@bridgewater.de>2019-12-25 14:24:42 +0300
commitf8d7e2216e5821719b5a341c41251d5a860cf5f7 (patch)
tree8f3a1db4b065a844483ee1a8e388702463683570 /test
parent3d47c8592d179991d3bfa4902f12c4fce07ac2d3 (diff)
tls: add PSK support
Add the `pskCallback` client/server option, which resolves an identity or identity hint to a pre-shared key. Add the `pskIdentityHint` server option to set the identity hint for the ServerKeyExchange message. Co-authored-by: Chris Osborn <chris.osborn@sitelier.com> Co-authored-by: stephank <gh@stephank.nl> Co-authored-by: Taylor Zane Glaeser <tzglaeser@gmail.com> PR-URL: https://github.com/nodejs/node/pull/23188 Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'test')
-rw-r--r--test/parallel/test-tls-psk-circuit.js72
-rw-r--r--test/parallel/test-tls-psk-errors.js32
-rw-r--r--test/parallel/test-tls-psk-server.js77
-rw-r--r--test/sequential/test-tls-psk-client.js96
4 files changed, 277 insertions, 0 deletions
diff --git a/test/parallel/test-tls-psk-circuit.js b/test/parallel/test-tls-psk-circuit.js
new file mode 100644
index 00000000000..4bcdf368606
--- /dev/null
+++ b/test/parallel/test-tls-psk-circuit.js
@@ -0,0 +1,72 @@
+'use strict';
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const tls = require('tls');
+
+const CIPHERS = 'PSK+HIGH:TLS_AES_128_GCM_SHA256';
+const USERS = {
+ UserA: Buffer.allocUnsafe(128),
+ UserB: Buffer.from('82072606b502b0f4025e90eb75fe137d', 'hex'),
+};
+const TEST_DATA = 'x';
+
+const serverOptions = {
+ ciphers: CIPHERS,
+ pskCallback(socket, id) {
+ assert.ok(socket instanceof tls.TLSSocket);
+ assert.ok(typeof id === 'string');
+ return USERS[id];
+ },
+};
+
+function test(secret, opts, error) {
+ const cb = !error ?
+ common.mustCall((c) => { c.pipe(c); }) :
+ common.mustNotCall();
+ const server = tls.createServer(serverOptions, cb);
+ server.listen(0, common.mustCall(() => {
+ const options = {
+ port: server.address().port,
+ ciphers: CIPHERS,
+ checkServerIdentity: () => {},
+ pskCallback: common.mustCall(() => secret),
+ ...opts,
+ };
+
+ if (!error) {
+ const client = tls.connect(options, common.mustCall(() => {
+ client.end(TEST_DATA);
+
+ client.on('data', common.mustCall((data) => {
+ assert.strictEqual(data.toString(), TEST_DATA);
+ }));
+ client.on('close', common.mustCall(() => server.close()));
+ }));
+ } else {
+ const client = tls.connect(options, common.mustNotCall());
+ client.on('error', common.mustCall((err) => {
+ assert.strictEqual(err.message, error);
+ server.close();
+ }));
+ }
+ }));
+}
+
+const DISCONNECT_MESSAGE =
+ 'Client network socket disconnected before ' +
+ 'secure TLS connection was established';
+
+test({ psk: USERS.UserA, identity: 'UserA' });
+test({ psk: USERS.UserA, identity: 'UserA' }, { maxVersion: 'TLSv1.2' });
+test({ psk: USERS.UserA, identity: 'UserA' }, { minVersion: 'TLSv1.3' });
+test({ psk: USERS.UserB, identity: 'UserB' });
+test({ psk: USERS.UserB, identity: 'UserB' }, { minVersion: 'TLSv1.3' });
+// Unrecognized user should fail handshake
+test({ psk: USERS.UserB, identity: 'UserC' }, {}, DISCONNECT_MESSAGE);
+// Recognized user but incorrect secret should fail handshake
+test({ psk: USERS.UserA, identity: 'UserB' }, {}, DISCONNECT_MESSAGE);
+test({ psk: USERS.UserB, identity: 'UserB' });
diff --git a/test/parallel/test-tls-psk-errors.js b/test/parallel/test-tls-psk-errors.js
new file mode 100644
index 00000000000..4864a66f555
--- /dev/null
+++ b/test/parallel/test-tls-psk-errors.js
@@ -0,0 +1,32 @@
+'use strict';
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const tls = require('tls');
+
+{
+ // Check tlsClientError on invalid pskIdentityHint.
+
+ const server = tls.createServer({
+ ciphers: 'PSK+HIGH',
+ pskCallback: () => {},
+ pskIdentityHint: 'a'.repeat(512), // Too long identity hint.
+ });
+ server.on('tlsClientError', (err) => {
+ assert.ok(err instanceof Error);
+ assert.strictEqual(err.code, 'ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED');
+ server.close();
+ });
+ server.listen(0, () => {
+ const client = tls.connect({
+ port: server.address().port,
+ ciphers: 'PSK+HIGH',
+ checkServerIdentity: () => {},
+ pskCallback: () => {},
+ }, () => {});
+ client.on('error', common.expectsError({ code: 'ECONNRESET' }));
+ });
+}
diff --git a/test/parallel/test-tls-psk-server.js b/test/parallel/test-tls-psk-server.js
new file mode 100644
index 00000000000..69b850c7022
--- /dev/null
+++ b/test/parallel/test-tls-psk-server.js
@@ -0,0 +1,77 @@
+'use strict';
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+if (!common.opensslCli)
+ common.skip('missing openssl cli');
+
+const assert = require('assert');
+
+const tls = require('tls');
+const spawn = require('child_process').spawn;
+
+const CIPHERS = 'PSK+HIGH';
+const KEY = 'd731ef57be09e5204f0b205b60627028';
+const IDENTITY = 'TestUser';
+
+const server = tls.createServer({
+ ciphers: CIPHERS,
+ pskIdentityHint: IDENTITY,
+ pskCallback(socket, identity) {
+ assert.ok(socket instanceof tls.TLSSocket);
+ assert.ok(typeof identity === 'string');
+ if (identity === IDENTITY)
+ return Buffer.from(KEY, 'hex');
+ }
+});
+
+server.on('connection', common.mustCall());
+
+server.on('secureConnection', (socket) => {
+ socket.write('hello\r\n');
+
+ socket.on('data', (data) => {
+ socket.write(data);
+ });
+});
+
+let gotHello = false;
+let sentWorld = false;
+let gotWorld = false;
+
+server.listen(0, () => {
+ const client = spawn(common.opensslCli, [
+ 's_client',
+ '-connect', '127.0.0.1:' + server.address().port,
+ '-cipher', CIPHERS,
+ '-psk', KEY,
+ '-psk_identity', IDENTITY
+ ]);
+
+ let out = '';
+
+ client.stdout.setEncoding('utf8');
+ client.stdout.on('data', (d) => {
+ out += d;
+
+ if (!gotHello && /hello/.test(out)) {
+ gotHello = true;
+ client.stdin.write('world\r\n');
+ sentWorld = true;
+ }
+
+ if (!gotWorld && /world/.test(out)) {
+ gotWorld = true;
+ client.stdin.end();
+ }
+ });
+
+ client.on('exit', common.mustCall((code) => {
+ assert.ok(gotHello);
+ assert.ok(sentWorld);
+ assert.ok(gotWorld);
+ assert.strictEqual(code, 0);
+ server.close();
+ }));
+});
diff --git a/test/sequential/test-tls-psk-client.js b/test/sequential/test-tls-psk-client.js
new file mode 100644
index 00000000000..7c9fb939674
--- /dev/null
+++ b/test/sequential/test-tls-psk-client.js
@@ -0,0 +1,96 @@
+'use strict';
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+if (!common.opensslCli)
+ common.skip('missing openssl cli');
+
+const assert = require('assert');
+const tls = require('tls');
+const net = require('net');
+const { spawn } = require('child_process');
+
+const CIPHERS = 'PSK+HIGH';
+const KEY = 'd731ef57be09e5204f0b205b60627028';
+const IDENTITY = 'Client_identity'; // Hardcoded by `openssl s_server`
+
+const server = spawn(common.opensslCli, [
+ 's_server',
+ '-accept', common.PORT,
+ '-cipher', CIPHERS,
+ '-psk', KEY,
+ '-psk_hint', IDENTITY,
+ '-nocert',
+ '-rev',
+]);
+
+const cleanUp = (err) => {
+ clearTimeout(timeout);
+ if (err)
+ console.log('Failed:', err);
+ server.kill();
+ process.exitCode = err ? 1 : 0;
+};
+
+const timeout = setTimeout(() => cleanUp('Timeouted'), 5000);
+
+function waitForPort(port, cb) {
+ const socket = net.connect(common.PORT, () => {
+ socket.end();
+ socket.on('end', cb);
+ });
+ socket.on('error', (e) => {
+ if (e.code === 'ENOENT' || e.code === 'ECONNREFUSED') {
+ setTimeout(() => waitForPort(port, cb), 1000);
+ } else {
+ cb(e);
+ }
+ });
+}
+
+waitForPort(common.PORT, common.mustCall((err) => {
+ if (err) {
+ cleanUp(err);
+ return;
+ }
+
+ const message = 'hello';
+ const reverse = message.split('').reverse().join('');
+ runClient(message, common.mustCall((err, data) => {
+ try {
+ if (!err) assert.strictEqual(data.trim(), reverse);
+ } finally {
+ cleanUp(err);
+ }
+ }));
+}));
+
+function runClient(message, cb) {
+ const s = tls.connect(common.PORT, {
+ ciphers: CIPHERS,
+ checkServerIdentity: () => {},
+ pskCallback(hint) {
+ // 'hint' will be null in TLS1.3.
+ if (hint === null || hint === IDENTITY) {
+ return {
+ identity: IDENTITY,
+ psk: Buffer.from(KEY, 'hex')
+ };
+ }
+ }
+ });
+ s.on('secureConnect', common.mustCall(() => {
+ let data = '';
+ s.on('data', common.mustCallAtLeast((d) => {
+ data += d;
+ }));
+ s.on('end', common.mustCall(() => {
+ cb(null, data);
+ }));
+ s.end(message);
+ }));
+ s.on('error', (e) => {
+ cb(e);
+ });
+}