Merge branch '3.0'

This commit is contained in:
terrafrost 2022-01-30 01:19:37 -06:00
commit 48259b20b3
10 changed files with 113 additions and 43 deletions

View File

@ -158,9 +158,9 @@ abstract class Strings
/** /**
* Create SSH2-style string * Create SSH2-style string
* *
* @param string[] ...$elements * @param string|int|float|array|bool ...$elements
* @access public * @access public
* @return mixed * @return string
*/ */
public static function packSSH2(...$elements) public static function packSSH2(...$elements)
{ {

View File

@ -123,6 +123,12 @@ abstract class AsymmetricKey
*/ */
private $comment; private $comment;
/**
* @param string $type
* @return string
*/
abstract public function toString($type, array $options = []);
/** /**
* The constructor * The constructor
*/ */
@ -245,7 +251,7 @@ abstract class AsymmetricKey
* @param string $type * @param string $type
* @param string $key * @param string $key
* @param string $password optional * @param string $password optional
* @return AsymmetricKey * @return static
*/ */
public static function loadFormat($type, $key, $password = false) public static function loadFormat($type, $key, $password = false)
{ {

View File

@ -213,6 +213,13 @@ abstract class SymmetricKey
self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)' self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)'
]; ];
/** @var string|null */
public $fixed;
/** @var string|null */
public $invocation_counter;
/** @var string|null */
public $name;
/** /**
* The Encryption Mode * The Encryption Mode
* *
@ -3412,4 +3419,4 @@ abstract class SymmetricKey
{ {
return array_flip(self::MODE_MAP)[$this->mode]; return array_flip(self::MODE_MAP)[$this->mode];
} }
} }

View File

@ -78,7 +78,7 @@ abstract class DH extends AsymmetricKey
* - a string (eg. diffie-hellman-group14-sha1) * - a string (eg. diffie-hellman-group14-sha1)
* *
* @access public * @access public
* @return \phpseclib3\Crypt\DH|bool * @return Parameters
*/ */
public static function createParameters(...$args) public static function createParameters(...$args)
{ {
@ -397,4 +397,4 @@ abstract class DH extends AsymmetricKey
$key = $type::saveParameters($this->prime, $this->base); $key = $type::saveParameters($this->prime, $this->base);
return self::load($key, 'PKCS1'); return self::load($key, 'PKCS1');
} }
} }

View File

@ -129,7 +129,7 @@ abstract class DSA extends AsymmetricKey
SSH DSA implementations only support keys with an N of 160. SSH DSA implementations only support keys with an N of 160.
puttygen let's you set the size of L (but not the size of N) and uses 2048 as the puttygen let's you set the size of L (but not the size of N) and uses 2048 as the
default L value. that's not really compliant with any of the FIPS standards, however, default L value. that's not really compliant with any of the FIPS standards, however,
for the purposes of maintaining compatibility with puttygen, we'll support it for the purposes of maintaining compatibility with puttygen, we'll support it
*/ */
//case ($L >= 512 || $L <= 1024) && (($L & 0x3F) == 0) && $N == 160: //case ($L >= 512 || $L <= 1024) && (($L & 0x3F) == 0) && $N == 160:
// FIPS 186-3 changed this as follows: // FIPS 186-3 changed this as follows:
@ -341,4 +341,4 @@ abstract class DSA extends AsymmetricKey
{ {
return $this->shortFormat; return $this->shortFormat;
} }
} }

View File

@ -69,6 +69,11 @@ class Hash
*/ */
const PADDING_SHAKE = 3; const PADDING_SHAKE = 3;
/** @var int|false */
public $etm;
/** @var string|false */
public $name;
/** /**
* Padding Type * Padding Type
* *

View File

@ -51,7 +51,7 @@ abstract class Random
} }
try { try {
return \random_bytes($length); return random_bytes($length);
} catch (\Exception $e) { } catch (\Exception $e) {
// random_compat will throw an Exception, which in PHP 5 does not implement Throwable // random_compat will throw an Exception, which in PHP 5 does not implement Throwable
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -116,6 +116,18 @@ class SFTP extends SSH2
*/ */
private $status_codes = []; private $status_codes = [];
/** @var array<int, string> */
private $attributes;
/** @var array<int, string> */
private $open_flags;
/** @var array<int, string> */
private $open_flags5;
/** @var array<int, string> */
private $file_types;
/** /**
* The Request ID * The Request ID
* *
@ -188,7 +200,7 @@ class SFTP extends SSH2
/** /**
* Current working directory * Current working directory
* *
* @var string * @var string|bool
* @see self::realpath() * @see self::realpath()
* @see self::chdir() * @see self::chdir()
* @access private * @access private
@ -242,7 +254,7 @@ class SFTP extends SSH2
* *
* @see self::__construct() * @see self::__construct()
* @see self::get() * @see self::get()
* @var array * @var int
* @access private * @access private
*/ */
private $max_sftp_packet; private $max_sftp_packet;
@ -781,7 +793,7 @@ class SFTP extends SSH2
/** /**
* Returns the current directory name * Returns the current directory name
* *
* @return string|false * @return string|bool
* @access public * @access public
*/ */
public function pwd() public function pwd()
@ -1226,7 +1238,7 @@ class SFTP extends SSH2
* $sftp->setListOrder(); * $sftp->setListOrder();
* Don't do any sort of sorting * Don't do any sort of sorting
* *
* @param string[] ...$args * @param string ...$args
* @access public * @access public
*/ */
public function setListOrder(...$args) public function setListOrder(...$args)
@ -1809,7 +1821,7 @@ class SFTP extends SSH2
$packet = Strings::packSSH2('s', $path); $packet = Strings::packSSH2('s', $path);
$packet.= $this->version >= 4 ? $packet.= $this->version >= 4 ?
pack('Ca*', NET_SFTP_TYPE_UNKNOWN, $attr) : pack('Ca*', NET_SFTP_TYPE_UNKNOWN, $attr) :
$atr; $attr;
$this->send_sftp_packet(NET_SFTP_SETSTAT, $packet); $this->send_sftp_packet(NET_SFTP_SETSTAT, $packet);
$i++; $i++;
@ -3131,7 +3143,7 @@ class SFTP extends SSH2
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.4 // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.4
// represents the number of bytes that the file consumes on the disk. will // represents the number of bytes that the file consumes on the disk. will
// usually be larger than the 'size' field // usually be larger than the 'size' field
list($attr['allocation-size']) = Strings::unpack('Q', $response); list($attr['allocation-size']) = Strings::unpackSSH2('Q', $response);
break; break;
case NET_SFTP_ATTR_TEXT_HINT: // 0x00000800 case NET_SFTP_ATTR_TEXT_HINT: // 0x00000800
// https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.10 // https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.10
@ -3146,7 +3158,7 @@ class SFTP extends SSH2
break; break;
case NET_SFTP_ATTR_LINK_COUNT: // 0x00002000 case NET_SFTP_ATTR_LINK_COUNT: // 0x00002000
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.12 // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.12
list($attr['link-count']) = Strings::unpackSS2('N', $response); list($attr['link-count']) = Strings::unpackSSH2('N', $response);
break; break;
case NET_SFTP_ATTR_UNTRANSLATED_NAME:// 0x00004000 case NET_SFTP_ATTR_UNTRANSLATED_NAME:// 0x00004000
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.13 // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.13

View File

@ -204,7 +204,7 @@ class SSH2
/** /**
* The Socket Object * The Socket Object
* *
* @var object * @var resource|closed-resource|null
* @access private * @access private
*/ */
public $fsock; public $fsock;
@ -711,7 +711,7 @@ class SSH2
* Interactive Buffer * Interactive Buffer
* *
* @see self::read() * @see self::read()
* @var array * @var string
* @access private * @access private
*/ */
private $interactiveBuffer = ''; private $interactiveBuffer = '';
@ -756,7 +756,7 @@ class SSH2
* Real-time log file pointer * Real-time log file pointer
* *
* @see self::_append_log() * @see self::_append_log()
* @var resource * @var resource|closed-resource
* @access private * @access private
*/ */
private $realtime_log_file; private $realtime_log_file;
@ -798,7 +798,7 @@ class SSH2
/** /**
* Time of first network activity * Time of first network activity
* *
* @var int * @var float
* @access private * @access private
*/ */
private $last_packet; private $last_packet;
@ -966,7 +966,7 @@ class SSH2
/** /**
* A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario * A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario
* *
* @var \phpseclib3\System\Ssh\Agent * @var Agent
* @access private * @access private
*/ */
private $agent; private $agent;
@ -975,7 +975,7 @@ class SSH2
* Connection storage to replicates ssh2 extension functionality: * Connection storage to replicates ssh2 extension functionality:
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples} * {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
* *
* @var SSH2[] * @var array<string, SSH2|\WeakReference<SSH2>>
*/ */
private static $connections; private static $connections;
@ -1063,7 +1063,7 @@ class SSH2
/** /**
* Decompression method * Decompression method
* *
* @var resource|object * @var int
* @access private * @access private
*/ */
private $decompress = self::NET_SSH2_COMPRESSION_NONE; private $decompress = self::NET_SSH2_COMPRESSION_NONE;
@ -1071,7 +1071,7 @@ class SSH2
/** /**
* Compression context * Compression context
* *
* @var int * @var resource|false|null
* @access private * @access private
*/ */
private $compress_context; private $compress_context;
@ -1200,7 +1200,13 @@ class SSH2
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY'] 31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY']
); );
self::$connections[$this->getResourceId()] = class_exists('WeakReference') ? \WeakReference::create($this) : $this; /**
* Typehint is required due to a bug in Psalm: https://github.com/vimeo/psalm/issues/7508
* @var \WeakReference<SSH2>|SSH2
*/
self::$connections[$this->getResourceId()] = class_exists('WeakReference')
? \WeakReference::create($this)
: $this;
if (is_resource($host)) { if (is_resource($host)) {
$this->fsock = $host; $this->fsock = $host;
@ -1411,7 +1417,7 @@ class SSH2
if (!$this->send_kex_first) { if (!$this->send_kex_first) {
$response = $this->get_binary_packet(); $response = $this->get_binary_packet();
if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) { if (is_bool($response) || !strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
$this->bitmap = 0; $this->bitmap = 0;
throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
} }
@ -1546,7 +1552,11 @@ class SSH2
$kexinit_payload_server = $this->get_binary_packet(); $kexinit_payload_server = $this->get_binary_packet();
if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) { if (
is_bool($kexinit_payload_server)
|| !strlen($kexinit_payload_server)
|| ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT
) {
$this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
} }
@ -2159,7 +2169,7 @@ class SSH2
* Login Helper * Login Helper
* *
* @param string $username * @param string $username
* @param string[] ...$args * @param string ...$args
* @return bool * @return bool
* @see self::_login_helper() * @see self::_login_helper()
* @access private * @access private
@ -2402,7 +2412,7 @@ class SSH2
* See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator. * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator.
* *
* @param string $username * @param string $username
* @param string $password * @param string|array $password
* @return bool * @return bool
* @access private * @access private
*/ */
@ -2425,7 +2435,7 @@ class SSH2
/** /**
* Handle the keyboard-interactive requests / responses. * Handle the keyboard-interactive requests / responses.
* *
* @param mixed[] ...$responses * @param string|array ...$responses
* @return bool * @return bool
* @throws \RuntimeException on connection error * @throws \RuntimeException on connection error
* @access private * @access private
@ -2719,12 +2729,12 @@ class SSH2
* In all likelihood, this is not a feature you want to be taking advantage of. * In all likelihood, this is not a feature you want to be taking advantage of.
* *
* @param string $command * @param string $command
* @param callback $callback * @return string|bool
* @return string * @psalm-return ($callback is callable ? bool : string|bool)
* @throws \RuntimeException on connection error * @throws \RuntimeException on connection error
* @access public * @access public
*/ */
public function exec($command, $callback = null) public function exec($command, callable $callback = null)
{ {
$this->curTimeout = $this->timeout; $this->curTimeout = $this->timeout;
$this->is_timeout = false; $this->is_timeout = false;
@ -3290,12 +3300,15 @@ class SSH2
* *
* @see self::_send_binary_packet() * @see self::_send_binary_packet()
* @param bool $skip_channel_filter * @param bool $skip_channel_filter
* @return string * @return bool|string
* @access private * @access private
*/ */
private function get_binary_packet($skip_channel_filter = false) private function get_binary_packet($skip_channel_filter = false)
{ {
if ($skip_channel_filter) { if ($skip_channel_filter) {
if (!is_resource($this->fsock)) {
throw new \InvalidArgumentException('fsock is not a resource.');
}
$read = [$this->fsock]; $read = [$this->fsock];
$write = $except = null; $write = $except = null;
@ -3314,9 +3327,6 @@ class SSH2
return true; return true;
} }
$read = [$this->fsock];
$write = $except = null;
$start = microtime(true); $start = microtime(true);
if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) { if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) {
@ -3590,7 +3600,7 @@ class SSH2
* @see self::_get_binary_packet() * @see self::_get_binary_packet()
* @param string $payload * @param string $payload
* @param bool $skip_channel_filter * @param bool $skip_channel_filter
* @return string * @return string|bool
* @access private * @access private
*/ */
private function filter($payload, $skip_channel_filter) private function filter($payload, $skip_channel_filter)
@ -3624,7 +3634,7 @@ class SSH2
} }
// 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 // 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 & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && !is_bool($payload) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
Strings::shift($payload, 1); Strings::shift($payload, 1);
list($this->banner_message) = Strings::unpackSSH2('s', $payload); list($this->banner_message) = Strings::unpackSSH2('s', $payload);
$payload = $this->get_binary_packet(); $payload = $this->get_binary_packet();
@ -3632,8 +3642,8 @@ class SSH2
// only called when we've already logged in // only called when we've already logged in
if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) { if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
if ($payload === true) { if (is_bool($payload)) {
return true; return $payload;
} }
switch (ord($payload[0])) { switch (ord($payload[0])) {
@ -4364,7 +4374,7 @@ class SSH2
} }
$this->bitmap = 0; $this->bitmap = 0;
if (is_resource($this->fsock) && get_resource_type($this->fsock) == 'stream') { if (is_resource($this->fsock) && get_resource_type($this->fsock) === 'stream') {
fclose($this->fsock); fclose($this->fsock);
} }
@ -5115,11 +5125,12 @@ class SSH2
/** /**
* Return all excising connections * Return all excising connections
* *
* @return SSH2[] * @return array<string, SSH2>
*/ */
public static function getConnections() public static function getConnections()
{ {
if (!class_exists('WeakReference')) { if (!class_exists('WeakReference')) {
/** @var array<string, SSH2> */
return self::$connections; return self::$connections;
} }
$temp = []; $temp = [];

29
psalm.xml Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0"?>
<psalm
errorLevel="6"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedPsalmSuppress="true"
sealAllMethods="true"
>
<projectFiles>
<directory name="phpseclib/Net"/>
</projectFiles>
<fileExtensions>
<extension name=".php"/>
</fileExtensions>
<issueHandlers>
<Trace>
<errorLevel type="error">
<directory name="."/>
</errorLevel>
</Trace>
<UndefinedConstant>
<errorLevel type="suppress">
<directory name="phpseclib/Net"/>
</errorLevel>
</UndefinedConstant>
</issueHandlers>
</psalm>