123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- 'use strict';
- const Ber = require('asn1').Ber;
- let DISCONNECT_REASON;
- const FastBuffer = Buffer[Symbol.species];
- const TypedArrayFill = Object.getPrototypeOf(Uint8Array.prototype).fill;
- function readUInt32BE(buf, offset) {
- return (buf[offset++] * 16777216)
- + (buf[offset++] * 65536)
- + (buf[offset++] * 256)
- + buf[offset];
- }
- function bufferCopy(src, dest, srcStart, srcEnd, destStart) {
- if (!destStart)
- destStart = 0;
- if (srcEnd > src.length)
- srcEnd = src.length;
- let nb = srcEnd - srcStart;
- const destLeft = (dest.length - destStart);
- if (nb > destLeft)
- nb = destLeft;
- dest.set(new Uint8Array(src.buffer, src.byteOffset + srcStart, nb),
- destStart);
- return nb;
- }
- function bufferSlice(buf, start, end) {
- if (end === undefined)
- end = buf.length;
- return new FastBuffer(buf.buffer, buf.byteOffset + start, end - start);
- }
- function makeBufferParser() {
- let pos = 0;
- let buffer;
- const self = {
- init: (buf, start) => {
- buffer = buf;
- pos = (typeof start === 'number' ? start : 0);
- },
- pos: () => pos,
- length: () => (buffer ? buffer.length : 0),
- avail: () => (buffer && pos < buffer.length ? buffer.length - pos : 0),
- clear: () => {
- buffer = undefined;
- },
- readUInt32BE: () => {
- if (!buffer || pos + 3 >= buffer.length)
- return;
- return (buffer[pos++] * 16777216)
- + (buffer[pos++] * 65536)
- + (buffer[pos++] * 256)
- + buffer[pos++];
- },
- readUInt64BE: (behavior) => {
- if (!buffer || pos + 7 >= buffer.length)
- return;
- switch (behavior) {
- case 'always':
- return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`);
- case 'maybe':
- if (buffer[pos] > 0x1F)
- return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`);
- // FALLTHROUGH
- default:
- return (buffer[pos++] * 72057594037927940)
- + (buffer[pos++] * 281474976710656)
- + (buffer[pos++] * 1099511627776)
- + (buffer[pos++] * 4294967296)
- + (buffer[pos++] * 16777216)
- + (buffer[pos++] * 65536)
- + (buffer[pos++] * 256)
- + buffer[pos++];
- }
- },
- skip: (n) => {
- if (buffer && n > 0)
- pos += n;
- },
- skipString: () => {
- const len = self.readUInt32BE();
- if (len === undefined)
- return;
- pos += len;
- return (pos <= buffer.length ? len : undefined);
- },
- readByte: () => {
- if (buffer && pos < buffer.length)
- return buffer[pos++];
- },
- readBool: () => {
- if (buffer && pos < buffer.length)
- return !!buffer[pos++];
- },
- readList: () => {
- const list = self.readString(true);
- if (list === undefined)
- return;
- return (list ? list.split(',') : []);
- },
- readString: (dest, maxLen) => {
- if (typeof dest === 'number') {
- maxLen = dest;
- dest = undefined;
- }
- const len = self.readUInt32BE();
- if (len === undefined)
- return;
- if ((buffer.length - pos) < len
- || (typeof maxLen === 'number' && len > maxLen)) {
- return;
- }
- if (dest) {
- if (Buffer.isBuffer(dest))
- return bufferCopy(buffer, dest, pos, pos += len);
- return buffer.utf8Slice(pos, pos += len);
- }
- return bufferSlice(buffer, pos, pos += len);
- },
- readRaw: (len) => {
- if (!buffer)
- return;
- if (typeof len !== 'number')
- return bufferSlice(buffer, pos, pos += (buffer.length - pos));
- if ((buffer.length - pos) >= len)
- return bufferSlice(buffer, pos, pos += len);
- },
- };
- return self;
- }
- function makeError(msg, level, fatal) {
- const err = new Error(msg);
- if (typeof level === 'boolean') {
- fatal = level;
- err.level = 'protocol';
- } else {
- err.level = level || 'protocol';
- }
- err.fatal = !!fatal;
- return err;
- }
- function writeUInt32BE(buf, value, offset) {
- buf[offset++] = (value >>> 24);
- buf[offset++] = (value >>> 16);
- buf[offset++] = (value >>> 8);
- buf[offset++] = value;
- return offset;
- }
- const utilBufferParser = makeBufferParser();
- module.exports = {
- bufferCopy,
- bufferSlice,
- FastBuffer,
- bufferFill: (buf, value, start, end) => {
- return TypedArrayFill.call(buf, value, start, end);
- },
- makeError,
- doFatalError: (protocol, msg, level, reason) => {
- let err;
- if (DISCONNECT_REASON === undefined)
- ({ DISCONNECT_REASON } = require('./utils.js'));
- if (msg instanceof Error) {
- // doFatalError(protocol, err[, reason])
- err = msg;
- if (typeof level !== 'number')
- reason = DISCONNECT_REASON.PROTOCOL_ERROR;
- else
- reason = level;
- } else {
- // doFatalError(protocol, msg[, level[, reason]])
- err = makeError(msg, level, true);
- }
- if (typeof reason !== 'number')
- reason = DISCONNECT_REASON.PROTOCOL_ERROR;
- protocol.disconnect(reason);
- protocol._destruct();
- protocol._onError(err);
- return Infinity;
- },
- readUInt32BE,
- writeUInt32BE,
- writeUInt32LE: (buf, value, offset) => {
- buf[offset++] = value;
- buf[offset++] = (value >>> 8);
- buf[offset++] = (value >>> 16);
- buf[offset++] = (value >>> 24);
- return offset;
- },
- makeBufferParser,
- bufferParser: makeBufferParser(),
- readString: (buffer, start, dest, maxLen) => {
- if (typeof dest === 'number') {
- maxLen = dest;
- dest = undefined;
- }
- if (start === undefined)
- start = 0;
- const left = (buffer.length - start);
- if (start < 0 || start >= buffer.length || left < 4)
- return;
- const len = readUInt32BE(buffer, start);
- if (left < (4 + len) || (typeof maxLen === 'number' && len > maxLen))
- return;
- start += 4;
- const end = start + len;
- buffer._pos = end;
- if (dest) {
- if (Buffer.isBuffer(dest))
- return bufferCopy(buffer, dest, start, end);
- return buffer.utf8Slice(start, end);
- }
- return bufferSlice(buffer, start, end);
- },
- sigSSHToASN1: (sig, type) => {
- switch (type) {
- case 'ssh-dss': {
- if (sig.length > 40)
- return sig;
- // Change bare signature r and s values to ASN.1 BER values for OpenSSL
- const asnWriter = new Ber.Writer();
- asnWriter.startSequence();
- let r = sig.slice(0, 20);
- let s = sig.slice(20);
- if (r[0] & 0x80) {
- const rNew = Buffer.allocUnsafe(21);
- rNew[0] = 0x00;
- r.copy(rNew, 1);
- r = rNew;
- } else if (r[0] === 0x00 && !(r[1] & 0x80)) {
- r = r.slice(1);
- }
- if (s[0] & 0x80) {
- const sNew = Buffer.allocUnsafe(21);
- sNew[0] = 0x00;
- s.copy(sNew, 1);
- s = sNew;
- } else if (s[0] === 0x00 && !(s[1] & 0x80)) {
- s = s.slice(1);
- }
- asnWriter.writeBuffer(r, Ber.Integer);
- asnWriter.writeBuffer(s, Ber.Integer);
- asnWriter.endSequence();
- return asnWriter.buffer;
- }
- case 'ecdsa-sha2-nistp256':
- case 'ecdsa-sha2-nistp384':
- case 'ecdsa-sha2-nistp521': {
- utilBufferParser.init(sig, 0);
- const r = utilBufferParser.readString();
- const s = utilBufferParser.readString();
- utilBufferParser.clear();
- if (r === undefined || s === undefined)
- return;
- const asnWriter = new Ber.Writer();
- asnWriter.startSequence();
- asnWriter.writeBuffer(r, Ber.Integer);
- asnWriter.writeBuffer(s, Ber.Integer);
- asnWriter.endSequence();
- return asnWriter.buffer;
- }
- default:
- return sig;
- }
- },
- convertSignature: (signature, keyType) => {
- switch (keyType) {
- case 'ssh-dss': {
- if (signature.length <= 40)
- return signature;
- // This is a quick and dirty way to get from BER encoded r and s that
- // OpenSSL gives us, to just the bare values back to back (40 bytes
- // total) like OpenSSH (and possibly others) are expecting
- const asnReader = new Ber.Reader(signature);
- asnReader.readSequence();
- let r = asnReader.readString(Ber.Integer, true);
- let s = asnReader.readString(Ber.Integer, true);
- let rOffset = 0;
- let sOffset = 0;
- if (r.length < 20) {
- const rNew = Buffer.allocUnsafe(20);
- rNew.set(r, 1);
- r = rNew;
- r[0] = 0;
- }
- if (s.length < 20) {
- const sNew = Buffer.allocUnsafe(20);
- sNew.set(s, 1);
- s = sNew;
- s[0] = 0;
- }
- if (r.length > 20 && r[0] === 0)
- rOffset = 1;
- if (s.length > 20 && s[0] === 0)
- sOffset = 1;
- const newSig =
- Buffer.allocUnsafe((r.length - rOffset) + (s.length - sOffset));
- bufferCopy(r, newSig, rOffset, r.length, 0);
- bufferCopy(s, newSig, sOffset, s.length, r.length - rOffset);
- return newSig;
- }
- case 'ecdsa-sha2-nistp256':
- case 'ecdsa-sha2-nistp384':
- case 'ecdsa-sha2-nistp521': {
- if (signature[0] === 0)
- return signature;
- // Convert SSH signature parameters to ASN.1 BER values for OpenSSL
- const asnReader = new Ber.Reader(signature);
- asnReader.readSequence();
- const r = asnReader.readString(Ber.Integer, true);
- const s = asnReader.readString(Ber.Integer, true);
- if (r === null || s === null)
- return;
- const newSig = Buffer.allocUnsafe(4 + r.length + 4 + s.length);
- writeUInt32BE(newSig, r.length, 0);
- newSig.set(r, 4);
- writeUInt32BE(newSig, s.length, 4 + r.length);
- newSig.set(s, 4 + 4 + r.length);
- return newSig;
- }
- }
- return signature;
- },
- sendPacket: (proto, packet, bypass) => {
- if (!bypass && proto._kexinit !== undefined) {
- // We're currently in the middle of a handshake
- if (proto._queue === undefined)
- proto._queue = [];
- proto._queue.push(packet);
- proto._debug && proto._debug('Outbound: ... packet queued');
- return false;
- }
- proto._cipher.encrypt(packet);
- return true;
- },
- };
|