Getting the certificate chain for a hostname should not be difficult!
Sometimes websites do not present the full chain (against RFC recommendations) which means it's hard to find the certificate chain and troubleshoot.
This script will attempt to use the breadcrumbs that are left by the certificate to build the chain and output it into files.
It's worked on publicly available websites (at least the ones I've tested). Happy to troubleshoot if an error pops up.
$ python3 -m pip install re cryptography argparse ssl
To get the arguments available python3 getCertChain.py --help
. Should present information like this:
$ python3 getCertChain.py -h
usage: getCertChain.py [-h] [--hostname HOSTNAME] [--removeCertificateFiles] [--getCAcertPEM] [--insecure]
Get Certificate Chain v0.07
optional arguments:
-h, --help show this help message and exit
--hostname HOSTNAME The hostname:port pair that the script should connect to. Defaults to www.google.com:443.
--removeCertificateFiles
Remove the certificate files in current working directory (*.crt, *.pem).
--getCAcertPEM Get cacert.pem from curl.se website to help find Root CA.
--insecure Allow insecure connections to establish.
To get the certificate chain for www.google.com
$ python3 getCertChain --hostname www.google.com
$
It by default will not display any output (unless it struggles to find the Root CA).
To see the files it created (from where the script ran):
$ ls -l
total 28
-rw-r--r-- 1 gituser gituser 1911 Mar 12 16:38 0-gts-root-r1.crt
-rw-r--r-- 1 gituser gituser 1996 Mar 12 16:38 1-gts-ca-1c3.crt
-rw-r--r-- 1 gituser gituser 1631 Mar 12 16:38 2-www.google.com.crt
-rw-r--r-- 1 gituser gituser 13385 Mar 12 16:36 getCertChain.py
If you notice the prefix of each new file that was created (i.e. 0-, 1-, 2-) this is the order of the chain with
0-
being the Root CA1-
being the intermediate CA2-
being the endpoint/website certificate
The rest of the file name is deduced from the commonName in the certificate.
On some occasions, the intermediate CA does not present an Authority Information Access field (AIA) with a URI on where to get the file from.
To help build the chain, we need some external
help - leveraging the cacert.pem
file from curl.se
website.
This is the url: 🔗 https://curl.se/ca/cacert.pem
To get the cacert.pem
file as part of the connection from --hostname
argument:
$ python3 getCertChain.py --hostname www.google.com --getCAcertPEM
You could also run it by itself:
$ python3 getCertChain.py --getCAcertPEM
$ python3 getCertChain.py --removeCertificateFiles
Removing file 1-gts-ca-1c3.crt
Removing file 2-www.google.com.crt
Removing file 0-gts-root-r1.crt
Removing file cacert.pem
Using AI, I wrote a powershell script that can help accomplish the same thing within windows. This only downloads the certificates. It does not have the capability to remove them. To download the chain that the hostname presents: Usage:
.\getCertificateChain.ps1 -hostname www.example.com
To download the chain that the hostname presents and use the Authority Information Access (AIA) Fields use the -useAIA
argument to assist:
.\getCertificateChain.ps1 -hostname www.example.com -useAIA
Given the way MitM proxies and decryption services work, this tool is not intended to be used behind devices that perform SSL/TLS decryption as those devices strip the Authority Information Access
(AIA), and alter the Subject Key Identifier
(SKI) and Authority Key Identifier
(AKI) fields.
If a website's certificate chain has 4 or more tiers and one of the intermediate CA's do not have a AIA field - the script will only show the website certificate and the first issuing CA.
Something like this:
- Root CA
- Issuing CA 1
- Issuing Sub CA 1
- Website certificate (example.com)
- Issuing Sub CA 1
- Issuing CA 1
Script will only output Issuing Sub CA 1
and website certificate
.