[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/includes/vendor/composer/ca-bundle/src/ -> CaBundle.php (source)

   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      /** @var string|null */
  24      private static $caPath;
  25      /** @var array<string, bool> */
  26      private static $caFileValidity = array();
  27  
  28      /**
  29       * Returns the system CA bundle path, or a path to the bundled one
  30       *
  31       * This method was adapted from Sslurp.
  32       * https://github.com/EvanDotPro/Sslurp
  33       *
  34       * (c) Evan Coury <[email protected]>
  35       *
  36       * For the full copyright and license information, please see below:
  37       *
  38       * Copyright (c) 2013, Evan Coury
  39       * All rights reserved.
  40       *
  41       * Redistribution and use in source and binary forms, with or without modification,
  42       * are permitted provided that the following conditions are met:
  43       *
  44       *     * Redistributions of source code must retain the above copyright notice,
  45       *       this list of conditions and the following disclaimer.
  46       *
  47       *     * Redistributions in binary form must reproduce the above copyright notice,
  48       *       this list of conditions and the following disclaimer in the documentation
  49       *       and/or other materials provided with the distribution.
  50       *
  51       * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  52       * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  53       * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  54       * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  55       * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  56       * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  57       * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  58       * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  59       * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  60       * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61       *
  62       * @param  LoggerInterface $logger optional logger for information about which CA files were loaded
  63       * @return string          path to a CA bundle file or directory
  64       */
  65      public static function getSystemCaRootBundlePath(?LoggerInterface $logger = null)
  66      {
  67          if (self::$caPath !== null) {
  68              return self::$caPath;
  69          }
  70          $caBundlePaths = array();
  71  
  72          // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that.
  73          // This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
  74          $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE');
  75  
  76          // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that.
  77          // This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
  78          $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR');
  79  
  80          $caBundlePaths[] = ini_get('openssl.cafile');
  81          $caBundlePaths[] = ini_get('openssl.capath');
  82  
  83          $otherLocations = array(
  84              '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package)
  85              '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package)
  86              '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package)
  87              '/usr/ssl/certs/ca-bundle.crt', // Cygwin
  88              '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package
  89              '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option)
  90              '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat?
  91              '/etc/ssl/cert.pem', // OpenBSD
  92              '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package
  93              '/usr/local/etc/[email protected]/cert.pem', // OS X homebrew, [email protected] package
  94              '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package
  95              '/opt/homebrew/etc/[email protected]/cert.pem', // macOS silicon homebrew, [email protected] package
  96              '/etc/pki/tls/certs',
  97              '/etc/ssl/certs', // FreeBSD
  98          );
  99  
 100          $caBundlePaths = array_merge($caBundlePaths, $otherLocations);
 101  
 102          foreach ($caBundlePaths as $caBundle) {
 103              if ($caBundle && self::caFileUsable($caBundle, $logger)) {
 104                  return self::$caPath = $caBundle;
 105              }
 106  
 107              if ($caBundle && self::caDirUsable($caBundle, $logger)) {
 108                  return self::$caPath = $caBundle;
 109              }
 110          }
 111  
 112          return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort
 113      }
 114  
 115      /**
 116       * Returns the path to the bundled CA file
 117       *
 118       * In case you don't want to trust the user or the system, you can use this directly
 119       *
 120       * @return string path to a CA bundle file
 121       */
 122      public static function getBundledCaBundlePath()
 123      {
 124          $caBundleFile = __DIR__.'/../res/cacert.pem';
 125  
 126          // cURL does not understand 'phar://' paths
 127          // see https://github.com/composer/ca-bundle/issues/10
 128          if (0 === strpos($caBundleFile, 'phar://')) {
 129              $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-');
 130              if (false === $tempCaBundleFile) {
 131                  throw new \RuntimeException('Could not create a temporary file to store the bundled CA file');
 132              }
 133  
 134              file_put_contents(
 135                  $tempCaBundleFile,
 136                  file_get_contents($caBundleFile)
 137              );
 138  
 139              register_shutdown_function(function() use ($tempCaBundleFile) {
 140                  @unlink($tempCaBundleFile);
 141              });
 142  
 143              $caBundleFile = $tempCaBundleFile;
 144          }
 145  
 146          return $caBundleFile;
 147      }
 148  
 149      /**
 150       * Validates a CA file using opensl_x509_parse only if it is safe to use
 151       *
 152       * @param string          $filename
 153       * @param LoggerInterface $logger   optional logger for information about which CA files were loaded
 154       *
 155       * @return bool
 156       */
 157      public static function validateCaFile($filename, ?LoggerInterface $logger = null)
 158      {
 159          static $warned = false;
 160  
 161          if (isset(self::$caFileValidity[$filename])) {
 162              return self::$caFileValidity[$filename];
 163          }
 164  
 165          $contents = file_get_contents($filename);
 166  
 167          if (is_string($contents) && strlen($contents) > 0) {
 168              $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents);
 169              if (null === $contents) {
 170                  // regex extraction failed
 171                  $isValid = false;
 172              } else {
 173                  $isValid = (bool) openssl_x509_parse($contents);
 174              }
 175          } else {
 176              $isValid = false;
 177          }
 178  
 179          if ($logger) {
 180              $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid'));
 181          }
 182  
 183          return self::$caFileValidity[$filename] = $isValid;
 184      }
 185  
 186      /**
 187       * Test if it is safe to use the PHP function openssl_x509_parse().
 188       *
 189       * This checks if OpenSSL extensions is vulnerable to remote code execution
 190       * via the exploit documented as CVE-2013-6420.
 191       *
 192       * @return bool
 193       */
 194      public static function isOpensslParseSafe()
 195      {
 196          return true;
 197      }
 198  
 199      /**
 200       * Resets the static caches
 201       * @return void
 202       */
 203      public static function reset()
 204      {
 205          self::$caFileValidity = array();
 206          self::$caPath = null;
 207      }
 208  
 209      /**
 210       * @param  string $name
 211       * @return string|false
 212       */
 213      private static function getEnvVariable($name)
 214      {
 215          if (isset($_SERVER[$name])) {
 216              return (string) $_SERVER[$name];
 217          }
 218  
 219          if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) {
 220              return (string) $value;
 221          }
 222  
 223          return false;
 224      }
 225  
 226      /**
 227       * @param  string|false $certFile
 228       * @param  LoggerInterface|null $logger
 229       * @return bool
 230       */
 231      private static function caFileUsable($certFile, ?LoggerInterface $logger = null)
 232      {
 233          return $certFile
 234              && self::isFile($certFile, $logger)
 235              && self::isReadable($certFile, $logger)
 236              && self::validateCaFile($certFile, $logger);
 237      }
 238  
 239      /**
 240       * @param  string|false $certDir
 241       * @param  LoggerInterface|null $logger
 242       * @return bool
 243       */
 244      private static function caDirUsable($certDir, ?LoggerInterface $logger = null)
 245      {
 246          return $certDir
 247              && self::isDir($certDir, $logger)
 248              && self::isReadable($certDir, $logger)
 249              && self::glob($certDir . '/*', $logger);
 250      }
 251  
 252      /**
 253       * @param  string $certFile
 254       * @param  LoggerInterface|null $logger
 255       * @return bool
 256       */
 257      private static function isFile($certFile, ?LoggerInterface $logger = null)
 258      {
 259          $isFile = @is_file($certFile);
 260          if (!$isFile && $logger) {
 261              $logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile));
 262          }
 263  
 264          return $isFile;
 265      }
 266  
 267      /**
 268       * @param  string $certDir
 269       * @param  LoggerInterface|null $logger
 270       * @return bool
 271       */
 272      private static function isDir($certDir, ?LoggerInterface $logger = null)
 273      {
 274          $isDir = @is_dir($certDir);
 275          if (!$isDir && $logger) {
 276              $logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir));
 277          }
 278  
 279          return $isDir;
 280      }
 281  
 282      /**
 283       * @param  string $certFileOrDir
 284       * @param  LoggerInterface|null $logger
 285       * @return bool
 286       */
 287      private static function isReadable($certFileOrDir, ?LoggerInterface $logger = null)
 288      {
 289          $isReadable = @is_readable($certFileOrDir);
 290          if (!$isReadable && $logger) {
 291              $logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir));
 292          }
 293  
 294          return $isReadable;
 295      }
 296  
 297      /**
 298       * @param  string $pattern
 299       * @param  LoggerInterface|null $logger
 300       * @return bool
 301       */
 302      private static function glob($pattern, ?LoggerInterface $logger = null)
 303      {
 304          $certs = glob($pattern);
 305          if ($certs === false) {
 306              if ($logger) {
 307                  $logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern));
 308              }
 309              return false;
 310          }
 311  
 312          if (count($certs) === 0) {
 313              if ($logger) {
 314                  $logger->debug(sprintf("No CA files found for pattern: %s", $pattern));
 315              }
 316              return false;
 317          }
 318  
 319          return true;
 320      }
 321  }


Generated: Mon Mar 31 05:10:02 2025 Cross-referenced by PHPXref 0.7.1