• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer

Mister PKI

SSL Certificates * SSL Tools * Certificate Decoder

  • Buy SSL Certificates
  • Blog
  • OpenSSL
  • Keytool
  • SSL Tools
  • Donate

Python get SSL Certificate

July 15, 2022 by Mister PKI Leave a Comment

This article will demonstrate how to use Python to get an SSL Certificate from a server. The server may be a remote web server, sip server, or any other type of server supporting SSL or TLS protected by a certificate. The server may even be a local server on the same machine as you are working from, but serving its own SSL certificate.

Python convert pem to X509

Before we begin getting the SSL certificate from the server let us write a helper method to convert a pem encoded certificate to a python X509 object. Here is the code to do so.

@staticmethod
def pem_to_x509(cert_data: str):
    """Converts a given pem encoded certificate to X509 object
    @param cert_data: str pem encoded certificate data that includes the header and footer
    @return: X509 object
    """
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, str.encode(cert_data))

Note that this method is part of a larger Python class included at the bottom of this article. This will help make sense of the static method and comments.

The pyOpenSSL module is used here to convert the String pem encoded certificate data into a python X509 object. (https://cryptography.io/en/latest/x509/index.html)

Python get server certificate

The following python method will fetch a server certificate for a given DNS name and port.

def fetch_server_certificate(self, dns_name: str, port: int):
    """Fetch the server certificate from the given dns_name and port
    @param dns_name: The dns name to fetch the certificate for
    @param port: The port that is serving the certificate
    @return: X509 certificate object
    """
    pem_server_certificate = ssl.get_server_certificate((dns_name, port))
    x509_server_certificate = self.pem_to_x509(pem_server_certificate)
    return x509_server_certificate

This method uses the python ssl library to fetch the certificate being served by the given DNS name and port. The ssl.get_server_certificate method returns a String pem encoded certificate. The method passes this pem encoded certificate to the previous function we wrote to convert it into a python X509 object that we can then extract the certificate data from, which will be covered in more detail below.

Python get server certificate SNI

The example above will fetch a server certificate but if SNI is enabled on the server, it very well may fetch the wrong one. For example, the microk8s NGINX Ingress controller will return the Kubernetes Ingress Controller Fake Certificate if using the ssl.get_server_certificate method because it is using SNI. Instead of returning the fake certificate you will want to return the publicly trusted SSL certificate the same as your browser would.

See our article on openssl s_client to learn more about getting certificates from servers with SNI enabled.

To avoid the potential issues caused by SNI we recommend the following method instead which will utilize the python SSLContext and socket.

def fetch_server_certificate_sni(self, dns_name: str, port: int):
    """Fetch the server certificate from the given dns_name and port
       This implementation supports SNI. Compare to ssl.get_server_certificate() which will return an incorrect
       cert if SNI is enabled on the server
    @param dns_name: The dns name to fetch the certificate for
    @param port: The port that is serving the certificate
    @return: X509 certificate object
    """
    connection = ssl.create_connection((dns_name, port))
    context = ssl.SSLContext()
    sock = context.wrap_socket(connection, server_hostname=dns_name)
    server_certificate = self.pem_to_x509(ssl.DER_cert_to_PEM_cert(sock.getpeercert(True)))
    sock.close()
    return server_certificate

In English, the code performs the following steps:

  1. Create an SSL connection to the given DNS name and port.
  2. Create an SSLContext
  3. Create an SSLSocket from the connection and context created in steps 1 and 2
  4. Get the certificate from the socket and convert it to an X509 object
  5. Close the socket
  6. Return the certificate

Python SSL and X509 Utils class

Here is the class code for the above methods.

import OpenSSL
import ssl

class SSLUtils:
    @staticmethod
    def pem_to_x509(cert_data: str):
        """Converts a given pem encoded certificate to X509 object
        @param cert_data: str pem encoded certificate data that includes the header and footer
        @return: X509 object
        """
        return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, str.encode(cert_data))
    def fetch_server_certificate(self, dns_name: str, port: int):
        """Fetch the server certificate from the given dns_name and port
        @param dns_name: The dns name to fetch the certificate for
        @param port: The port that is serving the certificate
        @return: X509 certificate object
        """
        pem_server_certificate = ssl.get_server_certificate((dns_name, port))
        x509_server_certificate = self.pem_to_x509(pem_server_certificate)
        return x509_server_certificate
    def fetch_server_certificate_sni(self, dns_name: str, port: int):
        """Fetch the server certificate from the given dns_name and port
           This implementation supports SNI. Compare to ssl.get_server_certificate() which will return an incorrect
           cert if SNI is enabled on the server
        @param dns_name: The dns name to fetch the certificate for
        @param port: The port that is serving the certificate
        @return: X509 certificate object
        """
        connection = ssl.create_connection((dns_name, port))
        context = ssl.SSLContext()
        sock = context.wrap_socket(connection, server_hostname=dns_name)
        server_certificate = self.pem_to_x509(ssl.DER_cert_to_PEM_cert(sock.getpeercert(True)))
        sock.close()
        return server_certificate

sslUtils = SSLUtils()
print(sslUtils.fetch_server_certificate("example.com", 443).get_subject())
print(sslUtils.fetch_server_certificate_sni("example.com", 443).get_subject())

Note that the output from running the file prints the same server certificate subject using the two different methods.

<X509Name object '/C=US/ST=California/L=Los Angeles/O=Internet\xC2\xA0Corporation\xC2\xA0for\xC2\xA0Assigned\xC2\xA0Names\xC2\xA0and\xC2\xA0Numbers/CN=www.example.org'>
<X509Name object '/C=US/ST=California/L=Los Angeles/O=Internet\xC2\xA0Corporation\xC2\xA0for\xC2\xA0Assigned\xC2\xA0Names\xC2\xA0and\xC2\xA0Numbers/CN=www.example.org'>

Python X509 Certificate object

The reason we converted the pem encoded certificate in the previous examples to the python X509 object was for convenience of use. A pem encoded certificate is just text in a file. If that is all you need then there’s no reason to convert it but in many cases it is best to go ahead and convert it so that it can be parsed for the data it contains. The examples below will demonstrate how to parse the X509 certificate object.

Each of the following examples will assume you already have the X509 Certificate Object created in the variable named certificate.

Python get certificate fingerprint

To get the certificate fingerprint you must use the digest method, passing in the algorithm for the fingerprint. The example below prints the sha256 and sha1 fingerprints.

print(f"SHA256: {certificate.digest('sha256').decode()}")
print(f"SHA1: {certificate.digest('sha1').decode()}")

Python get certificate serial number

To get the serial number from the x509 certificate:

print(f"Serial Number: {certificate.get_serial_number()}")

Python get certificate public key

To get the public key from the certificate:

print(f"Public Key: {certificate.get_pubkey()}")

Python get validity period

The validity period consists of the not before and not after dates. Not after is also known as the expiration date.

To get the not before date of the certificate:

print(f"Not Before: {certificate.get_notBefore().decode()}")

To get the not after or expiration date of the certificate:

print(f"Not After: {certificate.get_notAfter().decode()}")

Python get issuer

To get the issuer of the certificate:

print(f"Issuer: {certificate.get_issuer()}")

Python get subject

To get the subject or distinguished name of the certificate:

print(f"Subject: {certificate.get_subject()}")

Python get signature hash algorithm

To get the signature algorithm of the certificate:

print(f"Signature Algorithm: {certificate.get_signature_algorithm().decode()}")

Python get certificate extensions

X.509 certificates contain many extensions. To get all of the extensions:

for i in range(0, certificate.get_extension_count()):
    ext = certificate.get_extension(i)
    print(f"{ext.get_short_name().decode()}: {ext.get_data()}")

For example, subject alternative names are an extension. To get the sans of a certificate with python:

for i in range(0, certificate.get_extension_count()):
    ext = certificate.get_extension(i)
    if 'subjectAltName' in str(ext.get_short_name()):
        print(ext.get_data())

Conclusion

This article has demonstrated how to get an SSL Certificate from a server. Two ways, one without SNI and one with SNI. After getting the certificate we have demonstrated how convert the pem encoded certificate to an X.509 Certificate Object and then how to parse the X.509 Certificate object to get the certificate data. Let us know in the comments if you have any questions or would like to see additional examples about using SSL Certificate in the python programming language.

python,  SSL Certificates

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

Popular Posts

PKCS12

openssl s_client

Keytool

Keytool list

ECDSA vs RSA

OpenSSL

PKCS7

Certificate Decoder

Buy SSL Certificates

The SSL Store

Comodo Store

Sectigo Store

RapidSSL

Recent Posts

  • Proxy Addresses Active Directory
  • Windows Private Key Permissions
  • Install .NET 3.5 on Windows Server 2019
  • Netscaler SSL Redirect
  • How to mount NFS share on Linux

Footer

  • Twitter
  • YouTube

Pages

  • About Mister PKI
  • Blog
  • Compare and Buy Affordable PKI Certificates
  • Contact Us
  • Full Disclosure
  • Privacy Policy
  • SSL Tools – Certificate Decoder and Certificate Checker

Copyright © 2023