Merge branch 'MDL-55404-master' of git://github.com/cameron1729/moodle

This commit is contained in:
Dan Poltawski 2016-10-04 18:23:36 +01:00
commit 6658ef6cd9
6 changed files with 338 additions and 0 deletions

View File

@ -1846,6 +1846,11 @@
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_tls_libraries" level="optional">
<FEEDBACK>
<ON_CHECK message="tlswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>

View File

@ -1080,6 +1080,7 @@ $string['timezoneisforcedto'] = 'Force all users to use';
$string['timezonenotforced'] = 'Users can choose their own timezone';
$string['timezonephpdefault'] = 'Default PHP timezone ({$a})';
$string['timezoneserver'] = 'Server timezone ({$a})';
$string['tlswarning'] = 'No PHP/cURL extension with TLSv1.2 support has been detected. Some services may not work. It is strongly recommentd that you upgrade your TLS libraries.';
$string['tokenizerrecommended'] = 'Installing the optional PHP Tokenizer extension is recommended -- it improves Moodle Networking functionality.';
$string['tools'] = 'Admin tools';
$string['toolsmanage'] = 'Manage admin tools';

View File

@ -0,0 +1,115 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* PayPal enrolment plugin utility class.
*
* @package core
* @copyright 2016 Cameron Ball <cameron@cameron1729.xyz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\upgrade;
defined('MOODLE_INTERNAL') || die();
/**
* Core upgrade utility class.
*
* @package core
* @copyright 2016 Cameron Ball <cameron@cameron1729.xyz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class util {
/**
* Gets the minimum version of a SSL/TLS library required for TLS 1.2 support.
*
* @param string $sslflavour The SSL/TLS library
* @return string|false The version string if it exists. False otherwise
*/
private static function get_min_ssl_lib_version_for_tls12($sslflavour) {
// Min versions for TLS 1.2.
$versionmatrix = [
'OpenSSL' => '1.0.1c',
'GnuTLS' => '1.7.1',
'NSS' => '3.15.1', // This number is usually followed by something like "Basic ECC".
'CyaSSL' => '1.1.0',
'wolfSSL' => '1.1.0',
'PolarSSL' => '1.2.0',
'WinSSL' => '*', // Does not specify a version but needs Windows >= 7.
'SecureTransport' => '*' // Does not specify a version but needs iOS >= 5.0 or OS X >= 10.8.0.
];
return isset($versionmatrix[$sslflavour]) ? $versionmatrix[$sslflavour] : false;
}
/**
* Validates PHP/cURL extension for use with SSL/TLS.
*
* @param array $curlinfo array of cURL information as returned by curl_version()
* @param int $zts 0 or 1 as defined by PHP_ZTS
* @return bool
*/
public static function validate_php_curl_tls(array $curlinfo, $zts) {
if (empty($curlinfo['ssl_version'])) {
return false;
}
$flavour = explode('/', $curlinfo['ssl_version'])[0];
// In threadsafe mode the only valid choices are OpenSSL and GnuTLS.
if ($zts === 1 && $flavour != 'OpenSSL' && $flavour !== 'GnuTLS') {
return false;
}
return true;
}
/**
* Tests if the system is capable of using TLS 1.2 for requests.
*
* @param array $curlinfo array of cURL information as returned by curl_version()
* @param string $uname server uname
* @return bool
*/
public static function can_use_tls12(array $curlinfo, $uname) {
if ($curlinfo['version_number'] < 467456 || !defined('CURL_SSLVERSION_TLSv1_2')) {
return false;
}
$sslversion = explode('/', $curlinfo['ssl_version']);
// NSS has a space in the version number 😦.
$flavour = explode(' ', $sslversion[0])[0];
$version = count($sslversion) == 2 ? $sslversion[1] : null;
$minversion = self::get_min_ssl_lib_version_for_tls12($flavour);
if (!$minversion) {
return false;
}
// Special case (see $versionmatrix above).
if ($flavour == 'WinSSL') {
return $uname >= '6.1';
}
// Special case (see $versionmatrix above).
if ($flavour == 'SecureTransport') {
return $uname >= '10.8.0';
}
return $version >= $minversion;
}
}

View File

@ -40,6 +40,8 @@ class core_environment_testcase extends advanced_testcase {
require_once($CFG->libdir.'/environmentlib.php');
list($envstatus, $environment_results) = check_moodle_environment(normalize_version($CFG->release), ENV_SELECT_RELEASE);
$sslmessages = ['ssl/tls configuration not supported', 'invalid ssl/tls configuration'];
$this->assertNotEmpty($envstatus);
foreach ($environment_results as $environment_result) {
if ($environment_result->part === 'php_setting'
@ -50,6 +52,14 @@ class core_environment_testcase extends advanced_testcase {
$this->markTestSkipped('OPCache extension is not necessary for unit testing.');
continue;
}
if ($environment_result->part === 'custom_check'
and in_array($environment_result->info, $sslmessages)
and $environment_result->getLevel() === 'optional'
and $environment_result->getStatus() === false
) {
$this->markTestSkipped('Up-to-date TLS libraries are not necessary for unit testing.');
continue;
}
$this->assertTrue($environment_result->getStatus(), "Problem detected in environment ($environment_result->part:$environment_result->info), fix all warnings and errors!");
}
}

View File

@ -0,0 +1,183 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Upgrade utility class tests.
*
* @package core
* @copyright 2016 Cameron Ball <cameron@cameron1729.xyz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Upgrade utility class tests.
*
* @package core
* @copyright 2016 Cameron Ball <cameron@cameron1729.xyz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class upgrade_util_testcase extends advanced_testcase {
/**
* A cURL version that supports TLS 1.2.
*/
const VALID_CURL_VERSION = 467456;
/**
* A cURL version that does not support TLS 1.2.
*/
const INVALID_CURL_VERSION = 467455;
/**
* The value of PHP_ZTS when thread safety is enabled.
*/
const PHP_ZTS_ENABLED = 1;
/**
* The value of PHP_ZTS when thread safety is disabled.
*/
const PHP_ZTS_DISABLED = 0;
/**
* Test PHP/cURL validation.
*
* @dataProvider validate_php_curl_tls_testcases()
* @param array $curlinfo server curl_version array
* @param int $zts 0 or 1 as defined by PHP_ZTS
* @param bool $expected expected result
*/
public function test_validate_php_curl_tls($curlinfo, $zts, $expected) {
$expected === true && $this->assertTrue(\core\upgrade\util::validate_php_curl_tls($curlinfo, $zts));
$expected === false && $this->assertFalse(\core\upgrade\util::validate_php_curl_tls($curlinfo, $zts));
}
/**
* Test cases for validate_php_curl_tls test.
*/
public function validate_php_curl_tls_testcases() {
$base = curl_version();
return [
'Not threadsafe - Valid SSL (GnuTLS)' => [
['ssl_version' => 'GnuTLS/4.20'] + $base,
self::PHP_ZTS_DISABLED,
true
],
'Not threadsafe - Valid SSL (OpenSSL)' => [
['ssl_version' => 'OpenSSL'] + $base,
self::PHP_ZTS_DISABLED,
true
],
'Not threadsafe - Valid SSL (WinSSL)' => [
['ssl_version' => 'WinSSL'] + $base,
self::PHP_ZTS_DISABLED,
true
],
'Not threadsafe - Invalid SSL' => [
['ssl_version' => ''] + $base,
self::PHP_ZTS_DISABLED,
false
],
'Threadsafe - Valid SSL (OpenSSL)' => [
['ssl_version' => 'OpenSSL/1729'] + $base,
self::PHP_ZTS_ENABLED,
true
],
'Threadsafe - Valid SSL (GnuTLS)' => [
['ssl_version' => 'GnuTLS/3.14'] + $base,
self::PHP_ZTS_ENABLED,
true
],
'Threadsafe - Invalid SSL' => [
['ssl_version' => ''] + $base,
self::PHP_ZTS_ENABLED,
false
],
'Threadsafe - Invalid SSL (but not empty)' => [
['ssl_version' => 'Not GnuTLS or OpenSSL'] + $base,
self::PHP_ZTS_ENABLED,
false
]
];
}
/**
* Test various combinations of SSL/TLS libraries.
*
* @dataProvider can_use_tls12_testcases
* @param array $environment the server environment
* @param bool $expected expected result
*/
public function test_can_use_tls12($environment, $expected) {
$curlinfo = $environment['curl_version'] + curl_version();
if ($curlinfo['version_number'] >= self::VALID_CURL_VERSION && !defined('CURL_SSLVERSION_TLSv1_2')) {
define('CURL_SSLVERSION_TLSv1_2', 6);
}
$expected === true && $this->assertTrue(\core\upgrade\util::can_use_tls12($curlinfo, $environment['uname']));
$expected === false && $this->assertFalse(\core\upgrade\util::can_use_tls12($curlinfo, $environment['uname']));
}
/**
* Test cases for the can_use_tls test.
*
* @return array of testcases
*/
public function can_use_tls12_testcases() {
$versionmatrix = [
'OpenSSL' => ['Older' => '0.9.8o', 'Min required' => '1.0.1c', 'Newer' => '1.0.1t'],
'GnuTLS' => ['Older' => '1.5.0', 'Min requires' => '1.7.1', 'Newer' => '1.8.1'],
'NSS' => ['Older' => '3.14.15', 'Min required' => '3.15.1 Basic ECC', 'Newer' => '3.17.2 Basic ECC'],
'CyaSSL' => ['Older' => '0.9.9', 'Min required' => '1.1.0', 'Newer' => '1.2.0'],
'wolfSSL' => ['Older' => '1.0.0', 'Min required' => '1.1.0', 'Newer' => '1.2.0'],
'WinSSL' => ['Older' => '5.1', 'Min required' => '6.1', 'Newer' => '7.0'],
'SecureTransport' => ['Older' => '10.7.5', 'Min required' => '10.8.0', 'Newer' => '10.9.0']
];
// This will generate an array of testcases from the matrix above.
// It generates one testcase for every version. If the version is too
// old or the cURL version (passed as an argument) is too old, the
// expected result of the testcase is false. Otherwise it is true.
//
// Each testcase is given a name like WinSSL/Valid env/Min required.
// The first part is the SSL/TLS library, the second part is whether
// or not the environment is valid (i.e., we are using a valid/invalid
// cURL version. The final part says which version of the SSL/TLS library
// is being used (i.e., Older, Min required or Newer).
$generatetestcases = function($curlversion) use ($versionmatrix) {
return array_reduce(array_keys($versionmatrix), function($carry, $sslflavour) use ($versionmatrix, $curlversion) {
return $carry + array_reduce(array_keys($versionmatrix[$sslflavour]), function($carry, $sslversion)
use ($versionmatrix, $curlversion, $sslflavour) {
$env = $curlversion == self::VALID_CURL_VERSION ? 'Valid' : 'Invalid';
$exceptions = ['WinSSL', 'SecureTransport'];
$versionsuffix = in_array($sslflavour, $exceptions) ? '' : '/' . $versionmatrix[$sslflavour][$sslversion];
return $carry + [$sslflavour . '/' . $env. ' env/' . $sslversion => [[
'curl_version' => [
'ssl_version' => $sslflavour . $versionsuffix,
'version_number' => $curlversion
],
'uname' => in_array($sslflavour, $exceptions) ? $versionmatrix[$sslflavour][$sslversion] : php_uname('r')
], $sslversion != 'Older' && $curlversion != self::INVALID_CURL_VERSION]];
}, []);
}, []);
};
return $generatetestcases(self::VALID_CURL_VERSION) + $generatetestcases(self::INVALID_CURL_VERSION);
}
}

View File

@ -2317,3 +2317,27 @@ function check_unoconv_version(environment_results $result) {
}
return null;
}
/**
* Checks for up-to-date TLS libraries.
*
* @param environment_results $result object to update, if relevant.
* @return environment_results|null updated results or null if unoconv path is not executable.
*/
function check_tls_libraries(environment_results $result) {
global $CFG;
if (!\core\upgrade\util::validate_php_curl_tls(curl_version(), PHP_ZTS)) {
$result->setInfo('invalid ssl/tls configuration');
$result->setStatus(false);
return $result;
}
if (!\core\upgrade\util::can_use_tls12(curl_version(), php_uname('r'))) {
$result->setInfo('ssl/tls configuration not supported');
$result->setStatus(false);
return $result;
}
return null;
}