[ 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/ca-trust/extracted/pem/tls-ca-bundle.pem', // Fedora, RHEL, CentOS (ca-certificates package) - NEW
  85              '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) - Deprecated
  86              '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package)
  87              '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package)
  88              '/usr/ssl/certs/ca-bundle.crt', // Cygwin
  89              '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package
  90              '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option)
  91              '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat?
  92              '/etc/ssl/cert.pem', // OpenBSD
  93              '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package
  94              '/usr/local/etc/[email protected]/cert.pem', // OS X homebrew, [email protected] package
  95              '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package
  96              '/opt/homebrew/etc/[email protected]/cert.pem', // macOS silicon homebrew, [email protected] package
  97              '/etc/pki/tls/certs',
  98              '/etc/ssl/certs', // FreeBSD
  99          );
 100  
 101          $caBundlePaths = array_merge($caBundlePaths, $otherLocations);
 102  
 103          foreach ($caBundlePaths as $caBundle) {
 104              if ($caBundle && self::caFileUsable($caBundle, $logger)) {
 105                  return self::$caPath = $caBundle;
 106              }
 107  
 108              if ($caBundle && self::caDirUsable($caBundle, $logger)) {
 109                  return self::$caPath = $caBundle;
 110              }
 111          }
 112  
 113          return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort
 114      }
 115  
 116      /**
 117       * Returns the path to the bundled CA file
 118       *
 119       * In case you don't want to trust the user or the system, you can use this directly
 120       *
 121       * @return string path to a CA bundle file
 122       */
 123      public static function getBundledCaBundlePath()
 124      {
 125          $caBundleFile = __DIR__.'/../res/cacert.pem';
 126  
 127          // cURL does not understand 'phar://' paths
 128          // see https://github.com/composer/ca-bundle/issues/10
 129          if (0 === strpos($caBundleFile, 'phar://')) {
 130              $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-');
 131              if (false === $tempCaBundleFile) {
 132                  throw new \RuntimeException('Could not create a temporary file to store the bundled CA file');
 133              }
 134  
 135              file_put_contents(
 136                  $tempCaBundleFile,
 137                  file_get_contents($caBundleFile)
 138              );
 139  
 140              register_shutdown_function(function() use ($tempCaBundleFile) {
 141                  @unlink($tempCaBundleFile);
 142              });
 143  
 144              $caBundleFile = $tempCaBundleFile;
 145          }
 146  
 147          return $caBundleFile;
 148      }
 149  
 150      /**
 151       * Validates a CA file using opensl_x509_parse only if it is safe to use
 152       *
 153       * @param string          $filename
 154       * @param LoggerInterface $logger   optional logger for information about which CA files were loaded
 155       *
 156       * @return bool
 157       */
 158      public static function validateCaFile($filename, ?LoggerInterface $logger = null)
 159      {
 160          static $warned = false;
 161  
 162          if (isset(self::$caFileValidity[$filename])) {
 163              return self::$caFileValidity[$filename];
 164          }
 165  
 166          $contents = file_get_contents($filename);
 167  
 168          if (is_string($contents) && strlen($contents) > 0) {
 169              $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents);
 170              if (null === $contents) {
 171                  // regex extraction failed
 172                  $isValid = false;
 173              } else {
 174                  $isValid = (bool) openssl_x509_parse($contents);
 175              }
 176          } else {
 177              $isValid = false;
 178          }
 179  
 180          if ($logger) {
 181              $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid'));
 182          }
 183  
 184          return self::$caFileValidity[$filename] = $isValid;
 185      }
 186  
 187      /**
 188       * Test if it is safe to use the PHP function openssl_x509_parse().
 189       *
 190       * This checks if OpenSSL extensions is vulnerable to remote code execution
 191       * via the exploit documented as CVE-2013-6420.
 192       *
 193       * @return bool
 194       */
 195      public static function isOpensslParseSafe()
 196      {
 197          return true;
 198      }
 199  
 200      /**
 201       * Resets the static caches
 202       * @return void
 203       */
 204      public static function reset()
 205      {
 206          self::$caFileValidity = array();
 207          self::$caPath = null;
 208      }
 209  
 210      /**
 211       * @param  string $name
 212       * @return string|false
 213       */
 214      private static function getEnvVariable($name)
 215      {
 216          if (isset($_SERVER[$name])) {
 217              return (string) $_SERVER[$name];
 218          }
 219  
 220          if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) {
 221              return (string) $value;
 222          }
 223  
 224          return false;
 225      }
 226  
 227      /**
 228       * @param  string|false $certFile
 229       * @param  LoggerInterface|null $logger
 230       * @return bool
 231       */
 232      private static function caFileUsable($certFile, ?LoggerInterface $logger = null)
 233      {
 234          return $certFile
 235              && self::isFile($certFile, $logger)
 236              && self::isReadable($certFile, $logger)
 237              && self::validateCaFile($certFile, $logger);
 238      }
 239  
 240      /**
 241       * @param  string|false $certDir
 242       * @param  LoggerInterface|null $logger
 243       * @return bool
 244       */
 245      private static function caDirUsable($certDir, ?LoggerInterface $logger = null)
 246      {
 247          return $certDir
 248              && self::isDir($certDir, $logger)
 249              && self::isReadable($certDir, $logger)
 250              && self::glob($certDir . '/*', $logger);
 251      }
 252  
 253      /**
 254       * @param  string $certFile
 255       * @param  LoggerInterface|null $logger
 256       * @return bool
 257       */
 258      private static function isFile($certFile, ?LoggerInterface $logger = null)
 259      {
 260          $isFile = @is_file($certFile);
 261          if (!$isFile && $logger) {
 262              $logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile));
 263          }
 264  
 265          return $isFile;
 266      }
 267  
 268      /**
 269       * @param  string $certDir
 270       * @param  LoggerInterface|null $logger
 271       * @return bool
 272       */
 273      private static function isDir($certDir, ?LoggerInterface $logger = null)
 274      {
 275          $isDir = @is_dir($certDir);
 276          if (!$isDir && $logger) {
 277              $logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir));
 278          }
 279  
 280          return $isDir;
 281      }
 282  
 283      /**
 284       * @param  string $certFileOrDir
 285       * @param  LoggerInterface|null $logger
 286       * @return bool
 287       */
 288      private static function isReadable($certFileOrDir, ?LoggerInterface $logger = null)
 289      {
 290          $isReadable = @is_readable($certFileOrDir);
 291          if (!$isReadable && $logger) {
 292              $logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir));
 293          }
 294  
 295          return $isReadable;
 296      }
 297  
 298      /**
 299       * @param  string $pattern
 300       * @param  LoggerInterface|null $logger
 301       * @return bool
 302       */
 303      private static function glob($pattern, ?LoggerInterface $logger = null)
 304      {
 305          $certs = glob($pattern);
 306          if ($certs === false) {
 307              if ($logger) {
 308                  $logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern));
 309              }
 310              return false;
 311          }
 312  
 313          if (count($certs) === 0) {
 314              if ($logger) {
 315                  $logger->debug(sprintf("No CA files found for pattern: %s", $pattern));
 316              }
 317              return false;
 318          }
 319  
 320          return true;
 321      }
 322  }


Generated: Sat Jul 11 05:10:54 2026 Cross-referenced by PHPXref 0.7.1