Skip to content
Snippets Groups Projects
Commit 0d515de1 authored by Lukas Reschke's avatar Lukas Reschke
Browse files

Detect old NSS and OpenSSL versions

This will detect old NSS and OpenSSL versions and show appropriate errors in the admin interface.

Fixes https://github.com/owncloud/core/issues/17901
parent c34e63bb
No related branches found
No related tags found
No related merge requests found
......@@ -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})
);
}
if(data.isUsedTlsLibOutdated) {
messages.push(data.isUsedTlsLibOutdated);
}
} else {
messages.push(t('core', 'Error occurred while checking server setup'));
}
......
......@@ -154,7 +154,8 @@ class Application extends App {
$c->query('Config'),
$c->query('ClientService'),
$c->query('URLGenerator'),
$c->query('Util')
$c->query('Util'),
$c->query('L10N')
);
});
......
......@@ -23,10 +23,12 @@
namespace OC\Settings\Controller;
use GuzzleHttp\Exception\ClientException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
use OC_Util;
use OCP\IURLGenerator;
......@@ -43,6 +45,8 @@ class CheckSetupController extends Controller {
private $util;
/** @var IURLGenerator */
private $urlGenerator;
/** @var IL10N */
private $l10n;
/**
* @param string $AppName
......@@ -51,18 +55,21 @@ class CheckSetupController extends Controller {
* @param IClientService $clientService
* @param IURLGenerator $urlGenerator
* @param \OC_Util $util
* @param IL10N $l10n
*/
public function __construct($AppName,
IRequest $request,
IConfig $config,
IClientService $clientService,
IURLGenerator $urlGenerator,
\OC_Util $util) {
\OC_Util $util,
IL10N $l10n) {
parent::__construct($AppName, $request);
$this->config = $config;
$this->clientService = $clientService;
$this->util = $util;
$this->urlGenerator = $urlGenerator;
$this->l10n = $l10n;
}
/**
......@@ -109,6 +116,66 @@ class CheckSetupController extends Controller {
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
*/
......@@ -121,6 +188,7 @@ class CheckSetupController extends Controller {
'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
'isUrandomAvailable' => $this->isUrandomAvailable(),
'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
]
);
}
......
......@@ -24,6 +24,7 @@ namespace OC\Settings\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IURLGenerator;
use OC_Util;
......@@ -47,6 +48,8 @@ class CheckSetupControllerTest extends TestCase {
private $urlGenerator;
/** @var OC_Util */
private $util;
/** @var IL10N */
private $l10n;
public function setUp() {
parent::setUp();
......@@ -63,15 +66,24 @@ class CheckSetupControllerTest extends TestCase {
->disableOriginalConstructor()->getMock();
$this->urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator')
->disableOriginalConstructor()->getMock();
$this->checkSetupController = new CheckSetupController(
'settings',
$this->request,
$this->config,
$this->clientService,
$this->urlGenerator,
$this->util
);
$this->l10n = $this->getMockBuilder('\OCP\IL10N')
->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',
$this->request,
$this->config,
$this->clientService,
$this->urlGenerator,
$this->util,
$this->l10n,
])
->setMethods(['getCurlVersion'])->getMock();
}
public function testIsInternetConnectionWorkingDisabledViaConfig() {
......@@ -241,8 +253,134 @@ class CheckSetupControllerTest extends TestCase {
'memcacheDocs' => 'http://doc.owncloud.org/server/go.php?to=admin-performance',
'isUrandomAvailable' => self::invokePrivate($this->checkSetupController, 'isUrandomAvailable'),
'securityDocs' => 'https://doc.owncloud.org/server/8.1/admin_manual/configuration_server/hardening.html',
'isUsedTlsLibOutdated' => '',
]
);
$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