private function rsa($public_or_private_key, $padding_mode) { if ($public_or_private_key instanceof JOSE_JWK) { $rsa = $public_or_private_key->toKey(); } else { if ($public_or_private_key instanceof RSA) { $rsa = $public_or_private_key; } else { $rsa = new RSA(); $rsa->loadKey($public_or_private_key); } } $rsa->setHash($this->digest()); $rsa->setMGFHash($this->digest()); $rsa->setSignatureMode($padding_mode); return $rsa; }
private function rsa($public_or_private_key, $padding_mode) { if ($public_or_private_key instanceof JOSE_JWK) { $rsa = $public_or_private_key->toKey(); } else { if ($public_or_private_key instanceof RSA) { $rsa = $public_or_private_key; } else { $rsa = new RSA(); $rsa->loadKey($public_or_private_key); } } $rsa->setHash($this->digest()); $rsa->setMGFHash($this->digest()); $rsa->setSaltLength(false); # NOTE: https://github.com/phpseclib/phpseclib/issues/768 $rsa->setSignatureMode($padding_mode); return $rsa; }
/** * 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; }
/** * Creates the signature data * * @param array $hashes * @param X509 $certificate * @param RSA $privateKey * @return string */ private function createSignatureData(array $hashes, X509 $certificate, RSA $privateKey) { ksort($hashes); $privateKey->setSignatureMode(RSA::SIGNATURE_PSS); $privateKey->setMGFHash('sha512'); $signature = $privateKey->sign(json_encode($hashes)); return ['hashes' => $hashes, 'signature' => base64_encode($signature), 'certificate' => $certificate->saveX509($certificate->currentCert)]; }
/** * Decrypt with RSAES-OAEP + MGF1+SHA256 * * @param string $ciphertext * @param PrivateKey $rsaPrivateKey * @return string * @throws InvalidCiphertextException */ protected static function rsaDecrypt($ciphertext, PrivateKey $rsaPrivateKey) { static $rsa = null; if (!$rsa) { $rsa = new RSA(); $rsa->setEncryptionMode(RSA::ENCRYPTION_OAEP); $rsa->setMGFHash('sha256'); } $rsa->loadKey($rsaPrivateKey->getKey()); $return = @$rsa->decrypt($ciphertext); if ($return === false) { throw new InvalidCiphertextException('Decryption failed'); } return $return; }