SNI server_hostname not supported in ssl.wrap_socket
https://github.com/Lawouach/WebSocket-for-Python/blob/961c07ce16ce4eedc34ca1fdacd29442870feccc/ws4py/client/init.py#L214
adding server_hostname in ssl_options returns an argument type error
we have to switch to SSLContext.wrap_socket or ssl.SSLSocket
Holy smokes, I finally found this. I was getting an error, unable to connect to SNI-enabled servers using a tool the relies on ws4py:
[Errno 1] _ssl.c:510: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
This was from my python2.7 installation. My old system python has a ssl.py that seems to not support SNI, at all!
So I rewrote my tool, to run under python3, out of desparation. But I got the same error from the newer ssl.py! I was pulling out my hair!
[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:777)
This was a huge breaking issue for me that cause massive downtime and nearly crashed all my servers! Oh jesus why.
I changed the line in ws4py/client/init.py
from:
self.sock = ssl.wrap_socket(self.sock)
to this:
self.ssl_options = { "server_hostname" : self.host }
self.sock = ssl.SSLSocket(self.sock, **self.ssl_options)
TLS SNI enabled! Thank god! You guys should update this code and maybe drop a note in the readme for people using older versions! I wasn't able to get SNI working under python2.7 but it might be possible with a new enough compatible ssl.py installed.
I'm no expert regarding ssl and so on. I solved the problem like this in the connect function and it works (not 100% sure if it is a good solution). Of course also adding server_hostname to ssl_options:
if self.scheme == "wss":
if "cert_reqs" in self.ssl_options:
del self.ssl_options["cert_reqs"] # is not needed for SSLContext (we could instead prevent ws4py from adding it at all)
# default port is now 443; upgrade self.sender to send ssl
try: # default protocol=ssl.PROTOCOL_TLS
self.sock = ssl.SSLContext().wrap_socket(sock=self.sock, **self.ssl_options) # accepts: (sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)
except Exception as err: # prior python 3.5 support
self.sock = ssl.SSLContext(protocol=ssl.PROTOCOL_SSLv23).wrap_socket(sock=self.sock, **self.ssl_options)
self._is_secure = True