Skip to content

Commit

Permalink
feat(deps): Upgrade phpseclib to v3
Browse files Browse the repository at this point in the history
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
  • Loading branch information
susnux committed Nov 5, 2024
1 parent 093ed1e commit d9d7046
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 84 deletions.
2 changes: 1 addition & 1 deletion 3rdparty
Submodule 3rdparty updated 358 files
4 changes: 1 addition & 3 deletions apps/encryption/lib/Crypto/Crypt.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use OCP\IConfig;
use OCP\IL10N;
use OCP\IUserSession;
use phpseclib\Crypt\RC4;
use phpseclib3\Crypt\RC4;
use Psr\Log\LoggerInterface;

/**
Expand Down Expand Up @@ -724,7 +724,6 @@ public function useLegacyBase64Encoding(): bool {
*/
private function rc4Decrypt(string $data, string $secret): string {
$rc4 = new RC4();
/** @psalm-suppress InternalMethod */
$rc4->setKey($secret);

return $rc4->decrypt($data);
Expand All @@ -735,7 +734,6 @@ private function rc4Decrypt(string $data, string $secret): string {
*/
private function rc4Encrypt(string $data, string $secret): string {
$rc4 = new RC4();
/** @psalm-suppress InternalMethod */
$rc4->setKey($secret);

return $rc4->encrypt($data);
Expand Down
18 changes: 10 additions & 8 deletions apps/files_external/lib/Controller/AjaxController.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@ public function __construct(
*/
private function generateSshKeys($keyLength) {
$key = $this->rsaMechanism->createKey($keyLength);
// Replace the placeholder label with a more meaningful one
$key['publickey'] = str_replace('phpseclib-generated-key', gethostname(), $key['publickey']);

return $key;
return [
'private_key' => $key->toString('PKCS1'),
// Replace the placeholder label with a more meaningful one
'public_key' => str_replace(
'phpseclib-generated-key',
gethostname(),
$key->getPublicKey()->toString('OpenSSH'),
),
];
}

/**
Expand All @@ -57,10 +62,7 @@ private function generateSshKeys($keyLength) {
public function getSshKeys($keyLength = 1024) {
$key = $this->generateSshKeys($keyLength);
return new JSONResponse(
['data' => [
'private_key' => $key['privatekey'],
'public_key' => $key['publickey']
],
['data' => $key,
'status' => 'success'
]);
}
Expand Down
27 changes: 13 additions & 14 deletions apps/files_external/lib/Lib/Auth/PublicKey/RSA.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use OCP\IConfig;
use OCP\IL10N;
use OCP\IUser;
use phpseclib\Crypt\RSA as RSACrypt;
use phpseclib3\Crypt\RSA as RSACrypt;

/**
* RSA public key authentication
Expand Down Expand Up @@ -41,33 +41,32 @@ public function __construct(
* @return void
*/
public function manipulateStorageConfig(StorageConfig &$storage, ?IUser $user = null) {
$auth = new RSACrypt();
$auth->setPassword($this->config->getSystemValue('secret', ''));
if (!$auth->loadKey($storage->getBackendOption('private_key'))) {
try {
$auth = RSACrypt::loadPrivateKey(
$storage->getBackendOption('private_key'),
$this->config->getSystemValue('secret', '')
);
} catch (\Throwable) {
// Add fallback routine for a time where secret was not enforced to be exists
$auth->setPassword('');
if (!$auth->loadKey($storage->getBackendOption('private_key'))) {
throw new \RuntimeException('unable to load private key');
}
$auth = RSACrypt::loadPrivateKey($storage->getBackendOption('private_key'));
}

$storage->setBackendOption('public_key_auth', $auth);
}

/**
* Generate a keypair
*
* @param int $keyLenth
* @return array ['privatekey' => $privateKey, 'publickey' => $publicKey]
*/
public function createKey($keyLength) {
public function createKey($keyLength): RSACrypt\PrivateKey {
$rsa = new RSACrypt();

Check failure on line 63 in apps/files_external/lib/Lib/Auth/PublicKey/RSA.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

AbstractInstantiation

apps/files_external/lib/Lib/Auth/PublicKey/RSA.php:63:10: AbstractInstantiation: Unable to instantiate a abstract class phpseclib3\Crypt\RSA (see https://psalm.dev/072)
$rsa->setPublicKeyFormat(RSACrypt::PUBLIC_FORMAT_OPENSSH);
$rsa->setPassword($this->config->getSystemValue('secret', ''));


if ($keyLength !== 1024 && $keyLength !== 2048 && $keyLength !== 4096) {
$keyLength = 1024;
}

return $rsa->createKey($keyLength);
return $rsa->createKey($keyLength)
->withPassword($this->config->getSystemValue('secret', ''));
}
}
7 changes: 3 additions & 4 deletions core/Command/Integrity/SignApp.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
use OC\IntegrityCheck\Checker;
use OC\IntegrityCheck\Helpers\FileAccessHelper;
use OCP\IURLGenerator;
use phpseclib\Crypt\RSA;
use phpseclib\File\X509;
use phpseclib3\Crypt\RSA;
use phpseclib3\File\X509;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
Expand Down Expand Up @@ -68,8 +68,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 1;
}

$rsa = new RSA();
$rsa->loadKey($privateKey);
$rsa = RSA::loadPrivateKey($privateKey);
$x509 = new X509();
$x509->loadX509($keyBundle);
$x509->setPrivateKey($rsa);
Expand Down
7 changes: 3 additions & 4 deletions core/Command/Integrity/SignCore.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

use OC\IntegrityCheck\Checker;
use OC\IntegrityCheck\Helpers\FileAccessHelper;
use phpseclib\Crypt\RSA;
use phpseclib\File\X509;
use phpseclib3\Crypt\RSA;
use phpseclib3\File\X509;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
Expand Down Expand Up @@ -63,8 +63,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 1;
}

$rsa = new RSA();
$rsa->loadKey($privateKey);
$rsa = RSA::loadPrivateKey($privateKey);
$x509 = new X509();
$x509->loadX509($keyBundle);
$x509->setPrivateKey($rsa);
Expand Down
2 changes: 1 addition & 1 deletion lib/private/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
use OCP\IConfig;
use OCP\ITempManager;
use OCP\Migration\IOutput;
use phpseclib\File\X509;
use phpseclib3\File\X509;
use Psr\Log\LoggerInterface;

/**
Expand Down
56 changes: 31 additions & 25 deletions lib/private/IntegrityCheck/Checker.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\ServerVersion;
use phpseclib\Crypt\RSA;
use phpseclib\File\X509;
use phpseclib3\Crypt\RSA;
use phpseclib3\File\X509;

/**
* Class Checker handles the code signing using X.509 and RSA. ownCloud ships with
Expand Down Expand Up @@ -167,24 +167,26 @@ private function generateHashes(\RecursiveIteratorIterator $iterator,
*
* @param array $hashes
* @param X509 $certificate
* @param RSA $privateKey
* @param RSA\PrivateKey $privateKey
* @return array
*/
private function createSignatureData(array $hashes,
private function createSignatureData(
array $hashes,
X509 $certificate,
RSA $privateKey): array {
RSA\PrivateKey $privateKey,
): array {
ksort($hashes);

$privateKey->setSignatureMode(RSA::SIGNATURE_PSS);
$privateKey->setMGFHash('sha512');
// See https://tools.ietf.org/html/rfc3447#page-38
$privateKey->setSaltLength(0);
$signature = $privateKey->sign(json_encode($hashes));
$signature = $privateKey
->withPadding(RSA::SIGNATURE_PSS)
->withMGFHash('sha512')
->withSaltLength(0)
->sign(json_encode($hashes));

return [
'hashes' => $hashes,
'signature' => base64_encode($signature),
'certificate' => $certificate->saveX509($certificate->currentCert),
'certificate' => $certificate->saveX509($certificate->getCurrentCert()),
];
}

Expand All @@ -193,12 +195,12 @@ private function createSignatureData(array $hashes,
*
* @param string $path
* @param X509 $certificate
* @param RSA $privateKey
* @param RSA\PrivateKey $privateKey
* @throws \Exception
*/
public function writeAppSignature($path,
X509 $certificate,
RSA $privateKey) {
RSA\PrivateKey $privateKey) {
$appInfoDir = $path . '/appinfo';
try {
$this->fileAccessHelper->assertDirectoryExists($appInfoDir);
Expand All @@ -222,12 +224,12 @@ public function writeAppSignature($path,
* Write the signature of core
*
* @param X509 $certificate
* @param RSA $rsa
* @param RSA\PrivateKey $rsa
* @param string $path
* @throws \Exception
*/
public function writeCoreSignature(X509 $certificate,
RSA $rsa,
RSA\PrivateKey $rsa,
$path) {
$coreDir = $path . '/core';
try {
Expand Down Expand Up @@ -291,15 +293,14 @@ private function verify(string $signaturePath, string $basePath, string $certifi
$certificate = $signatureData['certificate'];

// Check if certificate is signed by Nextcloud Root Authority
$x509 = new \phpseclib\File\X509();
$x509 = new X509();
$rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot() . '/resources/codesigning/root.crt');

$rootCerts = $this->splitCerts($rootCertificatePublicKey);
foreach ($rootCerts as $rootCert) {
$x509->loadCA($rootCert);
}
$x509->loadX509($certificate);
if (!$x509->validateSignature()) {
if ($x509->loadX509($certificate) === false || !$x509->validateSignature()) {
throw new InvalidSignatureException('Certificate is not valid.');
}
// Verify if certificate has proper CN. "core" CN is always trusted.
Expand All @@ -310,13 +311,18 @@ private function verify(string $signaturePath, string $basePath, string $certifi
}

// 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');
// See https://tools.ietf.org/html/rfc3447#page-38
$rsa->setSaltLength(0);
if (!$rsa->verify(json_encode($expectedHashes), $signature)) {
/** @var RSA\PublicKey|false */
$rsa = $x509->getPublicKey();
if ($rsa === false) {
throw new InvalidSignatureException('Certificate does not provide valid public RSA key.');
}

$rsa = $rsa
->withPadding(RSA::SIGNATURE_PSS)
->withMGFHash('sha512')
->withSaltLength(0);

if (!$rsa->verify(json_encode($expectedHashes), (string)$signature)) {
throw new InvalidSignatureException('Signature could not get verified.');
}

Expand Down
6 changes: 3 additions & 3 deletions lib/private/Security/Crypto.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
use Exception;
use OCP\IConfig;
use OCP\Security\ICrypto;
use phpseclib\Crypt\AES;
use phpseclib\Crypt\Hash;
use phpseclib3\Crypt\AES;
use phpseclib3\Crypt\Hash;

/**
* Class Crypto provides a high-level encryption layer using AES-CBC. If no key has been provided
Expand All @@ -31,7 +31,7 @@ class Crypto implements ICrypto {
public function __construct(
private IConfig $config,
) {
$this->cipher = new AES();
$this->cipher = new AES('cbc');
}

/**
Expand Down
Loading

0 comments on commit d9d7046

Please # to comment.