I'm trying to find a way to get the list of SAN from a given certificate, however, I couldn't find anything in the pyOpenSSL documentation.
Any Ideas on how can I pull this data from the certificate?
I found a way where we first check extension by name, and then, when "SAN" data found we get str
representation and return.
def get_certificate_san(x509cert):
san = ''
ext_count = x509cert.get_extension_count()
for i in range(0, ext_count):
ext = x509cert.get_extension(i)
if 'subjectAltName' in str(ext.get_short_name()):
san = ext.__str__()
return san
PyOpenSSL recommends using cryptography
as it provides a safer and better API. If you can install cryptography (it's a dependency of the requests
library, so many projects already have it installed), here's how you get the SAN:
from cryptography import x509
# classes must be subtype of:
# https://cryptography.io/en/latest/x509/reference/#cryptography.x509.ExtensionType
san = loaded_cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
print(san)
Here's a full example of retrieving a cert from a host and printing its common name and SAN.
import ssl
from cryptography import x509
from cryptography.hazmat.backends import default_backend
certificate: bytes = ssl.get_server_certificate(('example.com', 443)).encode('utf-8')
loaded_cert = x509.load_pem_x509_certificate(certificate, default_backend())
common_name = loaded_cert.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)
print(common_name)
# classes must be subtype of:
# https://cryptography.io/en/latest/x509/reference/#cryptography.x509.ExtensionType
san = loaded_cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
san_dns_names = san.value.get_values_for_type(x509.DNSName)
print(san_dns_names)
Alternatively, if you're downloading a cert from a host, Python's built-in ssl
library will parse the SANs for you:
from collections import defaultdict
import socket
import ssl
hostname = 'www.python.org'
context = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
# https://docs.python.org/3/library/ssl.html#ssl.SSLSocket.getpeercert
cert = ssock.getpeercert()
subject = dict(item[0] for item in cert['subject'])
print(subject['commonName'])
subjectAltName = defaultdict(set)
for type_, san in cert['subjectAltName']:
subjectAltName[type_].add(san)
print(subjectAltName['DNS'])
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