From 9aa9b66fbee188cbbe4dd05d3e99047b3ecc4c3c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 16 Dec 2015 22:53:59 +0100 Subject: [PATCH 1/4] do not ship with a custom rng implementation --- composer.json | 1 + .../Security/Core/Util/SecureRandom.php | 87 +------------------ .../Component/Security/Core/composer.json | 3 +- src/Symfony/Component/Security/composer.json | 3 +- 4 files changed, 6 insertions(+), 88 deletions(-) diff --git a/composer.json b/composer.json index 5f5fc25255bfa..46d4392577bbc 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "require": { "php": ">=5.3.3", "doctrine/common": "~2.3", + "paragonie/random_compat": "~1.0", "twig/twig": "~1.12,>=1.12.3", "psr/log": "~1.0" }, diff --git a/src/Symfony/Component/Security/Core/Util/SecureRandom.php b/src/Symfony/Component/Security/Core/Util/SecureRandom.php index c0924df61f1f0..478f556f1bb72 100644 --- a/src/Symfony/Component/Security/Core/Util/SecureRandom.php +++ b/src/Symfony/Component/Security/Core/Util/SecureRandom.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Security\Core\Util; -use Psr\Log\LoggerInterface; - /** * A secure random number generator implementation. * @@ -21,94 +19,11 @@ */ final class SecureRandom implements SecureRandomInterface { - private $logger; - private $useOpenSsl; - private $seed; - private $seedUpdated; - private $seedLastUpdatedAt; - private $seedFile; - - /** - * Constructor. - * - * Be aware that a guessable seed will severely compromise the PRNG - * algorithm that is employed. - * - * @param string $seedFile - * @param LoggerInterface $logger - */ - public function __construct($seedFile = null, LoggerInterface $logger = null) - { - $this->seedFile = $seedFile; - $this->logger = $logger; - - // determine whether to use OpenSSL - if ('\\' === DIRECTORY_SEPARATOR && PHP_VERSION_ID < 50304) { - $this->useOpenSsl = false; - } elseif (!function_exists('openssl_random_pseudo_bytes')) { - if (null !== $this->logger) { - $this->logger->notice('It is recommended that you enable the "openssl" extension for random number generation.'); - } - $this->useOpenSsl = false; - } else { - $this->useOpenSsl = true; - } - } - /** * {@inheritdoc} */ public function nextBytes($nbBytes) { - // try OpenSSL - if ($this->useOpenSsl) { - $bytes = openssl_random_pseudo_bytes($nbBytes, $strong); - - if (false !== $bytes && true === $strong) { - return $bytes; - } - - if (null !== $this->logger) { - $this->logger->info('OpenSSL did not produce a secure random number.'); - } - } - - // initialize seed - if (null === $this->seed) { - if (null === $this->seedFile) { - throw new \RuntimeException('You need to specify a file path to store the seed.'); - } - - if (is_file($this->seedFile)) { - list($this->seed, $this->seedLastUpdatedAt) = $this->readSeed(); - } else { - $this->seed = uniqid(mt_rand(), true); - $this->updateSeed(); - } - } - - $bytes = ''; - while (strlen($bytes) < $nbBytes) { - static $incr = 1; - $bytes .= hash('sha512', $incr++.$this->seed.uniqid(mt_rand(), true).$nbBytes, true); - $this->seed = base64_encode(hash('sha512', $this->seed.$bytes.$nbBytes, true)); - $this->updateSeed(); - } - - return substr($bytes, 0, $nbBytes); - } - - private function readSeed() - { - return json_decode(file_get_contents($this->seedFile)); - } - - private function updateSeed() - { - if (!$this->seedUpdated && $this->seedLastUpdatedAt < time() - mt_rand(1, 10)) { - file_put_contents($this->seedFile, json_encode(array($this->seed, microtime(true)))); - } - - $this->seedUpdated = true; + return random_bytes($nbBytes); } } diff --git a/src/Symfony/Component/Security/Core/composer.json b/src/Symfony/Component/Security/Core/composer.json index 7bc1bf03ac596..226e8439208c8 100644 --- a/src/Symfony/Component/Security/Core/composer.json +++ b/src/Symfony/Component/Security/Core/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "paragonie/random_compat": "~1.0" }, "require-dev": { "symfony/phpunit-bridge": "~2.7", diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json index 1705183cd47d4..9506eab66c0eb 100644 --- a/src/Symfony/Component/Security/composer.json +++ b/src/Symfony/Component/Security/composer.json @@ -19,7 +19,8 @@ "php": ">=5.3.3", "symfony/event-dispatcher": "~2.2", "symfony/http-foundation": "~2.1", - "symfony/http-kernel": "~2.4" + "symfony/http-kernel": "~2.4", + "paragonie/random_compat": "~1.0" }, "replace": { "symfony/security-acl": "self.version", From e05da262eb963da58d9a803277b82a3e902e5fb5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 14 Jan 2016 09:48:01 +0100 Subject: [PATCH 2/4] removed obsolete tests, fixed composer.json --- .../Core/Tests/Util/SecureRandomTest.php | 201 ------------------ src/Symfony/Component/Security/composer.json | 4 +- 2 files changed, 2 insertions(+), 203 deletions(-) delete mode 100644 src/Symfony/Component/Security/Core/Tests/Util/SecureRandomTest.php diff --git a/src/Symfony/Component/Security/Core/Tests/Util/SecureRandomTest.php b/src/Symfony/Component/Security/Core/Tests/Util/SecureRandomTest.php deleted file mode 100644 index 2e94cc14badd0..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Util/SecureRandomTest.php +++ /dev/null @@ -1,201 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Util; - -use Symfony\Component\Security\Core\Util\SecureRandom; - -class SecureRandomTest extends \PHPUnit_Framework_TestCase -{ - /** - * T1: Monobit test. - * - * @dataProvider getSecureRandoms - */ - public function testMonobit($secureRandom) - { - $nbOnBits = substr_count($this->getBitSequence($secureRandom, 20000), '1'); - $this->assertTrue($nbOnBits > 9654 && $nbOnBits < 10346, 'Monobit test failed, number of turned on bits: '.$nbOnBits); - } - - /** - * T2: Chi-square test with 15 degrees of freedom (chi-Quadrat-Anpassungstest). - * - * @dataProvider getSecureRandoms - */ - public function testPoker($secureRandom) - { - $b = $this->getBitSequence($secureRandom, 20000); - $c = array(); - for ($i = 0; $i <= 15; ++$i) { - $c[$i] = 0; - } - - for ($j = 1; $j <= 5000; ++$j) { - $k = 4 * $j - 1; - ++$c[8 * $b[$k - 3] + 4 * $b[$k - 2] + 2 * $b[$k - 1] + $b[$k]]; - } - - $f = 0; - for ($i = 0; $i <= 15; ++$i) { - $f += $c[$i] * $c[$i]; - } - - $Y = 16 / 5000 * $f - 5000; - - $this->assertTrue($Y > 1.03 && $Y < 57.4, 'Poker test failed, Y = '.$Y); - } - - /** - * Run test. - * - * @dataProvider getSecureRandoms - */ - public function testRun($secureRandom) - { - $b = $this->getBitSequence($secureRandom, 20000); - - $runs = array(); - for ($i = 1; $i <= 6; ++$i) { - $runs[$i] = 0; - } - - $addRun = function ($run) use (&$runs) { - if ($run > 6) { - $run = 6; - } - - ++$runs[$run]; - }; - - $currentRun = 0; - $lastBit = null; - for ($i = 0; $i < 20000; ++$i) { - if ($lastBit === $b[$i]) { - ++$currentRun; - } else { - if ($currentRun > 0) { - $addRun($currentRun); - } - - $lastBit = $b[$i]; - $currentRun = 0; - } - } - if ($currentRun > 0) { - $addRun($currentRun); - } - - $this->assertTrue($runs[1] > 2267 && $runs[1] < 2733, 'Runs of length 1 outside of defined interval: '.$runs[1]); - $this->assertTrue($runs[2] > 1079 && $runs[2] < 1421, 'Runs of length 2 outside of defined interval: '.$runs[2]); - $this->assertTrue($runs[3] > 502 && $runs[3] < 748, 'Runs of length 3 outside of defined interval: '.$runs[3]); - $this->assertTrue($runs[4] > 233 && $runs[4] < 402, 'Runs of length 4 outside of defined interval: '.$runs[4]); - $this->assertTrue($runs[5] > 90 && $runs[5] < 223, 'Runs of length 5 outside of defined interval: '.$runs[5]); - $this->assertTrue($runs[6] > 90 && $runs[6] < 233, 'Runs of length 6 outside of defined interval: '.$runs[6]); - } - - /** - * Long-run test. - * - * @dataProvider getSecureRandoms - */ - public function testLongRun($secureRandom) - { - $b = $this->getBitSequence($secureRandom, 20000); - - $longestRun = $currentRun = 0; - $lastBit = null; - for ($i = 0; $i < 20000; ++$i) { - if ($lastBit === $b[$i]) { - ++$currentRun; - } else { - if ($currentRun > $longestRun) { - $longestRun = $currentRun; - } - $lastBit = $b[$i]; - $currentRun = 0; - } - } - if ($currentRun > $longestRun) { - $longestRun = $currentRun; - } - - $this->assertTrue($longestRun < 34, 'Failed longest run test: '.$longestRun); - } - - /** - * Serial Correlation (Autokorrelationstest). - * - * @dataProvider getSecureRandoms - */ - public function testSerialCorrelation($secureRandom) - { - $shift = mt_rand(1, 5000); - $b = $this->getBitSequence($secureRandom, 20000); - - $Z = 0; - for ($i = 0; $i < 5000; ++$i) { - $Z += $b[$i] === $b[$i + $shift] ? 1 : 0; - } - - $this->assertTrue($Z > 2326 && $Z < 2674, 'Failed serial correlation test: '.$Z); - } - - public function getSecureRandoms() - { - $secureRandoms = array(); - - // only add if openssl is indeed present - $secureRandom = new SecureRandom(); - if ($this->hasOpenSsl($secureRandom)) { - $secureRandoms[] = array($secureRandom); - } - - // no-openssl with custom seed provider - $secureRandom = new SecureRandom(sys_get_temp_dir().'/_sf2.seed'); - $this->disableOpenSsl($secureRandom); - $secureRandoms[] = array($secureRandom); - - return $secureRandoms; - } - - protected function disableOpenSsl($secureRandom) - { - $ref = new \ReflectionProperty($secureRandom, 'useOpenSsl'); - $ref->setAccessible(true); - $ref->setValue($secureRandom, false); - $ref->setAccessible(false); - } - - protected function hasOpenSsl($secureRandom) - { - $ref = new \ReflectionProperty($secureRandom, 'useOpenSsl'); - $ref->setAccessible(true); - - $ret = $ref->getValue($secureRandom); - - $ref->setAccessible(false); - - return $ret; - } - - private function getBitSequence($secureRandom, $length) - { - $bitSequence = ''; - for ($i = 0; $i < $length; $i += 40) { - $value = unpack('H*', $secureRandom->nextBytes(5)); - $value = str_pad(base_convert($value[1], 16, 2), 40, '0', STR_PAD_LEFT); - $bitSequence .= $value; - } - - return substr($bitSequence, 0, $length); - } -} diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json index 9506eab66c0eb..0f5d293a4f998 100644 --- a/src/Symfony/Component/Security/composer.json +++ b/src/Symfony/Component/Security/composer.json @@ -17,10 +17,10 @@ ], "require": { "php": ">=5.3.3", + "paragonie/random_compat": "~1.0", "symfony/event-dispatcher": "~2.2", "symfony/http-foundation": "~2.1", - "symfony/http-kernel": "~2.4", - "paragonie/random_compat": "~1.0" + "symfony/http-kernel": "~2.4" }, "replace": { "symfony/security-acl": "self.version", From a0c98d400ac15e5cf5da897e1651cd584b59acda Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 14 Jan 2016 11:06:21 +0100 Subject: [PATCH 3/4] updated CHANGELOG for 2.6.13 --- CHANGELOG-2.6.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG-2.6.md b/CHANGELOG-2.6.md index cfaaa4c9027a2..28ba1f65df391 100644 --- a/CHANGELOG-2.6.md +++ b/CHANGELOG-2.6.md @@ -7,6 +7,10 @@ in 2.6 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.6.0...v2.6.1 +* 2.6.13 (2016-01-14) + + * security #17359 do not ship with a custom rng implementation (xabbuh, fabpot) + * 2.6.12 (2015-11-23) * security #16631 CVE-2015-8124: Session Fixation in the "Remember Me" Login Feature (xabbuh) From a651f54c9f1bfa026631193aa8aa41c737d7d123 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 14 Jan 2016 11:11:16 +0100 Subject: [PATCH 4/4] updated VERSION for 2.6.13 --- src/Symfony/Component/HttpKernel/Kernel.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 52a89dd2822d1..766e840e37a75 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -60,11 +60,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.6.12'; - const VERSION_ID = '20612'; + const VERSION = '2.6.13'; + const VERSION_ID = '20613'; const MAJOR_VERSION = '2'; const MINOR_VERSION = '6'; - const RELEASE_VERSION = '12'; + const RELEASE_VERSION = '13'; const EXTRA_VERSION = ''; /**