cert_hero package¶
Submodules¶
cert_hero.cert_hero module¶
Main module.
- class cert_hero.cert_hero.CertHero[source]¶
Bases:
dict
CertHero
represents the (resolved) SSL certificate of a server or hostname; it subclasses from builtindict
, so it is essentially the same as adict
object with convenience methods and a more human-readable__repr__()
method, for example.This means that a
CertHero
object is inherently JSON serializable:>>> import cert_hero, json >>> cert = cert_hero.CertHero({'key': 'value'}) >>> cert CertHero( { "key": "value" } ) >>> cert['key'] 'value' >>> json.dumps(cert) # or, easier: str(cert) '{"key": "value"}'
- classmethod from_dict(o: dict, _from_iso_format=<built-in method fromisoformat of type object>)[source]¶
Convert a serialized
dict
to aCertHero
object.
- property not_after_date: date¶
The Cert Not After Date (e.g. Valid Until)
- property not_before_date: date¶
The Cert Not Before Date (e.g. Valid From)
- cert_hero.cert_hero.cert_please(hostname: str, context: SSLContext = None, user_agent: str | None = None, default_encoding='latin-1') CertHero[str, str | int | dict[str, str | bool]] | None [source]¶
Retrieve the SSL certificate for a given
hostname
- works even in the case of expired or self-signed certificates.Usage:
>>> import cert_hero >>> cert = cert_hero.cert_please('google.com') >>> cert.not_after_date datetime.date(2023, 10, 28) >>> f'Cert is Valid Till: {cert.not_after_date.isoformat()}' '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 } ) >>> cert_hero.set_expired(cert) >>> cert['Validity'] {'Not After': '2023-10-28', 'Not Before': '2023-10-14', 'Expired': False}
Rationale:
The builtin Python module
ssl
can be used to retrieve a certificate from a server viagetpeercert
, 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.Additionally, if the host redirects the client to another URL, this info is captured in the
Location
andStatus
fields.- Parameters:
hostname – Host (or server) to retrieve SSL Certificate for
context – (Optional) Shared SSL Context
user_agent – A custom user agent to use for the HTTP call to retrieve
Location
andStatus
. Defaults topython-requests/{version}
, or a random user agent if thefake_useragent
module is installed (via thefake-ua
extra).default_encoding – Encoding used to decode bytes for the HTTP call to retrieve
Location
andStatus
. Defaults tolatin-1
(or ISO-8859-1).
- cert_hero.cert_hero.certs_please(hostnames: list[str] | tuple[str] | set[str], context: SSLContext = None, num_threads: int = 25, user_agent: str | None = None) dict[str, CertHero] [source]¶
Retrieve (concurrently) the SSL certificate(s) for a list of
hostnames
- works even in the case of expired or self-signed certificates.Usage:
>>> import cert_hero, json >>> host_to_cert = cert_hero.certs_please(['google.com', 'cnn.com', 'www.yahoo.co.in', 'youtu.be']) >>> cert_hero.set_expired(host_to_cert) >>> host_to_cert {'google.com': CertHero( { "Cert Status": "SUCCESS", "Serial": "753DD6FF20CB1B4510CB4C1EA27DA2EB", ... } ), 'cnn.com': CertHero( { "Cert Status": "SUCCESS", "Serial": "7F2F3E5C350554D71A6784CCFE6E8315", ... } ), ... } >>> json.dumps(host_to_cert) {"google.com": {"Cert Status": "SUCCESS", ...}, "cnn.com": {"Cert Status": "SUCCESS", ...}, ...}
- Parameters:
hostnames – List of hosts to retrieve SSL Certificate(s) for
context – (Optional) Shared SSL Context
num_threads – Max number of concurrent threads
user_agent – A custom user agent to use for the HTTP call to retrieve
Location
andStatus
. Defaults topython-requests/{version}
, or a random user agent if thefake_useragent
module is installed (via thefake-ua
extra).
- Returns:
A mapping of
hostname
to the SSL Certificate (e.g.CertHero
) for that host
- cert_hero.cert_hero.get_user_agent() str [source]¶
Return a random user agent using the
fake_useragent
module.
- cert_hero.cert_hero.set_expired(certs: ~cert_hero.cert_hero.CertHero | dict[str, str | int | dict[str, str | bool]] | dict[str, ~cert_hero.cert_hero.CertHero] | dict[str, dict[str, str | int | dict[str, str | bool]]] | ~typing.Iterable[~cert_hero.cert_hero.CertHero] | ~typing.Iterable[dict[str, str | int | dict[str, str | bool]]] | None, _date_from_iso_str=<built-in method fromisoformat of type object>) None [source]¶
Set or update the value for
Validity > Expired
(:type:`bool`) on each cert in a response fromcert_please()
orcerts_please()
, or a serialized version thereof (e.g.json.dumps
>json.loads
).Example Usage:
>>> from cert_hero import cert_please, set_expired >>> cert = cert_please('google.com') >>> assert 'Expired' not in cert['Validity'] >>> set_expired(cert) >>> assert 'Expired' in cert['Validity']
cert_hero.cli module¶
Console script for cert_hero.
Module contents¶
Cert Hero¶
Python Stand-alone Library to Download the SSL Certificate for Any Host™
Sample Usage:
>>> import cert_hero
>>> cert = cert_hero.cert_please('google.com')
>>> cert.not_after_date
datetime.date(2023, 10, 28)
>>> f'Cert is Valid Till: {cert.not_after_date.isoformat()}'
'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
}
)
>>> cert_hero.set_expired(cert)
>>> cert['Validity']
{'Not After': '2023-10-28', 'Not Before': '2023-10-14', 'Expired': False}
For full documentation and more advanced usage, please see <https://cert-hero.readthedocs.io>.
- copyright:
2023 by Ritvik Nag.
:license:MIT, see LICENSE for more details.
- class cert_hero.CertHero[source]¶
Bases:
dict
CertHero
represents the (resolved) SSL certificate of a server or hostname; it subclasses from builtindict
, so it is essentially the same as adict
object with convenience methods and a more human-readable__repr__()
method, for example.This means that a
CertHero
object is inherently JSON serializable:>>> import cert_hero, json >>> cert = cert_hero.CertHero({'key': 'value'}) >>> cert CertHero( { "key": "value" } ) >>> cert['key'] 'value' >>> json.dumps(cert) # or, easier: str(cert) '{"key": "value"}'
- classmethod from_dict(o: dict, _from_iso_format=<built-in method fromisoformat of type object>)[source]¶
Convert a serialized
dict
to aCertHero
object.
- property not_after_date: date¶
The Cert Not After Date (e.g. Valid Until)
- property not_before_date: date¶
The Cert Not Before Date (e.g. Valid From)
- cert_hero.cert_please(hostname: str, context: SSLContext = None, user_agent: str | None = None, default_encoding='latin-1') CertHero[str, str | int | dict[str, str | bool]] | None [source]¶
Retrieve the SSL certificate for a given
hostname
- works even in the case of expired or self-signed certificates.Usage:
>>> import cert_hero >>> cert = cert_hero.cert_please('google.com') >>> cert.not_after_date datetime.date(2023, 10, 28) >>> f'Cert is Valid Till: {cert.not_after_date.isoformat()}' '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 } ) >>> cert_hero.set_expired(cert) >>> cert['Validity'] {'Not After': '2023-10-28', 'Not Before': '2023-10-14', 'Expired': False}
Rationale:
The builtin Python module
ssl
can be used to retrieve a certificate from a server viagetpeercert
, 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.Additionally, if the host redirects the client to another URL, this info is captured in the
Location
andStatus
fields.- Parameters:
hostname – Host (or server) to retrieve SSL Certificate for
context – (Optional) Shared SSL Context
user_agent – A custom user agent to use for the HTTP call to retrieve
Location
andStatus
. Defaults topython-requests/{version}
, or a random user agent if thefake_useragent
module is installed (via thefake-ua
extra).default_encoding – Encoding used to decode bytes for the HTTP call to retrieve
Location
andStatus
. Defaults tolatin-1
(or ISO-8859-1).
- cert_hero.certs_please(hostnames: list[str] | tuple[str] | set[str], context: SSLContext = None, num_threads: int = 25, user_agent: str | None = None) dict[str, CertHero] [source]¶
Retrieve (concurrently) the SSL certificate(s) for a list of
hostnames
- works even in the case of expired or self-signed certificates.Usage:
>>> import cert_hero, json >>> host_to_cert = cert_hero.certs_please(['google.com', 'cnn.com', 'www.yahoo.co.in', 'youtu.be']) >>> cert_hero.set_expired(host_to_cert) >>> host_to_cert {'google.com': CertHero( { "Cert Status": "SUCCESS", "Serial": "753DD6FF20CB1B4510CB4C1EA27DA2EB", ... } ), 'cnn.com': CertHero( { "Cert Status": "SUCCESS", "Serial": "7F2F3E5C350554D71A6784CCFE6E8315", ... } ), ... } >>> json.dumps(host_to_cert) {"google.com": {"Cert Status": "SUCCESS", ...}, "cnn.com": {"Cert Status": "SUCCESS", ...}, ...}
- Parameters:
hostnames – List of hosts to retrieve SSL Certificate(s) for
context – (Optional) Shared SSL Context
num_threads – Max number of concurrent threads
user_agent – A custom user agent to use for the HTTP call to retrieve
Location
andStatus
. Defaults topython-requests/{version}
, or a random user agent if thefake_useragent
module is installed (via thefake-ua
extra).
- Returns:
A mapping of
hostname
to the SSL Certificate (e.g.CertHero
) for that host
- cert_hero.set_expired(certs: ~cert_hero.cert_hero.CertHero | dict[str, str | int | dict[str, str | bool]] | dict[str, ~cert_hero.cert_hero.CertHero] | dict[str, dict[str, str | int | dict[str, str | bool]]] | ~typing.Iterable[~cert_hero.cert_hero.CertHero] | ~typing.Iterable[dict[str, str | int | dict[str, str | bool]]] | None, _date_from_iso_str=<built-in method fromisoformat of type object>) None [source]¶
Set or update the value for
Validity > Expired
(:type:`bool`) on each cert in a response fromcert_please()
orcerts_please()
, or a serialized version thereof (e.g.json.dumps
>json.loads
).Example Usage:
>>> from cert_hero import cert_please, set_expired >>> cert = cert_please('google.com') >>> assert 'Expired' not in cert['Validity'] >>> set_expired(cert) >>> assert 'Expired' in cert['Validity']