I am doing research on the requirements for using untrusted root certificates on the Internet and I am having some problems with SSL chain detection.
Now I detect specified certificates with this function:
def _get_root_cert(link: str):
cert = ssl.get_server_certificate((link.split('//')[1], 443))
x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert.encode())
return x509.get_issuer().get_components()[2][1].decode()
This code works fine, but for some sites (like this) I got No-Sni certificate name instead of Russian Trusted CA. So now I need to get the full certificate chain, but I have some problems.
I've tried to get chain with this code, but it's not working as expected. Can anyone help me?
My experiments with chain detection:
import socket
import ssl
import base64
import binascii
hostname: str = 'https://mintrans.ryazan.gov.ru'
# Set up a socket connection to the site
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as sock:
# Get the certificate chain
cert_chain = sock.getpeercert(True)
# cert_chain_b64 = base64.b64encode(cert_chain).decode('utf-8')
# cert_chain_bytes = binascii.a2b_base64(cert_chain_b64)
# cert_chain_text = cert_chain_bytes.decode('utf-8')
cert_chain_text = None
try:
cert_chain_text = cert_chain.decode('utf-8')
except UnicodeDecodeError:
pass
if cert_chain_text is None:
try:
cert_chain_text = cert_chain.decode('latin-1')
except UnicodeDecodeError:
pass
if cert_chain_text is None:
try:
cert_chain_text = cert_chain.decode('windows-1252')
except UnicodeDecodeError:
pass
if cert_chain_text is None:
# Handle the error if none of the encodings work
print('Unable to decode certificate chain')
print(cert_chain_text)

I'm sorry I don't know how to proceed with python but it's quiete easy with openssl :
Which result in :
So in python if you can call a system command from the shell of the machine, you can use the previous command
Please also note the '-verify' value which is the depth of the chain. For big chains with lots of intermediate, you can upgrade this number to 10 or 15.
For your special case with python maybe you can do something like :
PS : As suggested by @SteffenUllrich, if you're using an old version of openssl, you should add to the prevuious command the servername, for example in your use case :
The whole command will be :
This is not necessary with :
Hope it could help