function isSigned($caPath) { $x509 = new X509(); $x509->loadX509($this->contents); foreach (glob($caPath) as $ca) { $x509->loadCA(file_get_contents($ca)); } return $x509->validateSignature(); }
/** * Verifies the signature for the specified path. * * @param string $signaturePath * @param string $basePath * @param string $certificateCN * @return array * @throws InvalidSignatureException * @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.'); } $expectedHashes = $signatureData['hashes']; ksort($expectedHashes); $signature = base64_decode($signatureData['signature']); $certificate = $signatureData['certificate']; // Check if certificate is signed by ownCloud Root Authority $x509 = new \phpseclib\File\X509(); $rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot() . '/resources/codesigning/root.crt'); $x509->loadCA($rootCertificatePublicKey); $x509->loadX509($certificate); if (!$x509->validateSignature()) { throw new InvalidSignatureException('Certificate is not valid.'); } // Verify if certificate has proper CN. "core" CN is always trusted. if ($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') { throw new InvalidSignatureException(sprintf('Certificate is not valid for required scope. (Requested: %s, current: %s)', $certificateCN, $x509->getDN(true))); } // Check if the signature of the files is valid $rsa = new \phpseclib\Crypt\RSA(); $rsa->loadKey($x509->currentCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']); $rsa->setSignatureMode(RSA::SIGNATURE_PSS); $rsa->setMGFHash('sha512'); if (!$rsa->verify(json_encode($expectedHashes), $signature)) { throw new InvalidSignatureException('Signature could not get verified.'); } // Compare the list of files which are not identical $currentInstanceHashes = $this->generateHashes($this->getFolderIterator($basePath), $basePath); $differencesA = array_diff($expectedHashes, $currentInstanceHashes); $differencesB = array_diff($currentInstanceHashes, $expectedHashes); $differences = array_unique(array_merge($differencesA, $differencesB)); $differenceArray = []; foreach ($differences as $filename => $hash) { // Check if file should not exist in the new signature table if (!array_key_exists($filename, $expectedHashes)) { $differenceArray['EXTRA_FILE'][$filename]['expected'] = ''; $differenceArray['EXTRA_FILE'][$filename]['current'] = $hash; continue; } // Check if file is missing if (!array_key_exists($filename, $currentInstanceHashes)) { $differenceArray['FILE_MISSING'][$filename]['expected'] = $expectedHashes[$filename]; $differenceArray['FILE_MISSING'][$filename]['current'] = ''; continue; } // Check if hash does mismatch if ($expectedHashes[$filename] !== $currentInstanceHashes[$filename]) { $differenceArray['INVALID_HASH'][$filename]['expected'] = $expectedHashes[$filename]; $differenceArray['INVALID_HASH'][$filename]['current'] = $currentInstanceHashes[$filename]; continue; } // Should never happen. throw new \Exception('Invalid behaviour in file hash comparison experienced. Please report this error to the developers.'); } return $differenceArray; }