Skip to content
Snippets Groups Projects
Commit 6d54d2fa authored by Robin McCorkell's avatar Robin McCorkell
Browse files

Merge pull request #17912 from owncloud/detect-old-openssl-versions

Detect old NSS and OpenSSL versions
parents 6f72c374 0d515de1
No related branches found
No related tags found
No related merge requests found
...@@ -69,6 +69,9 @@ ...@@ -69,6 +69,9 @@
t('core', '/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href="{docLink}">documentation</a>.', {docLink: data.securityDocs}) t('core', '/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a href="{docLink}">documentation</a>.', {docLink: data.securityDocs})
); );
} }
if(data.isUsedTlsLibOutdated) {
messages.push(data.isUsedTlsLibOutdated);
}
} else { } else {
messages.push(t('core', 'Error occurred while checking server setup')); messages.push(t('core', 'Error occurred while checking server setup'));
} }
......
...@@ -154,7 +154,8 @@ class Application extends App { ...@@ -154,7 +154,8 @@ class Application extends App {
$c->query('Config'), $c->query('Config'),
$c->query('ClientService'), $c->query('ClientService'),
$c->query('URLGenerator'), $c->query('URLGenerator'),
$c->query('Util') $c->query('Util'),
$c->query('L10N')
); );
}); });
......
...@@ -23,10 +23,12 @@ ...@@ -23,10 +23,12 @@
namespace OC\Settings\Controller; namespace OC\Settings\Controller;
use GuzzleHttp\Exception\ClientException;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\IConfig; use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest; use OCP\IRequest;
use OC_Util; use OC_Util;
use OCP\IURLGenerator; use OCP\IURLGenerator;
...@@ -43,6 +45,8 @@ class CheckSetupController extends Controller { ...@@ -43,6 +45,8 @@ class CheckSetupController extends Controller {
private $util; private $util;
/** @var IURLGenerator */ /** @var IURLGenerator */
private $urlGenerator; private $urlGenerator;
/** @var IL10N */
private $l10n;
/** /**
* @param string $AppName * @param string $AppName
...@@ -51,18 +55,21 @@ class CheckSetupController extends Controller { ...@@ -51,18 +55,21 @@ class CheckSetupController extends Controller {
* @param IClientService $clientService * @param IClientService $clientService
* @param IURLGenerator $urlGenerator * @param IURLGenerator $urlGenerator
* @param \OC_Util $util * @param \OC_Util $util
* @param IL10N $l10n
*/ */
public function __construct($AppName, public function __construct($AppName,
IRequest $request, IRequest $request,
IConfig $config, IConfig $config,
IClientService $clientService, IClientService $clientService,
IURLGenerator $urlGenerator, IURLGenerator $urlGenerator,
\OC_Util $util) { \OC_Util $util,
IL10N $l10n) {
parent::__construct($AppName, $request); parent::__construct($AppName, $request);
$this->config = $config; $this->config = $config;
$this->clientService = $clientService; $this->clientService = $clientService;
$this->util = $util; $this->util = $util;
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
$this->l10n = $l10n;
} }
/** /**
...@@ -109,6 +116,66 @@ class CheckSetupController extends Controller { ...@@ -109,6 +116,66 @@ class CheckSetupController extends Controller {
return false; return false;
} }
/**
* Public for the sake of unit-testing
*
* @return array
*/
public function getCurlVersion() {
return curl_version();
}
/**
* Check if the used SSL lib is outdated. Older OpenSSL and NSS versions do
* have multiple bugs which likely lead to problems in combination with
* functionalities required by ownCloud such as SNI.
*
* @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
* @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
* @return string
*/
private function isUsedTlsLibOutdated() {
$versionString = $this->getCurlVersion();
if(isset($versionString['ssl_version'])) {
$versionString = $versionString['ssl_version'];
} else {
return '';
}
$features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
if(OC_Util::getEditionString() !== '') {
$features = (string)$this->l10n->t('Federated Cloud Sharing');
}
// Check if at least OpenSSL after 1.01d or 1.0.2b
if(strpos($versionString, 'OpenSSL/') === 0) {
$majorVersion = substr($versionString, 8, 5);
$patchRelease = substr($versionString, 13, 6);
if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['OpenSSL', $versionString, $features]);
}
}
// Check if NSS and perform heuristic check
if(strpos($versionString, 'NSS/') === 0) {
try {
$firstClient = $this->clientService->newClient();
$firstClient->get('https://www.owncloud.org/');
$secondClient = $this->clientService->newClient();
$secondClient->get('https://owncloud.org/');
} catch (ClientException $e) {
if($e->getResponse()->getStatusCode() === 400) {
return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['NSS', $versionString, $features]);
}
}
}
return '';
}
/** /**
* @return DataResponse * @return DataResponse
*/ */
...@@ -121,6 +188,7 @@ class CheckSetupController extends Controller { ...@@ -121,6 +188,7 @@ class CheckSetupController extends Controller {
'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'), 'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
'isUrandomAvailable' => $this->isUrandomAvailable(), 'isUrandomAvailable' => $this->isUrandomAvailable(),
'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'), 'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
] ]
); );
} }
......
...@@ -24,6 +24,7 @@ namespace OC\Settings\Controller; ...@@ -24,6 +24,7 @@ namespace OC\Settings\Controller;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\IConfig; use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest; use OCP\IRequest;
use OCP\IURLGenerator; use OCP\IURLGenerator;
use OC_Util; use OC_Util;
...@@ -47,6 +48,8 @@ class CheckSetupControllerTest extends TestCase { ...@@ -47,6 +48,8 @@ class CheckSetupControllerTest extends TestCase {
private $urlGenerator; private $urlGenerator;
/** @var OC_Util */ /** @var OC_Util */
private $util; private $util;
/** @var IL10N */
private $l10n;
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
...@@ -63,15 +66,24 @@ class CheckSetupControllerTest extends TestCase { ...@@ -63,15 +66,24 @@ class CheckSetupControllerTest extends TestCase {
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();
$this->urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator') $this->urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator')
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();
$this->l10n = $this->getMockBuilder('\OCP\IL10N')
$this->checkSetupController = new CheckSetupController( ->disableOriginalConstructor()->getMock();
$this->l10n->expects($this->any())
->method('t')
->will($this->returnCallback(function($message, array $replace) {
return vsprintf($message, $replace);
}));
$this->checkSetupController = $this->getMockBuilder('\OC\Settings\Controller\CheckSetupController')
->setConstructorArgs([
'settings', 'settings',
$this->request, $this->request,
$this->config, $this->config,
$this->clientService, $this->clientService,
$this->urlGenerator, $this->urlGenerator,
$this->util $this->util,
); $this->l10n,
])
->setMethods(['getCurlVersion'])->getMock();
} }
public function testIsInternetConnectionWorkingDisabledViaConfig() { public function testIsInternetConnectionWorkingDisabledViaConfig() {
...@@ -241,8 +253,134 @@ class CheckSetupControllerTest extends TestCase { ...@@ -241,8 +253,134 @@ class CheckSetupControllerTest extends TestCase {
'memcacheDocs' => 'http://doc.owncloud.org/server/go.php?to=admin-performance', 'memcacheDocs' => 'http://doc.owncloud.org/server/go.php?to=admin-performance',
'isUrandomAvailable' => self::invokePrivate($this->checkSetupController, 'isUrandomAvailable'), 'isUrandomAvailable' => self::invokePrivate($this->checkSetupController, 'isUrandomAvailable'),
'securityDocs' => 'https://doc.owncloud.org/server/8.1/admin_manual/configuration_server/hardening.html', 'securityDocs' => 'https://doc.owncloud.org/server/8.1/admin_manual/configuration_server/hardening.html',
'isUsedTlsLibOutdated' => '',
] ]
); );
$this->assertEquals($expected, $this->checkSetupController->check()); $this->assertEquals($expected, $this->checkSetupController->check());
} }
public function testGetCurlVersion() {
$checkSetupController = $this->getMockBuilder('\OC\Settings\Controller\CheckSetupController')
->setConstructorArgs([
'settings',
$this->request,
$this->config,
$this->clientService,
$this->urlGenerator,
$this->util,
$this->l10n,
])
->setMethods(null)->getMock();
$this->assertArrayHasKey('ssl_version', $checkSetupController->getCurlVersion());
}
public function testIsUsedTlsLibOutdatedWithAnotherLibrary() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue(['ssl_version' => 'SSLlib']));
$this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
public function testIsUsedTlsLibOutdatedWithMisbehavingCurl() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue([]));
$this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
public function testIsUsedTlsLibOutdatedWithOlderOpenSsl() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.1c']));
$this->assertSame('cURL is using an outdated OpenSSL version (OpenSSL/1.0.1c). Please update your operating system or features such as installing and updating apps via the app store or Federated Cloud Sharing will not work reliably.', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
public function testIsUsedTlsLibOutdatedWithOlderOpenSsl1() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.2a']));
$this->assertSame('cURL is using an outdated OpenSSL version (OpenSSL/1.0.2a). Please update your operating system or features such as installing and updating apps via the app store or Federated Cloud Sharing will not work reliably.', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
public function testIsUsedTlsLibOutdatedWithMatchingOpenSslVersion() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.1d']));
$this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
public function testIsUsedTlsLibOutdatedWithMatchingOpenSslVersion1() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.2b']));
$this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
public function testIsBuggyNss400() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue(['ssl_version' => 'NSS/1.0.2b']));
$client = $this->getMockBuilder('\OCP\Http\Client\IClient')
->disableOriginalConstructor()->getMock();
$exception = $this->getMockBuilder('\GuzzleHttp\Exception\ClientException')
->disableOriginalConstructor()->getMock();
$response = $this->getMockBuilder('\GuzzleHttp\Message\ResponseInterface')
->disableOriginalConstructor()->getMock();
$response->expects($this->once())
->method('getStatusCode')
->will($this->returnValue(400));
$exception->expects($this->once())
->method('getResponse')
->will($this->returnValue($response));
$client->expects($this->at(0))
->method('get')
->with('https://www.owncloud.org/', [])
->will($this->throwException($exception));
$this->clientService->expects($this->once())
->method('newClient')
->will($this->returnValue($client));
$this->assertSame('cURL is using an outdated NSS version (NSS/1.0.2b). Please update your operating system or features such as installing and updating apps via the app store or Federated Cloud Sharing will not work reliably.', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
public function testIsBuggyNss200() {
$this->checkSetupController
->expects($this->once())
->method('getCurlVersion')
->will($this->returnValue(['ssl_version' => 'NSS/1.0.2b']));
$client = $this->getMockBuilder('\OCP\Http\Client\IClient')
->disableOriginalConstructor()->getMock();
$exception = $this->getMockBuilder('\GuzzleHttp\Exception\ClientException')
->disableOriginalConstructor()->getMock();
$response = $this->getMockBuilder('\GuzzleHttp\Message\ResponseInterface')
->disableOriginalConstructor()->getMock();
$response->expects($this->once())
->method('getStatusCode')
->will($this->returnValue(200));
$exception->expects($this->once())
->method('getResponse')
->will($this->returnValue($response));
$client->expects($this->at(0))
->method('get')
->with('https://www.owncloud.org/', [])
->will($this->throwException($exception));
$this->clientService->expects($this->once())
->method('newClient')
->will($this->returnValue($client));
$this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated'));
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment