Skip to content

Commit

Permalink
On to KEXINIT!
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedeboer committed May 13, 2011
1 parent ac3a224 commit a19f0ac
Showing 1 changed file with 108 additions and 184 deletions.
292 changes: 108 additions & 184 deletions lib/ssh2.js
Expand Up @@ -485,6 +485,8 @@ Util.inherits(ssh2, Events.EventEmitter);
*/
this.signature_format = "";

this.listen_callbacks = [];

this.connect = function(cbconnect) {
var _self = this;

Expand Down Expand Up @@ -529,6 +531,9 @@ Util.inherits(ssh2, Events.EventEmitter);
connected = true;
_self.fsock.removeListener("data", listener);

_self._get_binary_packet(function(response) {

});
_self._listen();
}
else {
Expand Down Expand Up @@ -1375,101 +1380,87 @@ Util.inherits(ssh2, Events.EventEmitter);
};

this._listen = function() {
// initialize the packets buffer, used by _get_binary_packet
this.packets = [];

var packet_length = -1,
padding_length = -1,
msgType = -1,
payload = null,
padding = null,
message = {},
_self = this;

var remaining_length, buffer, message,
_self = this;

function reset() {
packet_length = padding_length = msgType = -1;
payload = padding = null;
remaining_length = -1;
message = {};
return Strtok.UINT32_BE;
}
reset();

Strtok.parse(this.fsock, function(v, callback) {
//console.log("callback: ", v);
if (typeof v == "undefined")
return Strtok.UINT32_BE;

if (packet_length == -1) {
packet_length = v;
return Strtok.UINT8;
if (!message.packet_length) {
message.packet_length = v;
//return Strtok.UINT8;
return new Strtok.BufferType(_self.decrypt_block_size);
}
else if (padding_length == -1) {
padding_length = v;
return new Strtok.StringType(1, "binary");
else if (!message.padding_length) {
message.raw = v;
if (_self.decrypt)
raw = _self.decrypt.decrypt(message.raw);
message.padding_length = Strtok.UINT8.get(message.raw, 0);
message.type = (new Strtok.StringType(1, "binary")).get(message.raw, Strtok.UINT8.len).charCodeAt(0);

remaining_length = message.packet_length - _self.decrypt_block_size - 1;// + 4 - _self.decrypt_block_size;
//console.log("how many bytes remaining? ", message.packet_length, remaining_length, _self.decrypt_block_size);
buffer = new Buffer(0);
return new Strtok.BufferType(remaining_length);
}
else if (msgType == -1) {
msgType = v.charCodeAt(0);

//return new Strtok.StringType(packet_length - padding_length - 2, "utf-8");
else if (remaining_length > 0) {
remaining_length -= v.length;
buffer = Buffer.concat(buffer, v);
//console.log("MORE BYTES? ", remaining_length);
return new Strtok.BufferType(remaining_length);
}
switch (msgType) {
case exports.NET_SSH2_MSG_DISCONNECT:
if (!message.type) {
message.type = msgType;
return Strtok.UINT32_BE;
}
if (!message.reason_code) {
message.reason_code = v;
return Strtok.UINT32_BE;
}
if (!message.length) {
message.length = v;
return new Strtok.StringType(message.length, "utf-8");
else if (!message.payload) {
//console.log("DO WE GET HERE??", buffer.length);
if (buffer.length > 0)
message.raw = Buffer.concat(message.raw, _self.decrypt ? _self.decrypt.decrypt(buffer) : buffer);

var pay_len = message.packet_length - message.padding_length - 1;
//console.log("message length: ", message.raw.length, pay_len);
message.payload = message.raw.slice(0, pay_len);
message.padding = message.raw.slice(pay_len, pay_len + message.padding_length);

/*if (_self.hmac_check) {
message.hmac = fread($this->fsock, $this->hmac_size);
if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
user_error('Invalid HMAC', E_USER_NOTICE);
return false;
}
}
else {
_self.errors.push("SSH_MSG_DISCONNECT: "
+ _self.disconnect_reasons[message.reason_code] + "\r\n" + v);
_self.bitmask = 0;
// continue, to clear and pass on to the next message...
return reset();
case exports.NET_SSH2_MSG_IGNORE:
// continue, to clear and pass on to the next message...
return reset();
case exports.NET_SSH2_MSG_DEBUG:
if (!message.type) {
message.type = msgType;
return new Strtok.StringType(2, "binary");
}
if (!message.padding) {
message.padding = v;
return Strtok.UINT32_BE;
}
if (!message.length) {
message.length = v;
return new Strtok.StringType(message.length, "utf-8");
}
_self.errors.push("SSH_MSG_DEBUG: " + v);
// continue, to clear and pass on to the next message...
return reset();
case exports.NET_SSH2_MSG_UNIMPLEMENTED:
if (!message.type) {
message.type = msgType;
return new Strtok.StringType(packet_length - padding_length - 2, "utf-8");
}
//
return reset();
case exports.NET_SSH2_MSG_KEXINIT:
if (this.session_id !== false) {
if (!this._key_exchange(payload)) {
this.bitmask = 0;
return false;
}
payload = this._get_binary_packet();
}
}
}*/
_self.get_seq_no++;

if (exports.NET_SSH2_LOGGING) {
temp = _self.message_numbers[message.payload[0]]
? _self.message_numbers[message.payload[0]]
: "UNKNOWN";
if (exports.NET_SSH2_LOGGING == exports.NET_SSH2_LOG_COMPLEX)
_self.message_log.push(message.payload.slice(1));
}

//console.log('Read ' + v);
console.log("message: ", message);
return reset();
message = _self._filter(message);
if (message !== null) {
_self.packets[_self.get_seq_no] = message;
var cb = _self.listen_callbacks.shift();
if (cb)
cb(message);
}

// start over from the start (wait for the next packet)
return reset();
}
});
};

Expand All @@ -1480,74 +1471,8 @@ Util.inherits(ssh2, Events.EventEmitter);
* @see Net_SSH2::_send_binary_packet()
* @return String
*/
this._get_binary_packet = function() {
if (!this.fsock.writable)
throw "Connection closed prematurely";

var reader = new BufferReader(this.buffer);
var start = Date.now();
raw = new BufferReader(reader.popBuffer(this.decrypt_block_size));//this.buffer.slice(0, this.decrypt_block_size);
//this.buffer = this.buffer.slice(this.decrypt_block_size);
console.log("RAW",raw);
var stop = Date.now();

if (this.decrypt)
raw = this.decrypt.decrypt(raw);

// I = packet_length, c = padding_length
var len = new BufferReader(raw.popBuffer(6));
var packet_length = len.popIntBE(4);
var padding_length = len.popStringZero();
console.log("LENGHT:", packet_length, "next", padding_length);
var len = Utils.unpack("Ic", raw.slice(0, 5)),
packet_length = len[0],
padding_length = len[1],
remaining_length = Math.min(packet_length + 4 - this.decrypt_block_size, this.buffer.length),
buffer = new Buffer(0);
while (remaining_length > 0) {
temp = this.buffer.slice(0, remaining_length);
this.buffer = this.buffer.slice(remaining_length);
buffer.addChunk(temp);
remaining_length -= temp.length;
}
if (buffer.length) {
raw = raw.concat(this.decrypt !== false ? this.decrypt.decrypt(buffer) : buffer);
delete buffer;
delete temp;
}

// _string_shift = substr: string.substr(0, index), new string: string.substr(index);
var idx = Math.min(packet_length - padding_length - 1, raw.length);
var payload = raw.slice(0, idx);
raw = raw.slice(idx)
idx = Math.min(padding_length, raw.length);
padding = raw.slice(0, idx); // should leave raw empty
raw = raw.slice(idx);

if (this.hmac_check) {
hmac = this.buffer.slice(0, this.hmac_size);
if (hmac != this.hmac_check.hash(Utils.pack("IIcc", this.get_seq_no, packet_length, padding_length, payload + padding))) {
throw "Invalid HMAC";
}
}

//if (this.decompress) {
// payload = gzinflate(substr(payload, 2));
//}

this.get_seq_no++;

if (exports.NET_SSH2_LOGGING) {
temp = this.message_numbers[payload[0]]
? this.message_numbers[payload[0]]
: "UNKNOWN";
this.message_number_log.push("<- " + temp +
" (" + Math.round(stop - start, 4) + "s)");
if (exports.NET_SSH2_LOGGING == exports.NET_SSH2_LOG_COMPLEX)
this.message_log.push(payload.slice(1));
}

return this._filter(payload);
this._get_binary_packet = function(callback) {
this.listen_callbacks.push(callback);
};

/**
Expand All @@ -1557,70 +1482,68 @@ Util.inherits(ssh2, Events.EventEmitter);
* @see Net_SSH2::_get_binary_packet()
* @return String
*/
this._filter = function(payload) {
console.log("payload: ", payload.toString().charCodeAt(0), payload[0]);
switch (payload[0]) {
this._filter = function(message) {
console.log("payload: ", message);
switch (message.type) {
case exports.NET_SSH2_MSG_DISCONNECT:
this._string_shift(payload, 1);
extract(unpack("Nreason_code/Nlength", this._string_shift(payload, 8)));
var reason_code = Strtok.UINT8.get(message.payload, 1);
var length = Strtok.UINT8.get(message.payload, 1 + Strtok.UINT8.len);
this.errors.push("SSH_MSG_DISCONNECT: " + this.disconnect_reasons[reason_code] + "\r\n"
+ utf8_decode(this._string_shift(payload, length)));
+ message.payload.slice(1 + (Strtok.UINT8.len * 2), length).toString("utf8"));
this.bitmask = 0;
// return immediately, message will not be pushed on the stack
return false;
case exports.NET_SSH2_MSG_IGNORE:
payload = this._get_binary_packet();
break;
// return immediately, message will not be pushed on the stack
return null;
case exports.NET_SSH2_MSG_DEBUG:
this._string_shift(payload, 2);
extract(unpack("Nlength", this._string_shift(payload, 4)));
this.errors.push("SSH_MSG_DEBUG: " + utf8_decode(this._string_shift(payload, length)));
payload = this._get_binary_packet();
break;
var length = Strtok.UINT8.get(message.payload, 2);
this.errors.push("SSH_MSG_DEBUG: " + message.payload.slice(2 + Strtok.UINT8.len, length));
// return immediately, message will not be pushed on the stack
return null;
case exports.NET_SSH2_MSG_UNIMPLEMENTED:
// return immediately, message will not be pushed on the stack
return false;
case exports.NET_SSH2_MSG_KEXINIT:
console.log("KEXINIT: ", this.session_id);
if (this.session_id !== false) {
if (!this._key_exchange(payload)) {
if (!this._key_exchange(message.payload)) {
this.bitmask = 0;
return false;
}
payload = this._get_binary_packet();
// return immediately, message will not be pushed on the stack
return null;
}
break;
}
/// <--to here

// see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the
// encryption has been activated and when we haven"t already logged in
if ((this.bitmap & exports.NET_SSH2_MASK_CONSTRUCTOR) && !(this.bitmap & exports.NET_SSH2_MASK_LOGIN)
&& payload[0] == exports.NET_SSH2_MSG_USERAUTH_BANNER) {
payload = payload.slice(1);
var len = unpack("I", payload.slice(0, 4));
payload = payload.slice(4);
this.errors.push("SSH_MSG_USERAUTH_BANNER: " + utf8_decode(this._string_shift(payload, length)));
payload = this._get_binary_packet();
&& message.type == exports.NET_SSH2_MSG_USERAUTH_BANNER) {
var length = Strtok.INT32_BE.get(message.payload, 1);
this.errors.push("SSH_MSG_USERAUTH_BANNER: " + payload.slice(1 + Strtok.INT32_BE, length).toString("utf8"));
// return immediately, message will not be pushed on the stack
return null;
}

// only called when we've already logged in
if ((this.bitmap & exports.NET_SSH2_MASK_CONSTRUCTOR) && (this.bitmap & exports.NET_SSH2_MASK_LOGIN)) {
switch (String(payload[0]).charCodeAt(0)) {
switch (message.type) {
case exports.NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
this._string_shift(payload, 1);
extract(unpack("Nlength", this._string_shift(payload)));
this.errors.push("SSH_MSG_GLOBAL_REQUEST: " + utf8_decode(this._string_shift(payload, length)));

if (!this._send_binary_packet(pack("C", exports.NET_SSH2_MSG_REQUEST_FAILURE))) {
var length = Strtok.UINT8.get(message.payload, 1);
this.errors.push("SSH_MSG_GLOBAL_REQUEST: " + message.payload.slice(1 + Strtok.UINT8.len, length).toString("utf8"));
if (!this._send_binary_packet(pack("C", exports.NET_SSH2_MSG_REQUEST_FAILURE)))
return this._disconnect(exports.NET_SSH2_DISCONNECT_BY_APPLICATION);
}

payload = this._get_binary_packet();
// return immediately, message will not be pushed on the stack
return null;
break;
case exports.NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
this._string_shift(payload, 1);
extract(unpack("N", this._string_shift(payload, 4)));
this.errors.push("SSH_MSG_CHANNEL_OPEN: " + utf8_decode(this._string_shift(payload, length)));
var length = Strtok.UINT8.get(message.payload, 1);
this.errors.push("SSH_MSG_CHANNEL_OPEN: " + message.payload.slice(1, length).toString("utf8"));

this._string_shift(payload, 4); // skip over client channel
extract(unpack("Nserver_channel", this._string_shift(payload, 4)));
var server_channel = Strtok.UINT8.get(message.payload, 1 + 4); // skip over client channel

packet = pack("CN3a*Na*",
exports.NET_SSH2_MSG_REQUEST_FAILURE, server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, "", 0, "");
Expand All @@ -1629,14 +1552,15 @@ Util.inherits(ssh2, Events.EventEmitter);
return this._disconnect(exports.NET_SSH2_DISCONNECT_BY_APPLICATION);
}

payload = this._get_binary_packet();
break;
// return immediately, message will not be pushed on the stack
return null;
case exports.NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
payload = this._get_binary_packet();
// return immediately, message will not be pushed on the stack
return null;
}
}

return payload;
return message;
};

/**
Expand Down

0 comments on commit a19f0ac

Please sign in to comment.