diff --git a/lam-packaging/debian/copyright b/lam-packaging/debian/copyright
index 586f9bb4..ca07053c 100644
--- a/lam-packaging/debian/copyright
+++ b/lam-packaging/debian/copyright
@@ -422,7 +422,7 @@ main license and authors:
lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
-lib/3rdParty/phpseclib B Jim Wigginton
+lib/3rdParty/phpseclib B 2019 TerraFrost and other contributors
lib/3rdParty/Monolog B 2011 Jordi Boggiano
lib/3rdParty/Psr B 2012 PHP Framework Interoperability Group
lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB
diff --git a/lam/copyright b/lam/copyright
index 878733ed..0640e706 100644
--- a/lam/copyright
+++ b/lam/copyright
@@ -421,7 +421,7 @@ main license and authors:
lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
-lib/3rdParty/phpseclib B Jim Wigginton
+lib/3rdParty/phpseclib B 2019 TerraFrost and other contributors
lib/3rdParty/Monolog B 2011 Jordi Boggiano
lib/3rdParty/Psr B 2012 PHP Framework Interoperability Group
lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Base.php b/lam/lib/3rdParty/phpseclib/Crypt/Base.php
index fd99c44f..03b176e7 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/Base.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/Base.php
@@ -76,6 +76,10 @@ abstract class Base
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
const MODE_CFB = 3;
+ /**
+ * Encrypt / decrypt using the Cipher Feedback mode (8bit)
+ */
+ const MODE_CFB8 = 38;
/**
* Encrypt / decrypt using the Output Feedback mode.
*
@@ -479,6 +483,7 @@ abstract class Base
break;
case self::MODE_CTR:
case self::MODE_CFB:
+ case self::MODE_CFB8:
case self::MODE_OFB:
case self::MODE_STREAM:
$this->mode = $mode;
@@ -492,8 +497,8 @@ abstract class Base
$this->_setEngine();
// Determining whether inline crypting can be used by the cipher
- if ($this->use_inline_crypt !== false && function_exists('create_function')) {
- $this->use_inline_crypt = true;
+ if ($this->use_inline_crypt !== false) {
+ $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
}
}
@@ -644,10 +649,10 @@ abstract class Base
case !function_exists('hash_algos'):
case !in_array($hash, hash_algos()):
$i = 1;
+ $hmac = new Hash();
+ $hmac->setHash($hash);
+ $hmac->setKey($password);
while (strlen($key) < $dkLen) {
- $hmac = new Hash();
- $hmac->setHash($hash);
- $hmac->setKey($password);
$f = $u = $hmac->hash($salt . pack('N', $i++));
for ($j = 2; $j <= $count; ++$j) {
$u = $hmac->hash($u);
@@ -702,7 +707,7 @@ abstract class Base
case self::MODE_STREAM:
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
case self::MODE_ECB:
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
+ $result = @openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
case self::MODE_CBC:
$result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
@@ -762,6 +767,16 @@ abstract class Base
$iv = substr($ciphertext, -$this->block_size);
}
+ return $ciphertext;
+ case self::MODE_CFB8:
+ $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
+ if ($this->continuousBuffer) {
+ if (($len = strlen($ciphertext)) >= $this->block_size) {
+ $this->encryptIV = substr($ciphertext, -$this->block_size);
+ } else {
+ $this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
+ }
+ }
return $ciphertext;
case self::MODE_OFB:
return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
@@ -942,6 +957,24 @@ abstract class Base
$pos = $len;
}
break;
+ case self::MODE_CFB8:
+ $ciphertext = '';
+ $len = strlen($plaintext);
+ $iv = $this->encryptIV;
+
+ for ($i = 0; $i < $len; ++$i) {
+ $ciphertext .= ($c = $plaintext[$i] ^ $this->_encryptBlock($iv));
+ $iv = substr($iv, 1) . $c;
+ }
+
+ if ($this->continuousBuffer) {
+ if ($len >= $block_size) {
+ $this->encryptIV = substr($ciphertext, -$block_size);
+ } else {
+ $this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len);
+ }
+ }
+ break;
case self::MODE_OFB:
$xor = $this->encryptIV;
if (strlen($buffer['xor'])) {
@@ -1007,14 +1040,14 @@ abstract class Base
break;
case self::MODE_ECB:
if (!defined('OPENSSL_RAW_DATA')) {
- $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
+ $ciphertext.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
}
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
break;
case self::MODE_CBC:
if (!defined('OPENSSL_RAW_DATA')) {
$padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
- $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
+ $ciphertext.= substr(@openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
$offset = 2 * $this->block_size;
} else {
$offset = $this->block_size;
@@ -1072,6 +1105,16 @@ abstract class Base
$iv = substr($ciphertext, -$this->block_size);
}
break;
+ case self::MODE_CFB8:
+ $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
+ if ($this->continuousBuffer) {
+ if (($len = strlen($ciphertext)) >= $this->block_size) {
+ $this->decryptIV = substr($ciphertext, -$this->block_size);
+ } else {
+ $this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
+ }
+ }
+ break;
case self::MODE_OFB:
$plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
}
@@ -1235,6 +1278,24 @@ abstract class Base
$pos = $len;
}
break;
+ case self::MODE_CFB8:
+ $plaintext = '';
+ $len = strlen($ciphertext);
+ $iv = $this->decryptIV;
+
+ for ($i = 0; $i < $len; ++$i) {
+ $plaintext .= $ciphertext[$i] ^ $this->_encryptBlock($iv);
+ $iv = substr($iv, 1) . $ciphertext[$i];
+ }
+
+ if ($this->continuousBuffer) {
+ if ($len >= $block_size) {
+ $this->decryptIV = substr($ciphertext, -$block_size);
+ } else {
+ $this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len);
+ }
+ }
+ break;
case self::MODE_OFB:
$xor = $this->decryptIV;
if (strlen($buffer['xor'])) {
@@ -1297,7 +1358,7 @@ abstract class Base
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
- $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
+ $result = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
$buffer['ciphertext'].= $result;
}
@@ -1308,7 +1369,7 @@ abstract class Base
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
- $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
+ $otp = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
$this->_increment_str($xor);
$ciphertext.= $block ^ $otp;
@@ -1352,7 +1413,7 @@ abstract class Base
}
if ($this->continuousBuffer) {
if (!defined('OPENSSL_RAW_DATA')) {
- $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
+ $encryptIV.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
}
$encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
if ($overflow) {
@@ -1435,6 +1496,8 @@ abstract class Base
return 'ctr';
case self::MODE_CFB:
return 'cfb';
+ case self::MODE_CFB8:
+ return 'cfb8';
case self::MODE_OFB:
return 'ofb';
}
@@ -1788,6 +1851,7 @@ abstract class Base
self::MODE_ECB => MCRYPT_MODE_ECB,
self::MODE_CBC => MCRYPT_MODE_CBC,
self::MODE_CFB => 'ncfb',
+ self::MODE_CFB8 => MCRYPT_MODE_CFB,
self::MODE_OFB => MCRYPT_MODE_NOFB,
self::MODE_STREAM => MCRYPT_MODE_STREAM,
);
@@ -2359,6 +2423,52 @@ abstract class Base
$_pos = $_len;
}
+ return $_plaintext;
+ ';
+ break;
+ case self::MODE_CFB8:
+ $encrypt = $init_encrypt . '
+ $_ciphertext = "";
+ $_len = strlen($_text);
+ $_iv = $self->encryptIV;
+
+ for ($_i = 0; $_i < $_len; ++$_i) {
+ $in = $_iv;
+ '.$encrypt_block.'
+ $_ciphertext .= ($_c = $_text[$_i] ^ $in);
+ $_iv = substr($_iv, 1) . $_c;
+ }
+
+ if ($self->continuousBuffer) {
+ if ($_len >= '.$block_size.') {
+ $self->encryptIV = substr($_ciphertext, -'.$block_size.');
+ } else {
+ $self->encryptIV = substr($self->encryptIV, $_len - '.$block_size.') . substr($_ciphertext, -$_len);
+ }
+ }
+
+ return $_ciphertext;
+ ';
+ $decrypt = $init_encrypt . '
+ $_plaintext = "";
+ $_len = strlen($_text);
+ $_iv = $self->decryptIV;
+
+ for ($_i = 0; $_i < $_len; ++$_i) {
+ $in = $_iv;
+ '.$encrypt_block.'
+ $_plaintext .= $_text[$_i] ^ $in;
+ $_iv = substr($_iv, 1) . $_text[$_i];
+ }
+
+ if ($self->continuousBuffer) {
+ if ($_len >= '.$block_size.') {
+ $self->decryptIV = substr($_text, -'.$block_size.');
+ } else {
+ $self->decryptIV = substr($self->decryptIV, $_len - '.$block_size.') . substr($_text, -$_len);
+ }
+ }
+
return $_plaintext;
';
break;
@@ -2492,6 +2602,11 @@ abstract class Base
}
// Create the $inline function and return its name as string. Ready to run!
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+ eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
+ return $func;
+ }
+
return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
}
@@ -2550,4 +2665,44 @@ abstract class Base
return $result . pack('H*', sha1($hash));
}
}
+
+ /**
+ * Convert float to int
+ *
+ * On ARM CPUs converting floats to ints doesn't always work
+ *
+ * @access private
+ * @param string $x
+ * @return int
+ */
+ function safe_intval($x)
+ {
+ switch (true) {
+ case is_int($x):
+ // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
+ case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
+ return $x;
+ }
+ return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
+ ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
+ }
+
+ /**
+ * eval()'able string for in-line float to int
+ *
+ * @access private
+ * @return string
+ */
+ function safe_intval_inline()
+ {
+ switch (true) {
+ case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
+ case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
+ return '%s';
+ break;
+ default:
+ $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
+ return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
+ }
+ }
}
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php b/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php
index 19d0a020..74cc49de 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/Blowfish.php
@@ -294,7 +294,7 @@ class Blowfish extends Base
function setKeyLength($length)
{
if ($length < 32) {
- $this->key_length = 7;
+ $this->key_length = 4;
} elseif ($length > 448) {
$this->key_length = 56;
} else {
@@ -408,16 +408,14 @@ class Blowfish extends Base
for ($i = 0; $i < 16; $i+= 2) {
$l^= $p[$i];
- $r^= ($sb_0[$l >> 24 & 0xff] +
- $sb_1[$l >> 16 & 0xff] ^
+ $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
- $sb_3[$l & 0xff];
+ $sb_3[$l & 0xff]);
$r^= $p[$i + 1];
- $l^= ($sb_0[$r >> 24 & 0xff] +
- $sb_1[$r >> 16 & 0xff] ^
+ $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
- $sb_3[$r & 0xff];
+ $sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[17], $l ^ $p[16]);
}
@@ -443,16 +441,14 @@ class Blowfish extends Base
for ($i = 17; $i > 2; $i-= 2) {
$l^= $p[$i];
- $r^= ($sb_0[$l >> 24 & 0xff] +
- $sb_1[$l >> 16 & 0xff] ^
+ $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
- $sb_3[$l & 0xff];
+ $sb_3[$l & 0xff]);
$r^= $p[$i - 1];
- $l^= ($sb_0[$r >> 24 & 0xff] +
- $sb_1[$r >> 16 & 0xff] ^
+ $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
- $sb_3[$r & 0xff];
+ $sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[0], $l ^ $p[1]);
}
@@ -478,6 +474,8 @@ class Blowfish extends Base
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
+ $safeint = $this->safe_intval_inline();
+
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
@@ -513,16 +511,14 @@ class Blowfish extends Base
for ($i = 0; $i < 16; $i+= 2) {
$encrypt_block.= '
$l^= ' . $p[$i] . ';
- $r^= ($sb_0[$l >> 24 & 0xff] +
- $sb_1[$l >> 16 & 0xff] ^
+ $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
- $sb_3[$l & 0xff];
+ $sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i + 1] . ';
- $l^= ($sb_0[$r >> 24 & 0xff] +
- $sb_1[$r >> 16 & 0xff] ^
+ $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
- $sb_3[$r & 0xff];
+ $sb_3[$r & 0xff]') . ';
';
}
$encrypt_block.= '
@@ -542,16 +538,14 @@ class Blowfish extends Base
for ($i = 17; $i > 2; $i-= 2) {
$decrypt_block.= '
$l^= ' . $p[$i] . ';
- $r^= ($sb_0[$l >> 24 & 0xff] +
- $sb_1[$l >> 16 & 0xff] ^
+ $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
- $sb_3[$l & 0xff];
+ $sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i - 1] . ';
- $l^= ($sb_0[$r >> 24 & 0xff] +
- $sb_1[$r >> 16 & 0xff] ^
+ $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
- $sb_3[$r & 0xff];
+ $sb_3[$r & 0xff]') . ';
';
}
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/DES.php b/lam/lib/3rdParty/phpseclib/Crypt/DES.php
index 51220469..9a8225fb 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/DES.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/DES.php
@@ -1357,8 +1357,8 @@ class DES extends Base
$k[self::ENCRYPT][$i] = '$ke[' . $i . ']';
$k[self::DECRYPT][$i] = '$kd[' . $i . ']';
}
- $init_encrypt = '$ke = $self->keys[self::ENCRYPT];';
- $init_decrypt = '$kd = $self->keys[self::DECRYPT];';
+ $init_encrypt = '$ke = $self->keys[$self::ENCRYPT];';
+ $init_decrypt = '$kd = $self->keys[$self::DECRYPT];';
break;
}
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Hash.php b/lam/lib/3rdParty/phpseclib/Crypt/Hash.php
index 07665a16..a6166820 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/Hash.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/Hash.php
@@ -112,6 +112,15 @@ class Hash
*/
var $key = false;
+ /**
+ * Computed Key
+ *
+ * @see self::_computeKey()
+ * @var string
+ * @access private
+ */
+ var $computedKey = false;
+
/**
* Outer XOR (Internal HMAC)
*
@@ -130,6 +139,15 @@ class Hash
*/
var $ipad;
+ /**
+ * Engine
+ *
+ * @see self::setHash()
+ * @var string
+ * @access private
+ */
+ var $engine;
+
/**
* Default Constructor.
*
@@ -166,6 +184,43 @@ class Hash
function setKey($key = false)
{
$this->key = $key;
+ $this->_computeKey();
+ }
+
+ /**
+ * Pre-compute the key used by the HMAC
+ *
+ * Quoting http://tools.ietf.org/html/rfc2104#section-2, "Applications that use keys longer than B bytes
+ * will first hash the key using H and then use the resultant L byte string as the actual key to HMAC."
+ *
+ * As documented in https://www.reddit.com/r/PHP/comments/9nct2l/symfonypolyfill_hash_pbkdf2_correct_fix_for/
+ * when doing an HMAC multiple times it's faster to compute the hash once instead of computing it during
+ * every call
+ *
+ * @access private
+ */
+ function _computeKey()
+ {
+ if ($this->key === false) {
+ $this->computedKey = false;
+ return;
+ }
+
+ if (strlen($this->key) <= $this->b) {
+ $this->computedKey = $this->key;
+ return;
+ }
+
+ switch ($this->engine) {
+ case self::MODE_MHASH:
+ $this->computedKey = mhash($this->hash, $this->key);
+ break;
+ case self::MODE_HASH:
+ $this->computedKey = hash($this->hash, $this->key, true);
+ break;
+ case self::MODE_INTERNAL:
+ $this->computedKey = call_user_func($this->hash, $this->key);
+ }
}
/**
@@ -216,19 +271,38 @@ class Hash
}
switch ($hash) {
+ case 'md2-96':
case 'md2':
- $mode = CRYPT_HASH_MODE == self::MODE_HASH && in_array('md2', hash_algos()) ?
+ $this->b = 16;
+ case 'md5-96':
+ case 'sha1-96':
+ case 'sha224-96':
+ case 'sha256-96':
+ case 'md2':
+ case 'md5':
+ case 'sha1':
+ case 'sha224':
+ case 'sha256':
+ $this->b = 64;
+ break;
+ default:
+ $this->b = 128;
+ }
+
+ switch ($hash) {
+ case 'md2':
+ $this->engine = CRYPT_HASH_MODE == self::MODE_HASH && in_array('md2', hash_algos()) ?
self::MODE_HASH : self::MODE_INTERNAL;
break;
case 'sha384':
case 'sha512':
- $mode = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
+ $this->engine = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
break;
default:
- $mode = CRYPT_HASH_MODE;
+ $this->engine = CRYPT_HASH_MODE;
}
- switch ($mode) {
+ switch ($this->engine) {
case self::MODE_MHASH:
switch ($hash) {
case 'md5':
@@ -241,6 +315,7 @@ class Hash
default:
$this->hash = MHASH_SHA1;
}
+ $this->_computeKey(self::MODE_MHASH);
return;
case self::MODE_HASH:
switch ($hash) {
@@ -257,35 +332,33 @@ class Hash
default:
$this->hash = 'sha1';
}
+ $this->_computeKey(self::MODE_HASH);
return;
}
switch ($hash) {
case 'md2':
- $this->b = 16;
$this->hash = array($this, '_md2');
break;
case 'md5':
- $this->b = 64;
$this->hash = array($this, '_md5');
break;
case 'sha256':
- $this->b = 64;
$this->hash = array($this, '_sha256');
break;
case 'sha384':
case 'sha512':
- $this->b = 128;
$this->hash = array($this, '_sha512');
break;
case 'sha1':
default:
- $this->b = 64;
$this->hash = array($this, '_sha1');
}
$this->ipad = str_repeat(chr(0x36), $this->b);
$this->opad = str_repeat(chr(0x5C), $this->b);
+
+ $this->_computeKey(self::MODE_INTERNAL);
}
/**
@@ -297,33 +370,25 @@ class Hash
*/
function hash($text)
{
- $mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
-
if (!empty($this->key) || is_string($this->key)) {
- switch ($mode) {
+ switch ($this->engine) {
case self::MODE_MHASH:
- $output = mhash($this->hash, $text, $this->key);
+ $output = mhash($this->hash, $text, $this->computedKey);
break;
case self::MODE_HASH:
- $output = hash_hmac($this->hash, $text, $this->key, true);
+ $output = hash_hmac($this->hash, $text, $this->computedKey, true);
break;
case self::MODE_INTERNAL:
- /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
- resultant L byte string as the actual key to HMAC."
-
- -- http://tools.ietf.org/html/rfc2104#section-2 */
- $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
-
- $key = str_pad($key, $this->b, chr(0)); // step 1
- $temp = $this->ipad ^ $key; // step 2
- $temp .= $text; // step 3
- $temp = call_user_func($this->hash, $temp); // step 4
- $output = $this->opad ^ $key; // step 5
- $output.= $temp; // step 6
- $output = call_user_func($this->hash, $output); // step 7
+ $key = str_pad($this->computedKey, $this->b, chr(0)); // step 1
+ $temp = $this->ipad ^ $key; // step 2
+ $temp .= $text; // step 3
+ $temp = call_user_func($this->hash, $temp); // step 4
+ $output = $this->opad ^ $key; // step 5
+ $output.= $temp; // step 6
+ $output = call_user_func($this->hash, $output); // step 7
}
} else {
- switch ($mode) {
+ switch ($this->engine) {
case self::MODE_MHASH:
$output = mhash($this->hash, $text);
break;
@@ -802,7 +867,12 @@ class Hash
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
}
- return fmod($result, $mod);
+ if ((php_uname('m') & "\xDF\xDF\xDF") != 'ARM') {
+ return fmod($result, $mod);
+ }
+
+ return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
+ ((fmod(floor($result / 0x80000000), 2) & 1) << 31);
}
/**
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RC2.php b/lam/lib/3rdParty/phpseclib/Crypt/RC2.php
index e9cfa3f8..b2b9d48e 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/RC2.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/RC2.php
@@ -296,7 +296,7 @@ class RC2 extends Base
function setKeyLength($length)
{
if ($length < 8) {
- $this->default_key_length = 8;
+ $this->default_key_length = 1;
} elseif ($length > 1024) {
$this->default_key_length = 128;
} else {
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RC4.php b/lam/lib/3rdParty/phpseclib/Crypt/RC4.php
index 4812010c..25e4ff85 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/RC4.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/RC4.php
@@ -107,7 +107,7 @@ class RC4 extends Base
* @var string
* @access private
*/
- var $key = "\0";
+ var $key;
/**
* The Key Stream for decryption and encryption
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RSA.php b/lam/lib/3rdParty/phpseclib/Crypt/RSA.php
index 9670c01a..d2c6c7cb 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/RSA.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/RSA.php
@@ -182,6 +182,10 @@ class RSA
* PKCS#8 formatted private key
*/
const PRIVATE_FORMAT_PKCS8 = 8;
+ /**
+ * OpenSSH formatted private key
+ */
+ const PRIVATE_FORMAT_OPENSSH = 9;
/**#@-*/
/**#@+
@@ -468,23 +472,27 @@ class RSA
break;
case extension_loaded('openssl') && file_exists($this->configFile):
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
- ob_start();
- @phpinfo();
- $content = ob_get_contents();
- ob_end_clean();
-
- preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
-
$versions = array();
- if (!empty($matches[1])) {
- 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];
+ // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
+ if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
+ ob_start();
+ @phpinfo();
+ $content = ob_get_contents();
+ ob_end_clean();
+
+ preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
+
+ if (!empty($matches[1])) {
+ 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];
+ }
}
}
}
@@ -816,6 +824,58 @@ class RSA
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
return $key;
+ case self::PRIVATE_FORMAT_OPENSSH:
+ if ($num_primes != 2) {
+ return false;
+ }
+ $publicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']);
+ $privateKey = pack(
+ 'Na*Na*Na*Na*Na*Na*Na*',
+ strlen('ssh-rsa'),
+ 'ssh-rsa',
+ strlen($raw['modulus']),
+ $raw['modulus'],
+ strlen($raw['publicExponent']),
+ $raw['publicExponent'],
+ strlen($raw['privateExponent']),
+ $raw['privateExponent'],
+ strlen($raw['coefficient']),
+ $raw['coefficient'],
+ strlen($raw['prime1']),
+ $raw['prime1'],
+ strlen($raw['prime2']),
+ $raw['prime2']
+ );
+ $checkint = Random::string(4);
+ $paddedKey = pack(
+ 'a*Na*',
+ $checkint . $checkint . $privateKey,
+ strlen($this->comment),
+ $this->comment
+ );
+ $paddingLength = (7 * strlen($paddedKey)) % 8;
+ for ($i = 1; $i <= $paddingLength; $i++) {
+ $paddedKey.= chr($i);
+ }
+ $key = pack(
+ 'Na*Na*Na*NNa*Na*',
+ strlen('none'),
+ 'none',
+ strlen('none'),
+ 'none',
+ 0,
+ '',
+ 1,
+ strlen($publicKey),
+ $publicKey,
+ strlen($paddedKey),
+ $paddedKey
+ );
+ $key = "openssh-key-v1\0$key";
+
+ return "-----BEGIN OPENSSH PRIVATE KEY-----\r\n" .
+ chunk_split(base64_encode($key), 70) .
+ "-----END OPENSSH PRIVATE KEY-----";
default: // eg. self::PRIVATE_FORMAT_PKCS1
$components = array();
foreach ($raw as $name => $value) {
@@ -1016,9 +1076,9 @@ class RSA
* @access private
* @see self::_convertPublicKey()
* @see self::_convertPrivateKey()
- * @param string $key
+ * @param string|array $key
* @param int $type
- * @return array
+ * @return array|bool
*/
function _parseKey($key, $type)
{
@@ -1329,9 +1389,14 @@ class RSA
xml_set_character_data_handler($xml, '_data_handler');
// add to account for "dangling" tags like ... that are sometimes added
if (!xml_parse($xml, '' . $key . '')) {
+ xml_parser_free($xml);
+ unset($xml);
return false;
}
+ xml_parser_free($xml);
+ unset($xml);
+
return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
// from PuTTY's SSHPUBK.C
case self::PRIVATE_FORMAT_PUTTY:
@@ -1403,6 +1468,75 @@ class RSA
}
$components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256));
+ return $components;
+ case self::PRIVATE_FORMAT_OPENSSH:
+ $components = array();
+ $decoded = $this->_extractBER($key);
+ $magic = $this->_string_shift($decoded, 15);
+ if ($magic !== "openssh-key-v1\0") {
+ return false;
+ }
+ $options = $this->_string_shift($decoded, 24);
+ // \0\0\0\4none = ciphername
+ // \0\0\0\4none = kdfname
+ // \0\0\0\0 = kdfoptions
+ // \0\0\0\1 = numkeys
+ if ($options != "\0\0\0\4none\0\0\0\4none\0\0\0\0\0\0\0\1") {
+ return false;
+ }
+ extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
+ if (strlen($decoded) < $length) {
+ return false;
+ }
+ $publicKey = $this->_string_shift($decoded, $length);
+ extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
+ if (strlen($decoded) < $length) {
+ return false;
+ }
+ $paddedKey = $this->_string_shift($decoded, $length);
+
+ if ($this->_string_shift($publicKey, 11) !== "\0\0\0\7ssh-rsa") {
+ return false;
+ }
+
+ $checkint1 = $this->_string_shift($paddedKey, 4);
+ $checkint2 = $this->_string_shift($paddedKey, 4);
+ if (strlen($checkint1) != 4 || $checkint1 !== $checkint2) {
+ return false;
+ }
+
+ if ($this->_string_shift($paddedKey, 11) !== "\0\0\0\7ssh-rsa") {
+ return false;
+ }
+
+ $values = array(
+ &$components['modulus'],
+ &$components['publicExponent'],
+ &$components['privateExponent'],
+ &$components['coefficients'][2],
+ &$components['primes'][1],
+ &$components['primes'][2]
+ );
+
+ foreach ($values as &$value) {
+ extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
+ if (strlen($paddedKey) < $length) {
+ return false;
+ }
+ $value = new BigInteger($this->_string_shift($paddedKey, $length), -256);
+ }
+
+ extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
+ if (strlen($paddedKey) < $length) {
+ return false;
+ }
+ $components['comment'] = $this->_string_shift($decoded, $length);
+
+ $temp = $components['primes'][1]->subtract($this->one);
+ $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
+ $temp = $components['primes'][2]->subtract($this->one);
+ $components['exponents'][] = $components['publicExponent']->modInverse($temp);
+
return $components;
}
}
@@ -1501,8 +1635,9 @@ class RSA
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
*
* @access public
- * @param string $key
- * @param int $type optional
+ * @param string|RSA|array $key
+ * @param bool|int $type optional
+ * @return bool
*/
function loadKey($key, $type = false)
{
@@ -1559,7 +1694,8 @@ class RSA
self::PRIVATE_FORMAT_PKCS1,
self::PRIVATE_FORMAT_XML,
self::PRIVATE_FORMAT_PUTTY,
- self::PUBLIC_FORMAT_OPENSSH
+ self::PUBLIC_FORMAT_OPENSSH,
+ self::PRIVATE_FORMAT_OPENSSH
);
foreach ($types as $type) {
$components = $this->_parseKey($key, $type);
@@ -2207,16 +2343,21 @@ class RSA
*/
function _equals($x, $y)
{
+ if (function_exists('hash_equals')) {
+ return hash_equals($x, $y);
+ }
+
if (strlen($x) != strlen($y)) {
return false;
}
- $result = 0;
+ $result = "\0";
+ $x^= $y;
for ($i = 0; $i < strlen($x); $i++) {
- $result |= ord($x[$i]) ^ ord($y[$i]);
+ $result|= $x[$i];
}
- return $result == 0;
+ return $result === "\0";
}
/**
@@ -2423,19 +2564,26 @@ class RSA
$db = $maskedDB ^ $dbMask;
$lHash2 = substr($db, 0, $this->hLen);
$m = substr($db, $this->hLen);
- if ($lHash != $lHash2) {
- user_error('Decryption error');
- return false;
+ $hashesMatch = $this->_equals($lHash, $lHash2);
+ $leadingZeros = 1;
+ $patternMatch = 0;
+ $offset = 0;
+ for ($i = 0; $i < strlen($m); $i++) {
+ $patternMatch|= $leadingZeros & ($m[$i] === "\1");
+ $leadingZeros&= $m[$i] === "\0";
+ $offset+= $patternMatch ? 0 : 1;
}
- $m = ltrim($m, chr(0));
- if (ord($m[0]) != 1) {
+
+ // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
+ // to protect against timing attacks
+ if (!$hashesMatch & !$patternMatch) {
user_error('Decryption error');
return false;
}
// Output the message M
- return substr($m, 1);
+ return substr($m, $offset + 1);
}
/**
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Random.php b/lam/lib/3rdParty/phpseclib/Crypt/Random.php
index 6b29e751..01e34cc3 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/Random.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/Random.php
@@ -45,6 +45,10 @@ class Random
*/
static function string($length)
{
+ if (!$length) {
+ return '';
+ }
+
if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
try {
return \random_bytes($length);
diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php b/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php
index 3dd4ea1d..70980a2f 100644
--- a/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php
+++ b/lam/lib/3rdParty/phpseclib/Crypt/Twofish.php
@@ -432,8 +432,10 @@ class Twofish extends Base
$m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
- $K[] = $A+= $B;
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
+ $A = $this->safe_intval($A + $B);
+ $K[] = $A;
+ $A = $this->safe_intval($A + $B);
+ $K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
@@ -456,8 +458,10 @@ class Twofish extends Base
$m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
- $K[] = $A+= $B;
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
+ $A = $this->safe_intval($A + $B);
+ $K[] = $A;
+ $A = $this->safe_intval($A + $B);
+ $K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
@@ -481,8 +485,10 @@ class Twofish extends Base
$m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
- $K[] = $A+= $B;
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
+ $A = $this->safe_intval($A + $B);
+ $K[] = $A;
+ $A = $this->safe_intval($A + $B);
+ $K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
@@ -578,9 +584,9 @@ class Twofish extends Base
$S1[ $R1 & 0xff] ^
$S2[($R1 >> 8) & 0xff] ^
$S3[($R1 >> 16) & 0xff];
- $R2^= $t0 + $t1 + $K[++$ki];
+ $R2^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
+ $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
$t0 = $S0[ $R2 & 0xff] ^
$S1[($R2 >> 8) & 0xff] ^
@@ -590,9 +596,9 @@ class Twofish extends Base
$S1[ $R3 & 0xff] ^
$S2[($R3 >> 8) & 0xff] ^
$S3[($R3 >> 16) & 0xff];
- $R0^= ($t0 + $t1 + $K[++$ki]);
+ $R0^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
+ $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
}
// @codingStandardsIgnoreStart
@@ -634,9 +640,9 @@ class Twofish extends Base
$S1[$R1 & 0xff] ^
$S2[$R1 >> 8 & 0xff] ^
$S3[$R1 >> 16 & 0xff];
- $R3^= $t0 + ($t1 << 1) + $K[--$ki];
+ $R3^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]);
+ $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
$t0 = $S0[$R2 & 0xff] ^
$S1[$R2 >> 8 & 0xff] ^
@@ -646,9 +652,9 @@ class Twofish extends Base
$S1[$R3 & 0xff] ^
$S2[$R3 >> 8 & 0xff] ^
$S3[$R3 >> 16 & 0xff];
- $R1^= $t0 + ($t1 << 1) + $K[--$ki];
+ $R1^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
+ $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
}
// @codingStandardsIgnoreStart
@@ -679,6 +685,8 @@ class Twofish extends Base
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
+ $safeint = $this->safe_intval_inline();
+
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
@@ -727,9 +735,9 @@ class Twofish extends Base
$S1[ $R1 & 0xff] ^
$S2[($R1 >> 8) & 0xff] ^
$S3[($R1 >> 16) & 0xff];
- $R2^= ($t0 + $t1 + '.$K[++$ki].');
+ $R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
+ $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
$t0 = $S0[ $R2 & 0xff] ^
$S1[($R2 >> 8) & 0xff] ^
@@ -739,16 +747,16 @@ class Twofish extends Base
$S1[ $R3 & 0xff] ^
$S2[($R3 >> 8) & 0xff] ^
$S3[($R3 >> 16) & 0xff];
- $R0^= ($t0 + $t1 + '.$K[++$ki].');
+ $R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
+ $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
';
}
$encrypt_block.= '
- $in = pack("V4", '.$K[4].' ^ $R2,
- '.$K[5].' ^ $R3,
- '.$K[6].' ^ $R0,
- '.$K[7].' ^ $R1);
+ $in = pack("V4", ' . $K[4] . ' ^ $R2,
+ ' . $K[5] . ' ^ $R3,
+ ' . $K[6] . ' ^ $R0,
+ ' . $K[7] . ' ^ $R1);
';
// Generating decrypt code:
@@ -769,9 +777,9 @@ class Twofish extends Base
$S1[$R1 & 0xff] ^
$S2[$R1 >> 8 & 0xff] ^
$S3[$R1 >> 16 & 0xff];
- $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].';
+ $R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
+ $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
$t0 = $S0[$R2 & 0xff] ^
$S1[$R2 >> 8 & 0xff] ^
@@ -781,16 +789,16 @@ class Twofish extends Base
$S1[$R3 & 0xff] ^
$S2[$R3 >> 8 & 0xff] ^
$S3[$R3 >> 16 & 0xff];
- $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].';
+ $R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
+ $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
';
}
$decrypt_block.= '
- $in = pack("V4", '.$K[0].' ^ $R2,
- '.$K[1].' ^ $R3,
- '.$K[2].' ^ $R0,
- '.$K[3].' ^ $R1);
+ $in = pack("V4", ' . $K[0] . ' ^ $R2,
+ ' . $K[1] . ' ^ $R3,
+ ' . $K[2] . ' ^ $R0,
+ ' . $K[3] . ' ^ $R1);
';
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
diff --git a/lam/lib/3rdParty/phpseclib/File/ANSI.php b/lam/lib/3rdParty/phpseclib/File/ANSI.php
index 1f3eecb3..5ff1f2ea 100644
--- a/lam/lib/3rdParty/phpseclib/File/ANSI.php
+++ b/lam/lib/3rdParty/phpseclib/File/ANSI.php
@@ -305,6 +305,9 @@ class ANSI
case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
$this->old_x = $this->x;
$this->x-= $match[1];
+ if ($this->x < 0) {
+ $this->x = 0;
+ }
break;
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
break;
@@ -416,7 +419,7 @@ class ANSI
if ($this->x > $this->max_x) {
$this->x = 0;
- $this->y++;
+ $this->_newLine();
} else {
$this->x++;
}
diff --git a/lam/lib/3rdParty/phpseclib/File/ASN1.php b/lam/lib/3rdParty/phpseclib/File/ASN1.php
index 504dbe8b..3aaa3090 100644
--- a/lam/lib/3rdParty/phpseclib/File/ASN1.php
+++ b/lam/lib/3rdParty/phpseclib/File/ASN1.php
@@ -25,6 +25,8 @@ namespace phpseclib\File;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
+use DateTime;
+use DateTimeZone;
/**
* Pure-PHP ASN.1 Parser
@@ -242,9 +244,10 @@ class ASN1
$tag = 0;
// process septets (since the eighth bit is ignored, it's not an octet)
do {
- $loop = ord($encoded[0]) >> 7;
+ $temp = ord($encoded[$encoded_pos++]);
+ $loop = $temp >> 7;
$tag <<= 7;
- $tag |= ord($encoded[$encoded_pos++]) & 0x7F;
+ $tag |= $temp & 0x7F;
$start++;
} while ($loop);
}
@@ -306,6 +309,9 @@ class ASN1
$remainingLength = $length;
while ($remainingLength > 0) {
$temp = $this->_decode_ber($content, $start, $content_pos);
+ if ($temp === false) {
+ break;
+ }
$length = $temp['length'];
// end-of-content octets - see paragraph 8.1.5
if (substr($content, $content_pos + $length, 2) == "\0\0") {
@@ -357,6 +363,9 @@ class ASN1
$current['content'] = substr($content, $content_pos);
} else {
$temp = $this->_decode_ber($content, $start, $content_pos);
+ if ($temp === false) {
+ return false;
+ }
$length-= (strlen($content) - $content_pos);
$last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) {
@@ -381,6 +390,9 @@ class ASN1
$length = 0;
while (substr($content, $content_pos, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start, $content_pos);
+ if ($temp === false) {
+ return false;
+ }
$content_pos += $temp['length'];
// all subtags should be octet strings
//if ($temp['type'] != self::TYPE_OCTET_STRING) {
@@ -413,30 +425,16 @@ class ASN1
break 2;
}
$temp = $this->_decode_ber($content, $start + $offset, $content_pos);
+ if ($temp === false) {
+ return false;
+ }
$content_pos += $temp['length'];
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break;
case self::TYPE_OBJECT_IDENTIFIER:
- $temp = ord($content[$content_pos++]);
- $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
- $valuen = 0;
- // process septets
- $content_len = strlen($content);
- while ($content_pos < $content_len) {
- $temp = ord($content[$content_pos++]);
- $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;
- //}
+ $current['content'] = $this->_decodeOID(substr($content, $content_pos));
break;
/* Each character string type shall be encoded as if it had been declared:
[UNIVERSAL x] IMPLICIT OCTET STRING
@@ -580,7 +578,7 @@ class ASN1
$childClass = $tempClass = self::CLASS_UNIVERSAL;
$constant = null;
if (isset($temp['constant'])) {
- $tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
+ $tempClass = $temp['type'];
}
if (isset($child['class'])) {
$childClass = $child['class'];
@@ -643,7 +641,7 @@ class ASN1
$temp = $decoded['content'][$i];
$tempClass = self::CLASS_UNIVERSAL;
if (isset($temp['constant'])) {
- $tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
+ $tempClass = $temp['type'];
}
foreach ($mapping['children'] as $key => $child) {
@@ -707,7 +705,7 @@ class ASN1
if (isset($mapping['implicit'])) {
$decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
}
- return @date($this->format, $decoded['content']);
+ return $decoded['content'] ? $decoded['content']->format($this->format) : false;
case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$offset = ord($decoded['content'][0]);
@@ -956,7 +954,8 @@ class ASN1
case self::TYPE_GENERALIZED_TIME:
$format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
$format.= 'mdHis';
- $value = @gmdate($format, strtotime($source)) . 'Z';
+ $date = new DateTime($source, new DateTimeZone('GMT'));
+ $value = $date->format($format) . 'Z';
break;
case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
@@ -998,27 +997,7 @@ class ASN1
$value = base64_decode($source);
break;
case self::TYPE_OBJECT_IDENTIFIER:
- $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
- if ($oid === false) {
- user_error('Invalid OID');
- return false;
- }
- $value = '';
- $parts = explode('.', $oid);
- $value = chr(40 * $parts[0] + $parts[1]);
- for ($i = 2; $i < count($parts); $i++) {
- $temp = '';
- if (!$parts[$i]) {
- $temp = "\0";
- } else {
- while ($parts[$i]) {
- $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
- $parts[$i] >>= 7;
- }
- $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
- }
- $value.= $temp;
- }
+ $value = $this->_encodeOID($source);
break;
case self::TYPE_ANY:
$loc = $this->location;
@@ -1117,6 +1096,108 @@ class ASN1
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
+ /**
+ * BER-decode the OID
+ *
+ * Called by _decode_ber()
+ *
+ * @access private
+ * @param string $content
+ * @return string
+ */
+ function _decodeOID($content)
+ {
+ static $eighty;
+ if (!$eighty) {
+ $eighty = new BigInteger(80);
+ }
+
+ $oid = array();
+ $pos = 0;
+ $len = strlen($content);
+ $n = new BigInteger();
+ while ($pos < $len) {
+ $temp = ord($content[$pos++]);
+ $n = $n->bitwise_leftShift(7);
+ $n = $n->bitwise_or(new BigInteger($temp & 0x7F));
+ if (~$temp & 0x80) {
+ $oid[] = $n;
+ $n = new BigInteger();
+ }
+ }
+ $part1 = array_shift($oid);
+ $first = floor(ord($content[0]) / 40);
+ /*
+ "This packing of the first two object identifier components recognizes that only three values are allocated from the root
+ node, and at most 39 subsequent values from nodes reached by X = 0 and X = 1."
+
+ -- https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=22
+ */
+ if ($first <= 2) { // ie. 0 <= ord($content[0]) < 120 (0x78)
+ array_unshift($oid, ord($content[0]) % 40);
+ array_unshift($oid, $first);
+ } else {
+ array_unshift($oid, $part1->subtract($eighty));
+ array_unshift($oid, 2);
+ }
+
+ return implode('.', $oid);
+ }
+
+ /**
+ * DER-encode the OID
+ *
+ * Called by _encode_der()
+ *
+ * @access private
+ * @param string $content
+ * @return string
+ */
+ function _encodeOID($source)
+ {
+ static $mask, $zero, $forty;
+ if (!$mask) {
+ $mask = new BigInteger(0x7F);
+ $zero = new BigInteger();
+ $forty = new BigInteger(40);
+ }
+
+ $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
+ if ($oid === false) {
+ user_error('Invalid OID');
+ return false;
+ }
+ $parts = explode('.', $oid);
+ $part1 = array_shift($parts);
+ $part2 = array_shift($parts);
+
+ $first = new BigInteger($part1);
+ $first = $first->multiply($forty);
+ $first = $first->add(new BigInteger($part2));
+
+ array_unshift($parts, $first->toString());
+
+ $value = '';
+ foreach ($parts as $part) {
+ if (!$part) {
+ $temp = "\0";
+ } else {
+ $temp = '';
+ $part = new BigInteger($part);
+ while (!$part->equals($zero)) {
+ $submask = $part->bitwise_and($mask);
+ $submask->setPrecision(8);
+ $temp = (chr(0x80) | $submask->toBytes()) . $temp;
+ $part = $part->bitwise_rightShift(7);
+ }
+ $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
+ }
+ $value.= $temp;
+ }
+
+ return $value;
+ }
+
/**
* BER-decode the time
*
@@ -1137,33 +1218,32 @@ class ASN1
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
http://www.obj-sys.com/asn1tutorial/node14.html */
- $pattern = $tag == self::TYPE_UTC_TIME ?
- '#^(..)(..)(..)(..)(..)(..)?(.*)$#' :
- '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
-
- preg_match($pattern, $content, $matches);
-
- list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
+ $format = 'YmdHis';
if ($tag == self::TYPE_UTC_TIME) {
- $year = $year >= 50 ? "19$year" : "20$year";
- }
-
- if ($timezone == 'Z') {
- $mktime = 'gmmktime';
- $timezone = 0;
- } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
- $mktime = 'gmmktime';
- $timezone = 60 * $matches[3] + 3600 * $matches[2];
- if ($matches[1] == '-') {
- $timezone = -$timezone;
+ // https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
+ // element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
+ // browsers parse it phpseclib ought to too
+ if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
+ $content = $matches[1] . '00' . $matches[2];
}
- } else {
- $mktime = 'mktime';
- $timezone = 0;
+ $prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
+ $content = $prefix . $content;
+ } elseif (strpos($content, '.') !== false) {
+ $format.= '.u';
}
- return @$mktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year) + $timezone;
+ if ($content[strlen($content) - 1] == 'Z') {
+ $content = substr($content, 0, -1) . '+0000';
+ }
+
+ if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
+ $format.= 'O';
+ }
+
+ // error supression isn't necessary as of PHP 7.0:
+ // http://php.net/manual/en/migration70.other-changes.php
+ return @DateTime::createFromFormat($format, $content);
}
/**
diff --git a/lam/lib/3rdParty/phpseclib/File/X509.php b/lam/lib/3rdParty/phpseclib/File/X509.php
index 9a70457b..4ebafa17 100644
--- a/lam/lib/3rdParty/phpseclib/File/X509.php
+++ b/lam/lib/3rdParty/phpseclib/File/X509.php
@@ -31,6 +31,8 @@ use phpseclib\Crypt\Random;
use phpseclib\Crypt\RSA;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
+use DateTime;
+use DateTimeZone;
/**
* Pure-PHP X.509 Parser
@@ -303,6 +305,22 @@ class X509
*/
var $challenge;
+ /**
+ * Recursion Limit
+ *
+ * @var int
+ * @access private
+ */
+ static $recur_limit = 5;
+
+ /**
+ * URL fetch flag
+ *
+ * @var bool
+ * @access private
+ */
+ static $disable_url_fetch = false;
+
/**
* Default Constructor.
*
@@ -1910,6 +1928,9 @@ class X509
// "Certificate Transparency"
// https://tools.ietf.org/html/rfc6962
case '1.3.6.1.4.1.11129.2.4.2':
+ // "Qualified Certificate statements"
+ // https://tools.ietf.org/html/rfc3739#section-3.2.6
+ case '1.3.6.1.5.5.7.1.3':
return true;
// CSR attributes
@@ -2030,30 +2051,32 @@ class X509
}
if ($names = $this->getExtension('id-ce-subjectAltName')) {
- foreach ($names as $key => $value) {
- $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
- switch ($key) {
- case 'dNSName':
- /* From RFC2818 "HTTP over TLS":
+ foreach ($names as $name) {
+ foreach ($name as $key => $value) {
+ $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
+ switch ($key) {
+ case 'dNSName':
+ /* From RFC2818 "HTTP over TLS":
- If a subjectAltName extension of type dNSName is present, that MUST
- be used as the identity. Otherwise, the (most specific) Common Name
- field in the Subject field of the certificate MUST be used. Although
- the use of the Common Name is existing practice, it is deprecated and
- Certification Authorities are encouraged to use the dNSName instead. */
- if (preg_match('#^' . $value . '$#', $components['host'])) {
- return true;
- }
- break;
- case 'iPAddress':
- /* From RFC2818 "HTTP over TLS":
+ If a subjectAltName extension of type dNSName is present, that MUST
+ be used as the identity. Otherwise, the (most specific) Common Name
+ field in the Subject field of the certificate MUST be used. Although
+ the use of the Common Name is existing practice, it is deprecated and
+ Certification Authorities are encouraged to use the dNSName instead. */
+ if (preg_match('#^' . $value . '$#', $components['host'])) {
+ return true;
+ }
+ break;
+ case 'iPAddress':
+ /* From RFC2818 "HTTP over TLS":
- In some cases, the URI is specified as an IP address rather than a
- hostname. In this case, the iPAddress subjectAltName must be present
- in the certificate and must exactly match the IP in the URI. */
- if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
- return true;
- }
+ In some cases, the URI is specified as an IP address rather than a
+ hostname. In this case, the iPAddress subjectAltName must be present
+ in the certificate and must exactly match the IP in the URI. */
+ if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
+ return true;
+ }
+ }
}
}
return false;
@@ -2072,7 +2095,7 @@ class X509
*
* If $date isn't defined it is assumed to be the current date.
*
- * @param int $date optional
+ * @param \DateTime|string $date optional
* @access public
*/
function validateDate($date = null)
@@ -2082,7 +2105,7 @@ class X509
}
if (!isset($date)) {
- $date = time();
+ $date = new DateTime(null, new DateTimeZone(@date_default_timezone_get()));
}
$notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
@@ -2091,15 +2114,133 @@ class X509
$notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
$notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
+ if (is_string($date)) {
+ $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
+ }
+
+ $notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get()));
+ $notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get()));
+
switch (true) {
- case $date < @strtotime($notBefore):
- case $date > @strtotime($notAfter):
+ case $date < $notBefore:
+ case $date > $notAfter:
return false;
}
return true;
}
+ /**
+ * Fetches a URL
+ *
+ * @param string $url
+ * @access private
+ * @return bool|string
+ */
+ static function _fetchURL($url)
+ {
+ if (self::$disable_url_fetch) {
+ return false;
+ }
+
+ $parts = parse_url($url);
+ $data = '';
+ switch ($parts['scheme']) {
+ case 'http':
+ $fsock = @fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80);
+ if (!$fsock) {
+ return false;
+ }
+ fputs($fsock, "GET $parts[path] HTTP/1.0\r\n");
+ fputs($fsock, "Host: $parts[host]\r\n\r\n");
+ $line = fgets($fsock, 1024);
+ if (strlen($line) < 3) {
+ return false;
+ }
+ preg_match('#HTTP/1.\d (\d{3})#', $line, $temp);
+ if ($temp[1] != '200') {
+ return false;
+ }
+
+ // skip the rest of the headers in the http response
+ while (!feof($fsock) && fgets($fsock, 1024) != "\r\n") {
+ }
+
+ while (!feof($fsock)) {
+ $data.= fread($fsock, 1024);
+ }
+
+ break;
+ //case 'ftp':
+ //case 'ldap':
+ //default:
+ }
+
+ return $data;
+ }
+
+ /**
+ * Validates an intermediate cert as identified via authority info access extension
+ *
+ * See https://tools.ietf.org/html/rfc4325 for more info
+ *
+ * @param bool $caonly
+ * @param int $count
+ * @access private
+ * @return bool
+ */
+ function _testForIntermediate($caonly, $count)
+ {
+ $opts = $this->getExtension('id-pe-authorityInfoAccess');
+ if (!is_array($opts)) {
+ return false;
+ }
+ foreach ($opts as $opt) {
+ if ($opt['accessMethod'] == 'id-ad-caIssuers') {
+ // accessLocation is a GeneralName. GeneralName fields support stuff like email addresses, IP addresses, LDAP,
+ // etc, but we're only supporting URI's. URI's and LDAP are the only thing https://tools.ietf.org/html/rfc4325
+ // discusses
+ if (isset($opt['accessLocation']['uniformResourceIdentifier'])) {
+ $url = $opt['accessLocation']['uniformResourceIdentifier'];
+ break;
+ }
+ }
+ }
+
+ if (!isset($url)) {
+ return false;
+ }
+
+ $cert = static::_fetchURL($url);
+ if (!is_string($cert)) {
+ return false;
+ }
+
+ $parent = new static();
+ $parent->CAs = $this->CAs;
+ /*
+ "Conforming applications that support HTTP or FTP for accessing
+ certificates MUST be able to accept .cer files and SHOULD be able
+ to accept .p7c files." -- https://tools.ietf.org/html/rfc4325
+
+ A .p7c file is 'a "certs-only" CMS message as specified in RFC 2797"
+
+ These are currently unsupported
+ */
+ if (!is_array($parent->loadX509($cert))) {
+ return false;
+ }
+
+ if (!$parent->_validateSignatureCountable($caonly, ++$count)) {
+ return false;
+ }
+
+ $this->CAs[] = $parent->currentCert;
+ //$this->loadCA($cert);
+
+ return true;
+ }
+
/**
* Validate a signature
*
@@ -2116,11 +2257,30 @@ class X509
* @return mixed
*/
function validateSignature($caonly = true)
+ {
+ return $this->_validateSignatureCountable($caonly, 0);
+ }
+
+ /**
+ * Validate a signature
+ *
+ * Performs said validation whilst keeping track of how many times validation method is called
+ *
+ * @param bool $caonly
+ * @param int $count
+ * @access private
+ * @return mixed
+ */
+ function _validateSignatureCountable($caonly, $count)
{
if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
return null;
}
+ if ($count == self::$recur_limit) {
+ return false;
+ }
+
/* TODO:
"emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
-- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
@@ -2137,7 +2297,8 @@ class X509
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
switch (true) {
case !is_array($authorityKey):
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ case !$subjectKeyID:
+ case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $this->currentCert; // working cert
}
}
@@ -2154,17 +2315,21 @@ class X509
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ case !$subjectKeyID:
+ case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
+ break 2; // serial mismatch - check other ca
+ }
$signingCert = $ca; // working cert
break 3;
}
}
}
if (count($this->CAs) == $i && $caonly) {
- return false;
+ return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
}
} elseif (!isset($signingCert) || $caonly) {
- return false;
+ return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
}
return $this->_validateSignature(
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
@@ -2200,7 +2365,11 @@ class X509
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ case !$subjectKeyID:
+ case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
+ break 2; // serial mismatch - check other ca
+ }
$signingCert = $ca; // working cert
break 3;
}
@@ -2267,6 +2436,41 @@ class X509
return true;
}
+ /**
+ * Sets the recursion limit
+ *
+ * When validating a signature it may be necessary to download intermediate certs from URI's.
+ * An intermediate cert that linked to itself would result in an infinite loop so to prevent
+ * that we set a recursion limit. A negative number means that there is no recursion limit.
+ *
+ * @param int $count
+ * @access public
+ */
+ static function setRecurLimit($count)
+ {
+ self::$recur_limit = $count;
+ }
+
+ /**
+ * Prevents URIs from being automatically retrieved
+ *
+ * @access public
+ */
+ static function disableURLFetch()
+ {
+ self::$disable_url_fetch = true;
+ }
+
+ /**
+ * Allows URIs to be automatically retrieved
+ *
+ * @access public
+ */
+ static function enableURLFetch()
+ {
+ self::$disable_url_fetch = false;
+ }
+
/**
* Reformat public keys
*
@@ -2472,6 +2676,10 @@ class X509
}
$dn = array_values($dn);
+ // fix for https://bugs.php.net/75433 affecting PHP 7.2
+ if (!isset($dn[0])) {
+ $dn = array_splice($dn, 0, 0);
+ }
}
/**
@@ -2715,12 +2923,14 @@ class X509
$value = array_pop($value); // Always strip data type.
}
} elseif (is_object($value) && $value instanceof Element) {
- $callback = create_function('$x', 'return "\x" . bin2hex($x[0]);');
+ $callback = function ($x) {
+ return "\x" . bin2hex($x[0]);
+ };
$value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
}
$output.= $desc . '=' . $value;
$result[$desc] = isset($result[$desc]) ?
- array_merge((array) $dn[$prop], array($value)) :
+ array_merge((array) $result[$desc], array($value)) :
$value;
$start = false;
}
@@ -3338,7 +3548,11 @@ class X509
*/
function _timeField($date)
{
- $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
+ if ($date instanceof Element) {
+ return $date;
+ }
+ $dateObj = new DateTime($date, new DateTimeZone('GMT'));
+ $year = $dateObj->format('Y'); // the same way ASN1.php parses this
if ($year < 2050) {
return array('utcTime' => $date);
} else {
@@ -3403,8 +3617,12 @@ class 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 = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
+ $startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');
+
+ $endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
+ $endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');
+
/* "The serial number MUST be a positive integer"
"Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
-- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
@@ -3420,7 +3638,7 @@ class X509
'tbsCertificate' =>
array(
'version' => 'v3',
- 'serialNumber' => $serialNumber, // $this->setserialNumber()
+ 'serialNumber' => $serialNumber, // $this->setSerialNumber()
'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, // this is going to be overwritten later
'validity' => array(
@@ -3672,7 +3890,9 @@ class 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 = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
+ $thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');
if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
$this->currentCert = $crl->currentCert;
@@ -3823,7 +4043,11 @@ class X509
*/
function setStartDate($date)
{
- $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
+ if (!is_object($date) || !is_a($date, 'DateTime')) {
+ $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
+ }
+
+ $this->startDate = $date->format('D, d M Y H:i:s O');
}
/**
@@ -3847,7 +4071,11 @@ class X509
$temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
$this->endDate = new Element($temp);
} else {
- $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
+ if (!is_object($date) || !is_a($date, 'DateTime')) {
+ $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
+ }
+
+ $this->endDate = $date->format('D, d M Y H:i:s O');
}
}
@@ -4057,6 +4285,10 @@ class X509
}
$extensions = array_values($extensions);
+ // fix for https://bugs.php.net/75433 affecting PHP 7.2
+ if (!isset($extensions[0])) {
+ $extensions = array_splice($extensions, 0, 0);
+ }
return $result;
}
@@ -4577,8 +4809,9 @@ class X509
}
$i = count($rclist);
+ $revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$rclist[] = array('userCertificate' => $serial,
- 'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O')));
+ 'revocationDate' => $this->_timeField($revocationDate->format('D, d M Y H:i:s O')));
return $i;
}
diff --git a/lam/lib/3rdParty/phpseclib/Math/BigInteger.php b/lam/lib/3rdParty/phpseclib/Math/BigInteger.php
index 4b13d7c6..fe1f43c5 100644
--- a/lam/lib/3rdParty/phpseclib/Math/BigInteger.php
+++ b/lam/lib/3rdParty/phpseclib/Math/BigInteger.php
@@ -45,7 +45,6 @@
* @author 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
*/
namespace phpseclib\Math;
@@ -266,23 +265,27 @@ class BigInteger
if (extension_loaded('openssl') && !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();
- $content = ob_get_contents();
- ob_end_clean();
-
- preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
-
$versions = array();
- if (!empty($matches[1])) {
- 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];
+ // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
+ if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
+ ob_start();
+ @phpinfo();
+ $content = ob_get_contents();
+ ob_end_clean();
+
+ preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
+
+ if (!empty($matches[1])) {
+ 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];
+ }
}
}
}
@@ -360,8 +363,12 @@ class BigInteger
case 256:
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
- $sign = $this->is_negative ? '-' : '';
- $this->value = gmp_init($sign . '0x' . bin2hex($x));
+ $this->value = function_exists('gmp_import') ?
+ gmp_import($x) :
+ gmp_init('0x' . bin2hex($x));
+ if ($this->is_negative) {
+ $this->value = gmp_neg($this->value);
+ }
break;
case self::MODE_BCMATH:
// round $len to the nearest 4 (thanks, DavidMJ!)
@@ -438,6 +445,9 @@ class BigInteger
// (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
// [^-0-9].*: find any non-numeric characters and then any characters that follow that
$x = preg_replace('#(?add(new static(1)) : $this->copy();
$bytes = $temp->toBytes();
- if (empty($bytes)) { // eg. if the number we're trying to convert is -1
+ if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1
$bytes = chr(0);
}
@@ -548,9 +558,13 @@ class BigInteger
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}
- $temp = gmp_strval(gmp_abs($this->value), 16);
- $temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
- $temp = pack('H*', $temp);
+ if (function_exists('gmp_export')) {
+ $temp = gmp_export($this->value);
+ } else {
+ $temp = gmp_strval(gmp_abs($this->value), 16);
+ $temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
+ $temp = pack('H*', $temp);
+ }
return $this->precision > 0 ?
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
@@ -1547,7 +1561,9 @@ class BigInteger
$temp_value = array($quotient_value[$q_index]);
$temp = $temp->multiply($y);
$temp_value = &$temp->value;
- $temp_value = array_merge($adjust, $temp_value);
+ if (count($temp_value)) {
+ $temp_value = array_merge($adjust, $temp_value);
+ }
$x = $x->subtract($temp);
@@ -2680,7 +2696,14 @@ class BigInteger
{
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
- return gmp_cmp($this->value, $y->value);
+ $r = gmp_cmp($this->value, $y->value);
+ if ($r < -1) {
+ $r = -1;
+ }
+ if ($r > 1) {
+ $r = 1;
+ }
+ return $r;
case self::MODE_BCMATH:
return bccomp($this->value, $y->value, 0);
}
@@ -2860,8 +2883,7 @@ class BigInteger
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$temp = new static();
- $temp->value = gmp_xor($this->value, $x->value);
-
+ $temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
return $this->_normalize($temp);
case self::MODE_BCMATH:
$left = $this->toBytes();
@@ -2877,6 +2899,7 @@ class BigInteger
$length = max(count($this->value), count($x->value));
$result = $this->copy();
+ $result->is_negative = false;
$result->value = array_pad($result->value, $length, 0);
$x->value = array_pad($x->value, $length, 0);
@@ -2900,7 +2923,7 @@ class BigInteger
// (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
$temp = $this->toBytes();
if ($temp == '') {
- return '';
+ return $this->_normalize(new static());
}
$pre_msb = decbin(ord($temp[0]));
$temp = ~$temp;
@@ -3435,7 +3458,7 @@ class BigInteger
break;
}
}
- $s = 26 * $i + $j - 1;
+ $s = 26 * $i + $j;
$r->_rshift($s);
}
@@ -3561,6 +3584,7 @@ class BigInteger
$value = &$result->value;
if (!count($value)) {
+ $result->is_negative = false;
return $result;
}
diff --git a/lam/lib/3rdParty/phpseclib/Net/SCP.php b/lam/lib/3rdParty/phpseclib/Net/SCP.php
index f95bce6d..cf13496c 100644
--- a/lam/lib/3rdParty/phpseclib/Net/SCP.php
+++ b/lam/lib/3rdParty/phpseclib/Net/SCP.php
@@ -144,6 +144,11 @@ class SCP
return false;
}
+ if (empty($remote_file)) {
+ user_error('remote_file cannot be blank', E_USER_NOTICE);
+ return false;
+ }
+
if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
return false;
}
diff --git a/lam/lib/3rdParty/phpseclib/Net/SFTP.php b/lam/lib/3rdParty/phpseclib/Net/SFTP.php
index 1421ecb4..a248c258 100644
--- a/lam/lib/3rdParty/phpseclib/Net/SFTP.php
+++ b/lam/lib/3rdParty/phpseclib/Net/SFTP.php
@@ -109,11 +109,11 @@ class SFTP extends SSH2
* The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
* concurrent actions, so it's somewhat academic, here.
*
- * @var int
+ * @var boolean
* @see self::_send_sftp_packet()
* @access private
*/
- var $request_id = false;
+ var $use_request_id = false;
/**
* The Packet Type
@@ -158,7 +158,7 @@ class SFTP extends SSH2
* Current working directory
*
* @var string
- * @see self::_realpath()
+ * @see self::realpath()
* @see self::chdir()
* @access private
*/
@@ -187,7 +187,7 @@ class SFTP extends SSH2
*
* @see self::getSFTPErrors()
* @see self::getLastSFTPError()
- * @var string
+ * @var array
* @access private
*/
var $sftp_errors = array();
@@ -236,6 +236,29 @@ class SFTP extends SSH2
*/
var $sortOptions = array();
+ /**
+ * Canonicalization Flag
+ *
+ * Determines whether or not paths should be canonicalized before being
+ * passed on to the remote server.
+ *
+ * @see self::enablePathCanonicalization()
+ * @see self::disablePathCanonicalization()
+ * @see self::realpath()
+ * @var bool
+ * @access private
+ */
+ var $canonicalize_paths = true;
+
+ /**
+ * Request Buffers
+ *
+ * @see self::_get_sftp_packet()
+ * @var array
+ * @access private
+ */
+ var $requestBuffer = array();
+
/**
* Default Constructor.
*
@@ -335,7 +358,7 @@ class SFTP extends SSH2
// yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
// two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
// that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
- -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
+ (-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
);
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
// the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
@@ -409,7 +432,7 @@ class SFTP extends SSH2
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
- $response = $this->_get_channel_packet(self::CHANNEL);
+ $response = $this->_get_channel_packet(self::CHANNEL, true);
if ($response === false) {
return false;
}
@@ -430,7 +453,7 @@ class SFTP extends SSH2
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
- $response = $this->_get_channel_packet(self::CHANNEL);
+ $response = $this->_get_channel_packet(self::CHANNEL, true);
if ($response === false) {
// from PuTTY's psftp.exe
$command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
@@ -454,7 +477,7 @@ class SFTP extends SSH2
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
- $response = $this->_get_channel_packet(self::CHANNEL);
+ $response = $this->_get_channel_packet(self::CHANNEL, true);
if ($response === false) {
return false;
}
@@ -505,7 +528,7 @@ class SFTP extends SSH2
}
*/
- $this->request_id = 1;
+ $this->use_request_id = true;
/*
A Note on SFTPv4/5/6 support:
@@ -575,6 +598,26 @@ class SFTP extends SSH2
$this->stat_cache = array();
}
+ /**
+ * Enable path canonicalization
+ *
+ * @access public
+ */
+ function enablePathCanonicalization()
+ {
+ $this->canonicalize_paths = true;
+ }
+
+ /**
+ * Enable path canonicalization
+ *
+ * @access public
+ */
+ function disablePathCanonicalization()
+ {
+ $this->canonicalize_paths = false;
+ }
+
/**
* Returns the current directory name
*
@@ -633,13 +676,20 @@ class SFTP extends SSH2
* SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
* the absolute (canonicalized) path.
*
+ * If canonicalize_paths has been disabled using disablePathCanonicalization(), $path is returned as-is.
+ *
* @see self::chdir()
+ * @see self::disablePathCanonicalization()
* @param string $path
* @return mixed
* @access private
*/
function _realpath($path)
{
+ if (!$this->canonicalize_paths) {
+ return $path;
+ }
+
if ($this->pwd === false) {
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
@@ -792,6 +842,7 @@ class SFTP extends SSH2
}
if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
$temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
+ $temp = is_array($temp) ? $temp : array();
$result = array_merge($result, $temp);
} else {
$result[] = $relativeDir . $value;
@@ -823,7 +874,17 @@ class SFTP extends SSH2
unset($files[$key]);
continue;
}
- if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) {
+ $is_directory = false;
+ if ($key != '.' && $key != '..') {
+ if ($this->use_stat_cache) {
+ $is_directory = is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)));
+ } else {
+ $stat = $this->lstat($dir . '/' . $key);
+ $is_directory = $stat && $stat['type'] === NET_SFTP_TYPE_DIRECTORY;
+ }
+ }
+
+ if ($is_directory) {
$depth++;
$files[$key] = $this->rawlist($dir . '/' . $key, true);
$depth--;
@@ -1106,7 +1167,7 @@ class SFTP extends SSH2
$temp[$dir] = array();
}
if ($i === $max) {
- if (is_object($temp[$dir])) {
+ if (is_object($temp[$dir]) && is_object($value)) {
if (!isset($value->stat) && isset($temp[$dir]->stat)) {
$value->stat = $temp[$dir]->stat;
}
@@ -1294,7 +1355,7 @@ class SFTP extends SSH2
/**
* Returns general information about a file or symbolic link
*
- * Determines information without calling \phpseclib\Net\SFTP::_realpath().
+ * Determines information without calling \phpseclib\Net\SFTP::realpath().
* The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
*
* @param string $filename
@@ -1455,7 +1516,7 @@ class SFTP extends SSH2
return true;
}
- $filename = $this->_realPath($filename);
+ $filename = $this->realpath($filename);
// rather than return what the permissions *should* be, we'll return what they actually are. this will also
// tell us if the file actually exists.
// incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
@@ -1938,7 +1999,7 @@ class SFTP extends SSH2
if (isset($fp)) {
$stat = fstat($fp);
- $size = $stat['size'];
+ $size = !empty($stat) ? $stat['size'] : 0;
if ($local_start >= 0) {
fseek($fp, $local_start);
@@ -2087,10 +2148,11 @@ class SFTP extends SSH2
* @param string $local_file
* @param int $offset
* @param int $length
+ * @param callable|null $progressCallback
* @return mixed
* @access public
*/
- function get($remote_file, $local_file = false, $offset = 0, $length = -1)
+ function get($remote_file, $local_file = false, $offset = 0, $length = -1, $progressCallback = null)
{
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
return false;
@@ -2148,7 +2210,7 @@ class SFTP extends SSH2
$packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
$packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
- if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
+ if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet, $i)) {
if ($fclose_check) {
fclose($fp);
}
@@ -2156,6 +2218,9 @@ class SFTP extends SSH2
}
$packet = null;
$read+= $packet_size;
+ if (is_callable($progressCallback)) {
+ call_user_func($progressCallback, $read);
+ }
$i++;
}
@@ -2163,15 +2228,17 @@ class SFTP extends SSH2
break;
}
+ $packets_sent = $i - 1;
+
$clear_responses = false;
while ($i > 0) {
$i--;
if ($clear_responses) {
- $this->_get_sftp_packet();
+ $this->_get_sftp_packet($packets_sent - $i);
continue;
} else {
- $response = $this->_get_sftp_packet();
+ $response = $this->_get_sftp_packet($packets_sent - $i);
}
switch ($this->packet_type) {
@@ -2880,10 +2947,10 @@ class SFTP extends SSH2
* @return bool
* @access private
*/
- function _send_sftp_packet($type, $data)
+ function _send_sftp_packet($type, $data, $request_id = 1)
{
- $packet = $this->request_id !== false ?
- pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
+ $packet = $this->use_request_id ?
+ pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) :
pack('NCa*', strlen($data) + 1, $type, $data);
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
@@ -2921,15 +2988,24 @@ class SFTP extends SSH2
* @return string
* @access private
*/
- function _get_sftp_packet()
+ function _get_sftp_packet($request_id = null)
{
- $this->curTimeout = false;
+ if (isset($request_id) && isset($this->requestBuffer[$request_id])) {
+ $this->packet_type = $this->requestBuffer[$request_id]['packet_type'];
+ $temp = $this->requestBuffer[$request_id]['packet'];
+ unset($this->requestBuffer[$request_id]);
+ return $temp;
+ }
+
+ // in SSH2.php the timeout is cumulative per function call. eg. exec() will
+ // timeout after 10s. but for SFTP.php it's cumulative per packet
+ $this->curTimeout = $this->timeout;
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
// SFTP packet length
while (strlen($this->packet_buffer) < 4) {
- $temp = $this->_get_channel_packet(self::CHANNEL);
+ $temp = $this->_get_channel_packet(self::CHANNEL, true);
if (is_bool($temp)) {
$this->packet_type = false;
$this->packet_buffer = '';
@@ -2944,9 +3020,16 @@ class SFTP extends SSH2
$tempLength = $length;
$tempLength-= strlen($this->packet_buffer);
+
+ // 256 * 1024 is what SFTP_MAX_MSG_LENGTH is set to in OpenSSH's sftp-common.h
+ if ($tempLength > 256 * 1024) {
+ user_error('Invalid SFTP packet size');
+ return false;
+ }
+
// SFTP packet type and data payload
while ($tempLength > 0) {
- $temp = $this->_get_channel_packet(self::CHANNEL);
+ $temp = $this->_get_channel_packet(self::CHANNEL, true);
if (is_bool($temp)) {
$this->packet_type = false;
$this->packet_buffer = '';
@@ -2960,8 +3043,8 @@ class SFTP extends SSH2
$this->packet_type = ord($this->_string_shift($this->packet_buffer));
- if ($this->request_id !== false) {
- $this->_string_shift($this->packet_buffer, 4); // remove the request id
+ if ($this->use_request_id) {
+ extract(unpack('Npacket_id', $this->_string_shift($this->packet_buffer, 4))); // remove the request id
$length-= 5; // account for the request id and the packet type
} else {
$length-= 1; // account for the packet type
@@ -2984,6 +3067,14 @@ class SFTP extends SSH2
}
}
+ if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) {
+ $this->requestBuffer[$packet_id] = array(
+ 'packet_type' => $this->packet_type,
+ 'packet' => $packet
+ );
+ return $this->_get_sftp_packet($request_id);
+ }
+
return $packet;
}
@@ -3014,7 +3105,7 @@ class SFTP extends SSH2
/**
* Returns all errors
*
- * @return string
+ * @return array
* @access public
*/
function getSFTPErrors()
diff --git a/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php b/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php
index 08d726ca..d2c4425d 100644
--- a/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php
+++ b/lam/lib/3rdParty/phpseclib/Net/SFTP/Stream.php
@@ -179,7 +179,7 @@ class Stream
if ($host[0] == '$') {
$host = substr($host, 1);
- global $$host;
+ global ${$host};
if (($$host instanceof SFTP) === false) {
return false;
}
diff --git a/lam/lib/3rdParty/phpseclib/Net/SSH1.php b/lam/lib/3rdParty/phpseclib/Net/SSH1.php
index 9e608f4b..514b20a2 100644
--- a/lam/lib/3rdParty/phpseclib/Net/SSH1.php
+++ b/lam/lib/3rdParty/phpseclib/Net/SSH1.php
@@ -916,7 +916,7 @@ class SSH1
/**
* Returns the output of an interactive shell when there's a match for $expect
*
- * $expect can take the form of a string literal or, if $mode == self::READ__REGEX,
+ * $expect can take the form of a string literal or, if $mode == self::READ_REGEX,
* a regular expression.
*
* @see self::write()
@@ -925,7 +925,7 @@ class SSH1
* @return bool
* @access public
*/
- function read($expect, $mode = self::READ__SIMPLE)
+ function read($expect, $mode = self::READ_SIMPLE)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
@@ -939,7 +939,7 @@ class SSH1
$match = $expect;
while (true) {
- if ($mode == self::READ__REGEX) {
+ if ($mode == self::READ_REGEX) {
preg_match($expect, $this->interactiveBuffer, $matches);
$match = isset($matches[0]) ? $matches[0] : '';
}
diff --git a/lam/lib/3rdParty/phpseclib/Net/SSH2.php b/lam/lib/3rdParty/phpseclib/Net/SSH2.php
index 937c38cc..817fa165 100644
--- a/lam/lib/3rdParty/phpseclib/Net/SSH2.php
+++ b/lam/lib/3rdParty/phpseclib/Net/SSH2.php
@@ -100,10 +100,11 @@ class SSH2
* @see \phpseclib\Net\SSH2::_get_channel_packet()
* @access private
*/
- const CHANNEL_EXEC = 0; // PuTTy uses 0x100
- const CHANNEL_SHELL = 1;
- const CHANNEL_SUBSYSTEM = 2;
- const CHANNEL_AGENT_FORWARD = 3;
+ const CHANNEL_EXEC = 1; // PuTTy uses 0x100
+ const CHANNEL_SHELL = 2;
+ const CHANNEL_SUBSYSTEM = 3;
+ const CHANNEL_AGENT_FORWARD = 4;
+ const CHANNEL_KEEP_ALIVE = 5;
/**#@-*/
/**#@+
@@ -126,6 +127,10 @@ class SSH2
* Dumps the content real-time to a file
*/
const LOG_REALTIME_FILE = 4;
+ /**
+ * Make sure that the log never gets larger than this
+ */
+ const LOG_MAX_SIZE = 1048576; // 1024 * 1024
/**#@-*/
/**#@+
@@ -141,9 +146,12 @@ class SSH2
*/
const READ_REGEX = 2;
/**
- * Make sure that the log never gets larger than this
+ * Returns whenever a data packet is received.
+ *
+ * Some data packets may only contain a single character so it may be necessary
+ * to call read() multiple times when using this option
*/
- const LOG_MAX_SIZE = 1048576; // 1024 * 1024
+ const READ_NEXT = 3;
/**#@-*/
/**
@@ -866,6 +874,70 @@ class SSH2
*/
var $agent;
+ /**
+ * Send the identification string first?
+ *
+ * @var bool
+ * @access private
+ */
+ var $send_id_string_first = true;
+
+ /**
+ * Send the key exchange initiation packet first?
+ *
+ * @var bool
+ * @access private
+ */
+ var $send_kex_first = true;
+
+ /**
+ * Some versions of OpenSSH incorrectly calculate the key size
+ *
+ * @var bool
+ * @access private
+ */
+ var $bad_key_size_fix = false;
+
+ /**
+ * The selected decryption algorithm
+ *
+ * @var string
+ * @access private
+ */
+ var $decrypt_algorithm = '';
+
+ /**
+ * Should we try to re-connect to re-establish keys?
+ *
+ * @var bool
+ * @access private
+ */
+ var $retry_connect = false;
+
+ /**
+ * Binary Packet Buffer
+ *
+ * @var string|false
+ * @access private
+ */
+ var $binary_packet_buffer = false;
+
+ /**
+ * Preferred Signature Format
+ *
+ * @var string|false
+ * @access private
+ */
+ var $preferred_signature_format = false;
+
+ /**
+ * Authentication Credentials
+ *
+ * @var array
+ * @access private
+ */
+ var $auth = array();
+
/**
* Default Constructor.
*
@@ -978,13 +1050,69 @@ class SSH2
* CRYPT_MODE_INTERNAL, CRYPT_MODE_MCRYPT
*
* @param int $engine
- * @access private
+ * @access public
*/
function setCryptoEngine($engine)
{
$this->crypto_engine = $engine;
}
+ /**
+ * Send Identification String First
+ *
+ * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
+ * both sides MUST send an identification string". It does not say which side sends it first. In
+ * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+ *
+ * @access public
+ */
+ function sendIdentificationStringFirst()
+ {
+ $this->send_id_string_first = true;
+ }
+
+ /**
+ * Send Identification String Last
+ *
+ * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
+ * both sides MUST send an identification string". It does not say which side sends it first. In
+ * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+ *
+ * @access public
+ */
+ function sendIdentificationStringLast()
+ {
+ $this->send_id_string_first = false;
+ }
+
+ /**
+ * Send SSH_MSG_KEXINIT First
+ *
+ * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
+ * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
+ * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+ *
+ * @access public
+ */
+ function sendKEXINITFirst()
+ {
+ $this->send_kex_first = true;
+ }
+
+ /**
+ * Send SSH_MSG_KEXINIT Last
+ *
+ * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
+ * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
+ * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
+ *
+ * @access public
+ */
+ function sendKEXINITLast()
+ {
+ $this->send_kex_first = false;
+ }
+
/**
* Connect to an SSHv2 server
*
@@ -1016,17 +1144,20 @@ class SSH2
}
$elapsed = microtime(true) - $start;
- $this->curTimeout-= $elapsed;
-
- if ($this->curTimeout <= 0) {
- $this->is_timeout = true;
- return false;
+ if ($this->curTimeout) {
+ $this->curTimeout-= $elapsed;
+ if ($this->curTimeout < 0) {
+ $this->is_timeout = true;
+ return false;
+ }
}
}
$this->identifier = $this->_generate_identifier();
- fputs($this->fsock, $this->identifier . "\r\n");
+ if ($this->send_id_string_first) {
+ fputs($this->fsock, $this->identifier . "\r\n");
+ }
/* According to the SSH2 specs,
@@ -1083,6 +1214,7 @@ class SSH2
}
if (feof($this->fsock)) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -1096,26 +1228,37 @@ class SSH2
$this->server_identifier = trim($temp, "\r\n");
if (strlen($extra)) {
- $this->errors[] = utf8_decode($data);
+ $this->errors[] = $data;
}
- if ($matches[3] != '1.99' && $matches[3] != '2.0') {
+ if (version_compare($matches[3], '1.99', '<')) {
user_error("Cannot connect to SSH $matches[3] servers");
return false;
}
- $response = $this->_get_binary_packet();
- if ($response === false) {
- user_error('Connection closed by server');
- return false;
+ if (!$this->send_id_string_first) {
+ fputs($this->fsock, $this->identifier . "\r\n");
}
- if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
- user_error('Expected SSH_MSG_KEXINIT');
- return false;
+ if (!$this->send_kex_first) {
+ $response = $this->_get_binary_packet();
+ if ($response === false) {
+ $this->bitmap = 0;
+ user_error('Connection closed by server');
+ return false;
+ }
+
+ if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
+ user_error('Expected SSH_MSG_KEXINIT');
+ return false;
+ }
+
+ if (!$this->_key_exchange($response)) {
+ return false;
+ }
}
- if (!$this->_key_exchange($response)) {
+ if ($this->send_kex_first && !$this->_key_exchange()) {
return false;
}
@@ -1137,7 +1280,7 @@ class SSH2
$identifier = 'SSH-2.0-phpseclib_2.0';
$ext = array();
- if (extension_loaded('libsodium')) {
+ if (function_exists('\\Sodium\\library_version_major')) {
$ext[] = 'libsodium';
}
@@ -1163,10 +1306,10 @@ class SSH2
/**
* Key Exchange
*
- * @param string $kexinit_payload_server
+ * @param string $kexinit_payload_server optional
* @access private
*/
- function _key_exchange($kexinit_payload_server)
+ function _key_exchange($kexinit_payload_server = false)
{
$kex_algorithms = array(
// Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using
@@ -1189,6 +1332,8 @@ class SSH2
}
$server_host_key_algorithms = array(
+ 'rsa-sha2-256', // RFC 8332
+ 'rsa-sha2-512', // RFC 8332
'ssh-rsa', // RECOMMENDED sign Raw RSA Key
'ssh-dss' // REQUIRED sign Raw DSS Key
);
@@ -1287,8 +1432,9 @@ class SSH2
);
// some SSH servers have buggy implementations of some of the above algorithms
- switch ($this->server_identifier) {
- case 'SSH-2.0-SSHD':
+ switch (true) {
+ case $this->server_identifier == 'SSH-2.0-SSHD':
+ case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK':
$mac_algorithms = array_values(array_diff(
$mac_algorithms,
array('hmac-sha1-96', 'hmac-md5-96')
@@ -1303,6 +1449,52 @@ class SSH2
$client_cookie = Random::string(16);
+ $kexinit_payload_client = pack(
+ 'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
+ NET_SSH2_MSG_KEXINIT,
+ $client_cookie,
+ strlen($str_kex_algorithms),
+ $str_kex_algorithms,
+ strlen($str_server_host_key_algorithms),
+ $str_server_host_key_algorithms,
+ strlen($encryption_algorithms_client_to_server),
+ $encryption_algorithms_client_to_server,
+ strlen($encryption_algorithms_server_to_client),
+ $encryption_algorithms_server_to_client,
+ strlen($mac_algorithms_client_to_server),
+ $mac_algorithms_client_to_server,
+ strlen($mac_algorithms_server_to_client),
+ $mac_algorithms_server_to_client,
+ strlen($compression_algorithms_client_to_server),
+ $compression_algorithms_client_to_server,
+ strlen($compression_algorithms_server_to_client),
+ $compression_algorithms_server_to_client,
+ 0,
+ '',
+ 0,
+ '',
+ 0,
+ 0
+ );
+
+ if ($this->send_kex_first) {
+ if (!$this->_send_binary_packet($kexinit_payload_client)) {
+ return false;
+ }
+
+ $kexinit_payload_server = $this->_get_binary_packet();
+ if ($kexinit_payload_server === false) {
+ $this->bitmap = 0;
+ user_error('Connection closed by server');
+ return false;
+ }
+
+ if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
+ user_error('Expected SSH_MSG_KEXINIT');
+ return false;
+ }
+ }
+
$response = $kexinit_payload_server;
$this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
$server_cookie = $this->_string_shift($response, 16);
@@ -1373,39 +1565,9 @@ class SSH2
extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
$first_kex_packet_follows = $first_kex_packet_follows != 0;
- // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
- $kexinit_payload_client = pack(
- 'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
- NET_SSH2_MSG_KEXINIT,
- $client_cookie,
- strlen($str_kex_algorithms),
- $str_kex_algorithms,
- strlen($str_server_host_key_algorithms),
- $str_server_host_key_algorithms,
- strlen($encryption_algorithms_client_to_server),
- $encryption_algorithms_client_to_server,
- strlen($encryption_algorithms_server_to_client),
- $encryption_algorithms_server_to_client,
- strlen($mac_algorithms_client_to_server),
- $mac_algorithms_client_to_server,
- strlen($mac_algorithms_server_to_client),
- $mac_algorithms_server_to_client,
- strlen($compression_algorithms_client_to_server),
- $compression_algorithms_client_to_server,
- strlen($compression_algorithms_server_to_client),
- $compression_algorithms_server_to_client,
- 0,
- '',
- 0,
- '',
- 0,
- 0
- );
-
- if (!$this->_send_binary_packet($kexinit_payload_client)) {
+ if (!$this->send_kex_first && !$this->_send_binary_packet($kexinit_payload_client)) {
return false;
}
- // here ends the second place.
// we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
// we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
@@ -1459,6 +1621,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -1551,12 +1714,14 @@ class SSH2
$data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
if (!$this->_send_binary_packet($data)) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -1646,9 +1811,25 @@ class SSH2
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
- if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
- user_error('Server Host Key Algorithm Mismatch');
- return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
+ switch ($server_host_key_algorithm) {
+ case 'ssh-dss':
+ $expected_key_format = 'ssh-dss';
+ break;
+ //case 'rsa-sha2-256':
+ //case 'rsa-sha2-512':
+ //case 'ssh-rsa':
+ default:
+ $expected_key_format = 'ssh-rsa';
+ }
+
+ if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) {
+ switch (true) {
+ case $this->signature_format == $server_host_key_algorithm:
+ case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512':
+ case $this->signature_format != 'ssh-rsa':
+ user_error('Server Host Key Algorithm Mismatch');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
+ }
}
$packet = pack(
@@ -1663,6 +1844,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -1677,12 +1859,14 @@ class SSH2
return false;
}
+ $this->decrypt_algorithm = $decrypt;
+
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
$this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
if ($this->encrypt) {
if ($this->crypto_engine) {
- $this->encrypt->setEngine($this->crypto_engine);
+ $this->encrypt->setPreferredEngine($this->crypto_engine);
}
if ($this->encrypt->block_size) {
$this->encrypt_block_size = $this->encrypt->block_size;
@@ -1706,7 +1890,7 @@ class SSH2
$this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt);
if ($this->decrypt) {
if ($this->crypto_engine) {
- $this->decrypt->setEngine($this->crypto_engine);
+ $this->decrypt->setPreferredEngine($this->crypto_engine);
}
if ($this->decrypt->block_size) {
$this->decrypt_block_size = $this->decrypt->block_size;
@@ -1843,6 +2027,10 @@ class SSH2
*/
function _encryption_algorithm_to_key_size($algorithm)
{
+ if ($this->bad_key_size_fix && $this->_bad_algorithm_candidate($algorithm)) {
+ return 16;
+ }
+
switch ($algorithm) {
case 'none':
return 0;
@@ -1917,6 +2105,27 @@ class SSH2
return null;
}
+ /*
+ * Tests whether or not proposed algorithm has a potential for issues
+ *
+ * @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html
+ * @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291
+ * @param string $algorithm Name of the encryption algorithm
+ * @return bool
+ * @access private
+ */
+ function _bad_algorithm_candidate($algorithm)
+ {
+ switch ($algorithm) {
+ case 'arcfour256':
+ case 'aes192-ctr':
+ case 'aes256-ctr':
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Login
*
@@ -1932,6 +2141,7 @@ class SSH2
function login($username)
{
$args = func_get_args();
+ $this->auth[] = $args;
return call_user_func_array(array(&$this, '_login'), $args);
}
@@ -1996,6 +2206,14 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ if ($this->retry_connect) {
+ $this->retry_connect = false;
+ if (!$this->_connect()) {
+ return false;
+ }
+ return $this->_login_helper($username, $password);
+ }
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2048,6 +2266,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2106,6 +2325,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2124,7 +2344,7 @@ class SSH2
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
- $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length));
+ $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . $this->_string_shift($response, $length);
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
case NET_SSH2_MSG_USERAUTH_FAILURE:
// can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
@@ -2206,6 +2426,7 @@ class SSH2
} else {
$orig = $response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2375,6 +2596,21 @@ class SSH2
$publickey['n']
);
+ switch ($this->signature_format) {
+ case 'rsa-sha2-512':
+ $hash = 'sha512';
+ $signatureType = 'rsa-sha2-512';
+ break;
+ case 'rsa-sha2-256':
+ $hash = 'sha256';
+ $signatureType = 'rsa-sha2-256';
+ break;
+ //case 'ssh-rsa':
+ default:
+ $hash = 'sha1';
+ $signatureType = 'ssh-rsa';
+ }
+
$part1 = pack(
'CNa*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST,
@@ -2385,7 +2621,7 @@ class SSH2
strlen('publickey'),
'publickey'
);
- $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey);
+ $part2 = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($publickey), $publickey);
$packet = $part1 . chr(0) . $part2;
if (!$this->_send_binary_packet($packet)) {
@@ -2394,6 +2630,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2425,8 +2662,9 @@ class SSH2
$packet = $part1 . chr(1) . $part2;
$privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1);
+ $privatekey->setHash($hash);
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
- $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
+ $signature = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($signature), $signature);
$packet.= pack('Na*', strlen($signature), $signature);
if (!$this->_send_binary_packet($packet)) {
@@ -2435,6 +2673,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2561,6 +2800,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2700,6 +2940,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
+ $this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
@@ -2812,6 +3053,10 @@ class SSH2
$channel = $this->_get_interactive_channel();
+ if ($mode == self::READ_NEXT) {
+ return $this->_get_channel_packet($channel);
+ }
+
$match = $expect;
while (true) {
if ($mode == self::READ_REGEX) {
@@ -3010,6 +3255,84 @@ class SSH2
return (bool) ($this->bitmap & self::MASK_LOGIN);
}
+ /**
+ * Pings a server connection, or tries to reconnect if the connection has gone down
+ *
+ * Inspired by http://php.net/manual/en/mysqli.ping.php
+ *
+ * @return bool
+ * @access public
+ */
+ function ping()
+ {
+ if (!$this->isAuthenticated()) {
+ return false;
+ }
+
+ $this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE] = $this->window_size;
+ $packet_size = 0x4000;
+ $packet = pack(
+ 'CNa*N3',
+ NET_SSH2_MSG_CHANNEL_OPEN,
+ strlen('session'),
+ 'session',
+ self::CHANNEL_KEEP_ALIVE,
+ $this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE],
+ $packet_size
+ );
+
+ if (!@$this->_send_binary_packet($packet)) {
+ return $this->_reconnect();
+ }
+
+ $this->channel_status[self::CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN;
+
+ $response = @$this->_get_channel_packet(self::CHANNEL_KEEP_ALIVE);
+ if ($response !== false) {
+ $this->_close_channel(self::CHANNEL_KEEP_ALIVE);
+ return true;
+ }
+
+ return $this->_reconnect();
+ }
+
+ /**
+ * In situ reconnect method
+ *
+ * @return boolean
+ * @access private
+ */
+ function _reconnect()
+ {
+ $this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
+ $this->retry_connect = true;
+ if (!$this->_connect()) {
+ return false;
+ }
+ foreach ($this->auth as $auth) {
+ $result = call_user_func_array(array(&$this, 'login'), $auth);
+ }
+ return $result;
+ }
+
+ /**
+ * Resets a connection for re-use
+ *
+ * @param int $reason
+ * @access private
+ */
+ function _reset_connection($reason)
+ {
+ $this->_disconnect($reason);
+ $this->decrypt = $this->encrypt = false;
+ $this->decrypt_block_size = $this->encrypt_block_size = 8;
+ $this->hmac_check = $this->hmac_create = false;
+ $this->hmac_size = false;
+ $this->session_id = false;
+ $this->retry_connect = true;
+ $this->get_seq_no = $this->send_seq_no = 0;
+ }
+
/**
* Gets Binary Packets
*
@@ -3019,11 +3342,11 @@ class SSH2
* @return string
* @access private
*/
- function _get_binary_packet()
+ function _get_binary_packet($skip_channel_filter = false)
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
- user_error('Connection closed prematurely');
$this->bitmap = 0;
+ user_error('Connection closed prematurely');
return false;
}
@@ -3053,6 +3376,11 @@ class SSH2
// "implementations SHOULD check that the packet length is reasonable"
// PuTTY uses 0x9000 as the actual max packet size and so to shall we
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
+ if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decrypt_algorithm) && !($this->bitmap & SSH2::MASK_LOGIN)) {
+ $this->bad_key_size_fix = true;
+ $this->_reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
+ return false;
+ }
user_error('Invalid size');
return false;
}
@@ -3061,13 +3389,14 @@ class SSH2
while ($remaining_length > 0) {
$temp = stream_get_contents($this->fsock, $remaining_length);
if ($temp === false || feof($this->fsock)) {
- user_error('Error reading from socket');
$this->bitmap = 0;
+ user_error('Error reading from socket');
return false;
}
$buffer.= $temp;
$remaining_length-= strlen($temp);
}
+
$stop = microtime(true);
if (strlen($buffer)) {
$raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
@@ -3079,8 +3408,8 @@ class SSH2
if ($this->hmac_check !== false) {
$hmac = stream_get_contents($this->fsock, $this->hmac_size);
if ($hmac === false || strlen($hmac) != $this->hmac_size) {
- user_error('Error reading socket');
$this->bitmap = 0;
+ user_error('Error reading socket');
return false;
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
user_error('Invalid HMAC');
@@ -3103,7 +3432,7 @@ class SSH2
$this->last_packet = $current;
}
- return $this->_filter($payload);
+ return $this->_filter($payload, $skip_channel_filter);
}
/**
@@ -3115,7 +3444,7 @@ class SSH2
* @return string
* @access private
*/
- function _filter($payload)
+ function _filter($payload, $skip_channel_filter)
{
switch (ord($payload[0])) {
case NET_SSH2_MSG_DISCONNECT:
@@ -3124,11 +3453,11 @@ class SSH2
return false;
}
extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
- $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length));
+ $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
$this->bitmap = 0;
return false;
case NET_SSH2_MSG_IGNORE:
- $payload = $this->_get_binary_packet();
+ $payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_DEBUG:
$this->_string_shift($payload, 2);
@@ -3136,18 +3465,19 @@ class SSH2
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
- $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length));
- $payload = $this->_get_binary_packet();
+ $this->errors[] = 'SSH_MSG_DEBUG: ' . $this->_string_shift($payload, $length);
+ $payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_UNIMPLEMENTED:
return false;
case NET_SSH2_MSG_KEXINIT:
if ($this->session_id !== false) {
+ $this->send_kex_first = false;
if (!$this->_key_exchange($payload)) {
$this->bitmap = 0;
return false;
}
- $payload = $this->_get_binary_packet();
+ $payload = $this->_get_binary_packet($skip_channel_filter);
}
}
@@ -3158,13 +3488,24 @@ class SSH2
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
- $this->banner_message = utf8_decode($this->_string_shift($payload, $length));
+ $this->banner_message = $this->_string_shift($payload, $length);
$payload = $this->_get_binary_packet();
}
// only called when we've already logged in
if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
switch (ord($payload[0])) {
+ case NET_SSH2_MSG_CHANNEL_DATA:
+ case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ case NET_SSH2_MSG_CHANNEL_REQUEST:
+ case NET_SSH2_MSG_CHANNEL_CLOSE:
+ case NET_SSH2_MSG_CHANNEL_EOF:
+ if (!$skip_channel_filter && !empty($this->server_channels)) {
+ $this->binary_packet_buffer = $payload;
+ $this->_get_channel_packet(true);
+ $payload = $this->_get_binary_packet();
+ }
+ break;
case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
if (strlen($payload) < 4) {
return false;
@@ -3176,7 +3517,7 @@ class SSH2
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
- $payload = $this->_get_binary_packet();
+ $payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
$this->_string_shift($payload, 1);
@@ -3239,7 +3580,7 @@ class SSH2
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
}
- $payload = $this->_get_binary_packet();
+ $payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
$this->_string_shift($payload, 1);
@@ -3250,7 +3591,7 @@ class SSH2
extract(unpack('Nwindow_size', $this->_string_shift($payload, 4)));
$this->window_size_client_to_server[$channel]+= $window_size;
- $payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet();
+ $payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet($skip_channel_filter);
}
}
@@ -3347,39 +3688,50 @@ class SSH2
}
while (true) {
- if ($this->curTimeout) {
- if ($this->curTimeout < 0) {
- $this->is_timeout = true;
- return true;
- }
-
+ if ($this->binary_packet_buffer !== false) {
+ $response = $this->binary_packet_buffer;
+ $this->binary_packet_buffer = false;
+ } else {
$read = array($this->fsock);
$write = $except = null;
- $start = microtime(true);
- $sec = floor($this->curTimeout);
- $usec = 1000000 * ($this->curTimeout - $sec);
- // on windows this returns a "Warning: Invalid CRT parameters detected" error
- if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
- $this->is_timeout = true;
- return true;
+ if (!$this->curTimeout) {
+ @stream_select($read, $write, $except, null);
+ } else {
+ if ($this->curTimeout < 0) {
+ $this->is_timeout = true;
+ return true;
+ }
+
+ $read = array($this->fsock);
+ $write = $except = null;
+
+ $start = microtime(true);
+ $sec = floor($this->curTimeout);
+ $usec = 1000000 * ($this->curTimeout - $sec);
+ // on windows this returns a "Warning: Invalid CRT parameters detected" error
+ if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
+ $this->is_timeout = true;
+ if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) {
+ $this->_close_channel($client_channel);
+ }
+ return true;
+ }
+ $elapsed = microtime(true) - $start;
+ $this->curTimeout-= $elapsed;
+ }
+
+ $response = $this->_get_binary_packet(true);
+ if ($response === false) {
+ $this->bitmap = 0;
+ user_error('Connection closed by server');
+ return false;
}
- $elapsed = microtime(true) - $start;
- $this->curTimeout-= $elapsed;
}
- $response = $this->_get_binary_packet();
- if ($response === false) {
- user_error('Connection closed by server');
- return false;
- }
if ($client_channel == -1 && $response === true) {
return true;
}
- if (!strlen($response)) {
- return '';
- }
-
if (!strlen($response)) {
return false;
}
@@ -3407,6 +3759,82 @@ class SSH2
$this->window_size_server_to_client[$channel]+= $this->window_size;
}
+ switch ($type) {
+ case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ /*
+ if ($client_channel == self::CHANNEL_EXEC) {
+ $this->_send_channel_packet($client_channel, chr(0));
+ }
+ */
+ // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
+ if (strlen($response) < 8) {
+ return false;
+ }
+ extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
+ $data = $this->_string_shift($response, $length);
+ $this->stdErrorLog.= $data;
+ if ($skip_extended || $this->quiet_mode) {
+ continue 2;
+ }
+ if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
+ return $data;
+ }
+ if (!isset($this->channel_buffers[$channel])) {
+ $this->channel_buffers[$channel] = array();
+ }
+ $this->channel_buffers[$channel][] = $data;
+
+ continue 2;
+ case NET_SSH2_MSG_CHANNEL_REQUEST:
+ if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
+ continue 2;
+ }
+ if (strlen($response) < 4) {
+ return false;
+ }
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
+ $value = $this->_string_shift($response, $length);
+ switch ($value) {
+ case 'exit-signal':
+ $this->_string_shift($response, 1);
+ if (strlen($response) < 4) {
+ return false;
+ }
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
+ $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
+ $this->_string_shift($response, 1);
+ if (strlen($response) < 4) {
+ return false;
+ }
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
+ if ($length) {
+ $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
+ }
+
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
+
+ $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
+
+ continue 3;
+ case 'exit-status':
+ if (strlen($response) < 5) {
+ return false;
+ }
+ extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
+ $this->exit_status = $exit_status;
+
+ // "The client MAY ignore these messages."
+ // -- http://tools.ietf.org/html/rfc4254#section-6.10
+
+ continue 3;
+ default:
+ // "Some systems may not implement signals, in which case they SHOULD ignore this message."
+ // -- http://tools.ietf.org/html/rfc4254#section-6.9
+ continue 3;
+ }
+ }
+
switch ($this->channel_status[$channel]) {
case NET_SSH2_MSG_CHANNEL_OPEN:
switch ($type) {
@@ -3489,76 +3917,6 @@ class SSH2
}
$this->channel_buffers[$channel][] = $data;
break;
- case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
- /*
- if ($client_channel == self::CHANNEL_EXEC) {
- $this->_send_channel_packet($client_channel, chr(0));
- }
- */
- // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
- if (strlen($response) < 8) {
- return false;
- }
- extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
- $data = $this->_string_shift($response, $length);
- $this->stdErrorLog.= $data;
- if ($skip_extended || $this->quiet_mode) {
- break;
- }
- if ($client_channel == $channel) {
- return $data;
- }
- if (!isset($this->channel_buffers[$channel])) {
- $this->channel_buffers[$channel] = array();
- }
- $this->channel_buffers[$channel][] = $data;
- break;
- case NET_SSH2_MSG_CHANNEL_REQUEST:
- if (strlen($response) < 4) {
- return false;
- }
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
- $value = $this->_string_shift($response, $length);
- switch ($value) {
- case 'exit-signal':
- $this->_string_shift($response, 1);
- if (strlen($response) < 4) {
- return false;
- }
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
- $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
- $this->_string_shift($response, 1);
- if (strlen($response) < 4) {
- return false;
- }
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
- if ($length) {
- $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
- }
-
- $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
- $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
-
- $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
-
- break;
- case 'exit-status':
- if (strlen($response) < 5) {
- return false;
- }
- extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
- $this->exit_status = $exit_status;
-
- // "The client MAY ignore these messages."
- // -- http://tools.ietf.org/html/rfc4254#section-6.10
-
- break;
- default:
- // "Some systems may not implement signals, in which case they SHOULD ignore this message."
- // -- http://tools.ietf.org/html/rfc4254#section-6.9
- break;
- }
- break;
case NET_SSH2_MSG_CHANNEL_CLOSE:
$this->curTimeout = 0;
@@ -3596,8 +3954,8 @@ class SSH2
function _send_binary_packet($data, $logged = null)
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
- user_error('Connection closed prematurely');
$this->bitmap = 0;
+ user_error('Connection closed prematurely');
return false;
}
@@ -4258,6 +4616,8 @@ class SSH2
break;
case 'ssh-rsa':
+ case 'rsa-sha2-256':
+ case 'rsa-sha2-512':
if (strlen($server_public_host_key) < 4) {
return false;
}
@@ -4280,8 +4640,21 @@ class SSH2
$signature = $this->_string_shift($signature, $temp['length']);
$rsa = new RSA();
+ switch ($this->signature_format) {
+ case 'rsa-sha2-512':
+ $hash = 'sha512';
+ break;
+ case 'rsa-sha2-256':
+ $hash = 'sha256';
+ break;
+ //case 'ssh-rsa':
+ default:
+ $hash = 'sha1';
+ }
+ $rsa->setHash($hash);
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
$rsa->loadKey(array('e' => $e, 'n' => $n), RSA::PUBLIC_FORMAT_RAW);
+
if (!$rsa->verify($this->exchange_hash, $signature)) {
user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
@@ -4308,7 +4681,30 @@ class SSH2
$s = $s->modPow($e, $n);
$s = $s->toBytes();
- $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
+ switch ($this->signature_format) {
+ case 'rsa-sha2-512':
+ $hash = 'sha512';
+ break;
+ case 'rsa-sha2-256':
+ $hash = 'sha256';
+ break;
+ //case 'ssh-rsa':
+ default:
+ $hash = 'sha1';
+ }
+ $hashObj = new Hash($hash);
+ switch ($this->signature_format) {
+ case 'rsa-sha2-512':
+ $h = pack('N5a*', 0x00305130, 0x0D060960, 0x86480165, 0x03040203, 0x05000440, $hashObj->hash($this->exchange_hash));
+ break;
+ case 'rsa-sha2-256':
+ $h = pack('N5a*', 0x00303130, 0x0D060960, 0x86480165, 0x03040201, 0x05000420, $hashObj->hash($this->exchange_hash));
+ break;
+ //case 'ssh-rsa':
+ default:
+ $hash = 'sha1';
+ $h = pack('N4a*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, $hashObj->hash($this->exchange_hash));
+ }
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) {
diff --git a/lam/lib/3rdParty/phpseclib/System/SSH/Agent.php b/lam/lib/3rdParty/phpseclib/System/SSH/Agent.php
index a4ff0549..99dcecfe 100644
--- a/lam/lib/3rdParty/phpseclib/System/SSH/Agent.php
+++ b/lam/lib/3rdParty/phpseclib/System/SSH/Agent.php
@@ -43,7 +43,7 @@ use phpseclib\System\SSH\Agent\Identity;
*
* @package SSH\Agent
* @author Jim Wigginton
- * @access internal
+ * @access public
*/
class Agent
{
@@ -117,18 +117,20 @@ class Agent
* @return \phpseclib\System\SSH\Agent
* @access public
*/
- function __construct()
+ function __construct($address = null)
{
- 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;
+ if (!$address) {
+ 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);
@@ -155,12 +157,14 @@ class Agent
$packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed while requesting identities');
+ return array();
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities');
+ return array();
}
$identities = array();
diff --git a/lam/lib/3rdParty/phpseclib/System/SSH/Agent/Identity.php b/lam/lib/3rdParty/phpseclib/System/SSH/Agent/Identity.php
index b8cc6cde..b4649046 100644
--- a/lam/lib/3rdParty/phpseclib/System/SSH/Agent/Identity.php
+++ b/lam/lib/3rdParty/phpseclib/System/SSH/Agent/Identity.php
@@ -32,6 +32,17 @@ use phpseclib\System\SSH\Agent;
*/
class Identity
{
+ /**@+
+ * Signature Flags
+ *
+ * See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3
+ *
+ * @access private
+ */
+ const SSH_AGENT_RSA2_256 = 2;
+ const SSH_AGENT_RSA2_512 = 4;
+ /**#@-*/
+
/**
* Key Object
*
@@ -59,6 +70,16 @@ class Identity
*/
var $fsock;
+ /**
+ * Signature flags
+ *
+ * @var int
+ * @access private
+ * @see self::sign()
+ * @see self::setHash()
+ */
+ var $flags = 0;
+
/**
* Default Constructor.
*
@@ -126,6 +147,31 @@ class Identity
{
}
+ /**
+ * Set Hash
+ *
+ * ssh-agent doesn't support using hashes for RSA other than SHA1
+ *
+ * @param string $hash
+ * @access public
+ */
+ function setHash($hash)
+ {
+ $this->flags = 0;
+ switch ($hash) {
+ case 'sha1':
+ break;
+ case 'sha256':
+ $this->flags = self::SSH_AGENT_RSA2_256;
+ break;
+ case 'sha512':
+ $this->flags = self::SSH_AGENT_RSA2_512;
+ break;
+ default:
+ user_error('The only supported hashes for RSA are sha1, sha256 and sha512');
+ }
+ }
+
/**
* Create a signature
*
@@ -138,7 +184,7 @@ class Identity
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', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
+ $packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, $this->flags);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed during signing');
@@ -151,8 +197,34 @@ class Identity
}
$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);
+ $length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
+ if ($length != strlen($signature_blob)) {
+ user_error('Malformed signature blob');
+ }
+ $length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
+ if ($length > strlen($signature_blob) + 4) {
+ user_error('Malformed signature blob');
+ }
+ $type = $this->_string_shift($signature_blob, $length);
+ $this->_string_shift($signature_blob, 4);
+
+ return $signature_blob;
+ }
+
+ /**
+ * String Shift
+ *
+ * Inspired by array_shift
+ *
+ * @param string $string
+ * @param int $index
+ * @return string
+ * @access private
+ */
+ function _string_shift(&$string, $index = 1)
+ {
+ $substr = substr($string, 0, $index);
+ $string = substr($string, $index);
+ return $substr;
}
}
diff --git a/lam/lib/modules/imapAccess.inc b/lam/lib/modules/imapAccess.inc
index d08c4d11..df4ca939 100644
--- a/lam/lib/modules/imapAccess.inc
+++ b/lam/lib/modules/imapAccess.inc
@@ -281,21 +281,20 @@ class imapAccess extends baseModule {
* @return array HTML meta data
*/
function display_html_password() {
- $return = new htmlTable();
+ $return = new htmlResponsiveRow();
if($this->moduleSettings['ImapAccess_ImapAdminPasswordSelect'][0] == "lam_user_pass"){
$message = $this->messages['managemailbox'][6];
$messageElement = new htmlStatusMessage($message[0], $message[1]);
- $messageElement->colspan = 3;
- $return->addElement($messageElement);
- $return->addElement(new htmlSpacer(null, '10px'), true);
+ $return->add($messageElement, 12);
+ $return->addVerticalSpacer('1rem');
}
- $passwordInput = new htmlTableExtendedInputField(_("Password of IMAP admin user"), 'ImapAdminPassword', '', 'ImapAdminPassword_Sess');
+ $passwordInput = new htmlResponsiveInputField(_("Password of IMAP admin user"), 'ImapAdminPassword', '', 'ImapAdminPassword_Sess');
$passwordInput->setIsPassword(true);
$passwordInput->setRequired(true);
$passwordInput->setOnKeyPress('SubmitForm(\'enterPasswordButton\', event);');
- $return->addElement($passwordInput, true);
- $return->addElement(new htmlSpacer(null, '10px'), true);
- $return->addElement(new htmlButton('enterPasswordButton', _('Ok')));
+ $return->add($passwordInput, 12);
+ $return->addVerticalSpacer('2rem');
+ $return->add(new htmlButton('enterPasswordButton', _('Ok')), 12, 12, 12, 'text-center');
return $return;
}