From ec1bd6e19a3b8c68a1aa2be1bc521d63fea92f71 Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Tue, 11 Apr 2017 17:09:34 +0200 Subject: [PATCH] add OCSP stapling support for apache2 and nginx --- actions/admin/settings/131.ssl.php | 12 ++++ admin_domains.php | 56 +++++++++++++++++-- install/froxlor.sql | 4 +- .../updates/froxlor/0.9/update_0.9.inc.php | 14 +++++ lib/classes/webserver/class.WebserverBase.php | 3 +- .../admin/domains/formfield.domains_add.php | 19 ++++++- .../admin/domains/formfield.domains_edit.php | 21 ++++++- lib/version.inc.php | 2 +- lng/english.lng.php | 7 +++ lng/german.lng.php | 7 +++ .../jobs/cron_tasks.inc.http.10.apache.php | 19 ++++++- scripts/jobs/cron_tasks.inc.http.30.nginx.php | 8 +++ 12 files changed, 160 insertions(+), 12 deletions(-) diff --git a/actions/admin/settings/131.ssl.php b/actions/admin/settings/131.ssl.php index 56c27cd5..7a73da85 100644 --- a/actions/admin/settings/131.ssl.php +++ b/actions/admin/settings/131.ssl.php @@ -79,6 +79,18 @@ return array( 'default' => '', 'save_method' => 'storeSettingField' ), + 'system_apache24_ocsp_cache_path' => array( + 'label' => $lng['serversettings']['ssl']['apache24_ocsp_cache_path'], + 'settinggroup' => 'system', + 'varname' => 'apache24_ocsp_cache_path', + 'type' => 'string', + 'string_type' => 'string', + 'string_emptyallowed' => false, + 'default' => '', + 'visible' => Settings::Get('system.webserver') == "apache2" && + Settings::Get('system.apache24') == 1, + 'save_method' => 'storeSettingField' + ), 'system_leenabled' => array( 'label' => $lng['serversettings']['leenabled'], 'settinggroup' => 'system', diff --git a/admin_domains.php b/admin_domains.php index 8a28364c..f2a877aa 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -595,6 +595,9 @@ if ($page == 'domains' || $page == 'overview') { $hsts_sub = isset($_POST['hsts_sub']) && (int)$_POST['hsts_sub'] == 1 ? 1 : 0; $hsts_preload = isset($_POST['hsts_preload']) && (int)$_POST['hsts_preload'] == 1 ? 1 : 0; + // OCSP stapling + $ocsp_stapling = isset($_POST['ocsp_stapling']) && (int)$_POST['ocsp_stapling'] == 1 ? 1 : 0; + } else { $ssl_redirect = 0; $letsencrypt = 0; @@ -606,6 +609,9 @@ if ($page == 'domains' || $page == 'overview') { $hsts_maxage = 0; $hsts_sub = 0; $hsts_preload = 0; + + // OCSP stapling + $ocsp_stapling = 0; } } else { $ssl_redirect = 0; @@ -618,6 +624,9 @@ if ($page == 'domains' || $page == 'overview') { $hsts_maxage = 0; $hsts_sub = 0; $hsts_preload = 0; + + // OCSP stapling + $ocsp_stapling = 0; } // We can't enable let's encrypt for wildcard - domains @@ -789,7 +798,8 @@ if ($page == 'domains' || $page == 'overview') { 'letsencrypt' => $letsencrypt, 'hsts_maxage' => $hsts_maxage, 'hsts_sub' => $hsts_sub, - 'hsts_preload' => $hsts_preload + 'hsts_preload' => $hsts_preload, + 'ocsp_stapling' => $ocsp_stapling, ); $security_questions = array( @@ -841,7 +851,8 @@ if ($page == 'domains' || $page == 'overview') { 'letsencrypt' => $letsencrypt, 'hsts' => $hsts_maxage, 'hsts_sub' => $hsts_sub, - 'hsts_preload' => $hsts_preload + 'hsts_preload' => $hsts_preload, + 'ocsp_stapling' => $ocsp_stapling, ); $ins_stmt = Database::prepare(" @@ -878,7 +889,8 @@ if ($page == 'domains' || $page == 'overview') { `letsencrypt` = :letsencrypt, `hsts` = :hsts, `hsts_sub` = :hsts_sub, - `hsts_preload` = :hsts_preload + `hsts_preload` = :hsts_preload, + `ocsp_stapling` = :ocsp_stapling "); Database::pexecute($ins_stmt, $ins_data); $domainid = Database::lastInsertId(); @@ -1421,6 +1433,9 @@ if ($page == 'domains' || $page == 'overview') { $hsts_sub = isset($_POST['hsts_sub']) && (int)$_POST['hsts_sub'] == 1 ? 1 : 0; $hsts_preload = isset($_POST['hsts_preload']) && (int)$_POST['hsts_preload'] == 1 ? 1 : 0; + // OCSP stapling + $ocsp_stapling = isset($_POST['ocsp_stapling']) && (int)$_POST['ocsp_stapling'] == 1 ? 1 : 0; + $ssl_ipandports = array(); if (isset($_POST['ssl_ipandport']) && ! is_array($_POST['ssl_ipandport'])) { $_POST['ssl_ipandport'] = unserialize($_POST['ssl_ipandport']); @@ -1458,6 +1473,9 @@ if ($page == 'domains' || $page == 'overview') { $hsts_maxage = 0; $hsts_sub = 0; $hsts_preload = 0; + + // OCSP stapling + $ocsp_stapling = 0; } } else { $ssl_redirect = 0; @@ -1470,6 +1488,9 @@ if ($page == 'domains' || $page == 'overview') { $hsts_maxage = 0; $hsts_sub = 0; $hsts_preload = 0; + + // OCSP stapling + $ocsp_stapling = 0; } // We can't enable let's encrypt for wildcard domains @@ -1615,7 +1636,8 @@ if ($page == 'domains' || $page == 'overview') { 'letsencrypt' => $letsencrypt, 'hsts_maxage' => $hsts_maxage, 'hsts_sub' => $hsts_sub, - 'hsts_preload' => $hsts_preload + 'hsts_preload' => $hsts_preload, + 'ocsp_stapling' => $ocsp_stapling, ); $security_questions = array( @@ -1634,7 +1656,27 @@ if ($page == 'domains' || $page == 'overview') { $wwwserveralias = ($serveraliasoption == '1') ? '1' : '0'; $iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0'; - if ($documentroot != $result['documentroot'] || $ssl_redirect != $result['ssl_redirect'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $phpenabled != $result['phpenabled'] || $openbasedir != $result['openbasedir'] || $phpsettingid != $result['phpsettingid'] || $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $specialsettings != $result['specialsettings'] || $aliasdomain != $result['aliasdomain'] || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload']) { + if ( + $documentroot != $result['documentroot'] || + $ssl_redirect != $result['ssl_redirect'] || + $wwwserveralias != $result['wwwserveralias'] || + $iswildcarddomain != $result['iswildcarddomain'] || + $phpenabled != $result['phpenabled'] || + $openbasedir != $result['openbasedir'] || + $phpsettingid != $result['phpsettingid'] || + $mod_fcgid_starter != $result['mod_fcgid_starter'] || + $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || + $specialsettings != $result['specialsettings'] || + $aliasdomain != $result['aliasdomain'] || + $issubof != $result['ismainbutsubto'] || + $email_only != $result['email_only'] || + ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || + $letsencrypt != $result['letsencrypt'] || + $hsts_maxage != $result['hsts'] || + $hsts_sub != $result['hsts_sub'] || + $hsts_preload != $result['hsts_preload'] || + $ocsp_stapling != $result['ocsp_stapling'] + ) { inserttask('1'); } @@ -1789,6 +1831,7 @@ if ($page == 'domains' || $page == 'overview') { $update_data['hsts'] = $hsts_maxage; $update_data['hsts_sub'] = $hsts_sub; $update_data['hsts_preload'] = $hsts_preload; + $update_data['ocsp_stapling'] = $ocsp_stapling; $update_data['id'] = $id; $update_stmt = Database::prepare(" @@ -1820,7 +1863,8 @@ if ($page == 'domains' || $page == 'overview') { `letsencrypt` = :letsencrypt, `hsts` = :hsts, `hsts_sub` = :hsts_sub, - `hsts_preload` = :hsts_preload + `hsts_preload` = :hsts_preload, + `ocsp_stapling` = :ocsp_stapling WHERE `id` = :id "); Database::pexecute($update_stmt, $update_data); diff --git a/install/froxlor.sql b/install/froxlor.sql index d8d600a0..fa352c50 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -257,6 +257,7 @@ CREATE TABLE `panel_domains` ( `hsts` varchar(10) NOT NULL default '0', `hsts_sub` tinyint(1) NOT NULL default '0', `hsts_preload` tinyint(1) NOT NULL default '0', + `ocsp_stapling` tinyint(1) DEFAULT '0', PRIMARY KEY (`id`), KEY `customerid` (`customerid`), KEY `parentdomain` (`parentdomainid`), @@ -503,6 +504,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('system', 'perl_server', 'unix:/var/run/nginx/cgiwrap-dispatch.sock'), ('system', 'phpreload_command', ''), ('system', 'apache24', '0'), + ('system', 'apache24_ocsp_cache_path', 'shmcb:/var/run/apache2/ocsp-stapling.cache(131072)'), ('system', 'documentroot_use_default_value', '0'), ('system', 'passwordcryptfunc', '3'), ('system', 'axfrservers', ''), @@ -582,7 +584,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('panel', 'password_special_char', '!?<>§$%+#=@'), ('panel', 'customer_hide_options', ''), ('panel', 'version', '0.9.38.7'), - ('panel', 'db_version', '201612110'); + ('panel', 'db_version', '201704100'); DROP TABLE IF EXISTS `panel_tasks`; diff --git a/install/updates/froxlor/0.9/update_0.9.inc.php b/install/updates/froxlor/0.9/update_0.9.inc.php index d8aa8735..10a2ef19 100644 --- a/install/updates/froxlor/0.9/update_0.9.inc.php +++ b/install/updates/froxlor/0.9/update_0.9.inc.php @@ -3593,3 +3593,17 @@ if (isFroxlorVersion('0.9.38.6')) { showUpdateStep("Updating from 0.9.38.6 to 0.9.38.7", false); updateToVersion('0.9.38.7'); } + +if (isDatabaseVersion('201612110')) { + + showUpdateStep("Adding field for OCSP stapling"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . + "` ADD `ocsp_stapling` TINYINT(1) NOT NULL DEFAULT '0';"); + lastStepStatus(0); + + showUpdateStep("Adding default setting for Apache 2.4 OCSP cache path"); + Settings::AddNew('system.apache24_ocsp_cache_path', 'shmcb:/var/run/apache2/ocsp-stapling.cache(131072)'); + lastStepStatus(0); + + updateToDbVersion('201704100'); +} diff --git a/lib/classes/webserver/class.WebserverBase.php b/lib/classes/webserver/class.WebserverBase.php index b827f04c..8f7c27c5 100644 --- a/lib/classes/webserver/class.WebserverBase.php +++ b/lib/classes/webserver/class.WebserverBase.php @@ -33,7 +33,8 @@ class WebserverBase { `c`.`documentroot` AS `customerroot`, `c`.`deactivated`, `c`.`phpenabled` AS `phpenabled_customer`, `d`.`phpenabled` AS `phpenabled_vhost`, - `d`.`mod_fcgid_starter`,`d`.`mod_fcgid_maxrequests` + `d`.`mod_fcgid_starter`,`d`.`mod_fcgid_maxrequests`, + `d`.`ocsp_stapling` FROM `".TABLE_PANEL_DOMAINS."` `d` LEFT JOIN `".TABLE_PANEL_CUSTOMERS."` `c` USING(`customerid`) diff --git a/lib/formfields/admin/domains/formfield.domains_add.php b/lib/formfields/admin/domains/formfield.domains_add.php index 8482123e..988c496f 100644 --- a/lib/formfields/admin/domains/formfield.domains_add.php +++ b/lib/formfields/admin/domains/formfield.domains_add.php @@ -213,7 +213,24 @@ return array( ) ), 'value' => array() - ) + ), + 'ocsp_stapling' => array( + 'visible' => ($ssl_ipsandports != '' ? true : false) && + Settings::Get('system.webserver') != 'lighttpd', + 'label' => $lng['admin']['domain_ocsp_stapling']['title'], + 'desc' => $lng['admin']['domain_ocsp_stapling']['description'] . + (Settings::Get('system.webserver') == 'nginx' ? + $lng['admin']['domain_ocsp_stapling']['nginx_version_warning'] : + ""), + 'type' => 'checkbox', + 'values' => array( + array ( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() + ), ) ), 'section_c' => array( diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 22a293cc..e351c8da 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -251,7 +251,26 @@ return array( 'value' => array( $result['hsts_preload'] ) - ) + ), + 'ocsp_stapling' => array( + 'visible' => ($ssl_ipsandports != '' ? true : false) && + Settings::Get('system.webserver') != 'lighttpd', + 'label' => $lng['admin']['domain_ocsp_stapling']['title'], + 'desc' => $lng['admin']['domain_ocsp_stapling']['description'] . + (Settings::Get('system.webserver') == 'nginx' ? + $lng['admin']['domain_ocsp_stapling']['nginx_version_warning'] : + ""), + 'type' => 'checkbox', + 'values' => array( + array ( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['ocsp_stapling'] + ) + ), ) ), 'section_c' => array( diff --git a/lib/version.inc.php b/lib/version.inc.php index 3ce16650..db028f51 100644 --- a/lib/version.inc.php +++ b/lib/version.inc.php @@ -19,7 +19,7 @@ $version = '0.9.38.7'; // Database version (YYYYMMDDC where C is a daily counter) -$dbversion = '201612110'; +$dbversion = '201704100'; // Distribution branding-tag (used for Debian etc.) $branding = ''; diff --git a/lng/english.lng.php b/lng/english.lng.php index 59765e15..8ed89fd8 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -2067,3 +2067,10 @@ $lng['serversettings']['nginx_http2_support']['title'] = 'Nginx HTTP2 Support'; $lng['serversettings']['nginx_http2_support']['description'] = 'enable http2 support for ssl. ENABLE ONLY IF YOUR Nginx SUPPORT THIS FEATURE. (version 1.9.5+)'; $lng['error']['noipportgiven'] = 'No IP/port given'; + +// Added in froxlor 0.9.38.8 +$lng['admin']['domain_ocsp_stapling']['title'] = 'OCSP stapling'; +$lng['admin']['domain_ocsp_stapling']['description'] = 'See Wikipedia for a detailed explanation of OCSP stapling'; +$lng['admin']['domain_ocsp_stapling']['nginx_version_warning'] = '
WARNING: Nginx version 1.3.7 or above is required for OCSP stapling. If your version is older, the webserver will NOT start correctly while OCSP stapling is enabled!'; +$lng['serversettings']['ssl']['apache24_ocsp_cache_path']['title'] = 'Apache 2.4: path to the OCSP stapling cache'; +$lng['serversettings']['ssl']['apache24_ocsp_cache_path']['description'] = 'Configures the cache used to store OCSP responses which get included in TLS handshakes.'; diff --git a/lng/german.lng.php b/lng/german.lng.php index af0b418a..57e9476c 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1718,3 +1718,10 @@ $lng['serversettings']['nginx_http2_support']['title'] = 'Nginx HTTP2 Unterstüt $lng['serversettings']['nginx_http2_support']['description'] = 'Aktiviere http2 Unterstützung für SSL. NUR AKTIVIEREN, WENN nginx DIESE FUNKTION UNTERSTÜTZT (version 1.9.5+)'; $lng['error']['noipportgiven'] = 'Keine IP/Port angegeben'; + +// Added in froxlor 0.9.38.8 +$lng['admin']['domain_ocsp_stapling']['title'] = 'OCSP stapling'; +$lng['admin']['domain_ocsp_stapling']['description'] = 'Siehe Wikipedia für eine ausführliche Beschreibung von OCSP-Stapling'; +$lng['admin']['domain_ocsp_stapling']['nginx_version_warning'] = '
WARNUNG: Nginx unterstützt OCSP-Stapling erst ab Version 1.3.7. Wenn Ihre Version älter ist, wird der Webserver bei aktiviertem OCSP-Stapling NICHT korrekt starten.'; +$lng['serversettings']['ssl']['apache24_ocsp_cache_path']['title'] = 'Apache 2.4: Pfad zum OCSP-Stapling-Cache'; +$lng['serversettings']['ssl']['apache24_ocsp_cache_path']['description'] = 'Konfiguriert den Cache-Pfad zum Zwischenspeichern der OCSP-Antworten,
die an TLS-Handshakes angehängt werden.'; diff --git a/scripts/jobs/cron_tasks.inc.http.10.apache.php b/scripts/jobs/cron_tasks.inc.http.10.apache.php index c3de7b5a..85ef9bac 100644 --- a/scripts/jobs/cron_tasks.inc.http.10.apache.php +++ b/scripts/jobs/cron_tasks.inc.http.10.apache.php @@ -107,6 +107,17 @@ class apache extends HttpConfigBase } $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; } + + $ocsp_cache_filename = makeCorrectFile($vhosts_folder . '/03_froxlor_ocsp_cache.conf'); + if (Settings::Get('system.use_ssl') == '1' && Settings::Get('system.apache24') == 1) { + $this->virtualhosts_data[$ocsp_cache_filename] = 'SSLStaplingCache ' . + Settings::Get('system.apache24_ocsp_cache_path') . "\n"; + } else { + if (file_exists($ocsp_cache_filename)) { + $this->logger->logAction(CRON_ACTION, LOG_NOTICE, 'apache::_createStandardDirectoryEntry: unlinking ' . basename($ocsp_cache_filename)); + unlink(makeCorrectFile($ocsp_cache_filename)); + } + } } /** @@ -504,7 +515,7 @@ class apache extends HttpConfigBase // This vHost has PHP enabled and we are using the regular mod_php $cmail = getCustomerDetail($domain['customerid'], 'email'); $php_options_text .= ' php_admin_value sendmail_path "/usr/sbin/sendmail -t -f '.$cmail.'"' . PHP_EOL; - + if ($domain['openbasedir'] == '1') { if ($domain['openbasedir_path'] == '1' || strstr($domain['documentroot'], ":") !== false) { $_phpappendopenbasedir = appendOpenBasedirPath($domain['customerroot'], true); @@ -878,6 +889,12 @@ class apache extends HttpConfigBase $vhost_content .= ' SSLCertificateChainFile ' . makeCorrectFile($domain['ssl_cert_chainfile']) . "\n"; } + if (Settings::Get('system.apache24') == '1' && isset($domain['ocsp_stapling']) && + $domain['ocsp_stapling'] == '1') + { + $vhost_content .= ' SSLUseStapling on' . PHP_EOL; + } + if ($domain['hsts'] >= 0) { $vhost_content .= ' ' . "\n"; $vhost_content .= ' Header always set Strict-Transport-Security "max-age=' . $domain['hsts']; diff --git a/scripts/jobs/cron_tasks.inc.http.30.nginx.php b/scripts/jobs/cron_tasks.inc.http.30.nginx.php index 551d43b9..9e282193 100644 --- a/scripts/jobs/cron_tasks.inc.http.30.nginx.php +++ b/scripts/jobs/cron_tasks.inc.http.30.nginx.php @@ -634,6 +634,14 @@ class nginx extends HttpConfigBase } $sslsettings .= '";' . "\n"; } + + if ((isset($domain_or_ip['ocsp_stapling']) && $domain_or_ip['ocsp_stapling'] == "1") || + (isset($domain_or_ip['letsencrypt']) && $domain_or_ip['letsencrypt'] == "1") ) { + $sslsettings .= "\t" . 'ssl_stapling on;' . "\n"; + $sslsettings .= "\t" . 'ssl_stapling_verify on;' . "\n"; + $sslsettings .= "\t" . 'ssl_trusted_certificate ' . + makeCorrectFile($domain_or_ip['ssl_cert_file']) . ';' . "\n"; + } } }