Skip to main content

How to get the expiry date of an HTTPS certificate

I was tinkering with some HTTPS certificates, and I wanted to write a scheduled test that would check the certiifcates weren’t about to expire. This is the sort of thing that should be handled by a good certificate provider – for example, Let’s Encrypt sends me emails when my certificates are close to expiry – but another check is a good belt-and-braces measure.

With a bit of help from Stack Overflow, I wrote a Python function that works out when the HTTPS certificate for a domain expires:

import contextlib
import datetime
import socket
import ssl


def get_https_expiry_date(hostname: str) -> datetime.datetime:
    """
    Get the expiry date of the HTTPS certificate for a domain.
    """
    ctx = ssl.create_default_context()

    with contextlib.closing(socket.socket(socket.AF_INET)) as sock:
        conn = ctx.wrap_socket(sock, server_hostname=hostname)

        conn.settimeout(5.0)
        conn.connect((hostname, 443))
        ssl_info = conn.getpeercert()

        # Example date: "Oct 17 12:32:16 2024 GMT"
        expiry_date_str = ssl_info["notAfter"]
        expiry_date = datetime.datetime.strptime(
            expiry_date_str, "%b %d %H:%M:%S %Y %Z"
        )

    return expiry_date


if __name__ == "__main__":
    print(get_https_expiry_date("alexwlchan.net"))

I call that from a test, and assert the delta between now and the expiry date is at least two weeks. I can adjust that threshold as I think is useful.

As an example, here’s what ssl_info looks like for my domain:

{'OCSP': ('http://e5.o.lencr.org',),
 'caIssuers': ('http://e5.i.lencr.org/',),
 'issuer': ((('countryName', 'US'),),
            (('organizationName', "Let's Encrypt"),),
            (('commonName', 'E5'),)),
 'notAfter': 'Oct 17 12:32:16 2024 GMT',
 'notBefore': 'Jul 19 12:32:17 2024 GMT',
 'serialNumber': '04D4D59A60990543FD74EA616776AB2274DE',
 'subject': ((('commonName', 'alexwlchan.co.uk'),),),
 'subjectAltName': (('DNS', 'alexwlchan.co.uk'),
                    ('DNS', 'alexwlchan.com'),
                    ('DNS', 'alexwlchan.net'),
                    ('DNS', 'www.alexwlchan.net')),
 'version': 3}