Commit 2bccef8b authored by alexpott's avatar alexpott

Issue #2763787 by pwolanin, nerdstein, rlhawk, YesCT, slasher13, tuutti,...

Issue #2763787 by pwolanin, nerdstein, rlhawk, YesCT, slasher13, tuutti, alexpott, therealssj, TravisCarden, dawehner, maximpodorov, klausi, catch, talhaparacha, Eric_A: Upgrade random_compat to latest version
parent c225f3b9
......@@ -999,16 +999,16 @@
},
{
"name": "paragonie/random_compat",
"version": "1.1.1",
"version": "v2.0.2",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "a208865a5aeffc2dbbef2a5b3409887272d93f32"
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/a208865a5aeffc2dbbef2a5b3409887272d93f32",
"reference": "a208865a5aeffc2dbbef2a5b3409887272d93f32",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
"shasum": ""
},
"require": {
......@@ -1043,7 +1043,7 @@
"pseudorandom",
"random"
],
"time": "2015-12-01 02:52:15"
"time": "2016-04-03 06:00:07"
},
{
"name": "psr/http-message",
......
......@@ -31,7 +31,7 @@
"symfony/psr-http-message-bridge": "v0.2",
"zendframework/zend-diactoros": "~1.1",
"composer/semver": "~1.0",
"paragonie/random_compat": "~1.0",
"paragonie/random_compat": "^1.0|^2.0",
"asm89/stack-cors": "~1.0"
},
"require-dev": {
......
......@@ -19,7 +19,8 @@ class Crypt {
*
* In PHP 7 and up, this uses the built-in PHP function random_bytes().
* In older PHP versions, this uses the random_bytes() function provided by
* the random_compat library.
* the random_compat library, or the fallback hash-based generator from Drupal
* 7.x.
*
* @param int $count
* The number of characters (bytes) to return in the string.
......@@ -28,7 +29,43 @@ class Crypt {
* A randomly generated string.
*/
public static function randomBytes($count) {
return random_bytes($count);
try {
return random_bytes($count);
}
catch (\Exception $e) {
// $random_state does not use drupal_static as it stores random bytes.
static $random_state, $bytes;
// If the compatibility library fails, this simple hash-based PRNG will
// generate a good set of pseudo-random bytes on any system.
// Note that it may be important that our $random_state is passed
// through hash() prior to being rolled into $output, that the two hash()
// invocations are different, and that the extra input into the first one
// - the microtime() - is prepended rather than appended. This is to avoid
// directly leaking $random_state via the $output stream, which could
// allow for trivial prediction of further "random" numbers.
if (strlen($bytes) < $count) {
// Initialize on the first call. The $_SERVER variable includes user and
// system-specific information that varies a little with each page.
if (!isset($random_state)) {
$random_state = print_r($_SERVER, TRUE);
if (function_exists('getmypid')) {
// Further initialize with the somewhat random PHP process ID.
$random_state .= getmypid();
}
$bytes = '';
// Ensure mt_rand() is reseeded before calling it the first time.
mt_srand();
}
do {
$random_state = hash('sha256', microtime() . mt_rand() . $random_state);
$bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
} while (strlen($bytes) < $count);
}
$output = substr($bytes, 0, $count);
$bytes = substr($bytes, $count);
return $output;
}
}
/**
......
......@@ -6,7 +6,7 @@
"license": "GPL-2.0+",
"require": {
"php": ">=5.5.9",
"paragonie/random_compat": "~1.0",
"paragonie/random_compat": "^1.0|^2.0",
"drupal/core-render": "~8.2"
},
"autoload": {
......
......@@ -257,6 +257,44 @@ function system_requirements($phase) {
$requirements['php_opcache']['title'] = t('PHP OPcode caching');
}
if ($phase != 'update') {
// Test whether we have a good source of random bytes.
$requirements['php_random_bytes'] = array(
'title' => t('Random number generation'),
);
try {
$bytes = random_bytes(10);
if (strlen($bytes) != 10) {
throw new \Exception(t('Tried to generate 10 random bytes, generated @count', array('@count' => strlen($bytes))));
}
$requirements['php_random_bytes']['value'] = t('Successful');
}
catch (\Exception $e) {
// If /dev/urandom is not available on a UNIX-like system, check whether
// open_basedir restrictions are the cause.
$open_basedir_blocks_urandom = FALSE;
if (DIRECTORY_SEPARATOR === '/' && !@is_readable('/dev/urandom')) {
$open_basedir = ini_get('open_basedir');
if ($open_basedir) {
$open_basedir_paths = explode(PATH_SEPARATOR, $open_basedir);
$open_basedir_blocks_urandom = !array_intersect(array('/dev', '/dev/', '/dev/urandom'), $open_basedir_paths);
}
}
$args = array(
':drupal-php' => 'https://www.drupal.org/docs/7/system-requirements/php#csprng',
'%exception_message' => $e->getMessage(),
);
if ($open_basedir_blocks_urandom) {
$requirements['php_random_bytes']['description'] = t('Drupal is unable to generate highly randomized numbers, which means certain security features like password reset URLs are not as secure as they should be. Instead, only a slow, less-secure fallback generator is available. The most likely cause is that open_basedir restrictions are in effect and /dev/urandom is not on the whitelist. See the <a href=":drupal-php">system requirements</a> page for more information. %exception_message', $args);
}
else {
$requirements['php_random_bytes']['description'] = t('Drupal is unable to generate highly randomized numbers, which means certain security features like password reset URLs are not as secure as they should be. Instead, only a slow, less-secure fallback generator is available. See the <a href=":drupal-php">system requirements</a> page for more information. %exception_message', $args);
}
$requirements['php_random_bytes']['value'] = t('Less secure');
$requirements['php_random_bytes']['severity'] = REQUIREMENT_ERROR;
}
}
if ($phase == 'install' || $phase == 'update') {
// Test for PDO (database).
$requirements['database_extensions'] = array(
......
<?php
namespace Drupal\Tests\Component\Utility;
use Drupal\Tests\UnitTestCase;
use Drupal\Component\Utility\Crypt;
/**
* Tests random byte generation fallback exception situations.
*
* @group Utility
*
* @runTestsInSeparateProcesses
*
* @coversDefaultClass \Drupal\Component\Utility\Crypt
*/
class CryptRandomFallbackTest extends UnitTestCase {
static protected $functionCalled = 0;
/**
* Allows the test to confirm that the namespaced random_bytes() was called.
*/
public static function functionCalled() {
static::$functionCalled++;
}
/**
* Tests random byte generation using the fallback generator.
*
* If the call to random_bytes() throws an exception, Crypt::random_bytes()
* should still return a useful string of random bytes.
*
* @covers ::randomBytes
*
* @see \Drupal\Tests\Component\Utility\CryptTest::testRandomBytes()
*/
public function testRandomBytesFallback() {
// This loop is a copy of
// \Drupal\Tests\Component\Utility\CryptTest::testRandomBytes().
for ($i = 0; $i < 10; $i++) {
$count = rand(10, 10000);
// Check that different values are being generated.
$this->assertNotEquals(Crypt::randomBytes($count), Crypt::randomBytes($count));
// Check the length.
$this->assertEquals($count, strlen(Crypt::randomBytes($count)));
}
$this->assertEquals(30, static::$functionCalled, 'The namespaced function was called the expected number of times.');
}
}
namespace Drupal\Component\Utility;
use \Drupal\Tests\Component\Utility\CryptRandomFallbackTest;
/**
* Defines a function in same namespace as Drupal\Component\Utility\Crypt.
*
* Forces throwing an exception in this test environment because the function
* in the namespace is used in preference to the global function.
*
* @param int $count
* Matches the global function definition.
*
* @throws \Exception
*/
function random_bytes($count) {
CryptRandomFallbackTest::functionCalled();
throw new \Exception($count);
}
......@@ -18,6 +18,8 @@ class CryptTest extends UnitTestCase {
* Tests random byte generation.
*
* @covers ::randomBytes
*
* @see \Drupal\Tests\Component\Utility\CryptRandomFallbackTest::testRandomBytesFallback
*/
public function testRandomBytes() {
for ($i = 1; $i < 10; $i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment