test-client-server.js 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422
  1. var Client = require('../lib/client');
  2. var Server = require('../lib/server');
  3. var OPEN_MODE = require('ssh2-streams').SFTPStream.OPEN_MODE;
  4. var STATUS_CODE = require('ssh2-streams').SFTPStream.STATUS_CODE;
  5. var utils = require('ssh2-streams').utils;
  6. var net = require('net');
  7. var fs = require('fs');
  8. var crypto = require('crypto');
  9. var path = require('path');
  10. var join = path.join;
  11. var inspect = require('util').inspect;
  12. var assert = require('assert');
  13. var t = -1;
  14. var group = path.basename(__filename, '.js') + '/';
  15. var fixturesdir = join(__dirname, 'fixtures');
  16. var USER = 'nodejs';
  17. var PASSWORD = 'FLUXCAPACITORISTHEPOWER';
  18. var MD5_HOST_FINGERPRINT = '64254520742d3d0792e918f3ce945a64';
  19. var KEY_RSA_BAD = fs.readFileSync(join(fixturesdir, 'bad_rsa_private_key'));
  20. var HOST_KEY_RSA = fs.readFileSync(join(fixturesdir, 'ssh_host_rsa_key'));
  21. var HOST_KEY_DSA = fs.readFileSync(join(fixturesdir, 'ssh_host_dsa_key'));
  22. var HOST_KEY_ECDSA = fs.readFileSync(join(fixturesdir, 'ssh_host_ecdsa_key'));
  23. var CLIENT_KEY_ENC_RSA_RAW = fs.readFileSync(join(fixturesdir, 'id_rsa_enc'));
  24. var CLIENT_KEY_ENC_RSA = utils.parseKey(CLIENT_KEY_ENC_RSA_RAW, 'foobarbaz');
  25. var CLIENT_KEY_PPK_RSA_RAW = fs.readFileSync(join(fixturesdir, 'id_rsa.ppk'));
  26. var CLIENT_KEY_PPK_RSA = utils.parseKey(CLIENT_KEY_PPK_RSA_RAW);
  27. var CLIENT_KEY_RSA_RAW = fs.readFileSync(join(fixturesdir, 'id_rsa'));
  28. var CLIENT_KEY_RSA = utils.parseKey(CLIENT_KEY_RSA_RAW);
  29. var CLIENT_KEY_RSA_NEW_RAW =
  30. fs.readFileSync(join(fixturesdir, 'openssh_new_rsa'));
  31. var CLIENT_KEY_RSA_NEW = utils.parseKey(CLIENT_KEY_RSA_NEW_RAW)[0];
  32. var CLIENT_KEY_DSA_RAW = fs.readFileSync(join(fixturesdir, 'id_dsa'));
  33. var CLIENT_KEY_DSA = utils.parseKey(CLIENT_KEY_DSA_RAW);
  34. var CLIENT_KEY_ECDSA_RAW = fs.readFileSync(join(fixturesdir, 'id_ecdsa'));
  35. var CLIENT_KEY_ECDSA = utils.parseKey(CLIENT_KEY_ECDSA_RAW);
  36. var DEBUG = false;
  37. var DEFAULT_TEST_TIMEOUT = 30 * 1000;
  38. var tests = [
  39. { run: function() {
  40. var client;
  41. var server;
  42. var r;
  43. r = setup(
  44. this,
  45. { username: USER,
  46. privateKey: CLIENT_KEY_RSA_RAW
  47. },
  48. { hostKeys: [HOST_KEY_RSA] }
  49. );
  50. client = r.client;
  51. server = r.server;
  52. server.on('connection', function(conn) {
  53. conn.on('authentication', function(ctx) {
  54. if (ctx.method === 'none')
  55. return ctx.reject();
  56. assert(ctx.method === 'publickey',
  57. makeMsg('Unexpected auth method: ' + ctx.method));
  58. assert(ctx.username === USER,
  59. makeMsg('Unexpected username: ' + ctx.username));
  60. assert(ctx.key.algo === 'ssh-rsa',
  61. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  62. assert.deepEqual(CLIENT_KEY_RSA.getPublicSSH(),
  63. ctx.key.data,
  64. makeMsg('Public key mismatch'));
  65. if (ctx.signature) {
  66. assert(CLIENT_KEY_RSA.verify(ctx.blob, ctx.signature) === true,
  67. makeMsg('Could not verify PK signature'));
  68. ctx.accept();
  69. } else
  70. ctx.accept();
  71. }).on('ready', function() {
  72. conn.end();
  73. });
  74. });
  75. },
  76. what: 'Authenticate with an RSA key (old OpenSSH)'
  77. },
  78. { run: function() {
  79. var client;
  80. var server;
  81. var r;
  82. r = setup(
  83. this,
  84. { username: USER,
  85. privateKey: CLIENT_KEY_RSA_NEW_RAW
  86. },
  87. { hostKeys: [HOST_KEY_RSA] }
  88. );
  89. client = r.client;
  90. server = r.server;
  91. server.on('connection', function(conn) {
  92. conn.on('authentication', function(ctx) {
  93. if (ctx.method === 'none')
  94. return ctx.reject();
  95. assert(ctx.method === 'publickey',
  96. makeMsg('Unexpected auth method: ' + ctx.method));
  97. assert(ctx.username === USER,
  98. makeMsg('Unexpected username: ' + ctx.username));
  99. assert(ctx.key.algo === 'ssh-rsa',
  100. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  101. assert.deepEqual(CLIENT_KEY_RSA_NEW.getPublicSSH(),
  102. ctx.key.data,
  103. makeMsg('Public key mismatch'));
  104. if (ctx.signature) {
  105. assert(CLIENT_KEY_RSA_NEW.verify(ctx.blob, ctx.signature) === true,
  106. makeMsg('Could not verify PK signature'));
  107. ctx.accept();
  108. } else
  109. ctx.accept();
  110. }).on('ready', function() {
  111. conn.end();
  112. });
  113. });
  114. },
  115. what: 'Authenticate with an RSA key (new OpenSSH)'
  116. },
  117. { run: function() {
  118. var client;
  119. var server;
  120. var r;
  121. r = setup(
  122. this,
  123. { username: USER,
  124. privateKey: CLIENT_KEY_ENC_RSA_RAW,
  125. passphrase: 'foobarbaz',
  126. },
  127. { hostKeys: [HOST_KEY_RSA] }
  128. );
  129. client = r.client;
  130. server = r.server;
  131. server.on('connection', function(conn) {
  132. conn.on('authentication', function(ctx) {
  133. if (ctx.method === 'none')
  134. return ctx.reject();
  135. assert(ctx.method === 'publickey',
  136. makeMsg('Unexpected auth method: ' + ctx.method));
  137. assert(ctx.username === USER,
  138. makeMsg('Unexpected username: ' + ctx.username));
  139. assert(ctx.key.algo === 'ssh-rsa',
  140. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  141. assert.deepEqual(CLIENT_KEY_ENC_RSA.getPublicSSH(),
  142. ctx.key.data,
  143. makeMsg('Public key mismatch'));
  144. if (ctx.signature) {
  145. assert(CLIENT_KEY_ENC_RSA.verify(ctx.blob, ctx.signature) === true,
  146. makeMsg('Could not verify PK signature'));
  147. ctx.accept();
  148. } else
  149. ctx.accept();
  150. }).on('ready', function() {
  151. conn.end();
  152. });
  153. });
  154. },
  155. what: 'Authenticate with an encrypted RSA key'
  156. },
  157. { run: function() {
  158. var client;
  159. var server;
  160. var r;
  161. r = setup(
  162. this,
  163. { username: USER,
  164. privateKey: CLIENT_KEY_PPK_RSA_RAW
  165. },
  166. { hostKeys: [HOST_KEY_RSA] }
  167. );
  168. client = r.client;
  169. server = r.server;
  170. server.on('connection', function(conn) {
  171. conn.on('authentication', function(ctx) {
  172. if (ctx.method === 'none')
  173. return ctx.reject();
  174. assert(ctx.method === 'publickey',
  175. makeMsg('Unexpected auth method: ' + ctx.method));
  176. assert(ctx.username === USER,
  177. makeMsg('Unexpected username: ' + ctx.username));
  178. assert(ctx.key.algo === 'ssh-rsa',
  179. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  180. if (ctx.signature) {
  181. assert(CLIENT_KEY_PPK_RSA.verify(ctx.blob, ctx.signature) === true,
  182. makeMsg('Could not verify PK signature'));
  183. ctx.accept();
  184. } else
  185. ctx.accept();
  186. }).on('ready', function() {
  187. conn.end();
  188. });
  189. });
  190. },
  191. what: 'Authenticate with an RSA key (PPK)'
  192. },
  193. { run: function() {
  194. var client;
  195. var server;
  196. var r;
  197. r = setup(
  198. this,
  199. { username: USER,
  200. privateKey: CLIENT_KEY_DSA_RAW
  201. },
  202. { hostKeys: [HOST_KEY_RSA] }
  203. );
  204. client = r.client;
  205. server = r.server;
  206. server.on('connection', function(conn) {
  207. conn.on('authentication', function(ctx) {
  208. if (ctx.method === 'none')
  209. return ctx.reject();
  210. assert(ctx.method === 'publickey',
  211. makeMsg('Unexpected auth method: ' + ctx.method));
  212. assert(ctx.username === USER,
  213. makeMsg('Unexpected username: ' + ctx.username));
  214. assert(ctx.key.algo === 'ssh-dss',
  215. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  216. assert.deepEqual(CLIENT_KEY_DSA.getPublicSSH(),
  217. ctx.key.data,
  218. makeMsg('Public key mismatch'));
  219. if (ctx.signature) {
  220. assert(CLIENT_KEY_DSA.verify(ctx.blob, ctx.signature) === true,
  221. makeMsg('Could not verify PK signature'));
  222. ctx.accept();
  223. } else
  224. ctx.accept();
  225. }).on('ready', function() {
  226. conn.end();
  227. });
  228. });
  229. },
  230. what: 'Authenticate with a DSA key'
  231. },
  232. { run: function() {
  233. var client;
  234. var server;
  235. var r;
  236. r = setup(
  237. this,
  238. { username: USER,
  239. privateKey: CLIENT_KEY_ECDSA_RAW
  240. },
  241. { hostKeys: [HOST_KEY_RSA] }
  242. );
  243. client = r.client;
  244. server = r.server;
  245. server.on('connection', function(conn) {
  246. conn.on('authentication', function(ctx) {
  247. if (ctx.method === 'none')
  248. return ctx.reject();
  249. assert(ctx.method === 'publickey',
  250. makeMsg('Unexpected auth method: ' + ctx.method));
  251. assert(ctx.username === USER,
  252. makeMsg('Unexpected username: ' + ctx.username));
  253. assert(ctx.key.algo === 'ecdsa-sha2-nistp256',
  254. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  255. assert.deepEqual(CLIENT_KEY_ECDSA.getPublicSSH(),
  256. ctx.key.data,
  257. makeMsg('Public key mismatch'));
  258. if (ctx.signature) {
  259. assert(CLIENT_KEY_ECDSA.verify(ctx.blob, ctx.signature) === true,
  260. makeMsg('Could not verify PK signature'));
  261. ctx.accept();
  262. } else
  263. ctx.accept();
  264. }).on('ready', function() {
  265. conn.end();
  266. });
  267. });
  268. },
  269. what: 'Authenticate with a ECDSA key'
  270. },
  271. { run: function() {
  272. var client;
  273. var server;
  274. var r;
  275. r = setup(
  276. this,
  277. { username: USER,
  278. password: 'asdf',
  279. algorithms: {
  280. serverHostKey: ['ssh-dss']
  281. }
  282. },
  283. { hostKeys: [HOST_KEY_DSA] }
  284. );
  285. client = r.client;
  286. server = r.server;
  287. server.on('connection', function(conn) {
  288. conn.on('authentication', function(ctx) {
  289. if (ctx.method === 'none')
  290. return ctx.reject();
  291. assert(ctx.method === 'password',
  292. makeMsg('Unexpected auth method: ' + ctx.method));
  293. assert(ctx.username === USER,
  294. makeMsg('Unexpected username: ' + ctx.username));
  295. assert(ctx.password === 'asdf',
  296. makeMsg('Unexpected password: ' + ctx.password));
  297. ctx.accept();
  298. }).on('ready', function() {
  299. conn.end();
  300. });
  301. });
  302. },
  303. what: 'Server with DSA host key'
  304. },
  305. { run: function() {
  306. var client;
  307. var server;
  308. var r;
  309. r = setup(
  310. this,
  311. { username: USER,
  312. password: 'asdf'
  313. },
  314. { hostKeys: [HOST_KEY_ECDSA] }
  315. );
  316. client = r.client;
  317. server = r.server;
  318. server.on('connection', function(conn) {
  319. conn.on('authentication', function(ctx) {
  320. if (ctx.method === 'none')
  321. return ctx.reject();
  322. assert(ctx.method === 'password',
  323. makeMsg('Unexpected auth method: ' + ctx.method));
  324. assert(ctx.username === USER,
  325. makeMsg('Unexpected username: ' + ctx.username));
  326. assert(ctx.password === 'asdf',
  327. makeMsg('Unexpected password: ' + ctx.password));
  328. ctx.accept();
  329. }).on('ready', function() {
  330. conn.end();
  331. });
  332. });
  333. },
  334. what: 'Server with ECDSA host key'
  335. },
  336. { run: function() {
  337. var client;
  338. var server;
  339. var r;
  340. r = setup(
  341. this,
  342. { username: USER,
  343. password: 'asdf',
  344. algorithms: {
  345. serverHostKey: 'ssh-rsa'
  346. }
  347. },
  348. { hostKeys: [HOST_KEY_RSA, HOST_KEY_DSA] }
  349. );
  350. client = r.client;
  351. server = r.server;
  352. server.on('connection', function(conn) {
  353. conn.on('authentication', function(ctx) {
  354. if (ctx.method === 'none')
  355. return ctx.reject();
  356. assert(ctx.method === 'password',
  357. makeMsg('Unexpected auth method: ' + ctx.method));
  358. assert(ctx.username === USER,
  359. makeMsg('Unexpected username: ' + ctx.username));
  360. assert(ctx.password === 'asdf',
  361. makeMsg('Unexpected password: ' + ctx.password));
  362. ctx.accept();
  363. }).on('ready', function() {
  364. conn.end();
  365. });
  366. });
  367. },
  368. what: 'Server with multiple host keys (RSA selected)'
  369. },
  370. { run: function() {
  371. var client;
  372. var server;
  373. var r;
  374. r = setup(
  375. this,
  376. { username: USER,
  377. password: 'asdf',
  378. algorithms: {
  379. serverHostKey: 'ssh-dss'
  380. }
  381. },
  382. { hostKeys: [HOST_KEY_RSA, HOST_KEY_DSA] }
  383. );
  384. client = r.client;
  385. server = r.server;
  386. server.on('connection', function(conn) {
  387. conn.on('authentication', function(ctx) {
  388. if (ctx.method === 'none')
  389. return ctx.reject();
  390. assert(ctx.method === 'password',
  391. makeMsg('Unexpected auth method: ' + ctx.method));
  392. assert(ctx.username === USER,
  393. makeMsg('Unexpected username: ' + ctx.username));
  394. assert(ctx.password === 'asdf',
  395. makeMsg('Unexpected password: ' + ctx.password));
  396. ctx.accept();
  397. }).on('ready', function() {
  398. conn.end();
  399. });
  400. });
  401. },
  402. what: 'Server with multiple host keys (DSA selected)'
  403. },
  404. { run: function() {
  405. var client;
  406. var server;
  407. var r;
  408. var hostname = 'foo';
  409. var username = 'bar';
  410. r = setup(
  411. this,
  412. { username: USER,
  413. privateKey: CLIENT_KEY_RSA_RAW,
  414. localHostname: hostname,
  415. localUsername: username
  416. },
  417. { hostKeys: [ HOST_KEY_RSA] }
  418. );
  419. client = r.client;
  420. server = r.server;
  421. server.on('connection', function(conn) {
  422. conn.on('authentication', function(ctx) {
  423. if (ctx.method !== 'hostbased')
  424. return ctx.reject();
  425. assert(ctx.method === 'hostbased',
  426. makeMsg('Unexpected auth method: ' + ctx.method));
  427. assert(ctx.username === USER,
  428. makeMsg('Unexpected username: ' + ctx.username));
  429. assert(ctx.key.algo === 'ssh-rsa',
  430. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  431. assert.deepEqual(CLIENT_KEY_RSA.getPublicSSH(),
  432. ctx.key.data,
  433. makeMsg('Public key mismatch'));
  434. assert(ctx.signature,
  435. makeMsg('Expected signature'));
  436. assert(ctx.localHostname === hostname,
  437. makeMsg('Wrong local hostname'));
  438. assert(ctx.localUsername === username,
  439. makeMsg('Wrong local username'));
  440. assert(CLIENT_KEY_RSA.verify(ctx.blob, ctx.signature) === true,
  441. makeMsg('Could not verify hostbased signature'));
  442. ctx.accept();
  443. }).on('ready', function() {
  444. conn.end();
  445. });
  446. });
  447. },
  448. what: 'Authenticate with hostbased'
  449. },
  450. { run: function() {
  451. var client;
  452. var server;
  453. var r;
  454. r = setup(
  455. this,
  456. { username: USER,
  457. password: PASSWORD
  458. },
  459. { hostKeys: [HOST_KEY_RSA] }
  460. );
  461. client = r.client;
  462. server = r.server;
  463. server.on('connection', function(conn) {
  464. conn.on('authentication', function(ctx) {
  465. if (ctx.method === 'none')
  466. return ctx.reject();
  467. assert(ctx.method === 'password',
  468. makeMsg('Unexpected auth method: ' + ctx.method));
  469. assert(ctx.username === USER,
  470. makeMsg('Unexpected username: ' + ctx.username));
  471. assert(ctx.password === PASSWORD,
  472. makeMsg('Unexpected password: ' + ctx.password));
  473. ctx.accept();
  474. }).on('ready', function() {
  475. conn.end();
  476. });
  477. });
  478. },
  479. what: 'Authenticate with a password'
  480. },
  481. { run: function() {
  482. var client;
  483. var server;
  484. var r;
  485. var calls = 0;
  486. r = setup(
  487. this,
  488. { username: USER,
  489. password: PASSWORD,
  490. privateKey: CLIENT_KEY_RSA_RAW,
  491. authHandler: function(methodsLeft, partial, cb) {
  492. assert(calls++ === 0, makeMsg('authHandler called multiple times'));
  493. assert(methodsLeft === null, makeMsg('expected null methodsLeft'));
  494. assert(partial === null, makeMsg('expected null partial'));
  495. return 'none';
  496. }
  497. },
  498. { hostKeys: [HOST_KEY_RSA] }
  499. );
  500. client = r.client;
  501. server = r.server;
  502. var attempts = 0;
  503. server.on('connection', function(conn) {
  504. conn.on('authentication', function(ctx) {
  505. assert(++attempts === 1, makeMsg('too many auth attempts'));
  506. assert(ctx.method === 'none',
  507. makeMsg('Unexpected auth method: ' + ctx.method));
  508. ctx.accept();
  509. }).on('ready', function() {
  510. conn.end();
  511. });
  512. });
  513. },
  514. what: 'Custom authentication order (sync)'
  515. },
  516. { run: function() {
  517. var client;
  518. var server;
  519. var r;
  520. var calls = 0;
  521. r = setup(
  522. this,
  523. { username: USER,
  524. password: PASSWORD,
  525. privateKey: CLIENT_KEY_RSA_RAW,
  526. authHandler: function(methodsLeft, partial, cb) {
  527. assert(calls++ === 0, makeMsg('authHandler called multiple times'));
  528. assert(methodsLeft === null, makeMsg('expected null methodsLeft'));
  529. assert(partial === null, makeMsg('expected null partial'));
  530. process.nextTick(cb, 'none');
  531. }
  532. },
  533. { hostKeys: [HOST_KEY_RSA] }
  534. );
  535. client = r.client;
  536. server = r.server;
  537. var attempts = 0;
  538. server.on('connection', function(conn) {
  539. conn.on('authentication', function(ctx) {
  540. assert(++attempts === 1, makeMsg('too many auth attempts'));
  541. assert(ctx.method === 'none',
  542. makeMsg('Unexpected auth method: ' + ctx.method));
  543. ctx.accept();
  544. }).on('ready', function() {
  545. conn.end();
  546. });
  547. });
  548. },
  549. what: 'Custom authentication order (async)'
  550. },
  551. { run: function() {
  552. var client;
  553. var server;
  554. var r;
  555. var cliError;
  556. var calls = 0;
  557. r = setup(
  558. this,
  559. { username: USER,
  560. password: PASSWORD,
  561. privateKey: CLIENT_KEY_RSA_RAW,
  562. authHandler: function(methodsLeft, partial, cb) {
  563. assert(calls++ === 0, makeMsg('authHandler called multiple times'));
  564. assert(methodsLeft === null, makeMsg('expected null methodsLeft'));
  565. assert(partial === null, makeMsg('expected null partial'));
  566. return false;
  567. }
  568. },
  569. { hostKeys: [HOST_KEY_RSA] }
  570. );
  571. client = r.client;
  572. server = r.server;
  573. // Remove default client error handler added by `setup()` since we are
  574. // expecting an error in this case
  575. client.removeAllListeners('error');
  576. client.on('error', function(err) {
  577. cliError = err;
  578. assert.strictEqual(err.level, 'client-authentication');
  579. assert(/configured authentication methods failed/i.test(err.message),
  580. makeMsg('Wrong error message'));
  581. }).on('close', function() {
  582. assert(cliError, makeMsg('Expected client error'));
  583. });
  584. server.on('connection', function(conn) {
  585. conn.on('authentication', function(ctx) {
  586. assert(false, makeMsg('should not see auth attempt'));
  587. }).on('ready', function() {
  588. conn.end();
  589. });
  590. });
  591. },
  592. what: 'Custom authentication order (no methods)'
  593. },
  594. { run: function() {
  595. var client;
  596. var server;
  597. var r;
  598. var calls = 0;
  599. r = setup(
  600. this,
  601. { username: USER,
  602. password: PASSWORD,
  603. privateKey: CLIENT_KEY_RSA_RAW,
  604. authHandler: function(methodsLeft, partial, cb) {
  605. switch (calls++) {
  606. case 0:
  607. assert(methodsLeft === null,
  608. makeMsg('expected null methodsLeft'));
  609. assert(partial === null, makeMsg('expected null partial'));
  610. return 'publickey';
  611. case 1:
  612. assert.deepStrictEqual(methodsLeft,
  613. ['password'],
  614. makeMsg('expected password method left'
  615. + ', saw: ' + methodsLeft));
  616. assert(partial === true, makeMsg('expected partial success'));
  617. return 'password';
  618. default:
  619. assert(false, makeMsg('authHandler called too many times'));
  620. }
  621. }
  622. },
  623. { hostKeys: [HOST_KEY_RSA] }
  624. );
  625. client = r.client;
  626. server = r.server;
  627. var attempts = 0;
  628. server.on('connection', function(conn) {
  629. conn.on('authentication', function(ctx) {
  630. assert(++attempts === calls,
  631. makeMsg('server<->client state mismatch'));
  632. switch (calls) {
  633. case 1:
  634. assert(ctx.method === 'publickey',
  635. makeMsg('Unexpected auth method: ' + ctx.method));
  636. assert(ctx.username === USER,
  637. makeMsg('Unexpected username: ' + ctx.username));
  638. assert(ctx.key.algo === 'ssh-rsa',
  639. makeMsg('Unexpected key algo: ' + ctx.key.algo));
  640. assert.deepEqual(CLIENT_KEY_RSA.getPublicSSH(),
  641. ctx.key.data,
  642. makeMsg('Public key mismatch'));
  643. ctx.reject(['password'], true);
  644. break;
  645. case 2:
  646. assert(ctx.method === 'password',
  647. makeMsg('Unexpected auth method: ' + ctx.method));
  648. assert(ctx.username === USER,
  649. makeMsg('Unexpected username: ' + ctx.username));
  650. assert(ctx.password === PASSWORD,
  651. makeMsg('Unexpected password: ' + ctx.password));
  652. ctx.accept();
  653. break;
  654. default:
  655. assert(false, makeMsg('bad client auth state'));
  656. }
  657. }).on('ready', function() {
  658. conn.end();
  659. });
  660. });
  661. },
  662. what: 'Custom authentication order (multi-step)'
  663. },
  664. { run: function() {
  665. var client;
  666. var server;
  667. var r;
  668. var verified = false;
  669. r = setup(
  670. this,
  671. { username: USER,
  672. password: PASSWORD,
  673. hostHash: 'md5',
  674. hostVerifier: function(hash) {
  675. assert(hash === MD5_HOST_FINGERPRINT,
  676. makeMsg('Host fingerprint mismatch'));
  677. return (verified = true);
  678. }
  679. },
  680. { hostKeys: [HOST_KEY_RSA] }
  681. );
  682. client = r.client;
  683. server = r.server;
  684. server.on('connection', function(conn) {
  685. conn.on('authentication', function(ctx) {
  686. ctx.accept();
  687. }).on('ready', function() {
  688. conn.end();
  689. });
  690. }).on('close', function() {
  691. assert(verified, makeMsg('Failed to verify host fingerprint'));
  692. });
  693. },
  694. what: 'Verify host fingerprint'
  695. },
  696. { run: function() {
  697. var client;
  698. var server;
  699. var r;
  700. var out = '';
  701. var outErr = '';
  702. var exitArgs;
  703. var closeArgs;
  704. r = setup(
  705. this,
  706. { username: USER,
  707. password: PASSWORD
  708. },
  709. { hostKeys: [HOST_KEY_RSA] }
  710. );
  711. client = r.client;
  712. server = r.server;
  713. server.on('connection', function(conn) {
  714. conn.on('authentication', function(ctx) {
  715. ctx.accept();
  716. }).on('ready', function() {
  717. conn.once('session', function(accept, reject) {
  718. var session = accept();
  719. session.once('exec', function(accept, reject, info) {
  720. assert(info.command === 'foo --bar',
  721. makeMsg('Wrong exec command: ' + info.command));
  722. var stream = accept();
  723. stream.stderr.write('stderr data!\n');
  724. stream.write('stdout data!\n');
  725. stream.exit(100);
  726. stream.end();
  727. conn.end();
  728. });
  729. });
  730. });
  731. });
  732. client.on('ready', function() {
  733. client.exec('foo --bar', function(err, stream) {
  734. assert(!err, makeMsg('Unexpected exec error: ' + err));
  735. stream.on('data', function(d) {
  736. out += d;
  737. }).on('exit', function(code) {
  738. exitArgs = new Array(arguments.length);
  739. for (var i = 0; i < exitArgs.length; ++i)
  740. exitArgs[i] = arguments[i];
  741. }).on('close', function(code) {
  742. closeArgs = new Array(arguments.length);
  743. for (var i = 0; i < closeArgs.length; ++i)
  744. closeArgs[i] = arguments[i];
  745. }).stderr.on('data', function(d) {
  746. outErr += d;
  747. });
  748. });
  749. }).on('end', function() {
  750. assert.deepEqual(exitArgs,
  751. [100],
  752. makeMsg('Wrong exit args: ' + inspect(exitArgs)));
  753. assert.deepEqual(closeArgs,
  754. [100],
  755. makeMsg('Wrong close args: ' + inspect(closeArgs)));
  756. assert(out === 'stdout data!\n',
  757. makeMsg('Wrong stdout data: ' + inspect(out)));
  758. assert(outErr === 'stderr data!\n',
  759. makeMsg('Wrong stderr data: ' + inspect(outErr)));
  760. });
  761. },
  762. what: 'Simple exec'
  763. },
  764. { run: function() {
  765. var client;
  766. var server;
  767. var r;
  768. var serverEnv = {};
  769. var clientEnv = { SSH2NODETEST: 'foo' };
  770. r = setup(
  771. this,
  772. { username: USER,
  773. password: PASSWORD
  774. },
  775. { hostKeys: [HOST_KEY_RSA] }
  776. );
  777. client = r.client;
  778. server = r.server;
  779. server.on('connection', function(conn) {
  780. conn.on('authentication', function(ctx) {
  781. ctx.accept();
  782. }).on('ready', function() {
  783. conn.once('session', function(accept, reject) {
  784. var session = accept();
  785. session.once('env', function(accept, reject, info) {
  786. serverEnv[info.key] = info.val;
  787. accept && accept();
  788. }).once('exec', function(accept, reject, info) {
  789. assert(info.command === 'foo --bar',
  790. makeMsg('Wrong exec command: ' + info.command));
  791. var stream = accept();
  792. stream.exit(100);
  793. stream.end();
  794. conn.end();
  795. });
  796. });
  797. });
  798. });
  799. client.on('ready', function() {
  800. client.exec('foo --bar',
  801. { env: clientEnv },
  802. function(err, stream) {
  803. assert(!err, makeMsg('Unexpected exec error: ' + err));
  804. stream.resume();
  805. });
  806. }).on('end', function() {
  807. assert.deepEqual(serverEnv, clientEnv,
  808. makeMsg('Environment mismatch'));
  809. });
  810. },
  811. what: 'Exec with environment set'
  812. },
  813. { run: function() {
  814. var client;
  815. var server;
  816. var r;
  817. var out = '';
  818. r = setup(
  819. this,
  820. { username: USER,
  821. password: PASSWORD
  822. },
  823. { hostKeys: [HOST_KEY_RSA] }
  824. );
  825. client = r.client;
  826. server = r.server;
  827. server.on('connection', function(conn) {
  828. conn.on('authentication', function(ctx) {
  829. ctx.accept();
  830. }).on('ready', function() {
  831. conn.once('session', function(accept, reject) {
  832. var session = accept();
  833. var ptyInfo;
  834. session.once('pty', function(accept, reject, info) {
  835. ptyInfo = info;
  836. accept && accept();
  837. }).once('exec', function(accept, reject, info) {
  838. assert(info.command === 'foo --bar',
  839. makeMsg('Wrong exec command: ' + info.command));
  840. var stream = accept();
  841. stream.write(JSON.stringify(ptyInfo));
  842. stream.exit(100);
  843. stream.end();
  844. conn.end();
  845. });
  846. });
  847. });
  848. });
  849. var pty = {
  850. rows: 2,
  851. cols: 4,
  852. width: 0,
  853. height: 0,
  854. term: 'vt220',
  855. modes: {}
  856. };
  857. client.on('ready', function() {
  858. client.exec('foo --bar',
  859. { pty: pty },
  860. function(err, stream) {
  861. assert(!err, makeMsg('Unexpected exec error: ' + err));
  862. stream.on('data', function(d) {
  863. out += d;
  864. });
  865. });
  866. }).on('end', function() {
  867. assert.deepEqual(JSON.parse(out),
  868. pty,
  869. makeMsg('Wrong stdout data: ' + inspect(out)));
  870. });
  871. },
  872. what: 'Exec with pty set'
  873. },
  874. { run: function() {
  875. var client;
  876. var server;
  877. var r;
  878. var out = '';
  879. r = setup(
  880. this,
  881. { username: USER,
  882. password: PASSWORD,
  883. agent: '/foo/bar/baz'
  884. },
  885. { hostKeys: [HOST_KEY_RSA] }
  886. );
  887. client = r.client;
  888. server = r.server;
  889. server.on('connection', function(conn) {
  890. conn.on('authentication', function(ctx) {
  891. ctx.accept();
  892. }).on('ready', function() {
  893. conn.once('session', function(accept, reject) {
  894. var session = accept();
  895. var authAgentReq = false;
  896. session.once('auth-agent', function(accept, reject) {
  897. authAgentReq = true;
  898. accept && accept();
  899. }).once('exec', function(accept, reject, info) {
  900. assert(info.command === 'foo --bar',
  901. makeMsg('Wrong exec command: ' + info.command));
  902. var stream = accept();
  903. stream.write(inspect(authAgentReq));
  904. stream.exit(100);
  905. stream.end();
  906. conn.end();
  907. });
  908. });
  909. });
  910. });
  911. client.on('ready', function() {
  912. client.exec('foo --bar',
  913. { agentForward: true },
  914. function(err, stream) {
  915. assert(!err, makeMsg('Unexpected exec error: ' + err));
  916. stream.on('data', function(d) {
  917. out += d;
  918. });
  919. });
  920. }).on('end', function() {
  921. assert(out === 'true',
  922. makeMsg('Wrong stdout data: ' + inspect(out)));
  923. });
  924. },
  925. what: 'Exec with OpenSSH agent forwarding'
  926. },
  927. { run: function() {
  928. var client;
  929. var server;
  930. var r;
  931. var out = '';
  932. r = setup(
  933. this,
  934. { username: USER,
  935. password: PASSWORD
  936. },
  937. { hostKeys: [HOST_KEY_RSA] }
  938. );
  939. client = r.client;
  940. server = r.server;
  941. server.on('connection', function(conn) {
  942. conn.on('authentication', function(ctx) {
  943. ctx.accept();
  944. }).on('ready', function() {
  945. conn.once('session', function(accept, reject) {
  946. var session = accept();
  947. var x11 = false;
  948. session.once('x11', function(accept, reject, info) {
  949. assert.strictEqual(info.single,
  950. false,
  951. makeMsg('Wrong client x11.single: '
  952. + info.single));
  953. assert.strictEqual(info.screen,
  954. 0,
  955. makeMsg('Wrong client x11.screen: '
  956. + info.screen));
  957. assert.strictEqual(info.protocol,
  958. 'MIT-MAGIC-COOKIE-1',
  959. makeMsg('Wrong client x11.protocol: '
  960. + info.protocol));
  961. assert.strictEqual(info.cookie.length,
  962. 32,
  963. makeMsg('Invalid client x11.cookie: '
  964. + info.cookie));
  965. x11 = true;
  966. accept && accept();
  967. }).once('exec', function(accept, reject, info) {
  968. assert(info.command === 'foo --bar',
  969. makeMsg('Wrong exec command: ' + info.command));
  970. var stream = accept();
  971. conn.x11('127.0.0.1', 4321, function(err, xstream) {
  972. assert(!err, makeMsg('Unexpected x11() error: ' + err));
  973. xstream.resume();
  974. xstream.on('end', function() {
  975. stream.write(JSON.stringify(x11));
  976. stream.exit(100);
  977. stream.end();
  978. conn.end();
  979. }).end();
  980. });
  981. });
  982. });
  983. });
  984. });
  985. client.on('ready', function() {
  986. client.on('x11', function(info, accept, reject) {
  987. assert.strictEqual(info.srcIP,
  988. '127.0.0.1',
  989. makeMsg('Invalid server x11.srcIP: '
  990. + info.srcIP));
  991. assert.strictEqual(info.srcPort,
  992. 4321,
  993. makeMsg('Invalid server x11.srcPort: '
  994. + info.srcPort));
  995. accept();
  996. }).exec('foo --bar',
  997. { x11: true },
  998. function(err, stream) {
  999. assert(!err, makeMsg('Unexpected exec error: ' + err));
  1000. stream.on('data', function(d) {
  1001. out += d;
  1002. });
  1003. });
  1004. }).on('end', function() {
  1005. assert(out === 'true',
  1006. makeMsg('Wrong stdout data: ' + inspect(out)));
  1007. });
  1008. },
  1009. what: 'Exec with X11 forwarding'
  1010. },
  1011. { run: function() {
  1012. var client;
  1013. var server;
  1014. var r;
  1015. var out = '';
  1016. var x11ClientConfig = {
  1017. single: true,
  1018. screen: 1234,
  1019. protocol: 'YUMMY-MAGIC-COOKIE-1',
  1020. cookie: '00112233445566778899001122334455'
  1021. };
  1022. r = setup(
  1023. this,
  1024. { username: USER,
  1025. password: PASSWORD
  1026. },
  1027. { hostKeys: [HOST_KEY_RSA] }
  1028. );
  1029. client = r.client;
  1030. server = r.server;
  1031. server.on('connection', function(conn) {
  1032. conn.on('authentication', function(ctx) {
  1033. ctx.accept();
  1034. }).on('ready', function() {
  1035. conn.once('session', function(accept, reject) {
  1036. var session = accept();
  1037. var x11 = false;
  1038. session.once('x11', function(accept, reject, info) {
  1039. assert.strictEqual(info.single,
  1040. true,
  1041. makeMsg('Wrong client x11.single: '
  1042. + info.single));
  1043. assert.strictEqual(info.screen,
  1044. 1234,
  1045. makeMsg('Wrong client x11.screen: '
  1046. + info.screen));
  1047. assert.strictEqual(info.protocol,
  1048. 'YUMMY-MAGIC-COOKIE-1',
  1049. makeMsg('Wrong client x11.protocol: '
  1050. + info.protocol));
  1051. assert.strictEqual(info.cookie,
  1052. '00112233445566778899001122334455',
  1053. makeMsg('Wrong client x11.cookie: '
  1054. + info.cookie));
  1055. x11 = info;
  1056. accept && accept();
  1057. }).once('exec', function(accept, reject, info) {
  1058. assert(info.command === 'foo --bar',
  1059. makeMsg('Wrong exec command: ' + info.command));
  1060. var stream = accept();
  1061. conn.x11('127.0.0.1', 4321, function(err, xstream) {
  1062. assert(!err, makeMsg('Unexpected x11() error: ' + err));
  1063. xstream.resume();
  1064. xstream.on('end', function() {
  1065. stream.write(JSON.stringify(x11));
  1066. stream.exit(100);
  1067. stream.end();
  1068. conn.end();
  1069. }).end();
  1070. });
  1071. });
  1072. });
  1073. });
  1074. });
  1075. client.on('ready', function() {
  1076. client.on('x11', function(info, accept, reject) {
  1077. assert.strictEqual(info.srcIP,
  1078. '127.0.0.1',
  1079. makeMsg('Invalid server x11.srcIP: '
  1080. + info.srcIP));
  1081. assert.strictEqual(info.srcPort,
  1082. 4321,
  1083. makeMsg('Invalid server x11.srcPort: '
  1084. + info.srcPort));
  1085. accept();
  1086. }).exec('foo --bar',
  1087. { x11: x11ClientConfig },
  1088. function(err, stream) {
  1089. assert(!err, makeMsg('Unexpected exec error: ' + err));
  1090. stream.on('data', function(d) {
  1091. out += d;
  1092. });
  1093. });
  1094. }).on('end', function() {
  1095. var result = JSON.parse(out);
  1096. assert.deepStrictEqual(result,
  1097. x11ClientConfig,
  1098. makeMsg('Wrong stdout data: ' + result));
  1099. });
  1100. },
  1101. what: 'Exec with X11 forwarding (custom X11 settings)'
  1102. },
  1103. { run: function() {
  1104. var client;
  1105. var server;
  1106. var r;
  1107. var out = '';
  1108. r = setup(
  1109. this,
  1110. { username: USER,
  1111. password: PASSWORD
  1112. },
  1113. { hostKeys: [HOST_KEY_RSA] }
  1114. );
  1115. client = r.client;
  1116. server = r.server;
  1117. server.on('connection', function(conn) {
  1118. conn.on('authentication', function(ctx) {
  1119. ctx.accept();
  1120. }).on('ready', function() {
  1121. conn.once('session', function(accept, reject) {
  1122. var session = accept();
  1123. var sawPty = false;
  1124. session.once('pty', function(accept, reject, info) {
  1125. sawPty = true;
  1126. accept && accept();
  1127. }).once('shell', function(accept, reject) {
  1128. var stream = accept();
  1129. stream.write('Cowabunga dude! ' + inspect(sawPty));
  1130. stream.end();
  1131. conn.end();
  1132. });
  1133. });
  1134. });
  1135. });
  1136. client.on('ready', function() {
  1137. client.shell(function(err, stream) {
  1138. assert(!err, makeMsg('Unexpected shell error: ' + err));
  1139. stream.on('data', function(d) {
  1140. out += d;
  1141. });
  1142. });
  1143. }).on('end', function() {
  1144. assert(out === 'Cowabunga dude! true',
  1145. makeMsg('Wrong stdout data: ' + inspect(out)));
  1146. });
  1147. },
  1148. what: 'Simple shell'
  1149. },
  1150. { run: function() {
  1151. var client;
  1152. var server;
  1153. var r;
  1154. var serverEnv = {};
  1155. var clientEnv = { SSH2NODETEST: 'foo' };
  1156. var sawPty = false;
  1157. r = setup(
  1158. this,
  1159. { username: USER,
  1160. password: PASSWORD
  1161. },
  1162. { hostKeys: [HOST_KEY_RSA] }
  1163. );
  1164. client = r.client;
  1165. server = r.server;
  1166. server.on('connection', function(conn) {
  1167. conn.on('authentication', function(ctx) {
  1168. ctx.accept();
  1169. }).on('ready', function() {
  1170. conn.once('session', function(accept, reject) {
  1171. var session = accept();
  1172. session.once('env', function(accept, reject, info) {
  1173. serverEnv[info.key] = info.val;
  1174. accept && accept();
  1175. }).once('pty', function(accept, reject, info) {
  1176. sawPty = true;
  1177. accept && accept();
  1178. }).once('shell', function(accept, reject) {
  1179. var stream = accept();
  1180. stream.end();
  1181. conn.end();
  1182. });
  1183. });
  1184. });
  1185. });
  1186. client.on('ready', function() {
  1187. client.shell({ env: clientEnv }, function(err, stream) {
  1188. assert(!err, makeMsg('Unexpected shell error: ' + err));
  1189. stream.resume();
  1190. });
  1191. }).on('end', function() {
  1192. assert.deepEqual(serverEnv, clientEnv,
  1193. makeMsg('Environment mismatch'));
  1194. assert.strictEqual(sawPty, true);
  1195. });
  1196. },
  1197. what: 'Shell with environment set'
  1198. },
  1199. { run: function() {
  1200. var client;
  1201. var server;
  1202. var r;
  1203. var expHandle = Buffer.from([1, 2, 3, 4]);
  1204. var sawOpenS = false;
  1205. var sawCloseS = false;
  1206. var sawOpenC = false;
  1207. var sawCloseC = false;
  1208. r = setup(
  1209. this,
  1210. { username: USER,
  1211. password: PASSWORD
  1212. },
  1213. { hostKeys: [HOST_KEY_RSA] }
  1214. );
  1215. client = r.client;
  1216. server = r.server;
  1217. server.on('connection', function(conn) {
  1218. conn.on('authentication', function(ctx) {
  1219. ctx.accept();
  1220. }).on('ready', function() {
  1221. conn.once('session', function(accept, reject) {
  1222. var session = accept();
  1223. session.once('sftp', function(accept, reject) {
  1224. if (accept) {
  1225. var sftp = accept();
  1226. sftp.once('OPEN', function(id, filename, flags, attrs) {
  1227. assert(id === 0,
  1228. makeMsg('Unexpected sftp request ID: ' + id));
  1229. assert(filename === 'node.js',
  1230. makeMsg('Unexpected filename: ' + filename));
  1231. assert(flags === OPEN_MODE.READ,
  1232. makeMsg('Unexpected flags: ' + flags));
  1233. sawOpenS = true;
  1234. sftp.handle(id, expHandle);
  1235. sftp.once('CLOSE', function(id, handle) {
  1236. assert(id === 1,
  1237. makeMsg('Unexpected sftp request ID: ' + id));
  1238. assert.deepEqual(handle,
  1239. expHandle,
  1240. makeMsg('Wrong sftp file handle: '
  1241. + inspect(handle)));
  1242. sawCloseS = true;
  1243. sftp.status(id, STATUS_CODE.OK);
  1244. conn.end();
  1245. });
  1246. });
  1247. }
  1248. });
  1249. });
  1250. });
  1251. });
  1252. client.on('ready', function() {
  1253. client.sftp(function(err, sftp) {
  1254. assert(!err, makeMsg('Unexpected sftp error: ' + err));
  1255. sftp.open('node.js', 'r', function(err, handle) {
  1256. assert(!err, makeMsg('Unexpected sftp error: ' + err));
  1257. assert.deepEqual(handle,
  1258. expHandle,
  1259. makeMsg('Wrong sftp file handle: '
  1260. + inspect(handle)));
  1261. sawOpenC = true;
  1262. sftp.close(handle, function(err) {
  1263. assert(!err, makeMsg('Unexpected sftp error: ' + err));
  1264. sawCloseC = true;
  1265. });
  1266. });
  1267. });
  1268. }).on('end', function() {
  1269. assert(sawOpenS, makeMsg('Expected sftp open()'));
  1270. assert(sawOpenC, makeMsg('Expected sftp open() callback'));
  1271. assert(sawCloseS, makeMsg('Expected sftp open()'));
  1272. assert(sawOpenC, makeMsg('Expected sftp close() callback'));
  1273. });
  1274. },
  1275. what: 'Simple SFTP'
  1276. },
  1277. { run: function() {
  1278. var client;
  1279. var server;
  1280. var state = {
  1281. readies: 0,
  1282. closes: 0
  1283. };
  1284. var clientcfg = {
  1285. username: USER,
  1286. password: PASSWORD
  1287. };
  1288. var servercfg = {
  1289. hostKeys: [HOST_KEY_RSA]
  1290. };
  1291. var reconnect = false;
  1292. client = new Client(),
  1293. server = new Server(servercfg);
  1294. function onReady() {
  1295. assert(++state.readies <= 4,
  1296. makeMsg('Wrong ready count: ' + state.readies));
  1297. }
  1298. function onClose() {
  1299. assert(++state.closes <= 3,
  1300. makeMsg('Wrong close count: ' + state.closes));
  1301. if (state.closes === 2)
  1302. server.close();
  1303. else if (state.closes === 3)
  1304. next();
  1305. }
  1306. server.listen(0, 'localhost', function() {
  1307. clientcfg.host = 'localhost';
  1308. clientcfg.port = server.address().port;
  1309. client.connect(clientcfg);
  1310. });
  1311. server.on('connection', function(conn) {
  1312. conn.on('authentication', function(ctx) {
  1313. ctx.accept();
  1314. }).on('ready', onReady);
  1315. }).on('close', onClose);
  1316. client.on('ready', function() {
  1317. onReady();
  1318. if (reconnect)
  1319. client.end();
  1320. else {
  1321. reconnect = true;
  1322. client.connect(clientcfg);
  1323. }
  1324. }).on('close', onClose);
  1325. },
  1326. what: 'connect() on connected client'
  1327. },
  1328. { run: function() {
  1329. var client = new Client({
  1330. username: USER,
  1331. password: PASSWORD
  1332. });
  1333. assert.throws(function() {
  1334. client.exec('uptime', function(err, stream) {
  1335. assert(false, makeMsg('Callback unexpectedly called'));
  1336. });
  1337. });
  1338. next();
  1339. },
  1340. what: 'Throw when not connected'
  1341. },
  1342. { run: function() {
  1343. var client;
  1344. var server;
  1345. var r;
  1346. var calledBack = 0;
  1347. r = setup(
  1348. this,
  1349. { username: USER,
  1350. password: PASSWORD
  1351. },
  1352. { hostKeys: [HOST_KEY_RSA] }
  1353. );
  1354. client = r.client;
  1355. server = r.server;
  1356. server.on('connection', function(conn) {
  1357. conn.on('authentication', function(ctx) {
  1358. ctx.accept();
  1359. });
  1360. });
  1361. client.on('ready', function() {
  1362. function callback(err, stream) {
  1363. assert(err, makeMsg('Expected error'));
  1364. assert(err.message === 'No response from server',
  1365. makeMsg('Wrong error message: ' + err.message));
  1366. ++calledBack;
  1367. }
  1368. client.exec('uptime', callback);
  1369. client.shell(callback);
  1370. client.sftp(callback);
  1371. client.end();
  1372. }).on('close', function() {
  1373. // give the callbacks a chance to execute
  1374. process.nextTick(function() {
  1375. assert(calledBack === 3,
  1376. makeMsg('Only '
  1377. + calledBack
  1378. + '/3 outstanding callbacks called'));
  1379. });
  1380. });
  1381. },
  1382. what: 'Outstanding callbacks called on disconnect'
  1383. },
  1384. { run: function() {
  1385. var client;
  1386. var server;
  1387. var r;
  1388. var calledBack = 0;
  1389. r = setup(
  1390. this,
  1391. { username: USER,
  1392. password: PASSWORD
  1393. },
  1394. { hostKeys: [HOST_KEY_RSA] }
  1395. );
  1396. client = r.client;
  1397. server = r.server;
  1398. server.on('connection', function(conn) {
  1399. conn.on('authentication', function(ctx) {
  1400. ctx.accept();
  1401. }).on('ready', function() {
  1402. conn.on('session', function(accept, reject) {
  1403. var session = accept();
  1404. session.once('exec', function(accept, reject, info) {
  1405. var stream = accept();
  1406. stream.exit(0);
  1407. stream.end();
  1408. });
  1409. });
  1410. });
  1411. });
  1412. client.on('ready', function() {
  1413. function callback(err, stream) {
  1414. assert(!err, makeMsg('Unexpected error: ' + err));
  1415. stream.resume();
  1416. if (++calledBack === 3)
  1417. client.end();
  1418. }
  1419. client.exec('foo', callback);
  1420. client.exec('bar', callback);
  1421. client.exec('baz', callback);
  1422. }).on('end', function() {
  1423. assert(calledBack === 3,
  1424. makeMsg('Only '
  1425. + calledBack
  1426. + '/3 callbacks called'));
  1427. });
  1428. },
  1429. what: 'Pipelined requests'
  1430. },
  1431. { run: function() {
  1432. var client;
  1433. var server;
  1434. var r;
  1435. var calledBack = 0;
  1436. r = setup(
  1437. this,
  1438. { username: USER,
  1439. password: PASSWORD
  1440. },
  1441. { hostKeys: [HOST_KEY_RSA] }
  1442. );
  1443. client = r.client;
  1444. server = r.server;
  1445. server.on('connection', function(conn) {
  1446. conn.on('authentication', function(ctx) {
  1447. ctx.accept();
  1448. }).on('ready', function() {
  1449. var reqs = [];
  1450. conn.on('session', function(accept, reject) {
  1451. if (reqs.length === 0) {
  1452. conn.rekey(function(err) {
  1453. assert(!err, makeMsg('Unexpected rekey error: ' + err));
  1454. reqs.forEach(function(accept) {
  1455. var session = accept();
  1456. session.once('exec', function(accept, reject, info) {
  1457. var stream = accept();
  1458. stream.exit(0);
  1459. stream.end();
  1460. });
  1461. });
  1462. });
  1463. }
  1464. reqs.push(accept);
  1465. });
  1466. });
  1467. });
  1468. client.on('ready', function() {
  1469. function callback(err, stream) {
  1470. assert(!err, makeMsg('Unexpected error: ' + err));
  1471. stream.resume();
  1472. if (++calledBack === 3)
  1473. client.end();
  1474. }
  1475. client.exec('foo', callback);
  1476. client.exec('bar', callback);
  1477. client.exec('baz', callback);
  1478. }).on('end', function() {
  1479. assert(calledBack === 3,
  1480. makeMsg('Only '
  1481. + calledBack
  1482. + '/3 callbacks called'));
  1483. });
  1484. },
  1485. what: 'Pipelined requests with intermediate rekeying'
  1486. },
  1487. { run: function() {
  1488. var client;
  1489. var server;
  1490. var r;
  1491. r = setup(
  1492. this,
  1493. { username: USER,
  1494. password: PASSWORD
  1495. },
  1496. { hostKeys: [HOST_KEY_RSA] }
  1497. );
  1498. client = r.client;
  1499. server = r.server;
  1500. server.on('connection', function(conn) {
  1501. conn.on('authentication', function(ctx) {
  1502. ctx.accept();
  1503. }).on('ready', function() {
  1504. conn.on('session', function(accept, reject) {
  1505. var session = accept();
  1506. session.once('exec', function(accept, reject, info) {
  1507. var stream = accept();
  1508. stream.exit(0);
  1509. stream.end();
  1510. });
  1511. });
  1512. });
  1513. });
  1514. client.on('ready', function() {
  1515. client.exec('foo', function(err, stream) {
  1516. assert(!err, makeMsg('Unexpected error: ' + err));
  1517. stream.on('exit', function(code, signal) {
  1518. client.end();
  1519. });
  1520. });
  1521. });
  1522. },
  1523. what: 'Ignore outgoing after stream close'
  1524. },
  1525. { run: function() {
  1526. var client;
  1527. var server;
  1528. var r;
  1529. r = setup(
  1530. this,
  1531. { username: USER,
  1532. password: PASSWORD
  1533. },
  1534. { hostKeys: [HOST_KEY_RSA] }
  1535. );
  1536. client = r.client;
  1537. server = r.server;
  1538. server.on('connection', function(conn) {
  1539. conn.on('authentication', function(ctx) {
  1540. ctx.accept();
  1541. }).on('ready', function() {
  1542. conn.on('session', function(accept, reject) {
  1543. accept().on('sftp', function(accept, reject) {
  1544. var sftp = accept();
  1545. // XXX: hack to get channel ...
  1546. var channel = sftp._readableState.pipes;
  1547. channel.unpipe(sftp);
  1548. sftp.unpipe(channel);
  1549. channel.exit(127);
  1550. channel.close();
  1551. });
  1552. });
  1553. });
  1554. });
  1555. client.on('ready', function() {
  1556. var timeout = setTimeout(function() {
  1557. assert(false, makeMsg('Unexpected SFTP timeout'));
  1558. }, 1000);
  1559. client.sftp(function(err, sftp) {
  1560. clearTimeout(timeout);
  1561. assert(err, makeMsg('Expected error'));
  1562. assert(err.code === 127,
  1563. makeMsg('Expected exit code 127, saw: ' + err.code));
  1564. client.end();
  1565. });
  1566. });
  1567. },
  1568. what: 'SFTP server aborts with exit-status'
  1569. },
  1570. { run: function() {
  1571. var client;
  1572. var server;
  1573. var r;
  1574. r = setup(
  1575. this,
  1576. { username: USER,
  1577. password: PASSWORD,
  1578. sock: new net.Socket()
  1579. },
  1580. { hostKeys: [HOST_KEY_RSA] }
  1581. );
  1582. client = r.client;
  1583. server = r.server;
  1584. server.on('connection', function(conn) {
  1585. conn.on('authentication', function(ctx) {
  1586. ctx.accept();
  1587. }).on('ready', function() {});
  1588. });
  1589. client.on('ready', function() {
  1590. client.end();
  1591. });
  1592. },
  1593. what: 'Double pipe on unconnected, passed in net.Socket'
  1594. },
  1595. { run: function() {
  1596. var client;
  1597. var server;
  1598. var r;
  1599. r = setup(
  1600. this,
  1601. { username: USER },
  1602. { hostKeys: [HOST_KEY_RSA] }
  1603. );
  1604. client = r.client;
  1605. server = r.server;
  1606. server.on('connection', function(conn) {
  1607. conn.on('authentication', function(ctx) {
  1608. ctx.accept();
  1609. });
  1610. conn.on('request', function(accept, reject, name, info) {
  1611. accept();
  1612. conn.forwardOut('good', 0, 'remote', 12345, function(err, ch) {
  1613. if (err) {
  1614. assert(!err, makeMsg('Unexpected error: ' + err));
  1615. }
  1616. conn.forwardOut('bad', 0, 'remote', 12345, function(err, ch) {
  1617. assert(err, makeMsg('Should receive error'));
  1618. client.end();
  1619. });
  1620. });
  1621. });
  1622. });
  1623. client.on('ready', function() {
  1624. // request forwarding
  1625. client.forwardIn('good', 0, function(err, port) {
  1626. if (err) {
  1627. assert(!err, makeMsg('Unexpected error: ' + err));
  1628. }
  1629. });
  1630. });
  1631. client.on('tcp connection', function(details, accept, reject) {
  1632. accept();
  1633. });
  1634. },
  1635. what: 'Client auto-rejects unrequested, allows requested forwarded-tcpip'
  1636. },
  1637. { run: function() {
  1638. var client;
  1639. var server;
  1640. var r;
  1641. r = setup(
  1642. this,
  1643. { username: USER,
  1644. password: PASSWORD
  1645. },
  1646. { hostKeys: [HOST_KEY_RSA],
  1647. greeting: 'Hello world!'
  1648. }
  1649. );
  1650. client = r.client;
  1651. server = r.server;
  1652. var sawGreeting = false;
  1653. client.on('greeting', function(greeting) {
  1654. assert.strictEqual(greeting, 'Hello world!\r\n');
  1655. sawGreeting = true;
  1656. });
  1657. client.on('banner', function(message) {
  1658. assert.fail(null, null, makeMsg('Unexpected banner'));
  1659. });
  1660. server.on('connection', function(conn) {
  1661. conn.on('authentication', function(ctx) {
  1662. assert(sawGreeting, makeMsg('Client did not see greeting'));
  1663. if (ctx.method === 'none')
  1664. return ctx.reject();
  1665. assert(ctx.method === 'password',
  1666. makeMsg('Unexpected auth method: ' + ctx.method));
  1667. assert(ctx.username === USER,
  1668. makeMsg('Unexpected username: ' + ctx.username));
  1669. assert(ctx.password === PASSWORD,
  1670. makeMsg('Unexpected password: ' + ctx.password));
  1671. ctx.accept();
  1672. }).on('ready', function() {
  1673. conn.end();
  1674. });
  1675. });
  1676. },
  1677. what: 'Server greeting'
  1678. },
  1679. { run: function() {
  1680. var client;
  1681. var server;
  1682. var r;
  1683. r = setup(
  1684. this,
  1685. { username: USER,
  1686. password: PASSWORD
  1687. },
  1688. { hostKeys: [HOST_KEY_RSA],
  1689. banner: 'Hello world!'
  1690. }
  1691. );
  1692. client = r.client;
  1693. server = r.server;
  1694. var sawBanner = false;
  1695. client.on('greeting', function(greeting) {
  1696. assert.fail(null, null, makeMsg('Unexpected greeting'));
  1697. });
  1698. client.on('banner', function(message) {
  1699. assert.strictEqual(message, 'Hello world!\r\n');
  1700. sawBanner = true;
  1701. });
  1702. server.on('connection', function(conn) {
  1703. conn.on('authentication', function(ctx) {
  1704. assert(sawBanner, makeMsg('Client did not see banner'));
  1705. if (ctx.method === 'none')
  1706. return ctx.reject();
  1707. assert(ctx.method === 'password',
  1708. makeMsg('Unexpected auth method: ' + ctx.method));
  1709. assert(ctx.username === USER,
  1710. makeMsg('Unexpected username: ' + ctx.username));
  1711. assert(ctx.password === PASSWORD,
  1712. makeMsg('Unexpected password: ' + ctx.password));
  1713. ctx.accept();
  1714. }).on('ready', function() {
  1715. conn.end();
  1716. });
  1717. });
  1718. },
  1719. what: 'Server banner'
  1720. },
  1721. { run: function() {
  1722. var client;
  1723. var server;
  1724. var r;
  1725. var fastRejectSent = false;
  1726. function sendAcceptLater(accept) {
  1727. if (fastRejectSent)
  1728. accept();
  1729. else
  1730. setImmediate(sendAcceptLater, accept);
  1731. }
  1732. r = setup(
  1733. this,
  1734. { username: USER },
  1735. { hostKeys: [HOST_KEY_RSA] }
  1736. );
  1737. client = r.client;
  1738. server = r.server;
  1739. server.on('connection', function(conn) {
  1740. conn.on('authentication', function(ctx) {
  1741. ctx.accept();
  1742. });
  1743. conn.on('request', function(accept, reject, name, info) {
  1744. if (info.bindAddr === 'fastReject') {
  1745. // Will call reject on 'fastReject' soon
  1746. reject();
  1747. fastRejectSent = true;
  1748. } else
  1749. // but accept on 'slowAccept' later
  1750. sendAcceptLater(accept);
  1751. });
  1752. });
  1753. client.on('ready', function() {
  1754. var replyCnt = 0;
  1755. client.forwardIn('slowAccept', 0, function(err) {
  1756. assert(!err, makeMsg('Unexpected error: ' + err));
  1757. if (++replyCnt === 2)
  1758. client.end();
  1759. });
  1760. client.forwardIn('fastReject', 0, function(err) {
  1761. assert(err, makeMsg('Should receive error'));
  1762. if (++replyCnt === 2)
  1763. client.end();
  1764. });
  1765. });
  1766. },
  1767. what: 'Server responds to global requests in the right order'
  1768. },
  1769. { run: function() {
  1770. var client;
  1771. var server;
  1772. var r;
  1773. r = setup(
  1774. this,
  1775. { username: USER,
  1776. password: PASSWORD
  1777. },
  1778. { hostKeys: [HOST_KEY_RSA] }
  1779. );
  1780. client = r.client;
  1781. server = r.server;
  1782. var timer;
  1783. server.on('connection', function(conn) {
  1784. conn.on('authentication', function(ctx) {
  1785. ctx.accept();
  1786. }).on('ready', function() {
  1787. conn.on('session', function(accept, reject) {
  1788. var session = accept();
  1789. session.once('subsystem', function(accept, reject, info) {
  1790. assert.equal(info.name, 'netconf');
  1791. // Prevent success reply from being sent
  1792. conn._sshstream.channelSuccess = function() {};
  1793. var stream = accept();
  1794. stream.close();
  1795. timer = setTimeout(function() {
  1796. throw new Error(makeMsg('Expected client callback'));
  1797. }, 50);
  1798. });
  1799. });
  1800. });
  1801. });
  1802. client.on('ready', function() {
  1803. client.subsys('netconf', function(err, stream) {
  1804. clearTimeout(timer);
  1805. assert(err);
  1806. client.end();
  1807. });
  1808. });
  1809. },
  1810. what: 'Cleanup outstanding channel requests on channel close'
  1811. },
  1812. { run: function() {
  1813. var client;
  1814. var server;
  1815. var r;
  1816. r = setup(
  1817. this,
  1818. { username: USER,
  1819. password: PASSWORD
  1820. },
  1821. { hostKeys: [HOST_KEY_RSA] }
  1822. );
  1823. client = r.client;
  1824. server = r.server;
  1825. var timer;
  1826. server.on('connection', function(conn) {
  1827. conn.on('authentication', function(ctx) {
  1828. ctx.accept();
  1829. }).on('ready', function() {
  1830. conn.on('session', function(accept, reject) {
  1831. var session = accept();
  1832. session.once('exec', function(accept, reject, info) {
  1833. var stream = accept();
  1834. // Write enough to bring the Client's channel window to 0
  1835. // (currently 1MB)
  1836. var buf = Buffer.allocUnsafe(2048);
  1837. for (var i = 0; i < 1000; ++i)
  1838. stream.write(buf);
  1839. stream.exit(0);
  1840. stream.close();
  1841. });
  1842. });
  1843. });
  1844. });
  1845. client.on('ready', function() {
  1846. client.exec('foo', function(err, stream) {
  1847. var sawClose = false;
  1848. assert(!err, makeMsg('Unexpected error'));
  1849. client._sshstream.on('CHANNEL_CLOSE:' + stream.incoming.id, onClose);
  1850. function onClose() {
  1851. // This handler gets called *after* the internal handler, so we
  1852. // should have seen `stream`'s `close` event already if the bug
  1853. // exists
  1854. assert(!sawClose, makeMsg('Premature close event'));
  1855. client.end();
  1856. }
  1857. stream.on('close', function() {
  1858. sawClose = true;
  1859. });
  1860. });
  1861. });
  1862. },
  1863. what: 'Channel emits close prematurely'
  1864. },
  1865. { run: function() {
  1866. var client;
  1867. var server;
  1868. var r;
  1869. r = setup(
  1870. this,
  1871. { username: USER },
  1872. { hostKeys: [HOST_KEY_RSA], ident: 'OpenSSH_5.3' }
  1873. );
  1874. client = r.client;
  1875. server = r.server;
  1876. server.on('connection', function(conn) {
  1877. conn.on('authentication', function(ctx) {
  1878. ctx.accept();
  1879. });
  1880. conn.once('request', function(accept, reject, name, info) {
  1881. assert(name === 'tcpip-forward',
  1882. makeMsg('Unexpected request: ' + name));
  1883. accept(1337);
  1884. conn.forwardOut('good', 0, 'remote', 12345, function(err, ch) {
  1885. assert(!err, makeMsg('Unexpected error: ' + err));
  1886. client.end();
  1887. });
  1888. });
  1889. });
  1890. client.on('ready', function() {
  1891. // request forwarding
  1892. client.forwardIn('good', 0, function(err, port) {
  1893. assert(!err, makeMsg('Unexpected error: ' + err));
  1894. assert(port === 1337, makeMsg('Bad bound port: ' + port));
  1895. });
  1896. });
  1897. client.on('tcp connection', function(details, accept, reject) {
  1898. assert(details.destIP === 'good',
  1899. makeMsg('Bad incoming destIP: ' + details.destIP));
  1900. assert(details.destPort === 1337,
  1901. makeMsg('Bad incoming destPort: ' + details.destPort));
  1902. assert(details.srcIP === 'remote',
  1903. makeMsg('Bad incoming srcIP: ' + details.srcIP));
  1904. assert(details.srcPort === 12345,
  1905. makeMsg('Bad incoming srcPort: ' + details.srcPort));
  1906. accept();
  1907. });
  1908. },
  1909. what: 'OpenSSH 5.x workaround for binding on port 0'
  1910. },
  1911. { run: function() {
  1912. var client;
  1913. var server;
  1914. var r;
  1915. var srvError;
  1916. var cliError;
  1917. r = setup(
  1918. this,
  1919. { username: USER,
  1920. algorithms: {
  1921. cipher: [ 'aes128-cbc' ]
  1922. }
  1923. },
  1924. { hostKeys: [HOST_KEY_RSA],
  1925. algorithms: {
  1926. cipher: [ 'aes128-ctr' ]
  1927. }
  1928. }
  1929. );
  1930. client = r.client;
  1931. server = r.server;
  1932. // Remove default client error handler added by `setup()` since we are
  1933. // expecting an error in this case
  1934. client.removeAllListeners('error');
  1935. function onError(err) {
  1936. if (this === client) {
  1937. assert(!cliError, makeMsg('Unexpected multiple client errors'));
  1938. cliError = err;
  1939. } else {
  1940. assert(!srvError, makeMsg('Unexpected multiple server errors'));
  1941. srvError = err;
  1942. }
  1943. assert.strictEqual(err.level, 'handshake');
  1944. assert(/handshake failed/i.test(err.message),
  1945. makeMsg('Wrong error message'));
  1946. }
  1947. server.on('connection', function(conn) {
  1948. // Remove default server connection error handler added by `setup()`
  1949. // since we are expecting an error in this case
  1950. conn.removeAllListeners('error');
  1951. function onGoodHandshake() {
  1952. assert(false, makeMsg('Handshake should have failed'));
  1953. }
  1954. conn.on('authentication', onGoodHandshake);
  1955. conn.on('ready', onGoodHandshake);
  1956. conn.on('error', onError);
  1957. });
  1958. client.on('ready', function() {
  1959. assert(false, makeMsg('Handshake should have failed'));
  1960. });
  1961. client.on('error', onError);
  1962. client.on('close', function() {
  1963. assert(cliError, makeMsg('Expected client error'));
  1964. assert(srvError, makeMsg('Expected server error'));
  1965. });
  1966. },
  1967. what: 'Handshake errors are emitted'
  1968. },
  1969. { run: function() {
  1970. var client;
  1971. var server;
  1972. var r;
  1973. var cliError;
  1974. r = setup(
  1975. this,
  1976. { username: USER, privateKey: KEY_RSA_BAD },
  1977. { hostKeys: [HOST_KEY_RSA] }
  1978. );
  1979. client = r.client;
  1980. server = r.server;
  1981. // Remove default client error handler added by `setup()` since we are
  1982. // expecting an error in this case
  1983. client.removeAllListeners('error');
  1984. server.on('connection', function(conn) {
  1985. conn.on('authentication', function(ctx) {
  1986. assert(ctx.method === 'publickey' || ctx.method === 'none',
  1987. makeMsg('Unexpected auth method: ' + ctx.method));
  1988. assert(!ctx.signature, makeMsg('Unexpected signature'));
  1989. if (ctx.method === 'none')
  1990. return ctx.reject();
  1991. ctx.accept();
  1992. });
  1993. conn.on('ready', function() {
  1994. assert(false, makeMsg('Authentication should have failed'));
  1995. });
  1996. });
  1997. client.on('ready', function() {
  1998. assert(false, makeMsg('Authentication should have failed'));
  1999. });
  2000. client.on('error', function(err) {
  2001. if (cliError) {
  2002. assert(/all configured/i.test(err.message),
  2003. makeMsg('Wrong error message'));
  2004. } else {
  2005. cliError = err;
  2006. assert(/signing/i.test(err.message), makeMsg('Wrong error message'));
  2007. }
  2008. });
  2009. client.on('close', function() {
  2010. assert(cliError, makeMsg('Expected client error'));
  2011. });
  2012. },
  2013. what: 'Client signing errors are caught and emitted'
  2014. },
  2015. { run: function() {
  2016. var client;
  2017. var server;
  2018. var r;
  2019. var srvError;
  2020. var cliError;
  2021. r = setup(
  2022. this,
  2023. { username: USER, password: 'foo' },
  2024. { hostKeys: [KEY_RSA_BAD] }
  2025. );
  2026. client = r.client;
  2027. server = r.server;
  2028. // Remove default client error handler added by `setup()` since we are
  2029. // expecting an error in this case
  2030. client.removeAllListeners('error');
  2031. server.on('connection', function(conn) {
  2032. // Remove default server connection error handler added by `setup()`
  2033. // since we are expecting an error in this case
  2034. conn.removeAllListeners('error');
  2035. conn.once('error', function(err) {
  2036. assert(/signing/i.test(err.message), makeMsg('Wrong error message'));
  2037. srvError = err;
  2038. });
  2039. conn.on('authentication', function(ctx) {
  2040. assert(false, makeMsg('Handshake should have failed'));
  2041. });
  2042. conn.on('ready', function() {
  2043. assert(false, makeMsg('Authentication should have failed'));
  2044. });
  2045. });
  2046. client.on('ready', function() {
  2047. assert(false, makeMsg('Handshake should have failed'));
  2048. });
  2049. client.on('error', function(err) {
  2050. assert(!cliError, makeMsg('Unexpected multiple client errors'));
  2051. assert(/KEY_EXCHANGE_FAILED/.test(err.message),
  2052. makeMsg('Wrong error message'));
  2053. cliError = err;
  2054. });
  2055. client.on('close', function() {
  2056. assert(srvError, makeMsg('Expected server error'));
  2057. assert(cliError, makeMsg('Expected client error'));
  2058. });
  2059. },
  2060. what: 'Server signing errors are caught and emitted'
  2061. },
  2062. { run: function() {
  2063. var client;
  2064. var server;
  2065. var r;
  2066. var sawReady = false;
  2067. r = setup(
  2068. this,
  2069. { username: '', password: 'foo' },
  2070. { hostKeys: [HOST_KEY_RSA] }
  2071. );
  2072. client = r.client;
  2073. server = r.server;
  2074. server.on('connection', function(conn) {
  2075. conn.on('authentication', function(ctx) {
  2076. assert.strictEqual(ctx.username, '',
  2077. makeMsg('Expected empty username'));
  2078. ctx.accept();
  2079. }).on('ready', function() {
  2080. conn.end();
  2081. });
  2082. });
  2083. client.on('ready', function() {
  2084. sawReady = true;
  2085. }).on('close', function() {
  2086. assert.strictEqual(sawReady, true, makeMsg('Expected ready event'));
  2087. });
  2088. },
  2089. what: 'Empty username string works'
  2090. },
  2091. { run: function() {
  2092. var client;
  2093. var server;
  2094. var r;
  2095. var socketPath = '/foo';
  2096. var events = [];
  2097. var expected = [
  2098. ['client', 'openssh_forwardInStreamLocal'],
  2099. ['server',
  2100. 'streamlocal-forward@openssh.com',
  2101. { socketPath: socketPath }],
  2102. ['client', 'forward callback'],
  2103. ['client', 'unix connection', { socketPath: socketPath }],
  2104. ['client', 'socket data', '1'],
  2105. ['server', 'socket data', '2'],
  2106. ['client', 'socket end'],
  2107. ['server',
  2108. 'cancel-streamlocal-forward@openssh.com',
  2109. { socketPath: socketPath }],
  2110. ['client', 'cancel callback']
  2111. ];
  2112. r = setup(
  2113. this,
  2114. { username: USER },
  2115. { hostKeys: [HOST_KEY_RSA], ident: 'OpenSSH_7.1' }
  2116. );
  2117. client = r.client;
  2118. server = r.server;
  2119. server.on('connection', function(conn) {
  2120. conn.on('authentication', function(ctx) {
  2121. ctx.accept();
  2122. });
  2123. conn.on('request', function(accept, reject, name, info) {
  2124. events.push(['server', name, info]);
  2125. if (name === 'streamlocal-forward@openssh.com') {
  2126. accept();
  2127. conn.openssh_forwardOutStreamLocal(socketPath, function(err, ch) {
  2128. assert(!err, makeMsg('Unexpected error: ' + err));
  2129. ch.write('1');
  2130. ch.on('data', function(data) {
  2131. events.push(['server', 'socket data', data.toString()]);
  2132. ch.close();
  2133. });
  2134. });
  2135. } else if (name === 'cancel-streamlocal-forward@openssh.com') {
  2136. accept();
  2137. } else {
  2138. reject();
  2139. }
  2140. });
  2141. });
  2142. client.on('ready', function() {
  2143. // request forwarding
  2144. events.push(['client', 'openssh_forwardInStreamLocal']);
  2145. client.openssh_forwardInStreamLocal(socketPath, function(err) {
  2146. assert(!err, makeMsg('Unexpected error: ' + err));
  2147. events.push(['client', 'forward callback']);
  2148. });
  2149. client.on('unix connection', function(info, accept, reject) {
  2150. events.push(['client', 'unix connection', info]);
  2151. var stream = accept();
  2152. stream.on('data', function(data) {
  2153. events.push(['client', 'socket data', data.toString()]);
  2154. stream.write('2');
  2155. }).on('end', function() {
  2156. events.push(['client', 'socket end']);
  2157. client.openssh_unforwardInStreamLocal(socketPath, function(err) {
  2158. assert(!err, makeMsg('Unexpected error: ' + err));
  2159. events.push(['client', 'cancel callback']);
  2160. client.end();
  2161. });
  2162. });
  2163. });
  2164. });
  2165. client.on('end', function() {
  2166. var msg = 'Events mismatch\nActual:\n' + inspect(events)
  2167. + '\nExpected:\n' + inspect(expected);
  2168. assert.deepEqual(events, expected, makeMsg(msg));
  2169. });
  2170. },
  2171. what: 'OpenSSH forwarded UNIX socket connection'
  2172. },
  2173. ];
  2174. function setup(self, clientcfg, servercfg, timeout) {
  2175. self.state = {
  2176. clientReady: false,
  2177. serverReady: false,
  2178. clientClose: false,
  2179. serverClose: false
  2180. };
  2181. if (DEBUG) {
  2182. console.log('========================================================\n'
  2183. + '[TEST] '
  2184. + self.what
  2185. + '\n========================================================');
  2186. clientcfg.debug = function(str) {
  2187. console.log('[CLIENT] ' + str);
  2188. };
  2189. servercfg.debug = function(str) {
  2190. console.log('[SERVER] ' + str);
  2191. };
  2192. }
  2193. var client = new Client();
  2194. var server = new Server(servercfg);
  2195. if (timeout === undefined)
  2196. timeout = DEFAULT_TEST_TIMEOUT;
  2197. var timer;
  2198. server.on('error', onError)
  2199. .on('connection', function(conn) {
  2200. conn.on('error', onError)
  2201. .on('ready', onReady);
  2202. server.close();
  2203. })
  2204. .on('close', onClose);
  2205. client.on('error', onError)
  2206. .on('ready', onReady)
  2207. .on('close', onClose);
  2208. function onError(err) {
  2209. var which = (this === client ? 'client' : 'server');
  2210. assert(false, makeMsg('Unexpected ' + which + ' error: ' + err));
  2211. }
  2212. function onReady() {
  2213. if (this === client) {
  2214. assert(!self.state.clientReady,
  2215. makeMsg('Received multiple ready events for client'));
  2216. self.state.clientReady = true;
  2217. } else {
  2218. assert(!self.state.serverReady,
  2219. makeMsg('Received multiple ready events for server'));
  2220. self.state.serverReady = true;
  2221. }
  2222. if (self.state.clientReady && self.state.serverReady)
  2223. self.onReady && self.onReady();
  2224. }
  2225. function onClose() {
  2226. if (this === client) {
  2227. assert(!self.state.clientClose,
  2228. makeMsg('Received multiple close events for client'));
  2229. self.state.clientClose = true;
  2230. } else {
  2231. assert(!self.state.serverClose,
  2232. makeMsg('Received multiple close events for server'));
  2233. self.state.serverClose = true;
  2234. }
  2235. if (self.state.clientClose && self.state.serverClose) {
  2236. clearTimeout(timer);
  2237. next();
  2238. }
  2239. }
  2240. process.nextTick(function() {
  2241. server.listen(0, 'localhost', function() {
  2242. if (timeout >= 0) {
  2243. timer = setTimeout(function() {
  2244. assert(false, makeMsg('Test timed out'));
  2245. }, timeout);
  2246. }
  2247. if (clientcfg.sock)
  2248. clientcfg.sock.connect(server.address().port, 'localhost');
  2249. else {
  2250. clientcfg.host = 'localhost';
  2251. clientcfg.port = server.address().port;
  2252. }
  2253. client.connect(clientcfg);
  2254. });
  2255. });
  2256. return { client: client, server: server };
  2257. }
  2258. function next() {
  2259. if (Array.isArray(process._events.exit))
  2260. process._events.exit = process._events.exit[1];
  2261. if (++t === tests.length)
  2262. return;
  2263. var v = tests[t];
  2264. v.run.call(v);
  2265. }
  2266. function makeMsg(what, msg) {
  2267. if (msg === undefined)
  2268. msg = what;
  2269. if (tests[t])
  2270. what = tests[t].what;
  2271. else
  2272. what = '<Unknown>';
  2273. return '[' + group + what + ']: ' + msg;
  2274. }
  2275. process.once('uncaughtException', function(err) {
  2276. if (t > -1 && !/(?:^|\n)AssertionError: /i.test(''+err))
  2277. console.log(makeMsg('Unexpected Exception:'));
  2278. throw err;
  2279. });
  2280. process.once('exit', function() {
  2281. assert(t === tests.length,
  2282. makeMsg('_exit',
  2283. 'Only finished ' + t + '/' + tests.length + ' tests'));
  2284. });
  2285. next();