mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-14 14:49:21 +01:00
Verify server certificate, and deprecate Python < 2.7.9. Closes GH-1031.
This commit is contained in:
parent
c3dd5f8b64
commit
d922af1043
11
setup.py
11
setup.py
@ -236,10 +236,11 @@ setup(
|
||||
|
||||
)
|
||||
|
||||
if sys.version_info < (2, 7, 0):
|
||||
sys.stderr.write('+-----------------------------------------------+\n')
|
||||
sys.stderr.write('| Running Limnoria on Python 2.6 is deprecated. |\n')
|
||||
sys.stderr.write('| Please consider upgrading to Python 3.x. |\n')
|
||||
sys.stderr.write('+-----------------------------------------------+\n')
|
||||
if sys.version_info < (2, 7, 9):
|
||||
sys.stderr.write('+------------------------------------------------+\n')
|
||||
sys.stderr.write('| Running Limnoria on Python versions older than |\n')
|
||||
sys.stderr.write('| 2.7.9 is deprecated. |\n')
|
||||
sys.stderr.write('| Please consider upgrading to Python 3.x. |\n')
|
||||
sys.stderr.write('+------------------------------------------------+\n')
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||
|
17
src/conf.py
17
src/conf.py
@ -1163,6 +1163,23 @@ registerGlobalValue(supybot.protocols.http, 'proxy',
|
||||
through. The value should be of the form 'host:port'.""")))
|
||||
utils.web.proxy = supybot.protocols.http.proxy
|
||||
|
||||
###
|
||||
# supybot.protocols.ssl
|
||||
###
|
||||
registerGroup(supybot.protocols, 'ssl')
|
||||
class SSLVerifyMode(registry.OnlySomeStrings):
|
||||
validStrings = ('required', 'optional', 'none')
|
||||
def __call__(self):
|
||||
import ssl
|
||||
value = super(SSLVerifyMode, self).__call__()
|
||||
return getattr(ssl, 'CERT_' + value.upper())
|
||||
registerGlobalValue(supybot.protocols.ssl, 'verifyMode',
|
||||
SSLVerifyMode('required', _("""Determines whether server certificates '
|
||||
'will be verified. Valid values are "required", "optional", and "none". '
|
||||
'The default and recommended setting is "required", which checks the '
|
||||
'server certificate is signed by a known Certificate Authority, and '
|
||||
'aborts the connection if it is not.""")))
|
||||
|
||||
|
||||
###
|
||||
# HTTP server
|
||||
|
@ -238,9 +238,9 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
|
||||
if wait:
|
||||
self.scheduleReconnect()
|
||||
return
|
||||
server = self._getNextServer()
|
||||
socks_proxy = getattr(conf.supybot.networks, self.irc.network) \
|
||||
.socksproxy()
|
||||
self.server = self._getNextServer()
|
||||
network_config = getattr(conf.supybot.networks, self.irc.network)
|
||||
socks_proxy = network_config.socksproxy()
|
||||
try:
|
||||
if socks_proxy:
|
||||
import socks
|
||||
@ -249,16 +249,16 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
|
||||
'using direct connection instead.')
|
||||
socks_proxy = ''
|
||||
if socks_proxy:
|
||||
address = server[0]
|
||||
address = self.server[0]
|
||||
else:
|
||||
try:
|
||||
address = utils.net.getAddressFromHostname(server[0],
|
||||
address = utils.net.getAddressFromHostname(self.server[0],
|
||||
attempt=self._attempt)
|
||||
except (socket.gaierror, socket.error) as e:
|
||||
drivers.log.connectError(self.currentServer, e)
|
||||
self.scheduleReconnect()
|
||||
return
|
||||
port = server[1]
|
||||
port = self.server[1]
|
||||
drivers.log.connect(self.currentServer)
|
||||
try:
|
||||
self.conn = utils.net.getSocket(address, port=port,
|
||||
@ -276,9 +276,17 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
|
||||
try:
|
||||
# Connect before SSL, otherwise SSL is disabled if we use SOCKS.
|
||||
# See http://stackoverflow.com/q/16136916/539465
|
||||
self.conn.connect((address, server[1]))
|
||||
if getattr(conf.supybot.networks, self.irc.network).ssl():
|
||||
self.conn.connect((address, port))
|
||||
if network_config.ssl():
|
||||
self.starttls()
|
||||
elif not network_config.requireStarttls():
|
||||
drivers.log.critical(('Connection to network %s'
|
||||
'does not use SSL/TLS, which makes it vulnerable to '
|
||||
'man-in-the-middle attacks and passive eavesdropping. '
|
||||
'You should consider upgrading your connection to SSL/TLS '
|
||||
'<http://doc.supybot.aperio.fr/en/latest/use/faq.html#how-to-make-a-connection-secure>')
|
||||
% self.irc.network)
|
||||
|
||||
def setTimeout():
|
||||
self.conn.settimeout(conf.supybot.drivers.poll())
|
||||
conf.supybot.drivers.poll.addCallback(setTimeout)
|
||||
@ -353,7 +361,29 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
|
||||
drivers.log.warning('Could not find cert file %s.' %
|
||||
certfile)
|
||||
certfile = None
|
||||
self.conn = ssl.wrap_socket(self.conn, certfile=certfile)
|
||||
try:
|
||||
self.conn = utils.net.ssl_wrap_socket(self.conn,
|
||||
logger=drivers.log, hostname=self.server[0],
|
||||
certfile=certfile,
|
||||
verify_mode=conf.supybot.protocols.ssl.verifyMode())
|
||||
except ssl.CertificateError as e:
|
||||
drivers.log.critical(('Certificate validation failed when '
|
||||
'connecting to %s: %s\n'
|
||||
'This means someone is doing a man-in-the-middle attack '
|
||||
'on your connection.')
|
||||
% (self.irc.network, e.args[0]))
|
||||
raise ssl.SSLError('Aborting because of failed certificate '
|
||||
'verification.')
|
||||
except ssl.SSLError as e:
|
||||
drivers.log.critical(('Certificate validation failed when '
|
||||
'connecting to %s: %s\n'
|
||||
'This means someone is doing a man-in-the-middle attack '
|
||||
'on your connection, or because the server\'s '
|
||||
'certificate is not trusted.')
|
||||
% (self.irc.network, e.args[1]))
|
||||
raise ssl.SSLError('Aborting because of failed certificate '
|
||||
'verification.')
|
||||
|
||||
|
||||
|
||||
Driver = SocketDriver
|
||||
|
@ -33,6 +33,7 @@ Simple utility modules.
|
||||
"""
|
||||
|
||||
import re
|
||||
import ssl
|
||||
import socket
|
||||
|
||||
from .web import _ipAddr, _domain
|
||||
@ -128,4 +129,26 @@ def isIPV6(s):
|
||||
return bruteIsIPV6(s)
|
||||
return False
|
||||
|
||||
if hasattr(ssl, 'create_default_context'):
|
||||
def ssl_wrap_socket(conn, hostname, logger, certfile=None,
|
||||
verify_mode=ssl.CERT_REQUIRED, **kwargs):
|
||||
context = ssl.create_default_context(**kwargs)
|
||||
context.verify_mode = verify_mode
|
||||
if certfile:
|
||||
context.load_cert_chain(certfile)
|
||||
return context.wrap_socket(conn, server_hostname=hostname)
|
||||
else:
|
||||
def ssl_wrap_socket(conn, hostname, logger, certfile=None, ca_certs=None,
|
||||
verify_mode=ssl.CERT_REQUIRED):
|
||||
logger.critical('This Python version does not support SSL contexts, '
|
||||
'which makes your connection vulnerable to man-in-the-middle '
|
||||
'attacks. You should consider upgrading to Python 3 '
|
||||
'(or at least 2.7.9).')
|
||||
# TLSv1.0 is the only TLS version Python < 2.7.9 supports
|
||||
# (besides SSLv2 and v3, which are known to be insecure)
|
||||
return ssl.wrap_socket(conn, certfile=certfile, ca_certs=ca_certs,
|
||||
ssl_version=ssl.ssl.PROTOCOL_TLSv1, verify_mode=verify_mode)
|
||||
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||
|
Loading…
Reference in New Issue
Block a user