From ed25316489292232b6711078d4c463cf57bf0a4a Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Mon, 3 Jan 2022 00:35:35 +0100 Subject: [PATCH 1/3] security/acme-client: show CA in accounts list --- security/acme-client/pkg-descr | 6 ++++++ .../OPNsense/AcmeClient/Api/AccountsController.php | 2 +- .../mvc/app/views/OPNsense/AcmeClient/accounts.volt | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/security/acme-client/pkg-descr b/security/acme-client/pkg-descr index d679217f4..d7c904fdb 100644 --- a/security/acme-client/pkg-descr +++ b/security/acme-client/pkg-descr @@ -16,6 +16,12 @@ a new version of acme.sh, which has not been released yet. Added: * add support for cPanel HTTP API (#2731) +Fixed: +* fix calculation of renewal date (#2721) + +Changed: +* show CA in accounts list + 3.7 Fixed: diff --git a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/AccountsController.php b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/AccountsController.php index ef6dfbf2d..922850399 100644 --- a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/AccountsController.php +++ b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/AccountsController.php @@ -74,7 +74,7 @@ class AccountsController extends ApiMutableModelControllerBase public function searchAction() { - return $this->searchBase('accounts.account', array('enabled', 'name', 'email', 'statusCode', 'statusLastUpdate'), 'name'); + return $this->searchBase('accounts.account', array('enabled', 'name', 'email', 'ca', 'statusCode', 'statusLastUpdate'), 'name'); } /** diff --git a/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/accounts.volt b/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/accounts.volt index d9e417ebd..ec20a20e8 100644 --- a/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/accounts.volt +++ b/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/accounts.volt @@ -359,6 +359,7 @@ POSSIBILITY OF SUCH DAMAGE. {{ lang._('Enabled') }} {{ lang._('Name') }} {{ lang._('E-Mail') }} + {{ lang._('CA') }} {{ lang._('Status') }} {{ lang._('Registration Date') }} {{ lang._('Commands') }} From 0cac1cadc2f85bcf1dd68c42cd0bf71ecc724be8 Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Wed, 5 Jan 2022 12:00:01 +0100 Subject: [PATCH 2/3] security/acme-client: fix calculation of renewal date, closes #2721 Now we read the validFrom information directly from the cert file in order to calculate the renewal date. This is necessary, because in ae697392293e4a7fb3e9ed0450a559adccbab2e6 we made the import feature available to the end-user. As a result, the value of lastUpdate() does not only change after issue/renewal, but also everytime the user clicks on the "import" button. --- .../OPNsense/AcmeClient/LeCertificate.php | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php index 72a8f1ece..54e32d960 100644 --- a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php +++ b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php @@ -414,8 +414,31 @@ class LeCertificate extends LeCommon { $return = false; + // Try to get issue date from certificate + if (is_file($this->cert_file)) { + // Read contents from certificate file + $cert_content = @file_get_contents($this->cert_file); + if ($cert_content != false) { + $cert_info = @openssl_x509_parse($cert_content); + if (!empty($cert_info['validFrom_time_t'])) { + $last_update = $cert_info['validFrom_time_t']; + } else { + LeUtils::log_error('unable to get expiration time from certificate for ' . (string)$this->config->name); + $last_update = 0; // Just assume the cert requires renewal. + } + } else { + LeUtils::log_error('unable to read certificate content from file for ' . (string)$this->config->name); + $last_update = 0; // Just assume the cert requires renewal. + } + } elseif (!empty((string)$this->config->lastUpdate)) { + // Fallback to lastUpdate() state, although it may not be correct + // if the cert was imported manually after issue/renewal. + $last_update = (string)$this->config->lastUpdate; + } else { + $last_update = 0; // Just assume the cert requires renewal. + } + // Collect required information - $last_update = !empty((string)$this->config->lastUpdate) ? (string)$this->config->lastUpdate : 0; $current_time = new \DateTime(); $last_update_time = new \DateTime(); $last_update_time->setTimestamp($last_update); From fc78ebae146e757792316b4853a1fe63c31cef73 Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Thu, 6 Jan 2022 14:45:47 +0100 Subject: [PATCH 3/3] security/acme-client: fix ecc cert handling in automations, closes #2723 --- security/acme-client/pkg-descr | 1 + .../library/OPNsense/AcmeClient/LeAutomation/Base.php | 9 ++++++++- .../app/library/OPNsense/AcmeClient/LeCertificate.php | 7 +++++-- .../mvc/app/library/OPNsense/AcmeClient/LeCommon.php | 1 + .../library/OPNsense/AcmeClient/LeValidation/Base.php | 9 ++++++--- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/security/acme-client/pkg-descr b/security/acme-client/pkg-descr index d7c904fdb..5b08b3bf0 100644 --- a/security/acme-client/pkg-descr +++ b/security/acme-client/pkg-descr @@ -18,6 +18,7 @@ Added: Fixed: * fix calculation of renewal date (#2721) +* properly handle ecc certs in automations (#2723) Changed: * show CA in accounts list diff --git a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAutomation/Base.php b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAutomation/Base.php index 175a51e9f..1f11081fa 100644 --- a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAutomation/Base.php +++ b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAutomation/Base.php @@ -47,7 +47,7 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon * Initialize LeAutomation object by adding the required configuration. * @return boolean */ - public function init(string $certid, string $certname, string $accountuuid) + public function init(string $certid, string $certname, string $accountuuid, bool $certecc = false) { // Get config object $this->loadConfig(self::CONFIG_PATH, $this->uuid); @@ -79,6 +79,13 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon // Main domain for acme $this->acme_args[] = LeUtils::execSafe('--domain %s', $certname); + // ECC cert + $this->cert_ecc = $certecc; + if ($this->cert_ecc) { + // Pass --ecc to acme client to locate the correct cert directory + $this->acme_args[] = '--ecc'; + } + return true; } diff --git a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php index 54e32d960..06e406b57 100644 --- a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php +++ b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCertificate.php @@ -81,6 +81,9 @@ class LeCertificate extends LeCommon if ($this->config->keyLength == 'key_ec256' || $this->config->keyLength == 'key_ec384') { // Pass --ecc to acme client to locate the correct cert directory $this->acme_args[] = '--ecc'; + $this->cert_ecc = true; + } else { + $this->cert_ecc = false; } // Store cert filenames @@ -628,7 +631,7 @@ class LeCertificate extends LeCommon foreach ($automations as $auto_uuid) { $autoFactory = new LeAutomationFactory(); $automation = $autoFactory->getAutomation($auto_uuid); - $automation->init($this->getId(), (string)$this->config->name, (string)$this->config->account); + $automation->init($this->getId(), (string)$this->config->name, (string)$this->config->account, $this->cert_ecc); // Ignore invalid automations. if ($automation->prepare()) { $automation->run(); @@ -677,7 +680,7 @@ class LeCertificate extends LeCommon LeUtils::log_error('invalid challenge type for certificate: ' . (string)$this->config->name); return false; } - if (!$val->init((string)$this->config->id, (string)$this->config->account)) { + if (!$val->init((string)$this->config->id, (string)$this->config->account, $this->cert_ecc)) { LeUtils::log_error('failed to initialize validation for certificate: ' . (string)$this->config->name); return false; } diff --git a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCommon.php b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCommon.php index ce1ed6e71..631fab0c4 100644 --- a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCommon.php +++ b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeCommon.php @@ -73,6 +73,7 @@ abstract class LeCommon protected $cert_domainalias; # AcmeClient certificate object domain alias protected $cert_challengealias; # AcmeClient certificate object challenge alias protected $cert_keylength; # Private key length + protected $cert_ecc; # ECC cert? // Account details protected $account_id; # AcmeClient account object ID diff --git a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeValidation/Base.php b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeValidation/Base.php index 3c0a6881a..c0289569e 100644 --- a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeValidation/Base.php +++ b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeValidation/Base.php @@ -50,7 +50,7 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon * @param $accountuuid string the UUID of the account object * @return bool */ - public function init(string $certid, string $accountuuid) + public function init(string $certid, string $accountuuid, bool $certecc = false) { // Get config object $this->loadConfig(self::CONFIG_PATH, $this->uuid); @@ -97,6 +97,9 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon $this->acme_args[] = LeUtils::execSafe('--capath %s', sprintf(self::ACME_CHAIN_FILE, $this->cert_id)); $this->acme_args[] = LeUtils::execSafe('--fullchainpath %s', sprintf(self::ACME_FULLCHAIN_FILE, $this->cert_id)); + // ECC cert + $this->cert_ecc = $certecc; + return true; } @@ -136,8 +139,8 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon // Issue or renew $acme_action = $renew == true ? 'renew' : 'issue'; - // Handle special key types - if ($this->cert_keylength == 'ec256' || $this->cert_keylength == 'ec384') { + // Handle ECC certs + if ($this->cert_ecc) { if ($renew == true) { // If it's a renew then pass --ecc to acme client to locate the correct cert directory $this->acme_args[] = '--ecc';