Cert Hero¶
Python Stand-alone Library to Download the SSL Certificate for Any Host™
Documentation: https://cert-hero.readthedocs.io.
Why Use?
This library always returns the SSL certificate, if a server has one. This works for expired and self-signed certificate, whereas the builtin
ssl
library returns an emptydict
if verification fails for any reason (source).The only dependency is asn1crypto (with over 300 stars on GitHub), which is ~94% more lightweight and robust than a solution with pyOpenSSL (chart).
If a host redirects to another URL, this info is captured in
Location
andStatus
.Convenience methods such as
__repr__()
to make output more human-readable.
Core Exports
cert_please - Retrieve the SSL certificate for a given hostname.
certs_please - Retrieve (concurrently) the SSL certificate(s) for a list of hostnames.
set_expired - Helper function to check (at runtime) if a cert is expired or not.
Install¶
$ pip install cert-hero
Usage¶
Fetch the SSL certificate for a host with cert_please()
:
import cert_hero
cert = cert_hero.cert_please('google.com')
print('Cert is Valid Till:', cert.not_after_date.isoformat())
# To get the output as a JSON string, use `str(cert)` or remove `!r` from below
print(f'Cert -> \n{cert!r}')
cert_hero.set_expired(cert)
print(f'Validity ->\n{cert["Validity"]}')
Output (Sample)
Cert is Valid Till: 2023-10-28
Cert ->
CertHero(
{
"Cert Status": "SUCCESS",
"Serial": "753DD6FF20CB1B4510CB4C1EA27DA2EB",
"Subject Name": {
"Common Name": "*.google.com"
},
"Issuer Name": {
"Country": "US",
"State/Province": "California",
"Organization": "Zscaler Inc.",
"Organization Unit": "Zscaler Inc.",
"Common Name": "Zscaler Intermediate Root CA (zscalerthree.net) (t) "
},
"Validity": {
"Not After": "2023-10-28",
"Not Before": "2023-10-14"
},
"Wildcard": true,
"Signature Algorithm": "SHA256WITHRSA",
"Key Algorithm": "RSA-2048",
"Subject Alt Names": [
"*.google.com",
"*.appengine.google.com",
"youtu.be",
"*.youtube.com",
...
],
"Location": "https://www.google.com/",
"Status": 301
}
)
Validity ->
{'Not After': '2023-10-28', 'Not Before': '2023-10-14', 'Expired': False}
Fetch (concurrently) the SSL certificates for multiple hosts with certs_please()
:
import cert_hero
host_to_cert = cert_hero.certs_please(['google.com', 'cnn.com', 'www.yahoo.co.in', 'youtu.be'])
cert_hero.set_expired(host_to_cert)
for host, cert in host_to_cert.items():
print(f'=== {host.center(17)} ===')
# To get the output as a JSON string, use `str(cert)` or remove `!r` from below
print(f'{cert!r}')
print()
Output (Sample)
=== google.com ===
CertHero(
{
"Cert Status": "SUCCESS",
"Serial": "753DD6FF20CB1B4510CB4C1EA27DA2EB",
"Subject Name": {
"Common Name": "*.google.com"
},
...
}
)
=== cnn.com ===
CertHero(
{
"Cert Status": "SUCCESS",
"Serial": "7F2F3E5C350554D71A6784CCFE6E8315",
"Subject Name": {
"Common Name": "cnn.com"
},
...
}
)
=== www.yahoo.co.in ===
CertHero(
{
"Cert Status": "SUCCESS",
"Serial": "7D7FD7B7C2EE7146B4D4E43E36908B72",
"Subject Name": {
"Common Name": "src1.yahoo.com"
},
...
}
)
=== youtu.be ===
CertHero(
{
"Cert Status": "SUCCESS",
"Serial": "753DD6FF20CB1B4510CB4C1EA27DA2EB",
"Subject Name": {
"Common Name": "*.google.com"
},
...
}
)
Usage as a CLI¶
After the installation step you can use cert-hero just typing ch
in your terminal window.
The ch
command allows you to retrieve the SSL certificate(s) for one or more given host.
For example:
ch google.com cnn.com
You can get help about the main command using:
ch --help
Rationale¶
The builtin Python module ssl
can be used to retrieve a certificate from a server via getpeercert
,
but it’ll work only if the certificate of interest can be successfully verified (source).
If, for any reason, verification fails, like, for example, with expired or a self-signed certificate,
we’ll get ssl.SSLCertVerificationError
instead of the requested info.
We can work around this by asking for the certificate in the binary form:
getpeercert(binary_form=True)
But now we have to convert it, and thus we can use a third party asn1crypto
module, instead of
the (bulkier) cryptography
module.
Credits¶
This package was created with Cookiecutter and the rnag/cookiecutter-pypackage project template.