diff options
-rw-r--r-- | lib/private/integritycheck/checker.php | 32 | ||||
-rw-r--r-- | lib/private/integritycheck/helpers/environmenthelper.php | 9 | ||||
-rw-r--r-- | lib/private/updater.php | 4 | ||||
-rw-r--r-- | tests/lib/integritycheck/checkertest.php | 192 | ||||
-rw-r--r-- | tests/lib/integritycheck/helpers/EnvironmentHelperTest.php | 15 |
5 files changed, 248 insertions, 4 deletions
diff --git a/lib/private/integritycheck/checker.php b/lib/private/integritycheck/checker.php index d46b6d9b8fc..770b64c6b9d 100644 --- a/lib/private/integritycheck/checker.php +++ b/lib/private/integritycheck/checker.php @@ -82,6 +82,34 @@ class Checker { } /** + * Whether code signing is enforced or not. + * + * @return bool + */ + public function isCodeCheckEnforced() { + // FIXME: Once the signing server is instructed to sign daily, beta and + // RCs as well these need to be included also. + $signedChannels = [ + 'stable', + ]; + if(!in_array($this->environmentHelper->getChannel(), $signedChannels, true)) { + return false; + } + + /** + * This config option is undocumented and supposed to be so, it's only + * applicable for very specific scenarios and we should not advertise it + * too prominent. So please do not add it to config.sample.php. + */ + $isIntegrityCheckDisabled = $this->config->getSystemValue('integrity.check.disabled', false); + if($isIntegrityCheckDisabled === true) { + return false; + } + + return true; + } + + /** * Enumerates all files belonging to the folder. Sensible defaults are excluded. * * @param string $folderToIterate @@ -209,6 +237,10 @@ class Checker { * @throws \Exception */ private function verify($signaturePath, $basePath, $certificateCN) { + if(!$this->isCodeCheckEnforced()) { + return []; + } + $signatureData = json_decode($this->fileAccessHelper->file_get_contents($signaturePath), true); if(!is_array($signatureData)) { throw new InvalidSignatureException('Signature data not found.'); diff --git a/lib/private/integritycheck/helpers/environmenthelper.php b/lib/private/integritycheck/helpers/environmenthelper.php index b90e6ba9910..8bddcb3d794 100644 --- a/lib/private/integritycheck/helpers/environmenthelper.php +++ b/lib/private/integritycheck/helpers/environmenthelper.php @@ -36,4 +36,13 @@ class EnvironmentHelper { public function getServerRoot() { return \OC::$SERVERROOT; } + + /** + * Provides \OC_Util::getChannel() + * + * @return string + */ + public function getChannel() { + return \OC_Util::getChannel(); + } } diff --git a/lib/private/updater.php b/lib/private/updater.php index f3fa7de41ef..32264484ee3 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -345,8 +345,8 @@ class Updater extends BasicEmitter { //Invalidate update feed $this->config->setAppValue('core', 'lastupdatedat', 0); - // Check for code integrity on the stable channel - if(\OC_Util::getChannel() === 'stable') { + // Check for code integrity if not disabled + if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) { $this->emit('\OC\Updater', 'startCheckCodeIntegrity'); $this->checker->runInstanceVerification(); $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity'); diff --git a/tests/lib/integritycheck/checkertest.php b/tests/lib/integritycheck/checkertest.php index 17117a4274b..ed7ca4bceb8 100644 --- a/tests/lib/integritycheck/checkertest.php +++ b/tests/lib/integritycheck/checkertest.php @@ -120,6 +120,16 @@ class CheckerTest extends TestCase { } public function testVerifyAppSignatureWithoutSignatureData() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + $expected = [ 'EXCEPTION' => [ 'class' => 'OC\IntegrityCheck\Exceptions\InvalidSignatureException', @@ -130,6 +140,16 @@ class CheckerTest extends TestCase { } public function testVerifyAppSignatureWithValidSignatureData() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + $this->appLocator ->expects($this->once()) ->method('getAppPath') @@ -162,6 +182,16 @@ class CheckerTest extends TestCase { } public function testVerifyAppSignatureWithTamperedSignatureData() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + $this->appLocator ->expects($this->once()) ->method('getAppPath') @@ -200,6 +230,16 @@ class CheckerTest extends TestCase { } public function testVerifyAppSignatureWithTamperedFiles() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + $this->appLocator ->expects($this->once()) ->method('getAppPath') @@ -254,6 +294,16 @@ class CheckerTest extends TestCase { } public function testVerifyAppWithDifferentScope() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + $this->appLocator ->expects($this->once()) ->method('getAppPath') @@ -290,6 +340,16 @@ class CheckerTest extends TestCase { } public function testVerifyAppWithDifferentScopeAndAlwaysTrustedCore() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + $this->appLocator ->expects($this->once()) ->method('getAppPath') @@ -350,6 +410,16 @@ class CheckerTest extends TestCase { } public function testVerifyCoreSignatureWithoutSignatureData() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + $expected = [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', @@ -361,6 +431,16 @@ class CheckerTest extends TestCase { public function testVerifyCoreSignatureWithValidSignatureData() { $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + + $this->environmentHelper ->expects($this->any()) ->method('getServerRoot') ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/')); @@ -392,6 +472,16 @@ class CheckerTest extends TestCase { public function testVerifyCoreSignatureWithValidSignatureDataAndNotAlphabeticOrder() { $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + + $this->environmentHelper ->expects($this->any()) ->method('getServerRoot') ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/')); @@ -423,6 +513,16 @@ class CheckerTest extends TestCase { public function testVerifyCoreSignatureWithTamperedSignatureData() { $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + + $this->environmentHelper ->expects($this->any()) ->method('getServerRoot') ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/')); @@ -460,6 +560,16 @@ class CheckerTest extends TestCase { public function testVerifyCoreSignatureWithTamperedFiles() { $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + + $this->environmentHelper ->expects($this->any()) ->method('getServerRoot') ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/')); @@ -512,6 +622,16 @@ class CheckerTest extends TestCase { public function testVerifyCoreWithInvalidCertificate() { $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + + $this->environmentHelper ->expects($this->any()) ->method('getServerRoot') ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/')); @@ -549,6 +669,16 @@ class CheckerTest extends TestCase { public function testVerifyCoreWithDifferentScope() { $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + + $this->environmentHelper ->expects($this->any()) ->method('getServerRoot') ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/')); @@ -668,4 +798,66 @@ class CheckerTest extends TestCase { $this->checker->runInstanceVerification(); } + public function testVerifyAppSignatureWithoutSignatureDataAndCodeCheckerDisabled() { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue('stable')); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(true)); + + $expected = []; + $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); + } + + /** + * @return array + */ + public function channelDataProvider() { + return [ + ['stable', true], + ['git', false], + ]; + } + + /** + * @param string $channel + * @param bool $isCodeSigningEnforced + * @dataProvider channelDataProvider + */ + public function testIsCodeCheckEnforced($channel, $isCodeSigningEnforced) { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue($channel)); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(false)); + + $this->assertSame($isCodeSigningEnforced, $this->checker->isCodeCheckEnforced()); + } + + /** + * @param string $channel + * @dataProvider channelDataProvider + */ + public function testIsCodeCheckEnforcedWithDisabledConfigSwitch($channel) { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->will($this->returnValue($channel)); + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('integrity.check.disabled', false) + ->will($this->returnValue(true)); + + $result = $this->invokePrivate($this->checker, 'isCodeCheckEnforced'); + $this->assertSame(false, $result); + } } diff --git a/tests/lib/integritycheck/helpers/EnvironmentHelperTest.php b/tests/lib/integritycheck/helpers/EnvironmentHelperTest.php index 4a292188e75..a1d1f671b07 100644 --- a/tests/lib/integritycheck/helpers/EnvironmentHelperTest.php +++ b/tests/lib/integritycheck/helpers/EnvironmentHelperTest.php @@ -25,8 +25,19 @@ use OC\IntegrityCheck\Helpers\EnvironmentHelper; use Test\TestCase; class EnvironmentHelperTest extends TestCase { + /** @var EnvironmentHelper */ + private $environmentHelper; + + public function setUp() { + $this->environmentHelper = new EnvironmentHelper(); + return parent::setUp(); + } + public function testGetServerRoot() { - $factory = new EnvironmentHelper(); - $this->assertSame(\OC::$SERVERROOT, $factory->getServerRoot()); + $this->assertSame(\OC::$SERVERROOT, $this->environmentHelper->getServerRoot()); + } + + public function testGetChannel() { + $this->assertSame(\OC_Util::getChannel(), $this->environmentHelper->getChannel()); } } |