From 4bd1a35dd2039d584b45ca0cd607e63ed74c6a47 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 17 Nov 2017 18:02:03 +0100 Subject: [PATCH] Add CRUD for root CA certificates refs #3016 --- .../TlsrootcacollectionController.php | 50 +++++++++- .../Config/Tls/RootCaCollection/AddCaForm.php | 80 ++++++++++++++++ .../Tls/RootCaCollection/RemoveCaForm.php | 93 +++++++++++++++++++ .../scripts/tlsrootcacollection/edit.phtml | 73 +++++++++++++++ 4 files changed, 292 insertions(+), 4 deletions(-) create mode 100644 application/forms/Config/Tls/RootCaCollection/AddCaForm.php create mode 100644 application/forms/Config/Tls/RootCaCollection/RemoveCaForm.php create mode 100644 application/views/scripts/tlsrootcacollection/edit.phtml diff --git a/application/controllers/TlsrootcacollectionController.php b/application/controllers/TlsrootcacollectionController.php index 6cbfdbc08..8d905c1d9 100644 --- a/application/controllers/TlsrootcacollectionController.php +++ b/application/controllers/TlsrootcacollectionController.php @@ -6,8 +6,10 @@ namespace Icinga\Controllers; use Exception; use Icinga\Application\Icinga; use Icinga\File\Storage\LocalFileStorage; +use Icinga\Forms\Config\Tls\RootCaCollection\AddCaForm; use Icinga\Forms\Config\Tls\RootCaCollection\CreateForm; use Icinga\Forms\Config\Tls\RootCaCollection\EditForm; +use Icinga\Forms\Config\Tls\RootCaCollection\RemoveCaForm; use Icinga\Forms\ConfirmRemovalForm; use Icinga\Web\Controller; use Icinga\Web\Notification; @@ -40,18 +42,58 @@ class TlsrootcacollectionController extends Controller public function editAction() { - $this->view->form = $form = new EditForm(); + $this->view->editForm = $editForm = new EditForm(); $name = $this->params->getRequired('name'); - $form->setOldName($name) + $editForm->setOldName($name) ->setRedirectUrl('tlsrootcacollection/edit') ->handleRequest(); + $this->view->addCaForm = $addCaForm = new AddCaForm(); + $addCaForm->setCollectionName($name) + ->setRedirectUrl('tlsrootcacollection/edit') + ->handleRequest(); + + preg_match_all( + '/-+BEGIN CERTIFICATE-+.+?-+END CERTIFICATE-+/s', + LocalFileStorage::common('tls/rootcacollections')->read(bin2hex($name) . '.pem'), + $certs + ); + + $certs = $certs[0]; + + foreach ($certs as & $cert) { + $sha256 = openssl_x509_fingerprint($cert, 'sha256'); + $cert = array( + 'info' => openssl_x509_parse($cert), + 'sha1' => openssl_x509_fingerprint($cert, 'sha1'), + 'sha256' => $sha256, + 'removalForm' => new RemoveCaForm(array( + 'collectionName' => $name, + 'certBySha256' => $sha256, + 'redirectUrl' => 'tlsrootcacollection/edit' + )) + ); + + $cert['removalForm']->handleRequest(); + } + + usort($certs, function($a, $b) { + $a = $a['info']['name']; + $b = $b['info']['name']; + + if ($a < $b) { + return -1; + } + + return $a > $b ? 1 : 0; + }); + + $this->view->certs = $certs; + $this->addTitleTab( $this->translate('Edit Certificate Collection'), sprintf($this->translate('Edit TLS Root CA Certificate Collection "%s"'), $name) ); - - $this->render('form'); } public function removeAction() diff --git a/application/forms/Config/Tls/RootCaCollection/AddCaForm.php b/application/forms/Config/Tls/RootCaCollection/AddCaForm.php new file mode 100644 index 000000000..f10133046 --- /dev/null +++ b/application/forms/Config/Tls/RootCaCollection/AddCaForm.php @@ -0,0 +1,80 @@ +setName('form_config_tlsrootca_add'); + $this->setSubmitLabel($this->translate('Add')); + } + + public function createElements(array $formData) + { + $this->addElement( + 'file', + 'cert', + array( + 'label' => $this->translate('Certificate (PEM)'), + 'description' => $this->translate('The new TLS root CA certificate'), + 'required' => true, + 'validators' => array(new TlsCertFileValidator()) + ) + ); + } + + public function onSuccess() + { + try { + $rootCaCollections = LocalFileStorage::common('tls/rootcacollections'); + + /** @var \Zend_Form_Element_File $cert */ + $cert = $this->getElement('cert'); + + if ($cert->isUploaded()) { + $cert->getValue(); + } + + openssl_x509_export('file://' . $cert->getFileName(), $newCert); + + $collectionFileName = bin2hex($this->collectionName) . '.pem'; + $rootCaCollections->update($collectionFileName, $newCert . $rootCaCollections->read($collectionFileName)); + } catch (Exception $e) { + $this->error($e->getMessage()); + return false; + } + + $this->getRedirectUrl()->setParam('name', $this->collectionName); + } + + /** + * Set the TLS root CA certificate collection's name + * + * @param string $collectionName + * + * @return $this + */ + public function setCollectionName($collectionName) + { + $this->collectionName = $collectionName; + + return $this; + } +} diff --git a/application/forms/Config/Tls/RootCaCollection/RemoveCaForm.php b/application/forms/Config/Tls/RootCaCollection/RemoveCaForm.php new file mode 100644 index 000000000..255fc65f1 --- /dev/null +++ b/application/forms/Config/Tls/RootCaCollection/RemoveCaForm.php @@ -0,0 +1,93 @@ +setName('form_config_tlsrootca_remove_' . $this->certBySha256); + $this->setSubmitLabel($this->translate('Remove')); + } + + public function onSuccess() + { + try { + $rootCaCollections = LocalFileStorage::common('tls/rootcacollections'); + $collectionFileName = bin2hex($this->collectionName) . '.pem'; + + preg_match_all( + '/-+BEGIN CERTIFICATE-+.+?-+END CERTIFICATE-+/s', + $rootCaCollections->read($collectionFileName), + $certs + ); + + $certs = $certs[0]; + + foreach ($certs as $index => $cert) { + if (openssl_x509_fingerprint($cert, 'sha256') === $this->certBySha256) { + unset($certs[$index]); + $rootCaCollections->update($collectionFileName, implode(PHP_EOL, $certs)); + + break; + } + } + } catch (Exception $e) { + $this->error($e->getMessage()); + return false; + } + + $this->getRedirectUrl()->setParam('name', $this->collectionName); + } + + /** + * Set the TLS root CA certificate collection's name + * + * @param string $collectionName + * + * @return $this + */ + public function setCollectionName($collectionName) + { + $this->collectionName = $collectionName; + + return $this; + } + + /** + * Set the TLS root CA certificate's SHA256 sum + * + * @param string $certBySha256 + * + * @return $this + */ + public function setCertBySha256($certBySha256) + { + $this->certBySha256 = $certBySha256; + + return $this; + } +} diff --git a/application/views/scripts/tlsrootcacollection/edit.phtml b/application/views/scripts/tlsrootcacollection/edit.phtml new file mode 100644 index 000000000..aed285773 --- /dev/null +++ b/application/views/scripts/tlsrootcacollection/edit.phtml @@ -0,0 +1,73 @@ +success() ? $timezoneDetect->getTimezoneName() : date_default_timezone_get() + ); +} +?> +
+ +
+
+ + +

translate('TLS Root CA Certificates') ?>

+ + + + $value) { + $subject[] = $this->escape("$key = " . var_export($value, true)); + } + + $issuer = array(); + foreach ($cert['info']['issuer'] as $key => $value) { + $issuer[] = $this->escape("$key = " . var_export($value, true)); + } + + ?> +

escape($cert['info']['name']) ?>

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
escape($this->translate('Subject', 'x509.certificate')) ?>', $subject) ?>
escape($this->translate('Issuer', 'x509.certificate')) ?>', $issuer) ?>
escape($this->translate('Valid from', 'x509.certificate')) ?>escape( + DateTime::createFromFormat('U', $cert['info']['validFrom_time_t']) + ->setTimezone($timeZone) + ->format(DateTime::ISO8601) + ) ?>
escape($this->translate('Valid until', 'x509.certificate')) ?>escape( + DateTime::createFromFormat('U', $cert['info']['validTo_time_t']) + ->setTimezone($timeZone) + ->format(DateTime::ISO8601) + ) ?>
escape($this->translate('SHA256 fingerprint', 'x509.certificate')) ?>escape(implode(' ', str_split(strtoupper($cert['sha256']), 2))) ?>
escape($this->translate('SHA1 fingerprint', 'x509.certificate')) ?>escape(implode(' ', str_split(strtoupper($cert['sha1']), 2))) ?>
+ + + +
\ No newline at end of file