Thursday, 8 April 2021

Is it normal, that get_client_ca_list() of pyopenssl fails with TLS1.3

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.



from Is it normal, that get_client_ca_list() of pyopenssl fails with TLS1.3

No comments:

Post a Comment