Merge pull request #10482 from cakephp/issue-10232

Fix CakeSocket not being able to connect to TLS1.2 only servers
This commit is contained in:
Mark Story 2017-04-06 15:35:45 -04:00 committed by GitHub
commit 0a378021a0
3 changed files with 65 additions and 9 deletions

View file

@ -44,7 +44,8 @@ class CakeSocket {
'host' => 'localhost', 'host' => 'localhost',
'protocol' => 'tcp', 'protocol' => 'tcp',
'port' => 80, 'port' => 80,
'timeout' => 30 'timeout' => 30,
'cryptoType' => 'tls',
); );
/** /**
@ -96,7 +97,7 @@ class CakeSocket {
'sslv2_server' => STREAM_CRYPTO_METHOD_SSLv2_SERVER, 'sslv2_server' => STREAM_CRYPTO_METHOD_SSLv2_SERVER,
'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER, 'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER,
'sslv23_server' => STREAM_CRYPTO_METHOD_SSLv23_SERVER, 'sslv23_server' => STREAM_CRYPTO_METHOD_SSLv23_SERVER,
'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER 'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER,
// @codingStandardsIgnoreEnd // @codingStandardsIgnoreEnd
); );
@ -116,6 +117,44 @@ class CakeSocket {
*/ */
public function __construct($config = array()) { public function __construct($config = array()) {
$this->config = array_merge($this->_baseConfig, $config); $this->config = array_merge($this->_baseConfig, $config);
$this->_addTlsVersions();
}
/**
* Add TLS versions that are dependent on specific PHP versions.
*
* These TLS versions are not supported by older PHP versions,
* so we have to conditionally set them if they are supported.
*
* As of PHP5.6.6, STREAM_CRYPTO_METHOD_TLS_CLIENT does not include
* TLS1.1 or 1.2. If we have TLS1.2 support we need to update the method map.
*
* @see https://bugs.php.net/bug.php?id=69195
* @see https://github.com/php/php-src/commit/10bc5fd4c4c8e1dd57bd911b086e9872a56300a0
* @return void
*/
protected function _addTlsVersions() {
$conditionalCrypto = array(
'tlsv1_1_client' => 'STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT',
'tlsv1_2_client' => 'STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT',
'tlsv1_1_server' => 'STREAM_CRYPTO_METHOD_TLSv1_1_SERVER',
'tlsv1_2_server' => 'STREAM_CRYPTO_METHOD_TLSv1_2_SERVER'
);
foreach ($conditionalCrypto as $key => $const) {
if (defined($const)) {
$this->_encryptMethods[$key] = constant($const);
}
}
// @codingStandardsIgnoreStart
if (isset($this->_encryptMethods['tlsv1_2_client'])) {
$this->_encryptMethods['tls_client'] = STREAM_CRYPTO_METHOD_TLS_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
}
if (isset($this->_encryptMethods['tlsv1_2_server'])) {
$this->_encryptMethods['tls_server'] = STREAM_CRYPTO_METHOD_TLS_SERVER | STREAM_CRYPTO_METHOD_TLSv1_1_SERVER | STREAM_CRYPTO_METHOD_TLSv1_2_SERVER;
}
// @codingStandardsIgnoreEnd
} }
/** /**
@ -205,7 +244,7 @@ class CakeSocket {
} }
} }
$this->enableCrypto('tls', 'client'); $this->enableCrypto($this->config['cryptoType'], 'client');
} }
} }
return $this->connected; return $this->connected;
@ -433,7 +472,7 @@ class CakeSocket {
/** /**
* Encrypts current stream socket, using one of the defined encryption methods. * Encrypts current stream socket, using one of the defined encryption methods.
* *
* @param string $type Type which can be one of 'sslv2', 'sslv3', 'sslv23' or 'tls'. * @param string $type Type which can be one of 'sslv2', 'sslv3', 'sslv23', 'tls', 'tlsv1_1' or 'tlsv1_2'.
* @param string $clientOrServer Can be one of 'client', 'server'. Default is 'client'. * @param string $clientOrServer Can be one of 'client', 'server'. Default is 'client'.
* @param bool $enable Enable or disable encryption. Default is true (enable) * @param bool $enable Enable or disable encryption. Default is true (enable)
* @return bool True on success * @return bool True on success

View file

@ -54,11 +54,12 @@ class CakeSocketTest extends CakeTestCase {
$this->Socket = new CakeSocket(); $this->Socket = new CakeSocket();
$config = $this->Socket->config; $config = $this->Socket->config;
$this->assertSame($config, array( $this->assertSame($config, array(
'persistent' => false, 'persistent' => false,
'host' => 'localhost', 'host' => 'localhost',
'protocol' => 'tcp', 'protocol' => 'tcp',
'port' => 80, 'port' => 80,
'timeout' => 30 'timeout' => 30,
'cryptoType' => 'tls',
)); ));
$this->Socket->reset(); $this->Socket->reset();
@ -324,6 +325,20 @@ class CakeSocketTest extends CakeTestCase {
$this->Socket->disconnect(); $this->Socket->disconnect();
} }
/**
* testEnableCrypto tlsv1_1
*
* @return void
*/
public function testEnableCryptoTlsV11() {
$this->skipIf(!defined('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT'), 'TLS1.1 is not supported on this system');
// testing on tls server
$this->_connectSocketToSslTls();
$this->assertTrue($this->Socket->enableCrypto('tlsv1_1', 'client'));
$this->Socket->disconnect();
}
/** /**
* testEnableCryptoExceptionEnableTwice * testEnableCryptoExceptionEnableTwice
* *

View file

@ -215,11 +215,13 @@ class HttpSocketTest extends CakeTestCase {
$this->Socket->expects($this->never())->method('connect'); $this->Socket->expects($this->never())->method('connect');
$this->Socket->__construct(array('host' => 'foo-bar')); $this->Socket->__construct(array('host' => 'foo-bar'));
$baseConfig['host'] = 'foo-bar'; $baseConfig['host'] = 'foo-bar';
$baseConfig['cryptoType'] = 'tls';
$this->assertEquals($this->Socket->config, $baseConfig); $this->assertEquals($this->Socket->config, $baseConfig);
$this->Socket->reset(); $this->Socket->reset();
$baseConfig = $this->Socket->config; $baseConfig = $this->Socket->config;
$this->Socket->__construct('http://www.cakephp.org:23/'); $this->Socket->__construct('http://www.cakephp.org:23/');
$baseConfig['cryptoType'] = 'tls';
$baseConfig['host'] = $baseConfig['request']['uri']['host'] = 'www.cakephp.org'; $baseConfig['host'] = $baseConfig['request']['uri']['host'] = 'www.cakephp.org';
$baseConfig['port'] = $baseConfig['request']['uri']['port'] = 23; $baseConfig['port'] = $baseConfig['request']['uri']['port'] = 23;
$baseConfig['request']['uri']['scheme'] = 'http'; $baseConfig['request']['uri']['scheme'] = 'http';