Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Python

Python 3 - How to Download, View and Save Certificates

0.00/5 (No votes)
23 Feb 2019CPOL2 min read 23.5K  
The code below is a sample Python snippet that will connect to host (eg. any www.host.com) at specified port (eg. 443), download certificate chain from host, and store them on the specified cert_file_pathname location.

Introduction

I wrote this article to pass on my knowledge to other developers who might have stumbled upon a different version of Python (Python 2.7.x VS Python 3.7.x) when using OpenSSL to download, view, and save certificates.

Background

While doing POC, I stumbled upon the versioning conflict of Python 2.7.x and Python 3.7.x.

I searched through lots of public articles and lots of Q & A on this topic. Not much information was found on this topic. My purpose is to retrieve certificate chain and store the certificates on my local drive which can be further used in other modules.

Using the Code

The code below is a sample Python snippet that will connect to host (e.g., any www.host.com) at specified port (e.g., 443), download certificate chain from host, and store the certificates on the specified cert_file_pathname (e.g., c:\testfolder\certfile). In the code snippet, I iterate through the certificate list and retrieve the certificate's CN, then print out the CN string. But you can retrieve other fields as needed.

Notice that I manipulate cert_file_pathname and append the index of the certificate to certfile in the code so that I can store all the downloaded certificate with the same prefix. You can modify the code to serve your purpose as needed.

I would like to share this code with everyone as I realized that there aren't many article about this topic. I have learned the feature through articles and Q & A along with OpenSSL and Python documentation.

Python
def get_certificate(host, port, cert_file_pathname):
    s = socket()
    context = SSL.Context(SSL.TLSv1_2_METHOD)
    print('Connecting to {0} to get certificate...'.format(host))
    conn = SSL.Connection(context, s)
    certs = []

    try:
        conn.connect((host, port))
        conn.do_handshake()
        certs = conn.get_peer_cert_chain()

    except SSL.Error as e:
        print('Error: {0}'.format(str(e)))
        exit(1)

    try:
        for index, cert in enumerate(certs):
            cert_components = dict(cert.get_subject().get_components())
            if(sys.version_info[0] >= 3):
                cn = (cert_components.get(b'CN')).decode('utf-8')
            else:
                cn = cert_components.get('CN')
            print('Centificate {0} - CN: {1}'.format(index, cn))

            try:
                temp_certname = '{0}_{1}.crt'.format(cert_file_pathname, index)
                with open(temp_certname, 'w+') as output_file:
                    if(sys.version_info[0] >= 3):
                        output_file.write((crypto.dump_certificate
                                         (crypto.FILETYPE_PEM, cert).decode('utf-8')))
                    else:
                        output_file.write((crypto.dump_certificate(crypto.FILETYPE_PEM, cert)))
            except IOError:
                print('Exception:  {0}'.format(IOError.strerror))

    except SSL.Error as e:
        print('Error: {0}'.format(str(e)))
        exit(1)

Point of Interest

I learned the difference between Python 2.7.15 and 3.7.2 while writing this code. I have learned different certificate formats and security protocol that can be used as well. I am hoping this code will help those that are new to Python and SSL like me.

Note that I use crypto to dump the certificate off in PEM format, but the cert can be dumped in FILETYPE_ASN1 as well. See additional reference: https://pyopenssl.org/en/stable/api/crypto.html.

History

The code above will generate the following output:

Connecting to <host> to get certificate...
Centificate 0 - CN: <certificate CN>
Centificate 1 - CN: <certificate CN>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)