diff --git a/security/step-certificates/src/opnsense/mvc/app/controllers/OPNsense/StepCA/forms/initialize.xml b/security/step-certificates/src/opnsense/mvc/app/controllers/OPNsense/StepCA/forms/initialize.xml
new file mode 100644
index 0000000000..3d68b309c2
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/controllers/OPNsense/StepCA/forms/initialize.xml
@@ -0,0 +1,91 @@
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/controllers/OPNsense/StepCA/forms/provisioner.xml b/security/step-certificates/src/opnsense/mvc/app/controllers/OPNsense/StepCA/forms/provisioner.xml
new file mode 100644
index 0000000000..a77c4852c9
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/controllers/OPNsense/StepCA/forms/provisioner.xml
@@ -0,0 +1,131 @@
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/Base/Constraints/SetIfConstraintAbs.php b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/Base/Constraints/SetIfConstraintAbs.php
new file mode 100644
index 0000000000..b36e4dcff0
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/Base/Constraints/SetIfConstraintAbs.php
@@ -0,0 +1,72 @@
+getOption('node');
+ $field_name = $this->getOption('field');
+ $check = $this->getOption('check');
+ if ($node) {
+ $model = $node->getParentModel();
+ $refNode = $model->getNodeByReference($field_name);
+ if ($this->isEmpty($node) && $refNode == $check) {
+ $this->appendMessage($validator, $attribute);
+ }
+ }
+ return true;
+ }
+}
+
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/ACL/ACL.xml b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/ACL/ACL.xml
new file mode 100644
index 0000000000..75b0f28ce5
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/ACL/ACL.xml
@@ -0,0 +1,11 @@
+
+
+ Services: StepCA
+
+ ui/stepca/*
+ api/stepca/*
+ ui/diagnostics/log/core/stepca/*
+ api/diagnostics/log/core/stepca/*
+
+
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/FieldTypes/CertificateField.php b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/FieldTypes/CertificateField.php
new file mode 100644
index 0000000000..87c15e6b05
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/FieldTypes/CertificateField.php
@@ -0,0 +1,122 @@
+certificateType = "ca";
+ } elseif (trim(strtolower($value)) == "crl") {
+ $this->certificateType = "crl";
+ } else {
+ $this->certificateType = "cert";
+ }
+ }
+
+ /**
+ * Whether Certificate must have a private key
+ * @param string $value Y/N
+ */
+ public function setPrivKeyRequired($value)
+ {
+ $this->internalPrivKeyRequired = trim(strtoupper($value)) == "Y";
+ }
+
+ /**
+ * generate validation data (list of certificates)
+ */
+ protected function actionPostLoadingEvent()
+ {
+ if ($this->internalPrivKeyRequired) {
+ $configObj = Config::getInstance()->object();
+ foreach ($configObj->{$this->certificateType} as $cert) {
+ if ($this->certificateType == 'ca' && (string)$cert->x509_extensions == 'ocsp') {
+ // skip ocsp signing certs
+ continue;
+ }
+ if (empty($cert->prv)) {
+ // skip cert without private key
+ continue;
+ }
+ $this->internalOptionList[(string)$cert->refid] = (string)$cert->descr;
+ }
+ natcasesort($this->internalOptionList);
+ return;
+ }
+
+ if (!isset(self::$internalStaticOptionList[$this->certificateType])) {
+ self::$internalStaticOptionList[$this->certificateType] = array();
+ $configObj = Config::getInstance()->object();
+ foreach ($configObj->{$this->certificateType} as $cert) {
+ if ($this->certificateType == 'ca' && (string)$cert->x509_extensions == 'ocsp') {
+ // skip ocsp signing certs
+ continue;
+ }
+ // if ($this->internalPrivKeyRequired && empty($cert->prv)) {
+ // // skip cert without private key
+ // continue;
+ // }
+ self::$internalStaticOptionList[$this->certificateType][(string)$cert->refid] = (string)$cert->descr;
+ }
+ natcasesort(self::$internalStaticOptionList[$this->certificateType]);
+ }
+ $this->internalOptionList = self::$internalStaticOptionList[$this->certificateType];
+ }
+}
diff --git a/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/Initialize.php b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/Initialize.php
new file mode 100644
index 0000000000..49cf66d92c
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/Initialize.php
@@ -0,0 +1,37 @@
+
+ //OPNsense/StepCA/Initialize
+ 0.1.0
+ StepCA for OPNsense
+
+
+
+
+ N
+ ca
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ trust
+
+
+
+
+
+ N
+ /^[0-9a-f]{2}$/u
+ This does not look like a Yubikey slot
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyL
+
+
+
+
+ Y
+ "subject": "OPNsense StepCA Root",
+"issuer": "OPNsense StepCA Root",
+"keyUsage": ["certSign", "crlSign"],
+"basicConstraints": {
+ "isCA": true,
+ "maxPathLen": 1
+}
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+
+
+ N
+ ECC-P384
+ N
+ N
+
+ RSA 2048
+ RSA 3072
+ RSA 4096
+ ECC secp256r1
+ ECC secp384r1
+ ECC Ed25519
+
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+
+
+ N
+ 365
+ 1
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+
+
+
+
+
+ N
+ ca
+
+
+ This field must be set.
+ SetIfConstraint
+ aSource
+ trust
+
+
+
+
+
+ N
+ /^[0-9a-f]{2}$/u
+ This does not look like a Yubikey slot
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyL
+
+
+
+
+ Y
+ "subject": "OPNsense StepCA Intermediate",
+"keyUsage": ["certSign", "crlSign"],
+"basicConstraints": {
+ "isCA": true,
+ "maxPathLen": 0
+}
+
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+
+
+ N
+ ECC-P384
+ N
+ N
+
+ RSA 2048
+ RSA 3072
+ RSA 4096
+ ECC secp256r1
+ ECC secp384r1
+ ECC Ed25519
+
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+
+
+ N
+ 365
+ 1
+
+
+ This field must be set.
+ SetIfConstraint
+ Source
+ yubikeyC
+
+
+
+
+
+
+
+ N
+ /^.{4,}$/u
+ This does not look like a Yubikey pin
+
+
+ This field must be set.
+ SetIfConstraintAbs
+ root.Source
+ yubikeyC
+
+
+ This field must be set.
+ SetIfConstraintAbs
+ root.Source
+ yubikeyL
+
+
+ This field must be set.
+ SetIfConstraintAbs
+ intermediate.Source
+ yubikeyC
+
+
+ This field must be set.
+ SetIfConstraintAbs
+ intermediate.Source
+ yubikeyL
+
+
+
+
+
+
+ N
+
+
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/Menu/Menu.xml b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/Menu/Menu.xml
new file mode 100644
index 0000000000..685c035061
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/Menu/Menu.xml
@@ -0,0 +1,10 @@
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/StepCA.php b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/StepCA.php
new file mode 100644
index 0000000000..8976e8f2d5
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/models/OPNsense/StepCA/StepCA.php
@@ -0,0 +1,37 @@
+
+ //OPNsense/StepCA/CA
+ 0.1.0
+ StepCA for OPNsense
+
+
+ 0
+ Y
+
+
+ 127.0.0.1:9443
+ Y
+
+
+ localhost
+ Y
+ Y
+ ,
+ Y
+
+
+
+ Y
+ badgerv2
+ N
+ N
+
+ Badger (V2)
+ BoltDB
+ PostgreSQL
+ MySQL
+
+
+
+ N
+
+
+
+ This field must be set.
+ SetIfConstraint
+ DB
+ postgresql
+
+
+ This field must be set.
+ SetIfConstraint
+ DB
+ mysql
+
+
+
+
+ N
+
+
+
+ This field must be set.
+ SetIfConstraint
+ DB
+ postgresql
+
+
+ This field must be set.
+ SetIfConstraint
+ DB
+ mysql
+
+
+
+
+
+
+
+ N
+
+
+ N
+ 24h
+
+
+ N
+ 24h
+
+
+ N
+
+
+ N
+
+
+ N
+
+
+ N
+
+
+ N
+
+
+ N
+
+
+ N
+
+
+ N
+
+ N
+
+
+
+
+
+
+ N
+ N
+ ,
+ Y
+ Y
+
+
+
+ N
+ Y
+ N
+ ,
+ Y
+
+
+
+
+
+ N
+ N
+ ,
+ Y
+ Y
+
+
+
+ N
+ Y
+ N
+ ,
+ Y
+
+
+
+
+
+
+
+
+ N
+ N
+ ,
+ Y
+ Y
+
+
+
+ N
+ Y
+ N
+ ,
+ Y
+
+
+
+
+
+ N
+ N
+ ,
+ Y
+ Y
+
+
+
+ N
+ Y
+ N
+ ,
+ Y
+
+
+
+
+
+
+
+ N
+ Y
+ ,
+
+
+
+
+
+ N
+ Y
+ ,
+
+
+
+
+
+
+
+
+
+ 1
+ Y
+
+
+ Y
+ acme
+ N
+ N
+
+ ACME
+ JWT
+
+
+
+ acme
+ Y
+ /^([0-9a-z_\-]){4,32}$/u
+ Should be a string between 4 and 32 characters, containing lower-case characters, numbers, dashes and underscores.
+
+
+ A Provisioner with this name already exists.
+ UniqueConstraint
+
+
+
+
+ 1
+ Y
+
+
+ N
+ N
+ N
+ N
+ N
+ N
+ N
+ N
+ N
+ N
+ N
+ N
+
+
+ Y
+ http-01
+ N
+ Y
+
+ http-01
+ dns-01
+ tls-alpn-01
+ device-attest-01
+ wire-oidc-01
+ wire-dpop-01
+
+
+
+ N
+
+ N
+ Y
+
+ apple
+ step
+ tpm
+
+
+
+ This field must be set.
+ SetIfConstraint
+ Challenges
+ device-attest-01
+
+
+
+
+ N
+ ca
+ Y
+
+
+ This field must be set.
+ SetIfConstraint
+ Attestation
+ tpm
+
+
+
+
+ Y
+ "subject": {{ toJson .Subject }},
+"sans": {{ toJson .SANs }},
+{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }}
+"keyUsage": ["keyEncipherment", "digitalSignature"],
+{{- else }}
+"keyUsage": ["digitalSignature"],
+{{- end }}
+"extKeyUsage": ["serverAuth", "clientAuth"]
+
+
+
+
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/general.volt b/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/general.volt
new file mode 100644
index 0000000000..6bbffd1b66
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/general.volt
@@ -0,0 +1,72 @@
+{#
+
+Copyright (C) 2024 Volodymyr Paprotski
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+#}
+
+
+
+
diff --git a/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/initialize.volt b/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/initialize.volt
new file mode 100644
index 0000000000..5ce62c8c00
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/initialize.volt
@@ -0,0 +1,135 @@
+{#
+
+Copyright (C) 2024 Volodymyr Paprotski
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+#}
+
+
+
+
+#}
diff --git a/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/provisioners.volt b/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/provisioners.volt
new file mode 100644
index 0000000000..ac0c5f47d1
--- /dev/null
+++ b/security/step-certificates/src/opnsense/mvc/app/views/OPNsense/StepCA/provisioners.volt
@@ -0,0 +1,103 @@
+{#
+# Copyright (C) 2024 Volodymyr Paprotski
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#}
+
+
+
+
+