From 10c63745029a76793a98ca46fe71e9989e7bc8d3 Mon Sep 17 00:00:00 2001
From: Cameron Ball <cameron@moodle.com>
Date: Tue, 2 Aug 2016 16:31:25 +0800
Subject: [PATCH 1/5] MDL-56806 core_upgrade: Add libcurl environment checks

This patch adds logic to test whether or not the
libcurl (used by PHP/cURL)  was compiled against a compatible
SSL/TLS library.
---
 admin/environment.xml           |   5 ++
 lang/en/admin.php               |   1 +
 lib/classes/upgrade/util.php    | 115 +++++++++++++++++++++++++
 lib/tests/environment_test.php  |  10 +++
 lib/tests/upgrade_util_test.php | 183 ++++++++++++++++++++++++++++++++++++++++
 lib/upgradelib.php              |  24 ++++++
 6 files changed, 338 insertions(+)
 create mode 100644 lib/classes/upgrade/util.php
 create mode 100644 lib/tests/upgrade_util_test.php

diff --git a/admin/environment.xml b/admin/environment.xml
index f8c560b..41c0b5c 100644
--- a/admin/environment.xml
+++ b/admin/environment.xml
@@ -1863,6 +1863,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_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
         <FEEDBACK>
           <ON_CHECK message="libcurlwarning" />
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 83bafb7..a0a2527 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -1060,6 +1060,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';
diff --git a/lib/classes/upgrade/util.php b/lib/classes/upgrade/util.php
new file mode 100644
index 0000000..c300901
--- /dev/null
+++ b/lib/classes/upgrade/util.php
@@ -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;
+    }
+}
diff --git a/lib/tests/environment_test.php b/lib/tests/environment_test.php
index e59fbdb..a660edb 100644
--- a/lib/tests/environment_test.php
+++ b/lib/tests/environment_test.php
@@ -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!");
         }
     }
diff --git a/lib/tests/upgrade_util_test.php b/lib/tests/upgrade_util_test.php
new file mode 100644
index 0000000..7016ce1
--- /dev/null
+++ b/lib/tests/upgrade_util_test.php
@@ -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);
+    }
+}
diff --git a/lib/upgradelib.php b/lib/upgradelib.php
index 54e8f00..4c1cae2 100644
--- a/lib/upgradelib.php
+++ b/lib/upgradelib.php
@@ -2366,3 +2366,27 @@ function check_libcurl_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;
+}
-- 
1.9.1


From bb300613cdaf7ae4ffeb980a1961a00dd96a4986 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 4 Oct 2016 18:28:34 +0100
Subject: [PATCH 2/5] MDL-56806 upgrade: dramatically simplify test code

Fixing http://xunitpatterns.com/Obscure%20Test.html
---
 lib/tests/upgrade_util_test.php | 97 ++++++++++++++++++++---------------------
 1 file changed, 47 insertions(+), 50 deletions(-)

diff --git a/lib/tests/upgrade_util_test.php b/lib/tests/upgrade_util_test.php
index 7016ce1..db0ae663 100644
--- a/lib/tests/upgrade_util_test.php
+++ b/lib/tests/upgrade_util_test.php
@@ -62,8 +62,7 @@ class upgrade_util_testcase extends advanced_testcase {
      * @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));
+        $this->assertSame($expected, \core\upgrade\util::validate_php_curl_tls($curlinfo, $zts));
     }
 
     /**
@@ -120,64 +119,62 @@ class upgrade_util_testcase extends advanced_testcase {
      * Test various combinations of SSL/TLS libraries.
      *
      * @dataProvider can_use_tls12_testcases
-     * @param array $environment the server environment
-     * @param bool  $expected    expected result
+     * @param string $sslversion the ssl_version string.
+     * @param string|null $uname uname string (or null if not relevant)
+     * @param bool $expected expected result
      */
-    public function test_can_use_tls12($environment, $expected) {
-        $curlinfo = $environment['curl_version'] + curl_version();
+    public function test_can_use_tls12($sslversion, $uname, $expected) {
+        // Populate curlinfo with whats installed on this php install.
+        $curlinfo = curl_version();
 
-        if ($curlinfo['version_number'] >= self::VALID_CURL_VERSION && !defined('CURL_SSLVERSION_TLSv1_2')) {
-            define('CURL_SSLVERSION_TLSv1_2', 6);
-        }
+        // Set the curl values we are testing to the passed data.
+        $curlinfo['ssl_version'] = $sslversion;
+        $curlinfo['version_number'] = self::VALID_CURL_VERSION;
 
-        $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']));
+        // Set uname to system value if none passed in test case.
+        $uname = !empty($uname) ? $uname : php_uname('r');
+
+        $this->assertSame($expected, \core\upgrade\util::can_use_tls12($curlinfo, $uname));
+
+        // Now set the curl version to outdated one.
+        $curlinfo['version_number'] = self::INVALID_CURL_VERSION;
+        // Tls12 should never be possible now curl version is bad.
+        $this->assertFalse(\core\upgrade\util::can_use_tls12($curlinfo, $uname));
     }
 
     /**
-     * Test cases for the can_use_tls test.
+     * Test cases for the can_use_tls12 test.
+     * The returned data format is:
+     *  [(string) ssl_version, (string|null) uname (null if not relevant), (bool) expectation ]
      *
      * @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']
+        return [
+            // Bad versions.
+            ['OpenSSL/0.9.8o', null, false],
+            ['GnuTLS/1.5.0', null, false],
+            ['NSS/3.14.15', null, false],
+            ['CyaSSL/0.9.9', null, false],
+            ['wolfSSL/1.0.0', null, false],
+            ['WinSSL', '5.1', false],
+            ['SecureTransport', '10.7.5', false],
+            // Lowest good version.
+            ['OpenSSL/1.0.1c', null, true],
+            ['GnuTLS/1.7.1', null, true],
+            ['NSS/3.15.1 Basic ECC', null, true],
+            ['CyaSSL/1.1.0', null, true],
+            ['wolfSSL/1.1.0', null, true],
+            ['WinSSL', '6.1', true],
+            ['SecureTransport', '10.8.0', true],
+            // More higher good versions.
+            ['OpenSSL/1.0.1t', null, true],
+            ['GnuTLS/1.8.1', null, true],
+            ['NSS/3.17.2 Basic ECC', null, true],
+            ['CyaSSL/1.2.0', null, true],
+            ['wolfSSL/1.2.0', null, true],
+            ['WinSSL', '7.0', true],
+            ['SecureTransport', '10.9.0', true],
         ];
-
-        // 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);
     }
 }
-- 
1.9.1


From b94c775cfa3c138c54d0688cb186aed6bcfa0585 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 6 Oct 2016 17:50:58 +0100
Subject: [PATCH 3/5] MDL-56806 tests: make upgrade_util_test compatible with
 travis

---
 lib/tests/upgrade_util_test.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/tests/upgrade_util_test.php b/lib/tests/upgrade_util_test.php
index db0ae663..bba4ceb 100644
--- a/lib/tests/upgrade_util_test.php
+++ b/lib/tests/upgrade_util_test.php
@@ -24,6 +24,9 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+// Hack to let tests run on travis..
+defined('CURL_SSLVERSION_TLSv1_2') || define('CURL_SSLVERSION_TLSv1_2', 6);
+
 /**
  * Upgrade utility class tests.
  *
-- 
1.9.1


From b12ed2c3379a1ec5baa4a2d742c771d0e1bb537b Mon Sep 17 00:00:00 2001
From: Matteo Scaramuccia <moodle@matteoscaramuccia.com>
Date: Sat, 12 Nov 2016 23:35:40 +0100
Subject: [PATCH 4/5] MDL-56806 core_upgrade: Do not use the raw version to
 check cURL caps.

Some Linux distros can backport features due to security issues
while keeping the same (old) version. See e.g.:
- RHEL 7, https://rhn.redhat.com/errata/RHSA-2015-2159.html
- RHEL 6, https://rhn.redhat.com/errata/RHBA-2016-0842.html
- Remi PHP 7.0.x, https://github.com/remicollet/remirepo/commit/87954ef9ca41
---
 lib/classes/upgrade/util.php    |  4 +++-
 lib/tests/upgrade_util_test.php | 18 +-----------------
 2 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/lib/classes/upgrade/util.php b/lib/classes/upgrade/util.php
index c300901..2c14e98 100644
--- a/lib/classes/upgrade/util.php
+++ b/lib/classes/upgrade/util.php
@@ -86,7 +86,9 @@ final class util {
      * @return bool
      */
     public static function can_use_tls12(array $curlinfo, $uname) {
-        if ($curlinfo['version_number'] < 467456 || !defined('CURL_SSLVERSION_TLSv1_2')) {
+        // Do not compare the cURL version, e.g. $curlinfo['version_number'], with v7.34.0 (467456):
+        // some Linux distros backport security issues and keep lower version numbers.
+        if (!defined('CURL_SSLVERSION_TLSv1_2')) {
             return false;
         }
 
diff --git a/lib/tests/upgrade_util_test.php b/lib/tests/upgrade_util_test.php
index bba4ceb..50aa919 100644
--- a/lib/tests/upgrade_util_test.php
+++ b/lib/tests/upgrade_util_test.php
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-// Hack to let tests run on travis..
+// Hack to let tests run on Travis CI.
 defined('CURL_SSLVERSION_TLSv1_2') || define('CURL_SSLVERSION_TLSv1_2', 6);
 
 /**
@@ -37,16 +37,6 @@ defined('CURL_SSLVERSION_TLSv1_2') || define('CURL_SSLVERSION_TLSv1_2', 6);
 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;
@@ -132,17 +122,11 @@ class upgrade_util_testcase extends advanced_testcase {
 
         // Set the curl values we are testing to the passed data.
         $curlinfo['ssl_version'] = $sslversion;
-        $curlinfo['version_number'] = self::VALID_CURL_VERSION;
 
         // Set uname to system value if none passed in test case.
         $uname = !empty($uname) ? $uname : php_uname('r');
 
         $this->assertSame($expected, \core\upgrade\util::can_use_tls12($curlinfo, $uname));
-
-        // Now set the curl version to outdated one.
-        $curlinfo['version_number'] = self::INVALID_CURL_VERSION;
-        // Tls12 should never be possible now curl version is bad.
-        $this->assertFalse(\core\upgrade\util::can_use_tls12($curlinfo, $uname));
     }
 
     /**
-- 
1.9.1


From 3f066255422e739700fb8b72fa9093e919485517 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 28 Nov 2016 13:25:02 +0800
Subject: [PATCH 5/5] MDL-56806 install: Check curl availability before
 curl_version()

---
 lib/upgradelib.php | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/upgradelib.php b/lib/upgradelib.php
index 4c1cae2..dda526d 100644
--- a/lib/upgradelib.php
+++ b/lib/upgradelib.php
@@ -2376,6 +2376,12 @@ function check_libcurl_version(environment_results $result) {
 function check_tls_libraries(environment_results $result) {
     global $CFG;
 
+    if (!function_exists('curl_version')) {
+        $result->setInfo('cURL PHP extension is not installed');
+        $result->setStatus(false);
+        return $result;
+    }
+
     if (!\core\upgrade\util::validate_php_curl_tls(curl_version(), PHP_ZTS)) {
         $result->setInfo('invalid ssl/tls configuration');
         $result->setStatus(false);
-- 
1.9.1

