From be9aa41ae1f8b4fd918442893137b58f8353534a Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Sat, 7 Aug 2021 22:21:32 +0200 Subject: [PATCH] security/acme-client: make it possible to use multiple CAs --- security/acme-client/pkg-descr | 8 ++++-- .../AcmeClient/forms/dialogAccount.xml | 10 ++++++++ .../OPNsense/AcmeClient/forms/settings.xml | 6 ----- .../library/OPNsense/AcmeClient/LeAccount.php | 4 +-- .../OPNsense/AcmeClient/LeAutomation/Base.php | 2 +- .../OPNsense/AcmeClient/LeCertificate.php | 3 ++- .../library/OPNsense/AcmeClient/LeCommon.php | 25 ++++++++++++++----- .../OPNsense/AcmeClient/LeValidation/Base.php | 2 +- .../models/OPNsense/AcmeClient/AcmeClient.xml | 24 +++++++++--------- .../OPNsense/AcmeClient/Migrations/M3_0_0.php | 9 ++++--- .../views/OPNsense/AcmeClient/settings.volt | 2 +- 11 files changed, 60 insertions(+), 35 deletions(-) diff --git a/security/acme-client/pkg-descr b/security/acme-client/pkg-descr index 3dfdcafae..a78db9bed 100644 --- a/security/acme-client/pkg-descr +++ b/security/acme-client/pkg-descr @@ -11,15 +11,19 @@ Plugin Changelog 3.0 Added: -* add support for new ACME CA's: buypass, buypass_test, sslcom, zerossl (#2361) +* add support for new ACME CAs: buypass, buypass_test, sslcom, zerossl (#2361) +* add CA setting to accounts, make it possible to use multiple CAs * add introduction pages and an option to hide them * add tooltips for account command buttons (#2188) * add support for custom ACME EAB kid/hmac when registering accounts +Fixed: +* properly set/get the UUID of LE objects + Changed: * rename plugin from "Let's Encrypt client" to "ACME Client" (#2361) * change the suffix for imports to the certificate storage to "ACME Client" (#2361) -* rename "Let's Encrypt Environment" to "ACME CA" (#2361) +* rename "Let's Encrypt Environment" to "ACME CA" and move to account settings (#2361) * preserve old LE accounts/certs by adding a compatibility layer (#2361) * update tooltip style for 21.7 (#2188) * show more options in list view for challenge types and automations diff --git a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogAccount.xml b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogAccount.xml index 246f279df..33854114a 100644 --- a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogAccount.xml +++ b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogAccount.xml @@ -17,12 +17,22 @@ text Description for this account. + + + header + account.email text Optional e-mail address for this account. + + account.ca + + dropdown + acme.sh documentation for a list of supported CAs.]]> + header diff --git a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/settings.xml b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/settings.xml index e3b64b0ad..285b55c7f 100644 --- a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/settings.xml +++ b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/settings.xml @@ -11,12 +11,6 @@ checkbox - - acmeclient.settings.ca - - dropdown - acme.sh documentation for a list of supported CAs.]]> - acmeclient.settings.haproxyIntegration diff --git a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAccount.php b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAccount.php index 57589b7c5..94a91008d 100644 --- a/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAccount.php +++ b/security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeAccount.php @@ -54,7 +54,7 @@ class LeAccount extends LeCommon $this->setLoglevel(); // Set ACME CA - $this->setCa(); + $this->setCa($uuid); // Store acme filenames $this->acme_args[] = LeUtils::execSafe('--home %s', self::ACME_HOME_DIR); @@ -213,7 +213,7 @@ class LeAccount extends LeCommon LeUtils::log_debug('starting account registration for ' . (string)$this->config->name, $this->debug); // Check if ACME External Account Binding (EAB) is enabled - if (!empty((string)$this->config->eab_kid) && !empty((string)$this->config->eab_hmac) { + if (!empty((string)$this->config->eab_kid) && !empty((string)$this->config->eab_hmac)) { LeUtils::log_debug('enabling ACME EAB for this account', $this->debug); $this->acme_args[] = LeUtils::execSafe('--eab-kid %s', $this->config->eab_kid); $this->acme_args[] = LeUtils::execSafe('--eab-hmac-key %s', $this->config->eab_hmac); 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 67ce269f2..349e22bff 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 @@ -64,7 +64,7 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon $this->setLoglevel(); // Set ACME CA - $this->setCa(); + $this->setCa($accountuuid); 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 16fc4839a..cfe13498d 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 @@ -75,7 +75,7 @@ class LeCertificate extends LeCommon $this->setLoglevel(); // Set ACME CA - $this->setCa(); + $this->setCa((string)$this->config->account); // Handle special key types if ($this->config->keyLength == 'key_ec256' || $this->config->keyLength == 'key_ec384') { @@ -351,6 +351,7 @@ class LeCertificate extends LeCommon return false; } LeUtils::log("${acme_action} certificate: " . (string)$this->config->name); + LeUtils::log('using CA: ' . $this->ca); // Ensure that account is registered. if (!($this->setAccount())) { 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 1863061d6..d2097fe7a 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 @@ -105,7 +105,7 @@ abstract class LeCommon */ public function getUuid() { - return (string)$this->config->uuid; + return (string)$this->uuid; } /** @@ -124,6 +124,7 @@ abstract class LeCommon // Store config objects $this->config = $obj; $this->model = $model; + $this->uuid = $uuid; return true; } @@ -139,16 +140,28 @@ abstract class LeCommon /** * set ACME CA for acme.sh */ - public function setCa() + public function setCa(string $uuid) { - $this->ca = (string)$this->model->getNodeByReference('settings.ca'); - $this->acme_args[] = LeUtils::execSafe('--server %s', $this->ca); + // Get account config object + $model = new \OPNsense\AcmeClient\AcmeClient(); + $obj = $model->getNodeByReference("accounts.account.${uuid}"); + if (empty($obj) || $obj == null) { + LeUtils::log_error("unable to set CA, account not found: ${uuid}"); + return false; + } + + // Extract ACME CA from account config + $acme_ca = (string)$obj->ca; + $this->ca = $acme_ca; + + // Add CA to acme arguments + $this->acme_args[] = LeUtils::execSafe('--server %s', $acme_ca); // Evaluate how the CA should be represented in filenames. // This is a compatibility layer. It ensures that old files that // were generated for the Let's Encrypt Production/Staging CA // can still be used. - switch ($this->ca) { + switch ($acme_ca) { case 'letsencrypt': $ca_compat = 'prod'; break; @@ -156,7 +169,7 @@ abstract class LeCommon $ca_compat = 'stg'; break; default: - $ca_compat = $this->ca; + $ca_compat = $acme_ca; break; } $this->ca_compat = $ca_compat; 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 0c2dcb317..d50292c66 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 @@ -74,7 +74,7 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon $this->setLoglevel(); // Set ACME CA - $this->setCa(); + $this->setCa($accountuuid); // Store acme hook switch ((string)$this->config->method) { diff --git a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml index 5e0a936f6..a2f097ede 100644 --- a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml +++ b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml @@ -34,18 +34,6 @@ Staging Environment - - Y - - - Buypass - Buypass Test CA - Let's Encrypt [default] - Let's Encrypt Test CA - SSL.com - ZeroSSL - - 43580 1024 @@ -148,6 +136,18 @@ N + + Y + letsencrypt + + Buypass + Buypass Test CA + Let's Encrypt [default] + Let's Encrypt Test CA + SSL.com + ZeroSSL + + N /^.{1,8192}$/u diff --git a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/Migrations/M3_0_0.php b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/Migrations/M3_0_0.php index a2f0262e5..1ef4c2f66 100644 --- a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/Migrations/M3_0_0.php +++ b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/Migrations/M3_0_0.php @@ -46,9 +46,12 @@ class M3_0_0 extends BaseModelMigration $new_ca = 'letsencrypt_test'; break; } - - // Set new CA - $model->settings->ca = $new_ca; $model->settings->environment = null; // clear old value + + // Search accounts + foreach ($model->getNodeByReference('accounts.account')->iterateItems() as $account) { + // Set CA + $account->ca = $new_ca; + } } } diff --git a/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/settings.volt b/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/settings.volt index 146a17a92..539fc9738 100644 --- a/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/settings.volt +++ b/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/settings.volt @@ -260,7 +260,7 @@ POSSIBILITY OF SUCH DAMAGE.

{{ lang._("Setting up this plugin for the first time involves the following steps") }}

  • {{ lang._('%sEnable%s the plugin: When enabling this plugin in the %ssettings%s, a lightweight service is started and cron jobs are added for automatic tasks.') | format('', '', '', '') }}
  • -
  • {{ lang._('Create an %saccount%s: An %saccount%s is required and will be automatically at the chosen CA.') | format('', '', '', '') }}
  • +
  • {{ lang._('Create an %saccount%s: An %saccount%s is required. It determines which CA will be used for all associated certificates.') | format('', '', '', '') }}
  • {{ lang._('Set up a %schallenge type%s: Choose the %schallenge type%s that works best for you and if necessary, add the credentials for your DNS provider.') | format('', '', '', '') }}
  • {{ lang._('Add %sautomations%s: This is optional, but recommended when using short-lived certificates. %sAutomations%s allow to automatically run tasks when a certificate was created or renewed.') | format('', '', '', '') }}
  • {{ lang._('Create %scertificates%s: Finally create the %scertificates%s and let the CA complete the validation process.') | format('', '', '', '') }}