1
0
Fork 0

apply comments

- add capath to json schema
- simplify factory
- hash_file and sha256 for CA checking
- remove exception as scenario should not occur
- remove executable bit from CA file
- make CA file also group/world writable (we overwrite invalid content anyway)
    to avoid permission errors as much as possible
pull/4805/head
Rob Bast 2016-01-22 09:14:37 +01:00
parent c232566e52
commit 474541e9aa
3 changed files with 74 additions and 55 deletions

View File

@ -149,6 +149,10 @@
"type": "string", "type": "string",
"description": "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." "description": "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."
}, },
"capath": {
"type": "string",
"description": "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": { "http-basic": {
"type": "object", "type": "object",
"description": "A hash of domain name => {\"username\": \"...\", \"password\": \"...\"}.", "description": "A hash of domain name => {\"username\": \"...\", \"password\": \"...\"}.",

View File

@ -590,16 +590,10 @@ class Factory
$remoteFilesystemOptions = array(); $remoteFilesystemOptions = array();
if ($disableTls === false) { if ($disableTls === false) {
if ($config && $config->get('cafile')) { if ($config && $config->get('cafile')) {
$remoteFilesystemOptions = array_merge_recursive( $remoteFilesystemOptions['ssl']['cafile'] = $config->get('cafile');
$remoteFilesystemOptions,
array('ssl' => array('cafile' => $config->get('cafile')))
);
} }
if ($config && $config->get('capath')) { if ($config && $config->get('capath')) {
$remoteFilesystemOptions = array_merge_recursive( $remoteFilesystemOptions['ssl']['capath'] = $config->get('capath');
$remoteFilesystemOptions,
array('ssl' => array('capath' => $config->get('capath')))
);
} }
} }
try { try {

View File

@ -567,6 +567,11 @@ class RemoteFilesystem
return $options; return $options;
} }
/**
* @param array $options
*
* @return array
*/
private function getTlsDefaults(array $options) private function getTlsDefaults(array $options)
{ {
$ciphers = implode(':', array( $ciphers = implode(':', array(
@ -631,27 +636,16 @@ class RemoteFilesystem
* Attempt to find a local cafile or throw an exception if none pre-set * Attempt to find a local cafile or throw an exception if none pre-set
* The user may go download one if this occurs. * The user may go download one if this occurs.
*/ */
if (!isset($defaults['ssl']['cafile'], $defaults['ssl']['capath'])) { if (!isset($defaults['ssl']['cafile']) && !isset($defaults['ssl']['capath'])) {
$result = $this->getSystemCaRootBundlePath(); $result = $this->getSystemCaRootBundlePath();
if (!$result) {
throw new TransportException('A valid cafile or capath could not be located automatically.');
}
if (preg_match('{^phar://}', $result)) { if (preg_match('{^phar://}', $result)) {
$hash = md5(file_get_contents($result)); $hash = hash_file('sha256', $result);
$targetPath = rtrim(sys_get_temp_dir(), '\\/') . '/composer-cacert-' . $hash . '.pem'; $targetPath = rtrim(sys_get_temp_dir(), '\\/') . '/composer-cacert-' . $hash . '.pem';
if (!file_exists($targetPath)) { if (!file_exists($targetPath) || $hash !== hash_file('sha256', $targetPath)) {
// use stream_copy_to_stream instead of copy $this->safeCopy($result, $targetPath);
// to work around https://bugs.php.net/bug.php?id=64634 chmod($targetPath, 0644);
$source = fopen($result, 'r');
$target = fopen($targetPath, 'w+');
stream_copy_to_stream($source, $target);
fclose($source);
fclose($target);
chmod($targetPath, 0744);
unset($source, $target);
} }
$defaults['ssl']['cafile'] = $targetPath; $defaults['ssl']['cafile'] = $targetPath;
@ -681,37 +675,39 @@ class RemoteFilesystem
} }
/** /**
* This method was adapted from Sslurp. * This method was adapted from Sslurp.
* https://github.com/EvanDotPro/Sslurp * https://github.com/EvanDotPro/Sslurp
* *
* (c) Evan Coury <me@evancoury.com> * (c) Evan Coury <me@evancoury.com>
* *
* For the full copyright and license information, please see below: * For the full copyright and license information, please see below:
* *
* Copyright (c) 2013, Evan Coury * Copyright (c) 2013, Evan Coury
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met: * are permitted provided that the following conditions are met:
* *
* * Redistributions of source code must retain the above copyright notice, * * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright notice, * * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation * this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. * and/or other materials provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ *
* @return string
*/
private function getSystemCaRootBundlePath() private function getSystemCaRootBundlePath()
{ {
static $caPath = null; static $caPath = null;
@ -762,6 +758,11 @@ class RemoteFilesystem
return $caPath = __DIR__.'/../../../res/cacert.pem'; // Bundled with Composer, last resort return $caPath = __DIR__.'/../../../res/cacert.pem'; // Bundled with Composer, last resort
} }
/**
* @param string $filename
*
* @return bool
*/
private function validateCaFile($filename) private function validateCaFile($filename)
{ {
if ($this->io->isDebug()) { if ($this->io->isDebug()) {
@ -781,4 +782,24 @@ class RemoteFilesystem
return (bool) openssl_x509_parse($contents); return (bool) openssl_x509_parse($contents);
} }
/**
* Safely copy a file.
*
* Uses stream_copy_to_stream instead of copy to work around https://bugs.php.net/bug.php?id=64634
*
* @param string $source
* @param string $target
*/
private function safeCopy($source, $target)
{
$source = fopen($source, 'r');
$target = fopen($target, 'w+');
stream_copy_to_stream($source, $target);
fclose($source);
fclose($target);
unset($source, $target);
}
} }