Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support OpenSSL version 1.1.1 and TLS protocol version 1.3 #1257

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions admin/CTK/CTK/Checkbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ class CheckCfg (Checkbox):
checkbox with the value of the configuration tree given by key
argument if it exists. It accepts properties to pass to the base
Checkbox object.
As an option the checkbox setting can be inverted to show checked
for False instead of True.

Arguments:
key: key in the configuration tree.
Expand All @@ -103,12 +105,16 @@ def __init__ (self, key, default, props=None):
if not props:
props = {}

self.invert = False
if props.has_key('mode') and props['mode'] == 'inverse':
self.invert = True

# Read the key value
val = cfg.get_val(key)
if not val:
props['checked'] = "01"[bool(int(default))]
if not val or (props.has_key('disabled') and int(props['disabled'])):
props['checked'] = '01'[bool(int(default))]
elif val.isdigit():
props['checked'] = "01"[bool(int(val))]
props['checked'] = ['01', '10'][self.invert][bool(int(val))]
else:
assert False, "Could not handle value: %s"%(val)

Expand Down Expand Up @@ -159,6 +165,40 @@ def __init__ (self, key, default, text='Enabled', props=None):
assert type(props) in (dict, type(None))

CheckCfg.__init__ (self, key, default, props)
if not props:
props = {}
self.text = text
self.disabled = False
if props.has_key('disabled') and int(props['disabled']):
self.disabled = True

def Render (self):
render = CheckCfg.Render (self)
render.html = '<div id="%s" class="checkbox-text">%s <div class="description">%s</div></div>' %(self.id, render.html, self.text)
if not self.disabled:
render.js += CLICK_CHANGE_JS %(self.id)
return render


class CheckCfgTextInv (CheckCfg):
"""
Configuration-Tree based CheckboxText widget. Populates the input
checkbox with the inverted value of the configuration tree given by key
argument if it exists. It accepts properties to pass to the base
CheckboxText object.

Arguments:
key: key in the configuration tree.
default: default value to give to the checkbox.
text: text to show beside the checkbox (by default, 'Enabled')
props: additional properties for base CheckboxText.
"""
def __init__ (self, key, default, text='Enabled', props=None):
assert type(default) == bool
assert type(text) == str
assert type(props) in (dict, type(None))

CheckCfg.__init__ (self, key, default, props, True)
self.text = text

def Render (self):
Expand Down
24 changes: 24 additions & 0 deletions admin/CTK/static/css/CTK.css
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ button:hover { cursor: pointer; }
padding: 1em 1em 1em 40px;
margin: 1em 0;
}
.dialog-information-slim {
background: #f9fcff url(/CTK/images/dialog-information.png) 4px 4px no-repeat;
-moz-border-radius: 4px; -webkit-border-radius: 4px;
border: 1px solid #d4e1f1;
padding: 1em 1em 1em 40px;
margin: 1em 0;
width: 50%
}
.dialog-important-information {
background: #e9ffd4 url(/CTK/images/dialog-information.png) 4px 4px no-repeat;
-moz-border-radius: 4px; -webkit-border-radius: 4px;
Expand All @@ -216,13 +224,29 @@ button:hover { cursor: pointer; }
padding: 1em 1em 1em 40px;
margin: 1em 0;
}
.dialog-warning-slim {
background: #fff2b3 url(/CTK/images/dialog-warning.png) 4px 4px no-repeat;
-moz-border-radius: 4px; -webkit-border-radius: 4px;
border: 1px solid #b90;
padding: 1em 1em 1em 40px;
margin: 1em 0;
width: 50%
}
.dialog-error {
background: #ffe7e7 url(/CTK/images/dialog-error.png) 4px 4px no-repeat;
-moz-border-radius: 4px; -webkit-border-radius: 4px;
border: 1px solid #c00;
padding: 1em 1em 1em 40px;
margin: 1em 0;
}
.dialog-error-slim {
background: #ffe7e7 url(/CTK/images/dialog-error.png) 4px 4px no-repeat;
-moz-border-radius: 4px; -webkit-border-radius: 4px;
border: 1px solid #c00;
padding: 1em 1em 1em 40px;
margin: 1em 0;
width: 50%
}

.dialog-information h2,
.dialog-warning h2,
Expand Down
6 changes: 5 additions & 1 deletion admin/CTK/static/js/Submitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ if ((typeof submitter_loaded) == 'undefined') {
}
});
self.find ("input:checkbox").each(function(){
info[this.name] = this.checked ? "1" : "0";
if (this.hasAttribute('mode') && this.getAttribute('mode') == 'inverse') {
info[this.name] = this.checked ? "0" : "1";
} else {
info[this.name] = this.checked ? "1" : "0";
}
});
self.find ("select").each(function(){
info[this.name] = $(this).val();
Expand Down
15 changes: 13 additions & 2 deletions admin/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@ endif

SUFFIXES = .py.pre .py

if USE_OPENSSL
minmaxtls = @USE_OPENSSL_MIN_MAX_PROTOCOL@
tlsprotocols = @OPENSSL_TLS_PROTOCOLS@
else
minmaxtls = False
tlsprotocols =
endif

.py.pre.py:
sed -e "s|%sysconfdir%|${sysconfdir}|g; s|%sbindir%|${sbindir}|g; s|%docdir%|${docdir}|g; s|%prefix%|${prefix}|g; s|%localstatedir%|${localstatedir}|g; s|%libdir%|${libdir}|g; s|%wwwroot%|${WWW_ROOT}|g; s|%version%|${PACKAGE_VERSION}|g; s|%phpcgi%|${PHPCGI}|g; s|%datadir%|${datadir}|g; s|%localedir%|${localedir}|g" $< > $@
sed -e "s|%sysconfdir%|${sysconfdir}|g; s|%sbindir%|${sbindir}|g; s|%docdir%|${docdir}|g; s|%prefix%|${prefix}|g; s|%localstatedir%|${localstatedir}|g; s|%libdir%|${libdir}|g; s|%wwwroot%|${WWW_ROOT}|g; s|%version%|${PACKAGE_VERSION}|g; s|%bugreportlink%|${PACKAGE_BUGREPORT}|g; s|%phpcgi%|${PHPCGI}|g; s|%datadir%|${datadir}|g; s|%localedir%|${localedir}|g; s|%minmaxtls%|$(minmaxtls)|g; s|%tlsprotocols%|$(tlsprotocols)|g" $< > $@

PY_PRE = \
configured.py.pre
Expand Down Expand Up @@ -103,4 +111,7 @@ CLEANFILES = \
$(generated_DATA)

test:
python -m compileall .
$(PYTHON) -m compileall .

clean-local:
find . -type f -name "*.pyc" -exec rm -f {} \;
145 changes: 128 additions & 17 deletions admin/PageAdvanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,31 @@
URL_BASE = '/advanced'
URL_APPLY = '/advanced/apply'

KNOWN_TLS_PROTOCOLS = [
('SSLv2', 'SSL version 2'),
('SSLv3', 'SSL version 3'),
('TLSv1', 'TLS version 1'),
('TLSv1.1', 'TLS version 1.1'),
('TLSv1.2', 'TLS version 1.2'),
('TLSv1.3', 'TLS version 1.3')
]

# Keep aligned with cherokee_cryptor_init_base()
TLS_PROTOCOL_CHECKBOX_DEFAULT = {
'SSLv2': True,
'SSLv3': True,
'TLSv1': False,
'TLSv1.1': False,
'TLSv1.2': False,
'TLSv1.3': False
}

TLS_WARNING = N_("""<p><b>WARNING</b>: The SSL/TLS back-end supports more recent
versions of TLS protocols, which are not recognized by Cherokee. Please check
for latest Cherokee updates or report this issue. As a temporary workaround please
set 'Max. TLS protocol version' to the maximum TLS protocol version supported by
Cherokee.</p><p>Following unknown TLS protocols have been found:""")

VALIDATIONS = [
("server!fdlimit", validations.is_positive_int),
("server!pid_file", validations.can_create_file),
Expand All @@ -58,6 +83,7 @@
("server!tls!protocol!TLSv1", validations.is_boolean),
("server!tls!protocol!TLSv1_1", validations.is_boolean),
("server!tls!protocol!TLSv1_2", validations.is_boolean),
("server!tls!protocol!TLSv1_3", validations.is_boolean),
("server!tls!timeout_handshake", validations.is_positive_int),
("server!tls!dh_param512", validations.is_local_file_exists),
("server!tls!dh_param1024", validations.is_local_file_exists),
Expand Down Expand Up @@ -94,12 +120,27 @@
NOTE_DH1024 = N_('Path to a Diffie Hellman (DH) parameters PEM file: 1024 bits.')
NOTE_DH2048 = N_('Path to a Diffie Hellman (DH) parameters PEM file: 2048 bits.')
NOTE_DH4096 = N_('Path to a Diffie Hellman (DH) parameters PEM file: 4096 bits.')
NOTE_TLS_NA = N_('Your Cherokee Web Server does not support SSL/TLS encryption.')
NOTE_TLS_TIMEOUT = N_('Timeout for the TLS/SSL handshake. Default: 15 seconds.')
NOTE_TLS_SSLv2 = N_('Allow clients to use SSL version 2 - Beware: it is vulnerable. (Default: No)')
NOTE_TLS_SSLv3 = N_('Allow clients to use SSL version 3 - Beware: it is vulnerable. (Default: No)')
NOTE_TLS_TLSv1 = N_('Allow clients to use TLS version 1 (Default: Yes)')
NOTE_TLS_TLSv1_1 = N_('Allow clients to use TLS version 1.1 (Default: Yes)')
NOTE_TLS_TLSv1_2 = N_('Allow clients to use TLS version 1.2 (Default: Yes)')
NOTE_TLS_SSLv2 = N_('Beware: it is vulnerable. You should disable SSLv2.')
NOTE_TLS_SSLv3 = N_('Beware: it is vulnerable. You should disable SSLv3.')
NOTE_TLS_TLSv1 = N_('TLSv1 is deprecated')
NOTE_TLS_TLSv1_1 = N_('TLSv1.1 is deprecated')
NOTE_TLS_TLSv1_2 = N_(' ')
NOTE_TLS_TLSv1_3 = N_(' ')
NOTE_TLS_DISABLE = N_('The following options work in combination with above min/max TLS protocol version settings. '
'They are deprecated, only set the minimum and maximum supported protocol versions instead.')
NOTE_TLS_MIN = N_('Minimum required TLS protocol version from clients (Default: auto-configured by libssl)')
NOTE_TLS_MAX = N_('Maximum supported TLS protocol version (Default: auto-configured by libssl)')

TLS_PROTOCOL_NOTES = {
'SSLv2': NOTE_TLS_SSLv2,
'SSLv3': NOTE_TLS_SSLv3,
'TLSv1': NOTE_TLS_TLSv1,
'TLSv1.1': NOTE_TLS_TLSv1_1,
'TLSv1.2': NOTE_TLS_TLSv1_2,
'TLSv1.3': NOTE_TLS_TLSv1_3
}

HELPS = [('config_advanced', N_('Advanced'))]

Expand Down Expand Up @@ -176,23 +217,93 @@ def __init__ (self):
self += CTK.Indenter(table)

class TLSWidget (CTK.Container):
@staticmethod
def check_for_tls_protocol_versions (self):
available_tls_protocols = {}
unknown_tls_protocols = []
tls_option_list = TLSPROTOCOLS.split(',')
if len(tls_option_list) > 1:
for protocol in tls_option_list:
for known_protocol in KNOWN_TLS_PROTOCOLS:
if known_protocol[0] == protocol:
available_tls_protocols[protocol] = known_protocol[1]
break
else:
unknown_tls_protocols.append(protocol)
return available_tls_protocols, unknown_tls_protocols

@staticmethod
def add_tls_version_config (self, table):
props = {}
props = {'mode': 'inverse'}
props_disable = props.copy()
props_disable["disabled"] = 1
for protocol in KNOWN_TLS_PROTOCOLS:
if self.available_tls_protocols.has_key(protocol[0]):
table.Add ('%s%s' % (_('Disable '), self.available_tls_protocols[protocol[0]]), CTK.CheckCfgText('server!tls!protocol!' + protocol[0].replace('.','_'), TLS_PROTOCOL_CHECKBOX_DEFAULT[protocol[0]], _("Disable"), props), TLS_PROTOCOL_NOTES[protocol[0]])
else:
table.Add ('%s%s' % (_('Disable '), protocol[1]), CTK.CheckCfgText('server!tls!protocol!' + protocol[0].replace('.','_'), True, _("Protocol deacrivated") if protocol[0].startswith('SSLv') else _("Protocol not supported"), props_disable), TLS_PROTOCOL_NOTES[protocol[0]])

@staticmethod
def add_tls_version_disable_section (self):
props = {}
props = {'mode': 'inverse'}
props_disable = props.copy()
props_disable["disabled"] = 1
table = CTK.PropsAuto(URL_APPLY)
for protocol in KNOWN_TLS_PROTOCOLS:
if self.available_tls_protocols.has_key(protocol[0]):
table.Add ('%s%s' % (_('Disable '), self.available_tls_protocols[protocol[0]]), CTK.CheckCfgText('server!tls!protocol!' + protocol[0].replace('.','_'), TLS_PROTOCOL_CHECKBOX_DEFAULT[protocol[0]], _("Disable"), props), "")
else:
table.Add ('%s%s' % (_('Disable '), protocol[1]), CTK.CheckCfgText('server!tls!protocol!' + protocol[0].replace('.','_'), True, _("Protocol deactivated"), props_disable), "")

self += CTK.RawHTML ("<h3>%s</h3>" %(_('Turn off selected TLS Protocols (Deprecated)')))
tip = '%s' %(_(NOTE_TLS_DISABLE))
props = {'class': 'dialog-information-slim'}
self += CTK.Indenter (CTK.Notice ('information', CTK.RawHTML(tip), props))
self += CTK.Indenter(table)

def __init__ (self):
CTK.Container.__init__ (self)
tls_min_protocols = [('auto', N_('auto-configured'))]
tls_max_protocols = [('auto', N_('auto-configured'))]

table = CTK.PropsAuto(URL_APPLY)
table.Add (_('SSL version 2'), CTK.CheckCfgText('server!tls!protocol!SSLv2', False, _("Allow")), _(NOTE_TLS_SSLv2))
table.Add (_('SSL version 3'), CTK.CheckCfgText('server!tls!protocol!SSLv3', False, _("Allow")), _(NOTE_TLS_SSLv3))
table.Add (_('TLS version 1'), CTK.CheckCfgText('server!tls!protocol!TLSv1', True, _("Allow")), _(NOTE_TLS_TLSv1))
table.Add (_('TLS version 1.1'), CTK.CheckCfgText('server!tls!protocol!TLSv1_1', True, _("Allow")), _(NOTE_TLS_TLSv1_1))
table.Add (_('TLS version 1.2'), CTK.CheckCfgText('server!tls!protocol!TLSv1_2', True, _("Allow")), _(NOTE_TLS_TLSv1_2))
table.Add (_('Handshake Timeout'), CTK.TextCfg('server!tls!timeout_handshake', True), _(NOTE_TLS_TIMEOUT))
table.Add (_('DH parameters: 512 bits'), CTK.TextCfg('server!tls!dh_param512', True), _(NOTE_DH512))
table.Add (_('DH parameters: 1024 bits'), CTK.TextCfg('server!tls!dh_param1024', True), _(NOTE_DH1024))
table.Add (_('DH parameters: 2048 bits'), CTK.TextCfg('server!tls!dh_param2048', True), _(NOTE_DH2048))
table.Add (_('DH parameters: 4096 bits'), CTK.TextCfg('server!tls!dh_param4096', True), _(NOTE_DH4096))
if MINMAXTLS == True and KNOWN_TLS_PROTOCOLS[0][0] == 'SSLv2':
# Staring with OpenSSL 1.1.1, i. e. MINMAXTLS = True SSLv2 has been removed
KNOWN_TLS_PROTOCOLS.pop(0)
self.available_tls_protocols, self.unknown_tls_protocols = TLSWidget.check_for_tls_protocol_versions (self)

table = CTK.PropsAuto(URL_APPLY)
if MINMAXTLS == False:
TLSWidget.add_tls_version_config (self, table)
else:
for protocol in KNOWN_TLS_PROTOCOLS:
if self.available_tls_protocols.has_key(protocol[0]):
tls_min_protocols.append((protocol[0], N_(self.available_tls_protocols[protocol[0]])))
table.Add (_('Min. TLS protocol version'), CTK.ComboCfg('server!tls!protocol!min', trans_options(tls_min_protocols)), _(NOTE_TLS_MIN))
KNOWN_TLS_PROTOCOLS.reverse()
for protocol in KNOWN_TLS_PROTOCOLS:
if self.available_tls_protocols.has_key(protocol[0]):
tls_max_protocols.append((protocol[0], N_(self.available_tls_protocols[protocol[0]])))
table.Add (_('Max. TLS protocol version'), CTK.ComboCfg('server!tls!protocol!max', trans_options(tls_max_protocols)), _(NOTE_TLS_MAX))
table.Add (_('Handshake Timeout'), CTK.TextCfg('server!tls!timeout_handshake', True), _(NOTE_TLS_TIMEOUT))
table.Add (_('DH parameters: 512 bits'), CTK.TextCfg('server!tls!dh_param512', True), _(NOTE_DH512))
table.Add (_('DH parameters: 1024 bits'), CTK.TextCfg('server!tls!dh_param1024', True), _(NOTE_DH1024))
table.Add (_('DH parameters: 2048 bits'), CTK.TextCfg('server!tls!dh_param2048', True), _(NOTE_DH2048))
table.Add (_('DH parameters: 4096 bits'), CTK.TextCfg('server!tls!dh_param4096', True), _(NOTE_DH4096))
self += CTK.RawHTML ("<h2>%s</h2>" %(_('TLS')))
self += CTK.Indenter(table)
if len(self.unknown_tls_protocols) > 0:
tip = '%s %s</p>' % (_(TLS_WARNING), join(self.unknown_tls_protocols))
props = {'class': 'dialog-error-slim'}
self += CTK.Notice ('error', CTK.RawHTML(tip), props)
if len(self.available_tls_protocols) == 0:
self += CTK.RawHTML ("<p>%s</p>" %(_(NOTE_TLS_NA)))
else:
self += CTK.Indenter(table)

if MINMAXTLS == True:
KNOWN_TLS_PROTOCOLS.reverse()
TLSWidget.add_tls_version_disable_section (self)

class Render:
def __call__ (self):
Expand Down
2 changes: 1 addition & 1 deletion admin/PageException.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from urllib import quote, unquote, urlencode
from httplib import HTTPConnection

URL_BTS = 'http://bugs.cherokee-project.com/new'
URL_BTS = configured.BUGREPORTLINK
URL_REPORT_HOST = 'www.cherokee-project.com'
URL_REPORT_URL = '/CTK_ok.html'

Expand Down
2 changes: 1 addition & 1 deletion admin/PageGeneral.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
NOTE_DELETE_DIALOG = N_('You are about to delete an binding. Are you sure you want to proceed?')

HELPS = [('config_general', N_("General Configuration")),
('config_quickstart', N_("Configuration Quickstart"))]
('config_walkthrough', N_("Configuration Quickstart"))]


VALIDATIONS = [
Expand Down
2 changes: 1 addition & 1 deletion admin/PageIndex.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from configured import *

# Links
LINK_BUGTRACKER = 'http://bugs.cherokee-project.com/'
LINK_BUGTRACKER = BUGREPORTLINK
LINK_TWITTER = 'http://twitter.com/webserver'
LINK_FACEBOOK = 'http://www.facebook.com/cherokee.project'
LINK_GOOGLEPLUS = 'https://plus.google.com/u/1/communities/109478817835447552345'
Expand Down
13 changes: 11 additions & 2 deletions admin/PageVServer.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,15 @@
URL_BASE = '/vserver/content'
URL_APPLY = '/vserver/content/apply'

URL_OPENSSL_REFERENCE = '<a target="_blank" href="http://www.openssl.org/docs/apps/openssl-ciphers.html">%s</a>' % (_('Reference'))
URL_MOZILLA = '<a target="_blank" href="https://wiki.mozilla.org/Security/Server_Side_TLS#">Mozilla</a>'

NOTE_NICKNAME = N_('Nickname for the virtual server.')
NOTE_CERT = N_('This directive points to the PEM-encoded Certificate file for the server (Full path to the file)')
NOTE_CERT_KEY = N_('PEM-encoded Private Key file for the server (Full path to the file)')
NOTE_CA_LIST = N_('File containing the trusted CA certificates, utilized for checking the client certificates (Full path to the file)')
NOTE_CIPHERS = N_('Ciphers that TLS/SSL is allowed to use. <a target="_blank" href="http://www.openssl.org/docs/apps/ciphers.html">Reference</a>. (Default enables Forward Secrecy).')
NOTE_CIPHERS = N_('Ciphers that TLSv1.2 and below is allowed to use.')
NOTE_CIPHERSUITES = N_('Ciphersuites that TLSv1.3 is allowed to use.')
NOTE_CIPHER_SERVER_PREFERENCE = N_('The cipher sequence that is specified by the server should have preference over the client preference. (Default: True).')
NOTE_COMPRESSION = N_('Explicitly enable or disable serverside compression support. (Default: Disabled).')
NOTE_DH_LENGTH = N_('Explicitely sets the Diffie-Hellman parameters length. (Default: Let openssl choose).')
Expand Down Expand Up @@ -661,9 +665,14 @@ def __init__ (self, vsrv_num, refreshable):
self += CTK.RawHTML ('<h2>%s</h2>' % (_('Required SSL/TLS Values')))
self += CTK.Indenter (submit)

CIPHER_COMP = 'Intermediate Compatibility'
if MINMAXTLS == False:
CIPHER_COMP = 'Old Compatibility'

# Advanced options
table = CTK.PropsTable()
table.Add (_('Ciphers'), CTK.TextCfg ('%s!ssl_ciphers' %(pre), True), _(NOTE_CIPHERS))
table.Add (_('Ciphersuites'), CTK.TextCfg ('%s!ssl_ciphersuites' %(pre), True), '%s %s. %s: %s Intermediate Compatibility %s.' % (_(NOTE_CIPHERSUITES), URL_OPENSSL_REFERENCE, _('Default'), URL_MOZILLA, _('Ciphersuites')))
table.Add (_('Ciphers'), CTK.TextCfg ('%s!ssl_ciphers' %(pre), True), '%s %s. %s: %s %s %s' % (_(NOTE_CIPHERS), URL_OPENSSL_REFERENCE, _('Default'), URL_MOZILLA, CIPHER_COMP, _('Ciphers')))
table.Add (_('Server Preference'), CTK.CheckCfgText ('%s!ssl_cipher_server_preference' % (pre), True, _('Prefer')), _(NOTE_CIPHER_SERVER_PREFERENCE))
table.Add (_('Client Certs. Request'), CTK.ComboCfg('%s!ssl_client_certs' %(pre), trans_options(CLIENT_CERTS)), _(NOTE_CLIENT_CERTS))
table.Add (_('Compression'), CTK.CheckCfgText ('%s!ssl_compression' % (pre), False, _('Enable')), _(NOTE_COMPRESSION))
Expand Down
Loading