With PyOpenSSL ( version 20.0.0 ), is it possible to set a timeout on do_handshake() call when socket.setblocking(False)?
I have a hostname that responds to a socket ( so you get an IP address). But when I call do_handshake() the server never answers the Client Hello. I don't control the server.
If I set the sock.setblocking(True) the do_handshake() works great with normal endpoints. But then I hit my bad host ( good socket, no TLS ). It fails after ~ 35 seconds with OpenSSL.SSL.Error. Makes sense. The error is ('SSL routines', 'ssl3_get_record', 'wrong version number').
I tried setting the timeout in the OpenSSL.Context:
context = Context(TLSv1_2_METHOD)
context.set_timeout(5)
That didn't work. I tried setting a timeout on the socket:
sock.setblocking(False)
sock.settimeout(3.0)
I think that could work. But, that always fires OpenSSL.SSL.WantReadError when I call do_handshake():
tls_client = Connection(verifier.context, s.sock)
tls_client.set_tlsext_host_name(bytes(s.host, 'utf-8'))
tls_client.set_connect_state() # set to work in client mode
try:
tls_client.do_handshake()
except WantReadError:
print("[!]WantReadError. Only generated with sock.setblocking(False)")
So I am stuck waiting for ~35 seconds with the following settings to avoid the WantReadError:
self.sock.setblocking(True)
#self.sock.settimeout(3.0)
openssl s_client shows the debug flow:
openssl s_client -CApath ${CERTS} -state -nbio -connect foo.bar.com:443
CONNECTED(00000007)
Turned on non blocking io
SSL_connect:before SSL initialization
SSL_connect:SSLv3/TLS write client hello
SSL_connect:error in SSLv3/TLS write client hello
write R BLOCK
I met the exact problem (no comments yet). Mine is getting reset after 300 seconds.
After struggling for a few days, I use standard ssl lib to handle timeout before PyOpenSSL code:
import ssl
import socket
_ssl_ctx = ssl.SSLContext()
_ssl_ctx.verify_mode = ssl.CERT_NONE
_ssl_ctx.check_hostname = False
_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_sock.settimeout(1)
_ssl_sock = _ssl_ctx.wrap_socket(_sock, do_handshake_on_connect=False)
try:
_ssl_sock.connect(("host", 443))
_ssl_sock.do_handshake()
except Exception as e:
print(str(e))
finally:
_ssl_sock.close()
#
ssl_context = SSL.Context(SSL.SSLv23_METHOD)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn = SSL.Connection(ssl_context, sock)
conn.settimeout(1) # socket timeout for establishing connection
conn.connect(("host", 443))
conn.setblocking(True)
conn.do_handshake()
conn.get_peer_cert_chain()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With