From c1488f65bf7c91f44f5ad960c8c10212b3c6e4bf Mon Sep 17 00:00:00 2001 From: Rob Bast Date: Wed, 20 Jan 2016 21:20:18 +0100 Subject: [PATCH] a quick stab at adding capath --- doc/06-config.md | 12 ++++++--- src/Composer/Command/ConfigCommand.php | 4 +++ src/Composer/Config.php | 2 ++ src/Composer/Factory.php | 12 +++++++-- src/Composer/Util/RemoteFilesystem.php | 35 ++++++++++---------------- 5 files changed, 38 insertions(+), 27 deletions(-) diff --git a/doc/06-config.md b/doc/06-config.md index 59390ea42..f6c2da532 100644 --- a/doc/06-config.md +++ b/doc/06-config.md @@ -55,9 +55,15 @@ php_openssl extension in php.ini. ## cafile -A way to set the path to the openssl CA file. In PHP 5.6+ you should rather -set this via openssl.cafile in php.ini, although PHP 5.6+ should be able to -detect your system CA file automatically. +Location of Certificate Authority file on local filesystem. In PHP 5.6+ you +should rather set this via openssl.cafile in php.ini, although PHP 5.6+ should +be able to detect your system CA file automatically. + +## capath + +If cafile is not specified or if the certificate is not found there, the +directory pointed to by capath is searched for a suitable certificate. +capath must be a correctly hashed certificate directory. ## http-basic diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 8378bc5b4..0bf8f97d5 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -333,6 +333,10 @@ EOT function ($val) { return file_exists($val) && is_readable($val); }, function ($val) { return $val === 'null' ? null : $val; } ), + 'capath' => array( + function ($val) { return is_dir($val) && is_readable($val); }, + function ($val) { return $val === 'null' ? null : $val; } + ), 'github-expose-hostname' => array($booleanValidator, $booleanNormalizer), ); $multiConfigValues = array( diff --git a/src/Composer/Config.php b/src/Composer/Config.php index c7d8efa8e..a1b0246b9 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -47,6 +47,7 @@ class Config 'github-domains' => array('github.com'), 'disable-tls' => false, 'cafile' => null, + 'capath' => null, 'github-expose-hostname' => true, 'gitlab-domains' => array('gitlab.com'), 'store-auths' => 'prompt', @@ -179,6 +180,7 @@ class Config case 'cache-repo-dir': case 'cache-vcs-dir': case 'cafile': + case 'capath': // convert foo-bar to COMPOSER_FOO_BAR and check if it exists since it overrides the local config $env = 'COMPOSER_' . strtoupper(strtr($key, '-', '_')); diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 60431229b..042445a2a 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -590,9 +590,17 @@ class Factory $remoteFilesystemOptions = array(); if ($disableTls === false) { if ($config && $config->get('cafile')) { - $remoteFilesystemOptions = array('ssl' => array('cafile' => $config->get('cafile'))); + $remoteFilesystemOptions = array_merge_recursive( + $remoteFilesystemOptions, + array('ssl' => array('cafile' => $config->get('cafile'))) + ); + } + if ($config && $config->get('capath')) { + $remoteFilesystemOptions = array_merge_recursive( + $remoteFilesystemOptions, + array('ssl' => array('capath' => $config->get('capath'))) + ); } - $remoteFilesystemOptions = array_merge_recursive($remoteFilesystemOptions, $options); } try { $remoteFilesystem = new RemoteFilesystem($io, $config, $remoteFilesystemOptions, $disableTls); diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 4754e304b..48551be1b 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -54,15 +54,7 @@ class RemoteFilesystem // Setup TLS options // The cafile option can be set via config.json if ($disableTls === false) { - $this->options = $this->getTlsDefaults(); - if (isset($options['ssl']['cafile']) - && ( - !is_readable($options['ssl']['cafile']) - || !$this->validateCaFile($options['ssl']['cafile']) - ) - ) { - throw new TransportException('The configured cafile was not valid or could not be read.'); - } + $this->options = $this->getTlsDefaults($options); } else { $this->disableTls = true; } @@ -575,7 +567,7 @@ class RemoteFilesystem return $options; } - private function getTlsDefaults() + private function getTlsDefaults(array $options) { $ciphers = implode(':', array( 'ECDHE-RSA-AES128-GCM-SHA256', @@ -622,7 +614,7 @@ class RemoteFilesystem * * cafile or capath can be overridden by passing in those options to constructor. */ - $options = array( + $defaults = array( 'ssl' => array( 'ciphers' => $ciphers, 'verify_peer' => true, @@ -635,7 +627,7 @@ class RemoteFilesystem * Attempt to find a local cafile or throw an exception if none pre-set * The user may go download one if this occurs. */ - if (!isset($this->options['ssl']['cafile'])) { + if (!isset($options['ssl']['cafile']) && !isset($options['ssl']['capath'])) { $result = $this->getSystemCaRootBundlePath(); if ($result) { if (preg_match('{^phar://}', $result)) { @@ -659,7 +651,7 @@ class RemoteFilesystem } } } else { - throw new TransportException('A valid cafile could not be located automatically.'); + throw new TransportException('A valid cafile or capath could not be located automatically.'); } } @@ -667,10 +659,10 @@ class RemoteFilesystem * Disable TLS compression to prevent CRIME attacks where supported. */ if (PHP_VERSION_ID >= 50413) { - $options['ssl']['disable_compression'] = true; + $defaults['ssl']['disable_compression'] = true; } - return $options; + return $defaults; } /** @@ -721,6 +713,11 @@ class RemoteFilesystem return $caPath = $envCertFile; } + $configured = ini_get('openssl.cafile'); + if ($configured && strlen($configured) > 0 && is_readable($configured) && $this->validateCaFile($configured)) { + return $caPath = $configured; + } + $caBundlePaths = array( '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) @@ -732,14 +729,8 @@ class RemoteFilesystem '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? '/etc/ssl/cert.pem', // OpenBSD '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x - __DIR__.'/../../../res/cacert.pem', // Bundled with Composer ); - $configured = ini_get('openssl.cafile'); - if ($configured && strlen($configured) > 0 && is_readable($configured) && $this->validateCaFile($configured)) { - return $caPath = $configured; - } - foreach ($caBundlePaths as $caBundle) { if (@is_readable($caBundle) && $this->validateCaFile($caBundle)) { return $caPath = $caBundle; @@ -753,7 +744,7 @@ class RemoteFilesystem } } - return $caPath = false; + return $caPath = __DIR__.'/../../../res/cacert.pem'; // Bundled with Composer, last resort } private function validateCaFile($filename)