test-client-server.js 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497
  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. if (Array.isArray(channel))
  1548. channel = channel[0];
  1549. channel.unpipe(sftp);
  1550. sftp.unpipe(channel);
  1551. channel.exit(127);
  1552. channel.close();
  1553. });
  1554. });
  1555. });
  1556. });
  1557. client.on('ready', function() {
  1558. var timeout = setTimeout(function() {
  1559. assert(false, makeMsg('Unexpected SFTP timeout'));
  1560. }, 1000);
  1561. client.sftp(function(err, sftp) {
  1562. clearTimeout(timeout);
  1563. assert(err, makeMsg('Expected error'));
  1564. assert(err.code === 127,
  1565. makeMsg('Expected exit code 127, saw: ' + err.code));
  1566. client.end();
  1567. });
  1568. });
  1569. },
  1570. what: 'SFTP server aborts with exit-status'
  1571. },
  1572. { run: function() {
  1573. var client;
  1574. var server;
  1575. var r;
  1576. r = setup(
  1577. this,
  1578. { username: USER,
  1579. password: PASSWORD,
  1580. sock: new net.Socket()
  1581. },
  1582. { hostKeys: [HOST_KEY_RSA] }
  1583. );
  1584. client = r.client;
  1585. server = r.server;
  1586. server.on('connection', function(conn) {
  1587. conn.on('authentication', function(ctx) {
  1588. ctx.accept();
  1589. }).on('ready', function() {});
  1590. });
  1591. client.on('ready', function() {
  1592. client.end();
  1593. });
  1594. },
  1595. what: 'Double pipe on unconnected, passed in net.Socket'
  1596. },
  1597. { run: function() {
  1598. var client;
  1599. var server;
  1600. var r;
  1601. r = setup(
  1602. this,
  1603. { username: USER },
  1604. { hostKeys: [HOST_KEY_RSA] }
  1605. );
  1606. client = r.client;
  1607. server = r.server;
  1608. server.on('connection', function(conn) {
  1609. conn.on('authentication', function(ctx) {
  1610. ctx.accept();
  1611. });
  1612. conn.on('request', function(accept, reject, name, info) {
  1613. accept();
  1614. conn.forwardOut('good', 0, 'remote', 12345, function(err, ch) {
  1615. if (err) {
  1616. assert(!err, makeMsg('Unexpected error: ' + err));
  1617. }
  1618. conn.forwardOut('bad', 0, 'remote', 12345, function(err, ch) {
  1619. assert(err, makeMsg('Should receive error'));
  1620. client.end();
  1621. });
  1622. });
  1623. });
  1624. });
  1625. client.on('ready', function() {
  1626. // request forwarding
  1627. client.forwardIn('good', 0, function(err, port) {
  1628. if (err) {
  1629. assert(!err, makeMsg('Unexpected error: ' + err));
  1630. }
  1631. });
  1632. });
  1633. client.on('tcp connection', function(details, accept, reject) {
  1634. accept();
  1635. });
  1636. },
  1637. what: 'Client auto-rejects unrequested, allows requested forwarded-tcpip'
  1638. },
  1639. { run: function() {
  1640. var client;
  1641. var server;
  1642. var r;
  1643. r = setup(
  1644. this,
  1645. { username: USER,
  1646. password: PASSWORD
  1647. },
  1648. { hostKeys: [HOST_KEY_RSA],
  1649. greeting: 'Hello world!'
  1650. }
  1651. );
  1652. client = r.client;
  1653. server = r.server;
  1654. var sawGreeting = false;
  1655. client.on('greeting', function(greeting) {
  1656. assert.strictEqual(greeting, 'Hello world!\r\n');
  1657. sawGreeting = true;
  1658. });
  1659. client.on('banner', function(message) {
  1660. assert.fail(null, null, makeMsg('Unexpected banner'));
  1661. });
  1662. server.on('connection', function(conn) {
  1663. conn.on('authentication', function(ctx) {
  1664. assert(sawGreeting, makeMsg('Client did not see greeting'));
  1665. if (ctx.method === 'none')
  1666. return ctx.reject();
  1667. assert(ctx.method === 'password',
  1668. makeMsg('Unexpected auth method: ' + ctx.method));
  1669. assert(ctx.username === USER,
  1670. makeMsg('Unexpected username: ' + ctx.username));
  1671. assert(ctx.password === PASSWORD,
  1672. makeMsg('Unexpected password: ' + ctx.password));
  1673. ctx.accept();
  1674. }).on('ready', function() {
  1675. conn.end();
  1676. });
  1677. });
  1678. },
  1679. what: 'Server greeting'
  1680. },
  1681. { run: function() {
  1682. var client;
  1683. var server;
  1684. var r;
  1685. r = setup(
  1686. this,
  1687. { username: USER,
  1688. password: PASSWORD
  1689. },
  1690. { hostKeys: [HOST_KEY_RSA],
  1691. banner: 'Hello world!'
  1692. }
  1693. );
  1694. client = r.client;
  1695. server = r.server;
  1696. var sawBanner = false;
  1697. client.on('greeting', function(greeting) {
  1698. assert.fail(null, null, makeMsg('Unexpected greeting'));
  1699. });
  1700. client.on('banner', function(message) {
  1701. assert.strictEqual(message, 'Hello world!\r\n');
  1702. sawBanner = true;
  1703. });
  1704. server.on('connection', function(conn) {
  1705. conn.on('authentication', function(ctx) {
  1706. assert(sawBanner, makeMsg('Client did not see banner'));
  1707. if (ctx.method === 'none')
  1708. return ctx.reject();
  1709. assert(ctx.method === 'password',
  1710. makeMsg('Unexpected auth method: ' + ctx.method));
  1711. assert(ctx.username === USER,
  1712. makeMsg('Unexpected username: ' + ctx.username));
  1713. assert(ctx.password === PASSWORD,
  1714. makeMsg('Unexpected password: ' + ctx.password));
  1715. ctx.accept();
  1716. }).on('ready', function() {
  1717. conn.end();
  1718. });
  1719. });
  1720. },
  1721. what: 'Server banner'
  1722. },
  1723. { run: function() {
  1724. var client;
  1725. var server;
  1726. var r;
  1727. var fastRejectSent = false;
  1728. function sendAcceptLater(accept) {
  1729. if (fastRejectSent)
  1730. accept();
  1731. else
  1732. setImmediate(sendAcceptLater, accept);
  1733. }
  1734. r = setup(
  1735. this,
  1736. { username: USER },
  1737. { hostKeys: [HOST_KEY_RSA] }
  1738. );
  1739. client = r.client;
  1740. server = r.server;
  1741. server.on('connection', function(conn) {
  1742. conn.on('authentication', function(ctx) {
  1743. ctx.accept();
  1744. });
  1745. conn.on('request', function(accept, reject, name, info) {
  1746. if (info.bindAddr === 'fastReject') {
  1747. // Will call reject on 'fastReject' soon
  1748. reject();
  1749. fastRejectSent = true;
  1750. } else
  1751. // but accept on 'slowAccept' later
  1752. sendAcceptLater(accept);
  1753. });
  1754. });
  1755. client.on('ready', function() {
  1756. var replyCnt = 0;
  1757. client.forwardIn('slowAccept', 0, function(err) {
  1758. assert(!err, makeMsg('Unexpected error: ' + err));
  1759. if (++replyCnt === 2)
  1760. client.end();
  1761. });
  1762. client.forwardIn('fastReject', 0, function(err) {
  1763. assert(err, makeMsg('Should receive error'));
  1764. if (++replyCnt === 2)
  1765. client.end();
  1766. });
  1767. });
  1768. },
  1769. what: 'Server responds to global requests in the right order'
  1770. },
  1771. { run: function() {
  1772. var client;
  1773. var server;
  1774. var r;
  1775. r = setup(
  1776. this,
  1777. { username: USER,
  1778. password: PASSWORD
  1779. },
  1780. { hostKeys: [HOST_KEY_RSA] }
  1781. );
  1782. client = r.client;
  1783. server = r.server;
  1784. var timer;
  1785. server.on('connection', function(conn) {
  1786. conn.on('authentication', function(ctx) {
  1787. ctx.accept();
  1788. }).on('ready', function() {
  1789. conn.on('session', function(accept, reject) {
  1790. var session = accept();
  1791. session.once('subsystem', function(accept, reject, info) {
  1792. assert.equal(info.name, 'netconf');
  1793. // Prevent success reply from being sent
  1794. conn._sshstream.channelSuccess = function() {};
  1795. var stream = accept();
  1796. stream.close();
  1797. timer = setTimeout(function() {
  1798. throw new Error(makeMsg('Expected client callback'));
  1799. }, 50);
  1800. });
  1801. });
  1802. });
  1803. });
  1804. client.on('ready', function() {
  1805. client.subsys('netconf', function(err, stream) {
  1806. clearTimeout(timer);
  1807. assert(err);
  1808. client.end();
  1809. });
  1810. });
  1811. },
  1812. what: 'Cleanup outstanding channel requests on channel close'
  1813. },
  1814. { run: function() {
  1815. var client;
  1816. var server;
  1817. var r;
  1818. r = setup(
  1819. this,
  1820. { username: USER,
  1821. password: PASSWORD
  1822. },
  1823. { hostKeys: [HOST_KEY_RSA] }
  1824. );
  1825. client = r.client;
  1826. server = r.server;
  1827. var timer;
  1828. server.on('connection', function(conn) {
  1829. conn.on('authentication', function(ctx) {
  1830. ctx.accept();
  1831. }).on('ready', function() {
  1832. conn.on('session', function(accept, reject) {
  1833. var session = accept();
  1834. session.once('exec', function(accept, reject, info) {
  1835. var stream = accept();
  1836. // Write enough to bring the Client's channel window to 0
  1837. // (currently 1MB)
  1838. var buf = Buffer.allocUnsafe(2048);
  1839. for (var i = 0; i < 1000; ++i)
  1840. stream.write(buf);
  1841. stream.exit(0);
  1842. stream.close();
  1843. });
  1844. });
  1845. });
  1846. });
  1847. client.on('ready', function() {
  1848. client.exec('foo', function(err, stream) {
  1849. var sawClose = false;
  1850. assert(!err, makeMsg('Unexpected error'));
  1851. client._sshstream.on('CHANNEL_CLOSE:' + stream.incoming.id, onClose);
  1852. function onClose() {
  1853. // This handler gets called *after* the internal handler, so we
  1854. // should have seen `stream`'s `close` event already if the bug
  1855. // exists
  1856. assert(!sawClose, makeMsg('Premature close event'));
  1857. client.end();
  1858. }
  1859. stream.on('close', function() {
  1860. sawClose = true;
  1861. });
  1862. });
  1863. });
  1864. },
  1865. what: 'Channel emits close prematurely'
  1866. },
  1867. { run: function() {
  1868. var client;
  1869. var server;
  1870. var r;
  1871. r = setup(
  1872. this,
  1873. { username: USER },
  1874. { hostKeys: [HOST_KEY_RSA], ident: 'OpenSSH_5.3' }
  1875. );
  1876. client = r.client;
  1877. server = r.server;
  1878. server.on('connection', function(conn) {
  1879. conn.on('authentication', function(ctx) {
  1880. ctx.accept();
  1881. });
  1882. conn.once('request', function(accept, reject, name, info) {
  1883. assert(name === 'tcpip-forward',
  1884. makeMsg('Unexpected request: ' + name));
  1885. accept(1337);
  1886. conn.forwardOut('good', 0, 'remote', 12345, function(err, ch) {
  1887. assert(!err, makeMsg('Unexpected error: ' + err));
  1888. client.end();
  1889. });
  1890. });
  1891. });
  1892. client.on('ready', function() {
  1893. // request forwarding
  1894. client.forwardIn('good', 0, function(err, port) {
  1895. assert(!err, makeMsg('Unexpected error: ' + err));
  1896. assert(port === 1337, makeMsg('Bad bound port: ' + port));
  1897. });
  1898. });
  1899. client.on('tcp connection', function(details, accept, reject) {
  1900. assert(details.destIP === 'good',
  1901. makeMsg('Bad incoming destIP: ' + details.destIP));
  1902. assert(details.destPort === 1337,
  1903. makeMsg('Bad incoming destPort: ' + details.destPort));
  1904. assert(details.srcIP === 'remote',
  1905. makeMsg('Bad incoming srcIP: ' + details.srcIP));
  1906. assert(details.srcPort === 12345,
  1907. makeMsg('Bad incoming srcPort: ' + details.srcPort));
  1908. accept();
  1909. });
  1910. },
  1911. what: 'OpenSSH 5.x workaround for binding on port 0'
  1912. },
  1913. { run: function() {
  1914. var client;
  1915. var server;
  1916. var r;
  1917. var srvError;
  1918. var cliError;
  1919. r = setup(
  1920. this,
  1921. { username: USER,
  1922. algorithms: {
  1923. cipher: [ 'aes128-cbc' ]
  1924. }
  1925. },
  1926. { hostKeys: [HOST_KEY_RSA],
  1927. algorithms: {
  1928. cipher: [ 'aes128-ctr' ]
  1929. }
  1930. }
  1931. );
  1932. client = r.client;
  1933. server = r.server;
  1934. // Remove default client error handler added by `setup()` since we are
  1935. // expecting an error in this case
  1936. client.removeAllListeners('error');
  1937. function onError(err) {
  1938. if (this === client) {
  1939. assert(!cliError, makeMsg('Unexpected multiple client errors'));
  1940. cliError = err;
  1941. } else {
  1942. assert(!srvError, makeMsg('Unexpected multiple server errors'));
  1943. srvError = err;
  1944. }
  1945. assert.strictEqual(err.level, 'handshake');
  1946. assert(/handshake failed/i.test(err.message),
  1947. makeMsg('Wrong error message'));
  1948. }
  1949. server.on('connection', function(conn) {
  1950. // Remove default server connection error handler added by `setup()`
  1951. // since we are expecting an error in this case
  1952. conn.removeAllListeners('error');
  1953. function onGoodHandshake() {
  1954. assert(false, makeMsg('Handshake should have failed'));
  1955. }
  1956. conn.on('authentication', onGoodHandshake);
  1957. conn.on('ready', onGoodHandshake);
  1958. conn.on('error', onError);
  1959. });
  1960. client.on('ready', function() {
  1961. assert(false, makeMsg('Handshake should have failed'));
  1962. });
  1963. client.on('error', onError);
  1964. client.on('close', function() {
  1965. assert(cliError, makeMsg('Expected client error'));
  1966. assert(srvError, makeMsg('Expected server error'));
  1967. });
  1968. },
  1969. what: 'Handshake errors are emitted'
  1970. },
  1971. { run: function() {
  1972. var client;
  1973. var server;
  1974. var r;
  1975. var cliError;
  1976. r = setup(
  1977. this,
  1978. { username: USER, privateKey: KEY_RSA_BAD },
  1979. { hostKeys: [HOST_KEY_RSA] }
  1980. );
  1981. client = r.client;
  1982. server = r.server;
  1983. // Remove default client error handler added by `setup()` since we are
  1984. // expecting an error in this case
  1985. client.removeAllListeners('error');
  1986. server.on('connection', function(conn) {
  1987. conn.on('authentication', function(ctx) {
  1988. assert(ctx.method === 'publickey' || ctx.method === 'none',
  1989. makeMsg('Unexpected auth method: ' + ctx.method));
  1990. assert(!ctx.signature, makeMsg('Unexpected signature'));
  1991. if (ctx.method === 'none')
  1992. return ctx.reject();
  1993. ctx.accept();
  1994. });
  1995. conn.on('ready', function() {
  1996. assert(false, makeMsg('Authentication should have failed'));
  1997. });
  1998. });
  1999. client.on('ready', function() {
  2000. assert(false, makeMsg('Authentication should have failed'));
  2001. });
  2002. client.on('error', function(err) {
  2003. if (cliError) {
  2004. assert(/all configured/i.test(err.message),
  2005. makeMsg('Wrong error message'));
  2006. } else {
  2007. cliError = err;
  2008. assert(/signing/i.test(err.message), makeMsg('Wrong error message'));
  2009. }
  2010. });
  2011. client.on('close', function() {
  2012. assert(cliError, makeMsg('Expected client error'));
  2013. });
  2014. },
  2015. what: 'Client signing errors are caught and emitted'
  2016. },
  2017. { run: function() {
  2018. var client;
  2019. var server;
  2020. var r;
  2021. var srvError;
  2022. var cliError;
  2023. r = setup(
  2024. this,
  2025. { username: USER, password: 'foo' },
  2026. { hostKeys: [KEY_RSA_BAD] }
  2027. );
  2028. client = r.client;
  2029. server = r.server;
  2030. // Remove default client error handler added by `setup()` since we are
  2031. // expecting an error in this case
  2032. client.removeAllListeners('error');
  2033. server.on('connection', function(conn) {
  2034. // Remove default server connection error handler added by `setup()`
  2035. // since we are expecting an error in this case
  2036. conn.removeAllListeners('error');
  2037. conn.once('error', function(err) {
  2038. assert(/signing/i.test(err.message), makeMsg('Wrong error message'));
  2039. srvError = err;
  2040. });
  2041. conn.on('authentication', function(ctx) {
  2042. assert(false, makeMsg('Handshake should have failed'));
  2043. });
  2044. conn.on('ready', function() {
  2045. assert(false, makeMsg('Authentication should have failed'));
  2046. });
  2047. });
  2048. client.on('ready', function() {
  2049. assert(false, makeMsg('Handshake should have failed'));
  2050. });
  2051. client.on('error', function(err) {
  2052. assert(!cliError, makeMsg('Unexpected multiple client errors'));
  2053. assert(/KEY_EXCHANGE_FAILED/.test(err.message),
  2054. makeMsg('Wrong error message'));
  2055. cliError = err;
  2056. });
  2057. client.on('close', function() {
  2058. assert(srvError, makeMsg('Expected server error'));
  2059. assert(cliError, makeMsg('Expected client error'));
  2060. });
  2061. },
  2062. what: 'Server signing errors are caught and emitted'
  2063. },
  2064. { run: function() {
  2065. var client;
  2066. var server;
  2067. var r;
  2068. var sawReady = false;
  2069. r = setup(
  2070. this,
  2071. { username: '', password: 'foo' },
  2072. { hostKeys: [HOST_KEY_RSA] }
  2073. );
  2074. client = r.client;
  2075. server = r.server;
  2076. server.on('connection', function(conn) {
  2077. conn.on('authentication', function(ctx) {
  2078. assert.strictEqual(ctx.username, '',
  2079. makeMsg('Expected empty username'));
  2080. ctx.accept();
  2081. }).on('ready', function() {
  2082. conn.end();
  2083. });
  2084. });
  2085. client.on('ready', function() {
  2086. sawReady = true;
  2087. }).on('close', function() {
  2088. assert.strictEqual(sawReady, true, makeMsg('Expected ready event'));
  2089. });
  2090. },
  2091. what: 'Empty username string works'
  2092. },
  2093. { run: function() {
  2094. var client;
  2095. var server;
  2096. var r;
  2097. var socketPath = '/foo';
  2098. var events = [];
  2099. var expected = [
  2100. ['client', 'openssh_forwardInStreamLocal'],
  2101. ['server',
  2102. 'streamlocal-forward@openssh.com',
  2103. { socketPath: socketPath }],
  2104. ['client', 'forward callback'],
  2105. ['client', 'unix connection', { socketPath: socketPath }],
  2106. ['client', 'socket data', '1'],
  2107. ['server', 'socket data', '2'],
  2108. ['client', 'socket end'],
  2109. ['server',
  2110. 'cancel-streamlocal-forward@openssh.com',
  2111. { socketPath: socketPath }],
  2112. ['client', 'cancel callback']
  2113. ];
  2114. r = setup(
  2115. this,
  2116. { username: USER },
  2117. { hostKeys: [HOST_KEY_RSA], ident: 'OpenSSH_7.1' }
  2118. );
  2119. client = r.client;
  2120. server = r.server;
  2121. server.on('connection', function(conn) {
  2122. conn.on('authentication', function(ctx) {
  2123. ctx.accept();
  2124. });
  2125. conn.on('request', function(accept, reject, name, info) {
  2126. events.push(['server', name, info]);
  2127. if (name === 'streamlocal-forward@openssh.com') {
  2128. accept();
  2129. conn.openssh_forwardOutStreamLocal(socketPath, function(err, ch) {
  2130. assert(!err, makeMsg('Unexpected error: ' + err));
  2131. ch.write('1');
  2132. ch.on('data', function(data) {
  2133. events.push(['server', 'socket data', data.toString()]);
  2134. ch.close();
  2135. });
  2136. });
  2137. } else if (name === 'cancel-streamlocal-forward@openssh.com') {
  2138. accept();
  2139. } else {
  2140. reject();
  2141. }
  2142. });
  2143. });
  2144. client.on('ready', function() {
  2145. // request forwarding
  2146. events.push(['client', 'openssh_forwardInStreamLocal']);
  2147. client.openssh_forwardInStreamLocal(socketPath, function(err) {
  2148. assert(!err, makeMsg('Unexpected error: ' + err));
  2149. events.push(['client', 'forward callback']);
  2150. });
  2151. client.on('unix connection', function(info, accept, reject) {
  2152. events.push(['client', 'unix connection', info]);
  2153. var stream = accept();
  2154. stream.on('data', function(data) {
  2155. events.push(['client', 'socket data', data.toString()]);
  2156. stream.write('2');
  2157. }).on('end', function() {
  2158. events.push(['client', 'socket end']);
  2159. client.openssh_unforwardInStreamLocal(socketPath, function(err) {
  2160. assert(!err, makeMsg('Unexpected error: ' + err));
  2161. events.push(['client', 'cancel callback']);
  2162. client.end();
  2163. });
  2164. });
  2165. });
  2166. });
  2167. client.on('end', function() {
  2168. var msg = 'Events mismatch\nActual:\n' + inspect(events)
  2169. + '\nExpected:\n' + inspect(expected);
  2170. assert.deepEqual(events, expected, makeMsg(msg));
  2171. });
  2172. },
  2173. what: 'OpenSSH forwarded UNIX socket connection'
  2174. },
  2175. { run: function() {
  2176. var client;
  2177. var server;
  2178. var r;
  2179. var calledBack = 0;
  2180. r = setup(
  2181. this,
  2182. { username: USER,
  2183. password: PASSWORD,
  2184. algorithms: {
  2185. cipher: [ 'aes128-gcm@openssh.com' ],
  2186. },
  2187. },
  2188. { hostKeys: [HOST_KEY_RSA],
  2189. algorithms: {
  2190. cipher: [ 'aes128-gcm@openssh.com' ],
  2191. },
  2192. }
  2193. );
  2194. client = r.client;
  2195. server = r.server;
  2196. server.on('connection', function(conn) {
  2197. conn.on('authentication', function(ctx) {
  2198. ctx.accept();
  2199. }).on('ready', function() {
  2200. var reqs = [];
  2201. conn.on('session', function(accept, reject) {
  2202. if (reqs.length === 0) {
  2203. conn.rekey(function(err) {
  2204. assert(!err, makeMsg('Unexpected rekey error: ' + err));
  2205. reqs.forEach(function(accept) {
  2206. var session = accept();
  2207. session.once('exec', function(accept, reject, info) {
  2208. var stream = accept();
  2209. stream.exit(0);
  2210. stream.end();
  2211. });
  2212. });
  2213. });
  2214. }
  2215. reqs.push(accept);
  2216. });
  2217. });
  2218. });
  2219. client.on('ready', function() {
  2220. function callback(err, stream) {
  2221. assert(!err, makeMsg('Unexpected error: ' + err));
  2222. stream.resume();
  2223. if (++calledBack === 3)
  2224. client.end();
  2225. }
  2226. client.exec('foo', callback);
  2227. client.exec('bar', callback);
  2228. client.exec('baz', callback);
  2229. }).on('end', function() {
  2230. assert(calledBack === 3,
  2231. makeMsg('Only '
  2232. + calledBack
  2233. + '/3 callbacks called'));
  2234. });
  2235. },
  2236. what: 'Rekeying with AES-GCM'
  2237. },
  2238. ];
  2239. function setup(self, clientcfg, servercfg, timeout) {
  2240. self.state = {
  2241. clientReady: false,
  2242. serverReady: false,
  2243. clientClose: false,
  2244. serverClose: false
  2245. };
  2246. if (DEBUG) {
  2247. console.log('========================================================\n'
  2248. + '[TEST] '
  2249. + self.what
  2250. + '\n========================================================');
  2251. clientcfg.debug = function() {
  2252. var args = new Array(arguments.length + 1);
  2253. args[0] = '[CLIENT]';
  2254. for (var i = 0; i < arguments.length; ++i)
  2255. args[i + 1] = arguments[i];
  2256. console.log.apply(null, args);
  2257. };
  2258. servercfg.debug = function() {
  2259. var args = new Array(arguments.length + 1);
  2260. args[0] = '[SERVER]';
  2261. for (var i = 0; i < arguments.length; ++i)
  2262. args[i + 1] = arguments[i];
  2263. console.log.apply(null, args);
  2264. };
  2265. }
  2266. var client = new Client();
  2267. var server = new Server(servercfg);
  2268. if (timeout === undefined)
  2269. timeout = DEFAULT_TEST_TIMEOUT;
  2270. var timer;
  2271. server.on('error', onError)
  2272. .on('connection', function(conn) {
  2273. conn.on('error', onError)
  2274. .on('ready', onReady);
  2275. server.close();
  2276. })
  2277. .on('close', onClose);
  2278. client.on('error', onError)
  2279. .on('ready', onReady)
  2280. .on('close', onClose);
  2281. function onError(err) {
  2282. var which = (this === client ? 'client' : 'server');
  2283. assert(false, makeMsg('Unexpected ' + which + ' error: ' + err));
  2284. }
  2285. function onReady() {
  2286. if (this === client) {
  2287. assert(!self.state.clientReady,
  2288. makeMsg('Received multiple ready events for client'));
  2289. self.state.clientReady = true;
  2290. } else {
  2291. assert(!self.state.serverReady,
  2292. makeMsg('Received multiple ready events for server'));
  2293. self.state.serverReady = true;
  2294. }
  2295. if (self.state.clientReady && self.state.serverReady)
  2296. self.onReady && self.onReady();
  2297. }
  2298. function onClose() {
  2299. if (this === client) {
  2300. assert(!self.state.clientClose,
  2301. makeMsg('Received multiple close events for client'));
  2302. self.state.clientClose = true;
  2303. } else {
  2304. assert(!self.state.serverClose,
  2305. makeMsg('Received multiple close events for server'));
  2306. self.state.serverClose = true;
  2307. }
  2308. if (self.state.clientClose && self.state.serverClose) {
  2309. clearTimeout(timer);
  2310. next();
  2311. }
  2312. }
  2313. process.nextTick(function() {
  2314. server.listen(0, 'localhost', function() {
  2315. if (timeout >= 0) {
  2316. timer = setTimeout(function() {
  2317. assert(false, makeMsg('Test timed out'));
  2318. }, timeout);
  2319. }
  2320. if (clientcfg.sock)
  2321. clientcfg.sock.connect(server.address().port, 'localhost');
  2322. else {
  2323. clientcfg.host = 'localhost';
  2324. clientcfg.port = server.address().port;
  2325. }
  2326. client.connect(clientcfg);
  2327. });
  2328. });
  2329. return { client: client, server: server };
  2330. }
  2331. function next() {
  2332. if (Array.isArray(process._events.exit))
  2333. process._events.exit = process._events.exit[1];
  2334. if (++t === tests.length)
  2335. return;
  2336. var v = tests[t];
  2337. v.run.call(v);
  2338. }
  2339. function makeMsg(what, msg) {
  2340. if (msg === undefined)
  2341. msg = what;
  2342. if (tests[t])
  2343. what = tests[t].what;
  2344. else
  2345. what = '<Unknown>';
  2346. return '[' + group + what + ']: ' + msg;
  2347. }
  2348. process.once('uncaughtException', function(err) {
  2349. if (t > -1 && !/(?:^|\n)AssertionError: /i.test(''+err))
  2350. console.log(makeMsg('Unexpected Exception:'));
  2351. throw err;
  2352. });
  2353. process.once('exit', function() {
  2354. assert(t === tests.length,
  2355. makeMsg('_exit',
  2356. 'Only finished ' + t + '/' + tests.length + ' tests'));
  2357. });
  2358. next();