From 8569a08e6c90395e0e0eef36b5a74d61b30e3b4c Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Thu, 11 Apr 2024 22:44:54 -0300 Subject: [PATCH] fix: Read legacy certificate Reference: https://github.com/php/php-src/issues/12128 https://www.php.net/manual/en/function.openssl-pkcs12-read.php#128992 Signed-off-by: Vitor Mattos --- .../CertificateEngine/AEngineHandler.php | 47 +++++++++++++++---- .../CertificateEngine/CfsslHandler.php | 4 +- .../CertificateEngine/OpenSslHandler.php | 2 +- lib/Handler/Pkcs12Handler.php | 4 ++ lib/Handler/SignEngineHandler.php | 2 +- .../SignatureMethod/Password.php | 4 +- 6 files changed, 50 insertions(+), 13 deletions(-) diff --git a/lib/Handler/CertificateEngine/AEngineHandler.php b/lib/Handler/CertificateEngine/AEngineHandler.php index 62ecd571f3..297c360fc3 100644 --- a/lib/Handler/CertificateEngine/AEngineHandler.php +++ b/lib/Handler/CertificateEngine/AEngineHandler.php @@ -34,6 +34,7 @@ use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IConfig; use OCP\IDateTimeFormatter; +use OCP\ITempManager; use OpenSSLAsymmetricKey; use OpenSSLCertificate; use ReflectionClass; @@ -80,6 +81,7 @@ public function __construct( protected IAppConfig $appConfig, protected IAppDataFactory $appDataFactory, protected IDateTimeFormatter $dateTimeFormatter, + protected ITempManager $tempManager, ) { $this->appData = $appDataFactory->get('libresign'); } @@ -114,10 +116,7 @@ public function updatePassword(string $certificate, string $currentPrivateKey, s if (empty($certificate) || empty($currentPrivateKey) || empty($newPrivateKey)) { throw new EmptyCertificateException(); } - openssl_pkcs12_read($certificate, $certContent, $currentPrivateKey); - if (empty($certContent)) { - throw new InvalidPasswordException(); - } + $certContent = $this->opensslPkcs12Read($certificate, $currentPrivateKey); $this->setPassword($newPrivateKey); $certContent = self::exportToPkcs12($certContent['cert'], $certContent['pkey']); return $certContent; @@ -127,10 +126,7 @@ public function readCertificate(string $certificate, string $privateKey): array if (empty($certificate) || empty($privateKey)) { throw new EmptyCertificateException(); } - openssl_pkcs12_read($certificate, $certContent, $privateKey); - if (empty($certContent)) { - throw new InvalidPasswordException(); - } + $certContent = $this->opensslPkcs12Read($certificate, $privateKey); $parsed = openssl_x509_parse(openssl_x509_read($certContent['cert'])); $return['name'] = $parsed['name']; @@ -144,6 +140,41 @@ public function readCertificate(string $certificate, string $privateKey): array return $return; } + public function opensslPkcs12Read(string &$certificate, string $privateKey): array { + openssl_pkcs12_read($certificate, $certContent, $privateKey); + if (!empty($certContent)) { + return $certContent; + } + /** + * Reference: + * + * https://github.com/php/php-src/issues/12128 + * https://www.php.net/manual/en/function.openssl-pkcs12-read.php#128992 + */ + $msg = openssl_error_string(); + if ($msg === 'error:0308010C:digital envelope routines::unsupported') { + $tempPassword = $this->tempManager->getTemporaryFile(); + $tempEncriptedOriginal = $this->tempManager->getTemporaryFile(); + $tempEncriptedRepacked = $this->tempManager->getTemporaryFile(); + $tempDecrypted = $this->tempManager->getTemporaryFile(); + file_put_contents($tempPassword, $privateKey); + file_put_contents($tempEncriptedOriginal, $certificate); + shell_exec(<<tempManager->clean(); + openssl_pkcs12_read($certificateRepacked, $certContent, $privateKey); + if (!empty($certContent)) { + $certificate = $certificateRepacked; + return $certContent; + } + } + throw new InvalidPasswordException(); + } + public function translateToLong($name): string { switch ($name) { case 'CN': diff --git a/lib/Handler/CertificateEngine/CfsslHandler.php b/lib/Handler/CertificateEngine/CfsslHandler.php index 73d94b7663..910f53eb32 100644 --- a/lib/Handler/CertificateEngine/CfsslHandler.php +++ b/lib/Handler/CertificateEngine/CfsslHandler.php @@ -37,6 +37,7 @@ use OCP\Files\AppData\IAppDataFactory; use OCP\IConfig; use OCP\IDateTimeFormatter; +use OCP\ITempManager; /** * Class CfsslHandler @@ -60,8 +61,9 @@ public function __construct( private CfsslServerHandler $cfsslServerHandler, protected IAppDataFactory $appDataFactory, protected IDateTimeFormatter $dateTimeFormatter, + protected ITempManager $tempManager, ) { - parent::__construct($config, $appConfig, $appDataFactory, $dateTimeFormatter); + parent::__construct($config, $appConfig, $appDataFactory, $dateTimeFormatter, $tempManager); } public function generateRootCert( diff --git a/lib/Handler/CertificateEngine/OpenSslHandler.php b/lib/Handler/CertificateEngine/OpenSslHandler.php index c9a519a57a..b2e753d87a 100644 --- a/lib/Handler/CertificateEngine/OpenSslHandler.php +++ b/lib/Handler/CertificateEngine/OpenSslHandler.php @@ -47,7 +47,7 @@ public function __construct( protected IDateTimeFormatter $dateTimeFormatter, protected ITempManager $tempManager, ) { - parent::__construct($config, $appConfig, $appDataFactory, $dateTimeFormatter); + parent::__construct($config, $appConfig, $appDataFactory, $dateTimeFormatter, $tempManager); } public function generateRootCert( diff --git a/lib/Handler/Pkcs12Handler.php b/lib/Handler/Pkcs12Handler.php index 099f07867f..d0c120896a 100644 --- a/lib/Handler/Pkcs12Handler.php +++ b/lib/Handler/Pkcs12Handler.php @@ -103,6 +103,7 @@ public function updatePassword(string $uid, string $currentPrivateKey, string $n } public function readCertificate(string $uid, string $privateKey): array { + $this->setPassword($privateKey); $pfx = $this->getPfx($uid); return $this->certificateEngineHandler->getEngine()->readCertificate( $pfx, @@ -132,6 +133,9 @@ public function getPfx(?string $uid = null): string { if (empty($this->pfxContent)) { throw new LibresignException($this->l10n->t('Password to sign not defined. Create a password to sign.'), 400); } + if ($this->getPassword()) { + $this->certificateEngineHandler->getEngine()->opensslPkcs12Read($this->pfxContent, $this->getPassword()); + } return $this->pfxContent; } diff --git a/lib/Handler/SignEngineHandler.php b/lib/Handler/SignEngineHandler.php index 31f770a084..b60eca66a8 100644 --- a/lib/Handler/SignEngineHandler.php +++ b/lib/Handler/SignEngineHandler.php @@ -32,7 +32,7 @@ abstract class SignEngineHandler implements ISignEngineHandler { private $inputFile; private string $certificate; /** @var string */ - private $password; + private $password = ''; /** @var VisibleElementAssoc[] */ private $visibleElements = []; diff --git a/lib/Service/IdentifyMethod/SignatureMethod/Password.php b/lib/Service/IdentifyMethod/SignatureMethod/Password.php index 1b0879d254..bea290c2ba 100644 --- a/lib/Service/IdentifyMethod/SignatureMethod/Password.php +++ b/lib/Service/IdentifyMethod/SignatureMethod/Password.php @@ -43,9 +43,9 @@ public function __construct( } public function validateToIdentify(): void { + $this->pkcs12Handler->setPassword($this->codeSentByUser); $pfx = $this->pkcs12Handler->getPfx($this->userSession->getUser()?->getUID()); - openssl_pkcs12_read($pfx, $cert_info, $this->codeSentByUser); - if (empty($cert_info)) { + if (empty($pfx)) { throw new LibresignException($this->identifyService->getL10n()->t('Invalid password')); } }