mirror of
https://github.com/danog/phpseclib.git
synced 2024-12-04 02:28:06 +01:00
SSH2: add support for zlib and zlib@openssh.com compression
This commit is contained in:
parent
30a9a1541c
commit
da6c1b06bf
@ -150,6 +150,23 @@ define('NET_SSH2_READ_REGEX', 2);
|
|||||||
define('NET_SSH2_READ_NEXT', 3);
|
define('NET_SSH2_READ_NEXT', 3);
|
||||||
/**#@-*/
|
/**#@-*/
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* No compression
|
||||||
|
*/
|
||||||
|
define('NET_SSH2_COMPRESSION_NONE', 1);
|
||||||
|
/**
|
||||||
|
* zlib compression
|
||||||
|
*/
|
||||||
|
define('NET_SSH2_COMPRESSION_ZLIB', 2);
|
||||||
|
/**
|
||||||
|
* zlib@openssh.com
|
||||||
|
*/
|
||||||
|
define('NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH', 3);
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pure-PHP implementation of SSHv2.
|
* Pure-PHP implementation of SSHv2.
|
||||||
*
|
*
|
||||||
@ -980,8 +997,57 @@ class Net_SSH2
|
|||||||
*
|
*
|
||||||
* @see https://tools.ietf.org/html/rfc4252#section-5.1
|
* @see https://tools.ietf.org/html/rfc4252#section-5.1
|
||||||
* @var array|null
|
* @var array|null
|
||||||
|
* @access private
|
||||||
*/
|
*/
|
||||||
private $auth_methods_to_continue = null;
|
var $auth_methods_to_continue = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compression method
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $compress = NET_SSH2_COMPRESSION_NONE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompression method
|
||||||
|
*
|
||||||
|
* @var resource|object
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $decompress = NET_SSH2_COMPRESSION_NONE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compression context
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $compress_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompression context
|
||||||
|
*
|
||||||
|
* @var resource|object
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $decompress_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regenerate Compression Context
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $regenerate_compression_context = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regenerate Decompression Context
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $regenerate_decompression_context = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Constructor.
|
* Default Constructor.
|
||||||
@ -1590,19 +1656,25 @@ class Net_SSH2
|
|||||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$compression_map = array(
|
||||||
|
'none' => NET_SSH2_COMPRESSION_NONE,
|
||||||
|
'zlib' => NET_SSH2_COMPRESSION_ZLIB,
|
||||||
|
'zlib@openssh.com' => NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH
|
||||||
|
);
|
||||||
|
|
||||||
$compression_algorithm_out = $this->_array_intersect_first($c2s_compression_algorithms, $this->compression_algorithms_client_to_server);
|
$compression_algorithm_out = $this->_array_intersect_first($c2s_compression_algorithms, $this->compression_algorithms_client_to_server);
|
||||||
if ($compression_algorithm_out === false) {
|
if ($compression_algorithm_out === false) {
|
||||||
user_error('No compatible client to server compression algorithms found');
|
user_error('No compatible client to server compression algorithms found');
|
||||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||||
}
|
}
|
||||||
//$this->decompress = $compression_algorithm_out == 'zlib';
|
$this->compress = $compression_map[$compression_algorithm_out];
|
||||||
|
|
||||||
$compression_algorithm_in = $this->_array_intersect_first($s2c_compression_algorithms, $this->compression_algorithms_client_to_server);
|
$compression_algorithm_in = $this->_array_intersect_first($s2c_compression_algorithms, $this->compression_algorithms_server_to_client);
|
||||||
if ($compression_algorithm_in === false) {
|
if ($compression_algorithm_in === false) {
|
||||||
user_error('No compatible server to client compression algorithms found');
|
user_error('No compatible server to client compression algorithms found');
|
||||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||||
}
|
}
|
||||||
//$this->compress = $compression_algorithm_in == 'zlib';
|
$this->decompress = $compression_map[$compression_algorithm_in];
|
||||||
|
|
||||||
if (strpos($kex_algorithm, 'diffie-hellman-group-exchange') === 0) {
|
if (strpos($kex_algorithm, 'diffie-hellman-group-exchange') === 0) {
|
||||||
$dh_group_sizes_packed = pack(
|
$dh_group_sizes_packed = pack(
|
||||||
@ -1996,6 +2068,8 @@ class Net_SSH2
|
|||||||
}
|
}
|
||||||
$this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
|
$this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
|
||||||
|
|
||||||
|
$this->regenerate_compression_context = $this->regenerate_decompression_context = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3399,7 +3473,7 @@ class Net_SSH2
|
|||||||
|
|
||||||
if (!is_resource($this->fsock) || feof($this->fsock)) {
|
if (!is_resource($this->fsock) || feof($this->fsock)) {
|
||||||
$this->bitmap = 0;
|
$this->bitmap = 0;
|
||||||
user_error('Connection closed (by server) prematurely');
|
user_error('Connection closed (by server) prematurely ' . $elapsed . 's');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3470,9 +3544,41 @@ class Net_SSH2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ($this->decompress) {
|
switch ($this->decompress) {
|
||||||
// $payload = gzinflate(substr($payload, 2));
|
case NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
|
||||||
//}
|
if (!$this->isAuthenticated()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NET_SSH2_COMPRESSION_ZLIB:
|
||||||
|
if ($this->regenerate_decompression_context) {
|
||||||
|
$this->regenerate_decompression_context = false;
|
||||||
|
|
||||||
|
$cmf = ord($payload[0]);
|
||||||
|
$cm = $cmf & 0x0F;
|
||||||
|
if ($cm != 8) { // deflate
|
||||||
|
user_error("Only CM = 8 ('deflate') is supported ($cm)");
|
||||||
|
}
|
||||||
|
$cinfo = ($cmf & 0xF0) >> 4;
|
||||||
|
if ($cinfo > 7) {
|
||||||
|
user_error("CINFO above 7 is not allowed ($cinfo)");
|
||||||
|
}
|
||||||
|
$windowSize = 1 << ($cinfo + 8);
|
||||||
|
|
||||||
|
$flg = ord($payload[1]);
|
||||||
|
//$fcheck = $flg && 0x0F;
|
||||||
|
if ((($cmf << 8) | $flg) % 31) {
|
||||||
|
user_error('fcheck failed');
|
||||||
|
}
|
||||||
|
$fdict = boolval($flg & 0x20);
|
||||||
|
$flevel = ($flg & 0xC0) >> 6;
|
||||||
|
|
||||||
|
$this->decompress_context = inflate_init(ZLIB_ENCODING_RAW, ['window' => $cinfo + 8]);
|
||||||
|
$payload = substr($payload, 2);
|
||||||
|
}
|
||||||
|
if ($this->decompress_context) {
|
||||||
|
$payload = inflate_add($this->decompress_context, $payload, ZLIB_PARTIAL_FLUSH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->get_seq_no++;
|
$this->get_seq_no++;
|
||||||
|
|
||||||
@ -4028,11 +4134,27 @@ class Net_SSH2
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ($this->compress) {
|
if (!isset($logged)) {
|
||||||
// // the -4 removes the checksum:
|
$logged = $data;
|
||||||
// // http://php.net/function.gzcompress#57710
|
}
|
||||||
// $data = substr(gzcompress($data), 0, -4);
|
|
||||||
//}
|
switch ($this->compress) {
|
||||||
|
case NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
|
||||||
|
if (!$this->isAuthenticated()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NET_SSH2_COMPRESSION_ZLIB:
|
||||||
|
if (!$this->regenerate_compression_context) {
|
||||||
|
$header = '';
|
||||||
|
} else {
|
||||||
|
$this->regenerate_compression_context = false;
|
||||||
|
$this->compress_context = deflate_init(ZLIB_ENCODING_RAW, ['window' => 15]);
|
||||||
|
$header = "\x78\x9C";
|
||||||
|
}
|
||||||
|
if ($this->compress_context) {
|
||||||
|
$data = $header . deflate_add($this->compress_context, $data, ZLIB_PARTIAL_FLUSH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
|
// 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
|
||||||
$packet_length = strlen($data) + 9;
|
$packet_length = strlen($data) + 9;
|
||||||
@ -4060,10 +4182,10 @@ class Net_SSH2
|
|||||||
|
|
||||||
if (defined('NET_SSH2_LOGGING')) {
|
if (defined('NET_SSH2_LOGGING')) {
|
||||||
$current = strtok(microtime(), ' ') + strtok('');
|
$current = strtok(microtime(), ' ') + strtok('');
|
||||||
$message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')';
|
$message_number = isset($this->message_numbers[ord($logged[0])]) ? $this->message_numbers[ord($logged[0])] : 'UNKNOWN (' . ord($logged[0]) . ')';
|
||||||
$message_number = '-> ' . $message_number .
|
$message_number = '-> ' . $message_number .
|
||||||
' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
|
' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
|
||||||
$this->_append_log($message_number, isset($logged) ? $logged : $data);
|
$this->_append_log($message_number, $logged);
|
||||||
$this->last_packet = $current;
|
$this->last_packet = $current;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4746,10 +4868,12 @@ class Net_SSH2
|
|||||||
*/
|
*/
|
||||||
function getSupportedCompressionAlgorithms()
|
function getSupportedCompressionAlgorithms()
|
||||||
{
|
{
|
||||||
return array(
|
$algos = array('none'); // REQUIRED no compression
|
||||||
'none' // REQUIRED no compression
|
if (function_exists('deflate_init')) {
|
||||||
//'zlib' // OPTIONAL ZLIB (LZ77) compression
|
$algos[] = 'zlib@openssh.com'; // https://datatracker.ietf.org/doc/html/draft-miller-secsh-compression-delayed
|
||||||
);
|
$algos[] = 'zlib';
|
||||||
|
}
|
||||||
|
return $algos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4764,18 +4888,24 @@ class Net_SSH2
|
|||||||
{
|
{
|
||||||
$this->_connect();
|
$this->_connect();
|
||||||
|
|
||||||
|
$compression_map = array(
|
||||||
|
NET_SSH2_COMPRESSION_NONE => 'none',
|
||||||
|
NET_SSH2_COMPRESSION_ZLIB => 'zlib',
|
||||||
|
NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH => 'zlib@openssh.com'
|
||||||
|
);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'kex' => $this->kex_algorithm,
|
'kex' => $this->kex_algorithm,
|
||||||
'hostkey' => $this->signature_format,
|
'hostkey' => $this->signature_format,
|
||||||
'client_to_server' => array(
|
'client_to_server' => array(
|
||||||
'crypt' => $this->encrypt->name,
|
'crypt' => $this->encrypt->name,
|
||||||
'mac' => $this->hmac_create->name,
|
'mac' => $this->hmac_create->name,
|
||||||
'comp' => 'none',
|
'comp' => $compression_map[$this->compress],
|
||||||
),
|
),
|
||||||
'server_to_client' => array(
|
'server_to_client' => array(
|
||||||
'crypt' => $this->decrypt->name,
|
'crypt' => $this->decrypt->name,
|
||||||
'mac' => $this->hmac_check->name,
|
'mac' => $this->hmac_check->name,
|
||||||
'comp' => 'none',
|
'comp' => $compression_map[$this->decompress],
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user