diff --git a/lam/lib/3rdParty/phpseclib/Crypt/AES.php b/lam/lib/3rdParty/phpseclib/Crypt/AES.php index cf8c050a..6b1f9daa 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/AES.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/AES.php @@ -19,7 +19,7 @@ * Here's a short example of how to use this library: * * - * @copyright MMVIII Jim Wigginton + * @copyright 2008 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -109,7 +109,7 @@ define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); /**#@+ * @access private - * @see Crypt_AES::Crypt_AES() + * @see Crypt_Base::Crypt_Base() */ /** * Toggles the internal implementation @@ -126,7 +126,6 @@ define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); * * @package Crypt_AES * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Crypt_AES extends Crypt_Rijndael @@ -140,35 +139,6 @@ class Crypt_AES extends Crypt_Rijndael */ var $const_namespace = 'AES'; - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_AES_MODE_ECB - * - * - CRYPT_AES_MODE_CBC - * - * - CRYPT_AES_MODE_CTR - * - * - CRYPT_AES_MODE_CFB - * - * - CRYPT_AES_MODE_OFB - * - * If not explictly set, CRYPT_AES_MODE_CBC will be used. - * - * @see Crypt_Rijndael::Crypt_Rijndael() - * @see Crypt_Base::Crypt_Base() - * @param optional Integer $mode - * @access public - */ - function Crypt_AES($mode = CRYPT_AES_MODE_CBC) - { - parent::Crypt_Rijndael($mode); - } - /** * Dummy function * @@ -182,4 +152,56 @@ class Crypt_AES extends Crypt_Rijndael { return; } + + /** + * Sets the key length + * + * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. + * + * @see Crypt_Rijndael:setKeyLength() + * @access public + * @param Integer $length + */ + function setKeyLength($length) + { + switch ($length) { + case 160: + $length = 192; + break; + case 224: + $length = 256; + } + parent::setKeyLength($length); + } + + /** + * Sets the key. + * + * Rijndael supports five different key lengths, AES only supports three. + * + * @see Crypt_Rijndael:setKey() + * @see setKeyLength() + * @access public + * @param String $key + */ + function setKey($key) + { + parent::setKey($key); + + if (!$this->explicit_key_length) { + $length = strlen($key); + switch (true) { + case $length <= 16: + $this->key_size = 16; + break; + case $length <= 24: + $this->key_size = 24; + break; + default: + $this->key_size = 32; + } + $this->_setupEngine(); + } + } } diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Base.php b/lam/lib/3rdParty/phpseclib/Crypt/Base.php index f288e79c..7ba61348 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Base.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Base.php @@ -47,9 +47,8 @@ * @package Crypt_Base * @author Jim Wigginton * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0.1 * @link http://phpseclib.sourceforge.net */ @@ -117,7 +116,6 @@ define('CRYPT_MODE_MCRYPT', 2); * @package Crypt_Base * @author Jim Wigginton * @author Hans-Juergen Petrich - * @version 1.0.0 * @access public */ class Crypt_Base @@ -279,7 +277,7 @@ class Crypt_Base * $buffer bytes > $cfb_init_len than * using the $ecb resource furthermore. * - * This value depends of the choosen cipher + * This value depends of the chosen cipher * and the time it would be needed for it's * initialization [by mcrypt_generic_init()] * which, typically, depends on the complexity @@ -438,9 +436,9 @@ class Crypt_Base * * - CRYPT_MODE_OFB * - * (or the alias constants of the choosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...) + * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...) * - * If not explictly set, CRYPT_MODE_CBC will be used. + * If not explicitly set, CRYPT_MODE_CBC will be used. * * @param optional Integer $mode * @access public @@ -500,7 +498,7 @@ class Crypt_Base /** * Sets the initialization vector. (optional) * - * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explictly set, it'll be assumed + * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed * to be all zero's. * * Note: Could, but not must, extend by the child Crypt_* class @@ -543,7 +541,7 @@ class Crypt_Base * Sets the password. * * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: - * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1: * $hash, $salt, $count, $dkLen * * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php @@ -553,6 +551,7 @@ class Crypt_Base * @see Crypt/Hash.php * @param String $password * @param optional String $method + * @return Boolean * @access public */ function setPassword($password, $method = 'pbkdf2') @@ -560,7 +559,7 @@ class Crypt_Base $key = ''; switch ($method) { - default: // 'pbkdf2' + default: // 'pbkdf2' or 'pbkdf1' $func_args = func_get_args(); // Hash function @@ -574,10 +573,34 @@ class Crypt_Base $count = isset($func_args[4]) ? $func_args[4] : 1000; // Keylength - $dkLen = isset($func_args[5]) ? $func_args[5] : $this->password_key_size; + if (isset($func_args[5])) { + $dkLen = $func_args[5]; + } else { + $dkLen = $method == 'pbkdf1' ? 2 * $this->password_key_size : $this->password_key_size; + } - // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable switch (true) { + case $method == 'pbkdf1': + if (!class_exists('Crypt_Hash')) { + include_once 'Crypt/Hash.php'; + } + $hashObj = new Crypt_Hash(); + $hashObj->setHash($hash); + if ($dkLen > $hashObj->getLength()) { + user_error('Derived key too long'); + return false; + } + $t = $password . $salt; + for ($i = 0; $i < $count; ++$i) { + $t = $hashObj->hash($t); + } + $key = substr($t, 0, $dkLen); + + $this->setKey(substr($key, 0, $dkLen >> 1)); + $this->setIV(substr($key, $dkLen >> 1)); + + return true; + // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable case !function_exists('hash_pbkdf2'): case !function_exists('hash_algos'): case !in_array($hash, hash_algos()): @@ -604,6 +627,8 @@ class Crypt_Base } $this->setKey($key); + + return true; } /** @@ -1446,7 +1471,7 @@ class Crypt_Base * - each time on _setup(), after(!) _setupKey() * * - * This ensures that _setupInlineCrypt() has allways a + * This ensures that _setupInlineCrypt() has always a * full ready2go initializated internal cipher $engine state * where, for example, the keys allready expanded, * keys/block_size calculated and such. diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php b/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php index dec28167..97584900 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php @@ -14,7 +14,7 @@ * Here's a short example of how to use this library: * * * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0 * @link http://phpseclib.sourceforge.net */ @@ -104,7 +103,7 @@ define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB); /**#@+ * @access private - * @see Crypt_Blowfish::Crypt_Blowfish() + * @see Crypt_Base::Crypt_Base() */ /** * Toggles the internal implementation @@ -122,7 +121,6 @@ define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); * @package Crypt_Blowfish * @author Jim Wigginton * @author Hans-Juergen Petrich - * @version 1.0 * @access public */ class Crypt_Blowfish extends Crypt_Base @@ -369,34 +367,6 @@ class Crypt_Blowfish extends Crypt_Base */ var $kl; - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_BLOWFISH_MODE_ECB - * - * - CRYPT_BLOWFISH_MODE_CBC - * - * - CRYPT_BLOWFISH_MODE_CTR - * - * - CRYPT_BLOWFISH_MODE_CFB - * - * - CRYPT_BLOWFISH_MODE_OFB - * - * If not explictly set, CRYPT_BLOWFISH_MODE_CBC will be used. - * - * @see Crypt_Base::Crypt_Base() - * @param optional Integer $mode - * @access public - */ - function Crypt_Blowfish($mode = CRYPT_BLOWFISH_MODE_CBC) - { - parent::Crypt_Base($mode); - } - /** * Sets the key. * diff --git a/lam/lib/3rdParty/phpseclib/Crypt/DES.php b/lam/lib/3rdParty/phpseclib/Crypt/DES.php index fcbf0199..f92f30b2 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/DES.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/DES.php @@ -16,7 +16,7 @@ * Here's a short example of how to use this library: * * - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -123,7 +123,7 @@ define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB); /**#@+ * @access private - * @see Crypt_DES::Crypt_DES() + * @see Crypt_Base::Crypt_Base() */ /** * Toggles the internal implementation @@ -140,7 +140,6 @@ define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); * * @package Crypt_DES * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Crypt_DES extends Crypt_Base @@ -662,34 +661,6 @@ class Crypt_DES extends Crypt_Base 0x00000820, 0x00020020, 0x08000000, 0x08020800 ); - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_DES_MODE_ECB - * - * - CRYPT_DES_MODE_CBC - * - * - CRYPT_DES_MODE_CTR - * - * - CRYPT_DES_MODE_CFB - * - * - CRYPT_DES_MODE_OFB - * - * If not explictly set, CRYPT_DES_MODE_CBC will be used. - * - * @see Crypt_Base::Crypt_Base() - * @param optional Integer $mode - * @access public - */ - function Crypt_DES($mode = CRYPT_DES_MODE_CBC) - { - parent::Crypt_Base($mode); - } - /** * Sets the key. * diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Hash.php b/lam/lib/3rdParty/phpseclib/Crypt/Hash.php index b156169d..4ab75b2d 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Hash.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Hash.php @@ -5,7 +5,7 @@ * * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following: * - * md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512 + * md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96 * * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to * the hash. If no valid algorithm is provided, sha1 will be used. @@ -18,7 +18,7 @@ * Here's a short example of how to use this library: * * - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -77,7 +77,6 @@ define('CRYPT_HASH_MODE_HASH', 3); * * @package Crypt_Hash * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Crypt_Hash @@ -208,6 +207,9 @@ class Crypt_Hash switch ($hash) { case 'md5-96': case 'sha1-96': + case 'sha256-96': + case 'sha512-96': + $hash = substr($hash, 0, -3); $this->l = 12; // 96 / 8 = 12 break; case 'md2': @@ -244,14 +246,12 @@ class Crypt_Hash case CRYPT_HASH_MODE_MHASH: switch ($hash) { case 'md5': - case 'md5-96': $this->hash = MHASH_MD5; break; case 'sha256': $this->hash = MHASH_SHA256; break; case 'sha1': - case 'sha1-96': default: $this->hash = MHASH_SHA1; } @@ -259,7 +259,6 @@ class Crypt_Hash case CRYPT_HASH_MODE_HASH: switch ($hash) { case 'md5': - case 'md5-96': $this->hash = 'md5'; return; case 'md2': @@ -269,7 +268,6 @@ class Crypt_Hash $this->hash = $hash; return; case 'sha1': - case 'sha1-96': default: $this->hash = 'sha1'; } @@ -282,7 +280,6 @@ class Crypt_Hash $this->hash = array($this, '_md2'); break; case 'md5': - case 'md5-96': $this->b = 64; $this->hash = array($this, '_md5'); break; @@ -296,7 +293,6 @@ class Crypt_Hash $this->hash = array($this, '_sha512'); break; case 'sha1': - case 'sha1-96': default: $this->b = 64; $this->hash = array($this, '_sha1'); diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RC2.php b/lam/lib/3rdParty/phpseclib/Crypt/RC2.php index 3436c34b..f98dc2cc 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/RC2.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/RC2.php @@ -14,7 +14,7 @@ * Here's a short example of how to use this library: * * > 16; - if ($j == $limit) { - if ($limit == 64) { + if ($j === $limit) { + if ($limit === 64) { break; } @@ -490,8 +489,8 @@ class Crypt_RC2 extends Crypt_Base $r0 = ($r0 | ($r0 << 16)) >> 1; $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF; - if ($j == $limit) { - if (!$limit) { + if ($j === $limit) { + if ($limit === 0) { break; } @@ -582,8 +581,8 @@ class Crypt_RC2 extends Crypt_Base ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; $r3 |= $r3 >> 16;'; - if ($j == $limit) { - if ($limit == 64) { + if ($j === $limit) { + if ($limit === 64) { break; } @@ -620,8 +619,8 @@ class Crypt_RC2 extends Crypt_Base $r0 = ($r0 - ' . $keys[--$j] . ' - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;'; - if ($j == $limit) { - if (!$limit) { + if ($j === $limit) { + if ($limit === 0) { break; } diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RC4.php b/lam/lib/3rdParty/phpseclib/Crypt/RC4.php index d062be25..d5eda8c3 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/RC4.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/RC4.php @@ -18,7 +18,7 @@ * Here's a short example of how to use this library: * * - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -96,7 +96,6 @@ define('CRYPT_RC4_DECRYPT', 1); * * @package Crypt_RC4 * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Crypt_RC4 extends Crypt_Base @@ -241,7 +240,7 @@ class Crypt_RC4 extends Crypt_Base * Decrypts a message. * * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). - * Atleast if the continuous buffer is disabled. + * At least if the continuous buffer is disabled. * * @see Crypt_Base::encrypt() * @see Crypt_RC4::_crypt() @@ -268,10 +267,7 @@ class Crypt_RC4 extends Crypt_Base { $key = $this->key; $keyLength = strlen($key); - $keyStream = array(); - for ($i = 0; $i < 256; $i++) { - $keyStream[$i] = $i; - } + $keyStream = range(0, 255); $j = 0; for ($i = 0; $i < 256; $i++) { $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; @@ -325,7 +321,7 @@ class Crypt_RC4 extends Crypt_Base $keyStream[$i] = $ksj; $keyStream[$j] = $ksi; - $text[$k] = chr(ord($text[$k]) ^ $keyStream[($ksj + $ksi) & 255]); + $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]); } return $text; diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RSA.php b/lam/lib/3rdParty/phpseclib/Crypt/RSA.php index feb887c7..53f94354 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/RSA.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/RSA.php @@ -8,7 +8,7 @@ * Here's an example of how to encrypt and decrypt text with this library: * * createKey()); @@ -26,7 +26,7 @@ * Here's an example of how to create signatures and verify signatures with this library: * * createKey()); @@ -62,7 +62,7 @@ * @category Crypt * @package Crypt_RSA * @author Jim Wigginton - * @copyright MMIX Jim Wigginton + * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -104,7 +104,7 @@ define('CRYPT_RSA_ENCRYPTION_OAEP', 1); * Use PKCS#1 padding. * * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards - * compatability with protocols (like SSH-1) written before OAEP's introduction. + * compatibility with protocols (like SSH-1) written before OAEP's introduction. */ define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); /**#@-*/ @@ -128,7 +128,7 @@ define('CRYPT_RSA_SIGNATURE_PSS', 1); * Use the PKCS#1 scheme by default. * * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards - * compatability with protocols (like SSH-2) written before PSS's introduction. + * compatibility with protocols (like SSH-2) written before PSS's introduction. */ define('CRYPT_RSA_SIGNATURE_PKCS1', 2); /**#@-*/ @@ -140,15 +140,23 @@ define('CRYPT_RSA_SIGNATURE_PKCS1', 2); /** * ASN1 Integer */ -define('CRYPT_RSA_ASN1_INTEGER', 2); +define('CRYPT_RSA_ASN1_INTEGER', 2); /** * ASN1 Bit String */ -define('CRYPT_RSA_ASN1_BITSTRING', 3); +define('CRYPT_RSA_ASN1_BITSTRING', 3); +/** + * ASN1 Octet String + */ +define('CRYPT_RSA_ASN1_OCTETSTRING', 4); +/** + * ASN1 Object Identifier + */ +define('CRYPT_RSA_ASN1_OBJECT', 6); /** * ASN1 Sequence (with the constucted bit set) */ -define('CRYPT_RSA_ASN1_SEQUENCE', 48); +define('CRYPT_RSA_ASN1_SEQUENCE', 48); /**#@-*/ /**#@+ @@ -191,6 +199,10 @@ define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1); * XML formatted private key */ define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2); +/** + * PKCS#8 formatted private key + */ +define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 3); /**#@-*/ /**#@+ @@ -216,7 +228,14 @@ define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3); * PKCS#1 formatted public key (raw) * * Used by File/X509.php + * + * Has the following header: + * + * -----BEGIN RSA PUBLIC KEY----- + * + * Analogous to ssh-keygen's pem format (as specified by -m) */ +define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4); define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4); /** * XML formatted public key @@ -232,8 +251,16 @@ define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6); * PKCS#1 formatted public key (encapsulated) * * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) + * + * Has the following header: + * + * -----BEGIN PUBLIC KEY----- + * + * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 + * is specific to private keys it's basically creating a DER-encoded wrapper + * for keys. This just extends that same concept to public keys (much like ssh-keygen) */ -define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7); +define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7); /**#@-*/ /** @@ -241,7 +268,6 @@ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7); * * @package Crypt_RSA * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Crypt_RSA @@ -276,7 +302,7 @@ class Crypt_RSA * @var Integer * @access public */ - var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1; + var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8; /** * Modulus (ie. n) @@ -467,18 +493,21 @@ class Crypt_RSA $this->configFile = CRYPT_RSA_OPENSSL_CONFIG; if ( !defined('CRYPT_RSA_MODE') ) { - // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, - // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger - // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. - if ( defined('MATH_BIGINTEGER_OPENSSL_DISABLE') ) { - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); - } - - switch ( !defined('CRYPT_RSA_MODE') ) { // ie. only run this if the above didn't set CRYPT_RSA_MODE already + switch (true) { + // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, + // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger + // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. + case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'): + define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); + break; + // openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0 + case !function_exists('openssl_pkey_get_details'): + define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); + break; case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile): // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work ob_start(); - phpinfo(); + @phpinfo(); $content = ob_get_contents(); ob_end_clean(); @@ -486,9 +515,16 @@ class Crypt_RSA $versions = array(); if (!empty($matches[1])) { - for ($i = 0; $i < count($matches[1]); $i++) { - $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); - } + for ($i = 0; $i < count($matches[1]); $i++) { + $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + + // Remove letter part in OpenSSL version + if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { + $versions[$matches[1][$i]] = $fullVersion; + } else { + $versions[$matches[1][$i]] = $m[0]; + } + } } // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ @@ -503,7 +539,7 @@ class Crypt_RSA define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); } break; - case true: + default: define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); } } @@ -713,17 +749,18 @@ class Crypt_RSA */ function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) { + $signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML; $num_primes = count($primes); $raw = array( 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi - 'modulus' => $n->toBytes(true), - 'publicExponent' => $e->toBytes(true), - 'privateExponent' => $d->toBytes(true), - 'prime1' => $primes[1]->toBytes(true), - 'prime2' => $primes[2]->toBytes(true), - 'exponent1' => $exponents[1]->toBytes(true), - 'exponent2' => $exponents[2]->toBytes(true), - 'coefficient' => $coefficients[2]->toBytes(true) + 'modulus' => $n->toBytes($signed), + 'publicExponent' => $e->toBytes($signed), + 'privateExponent' => $d->toBytes($signed), + 'prime1' => $primes[1]->toBytes($signed), + 'prime2' => $primes[2]->toBytes($signed), + 'exponent1' => $exponents[1]->toBytes($signed), + 'exponent2' => $exponents[2]->toBytes($signed), + 'coefficient' => $coefficients[2]->toBytes($signed) ); // if the format in question does not support multi-prime rsa and multi-prime rsa was used, @@ -756,8 +793,8 @@ class Crypt_RSA strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus'] ); $source = pack('Na*Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, - strlen($this->comment), $this->comment, strlen($public), $public + strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, + strlen($this->comment), $this->comment, strlen($public), $public ); $public = base64_encode($public); $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; @@ -829,6 +866,52 @@ class Crypt_RSA $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); + if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) { + $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA + $RSAPrivateKey = pack('Ca*a*Ca*a*', + CRYPT_RSA_ASN1_INTEGER, "\01\00", $rsaOID, 4, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey + ); + $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); + if (!empty($this->password) || is_string($this->password)) { + $salt = crypt_random_string(8); + $iterationCount = 2048; + + if (!class_exists('Crypt_DES')) { + include_once 'Crypt/DES.php'; + } + $crypto = new Crypt_DES(); + $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); + $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey); + + $parameters = pack('Ca*a*Ca*N', + CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($salt)), $salt, + CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(4), $iterationCount + ); + $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03"; + + $encryptionAlgorithm = pack('Ca*a*Ca*a*', + CRYPT_RSA_ASN1_OBJECT, $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), $pbeWithMD5AndDES_CBC, + CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($parameters)), $parameters + ); + + $RSAPrivateKey = pack('Ca*a*Ca*a*', + CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($encryptionAlgorithm)), $encryptionAlgorithm, + CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey + ); + + $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); + + $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" . + chunk_split(base64_encode($RSAPrivateKey), 64) . + '-----END ENCRYPTED PRIVATE KEY-----'; + } else { + $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" . + chunk_split(base64_encode($RSAPrivateKey), 64) . + '-----END PRIVATE KEY-----'; + } + return $RSAPrivateKey; + } + if (!empty($this->password) || is_string($this->password)) { $iv = crypt_random_string(8); $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key @@ -866,8 +949,10 @@ class Crypt_RSA */ function _convertPublicKey($n, $e) { - $modulus = $n->toBytes(true); - $publicExponent = $e->toBytes(true); + $signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML; + + $modulus = $n->toBytes($signed); + $publicExponent = $e->toBytes($signed); switch ($this->publicKeyFormat) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: @@ -903,7 +988,11 @@ class Crypt_RSA $components['modulus'], $components['publicExponent'] ); - if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { + if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) { + $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" . + chunk_split(base64_encode($RSAPublicKey), 64) . + '-----END RSA PUBLIC KEY-----'; + } else { // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption. $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $RSAPublicKey = chr(0) . $RSAPublicKey; @@ -912,11 +1001,11 @@ class Crypt_RSA $RSAPublicKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey ); - } - $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . - chunk_split(base64_encode($RSAPublicKey), 64) . - '-----END PUBLIC KEY-----'; + $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . + chunk_split(base64_encode($RSAPublicKey), 64) . + '-----END PUBLIC KEY-----'; + } return $RSAPublicKey; } @@ -972,6 +1061,7 @@ class Crypt_RSA } return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false; case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: + case CRYPT_RSA_PRIVATE_FORMAT_PKCS8: case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to @@ -1062,7 +1152,9 @@ class Crypt_RSA 7:d=1 hl=2 l= 13 cons: SEQUENCE 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 20:d=2 hl=2 l= 0 prim: NULL - 22:d=1 hl=4 l= 609 prim: OCTET STRING */ + 22:d=1 hl=4 l= 609 prim: OCTET STRING + + ie. PKCS8 keys*/ if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") { $this->_string_shift($key, 3); @@ -1070,6 +1162,52 @@ class Crypt_RSA } if ($tag == CRYPT_RSA_ASN1_SEQUENCE) { + $temp = $this->_string_shift($key, $this->_decodeLength($key)); + if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_OBJECT) { + return false; + } + $length = $this->_decodeLength($temp); + switch ($this->_string_shift($temp, $length)) { + case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption + break; + case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC + /* + PBEParameter ::= SEQUENCE { + salt OCTET STRING (SIZE(8)), + iterationCount INTEGER } + */ + if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_SEQUENCE) { + return false; + } + if ($this->_decodeLength($temp) != strlen($temp)) { + return false; + } + $this->_string_shift($temp); // assume it's an octet string + $salt = $this->_string_shift($temp, $this->_decodeLength($temp)); + if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_INTEGER) { + return false; + } + $this->_decodeLength($temp); + list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT)); + $this->_string_shift($key); // assume it's an octet string + $length = $this->_decodeLength($key); + if (strlen($key) != $length) { + return false; + } + + if (!class_exists('Crypt_DES')) { + include_once 'Crypt/DES.php'; + } + $crypto = new Crypt_DES(); + $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); + $key = $crypto->decrypt($key); + if ($key === false) { + return false; + } + return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1); + default: + return false; + } /* intended for keys for which OpenSSL's asn1parse returns the following: 0:d=0 hl=4 l= 290 cons: SEQUENCE @@ -1077,7 +1215,6 @@ class Crypt_RSA 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING */ - $this->_string_shift($key, $this->_decodeLength($key)); $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of @@ -1479,6 +1616,19 @@ class Crypt_RSA $this->publicExponent = false; } + switch ($type) { + case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: + case CRYPT_RSA_PUBLIC_FORMAT_RAW: + $this->setPublicKey(); + break; + case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: + switch (true) { + case strpos($key, '-BEGIN PUBLIC KEY-') !== false: + case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false: + $this->setPublicKey(); + } + } + return true; } @@ -1505,7 +1655,9 @@ class Crypt_RSA * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public - * exponent this won't work unless you manually add the public exponent. + * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used + * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being + * public. * * Do note that when a new key is loaded the index will be cleared. * @@ -1561,6 +1713,40 @@ class Crypt_RSA return true; } + /** + * Defines the private key + * + * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force + * phpseclib to treat the key as a private key. This function will do that. + * + * Do note that when a new key is loaded the index will be cleared. + * + * Returns true on success, false on failure + * + * @see getPublicKey() + * @access public + * @param String $key optional + * @param Integer $type optional + * @return Boolean + */ + function setPrivateKey($key = false, $type = false) + { + if ($key === false && !empty($this->publicExponent)) { + unset($this->publicExponent); + return true; + } + + $rsa = new Crypt_RSA(); + if (!$rsa->loadKey($key, $type)) { + return false; + } + unset($rsa->publicExponent); + + // don't overwrite the old key if the new key is invalid + $this->loadKey($rsa); + return true; + } + /** * Returns the public key * @@ -1573,7 +1759,7 @@ class Crypt_RSA * @param String $key * @param Integer $type optional */ - function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) + function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8) { if (empty($this->modulus) || empty($this->publicExponent)) { return false; @@ -1620,7 +1806,7 @@ class Crypt_RSA * @param String $key * @param Integer $type optional */ - function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) + function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8) { if (empty($this->modulus) || empty($this->exponent)) { return false; @@ -2275,11 +2461,11 @@ class Crypt_RSA * * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. * - * For compatability purposes, this function departs slightly from the description given in RFC3447. + * For compatibility purposes, this function departs slightly from the description given in RFC3447. * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed - * to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the + * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the * second byte is 2 or less. If it is, we'll accept the decrypted string as valid. * * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Random.php b/lam/lib/3rdParty/phpseclib/Crypt/Random.php index 977ec797..918b97bf 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Random.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Random.php @@ -3,12 +3,15 @@ /** * Random Number Generator * + * The idea behind this function is that it can be easily replaced with your own crypt_random_string() + * function. eg. maybe you have a better source of entropy for creating the initial states or whatever. + * * PHP versions 4 and 5 * * Here's a short example of how to use this library: * * @@ -35,181 +38,210 @@ * @category Crypt * @package Crypt_Random * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ -/** - * "Is Windows" test - * - * @access private - */ -define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); +// laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently, +// have phpseclib as a requirement as well. if you're developing such a program you may encounter +// a "Cannot redeclare crypt_random_string()" error. +if (!function_exists('crypt_random_string')) { + /** + * "Is Windows" test + * + * @access private + */ + define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); -/** - * Generate a random string. - * - * Although microoptimizations are generally discouraged as they impair readability this function is ripe with - * microoptimizations because this function has the potential of being called a huge number of times. - * eg. for RSA key generation. - * - * @param Integer $length - * @return String - * @access public - */ -function crypt_random_string($length) -{ - if (CRYPT_RANDOM_IS_WINDOWS) { - // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call. - // ie. class_alias is a function that was introduced in PHP 5.3 - if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { - return mcrypt_create_iv($length); - } - // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was, - // to quote , "possible blocking behavior". as of 5.3.4 - // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both - // call php_win32_get_random_bytes(): - // - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008 - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392 - // - // php_win32_get_random_bytes() is defined thusly: - // - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80 - // - // we're calling it, all the same, in the off chance that the mcrypt extension is not available - if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) { - return openssl_random_pseudo_bytes($length); - } - } else { - // method 1. the fastest - if (function_exists('openssl_random_pseudo_bytes')) { - return openssl_random_pseudo_bytes($length); - } - // method 2 - static $fp = true; - if ($fp === true) { - // warning's will be output unles the error suppression operator is used. errors such as - // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc. - $fp = @fopen('/dev/urandom', 'rb'); - } - if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource() - return fread($fp, $length); - } - // method 3. pretty much does the same thing as method 2 per the following url: - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391 - // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're - // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir - // restrictions or some such - if (function_exists('mcrypt_create_iv')) { - return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); - } - } - // at this point we have no choice but to use a pure-PHP CSPRNG - - // cascade entropy across multiple PHP instances by fixing the session and collecting all - // environmental variables, including the previous session data and the current session - // data. - // - // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively) - // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but - // PHP isn't low level to be able to use those as sources and on a web server there's not likely - // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use - // however. a ton of people visiting the website. obviously you don't want to base your seeding - // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled - // by the user and (2) this isn't just looking at the data sent by the current user - it's based - // on the data sent by all users. one user requests the page and a hash of their info is saved. - // another user visits the page and the serialization of their data is utilized along with the - // server envirnment stuff and a hash of the previous http request data (which itself utilizes - // a hash of the session data before that). certainly an attacker should be assumed to have - // full control over his own http requests. he, however, is not going to have control over - // everyone's http requests. - static $crypto = false, $v; - if ($crypto === false) { - // save old session data - $old_session_id = session_id(); - $old_use_cookies = ini_get('session.use_cookies'); - $old_session_cache_limiter = session_cache_limiter(); - $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false; - if ($old_session_id != '') { - session_write_close(); - } - - session_id(1); - ini_set('session.use_cookies', 0); - session_cache_limiter(''); - session_start(); - - $v = $seed = $_SESSION['seed'] = pack('H*', sha1( - serialize($_SERVER) . - serialize($_POST) . - serialize($_GET) . - serialize($_COOKIE) . - serialize($GLOBALS) . - serialize($_SESSION) . - serialize($_OLD_SESSION) - )); - if (!isset($_SESSION['count'])) { - $_SESSION['count'] = 0; - } - $_SESSION['count']++; - - session_write_close(); - - // restore old session data - if ($old_session_id != '') { - session_id($old_session_id); - session_start(); - ini_set('session.use_cookies', $old_use_cookies); - session_cache_limiter($old_session_cache_limiter); + /** + * Generate a random string. + * + * Although microoptimizations are generally discouraged as they impair readability this function is ripe with + * microoptimizations because this function has the potential of being called a huge number of times. + * eg. for RSA key generation. + * + * @param Integer $length + * @return String + * @access public + */ + function crypt_random_string($length) + { + if (CRYPT_RANDOM_IS_WINDOWS) { + // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call. + // ie. class_alias is a function that was introduced in PHP 5.3 + if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { + return mcrypt_create_iv($length); + } + // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was, + // to quote , "possible blocking behavior". as of 5.3.4 + // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both + // call php_win32_get_random_bytes(): + // + // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008 + // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392 + // + // php_win32_get_random_bytes() is defined thusly: + // + // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80 + // + // we're calling it, all the same, in the off chance that the mcrypt extension is not available + if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) { + return openssl_random_pseudo_bytes($length); + } } else { - if ($_OLD_SESSION !== false) { - $_SESSION = $_OLD_SESSION; - unset($_OLD_SESSION); - } else { - unset($_SESSION); + // method 1. the fastest + if (function_exists('openssl_random_pseudo_bytes')) { + return openssl_random_pseudo_bytes($length); + } + // method 2 + static $fp = true; + if ($fp === true) { + // warning's will be output unles the error suppression operator is used. errors such as + // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc. + $fp = @fopen('/dev/urandom', 'rb'); + } + if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource() + return fread($fp, $length); + } + // method 3. pretty much does the same thing as method 2 per the following url: + // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391 + // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're + // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir + // restrictions or some such + if (function_exists('mcrypt_create_iv')) { + return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); } } + // at this point we have no choice but to use a pure-PHP CSPRNG - // in SSH2 a shared secret and an exchange hash are generated through the key exchange process. - // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C. - // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the - // original hash and the current hash. we'll be emulating that. for more info see the following URL: + // cascade entropy across multiple PHP instances by fixing the session and collecting all + // environmental variables, including the previous session data and the current session + // data. // - // http://tools.ietf.org/html/rfc4253#section-7.2 - // - // see the is_string($crypto) part for an example of how to expand the keys - $key = pack('H*', sha1($seed . 'A')); - $iv = pack('H*', sha1($seed . 'C')); + // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively) + // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but + // PHP isn't low level to be able to use those as sources and on a web server there's not likely + // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use + // however, a ton of people visiting the website. obviously you don't want to base your seeding + // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled + // by the user and (2) this isn't just looking at the data sent by the current user - it's based + // on the data sent by all users. one user requests the page and a hash of their info is saved. + // another user visits the page and the serialization of their data is utilized along with the + // server envirnment stuff and a hash of the previous http request data (which itself utilizes + // a hash of the session data before that). certainly an attacker should be assumed to have + // full control over his own http requests. he, however, is not going to have control over + // everyone's http requests. + static $crypto = false, $v; + if ($crypto === false) { + // save old session data + $old_session_id = session_id(); + $old_use_cookies = ini_get('session.use_cookies'); + $old_session_cache_limiter = session_cache_limiter(); + $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false; + if ($old_session_id != '') { + session_write_close(); + } - // ciphers are used as per the nist.gov link below. also, see this link: - // - // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives - switch (true) { - case class_exists('Crypt_AES'): - $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); - break; - case class_exists('Crypt_TripleDES'): - $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); - break; - case class_exists('Crypt_DES'): - $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); - break; - case class_exists('Crypt_RC4'): - $crypto = new Crypt_RC4(); - break; - default: - $crypto = $seed; - return crypt_random_string($length); + session_id(1); + ini_set('session.use_cookies', 0); + session_cache_limiter(''); + session_start(); + + $v = $seed = $_SESSION['seed'] = pack('H*', sha1( + serialize($_SERVER) . + serialize($_POST) . + serialize($_GET) . + serialize($_COOKIE) . + serialize($GLOBALS) . + serialize($_SESSION) . + serialize($_OLD_SESSION) + )); + if (!isset($_SESSION['count'])) { + $_SESSION['count'] = 0; + } + $_SESSION['count']++; + + session_write_close(); + + // restore old session data + if ($old_session_id != '') { + session_id($old_session_id); + session_start(); + ini_set('session.use_cookies', $old_use_cookies); + session_cache_limiter($old_session_cache_limiter); + } else { + if ($_OLD_SESSION !== false) { + $_SESSION = $_OLD_SESSION; + unset($_OLD_SESSION); + } else { + unset($_SESSION); + } + } + + // in SSH2 a shared secret and an exchange hash are generated through the key exchange process. + // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C. + // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the + // original hash and the current hash. we'll be emulating that. for more info see the following URL: + // + // http://tools.ietf.org/html/rfc4253#section-7.2 + // + // see the is_string($crypto) part for an example of how to expand the keys + $key = pack('H*', sha1($seed . 'A')); + $iv = pack('H*', sha1($seed . 'C')); + + // ciphers are used as per the nist.gov link below. also, see this link: + // + // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives + switch (true) { + case phpseclib_resolve_include_path('Crypt/AES.php'): + if (!class_exists('Crypt_AES')) { + include_once 'AES.php'; + } + $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); + break; + case phpseclib_resolve_include_path('Crypt/Twofish.php'): + if (!class_exists('Crypt_Twofish')) { + include_once 'Twofish.php'; + } + $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); + break; + case phpseclib_resolve_include_path('Crypt/Blowfish.php'): + if (!class_exists('Crypt_Blowfish')) { + include_once 'Blowfish.php'; + } + $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); + break; + case phpseclib_resolve_include_path('Crypt/TripleDES.php'): + if (!class_exists('Crypt_TripleDES')) { + include_once 'TripleDES.php'; + } + $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); + break; + case phpseclib_resolve_include_path('Crypt/DES.php'): + if (!class_exists('Crypt_DES')) { + include_once 'DES.php'; + } + $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); + break; + case phpseclib_resolve_include_path('Crypt/RC4.php'): + if (!class_exists('Crypt_RC4')) { + include_once 'RC4.php'; + } + $crypto = new Crypt_RC4(); + break; + default: + user_error('crypt_random_string requires at least one symmetric cipher be loaded'); + return false; + } + + $crypto->setKey($key); + $crypto->setIV($iv); + $crypto->enableContinuousBuffer(); } - $crypto->setKey($key); - $crypto->setIV($iv); - $crypto->enableContinuousBuffer(); - } + //return $crypto->encrypt(str_repeat("\0", $length)); - if (is_string($crypto)) { // the following is based off of ANSI X9.31: // // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf @@ -218,29 +250,51 @@ function crypt_random_string($length) // // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c // (do a search for "ANS X9.31 A.2.4") - // - // ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see - // later on in the code) but if they're not we'll use sha1 $result = ''; - while (strlen($result) < $length) { // each loop adds 20 bytes - // microtime() isn't packed as "densely" as it could be but then neither is that the idea. - // the idea is simply to ensure that each "block" has a unique element to it. - $i = pack('H*', sha1(microtime())); - $r = pack('H*', sha1($i ^ $v)); - $v = pack('H*', sha1($r ^ $i)); + while (strlen($result) < $length) { + $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21 + $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20 + $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20 $result.= $r; } return substr($result, 0, $length); } - - //return $crypto->encrypt(str_repeat("\0", $length)); - - $result = ''; - while (strlen($result) < $length) { - $i = $crypto->encrypt(microtime()); - $r = $crypto->encrypt($i ^ $v); - $v = $crypto->encrypt($r ^ $i); - $result.= $r; - } - return substr($result, 0, $length); +} + +if (!function_exists('phpseclib_resolve_include_path')) { + /** + * Resolve filename against the include path. + * + * Wrapper around stream_resolve_include_path() (which was introduced in + * PHP 5.3.2) with fallback implementation for earlier PHP versions. + * + * @param string $filename + * @return mixed Filename (string) on success, false otherwise. + * @access public + */ + function phpseclib_resolve_include_path($filename) + { + if (function_exists('stream_resolve_include_path')) { + return stream_resolve_include_path($filename); + } + + // handle non-relative paths + if (file_exists($filename)) { + return realpath($filename); + } + + $paths = PATH_SEPARATOR == ':' ? + preg_split('#(? * - * @copyright MMVIII Jim Wigginton + * @copyright 2008 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -120,7 +120,7 @@ define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB); /**#@+ * @access private - * @see Crypt_Rijndael::Crypt_Rijndael() + * @see Crypt_Base::Crypt_Base() */ /** * Toggles the internal implementation @@ -137,7 +137,6 @@ define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); * * @package Crypt_Rijndael * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Crypt_Rijndael extends Crypt_Base @@ -167,7 +166,7 @@ class Crypt_Rijndael extends Crypt_Base * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not. * Crypt_Rijndael determines automatically whether mcrypt is useable * or not for the current $block_size/$key_size. - * In case of, $cipher_name_mcrypt will be set dynamicaly at run time accordingly. + * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly. * * @see Crypt_Base::cipher_name_mcrypt * @see Crypt_Base::engine @@ -676,34 +675,6 @@ class Crypt_Rijndael extends Crypt_Base 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D ); - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_RIJNDAEL_MODE_ECB - * - * - CRYPT_RIJNDAEL_MODE_CBC - * - * - CRYPT_RIJNDAEL_MODE_CTR - * - * - CRYPT_RIJNDAEL_MODE_CFB - * - * - CRYPT_RIJNDAEL_MODE_OFB - * - * If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. - * - * @see Crypt_Base::Crypt_Base() - * @param optional Integer $mode - * @access public - */ - function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) - { - parent::Crypt_Base($mode); - } - /** * Sets the key. * @@ -731,9 +702,15 @@ class Crypt_Rijndael extends Crypt_Base case $length <= 16: $this->key_size = 16; break; + case $length <= 20: + $this->key_size = 20; + break; case $length <= 24: $this->key_size = 24; break; + case $length <= 28: + $this->key_size = 28; + break; default: $this->key_size = 32; } @@ -755,7 +732,7 @@ class Crypt_Rijndael extends Crypt_Base * you should not setKeyLength(160) or setKeyLength(224). * * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use - * the mcrypt php extention, even if available. + * the mcrypt php extension, even if available. * This results then in slower encryption. * * @access public diff --git a/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php b/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php index 21318209..06ea09b1 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php @@ -10,7 +10,7 @@ * Here's a short example of how to use this library: * * - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -78,7 +78,6 @@ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); * * @package Crypt_TripleDES * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Crypt_TripleDES extends Crypt_DES @@ -180,7 +179,7 @@ class Crypt_TripleDES extends Crypt_DES * * - CRYPT_DES_MODE_3CBC * - * If not explictly set, CRYPT_DES_MODE_CBC will be used. + * If not explicitly set, CRYPT_DES_MODE_CBC will be used. * * @see Crypt_DES::Crypt_DES() * @see Crypt_Base::Crypt_Base() @@ -193,7 +192,7 @@ class Crypt_TripleDES extends Crypt_DES // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC // and additional flag us internally as 3CBC case CRYPT_DES_MODE_3CBC: - parent::Crypt_DES(CRYPT_DES_MODE_CBC); + parent::Crypt_Base(CRYPT_DES_MODE_CBC); $this->mode_3cbc = true; // This three $des'es will do the 3CBC work (if $key > 64bits) @@ -210,14 +209,14 @@ class Crypt_TripleDES extends Crypt_DES break; // If not 3CBC, we init as usual default: - parent::Crypt_DES($mode); + parent::Crypt_Base($mode); } } /** * Sets the initialization vector. (optional) * - * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed + * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed * to be all zero's. * * @see Crypt_Base::setIV() @@ -289,8 +288,12 @@ class Crypt_TripleDES extends Crypt_DES // if the key is smaller then 8, do what we'd normally do if ($this->mode_3cbc && strlen($this->key) > 8) { return $this->des[2]->encrypt( - $this->des[1]->decrypt( - $this->des[0]->encrypt($this->_pad($plaintext)))); + $this->des[1]->decrypt( + $this->des[0]->encrypt( + $this->_pad($plaintext) + ) + ) + ); } return parent::encrypt($plaintext); @@ -307,9 +310,15 @@ class Crypt_TripleDES extends Crypt_DES function decrypt($ciphertext) { if ($this->mode_3cbc && strlen($this->key) > 8) { - return $this->_unpad($this->des[0]->decrypt( - $this->des[1]->encrypt( - $this->des[2]->decrypt(str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0"))))); + return $this->_unpad( + $this->des[0]->decrypt( + $this->des[1]->encrypt( + $this->des[2]->decrypt( + str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0") + ) + ) + ) + ); } return parent::decrypt($ciphertext); diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php b/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php index cf950832..71696c94 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php @@ -14,7 +14,7 @@ * Here's a short example of how to use this library: * * * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0 * @link http://phpseclib.sourceforge.net */ @@ -104,7 +103,7 @@ define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB); /**#@+ * @access private - * @see Crypt_Twofish::Crypt_Twofish() + * @see Crypt_Base::Crypt_Base() */ /** * Toggles the internal implementation @@ -122,7 +121,6 @@ define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); * @package Crypt_Twofish * @author Jim Wigginton * @author Hans-Juergen Petrich - * @version 1.0 * @access public */ class Crypt_Twofish extends Crypt_Base @@ -448,34 +446,6 @@ class Crypt_Twofish extends Crypt_Base */ var $kl; - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_TWOFISH_MODE_ECB - * - * - CRYPT_TWOFISH_MODE_CBC - * - * - CRYPT_TWOFISH_MODE_CTR - * - * - CRYPT_TWOFISH_MODE_CFB - * - * - CRYPT_TWOFISH_MODE_OFB - * - * If not explictly set, CRYPT_TWOFISH_MODE_CBC will be used. - * - * @see Crypt_Base::Crypt_Base() - * @param optional Integer $mode - * @access public - */ - function Crypt_Twofish($mode = CRYPT_TWOFISH_MODE_CBC) - { - parent::Crypt_Base($mode); - } - /** * Sets the key. * @@ -709,10 +679,12 @@ class Crypt_Twofish extends Crypt_Base $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); } + // @codingStandardsIgnoreStart return pack("V4", $K[4] ^ $R2, $K[5] ^ $R3, $K[6] ^ $R0, $K[7] ^ $R1); + // @codingStandardsIgnoreEnd } /** @@ -763,10 +735,12 @@ class Crypt_Twofish extends Crypt_Base $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]); } + // @codingStandardsIgnoreStart return pack("V4", $K[0] ^ $R2, $K[1] ^ $R3, $K[2] ^ $R0, $K[3] ^ $R1); + // @codingStandardsIgnoreEnd } /** diff --git a/lam/lib/3rdParty/phpseclib/File/ANSI.php b/lam/lib/3rdParty/phpseclib/File/ANSI.php index b8ea91aa..7f8741c1 100644 --- a/lam/lib/3rdParty/phpseclib/File/ANSI.php +++ b/lam/lib/3rdParty/phpseclib/File/ANSI.php @@ -31,7 +31,7 @@ * @category File * @package File_ANSI * @author Jim Wigginton - * @copyright MMXII Jim Wigginton + * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -41,7 +41,6 @@ * * @package File_ANSI * @author Jim Wigginton - * @version 0.3.0 * @access public */ class File_ANSI diff --git a/lam/lib/3rdParty/phpseclib/File/ASN1.php b/lam/lib/3rdParty/phpseclib/File/ASN1.php index 029ee679..ac95e7b9 100644 --- a/lam/lib/3rdParty/phpseclib/File/ASN1.php +++ b/lam/lib/3rdParty/phpseclib/File/ASN1.php @@ -34,7 +34,7 @@ * @category File * @package File_ASN1 * @author Jim Wigginton - * @copyright MMXII Jim Wigginton + * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -112,7 +112,6 @@ define('FILE_ASN1_TYPE_ANY', -2); * * @package File_ASN1 * @author Jim Wigginton - * @version 0.3.0 * @access public */ class File_ASN1_Element @@ -143,7 +142,6 @@ class File_ASN1_Element * * @package File_ASN1 * @author Jim Wigginton - * @version 0.3.0 * @access public */ class File_ASN1 @@ -164,7 +162,7 @@ class File_ASN1 * @access private * @link http://php.net/class.datetime */ - var $format = 'D, d M y H:i:s O'; + var $format = 'D, d M Y H:i:s O'; /** * Default date format @@ -274,7 +272,8 @@ class File_ASN1 } $this->encoded = $encoded; - return $this->_decode_ber($encoded); + // encapsulate in an array for BC with the old decodeBER + return array($this->_decode_ber($encoded)); } /** @@ -289,215 +288,245 @@ class File_ASN1 * @return Array * @access private */ - function _decode_ber(&$encoded, $start = 0) + function _decode_ber($encoded, $start = 0) { - $decoded = array(); + $current = array('start' => $start); - while ( strlen($encoded) ) { - $current = array('start' => $start); + $type = ord($this->_string_shift($encoded)); + $start++; - $type = ord($this->_string_shift($encoded)); - $start++; + $constructed = ($type >> 5) & 1; - $constructed = ($type >> 5) & 1; - - $tag = $type & 0x1F; - if ($tag == 0x1F) { - $tag = 0; - // process septets (since the eighth bit is ignored, it's not an octet) - do { - $loop = ord($encoded[0]) >> 7; - $tag <<= 7; - $tag |= ord($this->_string_shift($encoded)) & 0x7F; - $start++; - } while ( $loop ); - } - - // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13 - $length = ord($this->_string_shift($encoded)); - $start++; - if ( $length == 0x80 ) { // indefinite length - // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all - // immediately available." -- paragraph 8.1.3.2.c - //if ( !$constructed ) { - // return false; - //} - $length = strlen($encoded); - } elseif ( $length & 0x80 ) { // definite length, long form - // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only - // support it up to four. - $length&= 0x7F; - $temp = $this->_string_shift($encoded, $length); - // tags of indefinite length don't really have a header length; this length includes the tag - $current+= array('headerlength' => $length + 2); - $start+= $length; - extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); - } else { - $current+= array('headerlength' => 2); - } - - // End-of-content, see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2 - if (!$type && !$length) { - return $decoded; - } - $content = $this->_string_shift($encoded, $length); - - /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1 - built-in types. It defines an application-independent data type that must be distinguishable from all other - data types. The other three classes are user defined. The APPLICATION class distinguishes data types that - have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within - a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the - alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this - data type; the term CONTEXT-SPECIFIC does not appear. - - -- http://www.obj-sys.com/asn1tutorial/node12.html */ - $class = ($type >> 6) & 3; - switch ($class) { - case FILE_ASN1_CLASS_APPLICATION: - case FILE_ASN1_CLASS_PRIVATE: - case FILE_ASN1_CLASS_CONTEXT_SPECIFIC: - $decoded[] = array( - 'type' => $class, - 'constant' => $tag, - 'content' => $constructed ? $this->_decode_ber($content, $start) : $content, - 'length' => $length + $start - $current['start'] - ) + $current; - $start+= $length; - continue 2; - } - - $current+= array('type' => $tag); - - // decode UNIVERSAL tags - switch ($tag) { - case FILE_ASN1_TYPE_BOOLEAN: - // "The contents octets shall consist of a single octet." -- paragraph 8.2.1 - //if (strlen($content) != 1) { - // return false; - //} - $current['content'] = (bool) ord($content[0]); - break; - case FILE_ASN1_TYPE_INTEGER: - case FILE_ASN1_TYPE_ENUMERATED: - $current['content'] = new Math_BigInteger($content, -256); - break; - case FILE_ASN1_TYPE_REAL: // not currently supported - return false; - case FILE_ASN1_TYPE_BIT_STRING: - // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit, - // the number of unused bits in the final subsequent octet. The number shall be in the range zero to - // seven. - if (!$constructed) { - $current['content'] = $content; - } else { - $temp = $this->_decode_ber($content, $start); - $length-= strlen($content); - $last = count($temp) - 1; - for ($i = 0; $i < $last; $i++) { - // all subtags should be bit strings - //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) { - // return false; - //} - $current['content'].= substr($temp[$i]['content'], 1); - } - // all subtags should be bit strings - //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) { - // return false; - //} - $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1); - } - break; - case FILE_ASN1_TYPE_OCTET_STRING: - if (!$constructed) { - $current['content'] = $content; - } else { - $temp = $this->_decode_ber($content, $start); - $length-= strlen($content); - for ($i = 0, $size = count($temp); $i < $size; $i++) { - // all subtags should be octet strings - //if ($temp[$i]['type'] != FILE_ASN1_TYPE_OCTET_STRING) { - // return false; - //} - $current['content'].= $temp[$i]['content']; - } - // $length = - } - break; - case FILE_ASN1_TYPE_NULL: - // "The contents octets shall not contain any octets." -- paragraph 8.8.2 - //if (strlen($content)) { - // return false; - //} - break; - case FILE_ASN1_TYPE_SEQUENCE: - case FILE_ASN1_TYPE_SET: - $current['content'] = $this->_decode_ber($content, $start); - break; - case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: - $temp = ord($this->_string_shift($content)); - $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40); - $valuen = 0; - // process septets - while (strlen($content)) { - $temp = ord($this->_string_shift($content)); - $valuen <<= 7; - $valuen |= $temp & 0x7F; - if (~$temp & 0x80) { - $current['content'].= ".$valuen"; - $valuen = 0; - } - } - // the eighth bit of the last byte should not be 1 - //if ($temp >> 7) { - // return false; - //} - break; - /* Each character string type shall be encoded as if it had been declared: - [UNIVERSAL x] IMPLICIT OCTET STRING - - -- X.690-0207.pdf#page=23 (paragraph 8.21.3) - - Per that, we're not going to do any validation. If there are any illegal characters in the string, - we don't really care */ - case FILE_ASN1_TYPE_NUMERIC_STRING: - // 0,1,2,3,4,5,6,7,8,9, and space - case FILE_ASN1_TYPE_PRINTABLE_STRING: - // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma, - // hyphen, full stop, solidus, colon, equal sign, question mark - case FILE_ASN1_TYPE_TELETEX_STRING: - // The Teletex character set in CCITT's T61, space, and delete - // see http://en.wikipedia.org/wiki/Teletex#Character_sets - case FILE_ASN1_TYPE_VIDEOTEX_STRING: - // The Videotex character set in CCITT's T.100 and T.101, space, and delete - case FILE_ASN1_TYPE_VISIBLE_STRING: - // Printing character sets of international ASCII, and space - case FILE_ASN1_TYPE_IA5_STRING: - // International Alphabet 5 (International ASCII) - case FILE_ASN1_TYPE_GRAPHIC_STRING: - // All registered G sets, and space - case FILE_ASN1_TYPE_GENERAL_STRING: - // All registered C and G sets, space and delete - case FILE_ASN1_TYPE_UTF8_STRING: - // ???? - case FILE_ASN1_TYPE_BMP_STRING: - $current['content'] = $content; - break; - case FILE_ASN1_TYPE_UTC_TIME: - case FILE_ASN1_TYPE_GENERALIZED_TIME: - $current['content'] = $this->_decodeTime($content, $tag); - default: - - } - - $start+= $length; - $decoded[] = $current + array('length' => $start - $current['start']); + $tag = $type & 0x1F; + if ($tag == 0x1F) { + $tag = 0; + // process septets (since the eighth bit is ignored, it's not an octet) + do { + $loop = ord($encoded[0]) >> 7; + $tag <<= 7; + $tag |= ord($this->_string_shift($encoded)) & 0x7F; + $start++; + } while ( $loop ); } - return $decoded; + // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13 + $length = ord($this->_string_shift($encoded)); + $start++; + if ( $length == 0x80 ) { // indefinite length + // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all + // immediately available." -- paragraph 8.1.3.2.c + $length = strlen($encoded); + } elseif ( $length & 0x80 ) { // definite length, long form + // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only + // support it up to four. + $length&= 0x7F; + $temp = $this->_string_shift($encoded, $length); + // tags of indefinte length don't really have a header length; this length includes the tag + $current+= array('headerlength' => $length + 2); + $start+= $length; + extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); + } else { + $current+= array('headerlength' => 2); + } + + $content = $this->_string_shift($encoded, $length); + + // at this point $length can be overwritten. it's only accurate for definite length things as is + + /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1 + built-in types. It defines an application-independent data type that must be distinguishable from all other + data types. The other three classes are user defined. The APPLICATION class distinguishes data types that + have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within + a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the + alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this + data type; the term CONTEXT-SPECIFIC does not appear. + + -- http://www.obj-sys.com/asn1tutorial/node12.html */ + $class = ($type >> 6) & 3; + switch ($class) { + case FILE_ASN1_CLASS_APPLICATION: + case FILE_ASN1_CLASS_PRIVATE: + case FILE_ASN1_CLASS_CONTEXT_SPECIFIC: + if (!$constructed) { + return array( + 'type' => $class, + 'constant' => $tag, + 'content' => $content, + 'length' => $length + $start - $current['start'] + ); + } + + $newcontent = array(); + if (strlen($content)) { + $newcontent = $this->_decode_ber($content, $start); + $length = $newcontent['length']; + if (substr($content, $length, 2) == "\0\0") { + $length+= 2; + } + $start+= $length; + $newcontent = array($newcontent); + } + + return array( + 'type' => $class, + 'constant' => $tag, + // the array encapsulation is for BC with the old format + 'content' => $newcontent, + // the only time when $content['headerlength'] isn't defined is when the length is indefinite. + // the absence of $content['headerlength'] is how we know if something is indefinite or not. + // technically, it could be defined to be 2 and then another indicator could be used but whatever. + 'length' => $start - $current['start'] + ) + $current; + } + + $current+= array('type' => $tag); + + // decode UNIVERSAL tags + switch ($tag) { + case FILE_ASN1_TYPE_BOOLEAN: + // "The contents octets shall consist of a single octet." -- paragraph 8.2.1 + //if (strlen($content) != 1) { + // return false; + //} + $current['content'] = (bool) ord($content[0]); + break; + case FILE_ASN1_TYPE_INTEGER: + case FILE_ASN1_TYPE_ENUMERATED: + $current['content'] = new Math_BigInteger($content, -256); + break; + case FILE_ASN1_TYPE_REAL: // not currently supported + return false; + case FILE_ASN1_TYPE_BIT_STRING: + // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit, + // the number of unused bits in the final subsequent octet. The number shall be in the range zero to + // seven. + if (!$constructed) { + $current['content'] = $content; + } else { + $temp = $this->_decode_ber($content, $start); + $length-= strlen($content); + $last = count($temp) - 1; + for ($i = 0; $i < $last; $i++) { + // all subtags should be bit strings + //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) { + // return false; + //} + $current['content'].= substr($temp[$i]['content'], 1); + } + // all subtags should be bit strings + //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) { + // return false; + //} + $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1); + } + break; + case FILE_ASN1_TYPE_OCTET_STRING: + if (!$constructed) { + $current['content'] = $content; + } else { + $current['content'] = ''; + $length = 0; + while (substr($content, 0, 2) != "\0\0") { + $temp = $this->_decode_ber($content, $length + $start); + $this->_string_shift($content, $temp['length']); + // all subtags should be octet strings + //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) { + // return false; + //} + $current['content'].= $temp['content']; + $length+= $temp['length']; + } + if (substr($content, 0, 2) == "\0\0") { + $length+= 2; // +2 for the EOC + } + } + break; + case FILE_ASN1_TYPE_NULL: + // "The contents octets shall not contain any octets." -- paragraph 8.8.2 + //if (strlen($content)) { + // return false; + //} + break; + case FILE_ASN1_TYPE_SEQUENCE: + case FILE_ASN1_TYPE_SET: + $offset = 0; + $current['content'] = array(); + while (strlen($content)) { + // if indefinite length construction was used and we have an end-of-content string next + // see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2 + if (!isset($current['headerlength']) && substr($content, 0, 2) == "\0\0") { + $length = $offset + 2; // +2 for the EOC + break 2; + } + $temp = $this->_decode_ber($content, $start + $offset); + $this->_string_shift($content, $temp['length']); + $current['content'][] = $temp; + $offset+= $temp['length']; + } + break; + case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: + $temp = ord($this->_string_shift($content)); + $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40); + $valuen = 0; + // process septets + while (strlen($content)) { + $temp = ord($this->_string_shift($content)); + $valuen <<= 7; + $valuen |= $temp & 0x7F; + if (~$temp & 0x80) { + $current['content'].= ".$valuen"; + $valuen = 0; + } + } + // the eighth bit of the last byte should not be 1 + //if ($temp >> 7) { + // return false; + //} + break; + /* Each character string type shall be encoded as if it had been declared: + [UNIVERSAL x] IMPLICIT OCTET STRING + + -- X.690-0207.pdf#page=23 (paragraph 8.21.3) + + Per that, we're not going to do any validation. If there are any illegal characters in the string, + we don't really care */ + case FILE_ASN1_TYPE_NUMERIC_STRING: + // 0,1,2,3,4,5,6,7,8,9, and space + case FILE_ASN1_TYPE_PRINTABLE_STRING: + // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma, + // hyphen, full stop, solidus, colon, equal sign, question mark + case FILE_ASN1_TYPE_TELETEX_STRING: + // The Teletex character set in CCITT's T61, space, and delete + // see http://en.wikipedia.org/wiki/Teletex#Character_sets + case FILE_ASN1_TYPE_VIDEOTEX_STRING: + // The Videotex character set in CCITT's T.100 and T.101, space, and delete + case FILE_ASN1_TYPE_VISIBLE_STRING: + // Printing character sets of international ASCII, and space + case FILE_ASN1_TYPE_IA5_STRING: + // International Alphabet 5 (International ASCII) + case FILE_ASN1_TYPE_GRAPHIC_STRING: + // All registered G sets, and space + case FILE_ASN1_TYPE_GENERAL_STRING: + // All registered C and G sets, space and delete + case FILE_ASN1_TYPE_UTF8_STRING: + // ???? + case FILE_ASN1_TYPE_BMP_STRING: + $current['content'] = $content; + break; + case FILE_ASN1_TYPE_UTC_TIME: + case FILE_ASN1_TYPE_GENERALIZED_TIME: + $current['content'] = $this->_decodeTime($content, $tag); + default: + } + + $start+= $length; + + // ie. length is the length of the full TLV encoding - it's not just the length of the value + return $current + array('length' => $start - $current['start']); } /** - * ASN.1 Decode + * ASN.1 Map * * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format. * @@ -511,7 +540,7 @@ class File_ASN1 */ function asn1map($decoded, $mapping, $special = array()) { - if (isset($mapping['explicit'])) { + if (isset($mapping['explicit']) && is_array($decoded['content'])) { $decoded = $decoded['content'][0]; } @@ -552,7 +581,15 @@ class File_ASN1 case $decoded['type'] == $mapping['type']: break; default: - return null; + // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings, + // let it through + switch (true) { + case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18 + case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30 + case $mapping['type'] < 18: + case $mapping['type'] > 30: + return null; + } } if (isset($mapping['implicit'])) { @@ -799,16 +836,6 @@ class File_ASN1 return $this->_encode_der($source, $mapping, null, $special); } - /** - * ASN.1 Encode (Helper function) - * - * @param String $source - * @param Array $mapping - * @param Integer $idx - * @param Array $special - * @return String - * @access private - */ /** * ASN.1 Encode (Helper function) * @@ -944,6 +971,9 @@ class File_ASN1 case FILE_ASN1_TYPE_INTEGER: case FILE_ASN1_TYPE_ENUMERATED: if (!isset($mapping['mapping'])) { + if (is_numeric($source)) { + $source = new Math_BigInteger($source); + } $value = $source->toBytes(true); } else { $value = array_search($source, $mapping['mapping']); @@ -974,6 +1004,10 @@ class File_ASN1 } } + if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) { + $size = $mapping['min'] - 1; + } + $offset = 8 - (($size + 1) & 7); $offset = $offset !== 8 ? $offset : 0; @@ -1087,7 +1121,12 @@ class File_ASN1 } if (isset($mapping['cast'])) { - $tag = ($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']; + if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) { + $value = chr($tag) . $this->_encodeLength(strlen($value)) . $value; + $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast']; + } else { + $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast']; + } } return chr($tag) . $this->_encodeLength(strlen($value)) . $value; diff --git a/lam/lib/3rdParty/phpseclib/File/X509.php b/lam/lib/3rdParty/phpseclib/File/X509.php index 9dc8b391..e515f982 100644 --- a/lam/lib/3rdParty/phpseclib/File/X509.php +++ b/lam/lib/3rdParty/phpseclib/File/X509.php @@ -37,7 +37,7 @@ * @category File * @package File_X509 * @author Jim Wigginton - * @copyright MMXII Jim Wigginton + * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -125,7 +125,6 @@ define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value. * * @package File_X509 * @author Jim Wigginton - * @version 0.3.1 * @access public */ class File_X509 @@ -298,6 +297,14 @@ class File_X509 */ var $caFlag = false; + /** + * SPKAC Challenge + * + * @var String + * @access private + */ + var $challenge; + /** * Default Constructor. * @@ -2166,12 +2173,12 @@ class File_X509 switch ($algorithm) { case 'rsaEncryption': return - "-----BEGIN PUBLIC KEY-----\r\n" . + "-----BEGIN RSA PUBLIC KEY-----\r\n" . // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do. chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) . - '-----END PUBLIC KEY-----'; + '-----END RSA PUBLIC KEY-----'; default: return $key; } @@ -2502,7 +2509,8 @@ class File_X509 $asn1->loadFilters($filters); $result = ''; foreach ($dn['rdnSequence'] as $rdn) { - foreach ($rdn as &$attr) { + foreach ($rdn as $i=>$attr) { + $attr = &$rdn[$i]; if (is_array($attr['value'])) { foreach ($attr['value'] as $type => $v) { $type = array_search($type, $asn1->ANYmap, true); @@ -2531,7 +2539,7 @@ class File_X509 return strtolower(bin2hex(pack('N', $hash))); } - // Defaut is to return a string. + // Default is to return a string. $start = true; $output = ''; $asn1 = new File_ASN1(); @@ -2760,6 +2768,19 @@ class File_X509 $this->privateKey = $key; } + /** + * Set challenge + * + * Used for SPKAC CSR's + * + * @param String $challenge + * @access public + */ + function setChallenge($challenge) + { + $this->challenge = $challenge; + } + /** * Gets the public key * @@ -2953,7 +2974,8 @@ class File_X509 $asn1 = new File_ASN1(); - $temp = preg_replace('#(?:^[^=]+=)|[\r\n\\\]#', '', $spkac); + // OpenSSL produces SPKAC's that are preceeded by the string SPKAC= + $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac); $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; if ($temp != false) { $spkac = $temp; @@ -3005,6 +3027,49 @@ class File_X509 return $spkac; } + /** + * Save a SPKAC CSR request + * + * @param Array $csr + * @param Integer $format optional + * @access public + * @return String + */ + function saveSPKAC($spkac, $format = FILE_X509_FORMAT_PEM) + { + if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) { + return false; + } + + $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm'); + switch (true) { + case !$algorithm: + case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']); + break; + default: + switch ($algorithm) { + case 'rsaEncryption': + $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'] + = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']))); + } + } + + $asn1 = new File_ASN1(); + + $asn1->loadOIDs($this->oids); + $spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge); + + switch ($format) { + case FILE_X509_FORMAT_DER: + return $spkac; + // case FILE_X509_FORMAT_PEM: + default: + // OpenSSL's implementation of SPKAC requires the SPKAC be preceeded by SPKAC= and since there are pretty much + // no other SPKAC decoders phpseclib will use that same format + return 'SPKAC=' . base64_encode($spkac); + } + } + /** * Load a Certificate Revocation List * @@ -3117,6 +3182,28 @@ class File_X509 } } + /** + * Helper function to build a time field according to RFC 3280 section + * - 4.1.2.5 Validity + * - 5.1.2.4 This Update + * - 5.1.2.5 Next Update + * - 5.1.2.6 Revoked Certificates + * by choosing utcTime iff year of date given is before 2050 and generalTime else. + * + * @param String $date in format date('D, d M Y H:i:s O') + * @access private + * @return Array + */ + function _timeField($date) + { + $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this + if ($year < 2050) { + return array('utcTime' => $date); + } else { + return array('generalTime' => $date); + } + } + /** * Sign an X.509 certificate * @@ -3149,12 +3236,10 @@ class File_X509 $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; if (!empty($this->startDate)) { - $this->currentCert['tbsCertificate']['validity']['notBefore']['generalTime'] = $this->startDate; - unset($this->currentCert['tbsCertificate']['validity']['notBefore']['utcTime']); + $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate); } if (!empty($this->endDate)) { - $this->currentCert['tbsCertificate']['validity']['notAfter']['generalTime'] = $this->endDate; - unset($this->currentCert['tbsCertificate']['validity']['notAfter']['utcTime']); + $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate); } if (!empty($this->serialNumber)) { $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber; @@ -3176,8 +3261,8 @@ class File_X509 return false; } - $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M y H:i:s O'); - $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M y H:i:s O', strtotime('+1 year')); + $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); + $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year')); $serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new Math_BigInteger(); $this->currentCert = array( @@ -3188,8 +3273,8 @@ class File_X509 'signature' => array('algorithm' => $signatureAlgorithm), 'issuer' => false, // this is going to be overwritten later 'validity' => array( - 'notBefore' => array('generalTime' => $startDate), // $this->setStartDate() - 'notAfter' => array('generalTime' => $endDate) // $this->setEndDate() + 'notBefore' => $this->_timeField($startDate), // $this->setStartDate() + 'notAfter' => $this->_timeField($endDate) // $this->setEndDate() ), 'subject' => $subject->dn, 'subjectPublicKeyInfo' => $subjectPublicKey @@ -3349,6 +3434,71 @@ class File_X509 return $result; } + /** + * Sign a SPKAC + * + * @access public + * @return Mixed + */ + function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption') + { + if (!is_object($this->privateKey)) { + return false; + } + + $origPublicKey = $this->publicKey; + $class = get_class($this->privateKey); + $this->publicKey = new $class(); + $this->publicKey->loadKey($this->privateKey->getPublicKey()); + $this->publicKey->setPublicKey(); + $publicKey = $this->_formatSubjectPublicKey(); + if (!$publicKey) { + return false; + } + $this->publicKey = $origPublicKey; + + $currentCert = isset($this->currentCert) ? $this->currentCert : null; + $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; + + // re-signing a SPKAC seems silly but since everything else supports re-signing why not? + if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) { + $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; + $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey; + if (!empty($this->challenge)) { + // the bitwise AND ensures that the output is a valid IA5String + $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge)); + } + } else { + $this->currentCert = array( + 'publicKeyAndChallenge' => + array( + 'spki' => $publicKey, + // quoting , + // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified." + // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way + // we could alternatively do this instead if we ignored the specs: + // crypt_random_string(8) & str_repeat("\x7F", 8) + 'challenge' => !empty($this->challenge) ? $this->challenge : '' + ), + 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), + 'signature' => false // this is going to be overwritten later + ); + } + + // resync $this->signatureSubject + // save $publicKeyAndChallenge in case there are any File_ASN1_Element objects in it + $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge']; + $this->loadSPKAC($this->saveSPKAC($this->currentCert)); + + $result = $this->_sign($this->privateKey, $signatureAlgorithm); + $result['publicKeyAndChallenge'] = $publicKeyAndChallenge; + + $this->currentCert = $currentCert; + $this->signatureSubject = $signatureSubject; + + return $result; + } + /** * Sign a CRL * @@ -3368,7 +3518,7 @@ class File_X509 $currentCert = isset($this->currentCert) ? $this->currentCert : null; $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; - $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M y H:i:s O'); + $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) { $this->currentCert = $crl->currentCert; @@ -3381,7 +3531,7 @@ class File_X509 'version' => 'v2', 'signature' => array('algorithm' => $signatureAlgorithm), 'issuer' => false, // this is going to be overwritten later - 'thisUpdate' => array('generalTime' => $thisUpdate) // $this->setStartDate() + 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate() ), 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), 'signature' => false // this is going to be overwritten later @@ -3390,10 +3540,10 @@ class File_X509 $tbsCertList = &$this->currentCert['tbsCertList']; $tbsCertList['issuer'] = $issuer->dn; - $tbsCertList['thisUpdate'] = array('generalTime' => $thisUpdate); + $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate); if (!empty($this->endDate)) { - $tbsCertList['nextUpdate'] = array('generalTime' => $this->endDate); // $this->setEndDate() + $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate() } else { unset($tbsCertList['nextUpdate']); } @@ -3516,7 +3666,7 @@ class File_X509 */ function setStartDate($date) { - $this->startDate = @date('D, d M y H:i:s O', @strtotime($date)); + $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date)); } /** @@ -3540,7 +3690,7 @@ class File_X509 $temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp; $this->endDate = new File_ASN1_Element($temp); } else { - $this->endDate = @date('D, d M y H:i:s O', @strtotime($date)); + $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date)); } } @@ -4085,7 +4235,7 @@ class File_X509 } return false; default: // Should be a key object (i.e.: Crypt_RSA). - $key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW); + $key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1); break; } @@ -4126,7 +4276,7 @@ class File_X509 //return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey()))); return array( 'algorithm' => array('algorithm' => 'rsaEncryption'), - 'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) + 'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1) ); default: return false; @@ -4214,7 +4364,7 @@ class File_X509 $i = count($rclist); $rclist[] = array('userCertificate' => $serial, - 'revocationDate' => array('generalTime' => @date('D, d M y H:i:s O'))); + 'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O'))); return $i; } @@ -4234,7 +4384,7 @@ class File_X509 if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) { if (!empty($date)) { - $rclist[$i]['revocationDate'] = array('generalTime' => $date); + $rclist[$i]['revocationDate'] = $this->_timeField($date); } return true; diff --git a/lam/lib/3rdParty/phpseclib/Math/BigInteger.php b/lam/lib/3rdParty/phpseclib/Math/BigInteger.php index 1b4ea675..8e54f741 100644 --- a/lam/lib/3rdParty/phpseclib/Math/BigInteger.php +++ b/lam/lib/3rdParty/phpseclib/Math/BigInteger.php @@ -19,10 +19,6 @@ * which only supports integers. Although this fact will slow this library down, the fact that such a high * base is being used should more than compensate. * - * When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again, - * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition / - * subtraction). - * * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie. * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1) * @@ -35,7 +31,7 @@ * Here's an example of how to use this library: * * - * @copyright MMVI Jim Wigginton + * @copyright 2006 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ @@ -175,7 +171,6 @@ define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); * * @package Math_BigInteger * @author Jim Wigginton - * @version 1.0.0RC4 * @access public */ class Math_BigInteger @@ -242,13 +237,13 @@ class Math_BigInteger * * Here's an example: * - * <?php - * include('Math/BigInteger.php'); + * toString(); // outputs 50 - * ?> + * ?> * * * @param optional $x base-10 number or base-$base number if $base set. @@ -274,7 +269,7 @@ class Math_BigInteger if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work ob_start(); - phpinfo(); + @phpinfo(); $content = ob_get_contents(); ob_end_clean(); @@ -283,7 +278,14 @@ class Math_BigInteger $versions = array(); if (!empty($matches[1])) { for ($i = 0; $i < count($matches[1]); $i++) { - $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + + // Remove letter part in OpenSSL version + if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { + $versions[$matches[1][$i]] = $fullVersion; + } else { + $versions[$matches[1][$i]] = $m[0]; + } } } @@ -334,9 +336,12 @@ class Math_BigInteger switch ( MATH_BIGINTEGER_MODE ) { case MATH_BIGINTEGER_MODE_GMP: - if (is_resource($x) && get_resource_type($x) == 'GMP integer') { - $this->value = $x; - return; + switch (true) { + case is_resource($x) && get_resource_type($x) == 'GMP integer': + // PHP 5.6 switched GMP from using resources to objects + case is_object($x) && get_class($x) == 'GMP': + $this->value = $x; + return; } $this->value = gmp_init(0); break; @@ -511,7 +516,7 @@ class Math_BigInteger * Here's an example: * * * * * * = MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum; - $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); + $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31); $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) $value[$j] = $temp; @@ -957,7 +962,7 @@ class Math_BigInteger * Here's an example: * * > 31); $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); $x_value[$j] = $temp; @@ -1093,7 +1098,7 @@ class Math_BigInteger * Here's an example: * * > 31); $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } @@ -1222,7 +1227,7 @@ class Math_BigInteger for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } @@ -1310,13 +1315,13 @@ class Math_BigInteger $i2 = $i << 1; $temp = $square_value[$i2] + $value[$i] * $value[$i]; - $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); // note how we start from $i+1 instead of 0 as we do in multiplication. for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; - $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } @@ -1377,7 +1382,7 @@ class Math_BigInteger * Here's an example: * * _safe_divide( + $x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1], $y_window[0] ); } @@ -1584,7 +1588,7 @@ class Math_BigInteger for ($i = count($dividend) - 1; $i >= 0; --$i) { $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i]; - $result[$i] = (int) ($temp / $divisor); + $result[$i] = $this->_safe_divide($temp, $divisor); $carry = (int) ($temp - $divisor * $result[$i]); } @@ -1597,7 +1601,7 @@ class Math_BigInteger * Here's an example: * * _normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); + // the following code, although not callable, can be run independently of the above code + // although the above code performed better in my benchmarks the following could might + // perform better under different circumstances. in lieu of deleting it it's just been + // made uncallable + // is the modulo odd? if ( $n->value[0] & 1 ) { return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); @@ -2135,7 +2144,7 @@ class Math_BigInteger if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { $corrector_value = $this->_array_repeat(0, $n_length + 1); - $corrector_value[] = 1; + $corrector_value[count($corrector_value)] = 1; $result = $this->_add($result, false, $corrector_value, false); $result = $result[MATH_BIGINTEGER_VALUE]; } @@ -2196,7 +2205,7 @@ class Math_BigInteger for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 - $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } @@ -2212,7 +2221,7 @@ class Math_BigInteger for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); } @@ -2261,7 +2270,7 @@ class Math_BigInteger for ($i = 0; $i < $k; ++$i) { $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); $temp = $this->_regularMultiply(array($temp), $n); $temp = array_merge($this->_array_repeat(0, $i), $temp); $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); @@ -2295,6 +2304,11 @@ class Math_BigInteger $temp = $this->_multiply($x, false, $y, false); return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); + // the following code, although not callable, can be run independently of the above code + // although the above code performed better in my benchmarks the following could might + // perform better under different circumstances. in lieu of deleting it it's just been + // made uncallable + static $cache = array( MATH_BIGINTEGER_VARIABLE => array(), MATH_BIGINTEGER_DATA => array() @@ -2313,9 +2327,9 @@ class Math_BigInteger $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); for ($i = 0; $i < $n; ++$i) { $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; - $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); @@ -2392,7 +2406,7 @@ class Math_BigInteger * Here's an example: * * * * > 3); $this->_base256_lshift($leading_ones, $current_bits); - $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT); + $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); } @@ -3062,8 +3076,7 @@ class Math_BigInteger */ function _random_number_helper($size) { - $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string')); - if ($crypt_random) { + if (function_exists('crypt_random_string')) { $random = crypt_random_string($size); } else { $random = ''; @@ -3085,19 +3098,31 @@ class Math_BigInteger /** * Generate a random number * - * @param optional Integer $min - * @param optional Integer $max + * Returns a random number between $min and $max where $min and $max + * can be defined using one of the two methods: + * + * $min->random($max) + * $max->random($min) + * + * @param Math_BigInteger $arg1 + * @param optional Math_BigInteger $arg2 * @return Math_BigInteger * @access public + * @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a Math_BigInteger object. + * That method is still supported for BC purposes. */ - function random($min = false, $max = false) + function random($arg1, $arg2 = false) { - if ($min === false) { - $min = new Math_BigInteger(0); + if ($arg1 === false) { + return false; } - if ($max === false) { - $max = new Math_BigInteger(0x7FFFFFFF); + if ($arg2 === false) { + $max = $arg1; + $min = $this; + } else { + $min = $arg1; + $max = $arg2; } $compare = $max->compare($min); @@ -3160,21 +3185,25 @@ class Math_BigInteger * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed, * give up and return false. * - * @param optional Integer $min - * @param optional Integer $max + * @param Math_BigInteger $arg1 + * @param optional Math_BigInteger $arg2 * @param optional Integer $timeout - * @return Math_BigInteger + * @return Mixed * @access public * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}. */ - function randomPrime($min = false, $max = false, $timeout = false) + function randomPrime($arg1, $arg2 = false, $timeout = false) { - if ($min === false) { - $min = new Math_BigInteger(0); + if ($arg1 === false) { + return false; } - if ($max === false) { - $max = new Math_BigInteger(0x7FFFFFFF); + if ($arg2 === false) { + $max = $arg1; + $min = $this; + } else { + $min = $arg1; + $max = $arg2; } $compare = $max->compare($min); @@ -3283,10 +3312,10 @@ class Math_BigInteger * Checks a numer to see if it's prime * * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the - * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads + * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed across multiple pageloads * on a website instead of just one. * - * @param optional Integer $t + * @param optional Math_BigInteger $t * @return Boolean * @access public * @internal Uses the @@ -3455,12 +3484,12 @@ class Math_BigInteger for ($i = 0; $i < count($this->value); ++$i) { $temp = $this->value[$i] * $shift + $carry; - $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL); } if ( $carry ) { - $this->value[] = $carry; + $this->value[count($this->value)] = $carry; } while ($num_digits--) { @@ -3703,4 +3732,27 @@ class Math_BigInteger $temp = ltrim(pack('N', $length), chr(0)); return pack('Ca*', 0x80 | strlen($temp), $temp); } + + /** + * Single digit division + * + * Even if int64 is being used the division operator will return a float64 value + * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't + * have the precision of int64 this is a problem so, when int64 is being used, + * we'll guarantee that the dividend is divisible by first subtracting the remainder. + * + * @access private + * @param Integer $x + * @param Integer $y + * @return Integer + */ + function _safe_divide($x, $y) + { + if (MATH_BIGINTEGER_BASE === 26) { + return (int) ($x / $y); + } + + // MATH_BIGINTEGER_BASE === 31 + return ($x - ($x % $y)) / $y; + } } diff --git a/lam/lib/3rdParty/phpseclib/Net/SCP.php b/lam/lib/3rdParty/phpseclib/Net/SCP.php index cab91d7e..1e14727e 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SCP.php +++ b/lam/lib/3rdParty/phpseclib/Net/SCP.php @@ -10,8 +10,8 @@ * Here's a short example of how to use this library: * * login('username', 'password')) { @@ -44,7 +44,7 @@ * @category Net * @package Net_SCP * @author Jim Wigginton - * @copyright MMX Jim Wigginton + * @copyright 2010 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -83,7 +83,6 @@ define('NET_SCP_SSH2', 2); * * @package Net_SCP * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Net_SCP @@ -130,7 +129,7 @@ class Net_SCP } switch (strtolower(get_class($ssh))) { - case'net_ssh2': + case 'net_ssh2': $this->mode = NET_SCP_SSH2; break; case 'net_ssh1': @@ -171,7 +170,7 @@ class Net_SCP return false; } - if (!$this->ssh->exec('scp -t ' . $remote_file, false)) { // -t = to + if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to return false; } @@ -196,7 +195,6 @@ class Net_SCP $fp = @fopen($data, 'rb'); if (!$fp) { - fclose($fp); return false; } $size = filesize($data); @@ -216,7 +214,7 @@ class Net_SCP $sent+= strlen($temp); if (is_callable($callback)) { - $callback($sent); + call_user_func($callback, $sent); } } $this->_close(); @@ -246,7 +244,7 @@ class Net_SCP return false; } - if (!$this->ssh->exec('scp -f ' . $remote_file, false)) { // -f = from + if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from return false; } diff --git a/lam/lib/3rdParty/phpseclib/Net/SFTP.php b/lam/lib/3rdParty/phpseclib/Net/SFTP.php index 68d944f9..5f7d3666 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SFTP.php +++ b/lam/lib/3rdParty/phpseclib/Net/SFTP.php @@ -14,7 +14,7 @@ * Here's a short example of how to use this library: * * login('username', 'password')) { @@ -48,7 +48,7 @@ * @category Net * @package Net_SFTP * @author Jim Wigginton - * @copyright MMIX Jim Wigginton + * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -117,7 +117,6 @@ define('NET_SFTP_RESUME_START', 8); * * @package Net_SFTP * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Net_SFTP extends Net_SSH2 @@ -230,18 +229,18 @@ class Net_SFTP extends Net_SSH2 var $sftp_errors = array(); /** - * Directory Cache + * Stat Cache * - * Rather than always having to open a directory and close it immediately there after to see if a file is a directory or - * rather than always + * Rather than always having to open a directory and close it immediately there after to see if a file is a directory + * we'll cache the results. * - * @see Net_SFTP::_save_dir() - * @see Net_SFTP::_remove_dir() - * @see Net_SFTP::_is_dir() + * @see Net_SFTP::_update_stat_cache() + * @see Net_SFTP::_remove_from_stat_cache() + * @see Net_SFTP::_query_stat_cache() * @var Array * @access private */ - var $dirs = array(); + var $stat_cache = array(); /** * Max SFTP Packet Size @@ -253,6 +252,26 @@ class Net_SFTP extends Net_SSH2 */ var $max_sftp_packet; + /** + * Stat Cache Flag + * + * @see Net_SFTP::disableStatCache() + * @see Net_SFTP::enableStatCache() + * @var Boolean + * @access private + */ + var $use_stat_cache = true; + + /** + * Sort Options + * + * @see Net_SFTP::_comparator() + * @see Net_SFTP::setListOrder() + * @var Array + * @access private + */ + var $sortOptions = array(); + /** * Default Constructor. * @@ -293,6 +312,8 @@ class Net_SFTP extends Net_SSH2 SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */ 18 => 'NET_SFTP_RENAME', + 19 => 'NET_SFTP_READLINK', + 20 => 'NET_SFTP_SYMLINK', 101=> 'NET_SFTP_STATUS', 102=> 'NET_SFTP_HANDLE', @@ -523,11 +544,41 @@ class Net_SFTP extends Net_SSH2 $this->pwd = $this->_realpath('.'); - $this->_save_dir($this->pwd); + $this->_update_stat_cache($this->pwd, array()); return true; } + /** + * Disable the stat cache + * + * @access public + */ + function disableStatCache() + { + $this->use_stat_cache = false; + } + + /** + * Enable the stat cache + * + * @access public + */ + function enableStatCache() + { + $this->use_stat_cache = true; + } + + /** + * Clear the stat cache + * + * @access public + */ + function clearStatCache() + { + $this->stat_cache = array(); + } + /** * Returns the current directory name * @@ -646,7 +697,7 @@ class Net_SFTP extends Net_SSH2 $dir = $this->_realpath($dir); // confirm that $dir is, in fact, a valid directory - if ($this->_is_dir($dir)) { + if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) { $this->pwd = $dir; return true; } @@ -678,7 +729,7 @@ class Net_SFTP extends Net_SSH2 return false; } - $this->_save_dir($dir); + $this->_update_stat_cache($dir, array()); $this->pwd = $dir; return true; @@ -688,39 +739,94 @@ class Net_SFTP extends Net_SSH2 * Returns a list of files in the given directory * * @param optional String $dir + * @param optional Boolean $recursive * @return Mixed * @access public */ - function nlist($dir = '.') + function nlist($dir = '.', $recursive = false) { - return $this->_list($dir, false); + return $this->_nlist_helper($dir, $recursive, ''); + } + + /** + * Helper method for nlist + * + * @param String $dir + * @param Boolean $recursive + * @param String $relativeDir + * @return Mixed + * @access private + */ + function _nlist_helper($dir, $recursive, $relativeDir) + { + $files = $this->_list($dir, false); + + if (!$recursive) { + return $files; + } + + $result = array(); + foreach ($files as $value) { + if ($value == '.' || $value == '..') { + if ($relativeDir == '') { + $result[] = $value; + } + continue; + } + if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) { + $temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/'); + $result = array_merge($result, $temp); + } else { + $result[] = $relativeDir . $value; + } + } + + return $result; } /** * Returns a detailed list of files in the given directory * * @param optional String $dir + * @param optional Boolean $recursive * @return Mixed * @access public */ - function rawlist($dir = '.') + function rawlist($dir = '.', $recursive = false) { - return $this->_list($dir, true); + $files = $this->_list($dir, true); + if (!$recursive || $files === false) { + return $files; + } + + static $depth = 0; + + foreach ($files as $key=>$value) { + if ($depth != 0 && $key == '..') { + unset($files[$key]); + continue; + } + if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) { + $depth++; + $files[$key] = $this->rawlist($dir . '/' . $key, true); + $depth--; + } else { + $files[$key] = (object) $value; + } + } + + return $files; } /** * Reads a list, be it detailed or not, of files in the given directory * - * $realpath exists because, in the case of the recursive deletes and recursive chmod's $realpath has already - * been calculated. - * * @param String $dir * @param optional Boolean $raw - * @param optional Boolean $realpath * @return Mixed * @access private */ - function _list($dir, $raw = true, $realpath = true) + function _list($dir, $raw = true) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; @@ -753,7 +859,7 @@ class Net_SFTP extends Net_SSH2 return false; } - $this->_save_dir($dir); + $this->_update_stat_cache($dir, array()); $contents = array(); while (true) { @@ -780,14 +886,17 @@ class Net_SFTP extends Net_SSH2 $attributes['type'] = $fileType; } } - if (!$raw) { - $contents[] = $shortname; - } else { - $contents[$shortname] = $attributes; - } + $contents[$shortname] = $attributes + array('filename' => $shortname); if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) { - $this->_save_dir($dir . '/' . $shortname); + $this->_update_stat_cache($dir . '/' . $shortname, array()); + } else { + if ($shortname == '..') { + $temp = $this->_realpath($dir . '/..') . '/.'; + } else { + $temp = $dir . '/' . $shortname; + } + $this->_update_stat_cache($temp, (object) $attributes); } // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the // final SSH_FXP_STATUS packet should tell us that, already. @@ -810,7 +919,111 @@ class Net_SFTP extends Net_SSH2 return false; } - return $contents; + if (count($this->sortOptions)) { + uasort($contents, array(&$this, '_comparator')); + } + + return $raw ? $contents : array_keys($contents); + } + + /** + * Compares two rawlist entries using parameters set by setListOrder() + * + * Intended for use with uasort() + * + * @param Array $a + * @param Array $b + * @return Integer + * @access private + */ + function _comparator($a, $b) + { + switch (true) { + case $a['filename'] === '.' || $b['filename'] === '.': + if ($a['filename'] === $b['filename']) { + return 0; + } + return $a['filename'] === '.' ? -1 : 1; + case $a['filename'] === '..' || $b['filename'] === '..': + if ($a['filename'] === $b['filename']) { + return 0; + } + return $a['filename'] === '..' ? -1 : 1; + case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY: + if (!isset($b['type'])) { + return 1; + } + if ($b['type'] !== $a['type']) { + return -1; + } + break; + case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY: + return 1; + } + foreach ($this->sortOptions as $sort => $order) { + if (!isset($a[$sort]) || !isset($b[$sort])) { + if (isset($a[$sort])) { + return -1; + } + if (isset($b[$sort])) { + return 1; + } + return 0; + } + switch ($sort) { + case 'filename': + $result = strcasecmp($a['filename'], $b['filename']); + if ($result) { + return $order === SORT_DESC ? -$result : $result; + } + break; + case 'permissions': + case 'mode': + $a[$sort]&= 07777; + $b[$sort]&= 07777; + default: + if ($a[$sort] === $b[$sort]) { + break; + } + return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort]; + } + } + } + + /** + * Defines how nlist() and rawlist() will be sorted - if at all. + * + * If sorting is enabled directories and files will be sorted independently with + * directories appearing before files in the resultant array that is returned. + * + * Any parameter returned by stat is a valid sort parameter for this function. + * Filename comparisons are case insensitive. + * + * Examples: + * + * $sftp->setListOrder('filename', SORT_ASC); + * $sftp->setListOrder('size', SORT_DESC, 'filename', SORT_ASC); + * $sftp->setListOrder(true); + * Separates directories from files but doesn't do any sorting beyond that + * $sftp->setListOrder(); + * Don't do any sort of sorting + * + * @access public + */ + function setListOrder() + { + $this->sortOptions = array(); + $args = func_get_args(); + if (empty($args)) { + return; + } + $len = count($args) & 0x7FFFFFFE; + for ($i = 0; $i < $len; $i+=2) { + $this->sortOptions[$args[$i]] = $args[$i + 1]; + } + if (!count($this->sortOptions)) { + $this->sortOptions = array('bogus' => true); + } } /** @@ -828,47 +1041,54 @@ class Net_SFTP extends Net_SSH2 return false; } - $filename = $this->_realpath($filename); - if ($filename === false) { + $result = $this->stat($filename); + if ($result === false) { return false; } - - return $this->_size($filename); + return isset($result['size']) ? $result['size'] : -1; } /** - * Save directories to cache + * Save files / directories to cache * - * @param String $dir + * @param String $path + * @param Mixed $value * @access private */ - function _save_dir($dir) + function _update_stat_cache($path, $value) { - // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($dir, '/')) - $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir)); + // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/')) + $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); - $temp = &$this->dirs; - foreach ($dirs as $dir) { + $temp = &$this->stat_cache; + $max = count($dirs) - 1; + foreach ($dirs as $i=>$dir) { if (!isset($temp[$dir])) { $temp[$dir] = array(); } + if ($i === $max) { + $temp[$dir] = $value; + break; + } $temp = &$temp[$dir]; } } /** - * Remove directories from cache + * Remove files / directories from cache * - * @param String $dir + * @param String $path + * @return Boolean * @access private */ - function _remove_dir($dir) + function _remove_from_stat_cache($path) { - $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir)); + $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); - $temp = &$this->dirs; - foreach ($dirs as $dir) { - if ($dir == end($dirs)) { + $temp = &$this->stat_cache; + $max = count($dirs) - 1; + foreach ($dirs as $i=>$dir) { + if ($i === $max) { unset($temp[$dir]); return true; } @@ -880,26 +1100,26 @@ class Net_SFTP extends Net_SSH2 } /** - * Checks cache for directory + * Checks cache for path * - * Mainly used by chdir, which is, in turn, also used for determining whether or not an individual - * file is a directory or not by stat() and lstat() + * Mainly used by file_exists * * @param String $dir + * @return Mixed * @access private */ - function _is_dir($dir) + function _query_stat_cache($path) { - $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir)); + $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); - $temp = &$this->dirs; + $temp = &$this->stat_cache; foreach ($dirs as $dir) { if (!isset($temp[$dir])) { - return false; + return null; } $temp = &$temp[$dir]; } - return true; + return $temp; } /** @@ -922,11 +1142,26 @@ class Net_SFTP extends Net_SSH2 return false; } + if ($this->use_stat_cache) { + $result = $this->_query_stat_cache($filename); + if (is_array($result) && isset($result['.'])) { + return (array) $result['.']; + } + if (is_object($result)) { + return (array) $result; + } + } + $stat = $this->_stat($filename, NET_SFTP_STAT); if ($stat === false) { + $this->_remove_from_stat_cache($filename); return false; } if (isset($stat['type'])) { + if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { + $filename.= '/.'; + } + $this->_update_stat_cache($filename, (object) $stat); return $stat; } @@ -936,6 +1171,11 @@ class Net_SFTP extends Net_SSH2 NET_SFTP_TYPE_REGULAR; $this->pwd = $pwd; + if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { + $filename.= '/.'; + } + $this->_update_stat_cache($filename, (object) $stat); + return $stat; } @@ -959,18 +1199,35 @@ class Net_SFTP extends Net_SSH2 return false; } + if ($this->use_stat_cache) { + $result = $this->_query_stat_cache($filename); + if (is_array($result) && isset($result['.'])) { + return (array) $result['.']; + } + if (is_object($result)) { + return (array) $result; + } + } + $lstat = $this->_stat($filename, NET_SFTP_LSTAT); if ($lstat === false) { + $this->_remove_from_stat_cache($filename); return false; } if (isset($lstat['type'])) { + if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { + $filename.= '/.'; + } + $this->_update_stat_cache($filename, (object) $lstat); return $lstat; } $stat = $this->_stat($filename, NET_SFTP_STAT); if ($lstat != $stat) { - return array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK)); + $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK)); + $this->_update_stat_cache($filename, (object) $lstat); + return $stat; } $pwd = $this->pwd; @@ -979,6 +1236,11 @@ class Net_SFTP extends Net_SSH2 NET_SFTP_TYPE_REGULAR; $this->pwd = $pwd; + if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { + $filename.= '/.'; + } + $this->_update_stat_cache($filename, (object) $lstat); + return $lstat; } @@ -1014,24 +1276,6 @@ class Net_SFTP extends Net_SSH2 return false; } - /** - * Returns the file size, in bytes, or false, on failure - * - * Determines the size without calling Net_SFTP::_realpath() - * - * @param String $filename - * @return Mixed - * @access private - */ - function _size($filename) - { - $result = $this->_stat($filename, NET_SFTP_STAT); - if ($result === false) { - return false; - } - return isset($result['size']) ? $result['size'] : -1; - } - /** * Truncates a file to a given length * @@ -1206,6 +1450,8 @@ class Net_SFTP extends Net_SSH2 return false; } + $this->_remove_from_stat_cache($filename); + if ($recursive) { $i = 0; $result = $this->_setstat_recursive($filename, $attr, $i); @@ -1258,7 +1504,7 @@ class Net_SFTP extends Net_SSH2 return false; } $i = 0; - $entries = $this->_list($path, true, false); + $entries = $this->_list($path, true); if ($entries === false) { return $this->_setstat($path, $attr, false); @@ -1270,11 +1516,8 @@ class Net_SFTP extends Net_SSH2 return false; } + unset($entries['.'], $entries['..']); foreach ($entries as $filename=>$props) { - if ($filename == '.' || $filename == '..') { - continue; - } - if (!isset($props['type'])) { return false; } @@ -1316,6 +1559,86 @@ class Net_SFTP extends Net_SSH2 return true; } + /** + * Return the target of a symbolic link + * + * @param String $link + * @return Mixed + * @access public + */ + function readlink($link) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + return false; + } + + $link = $this->_realpath($link); + + if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) { + return false; + } + + $response = $this->_get_sftp_packet(); + switch ($this->packet_type) { + case NET_SFTP_NAME: + break; + case NET_SFTP_STATUS: + $this->_logError($response); + return false; + default: + user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Ncount', $this->_string_shift($response, 4))); + // the file isn't a symlink + if (!$count) { + return false; + } + + extract(unpack('Nlength', $this->_string_shift($response, 4))); + return $this->_string_shift($response, $length); + } + + /** + * Create a symlink + * + * symlink() creates a symbolic link to the existing target with the specified name link. + * + * @param String $target + * @param String $link + * @return Boolean + * @access public + */ + function symlink($target, $link) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + return false; + } + + $target = $this->_realpath($target); + $link = $this->_realpath($link); + + $packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link); + if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) { + return false; + } + + $response = $this->_get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + user_error('Expected SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Nstatus', $this->_string_shift($response, 4))); + if ($status != NET_SFTP_STATUS_OK) { + $this->_logError($response, $status); + return false; + } + + return true; + } + /** * Creates a directory. * @@ -1376,8 +1699,6 @@ class Net_SFTP extends Net_SSH2 return false; } - $this->_save_dir($dir); - return true; } @@ -1416,7 +1737,11 @@ class Net_SFTP extends Net_SSH2 return false; } - $this->_remove_dir($dir); + $this->_remove_from_stat_cache($dir); + // the following will do a soft delete, which would be useful if you deleted a file + // and then tried to do a stat on the deleted file. the above, in contrast, does + // a hard delete + //$this->_update_stat_cache($dir, false); return true; } @@ -1432,6 +1757,8 @@ class Net_SFTP extends Net_SSH2 * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how * large $remote_file will be, as well. * + * If $data is a resource then it'll be used as a resource instead. + * * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * care of that, yourself. * @@ -1453,7 +1780,7 @@ class Net_SFTP extends Net_SSH2 * Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE. * * @param String $remote_file - * @param String $data + * @param String|resource $data * @param optional Integer $mode * @param optional Integer $start * @param optional Integer $local_start @@ -1472,6 +1799,8 @@ class Net_SFTP extends Net_SSH2 return false; } + $this->_remove_from_stat_cache($remote_file); + $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE; // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file." // in practice, it doesn't seem to do that. @@ -1481,7 +1810,7 @@ class Net_SFTP extends Net_SSH2 $offset = $start; } elseif ($mode & NET_SFTP_RESUME) { // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called - $size = $this->_size($remote_file); + $size = $this->size($remote_file); $offset = $size !== false ? $size : 0; } else { $offset = 0; @@ -1507,16 +1836,25 @@ class Net_SFTP extends Net_SSH2 } // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 - if ($mode & NET_SFTP_LOCAL_FILE) { - if (!is_file($data)) { - user_error("$data is not a valid file"); - return false; - } - $fp = @fopen($data, 'rb'); - if (!$fp) { - return false; - } - $size = filesize($data); + switch (true) { + case is_resource($data): + $mode = $mode & ~NET_SFTP_LOCAL_FILE; + $fp = $data; + break; + case $mode & NET_SFTP_LOCAL_FILE: + if (!is_file($data)) { + user_error("$data is not a valid file"); + return false; + } + $fp = @fopen($data, 'rb'); + if (!$fp) { + return false; + } + } + + if (isset($fp)) { + $stat = fstat($fp); + $size = $stat['size']; if ($local_start >= 0) { fseek($fp, $local_start); @@ -1537,11 +1875,13 @@ class Net_SFTP extends Net_SSH2 $sftp_packet_size-= strlen($handle) + 25; $i = 0; while ($sent < $size) { - $temp = $mode & NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); + $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); $subtemp = $offset + $sent; $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { - fclose($fp); + if ($mode & NET_SFTP_LOCAL_FILE) { + fclose($fp); + } return false; } $sent+= strlen($temp); @@ -1676,21 +2016,30 @@ class Net_SFTP extends Net_SSH2 return false; } - if ($local_file !== false) { - $fp = fopen($local_file, 'wb'); - if (!$fp) { - return false; - } + if (is_resource($local_file)) { + $fp = $local_file; + $stat = fstat($fp); + $res_offset = $stat['size']; } else { - $content = ''; + $res_offset = 0; + if ($local_file !== false) { + $fp = fopen($local_file, 'wb'); + if (!$fp) { + return false; + } + } else { + $content = ''; + } } + $fclose_check = $local_file !== false && !is_resource($local_file); + $start = $offset; $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length; while (true) { $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size); if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { - if ($local_file !== false) { + if ($fclose_check) { fclose($fp); } return false; @@ -1713,7 +2062,7 @@ class Net_SFTP extends Net_SSH2 break 2; default: user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS'); - if ($local_file !== false) { + if ($fclose_check) { fclose($fp); } return false; @@ -1728,11 +2077,11 @@ class Net_SFTP extends Net_SSH2 if ($local_file === false) { $content = substr($content, 0, $length); } else { - ftruncate($fp, $length); + ftruncate($fp, $length + $res_offset); } } - if ($local_file !== false) { + if ($fclose_check) { fclose($fp); } @@ -1787,6 +2136,8 @@ class Net_SFTP extends Net_SSH2 return $result; } + $this->_remove_from_stat_cache($path); + return true; } @@ -1806,7 +2157,7 @@ class Net_SFTP extends Net_SSH2 return false; } $i = 0; - $entries = $this->_list($path, true, false); + $entries = $this->_list($path, true); // normally $entries would have at least . and .. but it might not if the directories // permissions didn't allow reading @@ -1814,11 +2165,8 @@ class Net_SFTP extends Net_SSH2 return false; } + unset($entries['.'], $entries['..']); foreach ($entries as $filename=>$props) { - if ($filename == '.' || $filename == '..') { - continue; - } - if (!isset($props['type'])) { return false; } @@ -1842,12 +2190,12 @@ class Net_SFTP extends Net_SSH2 $i = 0; } } + $this->_remove_from_stat_cache($path); } if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) { return false; } - $this->_remove_dir($path); $i++; @@ -1861,6 +2209,205 @@ class Net_SFTP extends Net_SSH2 return true; } + /** + * Checks whether a file or directory exists + * + * @param String $path + * @return Boolean + * @access public + */ + function file_exists($path) + { + if ($this->use_stat_cache) { + $path = $this->_realpath($path); + + $result = $this->_query_stat_cache($path); + + if (isset($result)) { + // return true if $result is an array or if it's an stdClass object + return $result !== false; + } + } + + return $this->stat($path) !== false; + } + + /** + * Tells whether the filename is a directory + * + * @param String $path + * @return Boolean + * @access public + */ + function is_dir($path) + { + $result = $this->_get_stat_cache_prop($path, 'type'); + if ($result === false) { + return false; + } + return $result === NET_SFTP_TYPE_DIRECTORY; + } + + /** + * Tells whether the filename is a regular file + * + * @param String $path + * @return Boolean + * @access public + */ + function is_file($path) + { + $result = $this->_get_stat_cache_prop($path, 'type'); + if ($result === false) { + return false; + } + return $result === NET_SFTP_TYPE_REGULAR; + } + + /** + * Tells whether the filename is a symbolic link + * + * @param String $path + * @return Boolean + * @access public + */ + function is_link($path) + { + $result = $this->_get_stat_cache_prop($path, 'type'); + if ($result === false) { + return false; + } + return $result === NET_SFTP_TYPE_SYMLINK; + } + + /** + * Gets last access time of file + * + * @param String $path + * @return Mixed + * @access public + */ + function fileatime($path) + { + return $this->_get_stat_cache_prop($path, 'atime'); + } + + /** + * Gets file modification time + * + * @param String $path + * @return Mixed + * @access public + */ + function filemtime($path) + { + return $this->_get_stat_cache_prop($path, 'mtime'); + } + + /** + * Gets file permissions + * + * @param String $path + * @return Mixed + * @access public + */ + function fileperms($path) + { + return $this->_get_stat_cache_prop($path, 'permissions'); + } + + /** + * Gets file owner + * + * @param String $path + * @return Mixed + * @access public + */ + function fileowner($path) + { + return $this->_get_stat_cache_prop($path, 'uid'); + } + + /** + * Gets file group + * + * @param String $path + * @return Mixed + * @access public + */ + function filegroup($path) + { + return $this->_get_stat_cache_prop($path, 'gid'); + } + + /** + * Gets file size + * + * @param String $path + * @return Mixed + * @access public + */ + function filesize($path) + { + return $this->_get_stat_cache_prop($path, 'size'); + } + + /** + * Gets file type + * + * @param String $path + * @return Mixed + * @access public + */ + function filetype($path) + { + $type = $this->_get_stat_cache_prop($path, 'type'); + if ($type === false) { + return false; + } + + switch ($type) { + case NET_SFTP_TYPE_BLOCK_DEVICE: return 'block'; + case NET_SFTP_TYPE_CHAR_DEVICE: return 'char'; + case NET_SFTP_TYPE_DIRECTORY: return 'dir'; + case NET_SFTP_TYPE_FIFO: return 'fifo'; + case NET_SFTP_TYPE_REGULAR: return 'file'; + case NET_SFTP_TYPE_SYMLINK: return 'link'; + default: return false; + } + } + + /** + * Return a stat properity + * + * Uses cache if appropriate. + * + * @param String $path + * @param String $prop + * @return Mixed + * @access private + */ + function _get_stat_cache_prop($path, $prop) + { + if ($this->use_stat_cache) { + $path = $this->_realpath($path); + + $result = $this->_query_stat_cache($path); + + if (is_object($result) && isset($result->$prop)) { + return $result->$prop; + } + } + + $result = $this->stat($path); + + if ($result === false || !isset($result[$prop])) { + return false; + } + + return $result[$prop]; + } + /** * Renames a file or a directory on the SFTP server * @@ -1900,6 +2447,12 @@ class Net_SFTP extends Net_SSH2 return false; } + // don't move the stat cache entry over since this operation could very well change the + // atime and mtime attributes + //$this->_update_stat_cache($newname, $this->_query_stat_cache($oldname)); + $this->_remove_from_stat_cache($oldname); + $this->_remove_from_stat_cache($newname); + return true; } @@ -1920,14 +2473,13 @@ class Net_SFTP extends Net_SSH2 foreach ($this->attributes as $key => $value) { switch ($flags & $key) { case NET_SFTP_ATTR_SIZE: // 0x00000001 - // size is represented by a 64-bit integer, so we perhaps ought to be doing the following: - // $attr['size'] = new Math_BigInteger($this->_string_shift($response, 8), 256); - // of course, you shouldn't be using Net_SFTP to transfer files that are in excess of 4GB - // (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than - // 4GB as being 4GB. - extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8))); - $attr['size'] = $upper ? 4294967296 * $upper : 0; - $attr['size']+= $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; + // The size attribute is defined as an unsigned 64-bit integer. + // The following will use floats on 32-bit platforms, if necessary. + // As can be seen in the BigInteger class, floats are generally + // IEEE 754 binary64 "double precision" on such platforms and + // as such can represent integers of at least 2^50 without loss + // of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB. + $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8))); break; case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8)); @@ -1987,7 +2539,7 @@ class Net_SFTP extends Net_SSH2 case 0020000: // character special return NET_SFTP_TYPE_CHAR_DEVICE; case 0060000: // block special - return NET_SFTP_BLOCK_DEVICE; + return NET_SFTP_TYPE_BLOCK_DEVICE; case 0140000: // socket return NET_SFTP_TYPE_SOCKET; case 0160000: // whiteout diff --git a/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php b/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php index f9005a55..3366ede5 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php +++ b/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php @@ -28,7 +28,7 @@ * @category Net * @package Net_SFTP_Stream * @author Jim Wigginton - * @copyright MMXIII Jim Wigginton + * @copyright 2013 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -38,7 +38,6 @@ * * @package Net_SFTP_Stream * @author Jim Wigginton - * @version 0.3.2 * @access public */ class Net_SFTP_Stream @@ -49,7 +48,6 @@ class Net_SFTP_Stream * Rather than re-create the connection we re-use instances if possible * * @var Array - * @access static */ static $instances; @@ -127,6 +125,22 @@ class Net_SFTP_Stream */ var $notification; + /** + * Registers this class as a URL wrapper. + * + * @param optional String $protocol The wrapper name to be registered. + * @return Boolean True on success, false otherwise. + * @access public + */ + static function register($protocol = 'sftp') + { + if (in_array($protocol, stream_get_wrappers(), true)) { + return false; + } + $class = function_exists('get_called_class') ? get_called_class() : __CLASS__; + return stream_wrapper_register($protocol, $class); + } + /** * The Constructor * @@ -181,24 +195,24 @@ class Net_SFTP_Stream if (isset($this->context)) { $context = stream_context_get_options($this->context); } - if (isset($context['sftp']['session'])) { - $sftp = $context['sftp']['session']; + if (isset($context[$scheme]['session'])) { + $sftp = $context[$scheme]['session']; } - if (isset($context['sftp']['sftp'])) { - $sftp = $context['sftp']['sftp']; + if (isset($context[$scheme]['sftp'])) { + $sftp = $context[$scheme]['sftp']; } if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') { $this->sftp = $sftp; return $path; } - if (isset($context['sftp']['username'])) { - $user = $context['sftp']['username']; + if (isset($context[$scheme]['username'])) { + $user = $context[$scheme]['username']; } - if (isset($context['sftp']['password'])) { - $pass = $context['sftp']['password']; + if (isset($context[$scheme]['password'])) { + $pass = $context[$scheme]['password']; } - if (isset($context['sftp']['privkey']) && is_object($context['sftp']['privkey']) && get_Class($context['sftp']['privkey']) == 'Crypt_RSA') { - $pass = $context['sftp']['privkey']; + if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') { + $pass = $context[$scheme]['privkey']; } if (!isset($user) || !isset($pass)) { @@ -210,6 +224,7 @@ class Net_SFTP_Stream $this->sftp = self::$instances[$host][$port][$user][(string) $pass]; } else { $this->sftp = new Net_SFTP($host, $port); + $this->sftp->disableStatCache(); if (isset($this->notification) && is_callable($this->notification)) { /* if !is_callable($this->notification) we could do this: @@ -517,7 +532,20 @@ class Net_SFTP_Stream * Open directory handle * * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and - * removed in 5.4 I'm just going to ignore it + * removed in 5.4 I'm just going to ignore it. + * + * Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client + * sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting + * the SFTP specs: + * + * The SSH_FXP_NAME response has the following format: + * + * uint32 id + * uint32 count + * repeats count times: + * string filename + * string longname + * ATTRS attrs * * @param String $path * @param Integer $options @@ -770,6 +798,4 @@ class Net_SFTP_Stream } } -if (function_exists('stream_wrapper_register')) { - stream_wrapper_register('sftp', 'Net_SFTP_Stream'); -} +Net_SFTP_Stream::register(); diff --git a/lam/lib/3rdParty/phpseclib/Net/SSH1.php b/lam/lib/3rdParty/phpseclib/Net/SSH1.php index 0a6aa908..f1fae02b 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SSH1.php +++ b/lam/lib/3rdParty/phpseclib/Net/SSH1.php @@ -8,7 +8,7 @@ * Here's a short example of how to use this library: * * login('username', 'password')) { @@ -22,7 +22,7 @@ * Here's another short example: * * login('username', 'password')) { @@ -59,7 +59,7 @@ * @category Net * @package Net_SSH1 * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -182,8 +182,9 @@ define('NET_SSH1_RESPONSE_DATA', 2); * @access private */ define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001); -define('NET_SSH1_MASK_LOGIN', 0x00000002); -define('NET_SSH1_MASK_SHELL', 0x00000004); +define('NET_SSH1_MASK_CONNECTED', 0x00000002); +define('NET_SSH1_MASK_LOGIN', 0x00000004); +define('NET_SSH1_MASK_SHELL', 0x00000008); /**#@-*/ /**#@+ @@ -227,7 +228,6 @@ define('NET_SSH1_READ_REGEX', 2); * * @package Net_SSH1 * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Net_SSH1 @@ -458,6 +458,51 @@ class Net_SSH1 */ var $log_short_width = 16; + /** + * Hostname + * + * @see Net_SSH1::Net_SSH1() + * @see Net_SSH1::_connect() + * @var String + * @access private + */ + var $host; + + /** + * Port Number + * + * @see Net_SSH1::Net_SSH1() + * @see Net_SSH1::_connect() + * @var Integer + * @access private + */ + var $port; + + /** + * Timeout for initial connection + * + * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like + * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor, + * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be + * 10 seconds. It is used by fsockopen() in that function. + * + * @see Net_SSH1::Net_SSH1() + * @see Net_SSH1::_connect() + * @var Integer + * @access private + */ + var $connectionTimeout; + + /** + * Default cipher + * + * @see Net_SSH1::Net_SSH1() + * @see Net_SSH1::_connect() + * @var Integer + * @access private + */ + var $cipher; + /** * Default Constructor. * @@ -506,10 +551,24 @@ class Net_SSH1 $this->_define_array($this->protocol_flags); - $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); + $this->host = $host; + $this->port = $port; + $this->connectionTimeout = $timeout; + $this->cipher = $cipher; + } + + /** + * Connect to an SSHv1 server + * + * @return Boolean + * @access private + */ + function _connect() + { + $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout); if (!$this->fsock) { - user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); - return; + user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr")); + return false; } $this->server_identification = $init_line = fgets($this->fsock, 255); @@ -521,11 +580,11 @@ class Net_SSH1 if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) { user_error('Can only connect to SSH servers'); - return; + return false; } if ($parts[1][0] != 1) { user_error("Cannot connect to SSH $parts[1] servers"); - return; + return false; } fputs($this->fsock, $this->identifier."\r\n"); @@ -533,7 +592,7 @@ class Net_SSH1 $response = $this->_get_binary_packet(); if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) { user_error('Expected SSH_SMSG_PUBLIC_KEY'); - return; + return false; } $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8); @@ -613,12 +672,12 @@ class Net_SSH1 ); } - $cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : NET_SSH1_CIPHER_3DES; + $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : NET_SSH1_CIPHER_3DES; $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0); if (!$this->_send_binary_packet($data)) { user_error('Error sending SSH_CMSG_SESSION_KEY'); - return; + return false; } switch ($cipher) { @@ -645,7 +704,7 @@ class Net_SSH1 break; //case NET_SSH1_CIPHER_RC4: // if (!class_exists('Crypt_RC4')) { - // include_once('Crypt/RC4.php'); + // include_once 'Crypt/RC4.php'; // } // $this->crypto = new Crypt_RC4(); // $this->crypto->enableContinuousBuffer(); @@ -657,10 +716,12 @@ class Net_SSH1 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { user_error('Expected SSH_SMSG_SUCCESS'); - return; + return false; } - $this->bitmap = NET_SSH1_MASK_CONSTRUCTOR; + $this->bitmap = NET_SSH1_MASK_CONNECTED; + + return true; } /** @@ -674,6 +735,13 @@ class Net_SSH1 function login($username, $password = '') { if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) { + $this->bitmap |= NET_SSH1_MASK_CONSTRUCTOR; + if (!$this->_connect()) { + return false; + } + } + + if (!($this->bitmap & NET_SSH1_MASK_CONNECTED)) { return false; } @@ -1060,6 +1128,7 @@ class Net_SSH1 $padding_length = 8 - ($temp['length'] & 7); $length = $temp['length'] + $padding_length; + $raw = ''; while ($length > 0) { $temp = fread($this->fsock, $length); diff --git a/lam/lib/3rdParty/phpseclib/Net/SSH2.php b/lam/lib/3rdParty/phpseclib/Net/SSH2.php index 2fddb68a..d6134562 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SSH2.php +++ b/lam/lib/3rdParty/phpseclib/Net/SSH2.php @@ -8,7 +8,7 @@ * Here are some examples of how to use this library: * * login('username', 'password')) { @@ -22,8 +22,8 @@ * * * setPassword('whatever'); @@ -61,7 +61,7 @@ * @category Net * @package Net_SSH2 * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -73,10 +73,11 @@ * @access private */ define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); -define('NET_SSH2_MASK_LOGIN_REQ', 0x00000002); -define('NET_SSH2_MASK_LOGIN', 0x00000004); -define('NET_SSH2_MASK_SHELL', 0x00000008); -define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000010); +define('NET_SSH2_MASK_CONNECTED', 0x00000002); +define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004); +define('NET_SSH2_MASK_LOGIN', 0x00000008); +define('NET_SSH2_MASK_SHELL', 0x00000010); +define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020); /**#@-*/ /**#@+ @@ -145,7 +146,6 @@ define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024); * * @package Net_SSH2 * @author Jim Wigginton - * @version 0.1.0 * @access public */ class Net_SSH2 @@ -191,100 +191,100 @@ class Net_SSH2 * Server Identifier * * @see Net_SSH2::getServerIdentification() - * @var String + * @var mixed false or Array * @access private */ - var $server_identifier = ''; + var $server_identifier = false; /** * Key Exchange Algorithms * * @see Net_SSH2::getKexAlgorithims() - * @var Array + * @var mixed false or Array * @access private */ - var $kex_algorithms; + var $kex_algorithms = false; /** * Server Host Key Algorithms * * @see Net_SSH2::getServerHostKeyAlgorithms() - * @var Array + * @var mixed false or Array * @access private */ - var $server_host_key_algorithms; + var $server_host_key_algorithms = false; /** * Encryption Algorithms: Client to Server * * @see Net_SSH2::getEncryptionAlgorithmsClient2Server() - * @var Array + * @var mixed false or Array * @access private */ - var $encryption_algorithms_client_to_server; + var $encryption_algorithms_client_to_server = false; /** * Encryption Algorithms: Server to Client * * @see Net_SSH2::getEncryptionAlgorithmsServer2Client() - * @var Array + * @var mixed false or Array * @access private */ - var $encryption_algorithms_server_to_client; + var $encryption_algorithms_server_to_client = false; /** * MAC Algorithms: Client to Server * * @see Net_SSH2::getMACAlgorithmsClient2Server() - * @var Array + * @var mixed false or Array * @access private */ - var $mac_algorithms_client_to_server; + var $mac_algorithms_client_to_server = false; /** * MAC Algorithms: Server to Client * * @see Net_SSH2::getMACAlgorithmsServer2Client() - * @var Array + * @var mixed false or Array * @access private */ - var $mac_algorithms_server_to_client; + var $mac_algorithms_server_to_client = false; /** * Compression Algorithms: Client to Server * * @see Net_SSH2::getCompressionAlgorithmsClient2Server() - * @var Array + * @var mixed false or Array * @access private */ - var $compression_algorithms_client_to_server; + var $compression_algorithms_client_to_server = false; /** * Compression Algorithms: Server to Client * * @see Net_SSH2::getCompressionAlgorithmsServer2Client() - * @var Array + * @var mixed false or Array * @access private */ - var $compression_algorithms_server_to_client; + var $compression_algorithms_server_to_client = false; /** * Languages: Server to Client * * @see Net_SSH2::getLanguagesServer2Client() - * @var Array + * @var mixed false or Array * @access private */ - var $languages_server_to_client; + var $languages_server_to_client = false; /** * Languages: Client to Server * * @see Net_SSH2::getLanguagesClient2Server() - * @var Array + * @var mixed false or Array * @access private */ - var $languages_client_to_server; + var $languages_client_to_server = false; /** * Block Size for Server to Client Encryption @@ -670,6 +670,7 @@ class Net_SSH2 /** * Time of first network activity * + * @var Integer * @access private */ var $last_packet; @@ -685,6 +686,7 @@ class Net_SSH2 /** * Flag to request a PTY when using exec() * + * @var Boolean * @see Net_SSH2::enablePTY() * @access private */ @@ -693,6 +695,7 @@ class Net_SSH2 /** * Flag set while exec() is running when using enablePTY() * + * @var Boolean * @access private */ var $in_request_pty_exec = false; @@ -700,6 +703,7 @@ class Net_SSH2 /** * Flag set after startSubsystem() is called * + * @var Boolean * @access private */ var $in_subsystem; @@ -707,6 +711,7 @@ class Net_SSH2 /** * Contents of stdError * + * @var String * @access private */ var $stdErrorLog; @@ -715,6 +720,7 @@ class Net_SSH2 * The Last Interactive Response * * @see Net_SSH2::_keyboard_interactive_process() + * @var String * @access private */ var $last_interactive_response = ''; @@ -723,6 +729,7 @@ class Net_SSH2 * Keyboard Interactive Request / Responses * * @see Net_SSH2::_keyboard_interactive_process() + * @var Array * @access private */ var $keyboard_requests_responses = array(); @@ -735,6 +742,7 @@ class Net_SSH2 * * @see Net_SSH2::_filter() * @see Net_SSH2::getBannerMessage() + * @var String * @access private */ var $banner_message = ''; @@ -742,7 +750,8 @@ class Net_SSH2 /** * Did read() timeout or return normally? * - * @see Net_SSH2::isTimeout + * @see Net_SSH2::isTimeout() + * @var Boolean * @access private */ var $is_timeout = false; @@ -750,7 +759,8 @@ class Net_SSH2 /** * Log Boundary * - * @see Net_SSH2::_format_log + * @see Net_SSH2::_format_log() + * @var String * @access private */ var $log_boundary = ':'; @@ -758,7 +768,8 @@ class Net_SSH2 /** * Log Long Width * - * @see Net_SSH2::_format_log + * @see Net_SSH2::_format_log() + * @var Integer * @access private */ var $log_long_width = 65; @@ -766,19 +777,76 @@ class Net_SSH2 /** * Log Short Width * - * @see Net_SSH2::_format_log + * @see Net_SSH2::_format_log() + * @var Integer * @access private */ var $log_short_width = 16; /** - * Default Constructor. + * Hostname * - * Connects to an SSHv2 server + * @see Net_SSH2::Net_SSH2() + * @see Net_SSH2::_connect() + * @var String + * @access private + */ + var $host; + + /** + * Port Number + * + * @see Net_SSH2::Net_SSH2() + * @see Net_SSH2::_connect() + * @var Integer + * @access private + */ + var $port; + + /** + * Timeout for initial connection + * + * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like + * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor, + * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be + * 10 seconds. It is used by fsockopen() and the initial stream_select in that function. + * + * @see Net_SSH2::Net_SSH2() + * @see Net_SSH2::_connect() + * @var Integer + * @access private + */ + var $connectionTimeout; + + /** + * Number of columns for terminal window size + * + * @see Net_SSH2::getWindowColumns() + * @see Net_SSH2::setWindowColumns() + * @see Net_SSH2::setWindowSize() + * @var Integer + * @access private + */ + var $windowColumns = 80; + + /** + * Number of columns for terminal window size + * + * @see Net_SSH2::getWindowRows() + * @see Net_SSH2::setWindowRows() + * @see Net_SSH2::setWindowSize() + * @var Integer + * @access private + */ + var $windowRows = 24; + + /** + * Default Constructor. * * @param String $host * @param optional Integer $port * @param optional Integer $timeout + * @see Net_SSH2::login() * @return Net_SSH2 * @access public */ @@ -798,7 +866,6 @@ class Net_SSH2 include_once 'Crypt/Hash.php'; } - $this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5 $this->message_numbers = array( 1 => 'NET_SSH2_MSG_DISCONNECT', 2 => 'NET_SSH2_MSG_IGNORE', @@ -869,19 +936,43 @@ class Net_SSH2 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE') ); + $this->host = $host; + $this->port = $port; + $this->connectionTimeout = $timeout; + } + + /** + * Connect to an SSHv2 server + * + * @return Boolean + * @access private + */ + function _connect() + { + if ($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) { + return false; + } + + $this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR; + + $timeout = $this->connectionTimeout; + $host = $this->host . ':' . $this->port; + + $this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5 + $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); + $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $timeout); if (!$this->fsock) { user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); - return; + return false; } $elapsed = strtok(microtime(), ' ') + strtok('') - $start; $timeout-= $elapsed; if ($timeout <= 0) { - user_error(rtrim("Cannot connect to $host. Timeout error")); - return; + user_error("Cannot connect to $host. Timeout error"); + return false; } $read = array($this->fsock); @@ -893,8 +984,8 @@ class Net_SSH2 // on windows this returns a "Warning: Invalid CRT parameters detected" error // the !count() is done as a workaround for if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { - user_error(rtrim("Cannot connect to $host. Banner timeout")); - return; + user_error("Cannot connect to $host. Banner timeout"); + return false; } /* According to the SSH2 specs, @@ -933,7 +1024,7 @@ class Net_SSH2 if ($matches[1] != '1.99' && $matches[1] != '2.0') { user_error("Cannot connect to SSH $matches[1] servers"); - return; + return false; } fputs($this->fsock, $this->identifier . "\r\n"); @@ -941,19 +1032,21 @@ class Net_SSH2 $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); - return; + return false; } if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { user_error('Expected SSH_MSG_KEXINIT'); - return; + return false; } if (!$this->_key_exchange($response)) { - return; + return false; } - $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR; + $this->bitmap|= NET_SSH2_MASK_CONNECTED; + + return true; } /** @@ -1011,7 +1104,7 @@ class Net_SSH2 'arcfour256', 'arcfour128', - 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key + //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key // CTR modes from : 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key @@ -1039,34 +1132,34 @@ class Net_SSH2 '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode '3des-cbc', // REQUIRED three-key 3DES in CBC mode - 'none' // OPTIONAL no encryption; NOT RECOMMENDED + //'none' // OPTIONAL no encryption; NOT RECOMMENDED ); - if (!$this->_is_includable('Crypt/RC4.php')) { + if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('arcfour256', 'arcfour128', 'arcfour') ); } - if (!$this->_is_includable('Crypt/Rijndael.php')) { + if (phpseclib_resolve_include_path('Crypt/Rijndael.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc') ); } - if (!$this->_is_includable('Crypt/Twofish.php')) { + if (phpseclib_resolve_include_path('Crypt/Twofish.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc') ); } - if (!$this->_is_includable('Crypt/Blowfish.php')) { + if (phpseclib_resolve_include_path('Crypt/Blowfish.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('blowfish-ctr', 'blowfish-cbc') ); } - if (!$this->_is_includable('Crypt/TripleDES.php')) { + if (phpseclib_resolve_include_path('Crypt/TripleDES.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, array('3des-ctr', '3des-cbc') @@ -1075,12 +1168,15 @@ class Net_SSH2 $encryption_algorithms = array_values($encryption_algorithms); } - static $mac_algorithms = array( + $mac_algorithms = array( + // from : + 'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32) + 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20) 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20) 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16) 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16) - 'none' // OPTIONAL no MAC; NOT RECOMMENDED + //'none' // OPTIONAL no MAC; NOT RECOMMENDED ); static $compression_algorithms = array( @@ -1605,6 +1701,10 @@ class Net_SSH2 $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none' switch ($mac_algorithms[$i]) { + case 'hmac-sha2-256': + $this->hmac_create = new Crypt_Hash('sha256'); + $createKeyLength = 32; + break; case 'hmac-sha1': $this->hmac_create = new Crypt_Hash('sha1'); $createKeyLength = 20; @@ -1631,6 +1731,11 @@ class Net_SSH2 $checkKeyLength = 0; $this->hmac_size = 0; switch ($mac_algorithms[$i]) { + case 'hmac-sha2-256': + $this->hmac_check = new Crypt_Hash('sha256'); + $checkKeyLength = 32; + $this->hmac_size = 32; + break; case 'hmac-sha1': $this->hmac_check = new Crypt_Hash('sha1'); $checkKeyLength = 20; @@ -1711,6 +1816,12 @@ class Net_SSH2 */ function _login($username) { + if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { + if (!$this->_connect()) { + return false; + } + } + $args = array_slice(func_get_args(), 1); if (empty($args)) { return $this->_login_helper($username); @@ -1736,7 +1847,7 @@ class Net_SSH2 */ function _login_helper($username, $password = null) { - if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { + if (!($this->bitmap & NET_SSH2_MASK_CONNECTED)) { return false; } @@ -1968,7 +2079,6 @@ class Net_SSH2 if (!count($responses) && $num_prompts) { $this->last_interactive_response = $orig; - $this->bitmap |= NET_SSH_MASK_LOGIN_INTERACTIVE; return false; } @@ -2151,11 +2261,11 @@ class Net_SSH2 /** * Execute Command * - * If $block is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually. + * If $callback is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually. * In all likelihood, this is not a feature you want to be taking advantage of. * * @param String $command - * @param optional Boolean $block + * @param optional Callback $callback * @return String * @access public */ @@ -2173,7 +2283,7 @@ class Net_SSH2 // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, // honestly, if you're transfering more than 2GB, you probably shouldn't be using phpseclib, anyway. // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info - $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; + $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = $this->window_size; // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy // uses 0x4000, that's what will be used here, as well. $packet_size = 0x4000; @@ -2196,7 +2306,7 @@ class Net_SSH2 $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = pack('CNNa*CNa*N5a*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', - 80, 24, 0, 0, strlen($terminal_modes), $terminal_modes); + $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); if (!$this->_send_binary_packet($packet)) { return false; @@ -2258,7 +2368,10 @@ class Net_SSH2 return false; default: if (is_callable($callback)) { - $callback($temp); + if (call_user_func($callback, $temp) === true) { + $this->_close_channel(NET_SSH2_CHANNEL_EXEC); + return true; + } } else { $output.= $temp; } @@ -2280,7 +2393,7 @@ class Net_SSH2 return true; } - $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF; + $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = $this->window_size; $packet_size = 0x4000; $packet = pack('CNa*N3', @@ -2300,7 +2413,7 @@ class Net_SSH2 $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = pack('CNNa*CNa*N5a*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', - 80, 24, 0, 0, strlen($terminal_modes), $terminal_modes); + $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); if (!$this->_send_binary_packet($packet)) { return false; @@ -2557,11 +2670,12 @@ class Net_SSH2 /** * Is the connection still active? * + * @return boolean * @access public */ function isConnected() { - return $this->bitmap & NET_SSH2_MASK_LOGIN; + return (bool) ($this->bitmap & NET_SSH2_MASK_CONNECTED); } /** @@ -2611,6 +2725,11 @@ class Net_SSH2 $buffer = ''; while ($remaining_length > 0) { $temp = fread($this->fsock, $remaining_length); + if ($temp === false || feof($this->fsock)) { + user_error('Error reading from socket'); + $this->bitmap = 0; + return false; + } $buffer.= $temp; $remaining_length-= strlen($temp); } @@ -2624,7 +2743,11 @@ class Net_SSH2 if ($this->hmac_check !== false) { $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))) { + if ($hmac === false || strlen($hmac) != $this->hmac_size) { + user_error('Error reading socket'); + $this->bitmap = 0; + return false; + } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { user_error('Invalid HMAC'); return false; } @@ -2688,7 +2811,7 @@ class Net_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 - if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { + if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->banner_message = utf8_decode($this->_string_shift($payload, $length)); @@ -2696,7 +2819,7 @@ class Net_SSH2 } // only called when we've already logged in - if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { + if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { switch (ord($payload[0])) { case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 $this->_string_shift($payload, 1); @@ -2763,6 +2886,20 @@ class Net_SSH2 $this->quiet_mode = false; } + /** + * Returns whether Quiet Mode is enabled or not + * + * @see Net_SSH2::enableQuietMode() + * @see Net_SSH2::disableQuietMode() + * + * @access public + * @return boolean + */ + function isQuietModeEnabled() + { + return $this->quiet_mode; + } + /** * Enable request-pty when using exec() * @@ -2783,6 +2920,20 @@ class Net_SSH2 $this->request_pty = false; } + /** + * Returns whether request-pty is enabled or not + * + * @see Net_SSH2::enablePTY() + * @see Net_SSH2::disablePTY() + * + * @access public + * @return boolean + */ + function isPTYEnabled() + { + return $this->request_pty; + } + /** * Gets channel data * @@ -2834,7 +2985,7 @@ class Net_SSH2 extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); - $this->window_size_server_to_client[$channel]-= strlen($response) + 4; + $this->window_size_server_to_client[$channel]-= strlen($response); // resize the window, if appropriate if ($this->window_size_server_to_client[$channel] < 0) { @@ -2908,7 +3059,7 @@ class Net_SSH2 // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); $data = $this->_string_shift($response, $length); - $this->stdErrorLog .= $data; + $this->stdErrorLog.= $data; if ($skip_extended || $this->quiet_mode) { break; } @@ -3124,54 +3275,37 @@ class Net_SSH2 */ function _send_channel_packet($client_channel, $data) { - /* The maximum amount of data allowed is determined by the maximum - packet size for the channel, and the current window size, whichever - is smaller. - - -- http://tools.ietf.org/html/rfc4254#section-5.2 */ - $max_size = min( - $this->packet_size_client_to_server[$client_channel], - $this->window_size_client_to_server[$client_channel] - ) - 4; - while (strlen($data) > $max_size) { + while (strlen($data)) { if (!$this->window_size_client_to_server[$client_channel]) { $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; // using an invalid channel will let the buffers be built up for the valid channels - $output = $this->_get_channel_packet(-1); + $this->_get_channel_packet(-1); $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - $max_size = min( - $this->packet_size_client_to_server[$client_channel], - $this->window_size_client_to_server[$client_channel] - ) - 4; } + /* The maximum amount of data allowed is determined by the maximum + packet size for the channel, and the current window size, whichever + is smaller. + -- http://tools.ietf.org/html/rfc4254#section-5.2 */ + $max_size = min( + $this->packet_size_client_to_server[$client_channel], + $this->window_size_client_to_server[$client_channel] + ); + + $temp = $this->_string_shift($data, $max_size); $packet = pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], - $max_size, - $this->_string_shift($data, $max_size) + strlen($temp), + $temp ); - - $this->window_size_client_to_server[$client_channel]-= $max_size + 4; - + $this->window_size_client_to_server[$client_channel]-= strlen($temp); if (!$this->_send_binary_packet($packet)) { return false; } } - if (strlen($data) >= $this->window_size_client_to_server[$client_channel] - 4) { - $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - $this->_get_channel_packet(-1); - $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - } - - $this->window_size_client_to_server[$client_channel]-= strlen($data) + 4; - - return $this->_send_binary_packet(pack('CN2a*', - NET_SSH2_MSG_CHANNEL_DATA, - $this->server_channels[$client_channel], - strlen($data), - $data)); + return true; } /** @@ -3220,7 +3354,7 @@ class Net_SSH2 */ function _disconnect($reason) { - if ($this->bitmap) { + if ($this->bitmap & NET_SSH2_MASK_CONNECTED) { $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); $this->_send_binary_packet($data); $this->bitmap = 0; @@ -3374,6 +3508,8 @@ class Net_SSH2 */ function getServerIdentification() { + $this->_connect(); + return $this->server_identifier; } @@ -3385,6 +3521,8 @@ class Net_SSH2 */ function getKexAlgorithms() { + $this->_connect(); + return $this->kex_algorithms; } @@ -3396,6 +3534,8 @@ class Net_SSH2 */ function getServerHostKeyAlgorithms() { + $this->_connect(); + return $this->server_host_key_algorithms; } @@ -3407,6 +3547,8 @@ class Net_SSH2 */ function getEncryptionAlgorithmsClient2Server() { + $this->_connect(); + return $this->encryption_algorithms_client_to_server; } @@ -3418,6 +3560,8 @@ class Net_SSH2 */ function getEncryptionAlgorithmsServer2Client() { + $this->_connect(); + return $this->encryption_algorithms_server_to_client; } @@ -3429,6 +3573,8 @@ class Net_SSH2 */ function getMACAlgorithmsClient2Server() { + $this->_connect(); + return $this->mac_algorithms_client_to_server; } @@ -3440,6 +3586,8 @@ class Net_SSH2 */ function getMACAlgorithmsServer2Client() { + $this->_connect(); + return $this->mac_algorithms_server_to_client; } @@ -3451,6 +3599,8 @@ class Net_SSH2 */ function getCompressionAlgorithmsClient2Server() { + $this->_connect(); + return $this->compression_algorithms_client_to_server; } @@ -3462,6 +3612,8 @@ class Net_SSH2 */ function getCompressionAlgorithmsServer2Client() { + $this->_connect(); + return $this->compression_algorithms_server_to_client; } @@ -3473,6 +3625,8 @@ class Net_SSH2 */ function getLanguagesServer2Client() { + $this->_connect(); + return $this->languages_server_to_client; } @@ -3484,6 +3638,8 @@ class Net_SSH2 */ function getLanguagesClient2Server() { + $this->_connect(); + return $this->languages_client_to_server; } @@ -3512,6 +3668,12 @@ class Net_SSH2 */ function getServerPublicHostKey() { + if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { + if (!$this->_connect()) { + return false; + } + } + $signature = $this->signature; $server_public_host_key = $this->server_public_host_key; @@ -3589,8 +3751,9 @@ class Net_SSH2 $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - $nLength = $temp['length']; + $rawN = $this->_string_shift($server_public_host_key, $temp['length']); + $n = new Math_BigInteger($rawN, -256); + $nLength = strlen(ltrim($rawN, "\0")); /* $temp = unpack('Nlength', $this->_string_shift($signature, 4)); @@ -3627,7 +3790,7 @@ class Net_SSH2 $s = $s->toBytes(); $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); - $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h; + $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h; if ($s != $h) { user_error('Bad server signature'); @@ -3657,30 +3820,59 @@ class Net_SSH2 } /** - * Is a path includable? + * Returns the number of columns for the terminal window size. * - * @return Boolean - * @access private + * @return Integer + * @access public */ - function _is_includable($suffix) + function getWindowColumns() { - // stream_resolve_include_path was introduced in PHP 5.3.2 - if (function_exists('stream_resolve_include_path')) { - return stream_resolve_include_path($suffix) !== false; - } + return $this->windowColumns; + } - $paths = PATH_SEPARATOR == ':' ? - preg_split('#(?windowRows; + } - if (file_exists($file)) { - return true; - } - } + /** + * Sets the number of columns for the terminal window size. + * + * @param Integer $value + * @access public + */ + function setWindowColumns($value) + { + $this->windowColumns = $value; + } - return false; + /** + * Sets the number of rows for the terminal window size. + * + * @param Integer $value + * @access public + */ + function setWindowRows($value) + { + $this->windowRows = $value; + } + + /** + * Sets the number of columns and rows for the terminal window size. + * + * @param Integer $columns + * @param Integer $rows + * @access public + */ + function setWindowSize($columns = 80, $rows = 24) + { + $this->windowColumns = $columns; + $this->windowRows = $rows; } } diff --git a/lam/lib/3rdParty/phpseclib/System/SSH/Agent.php b/lam/lib/3rdParty/phpseclib/System/SSH/Agent.php new file mode 100644 index 00000000..6b1e5279 --- /dev/null +++ b/lam/lib/3rdParty/phpseclib/System/SSH/Agent.php @@ -0,0 +1,313 @@ + + * login('username', $agent)) { + * exit('Login Failed'); + * } + * + * echo $ssh->exec('pwd'); + * echo $ssh->exec('ls -la'); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category System + * @package System_SSH_Agent + * @author Jim Wigginton + * @copyright 2014 Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + * @internal See http://api.libssh.org/rfc/PROTOCOL.agent + */ + +/**#@+ + * Message numbers + * + * @access private + */ +// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1) +define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11); +// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2). +define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12); +define('SYSTEM_SSH_AGENT_FAILURE', 5); +// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3) +define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13); +// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) +define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); +/**#@-*/ + +/** + * Pure-PHP ssh-agent client identity object + * + * Instantiation should only be performed by System_SSH_Agent class. + * This could be thought of as implementing an interface that Crypt_RSA + * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. + * The methods in this interface would be getPublicKey, setSignatureMode + * and sign since those are the methods phpseclib looks for to perform + * public key authentication. + * + * @package System_SSH_Agent + * @author Jim Wigginton + * @access internal + */ +class System_SSH_Agent_Identity +{ + /** + * Key Object + * + * @var Crypt_RSA + * @access private + * @see System_SSH_Agent_Identity::getPublicKey() + */ + var $key; + + /** + * Key Blob + * + * @var String + * @access private + * @see System_SSH_Agent_Identity::sign() + */ + var $key_blob; + + /** + * Socket Resource + * + * @var Resource + * @access private + * @see System_SSH_Agent_Identity::sign() + */ + var $fsock; + + /** + * Default Constructor. + * + * @param Resource $fsock + * @return System_SSH_Agent_Identity + * @access private + */ + function System_SSH_Agent_Identity($fsock) + { + $this->fsock = $fsock; + } + + /** + * Set Public Key + * + * Called by System_SSH_Agent::requestIdentities() + * + * @param Crypt_RSA $key + * @access private + */ + function setPublicKey($key) + { + $this->key = $key; + $this->key->setPublicKey(); + } + + /** + * Set Public Key + * + * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key + * but this saves a small amount of computation. + * + * @param String $key_blob + * @access private + */ + function setPublicKeyBlob($key_blob) + { + $this->key_blob = $key_blob; + } + + /** + * Get Public Key + * + * Wrapper for $this->key->getPublicKey() + * + * @param Integer $format optional + * @return Mixed + * @access public + */ + function getPublicKey($format = null) + { + return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format); + } + + /** + * Set Signature Mode + * + * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie. + * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1 + * + * @param Integer $mode + * @access public + */ + function setSignatureMode($mode) + { + } + + /** + * Create a signature + * + * See "2.6.2 Protocol 2 private key signature request" + * + * @param String $message + * @return String + * @access public + */ + function sign($message) + { + // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE + $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0); + $packet = pack('Na*', strlen($packet), $packet); + if (strlen($packet) != fputs($this->fsock, $packet)) { + user_error('Connection closed during signing'); + } + + $length = current(unpack('N', fread($this->fsock, 4))); + $type = ord(fread($this->fsock, 1)); + if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) { + user_error('Unable to retreive signature'); + } + + $signature_blob = fread($this->fsock, $length - 1); + // the only other signature format defined - ssh-dss - is the same length as ssh-rsa + // the + 12 is for the other various SSH added length fields + return substr($signature_blob, strlen('ssh-rsa') + 12); + } +} + +/** + * Pure-PHP ssh-agent client identity factory + * + * requestIdentities() method pumps out System_SSH_Agent_Identity objects + * + * @package System_SSH_Agent + * @author Jim Wigginton + * @access internal + */ +class System_SSH_Agent +{ + /** + * Socket Resource + * + * @var Resource + * @access private + */ + var $fsock; + + /** + * Default Constructor + * + * @return System_SSH_Agent + * @access public + */ + function System_SSH_Agent() + { + switch (true) { + case isset($_SERVER['SSH_AUTH_SOCK']): + $address = $_SERVER['SSH_AUTH_SOCK']; + break; + case isset($_ENV['SSH_AUTH_SOCK']): + $address = $_ENV['SSH_AUTH_SOCK']; + break; + default: + user_error('SSH_AUTH_SOCK not found'); + return false; + } + + $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); + if (!$this->fsock) { + user_error("Unable to connect to ssh-agent (Error $errno: $errstr)"); + } + } + + /** + * Request Identities + * + * See "2.5.2 Requesting a list of protocol 2 keys" + * Returns an array containing zero or more System_SSH_Agent_Identity objects + * + * @return Array + * @access public + */ + function requestIdentities() + { + if (!$this->fsock) { + return array(); + } + + $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES); + if (strlen($packet) != fputs($this->fsock, $packet)) { + user_error('Connection closed while requesting identities'); + } + + $length = current(unpack('N', fread($this->fsock, 4))); + $type = ord(fread($this->fsock, 1)); + if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) { + user_error('Unable to request identities'); + } + + $identities = array(); + $keyCount = current(unpack('N', fread($this->fsock, 4))); + for ($i = 0; $i < $keyCount; $i++) { + $length = current(unpack('N', fread($this->fsock, 4))); + $key_blob = fread($this->fsock, $length); + $length = current(unpack('N', fread($this->fsock, 4))); + $key_comment = fread($this->fsock, $length); + $length = current(unpack('N', substr($key_blob, 0, 4))); + $key_type = substr($key_blob, 4, $length); + switch ($key_type) { + case 'ssh-rsa': + if (!class_exists('Crypt_RSA')) { + include_once 'Crypt/RSA.php'; + } + $key = new Crypt_RSA(); + $key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment); + break; + case 'ssh-dss': + // not currently supported + break; + } + // resources are passed by reference by default + if (isset($key)) { + $identity = new System_SSH_Agent_Identity($this->fsock); + $identity->setPublicKey($key); + $identity->setPublicKeyBlob($key_blob); + $identities[] = $identity; + unset($key); + } + } + + return $identities; + } +} diff --git a/lam/lib/3rdParty/phpseclib/System/SSH_Agent.php b/lam/lib/3rdParty/phpseclib/System/SSH_Agent.php index 5c8cdf9f..2800ea00 100644 --- a/lam/lib/3rdParty/phpseclib/System/SSH_Agent.php +++ b/lam/lib/3rdParty/phpseclib/System/SSH_Agent.php @@ -1,26 +1,13 @@ - * login('username', $agent)) { - * exit('Login Failed'); - * } - * - * echo $ssh->exec('pwd'); - * echo $ssh->exec('ls -la'); - * ?> - * + * Originally System_SSH_Agent was accessed as System/SSH_Agent.php instead of + * System/SSH/Agent.php. The problem with this is that PSR0 compatible autoloaders + * don't support that kind of directory layout hence the package being moved and + * this "alias" being created to maintain backwards compatibility. * * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,273 +30,10 @@ * @category System * @package System_SSH_Agent * @author Jim Wigginton - * @copyright MMXIV Jim Wigginton + * @copyright 2014 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net * @internal See http://api.libssh.org/rfc/PROTOCOL.agent */ -/**#@+ - * Message numbers - * - * @access private - */ -// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1) -define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11); -// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2). -define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12); -define('SYSTEM_SSH_AGENT_FAILURE', 5); -// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3) -define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13); -// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) -define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); -/**#@-*/ - -/** - * Pure-PHP ssh-agent client identity object - * - * Instantiation should only be performed by System_SSH_Agent class. - * This could be thought of as implementing an interface that Crypt_RSA - * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. - * The methods in this interface would be getPublicKey, setSignatureMode - * and sign since those are the methods phpseclib looks for to perform - * public key authentication. - * - * @package System_SSH_Agent - * @author Jim Wigginton - * @version 0.1.0 - * @access internal - */ -class System_SSH_Agent_Identity -{ - /** - * Key Object - * - * @var Crypt_RSA - * @access private - * @see System_SSH_Agent_Identity::getPublicKey() - */ - var $key; - - /** - * Key Blob - * - * @var String - * @access private - * @see System_SSH_Agent_Identity::sign() - */ - var $key_blob; - - /** - * Socket Resource - * - * @var Resource - * @access private - * @see System_SSH_Agent_Identity::sign() - */ - var $fsock; - - /** - * Default Constructor. - * - * @param Resource $fsock - * @return System_SSH_Agent_Identity - * @access private - */ - function System_SSH_Agent_Identity($fsock) - { - $this->fsock = $fsock; - } - - /** - * Set Public Key - * - * Called by System_SSH_Agent::requestIdentities() - * - * @param Crypt_RSA $key - * @access private - */ - function setPublicKey($key) - { - $this->key = $key; - $this->key->setPublicKey(); - } - - /** - * Set Public Key - * - * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key - * but this saves a small amount of computation. - * - * @param String $key_blob - * @access private - */ - function setPublicKeyBlob($key_blob) - { - $this->key_blob = $key_blob; - } - - /** - * Get Public Key - * - * Wrapper for $this->key->getPublicKey() - * - * @param Integer $format optional - * @return Mixed - * @access public - */ - function getPublicKey($format = null) - { - return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format); - } - - /** - * Set Signature Mode - * - * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie. - * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1 - * - * @param Integer $mode - * @access public - */ - function setSignatureMode($mode) - { - } - - /** - * Create a signature - * - * See "2.6.2 Protocol 2 private key signature request" - * - * @param String $message - * @return String - * @access public - */ - function sign($message) - { - // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE - $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0); - $packet = pack('Na*', strlen($packet), $packet); - if (strlen($packet) != fputs($this->fsock, $packet)) { - user_error('Connection closed during signing'); - } - - $length = current(unpack('N', fread($this->fsock, 4))); - $type = ord(fread($this->fsock, 1)); - if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) { - user_error('Unable to retreive signature'); - } - - $signature_blob = fread($this->fsock, $length - 1); - // the only other signature format defined - ssh-dss - is the same length as ssh-rsa - // the + 12 is for the other various SSH added length fields - return substr($signature_blob, strlen('ssh-rsa') + 12); - } -} - -/** - * Pure-PHP ssh-agent client identity factory - * - * requestIdentities() method pumps out System_SSH_Agent_Identity objects - * - * @package System_SSH_Agent - * @author Jim Wigginton - * @version 0.1.0 - * @access internal - */ -class System_SSH_Agent -{ - /** - * Socket Resource - * - * @var Resource - * @access private - */ - var $fsock; - - /** - * Default Constructor - * - * @return System_SSH_Agent - * @access public - */ - function System_SSH_Agent() - { - switch (true) { - case isset($_SERVER['SSH_AUTH_SOCK']): - $address = $_SERVER['SSH_AUTH_SOCK']; - break; - case isset($_ENV['SSH_AUTH_SOCK']): - $address = $_ENV['SSH_AUTH_SOCK']; - break; - default: - user_error('SSH_AUTH_SOCK not found'); - return false; - } - - $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); - if (!$this->fsock) { - user_error("Unable to connect to ssh-agent (Error $errno: $errstr)"); - } - } - - /** - * Request Identities - * - * See "2.5.2 Requesting a list of protocol 2 keys" - * Returns an array containing zero or more System_SSH_Agent_Identity objects - * - * @return Array - * @access public - */ - function requestIdentities() - { - if (!$this->fsock) { - return array(); - } - - $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES); - if (strlen($packet) != fputs($this->fsock, $packet)) { - user_error('Connection closed while requesting identities'); - } - - $length = current(unpack('N', fread($this->fsock, 4))); - $type = ord(fread($this->fsock, 1)); - if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) { - user_error('Unable to request identities'); - } - - $identities = array(); - $keyCount = current(unpack('N', fread($this->fsock, 4))); - for ($i = 0; $i < $keyCount; $i++) { - $length = current(unpack('N', fread($this->fsock, 4))); - $key_blob = fread($this->fsock, $length); - $length = current(unpack('N', fread($this->fsock, 4))); - $key_comment = fread($this->fsock, $length); - $length = current(unpack('N', substr($key_blob, 0, 4))); - $key_type = substr($key_blob, 4, $length); - switch ($key_type) { - case 'ssh-rsa': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $key = new Crypt_RSA(); - $key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment); - break; - case 'ssh-dss': - // not currently supported - break; - } - // resources are passed by reference by default - if (isset($key)) { - $identity = new System_SSH_Agent_Identity($this->fsock); - $identity->setPublicKey($key); - $identity->setPublicKeyBlob($key_blob); - $identities[] = $identity; - unset($key); - } - } - - return $identities; - } -} +require_once 'SSH/Agent.php';