Ejemplo n.º 1
0
    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        self._sock._handle_channel_future(handshake, "SSL handshake")
Ejemplo n.º 2
0
    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})
        self.setup_engine(self.sock.getpeername())

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        self._handshake_future = self.ssl_handler.handshakeFuture()
        if isinstance(self._sock, ChildSocket):
            pass
            # see
            # http://stackoverflow.com/questions/24628271/exception-in-netty-io-netty-util-concurrent-blockingoperationexception
            # - handshake in the child thread pool
        else:
            self._sock._handle_channel_future(self._handshake_future, "SSL handshake")
Ejemplo n.º 3
0
    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(0.001)  # Necessary apparently for the handler to get into a good state
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error as e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)
Ejemplo n.º 4
0
    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})
        self.setup_engine(self.sock.getpeername())

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})

            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(0.001)  # Necessary apparently for the handler to get into a good state
        if isinstance(self._sock, ChildSocket):
            # see
            # http://stackoverflow.com/questions/24628271/exception-in-netty-io-netty-util-concurrent-blockingoperationexception
            # - we are doing this in the handler thread!
            return
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error, e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)
Ejemplo n.º 5
0
class SSLSocket(object):
    
    def __init__(self, sock,
                 keyfile, certfile, ca_certs,
                 do_handshake_on_connect, server_side):
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket
        self.context = _get_ssl_context(keyfile, certfile, ca_certs)
        self.engine = self.context.createSSLEngine()
        self.server_side = server_side
        self.engine.setUseClientMode(not server_side)
        self.ssl_handler = None
        # _sslobj is used to follow CPython convention that an object
        # means we have handshaked, as used by existing code that
        # looks at this internal
        self._sslobj = None
        self.handshake_count = 0

        if self.do_handshake_on_connect and self.sock._sock.connected:
            self.do_handshake()

    def connect(self, addr):
        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def connect_ex(self, addr):
        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()
        return self._sock.connect_ex(addr)

    def unwrap(self):
        self._sock.channel.pipeline().remove("ssl")
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(0.001)  # Necessary apparently for the handler to get into a good state
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error as e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)

    # Various pass through methods to the wrapped socket

    def send(self, data):
        return self.sock.send(data)

    write = send

    def sendall(self, data):
        return self.sock.sendall(data)

    def recv(self, bufsize, flags=0):
        return self.sock.recv(bufsize, flags)

    read = recv

    def recvfrom(self, bufsize, flags=0):
        return self.sock.recvfrom(bufsize, flags)

    def recvfrom_into(self, buffer, nbytes=0, flags=0):
        return self.sock.recvfrom_into(buffer, nbytes, flags)

    def recv_into(self, buffer, nbytes=0, flags=0):
        return self.sock.recv_into(buffer, nbytes, flags)

    def sendto(self, string, arg1, arg2=None):
        raise socket_error(errno.EPROTO)

    def close(self):
        self.sock.close()

    def setblocking(self, mode):
        self.sock.setblocking(mode)

    def settimeout(self, timeout):
        self.sock.settimeout(timeout)

    def gettimeout(self):
        return self.sock.gettimeout()

    def makefile(self, mode='r', bufsize=-1):
        return self.sock.makefile(mode, bufsize)

    def shutdown(self, how):
        self.sock.shutdown(how)

    # Need to work with the real underlying socket as well

    def pending(self):
        # undocumented function, used by some tests
        # see also http://bugs.python.org/issue21430
        return self._sock._pending()

    def _readable(self):
        return self._sock._readable()

    def _writable(self):
        return self._sock._writable()

    def _register_selector(self, selector):
        self._sock._register_selector(selector)

    def _unregister_selector(self, selector):
        return self._sock._unregister_selector(selector)

    def _notify_selectors(self):
        self._sock._notify_selectors()

    def getpeername(self):
        return self.sock.getpeername()

    def fileno(self):
        return self

    @raises_java_exception
    def getpeercert(self, binary_form=False):
        cert = self.engine.getSession().getPeerCertificates()[0]
        if binary_form:
            return cert.getEncoded()
        dn = cert.getSubjectX500Principal().getName()
        ldapDN = LdapName(dn)
        # FIXME given this tuple of a single element tuple structure assumed here, is it possible this is
        # not actually the case, eg because of multi value attributes?
        rdns = tuple((((_ldap_rdn_display_names.get(rdn.type), rdn.value),) for rdn in ldapDN.getRdns()))
        # FIXME is it str? or utf8? or some other encoding? maybe a bug in cpython?
        alt_names = tuple(((_cert_name_types[type], str(name)) for (type, name) in cert.getSubjectAlternativeNames()))
        pycert = {
            "notAfter": _rfc2822_date_format.format(cert.getNotAfter()),
            "subject": rdns,
            "subjectAltName": alt_names, 
        }
        return pycert

    @raises_java_exception
    def issuer(self):
        return self.getpeercert().getIssuerDN().toString()

    def cipher(self):
        session = self._sslsocket.session
        suite = str(session.cipherSuite)
        if "256" in suite:  # FIXME!!! this test usually works, but there must be a better approach
            strength = 256
        elif "128" in suite:
            strength = 128
        else:
            strength = None
        return suite, str(session.protocol), strength
Ejemplo n.º 6
0
class SSLSocket(object):

    def __init__(self, sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE,
                 ssl_version=PROTOCOL_SSLv23, ca_certs=None,
                 do_handshake_on_connect=True, suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
                 server_hostname=None, _context=None):
        # TODO ^^ handle suppress_ragged_eofs
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket

        # FIXME in CPython, a check like so is performed - but this is
        # not quite correct, based on tests. We should revisit to see
        # if we can make this work as desired.

        # if do_handshake_on_connect and self._sock.timeout == 0:
        #     raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")

        self._connected = False
        if _context:
            self._context = _context
        else:
            if server_side and not certfile:
                raise ValueError("certfile must be specified for server-side "
                                 "operations")
            if keyfile and not certfile:
                raise ValueError("certfile must be specified")
            if certfile and not keyfile:
                keyfile = certfile
            self._context = SSLContext(ssl_version)
            self._context.verify_mode = cert_reqs
            if ca_certs:
                self._context.load_verify_locations(ca_certs)
            if certfile:
                self._context.load_cert_chain(certfile, keyfile)
            if npn_protocols:
                self._context.set_npn_protocols(npn_protocols)
            if ciphers:
                self._context.set_ciphers(ciphers)
            self.keyfile = keyfile
            self.certfile = certfile
            self.cert_reqs = cert_reqs
            self.ssl_version = ssl_version
            self.ca_certs = ca_certs
            self.ciphers = ciphers

        if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
            raise NotImplementedError("only stream sockets are supported")

        if server_side and server_hostname:
            raise ValueError("server_hostname can only be specified "
                             "in client mode")
        if self._context.check_hostname and not server_hostname:
            raise ValueError("check_hostname requires server_hostname")
        self.server_side = server_side
        self.server_hostname = server_hostname
        self.suppress_ragged_eofs = suppress_ragged_eofs

        self.ssl_handler = None
        # We use _sslobj here to support the CPython convention that
        # an object means we have handshaked. It is used by existing code
        # in the wild that looks at this ostensibly internal attribute.
        
        # FIXME CPython uses _sslobj to track the OpenSSL wrapper
        # object that's implemented in C, with the following
        # properties:
        #
        # 'cipher', 'compression', 'context', 'do_handshake',
        # 'peer_certificate', 'pending', 'read', 'shutdown',
        # 'tls_unique_cb', 'version', 'write'
        self._sslobj = self   # setting to self is not quite right

        self.engine = None

        if self.do_handshake_on_connect and self._sock.connected:
            log.debug("Handshaking socket on connect", extra={"sock": self._sock})
            if isinstance(self._sock, ChildSocket):
                # Need to handle child sockets differently depending
                # on whether the parent socket is wrapped or not.
                #
                # In either case, we cannot handshake here in this
                # thread - it must be done in the child pool and
                # before the child is activated.
                #
                # 1. If wrapped, this is going through SSLSocket.accept

                if isinstance(self._sock.parent_socket, SSLSocket):
                    # already wrapped, via `wrap_child` function a few lines below
                    log.debug(
                        "Child socket - will handshake in child loop type=%s parent=%s",
                        type(self._sock), self._sock.parent_socket,
                        extra={"sock": self._sock})
                    self._sock._make_active()

                # 2. If not, using code will be calling SSLContext.wrap_socket
                #    *after* accept from an unwrapped socket

                else:
                    log.debug("Child socket will wrap self with handshake", extra={"sock": self._sock})
                    setup_handshake_latch = CountDownLatch(1)

                    def setup_handshake():
                        handshake_future = self.do_handshake()
                        setup_handshake_latch.countDown()
                        return handshake_future

                    self._sock.ssl_wrap_self = setup_handshake
                    self._sock._make_active()
                    setup_handshake_latch.await()
                    log.debug("Child socket waiting on handshake=%s", self._handshake_future, extra={"sock": self._sock})
                    self._sock._handle_channel_future(self._handshake_future, "SSL handshake")
            else:
                self.do_handshake()

        if hasattr(self._sock, "accepted_children"):
            def wrap_child(child):
                log.debug(
                    "Wrapping child socket - about to handshake! parent=%s",
                    self._sock, extra={"sock": child})
                child._wrapper_socket = self.context.wrap_socket(
                    _socketobject(_sock=child),
                    do_handshake_on_connect=self.do_handshake_on_connect,
                    suppress_ragged_eofs=self.suppress_ragged_eofs,
                    server_side=True)
                if self.do_handshake_on_connect:
                    # this handshake will be done in the child pool - initChannel will block on it
                    child._wrapper_socket.do_handshake()
            self._sock.ssl_wrap_child_socket = wrap_child

    @property
    def context(self):
        return self._context

    @context.setter
    def context(self, context):
        self._context = context

    def setup_engine(self, addr):
        if self.engine is None:
            # http://stackoverflow.com/questions/13390964/java-ssl-fatal-error-80-unwrapping-net-record-after-adding-the-https-en
            self.engine = self._context._createSSLEngine(
                addr, self.server_hostname,
                cert_file=getattr(self, "certfile", None), key_file=getattr(self, "keyfile", None),
                server_side=self.server_side)
            self.engine.setUseClientMode(not self.server_side)

    def connect(self, addr):
        """Connects to remote ADDR, and then wraps the connection in
        an SSL channel."""
        if self.server_side:
            raise ValueError("can't connect in server-side mode")
        if self._connected:
            raise ValueError("attempt to connect already-connected SSLSocket!")

        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})

        self._sock.connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def connect_ex(self, addr):
        """Connects to remote ADDR, and then wraps the connection in
        an SSL channel."""
        if self.server_side:
            raise ValueError("can't connect in server-side mode")
        if self._connected:
            raise ValueError("attempt to connect already-connected SSLSocket!")

        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})

        rc = self._sock.connect_ex(addr)
        if rc == errno.EISCONN:
            self._connected = True
            if self.do_handshake_on_connect:
                self.do_handshake()
        return rc

    def accept(self):
        """Accepts a new connection from a remote client, and returns
        a tuple containing that new connection wrapped with a server-side
        SSL channel, and the address of the remote client."""
        child, addr = self._sock.accept()
        if self.do_handshake_on_connect:
            wrapped_child_socket = child._wrapper_socket
            del child._wrapper_socket
            return wrapped_child_socket, addr
        else:
            return self.context.wrap_socket(
                _socketobject(_sock=child),
                do_handshake_on_connect=self.do_handshake_on_connect,
                suppress_ragged_eofs=self.suppress_ragged_eofs,
                server_side=True)

    def unwrap(self):
        try:
            self._sock.channel.pipeline().remove("ssl")
        except NoSuchElementException:
            pass
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})
        self.setup_engine(self.sock.getpeername())

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        self._handshake_future = self.ssl_handler.handshakeFuture()
        if isinstance(self._sock, ChildSocket):
            pass
            # see
            # http://stackoverflow.com/questions/24628271/exception-in-netty-io-netty-util-concurrent-blockingoperationexception
            # - handshake in the child thread pool
        else:
            self._sock._handle_channel_future(self._handshake_future, "SSL handshake")

    def dup(self):
        raise NotImplemented("Can't dup() %s instances" %
                             self.__class__.__name__)

    @raises_java_exception
    def _ensure_handshake(self):
        log.debug("Ensure handshake", extra={"sock": self}) 
        self._sock._make_active()
        # nonblocking code should never wait here, but only attempt to
        # come to this point when notified via a selector
        if not hasattr(self, "_handshake_future"):
            self.do_handshake()
        # additional synchronization guard if this is a child socket
        self._handshake_future.sync()
        log.debug("Completed post connect", extra={"sock": self})

    # Various pass through methods to the wrapped socket

    def send(self, data):
        self._ensure_handshake()
        return self.sock.send(data)

    write = send

    def sendall(self, data):
        self._ensure_handshake()
        return self.sock.sendall(data)

    def recv(self, bufsize, flags=0):
        self._ensure_handshake()
        return self.sock.recv(bufsize, flags)

    def read(self, len=0, buffer=None):
        """Read up to LEN bytes and return them.
        Return zero-length string on EOF."""
        self._checkClosed()
        self._ensure_handshake()
        # FIXME? breaks test_smtpnet.py
        # if not self._sslobj:
        #     raise ValueError("Read on closed or unwrapped SSL socket.")
        try:
            if buffer is not None:
                v = self.recvfrom_into(buffer, len or 1024)
            else:
                v = self.recv(len or 1024)
            return v
        except SSLError as x:
            if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:
                if buffer is not None:
                    return 0
                else:
                    return b''
            else:
                raise

    def recvfrom(self, bufsize, flags=0):
        self._ensure_handshake()
        return self.sock.recvfrom(bufsize, flags)

    def recvfrom_into(self, buffer, nbytes=0, flags=0):
        self._ensure_handshake()
        return self.sock.recvfrom_into(buffer, nbytes, flags)

    def recv_into(self, buffer, nbytes=0, flags=0):
        self._ensure_handshake()
        return self.sock.recv_into(buffer, nbytes, flags)

    def sendto(self, string, arg1, arg2=None):
        # as observed on CPython, sendto when wrapped ignores the
        # destination address, thereby behaving just like send
        self._ensure_handshake()
        return self.sock.send(string)

    def close(self):
        self.sock.close()

    def setblocking(self, mode):
        self.sock.setblocking(mode)

    def settimeout(self, timeout):
        self.sock.settimeout(timeout)

    def gettimeout(self):
        return self.sock.gettimeout()

    def makefile(self, mode='r', bufsize=-1):
        return self.sock.makefile(mode, bufsize)

    def shutdown(self, how):
        self.sock.shutdown(how)
    # Need to work with the real underlying socket as well

    def pending(self):
        # undocumented function, used by some tests
        # see also http://bugs.python.org/issue21430
        return self._sock._pending()

    def _readable(self):
        return self._sock._readable()

    def _writable(self):
        return self._sock._writable()

    def _register_selector(self, selector):
        self._sock._register_selector(selector)

    def _unregister_selector(self, selector):
        return self._sock._unregister_selector(selector)

    def _notify_selectors(self):
        self._sock._notify_selectors()

    def _checkClosed(self, msg=None):
        # raise an exception here if you wish to check for spurious closes
        pass

    def _check_connected(self):
        if not self._connected:
            # getpeername() will raise ENOTCONN if the socket is really
            # not connected; note that we can be connected even without
            # _connected being set, e.g. if connect() first returned
            # EAGAIN.
            self.getpeername()

    def getpeername(self):
        return self.sock.getpeername()

    def selected_npn_protocol(self):
        self._checkClosed()
        # TODO Jython
        return None

    def selected_alpn_protocol(self):
        self._checkClosed()
        # TODO Jython

    def fileno(self):
        return self

    @raises_java_exception
    def getpeercert(self, binary_form=False):
        cert = self.engine.getSession().getPeerCertificates()[0]
        if binary_form:
            return cert.getEncoded()

        if self._context.verify_mode == CERT_NONE:
            return {}

        dn = cert.getSubjectX500Principal().getName()
        rdns = SSLContext._parse_dn(dn)
        alt_names = tuple()
        if cert.getSubjectAlternativeNames():
            alt_names = tuple(((_cert_name_types[type], str(name)) for (type, name) in cert.getSubjectAlternativeNames()))

        pycert = {
            "notAfter": str(_rfc2822_date_format.format(cert.getNotAfter())),
            "subject": rdns,
            "subjectAltName": alt_names,
        }
        return pycert

    @raises_java_exception
    def issuer(self):
        return self.getpeercert().getIssuerDN().toString()

    def cipher(self):
        session = self.engine.getSession()
        suite = str(session.cipherSuite)
        if "256" in suite:  # FIXME!!! this test usually works, but there must be a better approach
            strength = 256
        elif "128" in suite:
            strength = 128
        else:
            strength = None
        return suite, str(session.protocol), strength

    def get_channel_binding(self, cb_type="tls-unique"):
        """Get channel binding data for current connection.  Raise ValueError
        if the requested `cb_type` is not supported.  Return bytes of the data
        or None if the data is not available (e.g. before the handshake).
        """
        if cb_type not in CHANNEL_BINDING_TYPES:
            raise ValueError("Unsupported channel binding type")
        if cb_type != "tls-unique":
            raise NotImplementedError(
                "{0} channel binding type not implemented"
                    .format(cb_type))

        # TODO support this properly
        return None
        # if self._sslobj is None:
        #     return None
        # return self._sslobj.tls_unique_cb()

    def version(self):
        if self.ssl_handler:
            return str(self.engine.getSession().getProtocol())
        return None
Ejemplo n.º 7
0
class SSLSocket(object):
    def __init__(self, sock, keyfile, certfile, ca_certs,
                 do_handshake_on_connect, server_side):
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket
        self.context = _get_ssl_context(keyfile, certfile, ca_certs)
        self.engine = self.context.createSSLEngine()
        self.server_side = server_side
        self.engine.setUseClientMode(not server_side)
        self.ssl_handler = None
        # _sslobj is used to follow CPython convention that an object
        # means we have handshaked, as used by existing code that
        # looks at this internal
        self._sslobj = None
        self.handshake_count = 0

        if self.do_handshake_on_connect and self.sock._sock.connected:
            self.do_handshake()

    def connect(self, addr):
        log.debug("Connect SSL with handshaking %s",
                  self.do_handshake_on_connect,
                  extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def connect_ex(self, addr):
        log.debug("Connect SSL with handshaking %s",
                  self.do_handshake_on_connect,
                  extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()
        return self._sock.connect_ex(addr)

    def unwrap(self):
        self._sock.channel.pipeline().remove("ssl")
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s",
                      result,
                      extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection",
                          extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...",
                          extra={"sock": self._sock})
                self._sock.connect_handlers.append(
                    SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(
            0.001
        )  # Necessary apparently for the handler to get into a good state
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error, e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)
Ejemplo n.º 8
0
class SSLSocket(object):
    
    def __init__(self, sock,
                 keyfile, certfile, ca_certs,
                 do_handshake_on_connect, server_side):
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket
        self.context = _get_ssl_context(keyfile, certfile, ca_certs)
        self.engine = self.context.createSSLEngine()
        self.server_side = server_side
        self.engine.setUseClientMode(not server_side)
        self.ssl_handler = None
        # _sslobj is used to follow CPython convention that an object
        # means we have handshaked, as used by existing code that
        # looks at this internal
        self._sslobj = None
        self.handshake_count = 0

        if self.do_handshake_on_connect and self.sock._sock.connected:
            self.do_handshake()

    def connect(self, addr):
        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def unwrap(self):
        self._sock.channel.pipeline().remove("ssl")
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        self._sock._handle_channel_future(handshake, "SSL handshake")

    # Various pass through methods to the wrapped socket

    def send(self, data):
        return self.sock.send(data)

    def sendall(self, data):
        return self.sock.sendall(data)

    def recv(self, bufsize, flags=0):
        return self.sock.recv(bufsize, flags)

    def recvfrom(self, bufsize, flags=0):
        return self.sock.recvfrom(bufsize, flags)

    def recvfrom_into(self, buffer, nbytes=0, flags=0):
        return self.sock.recvfrom_into(buffer, nbytes, flags)

    def recv_into(self, buffer, nbytes=0, flags=0):
        return self.sock.recv_into(buffer, nbytes, flags)

    def sendto(self, string, arg1, arg2=None):
        raise socket_error(errno.EPROTO)

    def close(self):
        self.sock.close()

    def setblocking(self, mode):
        self.sock.setblocking(mode)

    def settimeout(self, timeout):
        self.sock.settimeout(timeout)

    def gettimeout(self):
        return self.sock.gettimeout()

    def makefile(self, mode='r', bufsize=-1):
        return self.sock.makefile(mode, bufsize)

    def shutdown(self, how):
        self.sock.shutdown(how)

    # Need to work with the real underlying socket as well

    def _readable(self):
        return self._sock._readable()

    def _writable(self):
        return self._sock._writable()

    def _register_selector(self, selector):
        self._sock._register_selector(selector)

    def _unregister_selector(self, selector):
        return self._sock._unregister_selector(selector)

    def _notify_selectors(self):
        self._sock._notify_selectors()

    def getpeername(self):
        return self.sock.getpeername()

    def fileno(self):
        return self

    @raises_java_exception
    def getpeercert(self, binary_form=False):
        cert = self.engine.getSession().getPeerCertificates()[0]
        if binary_form:
            return cert.getEncoded()
        dn = cert.getSubjectX500Principal().getName()
        ldapDN = LdapName(dn)
        # FIXME given this tuple of a single element tuple structure assumed here, is it possible this is
        # not actually the case, eg because of multi value attributes?
        rdns = tuple((((_ldap_rdn_display_names.get(rdn.type), rdn.value),) for rdn in ldapDN.getRdns()))
        # FIXME is it str? or utf8? or some other encoding? maybe a bug in cpython?
        alt_names = tuple(((_cert_name_types[type], str(name)) for (type, name) in cert.getSubjectAlternativeNames()))
        pycert = {
            "notAfter": _rfc2822_date_format.format(cert.getNotAfter()),
            "subject": rdns,
            "subjectAltName": alt_names, 
        }
        return pycert

    @raises_java_exception
    def issuer(self):
        return self.getpeercert().getIssuerDN().toString()

    def cipher(self):
        session = self._sslsocket.session
        suite = str(session.cipherSuite)
        if "256" in suite:  # FIXME!!! this test usually works, but there must be a better approach
            strength = 256
        elif "128" in suite:
            strength = 128
        else:
            strength = None
        return suite, str(session.protocol), strength
Ejemplo n.º 9
0
class SSLSocket(object):

    def __init__(self, sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE,
                 ssl_version=PROTOCOL_SSLv23, ca_certs=None,
                 do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None, _context=None):
        # TODO ^^ handle suppress_ragged_eofs
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket
        self.context = _context
        if _context is None:
            self.context = SSLContext(ssl_version)
        else:
            if server_side and not certfile:
                raise ValueError("certfile must be specified for server-side "
                                 "operations")
            if keyfile and not certfile:
                raise ValueError("certfile must be specified")
            if certfile and not keyfile:
                keyfile = certfile
            self._context = SSLContext(ssl_version)
            self._context.verify_mode = cert_reqs
            if ca_certs:
                self._context.load_verify_locations(ca_certs)
            if certfile:
                self._context.load_cert_chain(certfile, keyfile)
            if ciphers:
                self._context.set_ciphers(ciphers)

        self.engine = self.context._createSSLEngine()
        self.server_side = server_side
        self.engine.setUseClientMode(not server_side)
        self.ssl_handler = None
        # _sslobj is used to follow CPython convention that an object
        # means we have handshaked, as used by existing code that
        # looks at this internal
        self._sslobj = None
        self.handshake_count = 0

        if self.do_handshake_on_connect and self.sock._sock.connected:
            self.do_handshake()

    def connect(self, addr):
        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def connect_ex(self, addr):
        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()
        return self._sock.connect_ex(addr)

    def unwrap(self):
        self._sock.channel.pipeline().remove("ssl")
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(0.001)  # Necessary apparently for the handler to get into a good state
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error, e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)
Ejemplo n.º 10
0
 def channelActive(self, ctx):
     self.ctx = ctx
     SslHandler.channelActive(self)
Ejemplo n.º 11
0
class SSLSocket(object):

    def __init__(self, sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE,
                 ssl_version=PROTOCOL_SSLv23, ca_certs=None,
                 do_handshake_on_connect=True, suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
                 server_hostname=None, _context=None):
        # TODO ^^ handle suppress_ragged_eofs
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket
        self._connected = False
        if _context:
            self._context = _context
        else:
            if server_side and not certfile:
                raise ValueError("certfile must be specified for server-side "
                                 "operations")
            if keyfile and not certfile:
                raise ValueError("certfile must be specified")
            if certfile and not keyfile:
                keyfile = certfile
            self._context = SSLContext(ssl_version)
            self._context.verify_mode = cert_reqs
            if ca_certs:
                self._context.load_verify_locations(ca_certs)
            if certfile:
                self._context.load_cert_chain(certfile, keyfile)
            if npn_protocols:
                self._context.set_npn_protocols(npn_protocols)
            if ciphers:
                self._context.set_ciphers(ciphers)
            self.keyfile = keyfile
            self.certfile = certfile
            self.cert_reqs = cert_reqs
            self.ssl_version = ssl_version
            self.ca_certs = ca_certs
            self.ciphers = ciphers

        if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
            raise NotImplementedError("only stream sockets are supported")

        if server_side and server_hostname:
            raise ValueError("server_hostname can only be specified "
                             "in client mode")
        if self._context.check_hostname and not server_hostname:
            raise ValueError("check_hostname requires server_hostname")
        self.server_side = server_side
        self.server_hostname = server_hostname
        self.suppress_ragged_eofs = suppress_ragged_eofs

        self.ssl_handler = None
        # We use _sslobj here to support the CPython convention that
        # an object means we have handshaked, as used by existing code
        # in the wild that looks at this ostensibly internal attribute
        self._sslobj = None
        self.handshake_count = 0

        self.engine = None
        
        if self.do_handshake_on_connect and self._sock.connected:
            if isinstance(self._sock, ChildSocket):
                log.debug("Child socket - do not handshake! type=%s parent=%s", type(self._sock), self._sock.parent_socket, 
                          extra={"sock": self._sock})
            else:
                self.do_handshake()

        if hasattr(self._sock, "accepted_children"):
            def wrap_child(child):
                log.debug("Wrapping child socket - about to handshake! parent=%s", self._sock, extra={"sock": child})
                child._wrapper_socket = self.context.wrap_socket(
                    _socketobject(_sock=child),
                    do_handshake_on_connect=self.do_handshake_on_connect,
                    suppress_ragged_eofs=self.suppress_ragged_eofs,
                    server_side=True)

                if self.do_handshake_on_connect:
                    child._wrapper_socket.do_handshake()
            self._sock.ssl_wrap_child_socket = wrap_child

    @property
    def context(self):
        return self._context

    def setup_engine(self, addr):
        if self.engine is None:
            # http://stackoverflow.com/questions/13390964/java-ssl-fatal-error-80-unwrapping-net-record-after-adding-the-https-en
            self.engine = self._context._createSSLEngine(
                addr, self.server_hostname,
                cert_file=getattr(self, "certfile", None), key_file=getattr(self, "keyfile", None))
            self.engine.setUseClientMode(not self.server_side)

    def connect(self, addr):
        """Connects to remote ADDR, and then wraps the connection in
        an SSL channel."""
        if self.server_side:
            raise ValueError("can't connect in server-side mode")
        if self._connected:
            raise ValueError("attempt to connect already-connected SSLSocket!")

        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})

        self._sock.connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def connect_ex(self, addr):
        """Connects to remote ADDR, and then wraps the connection in
        an SSL channel."""
        if self.server_side:
            raise ValueError("can't connect in server-side mode")
        if self._connected:
            raise ValueError("attempt to connect already-connected SSLSocket!")

        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})

        rc = self._sock.connect_ex(addr)
        if not rc:
            self._connected = True
            if self.do_handshake_on_connect:
                self.do_handshake()
        return rc

    def accept(self):
        """Accepts a new connection from a remote client, and returns
        a tuple containing that new connection wrapped with a server-side
        SSL channel, and the address of the remote client."""
        child, addr = self._sock.accept()
        if self.do_handshake_on_connect:
            child.active_latch.await()

        log.debug("accepted sock=%s wrapped=%s addr=%s", child, child._wrapper_socket, addr, extra={"sock": self._sock})
        wrapped_child_socket = child._wrapper_socket
        del child._wrapper_socket
        return wrapped_child_socket, addr

    def unwrap(self):
        self._sock.channel.pipeline().remove("ssl")
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})
        self.setup_engine(self.sock.getpeername())

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})

            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(0.001)  # Necessary apparently for the handler to get into a good state
        if isinstance(self._sock, ChildSocket):
            # see
            # http://stackoverflow.com/questions/24628271/exception-in-netty-io-netty-util-concurrent-blockingoperationexception
            # - we are doing this in the handler thread!
            return
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error, e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)
Ejemplo n.º 12
0
class SSLSocket(object):
    def __init__(self,
                 sock,
                 keyfile=None,
                 certfile=None,
                 server_side=False,
                 cert_reqs=CERT_NONE,
                 ssl_version=PROTOCOL_SSLv23,
                 ca_certs=None,
                 do_handshake_on_connect=True,
                 suppress_ragged_eofs=True,
                 ciphers=None,
                 _context=None):
        # TODO ^^ handle suppress_ragged_eofs
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket
        self.context = _context
        if _context is None:
            self.context = SSLContext(ssl_version)
        else:
            if server_side and not certfile:
                raise ValueError("certfile must be specified for server-side "
                                 "operations")
            if keyfile and not certfile:
                raise ValueError("certfile must be specified")
            if certfile and not keyfile:
                keyfile = certfile
            self._context = SSLContext(ssl_version)
            self._context.verify_mode = cert_reqs
            if ca_certs:
                self._context.load_verify_locations(ca_certs)
            if certfile:
                self._context.load_cert_chain(certfile, keyfile)
            if ciphers:
                self._context.set_ciphers(ciphers)

        self.engine = self.context._createSSLEngine()
        self.server_side = server_side
        self.engine.setUseClientMode(not server_side)
        self.ssl_handler = None
        # _sslobj is used to follow CPython convention that an object
        # means we have handshaked, as used by existing code that
        # looks at this internal
        self._sslobj = None
        self.handshake_count = 0

        if self.do_handshake_on_connect and self.sock._sock.connected:
            self.do_handshake()

    def connect(self, addr):
        log.debug("Connect SSL with handshaking %s",
                  self.do_handshake_on_connect,
                  extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def connect_ex(self, addr):
        log.debug("Connect SSL with handshaking %s",
                  self.do_handshake_on_connect,
                  extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()
        return self._sock.connect_ex(addr)

    def unwrap(self):
        self._sock.channel.pipeline().remove("ssl")
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s",
                      result,
                      extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection",
                          extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...",
                          extra={"sock": self._sock})
                self._sock.connect_handlers.append(
                    SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(
            0.001
        )  # Necessary apparently for the handler to get into a good state
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error, e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)
Ejemplo n.º 13
0
class SSLSocket(object):
    
    def __init__(self, sock,
                 keyfile, certfile, ca_certs,
                 do_handshake_on_connect, server_side):
        self.sock = sock
        self.do_handshake_on_connect = do_handshake_on_connect
        self._sock = sock._sock  # the real underlying socket
        self.context = _get_ssl_context(keyfile, certfile, ca_certs)
        self.engine = self.context.createSSLEngine()
        self.server_side = server_side
        self.engine.setUseClientMode(not server_side)
        self.ssl_handler = None
        # _sslobj is used to follow CPython convention that an object
        # means we have handshaked, as used by existing code that
        # looks at this internal
        self._sslobj = None
        self.handshake_count = 0

        if self.do_handshake_on_connect and self.sock._sock.connected:
            self.do_handshake()

    def connect(self, addr):
        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()

    def connect_ex(self, addr):
        log.debug("Connect SSL with handshaking %s", self.do_handshake_on_connect, extra={"sock": self._sock})
        self._sock._connect(addr)
        if self.do_handshake_on_connect:
            self.do_handshake()
        return self._sock.connect_ex(addr)

    def unwrap(self):
        self._sock.channel.pipeline().remove("ssl")
        self.ssl_handler.close()
        return self._sock

    def do_handshake(self):
        log.debug("SSL handshaking", extra={"sock": self._sock})

        def handshake_step(result):
            log.debug("SSL handshaking completed %s", result, extra={"sock": self._sock})
            if not hasattr(self._sock, "active_latch"):
                log.debug("Post connect step", extra={"sock": self._sock})
                self._sock._post_connect()
                self._sock._unlatch()
            self._sslobj = object()  # we have now handshaked
            self._notify_selectors()

        if self.ssl_handler is None:
            self.ssl_handler = SslHandler(self.engine)
            self.ssl_handler.handshakeFuture().addListener(handshake_step)

            if hasattr(self._sock, "connected") and self._sock.connected:
                # The underlying socket is already connected, so some extra work to manage
                log.debug("Adding SSL handler to pipeline after connection", extra={"sock": self._sock})
                self._sock.channel.pipeline().addFirst("ssl", self.ssl_handler)
            else:
                log.debug("Not connected, adding SSL initializer...", extra={"sock": self._sock})
                self._sock.connect_handlers.append(SSLInitializer(self.ssl_handler))

        handshake = self.ssl_handler.handshakeFuture()
        time.sleep(0.001)  # Necessary apparently for the handler to get into a good state
        try:
            self._sock._handle_channel_future(handshake, "SSL handshake")
        except socket_error, e:
            raise SSLError(SSL_ERROR_SSL, e.strerror)