Update 2022-05-17: As TLS 1.2 will become more and more obsolete I'd really be interested in an answer for this question
Question and Title updated 2021-04-02:
I posted a question of how to get the list of permitted CAs for a given https server
And one person suggested using pyopenssl
, which helped me solving my problem at the time.
So I tried out following code:
import socket
from OpenSSL import SSL
def get_client_cert_cas(hostname, port):
ctx = SSL.Context(SSL.SSLv23_METHOD)
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
# next line for SNI
sock.set_tlsext_host_name(hostname.encode("utf-8"))
sock.connect((hostname, port))
return sock.get_client_ca_list()
It always returned no result.
After some playing around I came up with following solution:
Before calling sock.get_client_ca_list())
I perform a handshake with sock.do_handshake()
And this worked for all web servers, that I encountered up to this point.
Now however I encountered an https server where the SSL endpoint is on an F5
and now the code
def get_client_cert_cas(hostname, port):
ctx = SSL.Context(SSL.SSLv23_METHOD)
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
# next line for SNI
sock.set_tlsext_host_name(hostname.encode("utf-8"))
sock.connect((hostname, port))
sock.do_handshake() # now client_ca_list will not be empty
return sock.get_client_ca_list()
returns an empty result.
The openssl command openssl s_client -connect <hostname>:<port> -servername <hostname>
returns well the correct result.
After Further investigation I found out, that the F5 uses TLSv1.3 and the 'working' servers used TLSv1.2
Now my last fix which is working is to force TLSv1.2
def get_client_cert_cas(hostname, port):
ctx = SSL.Context(SSL.SSLv23_METHOD)
# It seems I must ensure to not use TLSV1.3
ctx.set_options(SSL.OP_NO_TLSv1_3)
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
# next line for SNI
sock.set_tlsext_host_name(hostname.encode("utf-8"))
sock.connect((hostname, port))
sock.do_handshake() # now client_ca_list will not be empty
return sock.get_client_ca_list()
Is it to be expected, that get_client_ca_list()
does not work with TLSV1.3 or is there an additional action to perform in the TLS1.3 case to have results for get_client_ca_list()
?
Please note, that I don't insist on pyopenssl
It is just the only solution, that I found so far.
If the problem can be solved with cryptography
or any other package, then this is also fine with me.