diff --git a/src/conf.py b/src/conf.py index fa90a16db..85db4410b 100644 --- a/src/conf.py +++ b/src/conf.py @@ -329,6 +329,9 @@ def registerNetwork(name, password='', ssl=True, sasl_username='', of fingerprints of trusted certificates for this network. If non-empty, Certification Authority signatures will not be used to verify certificates."""))) + registerGlobalValue(network.ssl, 'authorityCertificate', + registry.String('', _("""A certificate that is trusted to verify + certificates of this network (aka. Certificate Authority)."""))) registerGlobalValue(network, 'requireStarttls', registry.Boolean(False, _("""Determines whether the bot will connect in plain text to %s but require STARTTLS before authentication. This is ignored if the diff --git a/src/drivers/Socket.py b/src/drivers/Socket.py index 7ab479793..bd4e2833b 100644 --- a/src/drivers/Socket.py +++ b/src/drivers/Socket.py @@ -373,6 +373,7 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): certfile=certfile, verify=verifyCertificates, trusted_fingerprints=network_config.ssl.serverFingerprints(), + ca_file=network_config.ssl.authorityCertificate(), ) except getattr(ssl, 'CertificateError', None) as e: # Default to None for old Python version, which do not have @@ -389,7 +390,7 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): 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 ' + 'on your connection, or that the server\'s ' 'certificate is not trusted.') % (self.irc.network, e.args[1])) raise ssl.SSLError('Aborting because of failed certificate ' diff --git a/src/utils/net.py b/src/utils/net.py index 83584d00e..83e1e7f86 100644 --- a/src/utils/net.py +++ b/src/utils/net.py @@ -144,13 +144,15 @@ def check_certificate_fingerprint(conn, trusted_fingerprints): if hasattr(ssl, 'create_default_context'): def ssl_wrap_socket(conn, hostname, logger, certfile=None, - trusted_fingerprints=None, verify=True, + trusted_fingerprints=None, verify=True, ca_file=None, **kwargs): context = ssl.create_default_context(**kwargs) if trusted_fingerprints or not verify: # Do not use Certification Authorities context.check_hostname = False context.verify_mode = ssl.CERT_NONE + if ca_file: + context.load_verify_locations(cafile=ca_file) if certfile: context.load_cert_chain(certfile) conn = context.wrap_socket(conn, server_hostname=hostname) @@ -160,10 +162,10 @@ if hasattr(ssl, 'create_default_context'): else: def ssl_wrap_socket(conn, hostname, logger, verify=True, certfile=None, - ca_certs=None, trusted_fingerprints=None): + ca_file=None, trusted_fingerprints=None): # TLSv1.0 is the only TLS version Python < 2.7.9 supports # (besides SSLv2 and v3, which are known to be insecure) - conn = ssl.wrap_socket(conn, certfile=certfile, ca_certs=ca_certs, + conn = ssl.wrap_socket(conn, certfile=certfile, ca_certs=ca_file, ssl_version=ssl.ssl.PROTOCOL_TLSv1, verify_mode=ssl.CERT_NONE) if trusted_fingerprints: check_certificate_fingerprint(conn, trusted_fingerprints)