GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( b5e3c2...7799bc )
by
unknown
15s
created

CaBundle::isOpensslParseSafe()   D

Complexity

Conditions 21
Paths 10

Size

Total Lines 96
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 44
nc 10
nop 0
dl 0
loc 96
rs 4.6955
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of composer/ca-bundle.
5
 *
6
 * (c) Composer <https://github.com/composer>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace Composer\CaBundle;
13
14
use Psr\Log\LoggerInterface;
15
use Symfony\Component\Process\PhpProcess;
16
17
/**
18
 * @author Chris Smith <[email protected]>
19
 * @author Jordi Boggiano <[email protected]>
20
 */
21
class CaBundle
22
{
23
    private static $caPath;
24
    private static $caFileValidity = array();
25
    private static $useOpensslParse;
26
27
    /**
28
     * Returns the system CA bundle path, or a path to the bundled one
29
     *
30
     * This method was adapted from Sslurp.
31
     * https://github.com/EvanDotPro/Sslurp
32
     *
33
     * (c) Evan Coury <[email protected]>
34
     *
35
     * For the full copyright and license information, please see below:
36
     *
37
     * Copyright (c) 2013, Evan Coury
38
     * All rights reserved.
39
     *
40
     * Redistribution and use in source and binary forms, with or without modification,
41
     * are permitted provided that the following conditions are met:
42
     *
43
     *     * Redistributions of source code must retain the above copyright notice,
44
     *       this list of conditions and the following disclaimer.
45
     *
46
     *     * Redistributions in binary form must reproduce the above copyright notice,
47
     *       this list of conditions and the following disclaimer in the documentation
48
     *       and/or other materials provided with the distribution.
49
     *
50
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
51
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
52
     * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
53
     * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
54
     * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
55
     * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56
     * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
57
     * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
59
     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60
     *
61
     * @param  LoggerInterface $logger optional logger for information about which CA files were loaded
62
     * @return string          path to a CA bundle file or directory
63
     */
64
    public static function getSystemCaRootBundlePath(LoggerInterface $logger = null)
65
    {
66
        if (self::$caPath !== null) {
67
            return self::$caPath;
68
        }
69
70
        // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that.
71
        // This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
72
        $envCertFile = getenv('SSL_CERT_FILE');
73
        if ($envCertFile && is_readable($envCertFile) && static::validateCaFile($envCertFile, $logger)) {
74
            return self::$caPath = $envCertFile;
75
        }
76
77
        // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that.
78
        // This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
79
        $envCertDir = getenv('SSL_CERT_DIR');
80
        if ($envCertDir && is_dir($envCertDir) && is_readable($envCertDir)) {
81
            return self::$caPath = $envCertDir;
82
        }
83
84
        $configured = ini_get('openssl.cafile');
85
        if ($configured && strlen($configured) > 0 && is_readable($configured) && static::validateCaFile($configured, $logger)) {
86
            return self::$caPath = $configured;
87
        }
88
89
        $configured = ini_get('openssl.capath');
90
        if ($configured && is_dir($configured) && is_readable($configured)) {
91
            return self::$caPath = $configured;
92
        }
93
94
        $caBundlePaths = array(
95
            '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package)
96
            '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package)
97
            '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package)
98
            '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package)
99
            '/usr/ssl/certs/ca-bundle.crt', // Cygwin
100
            '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package
101
            '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option)
102
            '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat?
103
            '/etc/ssl/cert.pem', // OpenBSD
104
            '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x
105
            '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package
106
        );
107
108
        foreach ($caBundlePaths as $caBundle) {
109
            if (@is_readable($caBundle) && static::validateCaFile($caBundle, $logger)) {
110
                return self::$caPath = $caBundle;
111
            }
112
        }
113
114
        foreach ($caBundlePaths as $caBundle) {
115
            $caBundle = dirname($caBundle);
116
            if (@is_dir($caBundle) && glob($caBundle.'/*')) {
117
                return self::$caPath = $caBundle;
118
            }
119
        }
120
121
        return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort
122
    }
123
124
    /**
125
     * Returns the path to the bundled CA file
126
     *
127
     * In case you don't want to trust the user or the system, you can use this directly
128
     *
129
     * @return string path to a CA bundle file
130
     */
131
    public static function getBundledCaBundlePath()
132
    {
133
        $caBundleFile = __DIR__.'/../res/cacert.pem';
134
135
        // cURL does not understand 'phar://' paths
136
        // see https://github.com/composer/ca-bundle/issues/10
137
        if (0 === strpos($caBundleFile, 'phar://')) {
138
            file_put_contents(
139
                $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-'),
140
                file_get_contents($caBundleFile)
141
            );
142
143
            register_shutdown_function(function() use ($tempCaBundleFile) {
144
                @unlink($tempCaBundleFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
145
            });
146
147
            $caBundleFile = $tempCaBundleFile;
148
        }
149
150
        return $caBundleFile;
151
    }
152
153
    /**
154
     * Validates a CA file using opensl_x509_parse only if it is safe to use
155
     *
156
     * @param string          $filename
157
     * @param LoggerInterface $logger   optional logger for information about which CA files were loaded
158
     *
159
     * @return bool
160
     */
161
    public static function validateCaFile($filename, LoggerInterface $logger = null)
162
    {
163
        static $warned = false;
164
165
        if (isset(self::$caFileValidity[$filename])) {
166
            return self::$caFileValidity[$filename];
167
        }
168
169
        $contents = file_get_contents($filename);
170
171
        // assume the CA is valid if php is vulnerable to
172
        // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html
173
        if (!static::isOpensslParseSafe()) {
174
            if (!$warned && $logger) {
175
                $logger->warning(sprintf(
176
                    'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.',
177
                    PHP_VERSION
178
                ));
179
                $warned = true;
180
            }
181
182
            $isValid = !empty($contents);
183
        } else {
184
            $isValid = (bool) openssl_x509_parse($contents);
185
        }
186
187
        if ($logger) {
188
            $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid'));
189
        }
190
191
        return self::$caFileValidity[$filename] = $isValid;
192
    }
193
194
    /**
195
     * Test if it is safe to use the PHP function openssl_x509_parse().
196
     *
197
     * This checks if OpenSSL extensions is vulnerable to remote code execution
198
     * via the exploit documented as CVE-2013-6420.
199
     *
200
     * @return bool
201
     */
202
    public static function isOpensslParseSafe()
203
    {
204
        if (null !== self::$useOpensslParse) {
205
            return self::$useOpensslParse;
206
        }
207
208
        if (PHP_VERSION_ID >= 50600) {
209
            return self::$useOpensslParse = true;
210
        }
211
212
        // Vulnerable:
213
        // PHP 5.3.0 - PHP 5.3.27
214
        // PHP 5.4.0 - PHP 5.4.22
215
        // PHP 5.5.0 - PHP 5.5.6
216
        if (
217
               (PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328)
218
            || (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423)
219
            || (PHP_VERSION_ID < 50600 && PHP_VERSION_ID >= 50507)
220
        ) {
221
            // This version of PHP has the fix for CVE-2013-6420 applied.
222
            return self::$useOpensslParse = true;
223
        }
224
225
        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
226
            // Windows is probably insecure in this case.
227
            return self::$useOpensslParse = false;
228
        }
229
230
        $compareDistroVersionPrefix = function ($prefix, $fixedVersion) {
231
            $regex = '{^'.preg_quote($prefix).'([0-9]+)$}';
232
233
            if (preg_match($regex, PHP_VERSION, $m)) {
234
                return ((int) $m[1]) >= $fixedVersion;
235
            }
236
237
            return false;
238
        };
239
240
        // Hard coded list of PHP distributions with the fix backported.
241
        if (
242
            $compareDistroVersionPrefix('5.3.3-7+squeeze', 18) // Debian 6 (Squeeze)
243
            || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) // Debian 7 (Wheezy)
244
            || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) // Ubuntu 12.04 (Precise)
245
        ) {
246
            return self::$useOpensslParse = true;
247
        }
248
249
        // Symfony Process component is missing so we assume it is unsafe at this point
250
        if (!class_exists('Symfony\Component\Process\PhpProcess')) {
251
            return self::$useOpensslParse = false;
252
        }
253
254
        // This is where things get crazy, because distros backport security
255
        // fixes the chances are on NIX systems the fix has been applied but
256
        // it's not possible to verify that from the PHP version.
257
        //
258
        // To verify exec a new PHP process and run the issue testcase with
259
        // known safe input that replicates the bug.
260
261
        // Based on testcase in https://github.com/php/php-src/commit/c1224573c773b6845e83505f717fbf820fc18415
262
        // changes in https://github.com/php/php-src/commit/76a7fd893b7d6101300cc656058704a73254d593
263
        $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K';
264
        $script = <<<'EOT'
265
266
error_reporting(-1);
267
$info = openssl_x509_parse(base64_decode('%s'));
268
var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']);
269
270
EOT;
271
        $script = '<'."?php\n".sprintf($script, $cert);
272
273
        try {
274
            $process = new PhpProcess($script);
275
            $process->mustRun();
276
        } catch (\Exception $e) {
277
            // In the case of any exceptions just accept it is not possible to
278
            // determine the safety of openssl_x509_parse and bail out.
279
            return self::$useOpensslParse = false;
280
        }
281
282
        $output = preg_split('{\r?\n}', trim($process->getOutput()));
283
        $errorOutput = trim($process->getErrorOutput());
284
285
        if (
286
            count($output) === 3
287
            && $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION)
288
            && $output[1] === 'string(27) "[email protected]"'
289
            && $output[2] === 'int(-1)'
290
            && preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput)
291
        ) {
292
            // This PHP has the fix backported probably by a distro security team.
293
            return self::$useOpensslParse = true;
294
        }
295
296
        return self::$useOpensslParse = false;
297
    }
298
299
    /**
300
     * Resets the static caches
301
     */
302
    public static function reset()
303
    {
304
        self::$caFileValidity = array();
305
        self::$caPath = null;
306
        self::$useOpensslParse = null;
307
    }
308
}
309