|
@@ -43,7 +43,20 @@ class RemoteFilesystem
|
|
|
public function __construct(IOInterface $io, $options = array())
|
|
|
{
|
|
|
$this->io = $io;
|
|
|
- $this->options = $options;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Setup TLS options
|
|
|
+ * The cafile option can be set via config.json
|
|
|
+ */
|
|
|
+ $this->options = $this->getTlsDefaults();
|
|
|
+ if (isset($options['ssl']['cafile'])
|
|
|
+ && (!is_readable($options['ssl']['cafile'])
|
|
|
+ || !openssl_x509_parse(file_get_contents($options['ssl']['cafile'])))) { //check return value and test (it's subject to change)
|
|
|
+ throw new TransportException('The configured cafile could was not valid or could not be read.');
|
|
|
+ }
|
|
|
+
|
|
|
+ // handle the other externally set options normally.
|
|
|
+ $this->options = array_replace_recursive($this->options, $options);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -344,6 +357,158 @@ class RemoteFilesystem
|
|
|
$options['http']['header'][] = $header;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Setup TLS options CN_match and SNI_server_name based on URL given
|
|
|
+ */
|
|
|
+ $parts = parse_url($originUrl);
|
|
|
+
|
|
|
+
|
|
|
+ return $options;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function getTlsDefaults()
|
|
|
+ {
|
|
|
+ $ciphers = implode(':', array(
|
|
|
+ 'ECDHE-RSA-AES128-GCM-SHA256',
|
|
|
+ 'ECDHE-ECDSA-AES128-GCM-SHA256',
|
|
|
+ 'ECDHE-RSA-AES256-GCM-SHA384',
|
|
|
+ 'ECDHE-ECDSA-AES256-GCM-SHA384',
|
|
|
+ 'DHE-RSA-AES128-GCM-SHA256',
|
|
|
+ 'DHE-DSS-AES128-GCM-SHA256',
|
|
|
+ 'kEDH+AESGCM',
|
|
|
+ 'ECDHE-RSA-AES128-SHA256',
|
|
|
+ 'ECDHE-ECDSA-AES128-SHA256',
|
|
|
+ 'ECDHE-RSA-AES128-SHA',
|
|
|
+ 'ECDHE-ECDSA-AES128-SHA',
|
|
|
+ 'ECDHE-RSA-AES256-SHA384',
|
|
|
+ 'ECDHE-ECDSA-AES256-SHA384',
|
|
|
+ 'ECDHE-RSA-AES256-SHA',
|
|
|
+ 'ECDHE-ECDSA-AES256-SHA',
|
|
|
+ 'DHE-RSA-AES128-SHA256',
|
|
|
+ 'DHE-RSA-AES128-SHA',
|
|
|
+ 'DHE-DSS-AES128-SHA256',
|
|
|
+ 'DHE-RSA-AES256-SHA256',
|
|
|
+ 'DHE-DSS-AES256-SHA',
|
|
|
+ 'DHE-RSA-AES256-SHA',
|
|
|
+ 'AES128-GCM-SHA256',
|
|
|
+ 'AES256-GCM-SHA384',
|
|
|
+ 'ECDHE-RSA-RC4-SHA',
|
|
|
+ 'ECDHE-ECDSA-RC4-SHA',
|
|
|
+ 'AES128',
|
|
|
+ 'AES256',
|
|
|
+ 'RC4-SHA',
|
|
|
+ 'HIGH',
|
|
|
+ '!aNULL',
|
|
|
+ '!eNULL',
|
|
|
+ '!EXPORT',
|
|
|
+ '!DES',
|
|
|
+ '!3DES',
|
|
|
+ '!MD5',
|
|
|
+ '!PSK'
|
|
|
+ ));
|
|
|
+
|
|
|
+ /**
|
|
|
+ * CN_match and SNI_server_name are only known once a URL is passed.
|
|
|
+ * They will be set in the getOptionsForUrl() method which receives a URL.
|
|
|
+ *
|
|
|
+ * cafile or capath can be overridden by passing in those options to constructor.
|
|
|
+ */
|
|
|
+ $options = array(
|
|
|
+ 'ssl' => array(
|
|
|
+ 'ciphers' => $ciphers,
|
|
|
+ 'verify_peer' => true,
|
|
|
+ 'verify_depth' => 7,
|
|
|
+ 'SNI_enabled' => true,
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Attempt to find a local cafile or throw an exception.
|
|
|
+ * The user may go download one if this occurs.
|
|
|
+ */
|
|
|
+ $result = $this->getSystemCaRootBundlePath();
|
|
|
+ if ($result) {
|
|
|
+ $options['ssl']['cafile'] = $result;
|
|
|
+ } else {
|
|
|
+ throw new TransportException('A valid cafile could not be located automatically.');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Disable TLS compression to prevent CRIME attacks where supported.
|
|
|
+ */
|
|
|
+ if (version_compare(PHP_VERSION, '5.4.13') >= 0) {
|
|
|
+ $options['ssl']['disable_compression'] = true;
|
|
|
+ }
|
|
|
+
|
|
|
return $options;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This method was adapted from Sslurp.
|
|
|
+ * https://github.com/EvanDotPro/Sslurp
|
|
|
+ *
|
|
|
+ * (c) Evan Coury <me@evancoury.com>
|
|
|
+ *
|
|
|
+ * For the full copyright and license information, please see below:
|
|
|
+ *
|
|
|
+ * Copyright (c) 2013, Evan Coury
|
|
|
+ * All rights reserved.
|
|
|
+ *
|
|
|
+ * Redistribution and use in source and binary forms, with or without modification,
|
|
|
+ * are permitted provided that the following conditions are met:
|
|
|
+ *
|
|
|
+ * * Redistributions of source code must retain the above copyright notice,
|
|
|
+ * this list of conditions and the following disclaimer.
|
|
|
+ *
|
|
|
+ * * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
+ * this list of conditions and the following disclaimer in the documentation
|
|
|
+ * and/or other materials provided with the distribution.
|
|
|
+ *
|
|
|
+ * 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
|
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
+ * 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
|
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
+ */
|
|
|
+ protected static function getSystemCaRootBundlePath()
|
|
|
+ {
|
|
|
+ if (isset($found)) {
|
|
|
+ return $found;
|
|
|
+ }
|
|
|
+ // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that.
|
|
|
+ // This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
|
|
|
+ $envCertFile = getenv('SSL_CERT_FILE');
|
|
|
+ if ($envCertFile && is_readable($envCertFile) && openssl_x509_parse(file_get_contents($envCertFile))) {
|
|
|
+ // Possibly throw exception instead of ignoring SSL_CERT_FILE if it's invalid?
|
|
|
+ return $envCertFile;
|
|
|
+ }
|
|
|
+
|
|
|
+ $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)
|
|
|
+ '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package)
|
|
|
+ '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package)
|
|
|
+ '/usr/ssl/certs/ca-bundle.crt', // Cygwin
|
|
|
+ '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package
|
|
|
+ '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option)
|
|
|
+ '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat?
|
|
|
+ );
|
|
|
+
|
|
|
+ static $found = false;
|
|
|
+ foreach ($caBundlePaths as $caBundle) {
|
|
|
+ if (is_readable($caBundle) && openssl_x509_parse(file_get_contents($caBundle))) {
|
|
|
+ $found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($found) {
|
|
|
+ $found = $caBundle;
|
|
|
+ }
|
|
|
+ return $found;
|
|
|
+ }
|
|
|
}
|