utils.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. 'use strict';
  2. const Ber = require('asn1').Ber;
  3. let DISCONNECT_REASON;
  4. const FastBuffer = Buffer[Symbol.species];
  5. const TypedArrayFill = Object.getPrototypeOf(Uint8Array.prototype).fill;
  6. function readUInt32BE(buf, offset) {
  7. return (buf[offset++] * 16777216)
  8. + (buf[offset++] * 65536)
  9. + (buf[offset++] * 256)
  10. + buf[offset];
  11. }
  12. function bufferCopy(src, dest, srcStart, srcEnd, destStart) {
  13. if (!destStart)
  14. destStart = 0;
  15. if (srcEnd > src.length)
  16. srcEnd = src.length;
  17. let nb = srcEnd - srcStart;
  18. const destLeft = (dest.length - destStart);
  19. if (nb > destLeft)
  20. nb = destLeft;
  21. dest.set(new Uint8Array(src.buffer, src.byteOffset + srcStart, nb),
  22. destStart);
  23. return nb;
  24. }
  25. function bufferSlice(buf, start, end) {
  26. if (end === undefined)
  27. end = buf.length;
  28. return new FastBuffer(buf.buffer, buf.byteOffset + start, end - start);
  29. }
  30. function makeBufferParser() {
  31. let pos = 0;
  32. let buffer;
  33. const self = {
  34. init: (buf, start) => {
  35. buffer = buf;
  36. pos = (typeof start === 'number' ? start : 0);
  37. },
  38. pos: () => pos,
  39. length: () => (buffer ? buffer.length : 0),
  40. avail: () => (buffer && pos < buffer.length ? buffer.length - pos : 0),
  41. clear: () => {
  42. buffer = undefined;
  43. },
  44. readUInt32BE: () => {
  45. if (!buffer || pos + 3 >= buffer.length)
  46. return;
  47. return (buffer[pos++] * 16777216)
  48. + (buffer[pos++] * 65536)
  49. + (buffer[pos++] * 256)
  50. + buffer[pos++];
  51. },
  52. readUInt64BE: (behavior) => {
  53. if (!buffer || pos + 7 >= buffer.length)
  54. return;
  55. switch (behavior) {
  56. case 'always':
  57. return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`);
  58. case 'maybe':
  59. if (buffer[pos] > 0x1F)
  60. return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`);
  61. // FALLTHROUGH
  62. default:
  63. return (buffer[pos++] * 72057594037927940)
  64. + (buffer[pos++] * 281474976710656)
  65. + (buffer[pos++] * 1099511627776)
  66. + (buffer[pos++] * 4294967296)
  67. + (buffer[pos++] * 16777216)
  68. + (buffer[pos++] * 65536)
  69. + (buffer[pos++] * 256)
  70. + buffer[pos++];
  71. }
  72. },
  73. skip: (n) => {
  74. if (buffer && n > 0)
  75. pos += n;
  76. },
  77. skipString: () => {
  78. const len = self.readUInt32BE();
  79. if (len === undefined)
  80. return;
  81. pos += len;
  82. return (pos <= buffer.length ? len : undefined);
  83. },
  84. readByte: () => {
  85. if (buffer && pos < buffer.length)
  86. return buffer[pos++];
  87. },
  88. readBool: () => {
  89. if (buffer && pos < buffer.length)
  90. return !!buffer[pos++];
  91. },
  92. readList: () => {
  93. const list = self.readString(true);
  94. if (list === undefined)
  95. return;
  96. return (list ? list.split(',') : []);
  97. },
  98. readString: (dest, maxLen) => {
  99. if (typeof dest === 'number') {
  100. maxLen = dest;
  101. dest = undefined;
  102. }
  103. const len = self.readUInt32BE();
  104. if (len === undefined)
  105. return;
  106. if ((buffer.length - pos) < len
  107. || (typeof maxLen === 'number' && len > maxLen)) {
  108. return;
  109. }
  110. if (dest) {
  111. if (Buffer.isBuffer(dest))
  112. return bufferCopy(buffer, dest, pos, pos += len);
  113. return buffer.utf8Slice(pos, pos += len);
  114. }
  115. return bufferSlice(buffer, pos, pos += len);
  116. },
  117. readRaw: (len) => {
  118. if (!buffer)
  119. return;
  120. if (typeof len !== 'number')
  121. return bufferSlice(buffer, pos, pos += (buffer.length - pos));
  122. if ((buffer.length - pos) >= len)
  123. return bufferSlice(buffer, pos, pos += len);
  124. },
  125. };
  126. return self;
  127. }
  128. function makeError(msg, level, fatal) {
  129. const err = new Error(msg);
  130. if (typeof level === 'boolean') {
  131. fatal = level;
  132. err.level = 'protocol';
  133. } else {
  134. err.level = level || 'protocol';
  135. }
  136. err.fatal = !!fatal;
  137. return err;
  138. }
  139. function writeUInt32BE(buf, value, offset) {
  140. buf[offset++] = (value >>> 24);
  141. buf[offset++] = (value >>> 16);
  142. buf[offset++] = (value >>> 8);
  143. buf[offset++] = value;
  144. return offset;
  145. }
  146. const utilBufferParser = makeBufferParser();
  147. module.exports = {
  148. bufferCopy,
  149. bufferSlice,
  150. FastBuffer,
  151. bufferFill: (buf, value, start, end) => {
  152. return TypedArrayFill.call(buf, value, start, end);
  153. },
  154. makeError,
  155. doFatalError: (protocol, msg, level, reason) => {
  156. let err;
  157. if (DISCONNECT_REASON === undefined)
  158. ({ DISCONNECT_REASON } = require('./utils.js'));
  159. if (msg instanceof Error) {
  160. // doFatalError(protocol, err[, reason])
  161. err = msg;
  162. if (typeof level !== 'number')
  163. reason = DISCONNECT_REASON.PROTOCOL_ERROR;
  164. else
  165. reason = level;
  166. } else {
  167. // doFatalError(protocol, msg[, level[, reason]])
  168. err = makeError(msg, level, true);
  169. }
  170. if (typeof reason !== 'number')
  171. reason = DISCONNECT_REASON.PROTOCOL_ERROR;
  172. protocol.disconnect(reason);
  173. protocol._destruct();
  174. protocol._onError(err);
  175. return Infinity;
  176. },
  177. readUInt32BE,
  178. writeUInt32BE,
  179. writeUInt32LE: (buf, value, offset) => {
  180. buf[offset++] = value;
  181. buf[offset++] = (value >>> 8);
  182. buf[offset++] = (value >>> 16);
  183. buf[offset++] = (value >>> 24);
  184. return offset;
  185. },
  186. makeBufferParser,
  187. bufferParser: makeBufferParser(),
  188. readString: (buffer, start, dest, maxLen) => {
  189. if (typeof dest === 'number') {
  190. maxLen = dest;
  191. dest = undefined;
  192. }
  193. if (start === undefined)
  194. start = 0;
  195. const left = (buffer.length - start);
  196. if (start < 0 || start >= buffer.length || left < 4)
  197. return;
  198. const len = readUInt32BE(buffer, start);
  199. if (left < (4 + len) || (typeof maxLen === 'number' && len > maxLen))
  200. return;
  201. start += 4;
  202. const end = start + len;
  203. buffer._pos = end;
  204. if (dest) {
  205. if (Buffer.isBuffer(dest))
  206. return bufferCopy(buffer, dest, start, end);
  207. return buffer.utf8Slice(start, end);
  208. }
  209. return bufferSlice(buffer, start, end);
  210. },
  211. sigSSHToASN1: (sig, type) => {
  212. switch (type) {
  213. case 'ssh-dss': {
  214. if (sig.length > 40)
  215. return sig;
  216. // Change bare signature r and s values to ASN.1 BER values for OpenSSL
  217. const asnWriter = new Ber.Writer();
  218. asnWriter.startSequence();
  219. let r = sig.slice(0, 20);
  220. let s = sig.slice(20);
  221. if (r[0] & 0x80) {
  222. const rNew = Buffer.allocUnsafe(21);
  223. rNew[0] = 0x00;
  224. r.copy(rNew, 1);
  225. r = rNew;
  226. } else if (r[0] === 0x00 && !(r[1] & 0x80)) {
  227. r = r.slice(1);
  228. }
  229. if (s[0] & 0x80) {
  230. const sNew = Buffer.allocUnsafe(21);
  231. sNew[0] = 0x00;
  232. s.copy(sNew, 1);
  233. s = sNew;
  234. } else if (s[0] === 0x00 && !(s[1] & 0x80)) {
  235. s = s.slice(1);
  236. }
  237. asnWriter.writeBuffer(r, Ber.Integer);
  238. asnWriter.writeBuffer(s, Ber.Integer);
  239. asnWriter.endSequence();
  240. return asnWriter.buffer;
  241. }
  242. case 'ecdsa-sha2-nistp256':
  243. case 'ecdsa-sha2-nistp384':
  244. case 'ecdsa-sha2-nistp521': {
  245. utilBufferParser.init(sig, 0);
  246. const r = utilBufferParser.readString();
  247. const s = utilBufferParser.readString();
  248. utilBufferParser.clear();
  249. if (r === undefined || s === undefined)
  250. return;
  251. const asnWriter = new Ber.Writer();
  252. asnWriter.startSequence();
  253. asnWriter.writeBuffer(r, Ber.Integer);
  254. asnWriter.writeBuffer(s, Ber.Integer);
  255. asnWriter.endSequence();
  256. return asnWriter.buffer;
  257. }
  258. default:
  259. return sig;
  260. }
  261. },
  262. convertSignature: (signature, keyType) => {
  263. switch (keyType) {
  264. case 'ssh-dss': {
  265. if (signature.length <= 40)
  266. return signature;
  267. // This is a quick and dirty way to get from BER encoded r and s that
  268. // OpenSSL gives us, to just the bare values back to back (40 bytes
  269. // total) like OpenSSH (and possibly others) are expecting
  270. const asnReader = new Ber.Reader(signature);
  271. asnReader.readSequence();
  272. let r = asnReader.readString(Ber.Integer, true);
  273. let s = asnReader.readString(Ber.Integer, true);
  274. let rOffset = 0;
  275. let sOffset = 0;
  276. if (r.length < 20) {
  277. const rNew = Buffer.allocUnsafe(20);
  278. rNew.set(r, 1);
  279. r = rNew;
  280. r[0] = 0;
  281. }
  282. if (s.length < 20) {
  283. const sNew = Buffer.allocUnsafe(20);
  284. sNew.set(s, 1);
  285. s = sNew;
  286. s[0] = 0;
  287. }
  288. if (r.length > 20 && r[0] === 0)
  289. rOffset = 1;
  290. if (s.length > 20 && s[0] === 0)
  291. sOffset = 1;
  292. const newSig =
  293. Buffer.allocUnsafe((r.length - rOffset) + (s.length - sOffset));
  294. bufferCopy(r, newSig, rOffset, r.length, 0);
  295. bufferCopy(s, newSig, sOffset, s.length, r.length - rOffset);
  296. return newSig;
  297. }
  298. case 'ecdsa-sha2-nistp256':
  299. case 'ecdsa-sha2-nistp384':
  300. case 'ecdsa-sha2-nistp521': {
  301. if (signature[0] === 0)
  302. return signature;
  303. // Convert SSH signature parameters to ASN.1 BER values for OpenSSL
  304. const asnReader = new Ber.Reader(signature);
  305. asnReader.readSequence();
  306. const r = asnReader.readString(Ber.Integer, true);
  307. const s = asnReader.readString(Ber.Integer, true);
  308. if (r === null || s === null)
  309. return;
  310. const newSig = Buffer.allocUnsafe(4 + r.length + 4 + s.length);
  311. writeUInt32BE(newSig, r.length, 0);
  312. newSig.set(r, 4);
  313. writeUInt32BE(newSig, s.length, 4 + r.length);
  314. newSig.set(s, 4 + 4 + r.length);
  315. return newSig;
  316. }
  317. }
  318. return signature;
  319. },
  320. sendPacket: (proto, packet, bypass) => {
  321. if (!bypass && proto._kexinit !== undefined) {
  322. // We're currently in the middle of a handshake
  323. if (proto._queue === undefined)
  324. proto._queue = [];
  325. proto._queue.push(packet);
  326. proto._debug && proto._debug('Outbound: ... packet queued');
  327. return false;
  328. }
  329. proto._cipher.encrypt(packet);
  330. return true;
  331. },
  332. };