diff --git a/composer.json b/composer.json
index 2600d0a25..a96395443 100644
--- a/composer.json
+++ b/composer.json
@@ -40,7 +40,7 @@
"pear/pear-core-minimal": "^1.10",
"php-http/guzzle7-adapter": "^1.0.0",
"php-opencloud/openstack": "^3.1",
- "phpseclib/phpseclib": "^2.0.45",
+ "phpseclib/phpseclib": "^2.0.48",
"pimple/pimple": "^3.5.0",
"psr/clock": "^1.0",
"psr/container": "^2.0.2",
diff --git a/composer.lock b/composer.lock
index 8e4627904..1d2848932 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "98082464b9dd0c38d14cadb463a0e05c",
+ "content-hash": "0d8da5dc1140ab43c5a4a7dc8eb7971b",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -2771,16 +2771,16 @@
},
{
"name": "phpseclib/phpseclib",
- "version": "2.0.47",
+ "version": "2.0.48",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
- "reference": "b7d7d90ee7df7f33a664b4aea32d50a305d35adb"
+ "reference": "eaa7be704b8b93a6913b69eb7f645a59d7731b61"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/b7d7d90ee7df7f33a664b4aea32d50a305d35adb",
- "reference": "b7d7d90ee7df7f33a664b4aea32d50a305d35adb",
+ "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/eaa7be704b8b93a6913b69eb7f645a59d7731b61",
+ "reference": "eaa7be704b8b93a6913b69eb7f645a59d7731b61",
"shasum": ""
},
"require": {
@@ -2861,7 +2861,7 @@
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
- "source": "https://github.com/phpseclib/phpseclib/tree/2.0.47"
+ "source": "https://github.com/phpseclib/phpseclib/tree/2.0.48"
},
"funding": [
{
@@ -2877,7 +2877,7 @@
"type": "tidelift"
}
],
- "time": "2024-02-26T04:55:38+00:00"
+ "time": "2024-12-14T21:03:54+00:00"
},
{
"name": "pimple/pimple",
diff --git a/composer/installed.json b/composer/installed.json
index cc86d5bdc..8617898b9 100644
--- a/composer/installed.json
+++ b/composer/installed.json
@@ -2888,17 +2888,17 @@
},
{
"name": "phpseclib/phpseclib",
- "version": "2.0.47",
- "version_normalized": "2.0.47.0",
+ "version": "2.0.48",
+ "version_normalized": "2.0.48.0",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
- "reference": "b7d7d90ee7df7f33a664b4aea32d50a305d35adb"
+ "reference": "eaa7be704b8b93a6913b69eb7f645a59d7731b61"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/b7d7d90ee7df7f33a664b4aea32d50a305d35adb",
- "reference": "b7d7d90ee7df7f33a664b4aea32d50a305d35adb",
+ "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/eaa7be704b8b93a6913b69eb7f645a59d7731b61",
+ "reference": "eaa7be704b8b93a6913b69eb7f645a59d7731b61",
"shasum": ""
},
"require": {
@@ -2916,7 +2916,7 @@
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.",
"ext-xml": "Install the XML extension to load XML formatted public keys."
},
- "time": "2024-02-26T04:55:38+00:00",
+ "time": "2024-12-14T21:03:54+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -2981,7 +2981,7 @@
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
- "source": "https://github.com/phpseclib/phpseclib/tree/2.0.47"
+ "source": "https://github.com/phpseclib/phpseclib/tree/2.0.48"
},
"funding": [
{
diff --git a/composer/installed.php b/composer/installed.php
index 39eff4631..e7b85c649 100644
--- a/composer/installed.php
+++ b/composer/installed.php
@@ -401,9 +401,9 @@
'dev_requirement' => false,
),
'phpseclib/phpseclib' => array(
- 'pretty_version' => '2.0.47',
- 'version' => '2.0.47.0',
- 'reference' => 'b7d7d90ee7df7f33a664b4aea32d50a305d35adb',
+ 'pretty_version' => '2.0.48',
+ 'version' => '2.0.48.0',
+ 'reference' => 'eaa7be704b8b93a6913b69eb7f645a59d7731b61',
'type' => 'library',
'install_path' => __DIR__ . '/../phpseclib/phpseclib',
'aliases' => array(),
diff --git a/phpseclib/phpseclib/phpseclib/Crypt/Base.php b/phpseclib/phpseclib/phpseclib/Crypt/Base.php
index ab5944cde..2d4225a3f 100644
--- a/phpseclib/phpseclib/phpseclib/Crypt/Base.php
+++ b/phpseclib/phpseclib/phpseclib/Crypt/Base.php
@@ -611,7 +611,6 @@ function getBlockLength()
*
* @access public
* @param string $key
- * @internal Could, but not must, extend by the child Crypt_* class
*/
function setKey($key)
{
diff --git a/phpseclib/phpseclib/phpseclib/Crypt/RSA.php b/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
index fec689585..7f5df1d5f 100644
--- a/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
+++ b/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
@@ -1396,9 +1396,14 @@ function. As is, the definitive authority on this encoding scheme isn't the IET
$this->components = array();
$xml = xml_parser_create('UTF-8');
- xml_set_object($xml, $this);
- xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
- xml_set_character_data_handler($xml, '_data_handler');
+ if (version_compare(PHP_VERSION, '8.4.0', '>=')) {
+ xml_set_element_handler($xml, array($this, '_start_element_handler'), array($this, '_stop_element_handler'));
+ xml_set_character_data_handler($xml, array($this, '_data_handler'));
+ } else {
+ xml_set_object($xml, $this);
+ xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
+ xml_set_character_data_handler($xml, '_data_handler');
+ }
// add to account for "dangling" tags like ... that are sometimes added
if (!xml_parse($xml, '' . $key . '')) {
xml_parser_free($xml);
diff --git a/phpseclib/phpseclib/phpseclib/File/X509.php b/phpseclib/phpseclib/phpseclib/File/X509.php
index 7b8d96e29..64e22655c 100644
--- a/phpseclib/phpseclib/phpseclib/File/X509.php
+++ b/phpseclib/phpseclib/phpseclib/File/X509.php
@@ -3847,7 +3847,8 @@ function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
array(
'version' => 'v1',
'subject' => $this->dn,
- 'subjectPKInfo' => $publicKey
+ 'subjectPKInfo' => $publicKey,
+ 'attributes' => array()
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false // this is going to be overwritten later
@@ -4003,11 +4004,11 @@ function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
$version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
if (!$version) {
if (!empty($tbsCertList['crlExtensions'])) {
- $version = 1; // v2.
+ $version = 'v2'; // v2.
} elseif (!empty($tbsCertList['revokedCertificates'])) {
foreach ($tbsCertList['revokedCertificates'] as $cert) {
if (!empty($cert['crlEntryExtensions'])) {
- $version = 1; // v2.
+ $version = 'v2'; // v2.
}
}
}
diff --git a/phpseclib/phpseclib/phpseclib/Math/BigInteger.php b/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
index 7747a95b6..5f2283678 100644
--- a/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
+++ b/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
@@ -251,8 +251,17 @@ class BigInteger
function __construct($x = 0, $base = 10)
{
if (!defined('MATH_BIGINTEGER_MODE')) {
+
+ // https://github.com/php/php-src/commit/e0a0e216a909dc4ee4ea7c113a5f41d49525f02e broke GMP
+ // https://github.com/php/php-src/commit/424ba0f2ff9677d16b4e339e90885bd4bc49fcf1 fixed it
+ // see https://github.com/php/php-src/issues/16870 for more info
+ if (version_compare(PHP_VERSION, '8.2.26', '<')) {
+ $gmpOK = true;
+ } else {
+ $gmpOK = !in_array(PHP_VERSION_ID, array(80226, 80314, 80400, 80401));
+ }
switch (true) {
- case extension_loaded('gmp'):
+ case extension_loaded('gmp') && $gmpOK:
define('MATH_BIGINTEGER_MODE', self::MODE_GMP);
break;
case extension_loaded('bcmath'):
diff --git a/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/phpseclib/phpseclib/phpseclib/Net/SFTP.php
index 28b568062..1c6ef7f9a 100644
--- a/phpseclib/phpseclib/phpseclib/Net/SFTP.php
+++ b/phpseclib/phpseclib/phpseclib/Net/SFTP.php
@@ -758,7 +758,8 @@ function _init_sftp_connection()
return false;
}
$this->canonicalize_paths = false;
- $this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
+ $this->_reset_sftp();
+ return $this->_init_sftp_connection();
}
$this->_update_stat_cache($this->pwd, array());
@@ -3629,20 +3630,30 @@ function _send_sftp_packet($type, $data, $request_id = 1)
}
/**
- * Resets a connection for re-use
+ * Resets the SFTP channel for re-use
*
- * @param int $reason
* @access private
*/
- function _reset_connection($reason)
+ function _reset_sftp()
{
- parent::_reset_connection($reason);
$this->use_request_id = false;
$this->pwd = false;
$this->requestBuffer = array();
$this->partial_init = false;
}
+ /**
+ * Resets a connection for re-use
+ *
+ * @param int $reason
+ * @access private
+ */
+ function _reset_connection($reason)
+ {
+ parent::_reset_connection($reason);
+ $this->_reset_sftp();
+ }
+
/**
* Receives SFTP Packets
*
diff --git a/phpseclib/phpseclib/phpseclib/Net/SSH2.php b/phpseclib/phpseclib/phpseclib/Net/SSH2.php
index 607cc2145..775d894fb 100644
--- a/phpseclib/phpseclib/phpseclib/Net/SSH2.php
+++ b/phpseclib/phpseclib/phpseclib/Net/SSH2.php
@@ -146,6 +146,10 @@ class SSH2
* Dumps the content real-time to a file
*/
const LOG_REALTIME_FILE = 4;
+ /**
+ * Dumps the message numbers real-time
+ */
+ const LOG_REALTIME_SIMPLE = 5;
/**
* Make sure that the log never gets larger than this
*/
@@ -1005,7 +1009,7 @@ class SSH2
* @var bool
* @access private
*/
- var $retry_connect = false;
+ var $login_credentials_finalized = false;
/**
* Binary Packet Buffer
@@ -1097,12 +1101,57 @@ class SSH2
var $smartMFA = true;
/**
- * Extra packets counter
+ * Bytes Transferred Since Last Key Exchange
+ *
+ * Includes outbound and inbound totals
*
+ * @var int
+ * @access private
+ */
+ var $bytesTransferredSinceLastKEX = 0;
+
+ /**
+ * After how many transferred byte should phpseclib initiate a key re-exchange?
+ *
+ * @var int
+ * @access private
+ */
+ var $doKeyReexchangeAfterXBytes = 1073741824;
+
+ /**
+ * Has a key re-exchange been initialized?
+ *
* @var bool
* @access private
*/
- var $extra_packets;
+ var $keyExchangeInProgress = false;
+
+ /**
+ * KEX Buffer
+ *
+ * If we're in the middle of a key exchange we want to buffer any additional packets we get until
+ * the key exchange is over
+ *
+ * @see self::_get_binary_packet()
+ * @see self::_key_exchange()
+ * @see self::exec()
+ * @var array
+ * @access private
+ */
+ var $kex_buffer = array();
+
+ /**
+ * Strict KEX Flag
+ *
+ * If kex-strict-s-v00@openssh.com is present in the first KEX packet it need not
+ * be present in subsequent packet
+ *
+ * @see self::_key_exchange()
+ * @see self::exec()
+ * @var array
+ * @access private
+ */
+ var $strict_kex_flag = false;
/**
* Default Constructor.
@@ -1361,25 +1410,17 @@ function _connect()
}
$temp = stream_get_line($this->fsock, 255, "\n");
- if (strlen($temp) == 255) {
- continue;
- }
if ($temp === false) {
return false;
}
- $line.= "$temp\n";
-
- // quoting RFC4253, "Implementers who wish to maintain
- // compatibility with older, undocumented versions of this protocol may
- // want to process the identification string without expecting the
- // presence of the carriage return character for reasons described in
- // Section 5 of this document."
+ $line .= $temp;
+ if (strlen($temp) == 255) {
+ continue;
+ }
- //if (substr($line, -2) == "\r\n") {
- // break;
- //}
+ $line .= "\n";
break;
}
@@ -1400,7 +1441,8 @@ function _connect()
$this->_append_log('->', $this->identifier . "\r\n");
}
- $this->server_identifier = trim($temp, "\r\n");
+ $this->server_identifier = trim($data, "\r\n");
+
if (strlen($extra)) {
$this->errors[] = $data;
}
@@ -1485,8 +1527,13 @@ function _generate_identifier()
*/
function _key_exchange($kexinit_payload_server = false)
{
+ $this->bytesTransferredSinceLastKEX = 0;
+
$preferred = $this->preferred;
- $send_kex = true;
+ // for the initial key exchange $send_kex is true (no key re-exchange has been started)
+ // for phpseclib initiated key exchanges $send_kex is false
+ $send_kex = !$this->keyExchangeInProgress;
+ $this->keyExchangeInProgress = true;
$kex_algorithms = isset($preferred['kex']) ?
$preferred['kex'] :
@@ -1572,22 +1619,29 @@ function _key_exchange($kexinit_payload_server = false)
0
);
- if ($kexinit_payload_server === false) {
+ if ($kexinit_payload_server === false && $send_kex) {
if (!$this->_send_binary_packet($kexinit_payload_client)) {
return false;
}
- $this->extra_packets = 0;
- $kexinit_payload_server = $this->_get_binary_packet();
- if ($kexinit_payload_server === false) {
- $this->bitmap = 0;
- user_error('Connection closed by server');
- return false;
- }
+ while (true) {
+ $kexinit_payload_server = $this->_get_binary_packet();
+ if ($kexinit_payload_server === false) {
+ $this->bitmap = 0;
+ user_error('Connection closed by server');
+ return false;
+ }
+
+ if (strlen($kexinit_payload_server)) {
+ switch (ord($kexinit_payload_server[0])) {
+ case NET_SSH2_MSG_KEXINIT:
+ break 2;
+ case NET_SSH2_MSG_DISCONNECT:
+ return $this->_handleDisconnect($kexinit_payload_server);
+ }
+ }
- if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
- user_error('Expected SSH_MSG_KEXINIT');
- return false;
+ $this->kex_buffer[] = $kexinit_payload_server;
}
$send_kex = false;
@@ -1603,9 +1657,14 @@ function _key_exchange($kexinit_payload_server = false)
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
- if ($this->session_id === false && $this->extra_packets) {
- user_error('Possible Terrapin Attack detected');
- return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
+ if ($this->session_id === false) {
+ // [kex-strict-s-v00@openssh.com is] only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored
+ // if [it is] present in subsequent SSH2_MSG_KEXINIT packets
+ $this->strict_kex_flag = true;
+ if (count($this->kex_buffer)) {
+ user_error('Possible Terrapin Attack detected');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
+ }
}
}
@@ -2014,7 +2073,9 @@ function _key_exchange($kexinit_payload_server = false)
return false;
}
- if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
+ $this->keyExchangeInProgress = false;
+
+ if ($this->strict_kex_flag) {
$this->get_seq_no = $this->send_seq_no = 0;
}
@@ -2292,7 +2353,7 @@ function _bad_algorithm_candidate($algorithm)
function login($username)
{
$args = func_get_args();
- if (!$this->retry_connect) {
+ if (!$this->login_credentials_finalized) {
$this->auth[] = $args;
}
@@ -2383,6 +2444,7 @@ function _login($username)
foreach ($newargs as $arg) {
if ($this->_login_helper($username, $arg)) {
+ $this->login_credentials_finalized = true;
return true;
}
}
@@ -2418,10 +2480,14 @@ function _login_helper($username, $password = null)
return false;
}
+ $bad_key_size_fix = $this->bad_key_size_fix;
$response = $this->_get_binary_packet();
if ($response === false) {
- if ($this->retry_connect) {
- $this->retry_connect = false;
+ // bad_key_size_fix is only ever re-assigned to true
+ // under certain conditions. when it's newly set we'll
+ // retry the connection with that new setting but we'll
+ // only try it once.
+ if ($bad_key_size_fix != $this->bad_key_size_fix) {
if (!$this->_connect()) {
return false;
}
@@ -2790,10 +2856,12 @@ function _ssh_agent_login($username, $agent)
{
$this->agent = $agent;
$keys = $agent->requestIdentities();
+ $orig_algorithms = $this->supported_private_key_algorithms;
foreach ($keys as $key) {
if ($this->_privatekey_login($username, $key)) {
return true;
}
+ $this->supported_private_key_algorithms = $orig_algorithms;
}
return false;
@@ -3551,7 +3619,6 @@ function ping()
function _reconnect()
{
$this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
- $this->retry_connect = true;
if (!$this->_connect()) {
return false;
}
@@ -3575,7 +3642,6 @@ function _reset_connection($reason)
$this->hmac_check = $this->hmac_create = false;
$this->hmac_size = false;
$this->session_id = false;
- $this->retry_connect = true;
$this->get_seq_no = $this->send_seq_no = 0;
}
@@ -3590,6 +3656,10 @@ function _reset_connection($reason)
*/
function _get_binary_packet($skip_channel_filter = false)
{
+ if (!$this->keyExchangeInProgress && count($this->kex_buffer)) {
+ return $this->_filter(array_shift($this->kex_buffer), $skip_channel_filter);
+ }
+
if ($skip_channel_filter) {
$read = array($this->fsock);
$write = $except = null;
@@ -3674,9 +3744,13 @@ function _get_binary_packet($skip_channel_filter = false)
$remaining_length = $packet_length + 4 - $this->decrypt_block_size;
+ if (!$this->keyExchangeInProgress) {
+ $this->bytesTransferredSinceLastKEX+= $packet_length + $padding_length + 5;
+ }
+
// quoting ,
// "implementations SHOULD check that the packet length is reasonable"
- // PuTTY uses 0x9000 as the actual max packet size and so to shall we
+ // PuTTY uses 0x9000 as the actual max packet size and so, too, shall we
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decryptName) && !($this->bitmap & SSH2::MASK_LOGIN)) {
$this->bad_key_size_fix = true;
@@ -3766,7 +3840,34 @@ function _get_binary_packet($skip_channel_filter = false)
$this->last_packet = $current;
}
- return $this->_filter($payload, $skip_channel_filter);
+ if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) {
+ $this->_key_exchange();
+ }
+
+ // don't filter if we're in the middle of a key exchange (since _filter might send out packets)
+ return $this->keyExchangeInProgress ? $payload : $this->_filter($payload, $skip_channel_filter);
+ }
+
+ /**
+ * Handle Disconnect
+ *
+ * Because some binary packets need to be ignored...
+ *
+ * @see self::_filter()
+ * @see self::_key_exchange
+ * @return boolean
+ * @access private
+ */
+ function _handleDisconnect($payload)
+ {
+ $this->_string_shift($payload, 1);
+ if (strlen($payload) < 8) {
+ return false;
+ }
+ extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
+ $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
+ $this->bitmap = 0;
+ return false;
}
/**
@@ -3782,20 +3883,11 @@ function _filter($payload, $skip_channel_filter)
{
switch (ord($payload[0])) {
case NET_SSH2_MSG_DISCONNECT:
- $this->_string_shift($payload, 1);
- if (strlen($payload) < 8) {
- return false;
- }
- extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
- $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
- $this->bitmap = 0;
- return false;
+ return $this->_handleDisconnect($payload);
case NET_SSH2_MSG_IGNORE:
- $this->extra_packets++;
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_DEBUG:
- $this->extra_packets++;
$this->_string_shift($payload, 2);
if (strlen($payload) < 4) {
return false;
@@ -3807,7 +3899,7 @@ function _filter($payload, $skip_channel_filter)
case NET_SSH2_MSG_UNIMPLEMENTED:
return false;
case NET_SSH2_MSG_KEXINIT:
- // this is here for key re-exchanges after the initial key exchange
+ // this is here for server initiated key re-exchanges after the initial key exchange
if ($this->session_id !== false) {
$this->send_kex_first = false;
if (!$this->_key_exchange($payload)) {
@@ -3816,6 +3908,28 @@ function _filter($payload, $skip_channel_filter)
}
$payload = $this->_get_binary_packet($skip_channel_filter);
}
+ break;
+ case NET_SSH2_MSG_EXT_INFO:
+ $this->_string_shift($payload, 1);
+ if (strlen($payload) < 4) {
+ return false;
+ }
+ $nr_extensions = unpack('Nlength', $this->_string_shift($payload, 4));
+ for ($i = 0; $i < $nr_extensions['length']; $i++) {
+ if (strlen($payload) < 4) {
+ return false;
+ }
+ $temp = unpack('Nlength', $this->_string_shift($payload, 4));
+ $extension_name = $this->_string_shift($payload, $temp['length']);
+ if ($extension_name == 'server-sig-algs') {
+ if (strlen($payload) < 4) {
+ return false;
+ }
+ $temp = unpack('Nlength', $this->_string_shift($payload, 4));
+ $this->supported_private_key_algorithms = explode(',', $this->_string_shift($payload, $temp['length']));
+ }
+ }
+ $payload = $this->_get_binary_packet($skip_channel_filter);
}
// 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
@@ -4059,9 +4173,6 @@ function _get_channel_packet($client_channel, $skip_extended = false)
} else {
$response = $this->_get_binary_packet(true);
if ($response === true && $this->is_timeout) {
- if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) {
- $this->_close_channel($client_channel);
- }
return true;
}
if ($response === false) {
@@ -4352,6 +4463,10 @@ function _send_binary_packet($data, $logged = null)
$packet.= $hmac;
+ if (!$this->keyExchangeInProgress) {
+ $this->bytesTransferredSinceLastKEX+= strlen($packet);
+ }
+
$start = microtime(true);
$result = strlen($packet) == @fputs($this->fsock, $packet);
$stop = microtime(true);
@@ -4365,6 +4480,10 @@ function _send_binary_packet($data, $logged = null)
$this->last_packet = $current;
}
+ if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) {
+ $this->_key_exchange();
+ }
+
return $result;
}
@@ -4442,6 +4561,10 @@ function _append_log($message_number, $message)
$this->realtime_log_wrap = true;
}
fputs($this->realtime_log_file, $entry);
+ break;
+ case NET_SSH2_LOG_REALTIME_SIMPLE:
+ echo $message_number;
+ echo PHP_SAPI == 'cli' ? "\r\n" : '
';
}
}
@@ -5111,42 +5234,66 @@ function getAlgorithmsNegotiated()
*/
function setPreferredAlgorithms($methods)
{
+ $keys = array('client_to_server', 'server_to_client');
+
+ if (isset($methods['kex']) && is_string($methods['kex'])) {
+ $methods['kex'] = explode(',', $methods['kex']);
+ }
+
+ if (isset($methods['hostkey']) && is_string($methods['hostkey'])) {
+ $methods['hostkey'] = explode(',', $methods['hostkey']);
+ }
+
+ foreach ($keys as $key) {
+ if (isset($methods[$key])) {
+ $a = &$methods[$key];
+ if (isset($a['crypt']) && is_string($a['crypt'])) {
+ $a['crypt'] = explode(',', $a['crypt']);
+ }
+ if (isset($a['comp']) && is_string($a['comp'])) {
+ $a['comp'] = explode(',', $a['comp']);
+ }
+ if (isset($a['mac']) && is_string($a['mac'])) {
+ $a['mac'] = explode(',', $a['mac']);
+ }
+ }
+ }
+
$preferred = $methods;
if (isset($preferred['kex'])) {
$preferred['kex'] = array_intersect(
$preferred['kex'],
- $this->getSupportedKEXAlgorithms()
+ static::getSupportedKEXAlgorithms()
);
}
if (isset($preferred['hostkey'])) {
$preferred['hostkey'] = array_intersect(
$preferred['hostkey'],
- $this->getSupportedHostKeyAlgorithms()
+ static::getSupportedHostKeyAlgorithms()
);
}
- $keys = array('client_to_server', 'server_to_client');
foreach ($keys as $key) {
if (isset($preferred[$key])) {
$a = &$preferred[$key];
if (isset($a['crypt'])) {
$a['crypt'] = array_intersect(
$a['crypt'],
- $this->getSupportedEncryptionAlgorithms()
+ static::getSupportedEncryptionAlgorithms()
);
}
if (isset($a['comp'])) {
$a['comp'] = array_intersect(
$a['comp'],
- $this->getSupportedCompressionAlgorithms()
+ static::getSupportedCompressionAlgorithms()
);
}
if (isset($a['mac'])) {
$a['mac'] = array_intersect(
$a['mac'],
- $this->getSupportedMACAlgorithms()
+ static::getSupportedMACAlgorithms()
);
}
}
@@ -5526,4 +5673,12 @@ function disableSmartMFA()
{
$this->smartMFA = false;
}
+
+ /**
+ * How many bytes until the next key re-exchange?
+ */
+ function bytesUntilKeyReexchange($bytes)
+ {
+ $this->doKeyReexchangeAfterXBytes = $bytes;
+ }
}