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")
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 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)
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)
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
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
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)
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
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)
def channelActive(self, ctx): self.ctx = ctx SslHandler.channelActive(self)
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)
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)
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)