SSH SFTP Updater Support - Version 0.8.1

Version Description

  • 2019/Apr/13 =

  • TWEAK: Don't require phpseclib classes if they already exist

Download this release

Release Info

Developer DavidAnderson
Plugin Icon wp plugin SSH SFTP Updater Support
Version 0.8.1
Comparing to
See all releases

Code changes from version 0.8.0 to 0.8.1

class-wp-filesystem-ssh2.php CHANGED
@@ -8,8 +8,8 @@
8
 
9
  set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/phpseclib/');
10
 
11
- require_once('Net/SFTP.php');
12
- require_once('Crypt/RSA.php');
13
 
14
  /**
15
  * WordPress Filesystem Class for implementing SSH2.
8
 
9
  set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/phpseclib/');
10
 
11
+ if (!class_exists('Net_SFTP')) require_once('Net/SFTP.php');
12
+ if (!class_exists('Crypt_RSA')) require_once('Crypt/RSA.php');
13
 
14
  /**
15
  * WordPress Filesystem Class for implementing SSH2.
phpseclib/Crypt/Base.php CHANGED
@@ -661,7 +661,7 @@ class Crypt_Base
661
  $count = isset($func_args[4]) ? $func_args[4] : 1000;
662
 
663
  // Keylength
664
- if (isset($func_args[5])) {
665
  $dkLen = $func_args[5];
666
  } else {
667
  $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
@@ -696,10 +696,10 @@ class Crypt_Base
696
  include_once 'Crypt/Hash.php';
697
  }
698
  $i = 1;
 
 
 
699
  while (strlen($key) < $dkLen) {
700
- $hmac = new Crypt_Hash();
701
- $hmac->setHash($hash);
702
- $hmac->setKey($password);
703
  $f = $u = $hmac->hash($salt . pack('N', $i++));
704
  for ($j = 2; $j <= $count; ++$j) {
705
  $u = $hmac->hash($u);
@@ -754,7 +754,7 @@ class Crypt_Base
754
  case CRYPT_MODE_STREAM:
755
  return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
756
  case CRYPT_MODE_ECB:
757
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
758
  return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
759
  case CRYPT_MODE_CBC:
760
  $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
@@ -1059,14 +1059,14 @@ class Crypt_Base
1059
  break;
1060
  case CRYPT_MODE_ECB:
1061
  if (!defined('OPENSSL_RAW_DATA')) {
1062
- $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1063
  }
1064
  $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1065
  break;
1066
  case CRYPT_MODE_CBC:
1067
  if (!defined('OPENSSL_RAW_DATA')) {
1068
  $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1069
- $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1070
  $offset = 2 * $this->block_size;
1071
  } else {
1072
  $offset = $this->block_size;
@@ -1349,7 +1349,7 @@ class Crypt_Base
1349
  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1350
  $block = substr($plaintext, $i, $block_size);
1351
  if (strlen($block) > strlen($buffer['ciphertext'])) {
1352
- $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1353
  $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1354
  $buffer['ciphertext'].= $result;
1355
  }
@@ -1360,7 +1360,7 @@ class Crypt_Base
1360
  } else {
1361
  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1362
  $block = substr($plaintext, $i, $block_size);
1363
- $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1364
  $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1365
  $this->_increment_str($xor);
1366
  $ciphertext.= $block ^ $otp;
@@ -1404,7 +1404,7 @@ class Crypt_Base
1404
  }
1405
  if ($this->continuousBuffer) {
1406
  if (!defined('OPENSSL_RAW_DATA')) {
1407
- $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1408
  }
1409
  $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1410
  if ($overflow) {
661
  $count = isset($func_args[4]) ? $func_args[4] : 1000;
662
 
663
  // Keylength
664
+ if (isset($func_args[5]) && $func_args[5] > 0) {
665
  $dkLen = $func_args[5];
666
  } else {
667
  $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
696
  include_once 'Crypt/Hash.php';
697
  }
698
  $i = 1;
699
+ $hmac = new Crypt_Hash();
700
+ $hmac->setHash($hash);
701
+ $hmac->setKey($password);
702
  while (strlen($key) < $dkLen) {
 
 
 
703
  $f = $u = $hmac->hash($salt . pack('N', $i++));
704
  for ($j = 2; $j <= $count; ++$j) {
705
  $u = $hmac->hash($u);
754
  case CRYPT_MODE_STREAM:
755
  return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
756
  case CRYPT_MODE_ECB:
757
+ $result = @openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
758
  return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
759
  case CRYPT_MODE_CBC:
760
  $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
1059
  break;
1060
  case CRYPT_MODE_ECB:
1061
  if (!defined('OPENSSL_RAW_DATA')) {
1062
+ $ciphertext.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1063
  }
1064
  $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1065
  break;
1066
  case CRYPT_MODE_CBC:
1067
  if (!defined('OPENSSL_RAW_DATA')) {
1068
  $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1069
+ $ciphertext.= substr(@openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1070
  $offset = 2 * $this->block_size;
1071
  } else {
1072
  $offset = $this->block_size;
1349
  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1350
  $block = substr($plaintext, $i, $block_size);
1351
  if (strlen($block) > strlen($buffer['ciphertext'])) {
1352
+ $result = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1353
  $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1354
  $buffer['ciphertext'].= $result;
1355
  }
1360
  } else {
1361
  for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1362
  $block = substr($plaintext, $i, $block_size);
1363
+ $otp = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1364
  $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1365
  $this->_increment_str($xor);
1366
  $ciphertext.= $block ^ $otp;
1404
  }
1405
  if ($this->continuousBuffer) {
1406
  if (!defined('OPENSSL_RAW_DATA')) {
1407
+ $encryptIV.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1408
  }
1409
  $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1410
  if ($overflow) {
phpseclib/Crypt/Hash.php CHANGED
@@ -126,6 +126,15 @@ class Crypt_Hash
126
  */
127
  var $key = false;
128
 
 
 
 
 
 
 
 
 
 
129
  /**
130
  * Outer XOR (Internal HMAC)
131
  *
@@ -144,6 +153,15 @@ class Crypt_Hash
144
  */
145
  var $ipad;
146
 
 
 
 
 
 
 
 
 
 
147
  /**
148
  * Default Constructor.
149
  *
@@ -192,6 +210,43 @@ class Crypt_Hash
192
  function setKey($key = false)
193
  {
194
  $this->key = $key;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  }
196
 
197
  /**
@@ -242,19 +297,38 @@ class Crypt_Hash
242
  }
243
 
244
  switch ($hash) {
 
 
 
 
 
 
 
245
  case 'md2':
246
- $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
 
 
 
 
 
 
 
 
 
 
 
 
247
  CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
248
  break;
249
  case 'sha384':
250
  case 'sha512':
251
- $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
252
  break;
253
  default:
254
- $mode = CRYPT_HASH_MODE;
255
  }
256
 
257
- switch ($mode) {
258
  case CRYPT_HASH_MODE_MHASH:
259
  switch ($hash) {
260
  case 'md5':
@@ -267,6 +341,7 @@ class Crypt_Hash
267
  default:
268
  $this->hash = MHASH_SHA1;
269
  }
 
270
  return;
271
  case CRYPT_HASH_MODE_HASH:
272
  switch ($hash) {
@@ -283,35 +358,33 @@ class Crypt_Hash
283
  default:
284
  $this->hash = 'sha1';
285
  }
 
286
  return;
287
  }
288
 
289
  switch ($hash) {
290
  case 'md2':
291
- $this->b = 16;
292
  $this->hash = array($this, '_md2');
293
  break;
294
  case 'md5':
295
- $this->b = 64;
296
  $this->hash = array($this, '_md5');
297
  break;
298
  case 'sha256':
299
- $this->b = 64;
300
  $this->hash = array($this, '_sha256');
301
  break;
302
  case 'sha384':
303
  case 'sha512':
304
- $this->b = 128;
305
  $this->hash = array($this, '_sha512');
306
  break;
307
  case 'sha1':
308
  default:
309
- $this->b = 64;
310
  $this->hash = array($this, '_sha1');
311
  }
312
 
313
  $this->ipad = str_repeat(chr(0x36), $this->b);
314
  $this->opad = str_repeat(chr(0x5C), $this->b);
 
 
315
  }
316
 
317
  /**
@@ -323,33 +396,25 @@ class Crypt_Hash
323
  */
324
  function hash($text)
325
  {
326
- $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
327
-
328
  if (!empty($this->key) || is_string($this->key)) {
329
- switch ($mode) {
330
  case CRYPT_HASH_MODE_MHASH:
331
- $output = mhash($this->hash, $text, $this->key);
332
  break;
333
  case CRYPT_HASH_MODE_HASH:
334
- $output = hash_hmac($this->hash, $text, $this->key, true);
335
  break;
336
  case CRYPT_HASH_MODE_INTERNAL:
337
- /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
338
- resultant L byte string as the actual key to HMAC."
339
-
340
- -- http://tools.ietf.org/html/rfc2104#section-2 */
341
- $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
342
-
343
- $key = str_pad($key, $this->b, chr(0)); // step 1
344
- $temp = $this->ipad ^ $key; // step 2
345
- $temp .= $text; // step 3
346
- $temp = call_user_func($this->hash, $temp); // step 4
347
- $output = $this->opad ^ $key; // step 5
348
- $output.= $temp; // step 6
349
- $output = call_user_func($this->hash, $output); // step 7
350
  }
351
  } else {
352
- switch ($mode) {
353
  case CRYPT_HASH_MODE_MHASH:
354
  $output = mhash($this->hash, $text);
355
  break;
126
  */
127
  var $key = false;
128
 
129
+ /**
130
+ * Computed Key
131
+ *
132
+ * @see self::_computeKey()
133
+ * @var string
134
+ * @access private
135
+ */
136
+ var $computedKey = false;
137
+
138
  /**
139
  * Outer XOR (Internal HMAC)
140
  *
153
  */
154
  var $ipad;
155
 
156
+ /**
157
+ * Engine
158
+ *
159
+ * @see self::setHash()
160
+ * @var string
161
+ * @access private
162
+ */
163
+ var $engine;
164
+
165
  /**
166
  * Default Constructor.
167
  *
210
  function setKey($key = false)
211
  {
212
  $this->key = $key;
213
+ $this->_computeKey();
214
+ }
215
+
216
+ /**
217
+ * Pre-compute the key used by the HMAC
218
+ *
219
+ * Quoting http://tools.ietf.org/html/rfc2104#section-2, "Applications that use keys longer than B bytes
220
+ * will first hash the key using H and then use the resultant L byte string as the actual key to HMAC."
221
+ *
222
+ * As documented in https://www.reddit.com/r/PHP/comments/9nct2l/symfonypolyfill_hash_pbkdf2_correct_fix_for/
223
+ * when doing an HMAC multiple times it's faster to compute the hash once instead of computing it during
224
+ * every call
225
+ *
226
+ * @access private
227
+ */
228
+ function _computeKey()
229
+ {
230
+ if ($this->key === false) {
231
+ $this->computedKey = false;
232
+ return;
233
+ }
234
+
235
+ if (strlen($this->key) <= $this->b) {
236
+ $this->computedKey = $this->key;
237
+ return;
238
+ }
239
+
240
+ switch ($this->engine) {
241
+ case CRYPT_HASH_MODE_MHASH:
242
+ $this->computedKey = mhash($this->hash, $this->key);
243
+ break;
244
+ case CRYPT_HASH_MODE_HASH:
245
+ $this->computedKey = hash($this->hash, $this->key, true);
246
+ break;
247
+ case CRYPT_HASH_MODE_INTERNAL:
248
+ $this->computedKey = call_user_func($this->hash, $this->key);
249
+ }
250
  }
251
 
252
  /**
297
  }
298
 
299
  switch ($hash) {
300
+ case 'md2-96':
301
+ case 'md2':
302
+ $this->b = 16;
303
+ case 'md5-96':
304
+ case 'sha1-96':
305
+ case 'sha224-96':
306
+ case 'sha256-96':
307
  case 'md2':
308
+ case 'md5':
309
+ case 'sha1':
310
+ case 'sha224':
311
+ case 'sha256':
312
+ $this->b = 64;
313
+ break;
314
+ default:
315
+ $this->b = 128;
316
+ }
317
+
318
+ switch ($hash) {
319
+ case 'md2':
320
+ $this->engine = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
321
  CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
322
  break;
323
  case 'sha384':
324
  case 'sha512':
325
+ $this->engine = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
326
  break;
327
  default:
328
+ $this->engine = CRYPT_HASH_MODE;
329
  }
330
 
331
+ switch ($this->engine) {
332
  case CRYPT_HASH_MODE_MHASH:
333
  switch ($hash) {
334
  case 'md5':
341
  default:
342
  $this->hash = MHASH_SHA1;
343
  }
344
+ $this->_computeKey();
345
  return;
346
  case CRYPT_HASH_MODE_HASH:
347
  switch ($hash) {
358
  default:
359
  $this->hash = 'sha1';
360
  }
361
+ $this->_computeKey();
362
  return;
363
  }
364
 
365
  switch ($hash) {
366
  case 'md2':
 
367
  $this->hash = array($this, '_md2');
368
  break;
369
  case 'md5':
 
370
  $this->hash = array($this, '_md5');
371
  break;
372
  case 'sha256':
 
373
  $this->hash = array($this, '_sha256');
374
  break;
375
  case 'sha384':
376
  case 'sha512':
 
377
  $this->hash = array($this, '_sha512');
378
  break;
379
  case 'sha1':
380
  default:
 
381
  $this->hash = array($this, '_sha1');
382
  }
383
 
384
  $this->ipad = str_repeat(chr(0x36), $this->b);
385
  $this->opad = str_repeat(chr(0x5C), $this->b);
386
+
387
+ $this->_computeKey();
388
  }
389
 
390
  /**
396
  */
397
  function hash($text)
398
  {
 
 
399
  if (!empty($this->key) || is_string($this->key)) {
400
+ switch ($this->engine) {
401
  case CRYPT_HASH_MODE_MHASH:
402
+ $output = mhash($this->hash, $text, $this->computedKey);
403
  break;
404
  case CRYPT_HASH_MODE_HASH:
405
+ $output = hash_hmac($this->hash, $text, $this->computedKey, true);
406
  break;
407
  case CRYPT_HASH_MODE_INTERNAL:
408
+ $key = str_pad($this->computedKey, $this->b, chr(0)); // step 1
409
+ $temp = $this->ipad ^ $key; // step 2
410
+ $temp .= $text; // step 3
411
+ $temp = call_user_func($this->hash, $temp); // step 4
412
+ $output = $this->opad ^ $key; // step 5
413
+ $output.= $temp; // step 6
414
+ $output = call_user_func($this->hash, $output); // step 7
 
 
 
 
 
 
415
  }
416
  } else {
417
+ switch ($this->engine) {
418
  case CRYPT_HASH_MODE_MHASH:
419
  $output = mhash($this->hash, $text);
420
  break;
phpseclib/Crypt/RSA.php CHANGED
@@ -1415,9 +1415,14 @@ class Crypt_RSA
1415
  xml_set_character_data_handler($xml, '_data_handler');
1416
  // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1417
  if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
 
 
1418
  return false;
1419
  }
1420
 
 
 
 
1421
  return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1422
  // from PuTTY's SSHPUBK.C
1423
  case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
@@ -2300,12 +2305,13 @@ class Crypt_RSA
2300
  return false;
2301
  }
2302
 
2303
- $result = 0;
 
2304
  for ($i = 0; $i < strlen($x); $i++) {
2305
- $result |= ord($x[$i]) ^ ord($y[$i]);
2306
  }
2307
 
2308
- return $result == 0;
2309
  }
2310
 
2311
  /**
@@ -2512,19 +2518,26 @@ class Crypt_RSA
2512
  $db = $maskedDB ^ $dbMask;
2513
  $lHash2 = substr($db, 0, $this->hLen);
2514
  $m = substr($db, $this->hLen);
2515
- if (!$this->_equals($lHash, $lHash2)) {
2516
- user_error('Decryption error');
2517
- return false;
2518
- }
2519
- $m = ltrim($m, chr(0));
2520
- if (ord($m[0]) != 1) {
 
 
 
 
 
 
 
2521
  user_error('Decryption error');
2522
  return false;
2523
  }
2524
 
2525
  // Output the message M
2526
 
2527
- return substr($m, 1);
2528
  }
2529
 
2530
  /**
1415
  xml_set_character_data_handler($xml, '_data_handler');
1416
  // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1417
  if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1418
+ xml_parser_free($xml);
1419
+ unset($xml);
1420
  return false;
1421
  }
1422
 
1423
+ xml_parser_free($xml);
1424
+ unset($xml);
1425
+
1426
  return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1427
  // from PuTTY's SSHPUBK.C
1428
  case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
2305
  return false;
2306
  }
2307
 
2308
+ $result = "\0";
2309
+ $x^= $y;
2310
  for ($i = 0; $i < strlen($x); $i++) {
2311
+ $result|= $x[$i];
2312
  }
2313
 
2314
+ return $result === "\0";
2315
  }
2316
 
2317
  /**
2518
  $db = $maskedDB ^ $dbMask;
2519
  $lHash2 = substr($db, 0, $this->hLen);
2520
  $m = substr($db, $this->hLen);
2521
+ $hashesMatch = $this->_equals($lHash, $lHash2);
2522
+ $leadingZeros = 1;
2523
+ $patternMatch = 0;
2524
+ $offset = 0;
2525
+ for ($i = 0; $i < strlen($m); $i++) {
2526
+ $patternMatch|= $leadingZeros & ($m[$i] === "\1");
2527
+ $leadingZeros&= $m[$i] === "\0";
2528
+ $offset+= $patternMatch ? 0 : 1;
2529
+ }
2530
+
2531
+ // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
2532
+ // to protect against timing attacks
2533
+ if (!$hashesMatch & !$patternMatch) {
2534
  user_error('Decryption error');
2535
  return false;
2536
  }
2537
 
2538
  // Output the message M
2539
 
2540
+ return substr($m, $offset + 1);
2541
  }
2542
 
2543
  /**
phpseclib/File/ASN1.php CHANGED
@@ -390,6 +390,9 @@ class File_ASN1
390
  $remainingLength = $length;
391
  while ($remainingLength > 0) {
392
  $temp = $this->_decode_ber($content, $start, $content_pos);
 
 
 
393
  $length = $temp['length'];
394
  // end-of-content octets - see paragraph 8.1.5
395
  if (substr($content, $content_pos + $length, 2) == "\0\0") {
@@ -441,6 +444,9 @@ class File_ASN1
441
  $current['content'] = substr($content, $content_pos);
442
  } else {
443
  $temp = $this->_decode_ber($content, $start, $content_pos);
 
 
 
444
  $length-= (strlen($content) - $content_pos);
445
  $last = count($temp) - 1;
446
  for ($i = 0; $i < $last; $i++) {
@@ -465,6 +471,9 @@ class File_ASN1
465
  $length = 0;
466
  while (substr($content, $content_pos, 2) != "\0\0") {
467
  $temp = $this->_decode_ber($content, $length + $start, $content_pos);
 
 
 
468
  $content_pos += $temp['length'];
469
  // all subtags should be octet strings
470
  //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
@@ -497,6 +506,9 @@ class File_ASN1
497
  break 2;
498
  }
499
  $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
 
 
 
500
  $content_pos += $temp['length'];
501
  $current['content'][] = $temp;
502
  $offset+= $temp['length'];
390
  $remainingLength = $length;
391
  while ($remainingLength > 0) {
392
  $temp = $this->_decode_ber($content, $start, $content_pos);
393
+ if ($temp === false) {
394
+ break;
395
+ }
396
  $length = $temp['length'];
397
  // end-of-content octets - see paragraph 8.1.5
398
  if (substr($content, $content_pos + $length, 2) == "\0\0") {
444
  $current['content'] = substr($content, $content_pos);
445
  } else {
446
  $temp = $this->_decode_ber($content, $start, $content_pos);
447
+ if ($temp === false) {
448
+ return false;
449
+ }
450
  $length-= (strlen($content) - $content_pos);
451
  $last = count($temp) - 1;
452
  for ($i = 0; $i < $last; $i++) {
471
  $length = 0;
472
  while (substr($content, $content_pos, 2) != "\0\0") {
473
  $temp = $this->_decode_ber($content, $length + $start, $content_pos);
474
+ if ($temp === false) {
475
+ return false;
476
+ }
477
  $content_pos += $temp['length'];
478
  // all subtags should be octet strings
479
  //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
506
  break 2;
507
  }
508
  $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
509
+ if ($temp === false) {
510
+ return false;
511
+ }
512
  $content_pos += $temp['length'];
513
  $current['content'][] = $temp;
514
  $offset+= $temp['length'];
phpseclib/File/X509.php CHANGED
@@ -1958,6 +1958,9 @@ class File_X509
1958
  // "Certificate Transparency"
1959
  // https://tools.ietf.org/html/rfc6962
1960
  case '1.3.6.1.4.1.11129.2.4.2':
 
 
 
1961
  return true;
1962
 
1963
  // CSR attributes
@@ -2122,7 +2125,7 @@ class File_X509
2122
  *
2123
  * If $date isn't defined it is assumed to be the current date.
2124
  *
2125
- * @param int $date optional
2126
  * @access public
2127
  */
2128
  function validateDate($date = null)
@@ -2133,7 +2136,7 @@ class File_X509
2133
 
2134
  if (!isset($date)) {
2135
  $date = class_exists('DateTime') ?
2136
- new DateTime($date, new DateTimeZone(@date_default_timezone_get())) :
2137
  time();
2138
  }
2139
 
@@ -2143,12 +2146,18 @@ class File_X509
2143
  $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
2144
  $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
2145
 
2146
- if (class_exists('DateTime')) {
2147
- $notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get()));
2148
- $notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get()));
2149
- } else {
2150
- $notBefore = @strtotime($notBefore);
2151
- $notAfter = @strtotime($notAfter);
 
 
 
 
 
 
2152
  }
2153
 
2154
  switch (true) {
@@ -2968,7 +2977,7 @@ class File_X509
2968
  }
2969
  $output.= $desc . '=' . $value;
2970
  $result[$desc] = isset($result[$desc]) ?
2971
- array_merge((array) $dn[$prop], array($value)) :
2972
  $value;
2973
  $start = false;
2974
  }
1958
  // "Certificate Transparency"
1959
  // https://tools.ietf.org/html/rfc6962
1960
  case '1.3.6.1.4.1.11129.2.4.2':
1961
+ // "Qualified Certificate statements"
1962
+ // https://tools.ietf.org/html/rfc3739#section-3.2.6
1963
+ case '1.3.6.1.5.5.7.1.3':
1964
  return true;
1965
 
1966
  // CSR attributes
2125
  *
2126
  * If $date isn't defined it is assumed to be the current date.
2127
  *
2128
+ * @param \DateTime|int|string $date optional
2129
  * @access public
2130
  */
2131
  function validateDate($date = null)
2136
 
2137
  if (!isset($date)) {
2138
  $date = class_exists('DateTime') ?
2139
+ new DateTime(null, new DateTimeZone(@date_default_timezone_get())) :
2140
  time();
2141
  }
2142
 
2146
  $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
2147
  $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
2148
 
2149
+ switch (true) {
2150
+ case is_string($date) && class_exists('DateTime'):
2151
+ $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
2152
+ case is_object($date) && strtolower(get_class($date)) == 'datetime':
2153
+ $notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get()));
2154
+ $notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get()));
2155
+ break;
2156
+ case is_string($date):
2157
+ $date = @strtotime($date);
2158
+ default:
2159
+ $notBefore = @strtotime($notBefore);
2160
+ $notAfter = @strtotime($notAfter);
2161
  }
2162
 
2163
  switch (true) {
2977
  }
2978
  $output.= $desc . '=' . $value;
2979
  $result[$desc] = isset($result[$desc]) ?
2980
+ array_merge((array) $result[$desc], array($value)) :
2981
  $value;
2982
  $start = false;
2983
  }
phpseclib/Math/BigInteger.php CHANGED
@@ -65,7 +65,6 @@
65
  * @author Jim Wigginton <terrafrost@php.net>
66
  * @copyright 2006 Jim Wigginton
67
  * @license http://www.opensource.org/licenses/mit-license.html MIT License
68
- * @link http://pear.php.net/package/Math_BigInteger
69
  */
70
 
71
  /**#@+
65
  * @author Jim Wigginton <terrafrost@php.net>
66
  * @copyright 2006 Jim Wigginton
67
  * @license http://www.opensource.org/licenses/mit-license.html MIT License
 
68
  */
69
 
70
  /**#@+
phpseclib/Net/SCP.php CHANGED
@@ -180,6 +180,11 @@ class Net_SCP
180
  return false;
181
  }
182
 
 
 
 
 
 
183
  if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
184
  return false;
185
  }
180
  return false;
181
  }
182
 
183
+ if (empty($remote_file)) {
184
+ user_error('remote_file cannot be blank', E_USER_NOTICE);
185
+ return false;
186
+ }
187
+
188
  if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
189
  return false;
190
  }
phpseclib/Net/SFTP.php CHANGED
@@ -150,11 +150,11 @@ class Net_SFTP extends Net_SSH2
150
  * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
151
  * concurrent actions, so it's somewhat academic, here.
152
  *
153
- * @var int
154
  * @see self::_send_sftp_packet()
155
  * @access private
156
  */
157
- var $request_id = false;
158
 
159
  /**
160
  * The Packet Type
@@ -291,6 +291,15 @@ class Net_SFTP extends Net_SSH2
291
  */
292
  var $canonicalize_paths = true;
293
 
 
 
 
 
 
 
 
 
 
294
  /**
295
  * Default Constructor.
296
  *
@@ -574,7 +583,7 @@ class Net_SFTP extends Net_SSH2
574
  }
575
  */
576
 
577
- $this->request_id = 1;
578
 
579
  /*
580
  A Note on SFTPv4/5/6 support:
@@ -919,7 +928,17 @@ class Net_SFTP extends Net_SSH2
919
  unset($files[$key]);
920
  continue;
921
  }
922
- if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) {
 
 
 
 
 
 
 
 
 
 
923
  $depth++;
924
  $files[$key] = $this->rawlist($dir . '/' . $key, true);
925
  $depth--;
@@ -2246,7 +2265,7 @@ class Net_SFTP extends Net_SSH2
2246
  $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
2247
 
2248
  $packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
2249
- if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
2250
  if ($fclose_check) {
2251
  fclose($fp);
2252
  }
@@ -2261,15 +2280,17 @@ class Net_SFTP extends Net_SSH2
2261
  break;
2262
  }
2263
 
 
 
2264
  $clear_responses = false;
2265
  while ($i > 0) {
2266
  $i--;
2267
 
2268
  if ($clear_responses) {
2269
- $this->_get_sftp_packet();
2270
  continue;
2271
  } else {
2272
- $response = $this->_get_sftp_packet();
2273
  }
2274
 
2275
  switch ($this->packet_type) {
@@ -2978,10 +2999,10 @@ class Net_SFTP extends Net_SSH2
2978
  * @return bool
2979
  * @access private
2980
  */
2981
- function _send_sftp_packet($type, $data)
2982
  {
2983
- $packet = $this->request_id !== false ?
2984
- pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
2985
  pack('NCa*', strlen($data) + 1, $type, $data);
2986
 
2987
  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
@@ -3019,8 +3040,15 @@ class Net_SFTP extends Net_SSH2
3019
  * @return string
3020
  * @access private
3021
  */
3022
- function _get_sftp_packet()
3023
  {
 
 
 
 
 
 
 
3024
  $this->curTimeout = false;
3025
 
3026
  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
@@ -3058,8 +3086,8 @@ class Net_SFTP extends Net_SSH2
3058
 
3059
  $this->packet_type = ord($this->_string_shift($this->packet_buffer));
3060
 
3061
- if ($this->request_id !== false) {
3062
- $this->_string_shift($this->packet_buffer, 4); // remove the request id
3063
  $length-= 5; // account for the request id and the packet type
3064
  } else {
3065
  $length-= 1; // account for the packet type
@@ -3082,6 +3110,14 @@ class Net_SFTP extends Net_SSH2
3082
  }
3083
  }
3084
 
 
 
 
 
 
 
 
 
3085
  return $packet;
3086
  }
3087
 
150
  * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
151
  * concurrent actions, so it's somewhat academic, here.
152
  *
153
+ * @var boolean
154
  * @see self::_send_sftp_packet()
155
  * @access private
156
  */
157
+ var $use_request_id = false;
158
 
159
  /**
160
  * The Packet Type
291
  */
292
  var $canonicalize_paths = true;
293
 
294
+ /**
295
+ * Request Buffers
296
+ *
297
+ * @see self::_get_sftp_packet()
298
+ * @var array
299
+ * @access private
300
+ */
301
+ var $requestBuffer = array();
302
+
303
  /**
304
  * Default Constructor.
305
  *
583
  }
584
  */
585
 
586
+ $this->use_request_id = true;
587
 
588
  /*
589
  A Note on SFTPv4/5/6 support:
928
  unset($files[$key]);
929
  continue;
930
  }
931
+ $is_directory = false;
932
+ if ($key != '.' && $key != '..') {
933
+ if ($this->use_stat_cache) {
934
+ $is_directory = is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)));
935
+ } else {
936
+ $stat = $this->lstat($dir . '/' . $key);
937
+ $is_directory = $stat && $stat['type'] === NET_SFTP_TYPE_DIRECTORY;
938
+ }
939
+ }
940
+
941
+ if ($is_directory) {
942
  $depth++;
943
  $files[$key] = $this->rawlist($dir . '/' . $key, true);
944
  $depth--;
2265
  $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
2266
 
2267
  $packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
2268
+ if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet, $i)) {
2269
  if ($fclose_check) {
2270
  fclose($fp);
2271
  }
2280
  break;
2281
  }
2282
 
2283
+ $packets_sent = $i - 1;
2284
+
2285
  $clear_responses = false;
2286
  while ($i > 0) {
2287
  $i--;
2288
 
2289
  if ($clear_responses) {
2290
+ $this->_get_sftp_packet($packets_sent - $i);
2291
  continue;
2292
  } else {
2293
+ $response = $this->_get_sftp_packet($packets_sent - $i);
2294
  }
2295
 
2296
  switch ($this->packet_type) {
2999
  * @return bool
3000
  * @access private
3001
  */
3002
+ function _send_sftp_packet($type, $data, $request_id = 1)
3003
  {
3004
+ $packet = $this->use_request_id ?
3005
+ pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) :
3006
  pack('NCa*', strlen($data) + 1, $type, $data);
3007
 
3008
  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
3040
  * @return string
3041
  * @access private
3042
  */
3043
+ function _get_sftp_packet($request_id = null)
3044
  {
3045
+ if (isset($request_id) && isset($this->requestBuffer[$request_id])) {
3046
+ $this->packet_type = $this->requestBuffer[$request_id]['packet_type'];
3047
+ $temp = $this->requestBuffer[$request_id]['packet'];
3048
+ unset($this->requestBuffer[$request_id]);
3049
+ return $temp;
3050
+ }
3051
+
3052
  $this->curTimeout = false;
3053
 
3054
  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
3086
 
3087
  $this->packet_type = ord($this->_string_shift($this->packet_buffer));
3088
 
3089
+ if ($this->use_request_id) {
3090
+ extract(unpack('Npacket_id', $this->_string_shift($this->packet_buffer, 4))); // remove the request id
3091
  $length-= 5; // account for the request id and the packet type
3092
  } else {
3093
  $length-= 1; // account for the packet type
3110
  }
3111
  }
3112
 
3113
+ if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) {
3114
+ $this->requestBuffer[$packet_id] = array(
3115
+ 'packet_type' => $this->packet_type,
3116
+ 'packet' => $packet
3117
+ );
3118
+ return $this->_get_sftp_packet($request_id);
3119
+ }
3120
+
3121
  return $packet;
3122
  }
3123
 
phpseclib/Net/SSH2.php CHANGED
@@ -96,10 +96,11 @@ define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020);
96
  * @see self::_get_channel_packet()
97
  * @access private
98
  */
99
- define('NET_SSH2_CHANNEL_EXEC', 1); // PuTTy uses 0x100
100
- define('NET_SSH2_CHANNEL_SHELL', 2);
101
- define('NET_SSH2_CHANNEL_SUBSYSTEM', 3);
102
  define('NET_SSH2_CHANNEL_AGENT_FORWARD', 4);
 
103
  /**#@-*/
104
 
105
  /**#@+
@@ -923,6 +924,22 @@ class Net_SSH2
923
  */
924
  var $binary_packet_buffer = false;
925
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926
  /**
927
  * Default Constructor.
928
  *
@@ -1159,11 +1176,12 @@ class Net_SSH2
1159
  }
1160
  $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
1161
 
1162
- $this->curTimeout-= $elapsed;
1163
-
1164
- if ($this->curTimeout <= 0) {
1165
- $this->is_timeout = true;
1166
- return false;
 
1167
  }
1168
  }
1169
 
@@ -1212,6 +1230,7 @@ class Net_SSH2
1212
  }
1213
 
1214
  if (feof($this->fsock)) {
 
1215
  user_error('Connection closed by server');
1216
  return false;
1217
  }
@@ -1223,7 +1242,7 @@ class Net_SSH2
1223
 
1224
  $this->server_identifier = trim($temp, "\r\n");
1225
  if (strlen($extra)) {
1226
- $this->errors[] = utf8_decode($extra);
1227
  }
1228
 
1229
  if (version_compare($matches[1], '1.99', '<')) {
@@ -1238,6 +1257,7 @@ class Net_SSH2
1238
  if (!$this->send_kex_first) {
1239
  $response = $this->_get_binary_packet();
1240
  if ($response === false) {
 
1241
  user_error('Connection closed by server');
1242
  return false;
1243
  }
@@ -1309,6 +1329,8 @@ class Net_SSH2
1309
  );
1310
 
1311
  static $server_host_key_algorithms = array(
 
 
1312
  'ssh-rsa', // RECOMMENDED sign Raw RSA Key
1313
  'ssh-dss' // REQUIRED sign Raw DSS Key
1314
  );
@@ -1468,6 +1490,7 @@ class Net_SSH2
1468
 
1469
  $kexinit_payload_server = $this->_get_binary_packet();
1470
  if ($kexinit_payload_server === false) {
 
1471
  user_error('Connection closed by server');
1472
  return false;
1473
  }
@@ -1595,6 +1618,7 @@ class Net_SSH2
1595
 
1596
  $response = $this->_get_binary_packet();
1597
  if ($response === false) {
 
1598
  user_error('Connection closed by server');
1599
  return false;
1600
  }
@@ -1690,12 +1714,14 @@ class Net_SSH2
1690
  $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
1691
 
1692
  if (!$this->_send_binary_packet($data)) {
 
1693
  user_error('Connection closed by server');
1694
  return false;
1695
  }
1696
 
1697
  $response = $this->_get_binary_packet();
1698
  if ($response === false) {
 
1699
  user_error('Connection closed by server');
1700
  return false;
1701
  }
@@ -1776,9 +1802,25 @@ class Net_SSH2
1776
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1777
  }
1778
 
1779
- if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
1780
- user_error('Server Host Key Algorithm Mismatch');
1781
- return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1782
  }
1783
 
1784
  $packet = pack(
@@ -1793,6 +1835,7 @@ class Net_SSH2
1793
  $response = $this->_get_binary_packet();
1794
 
1795
  if ($response === false) {
 
1796
  user_error('Connection closed by server');
1797
  return false;
1798
  }
@@ -1967,7 +2010,7 @@ class Net_SSH2
1967
 
1968
  if ($this->encrypt) {
1969
  if ($this->crypto_engine) {
1970
- $this->encrypt->setEngine($this->crypto_engine);
1971
  }
1972
  $this->encrypt->enableContinuousBuffer();
1973
  $this->encrypt->disablePadding();
@@ -1987,7 +2030,7 @@ class Net_SSH2
1987
 
1988
  if ($this->decrypt) {
1989
  if ($this->crypto_engine) {
1990
- $this->decrypt->setEngine($this->crypto_engine);
1991
  }
1992
  $this->decrypt->enableContinuousBuffer();
1993
  $this->decrypt->disablePadding();
@@ -2191,6 +2234,7 @@ class Net_SSH2
2191
  function login($username)
2192
  {
2193
  $args = func_get_args();
 
2194
  return call_user_func_array(array(&$this, '_login'), $args);
2195
  }
2196
 
@@ -2262,6 +2306,7 @@ class Net_SSH2
2262
  }
2263
  return $this->_login_helper($username, $password);
2264
  }
 
2265
  user_error('Connection closed by server');
2266
  return false;
2267
  }
@@ -2318,6 +2363,7 @@ class Net_SSH2
2318
 
2319
  $response = $this->_get_binary_packet();
2320
  if ($response === false) {
 
2321
  user_error('Connection closed by server');
2322
  return false;
2323
  }
@@ -2376,6 +2422,7 @@ class Net_SSH2
2376
 
2377
  $response = $this->_get_binary_packet();
2378
  if ($response === false) {
 
2379
  user_error('Connection closed by server');
2380
  return false;
2381
  }
@@ -2394,7 +2441,7 @@ class Net_SSH2
2394
  return false;
2395
  }
2396
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
2397
- $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length));
2398
  return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
2399
  case NET_SSH2_MSG_USERAUTH_FAILURE:
2400
  // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
@@ -2476,6 +2523,7 @@ class Net_SSH2
2476
  } else {
2477
  $orig = $response = $this->_get_binary_packet();
2478
  if ($response === false) {
 
2479
  user_error('Connection closed by server');
2480
  return false;
2481
  }
@@ -2645,6 +2693,21 @@ class Net_SSH2
2645
  $publickey['n']
2646
  );
2647
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2648
  $part1 = pack(
2649
  'CNa*Na*Na*',
2650
  NET_SSH2_MSG_USERAUTH_REQUEST,
@@ -2655,7 +2718,7 @@ class Net_SSH2
2655
  strlen('publickey'),
2656
  'publickey'
2657
  );
2658
- $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey);
2659
 
2660
  $packet = $part1 . chr(0) . $part2;
2661
  if (!$this->_send_binary_packet($packet)) {
@@ -2664,6 +2727,7 @@ class Net_SSH2
2664
 
2665
  $response = $this->_get_binary_packet();
2666
  if ($response === false) {
 
2667
  user_error('Connection closed by server');
2668
  return false;
2669
  }
@@ -2695,8 +2759,9 @@ class Net_SSH2
2695
 
2696
  $packet = $part1 . chr(1) . $part2;
2697
  $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
 
2698
  $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
2699
- $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
2700
  $packet.= pack('Na*', strlen($signature), $signature);
2701
 
2702
  if (!$this->_send_binary_packet($packet)) {
@@ -2705,6 +2770,7 @@ class Net_SSH2
2705
 
2706
  $response = $this->_get_binary_packet();
2707
  if ($response === false) {
 
2708
  user_error('Connection closed by server');
2709
  return false;
2710
  }
@@ -2831,6 +2897,7 @@ class Net_SSH2
2831
 
2832
  $response = $this->_get_binary_packet();
2833
  if ($response === false) {
 
2834
  user_error('Connection closed by server');
2835
  return false;
2836
  }
@@ -2971,6 +3038,7 @@ class Net_SSH2
2971
 
2972
  $response = $this->_get_binary_packet();
2973
  if ($response === false) {
 
2974
  user_error('Connection closed by server');
2975
  return false;
2976
  }
@@ -3285,6 +3353,66 @@ class Net_SSH2
3285
  return (bool) ($this->bitmap & NET_SSH2_MASK_LOGIN);
3286
  }
3287
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3288
  /**
3289
  * Resets a connection for re-use
3290
  *
@@ -3315,8 +3443,8 @@ class Net_SSH2
3315
  function _get_binary_packet($skip_channel_filter = false)
3316
  {
3317
  if (!is_resource($this->fsock) || feof($this->fsock)) {
3318
- user_error('Connection closed prematurely');
3319
  $this->bitmap = 0;
 
3320
  return false;
3321
  }
3322
 
@@ -3359,8 +3487,8 @@ class Net_SSH2
3359
  while ($remaining_length > 0) {
3360
  $temp = fread($this->fsock, $remaining_length);
3361
  if ($temp === false || feof($this->fsock)) {
3362
- user_error('Error reading from socket');
3363
  $this->bitmap = 0;
 
3364
  return false;
3365
  }
3366
  $buffer.= $temp;
@@ -3378,8 +3506,8 @@ class Net_SSH2
3378
  if ($this->hmac_check !== false) {
3379
  $hmac = fread($this->fsock, $this->hmac_size);
3380
  if ($hmac === false || strlen($hmac) != $this->hmac_size) {
3381
- user_error('Error reading socket');
3382
  $this->bitmap = 0;
 
3383
  return false;
3384
  } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
3385
  user_error('Invalid HMAC');
@@ -3423,7 +3551,7 @@ class Net_SSH2
3423
  return false;
3424
  }
3425
  extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
3426
- $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length));
3427
  $this->bitmap = 0;
3428
  return false;
3429
  case NET_SSH2_MSG_IGNORE:
@@ -3435,7 +3563,7 @@ class Net_SSH2
3435
  return false;
3436
  }
3437
  extract(unpack('Nlength', $this->_string_shift($payload, 4)));
3438
- $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length));
3439
  $payload = $this->_get_binary_packet($skip_channel_filter);
3440
  break;
3441
  case NET_SSH2_MSG_UNIMPLEMENTED:
@@ -3458,7 +3586,7 @@ class Net_SSH2
3458
  return false;
3459
  }
3460
  extract(unpack('Nlength', $this->_string_shift($payload, 4)));
3461
- $this->banner_message = utf8_decode($this->_string_shift($payload, $length));
3462
  $payload = $this->_get_binary_packet();
3463
  }
3464
 
@@ -3664,7 +3792,12 @@ class Net_SSH2
3664
  $response = $this->binary_packet_buffer;
3665
  $this->binary_packet_buffer = false;
3666
  } else {
3667
- if ($this->curTimeout) {
 
 
 
 
 
3668
  if ($this->curTimeout < 0) {
3669
  $this->is_timeout = true;
3670
  return true;
@@ -3687,6 +3820,7 @@ class Net_SSH2
3687
 
3688
  $response = $this->_get_binary_packet(true);
3689
  if ($response === false) {
 
3690
  user_error('Connection closed by server');
3691
  return false;
3692
  }
@@ -3695,10 +3829,6 @@ class Net_SSH2
3695
  if ($client_channel == -1 && $response === true) {
3696
  return true;
3697
  }
3698
- if (!strlen($response)) {
3699
- return '';
3700
- }
3701
-
3702
  if (!strlen($response)) {
3703
  return false;
3704
  }
@@ -3921,8 +4051,8 @@ class Net_SSH2
3921
  function _send_binary_packet($data, $logged = null)
3922
  {
3923
  if (!is_resource($this->fsock) || feof($this->fsock)) {
3924
- user_error('Connection closed prematurely');
3925
  $this->bitmap = 0;
 
3926
  return false;
3927
  }
3928
 
@@ -4583,6 +4713,8 @@ class Net_SSH2
4583
 
4584
  break;
4585
  case 'ssh-rsa':
 
 
4586
  if (strlen($server_public_host_key) < 4) {
4587
  return false;
4588
  }
@@ -4609,6 +4741,18 @@ class Net_SSH2
4609
  }
4610
 
4611
  $rsa = new Crypt_RSA();
 
 
 
 
 
 
 
 
 
 
 
 
4612
  $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
4613
  $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
4614
  if (!$rsa->verify($this->exchange_hash, $signature)) {
@@ -4637,7 +4781,30 @@ class Net_SSH2
4637
  $s = $s->modPow($e, $n);
4638
  $s = $s->toBytes();
4639
 
4640
- $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4641
  $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
4642
 
4643
  if ($s != $h) {
96
  * @see self::_get_channel_packet()
97
  * @access private
98
  */
99
+ define('NET_SSH2_CHANNEL_EXEC', 1); // PuTTy uses 0x100
100
+ define('NET_SSH2_CHANNEL_SHELL', 2);
101
+ define('NET_SSH2_CHANNEL_SUBSYSTEM', 3);
102
  define('NET_SSH2_CHANNEL_AGENT_FORWARD', 4);
103
+ define('NET_SSH2_CHANNEL_KEEP_ALIVE', 5);
104
  /**#@-*/
105
 
106
  /**#@+
924
  */
925
  var $binary_packet_buffer = false;
926
 
927
+ /**
928
+ * Preferred Signature Format
929
+ *
930
+ * @var string|false
931
+ * @access private
932
+ */
933
+ var $preferred_signature_format = false;
934
+
935
+ /**
936
+ * Authentication Credentials
937
+ *
938
+ * @var array
939
+ * @access private
940
+ */
941
+ var $auth = array();
942
+
943
  /**
944
  * Default Constructor.
945
  *
1176
  }
1177
  $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
1178
 
1179
+ if ($this->curTimeout) {
1180
+ $this->curTimeout-= $elapsed;
1181
+ if ($this->curTimeout < 0) {
1182
+ $this->is_timeout = true;
1183
+ return false;
1184
+ }
1185
  }
1186
  }
1187
 
1230
  }
1231
 
1232
  if (feof($this->fsock)) {
1233
+ $this->bitmap = 0;
1234
  user_error('Connection closed by server');
1235
  return false;
1236
  }
1242
 
1243
  $this->server_identifier = trim($temp, "\r\n");
1244
  if (strlen($extra)) {
1245
+ $this->errors[] = $extra;
1246
  }
1247
 
1248
  if (version_compare($matches[1], '1.99', '<')) {
1257
  if (!$this->send_kex_first) {
1258
  $response = $this->_get_binary_packet();
1259
  if ($response === false) {
1260
+ $this->bitmap = 0;
1261
  user_error('Connection closed by server');
1262
  return false;
1263
  }
1329
  );
1330
 
1331
  static $server_host_key_algorithms = array(
1332
+ 'rsa-sha2-256', // RFC 8332
1333
+ 'rsa-sha2-512', // RFC 8332
1334
  'ssh-rsa', // RECOMMENDED sign Raw RSA Key
1335
  'ssh-dss' // REQUIRED sign Raw DSS Key
1336
  );
1490
 
1491
  $kexinit_payload_server = $this->_get_binary_packet();
1492
  if ($kexinit_payload_server === false) {
1493
+ $this->bitmap = 0;
1494
  user_error('Connection closed by server');
1495
  return false;
1496
  }
1618
 
1619
  $response = $this->_get_binary_packet();
1620
  if ($response === false) {
1621
+ $this->bitmap = 0;
1622
  user_error('Connection closed by server');
1623
  return false;
1624
  }
1714
  $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
1715
 
1716
  if (!$this->_send_binary_packet($data)) {
1717
+ $this->bitmap = 0;
1718
  user_error('Connection closed by server');
1719
  return false;
1720
  }
1721
 
1722
  $response = $this->_get_binary_packet();
1723
  if ($response === false) {
1724
+ $this->bitmap = 0;
1725
  user_error('Connection closed by server');
1726
  return false;
1727
  }
1802
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1803
  }
1804
 
1805
+ switch ($server_host_key_algorithm) {
1806
+ case 'ssh-dss':
1807
+ $expected_key_format = 'ssh-dss';
1808
+ break;
1809
+ //case 'rsa-sha2-256':
1810
+ //case 'rsa-sha2-512':
1811
+ //case 'ssh-rsa':
1812
+ default:
1813
+ $expected_key_format = 'ssh-rsa';
1814
+ }
1815
+
1816
+ if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) {
1817
+ switch (true) {
1818
+ case $this->signature_format == $server_host_key_algorithm:
1819
+ case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512':
1820
+ case $this->signature_format != 'ssh-rsa':
1821
+ user_error('Server Host Key Algorithm Mismatch');
1822
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1823
+ }
1824
  }
1825
 
1826
  $packet = pack(
1835
  $response = $this->_get_binary_packet();
1836
 
1837
  if ($response === false) {
1838
+ $this->bitmap = 0;
1839
  user_error('Connection closed by server');
1840
  return false;
1841
  }
2010
 
2011
  if ($this->encrypt) {
2012
  if ($this->crypto_engine) {
2013
+ $this->encrypt->setPreferredEngine($this->crypto_engine);
2014
  }
2015
  $this->encrypt->enableContinuousBuffer();
2016
  $this->encrypt->disablePadding();
2030
 
2031
  if ($this->decrypt) {
2032
  if ($this->crypto_engine) {
2033
+ $this->decrypt->setPreferredEngine($this->crypto_engine);
2034
  }
2035
  $this->decrypt->enableContinuousBuffer();
2036
  $this->decrypt->disablePadding();
2234
  function login($username)
2235
  {
2236
  $args = func_get_args();
2237
+ $this->auth[] = $args;
2238
  return call_user_func_array(array(&$this, '_login'), $args);
2239
  }
2240
 
2306
  }
2307
  return $this->_login_helper($username, $password);
2308
  }
2309
+ $this->bitmap = 0;
2310
  user_error('Connection closed by server');
2311
  return false;
2312
  }
2363
 
2364
  $response = $this->_get_binary_packet();
2365
  if ($response === false) {
2366
+ $this->bitmap = 0;
2367
  user_error('Connection closed by server');
2368
  return false;
2369
  }
2422
 
2423
  $response = $this->_get_binary_packet();
2424
  if ($response === false) {
2425
+ $this->bitmap = 0;
2426
  user_error('Connection closed by server');
2427
  return false;
2428
  }
2441
  return false;
2442
  }
2443
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
2444
+ $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . $this->_string_shift($response, $length);
2445
  return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
2446
  case NET_SSH2_MSG_USERAUTH_FAILURE:
2447
  // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
2523
  } else {
2524
  $orig = $response = $this->_get_binary_packet();
2525
  if ($response === false) {
2526
+ $this->bitmap = 0;
2527
  user_error('Connection closed by server');
2528
  return false;
2529
  }
2693
  $publickey['n']
2694
  );
2695
 
2696
+ switch ($this->signature_format) {
2697
+ case 'rsa-sha2-512':
2698
+ $hash = 'sha512';
2699
+ $signatureType = 'rsa-sha2-512';
2700
+ break;
2701
+ case 'rsa-sha2-256':
2702
+ $hash = 'sha256';
2703
+ $signatureType = 'rsa-sha2-256';
2704
+ break;
2705
+ //case 'ssh-rsa':
2706
+ default:
2707
+ $hash = 'sha1';
2708
+ $signatureType = 'ssh-rsa';
2709
+ }
2710
+
2711
  $part1 = pack(
2712
  'CNa*Na*Na*',
2713
  NET_SSH2_MSG_USERAUTH_REQUEST,
2718
  strlen('publickey'),
2719
  'publickey'
2720
  );
2721
+ $part2 = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($publickey), $publickey);
2722
 
2723
  $packet = $part1 . chr(0) . $part2;
2724
  if (!$this->_send_binary_packet($packet)) {
2727
 
2728
  $response = $this->_get_binary_packet();
2729
  if ($response === false) {
2730
+ $this->bitmap = 0;
2731
  user_error('Connection closed by server');
2732
  return false;
2733
  }
2759
 
2760
  $packet = $part1 . chr(1) . $part2;
2761
  $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
2762
+ $privatekey->setHash($hash);
2763
  $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
2764
+ $signature = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($signature), $signature);
2765
  $packet.= pack('Na*', strlen($signature), $signature);
2766
 
2767
  if (!$this->_send_binary_packet($packet)) {
2770
 
2771
  $response = $this->_get_binary_packet();
2772
  if ($response === false) {
2773
+ $this->bitmap = 0;
2774
  user_error('Connection closed by server');
2775
  return false;
2776
  }
2897
 
2898
  $response = $this->_get_binary_packet();
2899
  if ($response === false) {
2900
+ $this->bitmap = 0;
2901
  user_error('Connection closed by server');
2902
  return false;
2903
  }
3038
 
3039
  $response = $this->_get_binary_packet();
3040
  if ($response === false) {
3041
+ $this->bitmap = 0;
3042
  user_error('Connection closed by server');
3043
  return false;
3044
  }
3353
  return (bool) ($this->bitmap & NET_SSH2_MASK_LOGIN);
3354
  }
3355
 
3356
+ /**
3357
+ * Pings a server connection, or tries to reconnect if the connection has gone down
3358
+ *
3359
+ * Inspired by http://php.net/manual/en/mysqli.ping.php
3360
+ *
3361
+ * @return bool
3362
+ * @access public
3363
+ */
3364
+ function ping()
3365
+ {
3366
+ if (!$this->isAuthenticated()) {
3367
+ return false;
3368
+ }
3369
+
3370
+ $this->window_size_server_to_client[NET_SSH2_CHANNEL_KEEP_ALIVE] = $this->window_size;
3371
+ $packet_size = 0x4000;
3372
+ $packet = pack(
3373
+ 'CNa*N3',
3374
+ NET_SSH2_MSG_CHANNEL_OPEN,
3375
+ strlen('session'),
3376
+ 'session',
3377
+ NET_SSH2_CHANNEL_KEEP_ALIVE,
3378
+ $this->window_size_server_to_client[NET_SSH2_CHANNEL_KEEP_ALIVE],
3379
+ $packet_size
3380
+ );
3381
+
3382
+ if (!@$this->_send_binary_packet($packet)) {
3383
+ return $this->_reconnect();
3384
+ }
3385
+
3386
+ $this->channel_status[NET_SSH2_CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN;
3387
+
3388
+ $response = @$this->_get_channel_packet(NET_SSH2_CHANNEL_KEEP_ALIVE);
3389
+ if ($response !== false) {
3390
+ $this->_close_channel(NET_SSH2_CHANNEL_KEEP_ALIVE);
3391
+ return true;
3392
+ }
3393
+
3394
+ return $this->_reconnect();
3395
+ }
3396
+
3397
+ /**
3398
+ * In situ reconnect method
3399
+ *
3400
+ * @return boolean
3401
+ * @access private
3402
+ */
3403
+ function _reconnect()
3404
+ {
3405
+ $this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
3406
+ $this->retry_connect = true;
3407
+ if (!$this->_connect()) {
3408
+ return false;
3409
+ }
3410
+ foreach ($this->auth as $auth) {
3411
+ $result = call_user_func_array(array(&$this, 'parent::login'), $auth);
3412
+ }
3413
+ return $result;
3414
+ }
3415
+
3416
  /**
3417
  * Resets a connection for re-use
3418
  *
3443
  function _get_binary_packet($skip_channel_filter = false)
3444
  {
3445
  if (!is_resource($this->fsock) || feof($this->fsock)) {
 
3446
  $this->bitmap = 0;
3447
+ user_error('Connection closed prematurely');
3448
  return false;
3449
  }
3450
 
3487
  while ($remaining_length > 0) {
3488
  $temp = fread($this->fsock, $remaining_length);
3489
  if ($temp === false || feof($this->fsock)) {
 
3490
  $this->bitmap = 0;
3491
+ user_error('Error reading from socket');
3492
  return false;
3493
  }
3494
  $buffer.= $temp;
3506
  if ($this->hmac_check !== false) {
3507
  $hmac = fread($this->fsock, $this->hmac_size);
3508
  if ($hmac === false || strlen($hmac) != $this->hmac_size) {
 
3509
  $this->bitmap = 0;
3510
+ user_error('Error reading socket');
3511
  return false;
3512
  } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
3513
  user_error('Invalid HMAC');
3551
  return false;
3552
  }
3553
  extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
3554
+ $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
3555
  $this->bitmap = 0;
3556
  return false;
3557
  case NET_SSH2_MSG_IGNORE:
3563
  return false;
3564
  }
3565
  extract(unpack('Nlength', $this->_string_shift($payload, 4)));
3566
+ $this->errors[] = 'SSH_MSG_DEBUG: ' . $this->_string_shift($payload, $length);
3567
  $payload = $this->_get_binary_packet($skip_channel_filter);
3568
  break;
3569
  case NET_SSH2_MSG_UNIMPLEMENTED:
3586
  return false;
3587
  }
3588
  extract(unpack('Nlength', $this->_string_shift($payload, 4)));
3589
+ $this->banner_message = $this->_string_shift($payload, $length);
3590
  $payload = $this->_get_binary_packet();
3591
  }
3592
 
3792
  $response = $this->binary_packet_buffer;
3793
  $this->binary_packet_buffer = false;
3794
  } else {
3795
+ $read = array($this->fsock);
3796
+ $write = $except = null;
3797
+
3798
+ if (!$this->curTimeout) {
3799
+ @stream_select($read, $write, $except, null);
3800
+ } else {
3801
  if ($this->curTimeout < 0) {
3802
  $this->is_timeout = true;
3803
  return true;
3820
 
3821
  $response = $this->_get_binary_packet(true);
3822
  if ($response === false) {
3823
+ $this->bitmap = 0;
3824
  user_error('Connection closed by server');
3825
  return false;
3826
  }
3829
  if ($client_channel == -1 && $response === true) {
3830
  return true;
3831
  }
 
 
 
 
3832
  if (!strlen($response)) {
3833
  return false;
3834
  }
4051
  function _send_binary_packet($data, $logged = null)
4052
  {
4053
  if (!is_resource($this->fsock) || feof($this->fsock)) {
 
4054
  $this->bitmap = 0;
4055
+ user_error('Connection closed prematurely');
4056
  return false;
4057
  }
4058
 
4713
 
4714
  break;
4715
  case 'ssh-rsa':
4716
+ case 'rsa-sha2-256':
4717
+ case 'rsa-sha2-512':
4718
  if (strlen($server_public_host_key) < 4) {
4719
  return false;
4720
  }
4741
  }
4742
 
4743
  $rsa = new Crypt_RSA();
4744
+ switch ($this->signature_format) {
4745
+ case 'rsa-sha2-512':
4746
+ $hash = 'sha512';
4747
+ break;
4748
+ case 'rsa-sha2-256':
4749
+ $hash = 'sha256';
4750
+ break;
4751
+ //case 'ssh-rsa':
4752
+ default:
4753
+ $hash = 'sha1';
4754
+ }
4755
+ $rsa->setHash($hash);
4756
  $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
4757
  $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
4758
  if (!$rsa->verify($this->exchange_hash, $signature)) {
4781
  $s = $s->modPow($e, $n);
4782
  $s = $s->toBytes();
4783
 
4784
+ switch ($this->signature_format) {
4785
+ case 'rsa-sha2-512':
4786
+ $hash = 'sha512';
4787
+ break;
4788
+ case 'rsa-sha2-256':
4789
+ $hash = 'sha256';
4790
+ break;
4791
+ //case 'ssh-rsa':
4792
+ default:
4793
+ $hash = 'sha1';
4794
+ }
4795
+ $hashObj = new Crypt_Hash($hash);
4796
+ switch ($this->signature_format) {
4797
+ case 'rsa-sha2-512':
4798
+ $h = pack('N5a*', 0x00305130, 0x0D060960, 0x86480165, 0x03040203, 0x05000440, $hashObj->hash($this->exchange_hash));
4799
+ break;
4800
+ case 'rsa-sha2-256':
4801
+ $h = pack('N5a*', 0x00303130, 0x0D060960, 0x86480165, 0x03040201, 0x05000420, $hashObj->hash($this->exchange_hash));
4802
+ break;
4803
+ //case 'ssh-rsa':
4804
+ default:
4805
+ $hash = 'sha1';
4806
+ $h = pack('N4a*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, $hashObj->hash($this->exchange_hash));
4807
+ }
4808
  $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
4809
 
4810
  if ($s != $h) {
phpseclib/System/SSH/Agent.php CHANGED
@@ -64,7 +64,7 @@ define('SYSTEM_SSH_AGENT_FAILURE', 5);
64
  define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
65
  // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
66
  define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
67
-
68
 
69
  /**@+
70
  * Agent forwarding status
@@ -77,7 +77,17 @@ define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
77
  define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
78
  // forwarding has been request and is active
79
  define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
 
80
 
 
 
 
 
 
 
 
 
 
81
  /**#@-*/
82
 
83
  /**
@@ -123,6 +133,16 @@ class System_SSH_Agent_Identity
123
  */
124
  var $fsock;
125
 
 
 
 
 
 
 
 
 
 
 
126
  /**
127
  * Default Constructor.
128
  *
@@ -202,6 +222,31 @@ class System_SSH_Agent_Identity
202
  {
203
  }
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  /**
206
  * Create a signature
207
  *
@@ -214,7 +259,7 @@ class System_SSH_Agent_Identity
214
  function sign($message)
215
  {
216
  // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
217
- $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
218
  $packet = pack('Na*', strlen($packet), $packet);
219
  if (strlen($packet) != fputs($this->fsock, $packet)) {
220
  user_error('Connection closed during signing');
@@ -227,9 +272,35 @@ class System_SSH_Agent_Identity
227
  }
228
 
229
  $signature_blob = fread($this->fsock, $length - 1);
230
- // the only other signature format defined - ssh-dss - is the same length as ssh-rsa
231
- // the + 12 is for the other various SSH added length fields
232
- return substr($signature_blob, strlen('ssh-rsa') + 12);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  }
234
  }
235
 
@@ -240,7 +311,7 @@ class System_SSH_Agent_Identity
240
  *
241
  * @package System_SSH_Agent
242
  * @author Jim Wigginton <terrafrost@php.net>
243
- * @access internal
244
  */
245
  class System_SSH_Agent
246
  {
@@ -281,18 +352,20 @@ class System_SSH_Agent
281
  * @return System_SSH_Agent
282
  * @access public
283
  */
284
- function __construct()
285
  {
286
- switch (true) {
287
- case isset($_SERVER['SSH_AUTH_SOCK']):
288
- $address = $_SERVER['SSH_AUTH_SOCK'];
289
- break;
290
- case isset($_ENV['SSH_AUTH_SOCK']):
291
- $address = $_ENV['SSH_AUTH_SOCK'];
292
- break;
293
- default:
294
- user_error('SSH_AUTH_SOCK not found');
295
- return false;
 
 
296
  }
297
 
298
  $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
@@ -307,9 +380,9 @@ class System_SSH_Agent
307
  * @see self::__construct()
308
  * @access public
309
  */
310
- function System_SSH_Agent()
311
  {
312
- $this->__construct();
313
  }
314
 
315
  /**
@@ -330,12 +403,14 @@ class System_SSH_Agent
330
  $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
331
  if (strlen($packet) != fputs($this->fsock, $packet)) {
332
  user_error('Connection closed while requesting identities');
 
333
  }
334
 
335
  $length = current(unpack('N', fread($this->fsock, 4)));
336
  $type = ord(fread($this->fsock, 1));
337
  if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
338
  user_error('Unable to request identities');
 
339
  }
340
 
341
  $identities = array();
64
  define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
65
  // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
66
  define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
67
+ /**#@-*/
68
 
69
  /**@+
70
  * Agent forwarding status
77
  define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
78
  // forwarding has been request and is active
79
  define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
80
+ /**#@-*/
81
 
82
+ /**@+
83
+ * Signature Flags
84
+ *
85
+ * See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3
86
+ *
87
+ * @access private
88
+ */
89
+ define('SYSTEM_SSH_AGENT_RSA2_256', 2);
90
+ define('SYSTEM_SSH_AGENT_RSA2_512', 4);
91
  /**#@-*/
92
 
93
  /**
133
  */
134
  var $fsock;
135
 
136
+ /**
137
+ * Signature flags
138
+ *
139
+ * @var int
140
+ * @access private
141
+ * @see self::sign()
142
+ * @see self::setHash()
143
+ */
144
+ var $flags = 0;
145
+
146
  /**
147
  * Default Constructor.
148
  *
222
  {
223
  }
224
 
225
+ /**
226
+ * Set Hash
227
+ *
228
+ * ssh-agent doesn't support using hashes for RSA other than SHA1
229
+ *
230
+ * @param string $hash
231
+ * @access public
232
+ */
233
+ function setHash($hash)
234
+ {
235
+ $this->flags = 0;
236
+ switch ($hash) {
237
+ case 'sha1':
238
+ break;
239
+ case 'sha256':
240
+ $this->flags = SYSTEM_SSH_AGENT_RSA2_256;
241
+ break;
242
+ case 'sha512':
243
+ $this->flags = SYSTEM_SSH_AGENT_RSA2_512;
244
+ break;
245
+ default:
246
+ user_error('The only supported hashes for RSA are sha1, sha256 and sha512');
247
+ }
248
+ }
249
+
250
  /**
251
  * Create a signature
252
  *
259
  function sign($message)
260
  {
261
  // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
262
+ $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, $this->flags);
263
  $packet = pack('Na*', strlen($packet), $packet);
264
  if (strlen($packet) != fputs($this->fsock, $packet)) {
265
  user_error('Connection closed during signing');
272
  }
273
 
274
  $signature_blob = fread($this->fsock, $length - 1);
275
+ $length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
276
+ if ($length != strlen($signature_blob)) {
277
+ user_error('Malformed signature blob');
278
+ }
279
+ $length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
280
+ if ($length > strlen($signature_blob) + 4) {
281
+ user_error('Malformed signature blob');
282
+ }
283
+ $type = $this->_string_shift($signature_blob, $length);
284
+ $this->_string_shift($signature_blob, 4);
285
+
286
+ return $signature_blob;
287
+ }
288
+
289
+ /**
290
+ * String Shift
291
+ *
292
+ * Inspired by array_shift
293
+ *
294
+ * @param string $string
295
+ * @param int $index
296
+ * @return string
297
+ * @access private
298
+ */
299
+ function _string_shift(&$string, $index = 1)
300
+ {
301
+ $substr = substr($string, 0, $index);
302
+ $string = substr($string, $index);
303
+ return $substr;
304
  }
305
  }
306
 
311
  *
312
  * @package System_SSH_Agent
313
  * @author Jim Wigginton <terrafrost@php.net>
314
+ * @access public
315
  */
316
  class System_SSH_Agent
317
  {
352
  * @return System_SSH_Agent
353
  * @access public
354
  */
355
+ function __construct($address = null)
356
  {
357
+ if (!$address) {
358
+ switch (true) {
359
+ case isset($_SERVER['SSH_AUTH_SOCK']):
360
+ $address = $_SERVER['SSH_AUTH_SOCK'];
361
+ break;
362
+ case isset($_ENV['SSH_AUTH_SOCK']):
363
+ $address = $_ENV['SSH_AUTH_SOCK'];
364
+ break;
365
+ default:
366
+ user_error('SSH_AUTH_SOCK not found');
367
+ return false;
368
+ }
369
  }
370
 
371
  $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
380
  * @see self::__construct()
381
  * @access public
382
  */
383
+ function System_SSH_Agent($address = null)
384
  {
385
+ $this->__construct($address);
386
  }
387
 
388
  /**
403
  $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
404
  if (strlen($packet) != fputs($this->fsock, $packet)) {
405
  user_error('Connection closed while requesting identities');
406
+ return array();
407
  }
408
 
409
  $length = current(unpack('N', fread($this->fsock, 4)));
410
  $type = ord(fread($this->fsock, 1));
411
  if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
412
  user_error('Unable to request identities');
413
+ return array();
414
  }
415
 
416
  $identities = array();
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: DavidAnderson, TerraFrost, pmbaldha
3
  Donate link: http://sourceforge.net/donate/index.php?group_id=198487
4
  Tags: ssh, sftp
5
  Requires at least: 3.1
6
- Tested up to: 5.0
7
- Stable tag: 0.8.0
8
 
9
  "SSH SFTP Updater Support" is the easiest way to keep your Wordpress installation up-to-date with SFTP.
10
 
@@ -41,6 +41,10 @@ b) Others as <a href="https://codex.wordpress.org/Editing_wp-config.php#WordPres
41
 
42
  == Changelog ==
43
 
 
 
 
 
44
  = 0.8.0 - 2018/Dec/14 =
45
 
46
  * TWEAK: Replaced the deprecated 'var' visibility indicator
@@ -108,4 +112,4 @@ b) Others as <a href="https://codex.wordpress.org/Editing_wp-config.php#WordPres
108
  * Initial Release
109
 
110
  == Upgrade Notice ==
111
- * 0.8.0 : Better handle calls from other plugins (etc.) that don't check for error conditions
3
  Donate link: http://sourceforge.net/donate/index.php?group_id=198487
4
  Tags: ssh, sftp
5
  Requires at least: 3.1
6
+ Tested up to: 5.2
7
+ Stable tag: 0.8.1
8
 
9
  "SSH SFTP Updater Support" is the easiest way to keep your Wordpress installation up-to-date with SFTP.
10
 
41
 
42
  == Changelog ==
43
 
44
+ = 0.8.1 - 2019/Apr/13 =
45
+
46
+ * TWEAK: Don't require phpseclib classes if they already exist
47
+
48
  = 0.8.0 - 2018/Dec/14 =
49
 
50
  * TWEAK: Replaced the deprecated 'var' visibility indicator
112
  * Initial Release
113
 
114
  == Upgrade Notice ==
115
+ * 0.8.1 : Don't require phpseclib classes if they already exist
sftp.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: SSH SFTP Updater Support
4
  Plugin URI: https://wordpress.org/plugins/ssh-sftp-updater-support/
5
  Description: Update your WordPress blog / plugins via SFTP without libssh2
6
- Version: 0.8.0
7
  Author: TerraFrost, David Anderson + Team Updraft
8
  Author URI: https://updraftplus.com/
9
  */
@@ -12,7 +12,7 @@ if (!defined('ABSPATH')) die('No direct access allowed');
12
 
13
  define('SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH', plugin_dir_path(__FILE__));
14
  define('SSH_SFTP_UPDATER_SUPPORT_BASENAME', plugin_basename(__FILE__));
15
- define('SSH_SFTP_UPDATER_SUPPORT_VERSION', '0.8.0');
16
  define('SSH_SFTP_UPDATER_SUPPORT_URL', plugin_dir_url(__FILE__));
17
  // see http://adambrown.info/p/wp_hooks/hook/<filter name>
18
  add_filter('filesystem_method', 'phpseclib_filesystem_method', 10, 2); // since 2.6 - WordPress will ignore the ssh option if the php ssh extension is not loaded
3
  Plugin Name: SSH SFTP Updater Support
4
  Plugin URI: https://wordpress.org/plugins/ssh-sftp-updater-support/
5
  Description: Update your WordPress blog / plugins via SFTP without libssh2
6
+ Version: 0.8.1
7
  Author: TerraFrost, David Anderson + Team Updraft
8
  Author URI: https://updraftplus.com/
9
  */
12
 
13
  define('SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH', plugin_dir_path(__FILE__));
14
  define('SSH_SFTP_UPDATER_SUPPORT_BASENAME', plugin_basename(__FILE__));
15
+ define('SSH_SFTP_UPDATER_SUPPORT_VERSION', '0.8.1');
16
  define('SSH_SFTP_UPDATER_SUPPORT_URL', plugin_dir_url(__FILE__));
17
  // see http://adambrown.info/p/wp_hooks/hook/<filter name>
18
  add_filter('filesystem_method', 'phpseclib_filesystem_method', 10, 2); // since 2.6 - WordPress will ignore the ssh option if the php ssh extension is not loaded