Commit 07c5b980 authored by Sophie Herold's avatar Sophie Herold 🌼

Remove support for HTTPS certs

Only allow to activate or deactivate HTTPS
parent 2433e925
......@@ -142,7 +142,6 @@ class Utils
public static function htmlRedirect(Request $request)
{
global $config;
usleep(100 * 1000);
header(
sprintf('Location: %s', $config['base_url'].$request->getUrl())
, true
......
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Cantarell
Upstream-Contact: Dave Crossland <dave@understandinglimited.com>
Source: http://git.gnome.org/browse/cantarell-fonts
Files-Excluded: prebuilt
Files: *
Copyright:
......@@ -16,6 +16,10 @@ Copyright:
© 2012-2015, Fabian Greffrath <fabian@debian.org>
License: OFL-1.1
Files: appstream/*
Copyright: 2018 Nikolaus Waxweiler
License: CC0-1.0
License: OFL-1.1
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
......@@ -107,3 +111,14 @@ License: OFL-1.1
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
License: CC0-1.0
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
.
On Debian systems, the complete text of the CC0 1.0 Universal license can be
found in "/usr/share/common-licenses/CC0-1.0".
......@@ -146,7 +146,6 @@ try {
}
if ($authMethod === 'http' && !$httpAuthSupplied) {
usleep(100 * 1000);
header('WWW-Authenticate: Basic realm="Edentata"');
header('HTTP/1.1 401 Unauthorized');
throw new exception\Error(_('Login failed'));
......@@ -167,7 +166,6 @@ try {
$loginData = $qryAuth->execute()->fetch();
} catch (\Exception $e) {
if ($httpAuth) {
usleep(100 * 1000);
header('WWW-Authenticate: Basic realm="Edentata"');
header('HTTP/1.1 401 Unauthorized');
throw new exception\Error(_('Login failed'));
......
<?php
/*
* Copyright (C) 2015 Michael Herold <quabla@hemio.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace hemio\edentata\module\web;
/**
* X.509 Certificate
*
* @author Michael Herold <quabla@hemio.de>
*/
class Cert {
protected $formatted;
protected $raw;
protected $parsed;
const BEGIN = '-----BEGIN CERTIFICATE-----';
const END = '-----END CERTIFICATE-----';
public static function extract($str) {
$pattern = '/' . self::BEGIN . '(?<cert>[a-zA-Z\d+=\/\s]+)' . self::END . '/s';
$matches = [];
preg_match_all($pattern, $str, $matches);
if (count($matches['cert']) > 0) {
$certs = [];
foreach ($matches['cert'] as $cert) {
$certs[] = new Cert(self::clean($cert));
}
return $certs;
}
return [new Cert(self::clean($str))];
}
public static function clean($str) {
return preg_replace('/\s+/', '', $str);
}
public function __construct($certificate) {
if ($certificate != self::clean($certificate))
throw new \hemio\edentata\exception\Error('Expecting cleaned string');
$this->formatted = self::BEGIN . PHP_EOL . chunk_split($certificate, 64, PHP_EOL) . self::END;
$this->raw = $certificate;
$this->parsed = openssl_x509_parse($this->formatted, true);
if (!$this->parsed) {
throw new \hemio\edentata\exception\Error('Invalid Cert');
}
}
/**
*
* @param string $hashAlg
* @return string
*/
public function fingerprint($hashAlg) {
$str = openssl_x509_fingerprint($this->formatted, $hashAlg, false);
$chunk = trim(chunk_split($str, 2, ':'), ':');
return strtoupper($chunk);
}
/**
*
* @return array
*/
public function fingerprints() {
return [
'SHA-512' => $this->fingerprint('sha512'),
'SHA-384' => $this->fingerprint('sha384'),
'SHA-256' => $this->fingerprint('sha256'),
'SHA-1' => $this->fingerprint('sha1'),
'MD5' => $this->fingerprint('md5')
];
}
public function commonName() {
return $this->parsed['subject']['CN'];
}
public function altNames() {
$names = [];
$entries = explode(',', $this->parsed['extensions']['subjectAltName']);
foreach ($entries as $entry) {
$keyVal = explode(':', $entry);
if (trim($keyVal[0]) === 'DNS')
$names[] = trim($keyVal[1]);
}
return $names;
}
/**
*
* @return \DateTime
*/
public function validFrom() {
return new \DateTime('@' . $this->parsed['validFrom_time_t']);
}
/**
*
* @return \DateTime
*/
public function validTo() {
return new \DateTime('@' . $this->parsed['validTo_time_t']);
}
public function trusted(array $intermediate) {
$itermediateFormatted = array_map(function (Cert $obj) {
return $obj->formatted();
}, $intermediate);
$strInterm = implode(PHP_EOL, $itermediateFormatted);
$resInterm = tmpfile();
$pthInterm = stream_get_meta_data($resInterm)['uri'];
fwrite($resInterm, $strInterm);
$resCert = tmpfile();
$pthCert = stream_get_meta_data($resCert)['uri'];
fwrite($resCert, $this->formatted());
$status = null;
$stdout = '';
exec('/usr/bin/openssl verify -untrusted "' . $pthInterm . '" "' . $pthCert . '"', $stdout, $status);
return $status === 0;
}
public function authorityKeyIdentifier() {
$str = $this->parsed['extensions']['authorityKeyIdentifier'];
// extract from keyid:KEY,... format
$csv = explode(',', $str);
$key = explode(':', $csv[0], 2);
return trim($key[1]);
}
public function subjectKeyIdentifier() {
if (isset($this->parsed['extensions']['subjectKeyIdentifier']))
return $this->parsed['extensions']['subjectKeyIdentifier'];
else
return null;
}
public function raw() {
return $this->raw;
}
public function formatted() {
return $this->formatted;
}
public function suggestChain(Db $db) {
$ident = $this->authorityKeyIdentifier();
$chain = [];
while ($next = $db->intermediateCertSelect($ident)->fetch()) {
$chain[] = new Cert($next['x509_certificate']);
$ident = $next['authority_key_identifier'];
}
return $chain;
}
}
<?php
/*
* Copyright (C) 2015 Michael Herold <quabla@hemio.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace hemio\edentata\module\web;
/**
* Description of CertRequest
*
* @author Michael Herold <quabla@hemio.de>
*/
class CertRequest
{
protected $formatted;
protected $raw;
protected $parsed;
const BEGIN = '-----BEGIN CERTIFICATE REQUEST-----';
const END = '-----END CERTIFICATE REQUEST-----';
public function __construct($request)
{
if ($request != Cert::clean($request))
throw new \hemio\edentata\exception\Error('Expecting cleaned string');
$this->formatted = self::BEGIN.PHP_EOL.chunk_split($request, 64, PHP_EOL).self::END;
$this->raw = $request;
$this->parsed = openssl_csr_get_subject($this->formatted, true);
if (!$this->parsed) {
throw new \hemio\edentata\exception\Error('Invalid Cert');
}
}
public function commonName()
{
return $this->parsed['CN'];
}
public function formatted()
{
return $this->formatted;
}
}
......@@ -107,112 +107,6 @@ class Db extends \hemio\edentata\ModuleDb
))->execute();
}
public function siteUpdate(array $params)
{
(new sql\QuerySelectFunction(
$this->pdo
, 'web.upd_site'
, $params
))->execute();
}
public function httpsCreate(array $params)
{
(new sql\QuerySelectFunction(
$this->pdo
, 'web.ins_https'
, $params
))->execute();
}
public function httpsUpdate(array $params)
{
(new sql\QuerySelectFunction(
$this->pdo
, 'web.upd_https'
, $params
))->execute();
}
public function httpsSelectSingle($domain, $port, $identifier)
{
$stmt = new sql\QuerySelectFunction(
$this->pdo
, 'web.sel_https'
);
$stmt->options('WHERE domain = :domain AND port = :port AND identifier = :identifier');
return $stmt->execute([
'domain' => $domain,
'port' => $port,
'identifier' => $identifier
]);
}
public function httpsSelect($domain, $port)
{
$stmt = new sql\QuerySelectFunction(
$this->pdo
, 'web.sel_https'
);
$stmt->options('WHERE domain = :domain AND port = :port');
return $stmt->execute([
'domain' => $domain,
'port' => $port
]);
}
public function intermediateCertSelect($subjectKeyIdentifier)
{
return (new sql\QuerySelectFunction(
$this->pdo
, 'web.sel_intermediate_cert'
, ['p_subject_key_identifier' => $subjectKeyIdentifier]
))->execute();
}
public function intermediateCertCreate(array $params)
{
return (new sql\QuerySelectFunction(
$this->pdo
, 'web.ins_intermediate_cert'
, $params
))->execute();
}
public function intermediateChainInsert(array $params)
{
(new sql\QuerySelectFunction(
$this->pdo
, 'web.ins_intermediate_chain'
, $params
))->execute();
}
public function intermediateChainDelete(array $params)
{
(new sql\QuerySelectFunction(
$this->pdo
, 'web.del_intermediate_chain'
, $params
))->execute();
}
public function intermediateChainSelect($domain, $port, $identifier)
{
$stmt = new sql\QuerySelectFunction(
$this->pdo
, 'web.sel_intermediate_chain'
);
$stmt->options('WHERE domain = :domain AND port = :port AND identifier = :identifier');
return $stmt->execute(['domain' => $domain, 'port' => $port, 'identifier' => $identifier]);
}
public function availableDomainsWeb($port)
{
$stmt = new sql\QuerySelectFunction(
......
<?php
/*
* Copyright (C) 2015 Michael Herold <quabla@hemio.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace hemio\edentata\module\web;
use hemio\edentata\gui;
use hemio\form;
use hemio\edentata\exception;
/**
* Description of HttpsCert
*
* @author Michael Herold <quabla@hemio.de>
*/
class HttpsCert extends Window
{
public function content($address, $identifier)
{
$domain = Utils::getHost($address);
$port = Utils::getPort($address);
$window = $this->newFormWindow(
'https_cert'
, _('Supply Certificate')
, $address
, _('Supply Certificate')
);
$certData = $this->db->httpsSelectSingle($domain, $port, $identifier)->fetch();
$requestObj = new CertRequest($certData['x509_request']);
$request = new gui\Fieldset(_('Certificate Signing Request (CSR)'));
$request->addChild(new gui\Hint(
_('A CSR enables to request a SSL certificate from a certificate authority.'
.' The issued certificate from the certificate authority must be supplied below.')));
$request->addChild(
new gui\Output('Common Name (CN)', $requestObj->commonName()));
$pre = new gui\Pre($requestObj->formatted());
$request->addChild($pre);
$certFieldset = new gui\Fieldset(_('Certificate (PEM Format)'));
$cert = new form\FieldTextarea('x509_certificate',
_('Certificate'));
$cert->addInheritableAppendage(form\Abstract_\Form::FORM_FIELD_TEMPLATE,
new form\template\FormPlainControl());
$cert->getControlElement()->addCssClass('pre_content');
$cert->getControlElement()->setCssProperty('height', '50em');
$cert->getControlElement()->setAttribute('placeholder',
'-----BEGIN CERTIFICATE-----');
if ($certData['x509_certificate']) {
$certObj = new Cert($cert['x509_certificate']);
$cert->setDefaultValue($certObj->formatted());
}
$window->getForm()->addChild($request);
$window->getForm()->addChild($certFieldset)->addChild($cert);
$this->handleSubmit($window->getForm(), $cert, $domain, $port,
$identifier);
return $window;
}
protected function handleSubmit(
gui\FormPost $form
, form\FieldTextarea $cert
, $domain
, $port
, $identifier
)
{
if ($form->correctSubmitted()) {
$certs = Cert::extract($cert->getValueUser());
if (count($certs) !== 1)
throw new exception\Error('Expecting exactly one cert');
$crt = array_pop($certs);
$params = [
'p_domain' => $domain,
'p_port' => $port,
'p_identifier' => $identifier,
'p_authority_key_identifier' => $crt->authorityKeyIdentifier(),
'p_x509_certificate' => $crt->raw()
];
$this->db->httpsUpdate($params);
throw new exception\Successful;
}
}
}
<?php
/*
* Copyright (C) 2015 Michael Herold <quabla@hemio.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace hemio\edentata\module\web;
use hemio\edentata\gui;
use hemio\form;
/**
* Description of HttpsCreate
*
* @author Michael Herold <quabla@hemio.de>
*/
class HttpsCreate extends Window
{
public function content($address)
{
$domain = Utils::getHost($address);
$port = Utils::getPort($address);
$window = $this->newFormWindow(
'https_create', _('New HTTPS Configuration'), $address, _('Create'));
$existing = [];
foreach ($this->db->httpsSelect($domain, $port) as $cert)
$existing[] = $cert['identifier'];
$default = (new \DateTime)->format('Y');
$chr = 97;
while (in_array($default, $existing) && $chr < 123)
$default = (new \DateTime)->format('Y-').chr($chr++);
$identifier = new form\FieldText('identifier', _('Identifier'));
$identifier->setDefaultValue($default);
$window->getForm()->addChild($identifier);
$this->handleSubmit($domain, $port, $window->getForm());
return $window;
}
public function handleSubmit($domain, $port, gui\FormPost $form)
{
if ($form->correctSubmitted()) {
$params = ['p_domain' => $domain, 'p_port' => $port] + $form->getVal(['identifier']);
$this->db->httpsCreate($params);
throw new \hemio\edentata\exception\Successful();
}
}
}
<?php
/*
* Copyright (C) 2015 Michael Herold <quabla@hemio.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace hemio\edentata\module\web;
use hemio\edentata\gui;
use hemio\edentata;
use hemio\html;
/**
* Description of HttpsDetails
*
* @author Michael Herold <quabla@hemio.de>
*/
class HttpsDetails extends Window
{
public function content($address, $identifier)
{
$domain = Utils::getHost($address);
$port = Utils::getPort($address);
$window = $this->newWindow(_('HTTPS Configuration'), $address);
$window->addChild($this->https($domain, $port, $identifier));
$cert = $this->db->httpsSelectSingle(
$domain, $port, $identifier)->fetch();
if ($cert !== false && $cert['x509_certificate'] !== null) {
$window->addChild($this->certDetails(
new Cert($cert['x509_certificate']), $identifier));
$window->addChild($this->trustChain($domain, $port, $identifier));
}
return $window;
}
protected function tryFindingTrustChain($domain, $port, $identifier)
{
$cert = $this->db->httpsSelectSingle(
$domain, $port, $identifier)->fetch();
$certData = new Cert($cert['x509_certificate']);
$newChain = $certData->suggestChain($this->db);
if (!$certData->trusted($newChain))
return;
$this->db->beginTransaction();
$this->db->intermediateChainDelete([
'p_domain' => $domain,
'p_port' => $port,
'p_identifier' => $identifier
]);
$i = 0;
foreach ($newChain as $chainCert) {
$params = [
'p_domain' => $domain,
'p_port' => $port,
'p_identifier' => $identifier,
'p_order' => $i++,
'p_subject_key_identifier' => $chainCert->subjectKeyIdentifier()
];
$this->db->intermediateChainInsert($params);
}
<