Initial commit

This commit is contained in:
Scott Wallace 2024-02-23 08:09:14 +00:00
commit 4fba7dbabf
Signed by: scott
GPG key ID: AA742FDC5AFE2A72
4 changed files with 150 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.pyenv/

0
README.md Normal file
View file

120
cert_deets.py Normal file
View file

@ -0,0 +1,120 @@
#!python3
"""
Return the Akamai property and version for a given site
"""
import argparse
import socket
import ssl
import sys
from typing import Any
from urllib.parse import urlparse
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from tabulate import tabulate
SAN_GROUPING = 4
def display_error(
site: str,
error: Any = None,
) -> None:
"""
Print a generic error
"""
print(f"ERROR: Could not find a certificate for {site}")
if error:
print(str(error))
if __name__ == "__main__":
def parseargs() -> argparse.Namespace:
"""
Parse the CLI
Returns:
argparse.Namespace: parsed arguments
"""
parser = argparse.ArgumentParser()
parser.add_argument("site", help="site to lookup")
return parser.parse_args()
def main() -> int:
"""
Main entrypoint
Returns:
int: return value
"""
args = parseargs()
parts = urlparse(args.site, scheme="https")
if not parts.netloc:
parts = parts._replace(netloc=args.site)
if not parts.port:
parts = parts._replace(netloc=f"{parts.netloc}:443")
if not parts.hostname or not parts.port:
display_error(args.site, "Cannot parse hostname")
return 1
endpoint = f"{parts.hostname}:{parts.port}"
try:
pem_data = ssl.get_server_certificate(
(parts.hostname, parts.port),
).encode("utf-8")
except (
ConnectionRefusedError,
ssl.CertificateError,
ssl.SSLError,
socket.gaierror,
) as error:
display_error(endpoint, error)
return 2
if not pem_data:
display_error(endpoint, "Cannot fetch PEM data")
return 3
cert = x509.load_pem_x509_certificate(pem_data, default_backend())
sans = [
f"DNS:{dns}"
for dns in cert.extensions.get_extension_for_class(
x509.SubjectAlternativeName
).value.get_values_for_type(x509.DNSName)
]
sans.extend(
[
f"IP:{ip}"
for ip in cert.extensions.get_extension_for_class(
x509.SubjectAlternativeName
).value.get_values_for_type(x509.IPAddress)
]
)
sangroups = [
sans[group : group + SAN_GROUPING]
for group in range(0, len(sans), SAN_GROUPING)
]
table = [
["Common name", cert.subject.rfc4514_string()],
["SANs", tabulate(sangroups, tablefmt="plain")],
["Valid from", cert.not_valid_before_utc],
["Valid to", cert.not_valid_after_utc],
["Issuer", cert.issuer.rfc4514_string()],
]
print(tabulate(table, tablefmt="plain"))
return 0
sys.exit(main())

29
pyproject.toml Normal file
View file

@ -0,0 +1,29 @@
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "cert-deets"
version = "1.0"
authors = [{ name = "Scott Wallace", email = "scott@wallace.sh" }]
description = "Show TLS certificate details for a given endpoint"
keywords = ["tls", "certificate", "python"]
classifiers = ["Programming Language :: Python :: 3"]
readme = "README.md"
dependencies = ["cryptography", "tabulate"]
requires-python = ">=3.11"
[project.urls]
Homepage = "https://git.wallace.sh/scott/cert-deets/wiki"
Source = "https://git.wallace.sh/scott/cert-deets"
Issues = "https://git.wallace.sh/scott/cert-deets/issues"
[project.optional-dependencies]
dev = ["black", "pylint"]
tests = ["pytest", "pytest-cov"]
[tool.black]
target-version = ["py311"]
[project.scripts]
certs-deets = "cert_deets:main"