123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- var SSH2Stream = require('../lib/ssh');
- var parseKey = require('../lib/utils').parseKey;
-
- var assert = require('assert');
- var fs = require('fs');
-
- var t = -1;
- var SERVER_PRV_KEY = fs.readFileSync(__dirname + '/fixtures/openssh_new_rsa');
- var PARSED_SERVER_KEY = parseKey(SERVER_PRV_KEY);
- var CLIENT_PRV_KEY = fs.readFileSync(__dirname + '/fixtures/openssh_old_rsa');
- var PARSED_CLIENT_KEY = parseKey(CLIENT_PRV_KEY);
-
- function makePair(cb) {
- var server = new SSH2Stream({
- server: true,
- hostKeys: {
- 'ssh-rsa': PARSED_SERVER_KEY
- },
- algorithms: {
- serverHostKey: ['ssh-rsa']
- }
- });
- var client = new SSH2Stream();
-
- var done = [];
- function tryDone(who) {
- done.push(who);
- if (done.length !== 2)
- return;
- cb(server, client);
- }
-
- server.on('NEWKEYS', function () { tryDone('server'); });
- client.on('NEWKEYS', function () { tryDone('client'); });
- server.pipe(client).pipe(server);
- }
-
- function signWithClientKey(blob, syncCb) {
- syncCb(PARSED_CLIENT_KEY.sign(blob));
- }
-
- function bufferEqual(a, b) {
- if (a.length !== b.length)
- return false;
- for (var i = 0; i < a.length; ++i) {
- if (a[i] !== b[i])
- return false;
- }
- return true;
- }
-
- function publickey(server, client) {
- server.on('USERAUTH_REQUEST', function(user, service, method, data) {
- assert.equal(user, 'bob');
- assert.equal(service, 'ssh-connection');
- assert.equal(method, 'publickey');
- assert.equal(data.keyAlgo, PARSED_CLIENT_KEY.type);
- assert.equal(true, bufferEqual(data.key, PARSED_CLIENT_KEY.getPublicSSH()));
- assert.equal(data.signature, undefined);
- assert.equal(data.blob, undefined);
- return server.authPKOK(data.keyAlgo, data.key);
- });
- client.on('USERAUTH_PK_OK', function() {
- next();
- }).authPK('bob', PARSED_CLIENT_KEY);
- }
-
- function keyboardInteractive(server, client) {
- var infoReqsRxed = 0;
-
- server.on('USERAUTH_REQUEST', function(user, service, method, data) {
- assert.equal(user, 'bob');
- assert.equal(service, 'ssh-connection');
- assert.equal(method, 'keyboard-interactive');
- assert.equal(data, '');
- process.nextTick(function() {
- server.authInfoReq('req 0', 'instructions', [
- { prompt: 'Say something to req 0', echo: true }
- ]);
- });
- }).on('USERAUTH_INFO_RESPONSE', function(responses) {
- if (infoReqsRxed === 1) {
- assert.equal(responses.length, 1);
- assert.equal(responses[0], 'hello to req 0');
- process.nextTick(function() {
- server.authInfoReq('req 1', 'new instructions', [
- { prompt: 'Say something to req 1', echo: true },
- { prompt: 'Say something else', echo: false }
- ]);
- });
- } else if (infoReqsRxed === 2) {
- assert.equal(responses.length, 2);
- assert.equal(responses[0], 'hello to req 1');
- assert.equal(responses[1], 'something else');
- next();
- } else {
- throw new Error('Received too many info reqs: ' + infoReqsRxed);
- }
- });
-
- client.on('USERAUTH_INFO_REQUEST', function (name, inst, lang, prompts) {
- infoReqsRxed++;
- if (infoReqsRxed === 1) {
- assert.equal(name, 'req 0');
- assert.equal(inst, 'instructions');
- assert.equal(lang, '');
- assert.deepEqual(prompts, [
- { prompt: 'Say something to req 0', echo: true }
- ]);
- process.nextTick(function() {
- client.authInfoRes([ 'hello to req 0' ]);
- });
- } else if (infoReqsRxed === 2) {
- assert.equal(name, 'req 1');
- assert.equal(inst, 'new instructions');
- assert.equal(lang, '');
- assert.deepEqual(prompts, [
- { prompt: 'Say something to req 1', echo: true },
- { prompt: 'Say something else', echo: false }
- ]);
- process.nextTick(function() {
- client.authInfoRes([ 'hello to req 1', 'something else' ]);
- });
- } else {
- throw new Error('Received too many info reqs: ' + infoReqsRxed);
- }
- }).authKeyboard('bob');
- }
-
- function mixedMethods(server, client) {
- var expectedStages = [
- 'SERVER_SEES_PK_CHECK',
- 'SERVER_SEES_PK_REQUEST',
- 'SERVER_SEES_PASSWORD',
- 'SERVER_SEES_KEYBOARD_INTERACTIVE',
- 'CLIENT_SEES_PK_OK',
- 'CLIENT_SEES_USERAUTH_FAILURE_PK',
- 'CLIENT_SEES_USERAUTH_FAILURE_PASSWORD',
- 'CLIENT_SEES_KEYBOARD_REQ',
- 'SERVER_SEES_KEYBOARD_RES',
- 'CLIENT_SEES_USERAUTH_SUCCESS',
- ];
-
- server.on('USERAUTH_REQUEST', function(name, service, method, data) {
- assert.equal(name, 'bob');
- assert.equal(service, 'ssh-connection');
- var expectedStage = expectedStages.shift();
- switch (expectedStage) {
- case 'SERVER_SEES_PK_CHECK':
- assert.equal(method, 'publickey');
- assert.equal(data.signature, undefined);
- return process.nextTick(function() {
- server.authPKOK(data.keyAlgo, data.key);
- });
- case 'SERVER_SEES_PK_REQUEST':
- assert.equal(method, 'publickey');
- assert.notEqual(data.signature, undefined);
- return process.nextTick(function() {
- server.authFailure(
- ['publickey', 'password', 'keyboard-interactive'],
- false
- );
- });
- case 'SERVER_SEES_PASSWORD':
- assert.equal(method, 'password');
- assert.equal(data, 'seekrit');
- return process.nextTick(function() {
- server.authFailure(
- ['publickey', 'password', 'keyboard-interactive'],
- false
- );
- });
- case 'SERVER_SEES_KEYBOARD_INTERACTIVE':
- assert.equal(method, 'keyboard-interactive');
- assert.equal(data, '');
- return process.nextTick(function() {
- server.authInfoReq('Password required', 'Password prompt', [
- { prompt: 'Password:', echo: false }
- ]);
- });
- default:
- throw new Error('Server saw USERAUTH_REQUEST ' + method +
- ' but expected ' + expectedStage);
- }
- }).on('USERAUTH_INFO_RESPONSE', function(responses) {
- assert.equal(expectedStages.shift(), 'SERVER_SEES_KEYBOARD_RES');
- assert.deepEqual(responses, [ 'seekrit' ]);
- process.nextTick(function() {
- server.authSuccess();
- });
- });
-
-
- client.on('USERAUTH_PK_OK', function() {
- assert.equal(expectedStages.shift(), 'CLIENT_SEES_PK_OK');
- }).on('USERAUTH_FAILURE', function() {
- var expectedStage = expectedStages.shift();
- if (expectedStage !== 'CLIENT_SEES_USERAUTH_FAILURE_PK' &&
- expectedStage !== 'CLIENT_SEES_USERAUTH_FAILURE_PASSWORD') {
- throw new Error('Client saw USERAUTH_FAILURE but expected ' +
- expectedStage);
- }
- }).on('USERAUTH_INFO_REQUEST', function(name, inst, lang, prompts) {
- assert.equal(expectedStages.shift(), 'CLIENT_SEES_KEYBOARD_REQ');
- assert.equal(name, 'Password required');
- assert.equal(inst, 'Password prompt');
- assert.equal(lang, '');
- assert.deepEqual(prompts, [ { prompt: 'Password:', echo: false } ]);
- process.nextTick(function() {
- client.authInfoRes([ 'seekrit' ]);
- });
- }).on('USERAUTH_SUCCESS', function() {
- assert.equal(expectedStages.shift(), 'CLIENT_SEES_USERAUTH_SUCCESS');
- assert.equal(expectedStages.shift(), undefined);
- next();
- });
-
- // Silly to submit all these auths at once, but allowed by RFC4252
- client.authPK('bob', PARSED_CLIENT_KEY);
- client.authPK('bob', PARSED_CLIENT_KEY, signWithClientKey);
- client.authPassword('bob', 'seekrit');
- client.authKeyboard('bob');
- }
-
- var tests = [
- publickey,
- keyboardInteractive,
- // password // ssh2-streams can't generate a password change request
- mixedMethods
- ];
-
-
- function next() {
- if (Array.isArray(process._events.exit))
- process._events.exit = process._events.exit[1];
- if (++t === tests.length)
- return;
-
- var v = tests[t];
- makePair(v);
- }
-
- process.once('exit', function() {
- assert(t === tests.length,
- 'Only finished ' + t + '/' + tests.length + ' tests');
- });
-
- next();
|