summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/crypto/context_factory.py26
-rw-r--r--synapse/python_dependencies.py1
2 files changed, 12 insertions, 15 deletions
diff --git a/synapse/crypto/context_factory.py b/synapse/crypto/context_factory.py
index aa8b20fe7d..2f23782630 100644
--- a/synapse/crypto/context_factory.py
+++ b/synapse/crypto/context_factory.py
@@ -15,6 +15,7 @@
 
 import logging
 
+import idna
 from service_identity import VerificationError
 from service_identity.pyopenssl import verify_hostname
 from zope.interface import implementer
@@ -58,20 +59,6 @@ class ServerContextFactory(ContextFactory):
         return self._context
 
 
-def _idnaBytes(text):
-    """
-    Convert some text typed by a human into some ASCII bytes. This is a
-    copy of twisted.internet._idna._idnaBytes. For documentation, see the
-    twisted documentation.
-    """
-    try:
-        import idna
-    except ImportError:
-        return text.encode("idna")
-    else:
-        return idna.encode(text)
-
-
 class ClientTLSOptionsFactory(object):
     """Factory for Twisted SSLClientConnectionCreators that are used to make connections
     to remote servers for federation.
@@ -162,13 +149,21 @@ class ConnectionVerifier(object):
     This is a thing which is attached to the TLSMemoryBIOProtocol, and is called by
     the ssl context's info callback.
     """
+    # This code is based on twisted.internet.ssl.ClientTLSOptions.
+
     def __init__(self, hostname, verify_certs):
         self._verify_certs = verify_certs
+
         if isIPAddress(hostname) or isIPv6Address(hostname):
             self._hostnameBytes = hostname.encode('ascii')
             self._sendSNI = False
         else:
-            self._hostnameBytes = _idnaBytes(hostname)
+            # twisted's ClientTLSOptions falls back to the stdlib impl here if
+            # idna is not installed, but points out that lacks support for
+            # IDNA2008 (http://bugs.python.org/issue17305).
+            #
+            # We can rely on having idna.
+            self._hostnameBytes = idna.encode(hostname)
             self._sendSNI = True
 
         self._hostnameASCII = self._hostnameBytes.decode("ascii")
@@ -176,6 +171,7 @@ class ConnectionVerifier(object):
     def verify_context_info_cb(self, ssl_connection, where):
         if where & SSL.SSL_CB_HANDSHAKE_START and self._sendSNI:
             ssl_connection.set_tlsext_host_name(self._hostnameBytes)
+
         if where & SSL.SSL_CB_HANDSHAKE_DONE and self._verify_certs:
             try:
                 verify_hostname(ssl_connection, self._hostnameASCII)
diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py
index c78f2cb15e..db09ff285f 100644
--- a/synapse/python_dependencies.py
+++ b/synapse/python_dependencies.py
@@ -44,6 +44,7 @@ REQUIREMENTS = [
     "canonicaljson>=1.1.3",
     "signedjson>=1.0.0",
     "pynacl>=1.2.1",
+    "idna>=2",
     "service_identity>=16.0.0",
 
     # our logcontext handling relies on the ability to cancel inlineCallbacks