Compare commits

...

2 commits

Author SHA1 Message Date
Scott Wallace d207312a2e
Code tidy up 2025-03-05 17:29:06 +00:00
Scott Wallace ec2f5ce902
Add SHA256 fingerprints to output 2025-03-05 17:28:59 +00:00

View file

@ -1,12 +1,13 @@
#!python3
"""
Return the Akamai property and version for a given site
"""
"""Display TLS certificate details for an HTTP endpoint."""
from __future__ import annotations
import argparse
import socket
import ssl
import sys
import urllib.error
from contextlib import suppress
from typing import Any
from urllib.parse import urlparse
@ -20,8 +21,7 @@ SAN_GROUPING = 4
def get_cert_with_servername(addr: tuple[str, int], servername: str = "") -> bytes:
"""
Get TLS certificate from an address with an explicit servername override
"""Get TLS certificate from an address with an explicit servername override.
Args:
addr (tuple[str, int]): adress in tuple form (address, port)
@ -29,51 +29,49 @@ def get_cert_with_servername(addr: tuple[str, int], servername: str = "") -> byt
Returns:
bytes: PEM bytes
"""
context = ssl.create_default_context()
context.check_hostname = False
with socket.create_connection((addr[0], addr[1]), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=servername) as sslsock:
if der_cert := sslsock.getpeercert(True):
return ssl.DER_cert_to_PEM_cert(der_cert).encode("utf=8")
with socket.create_connection((addr[0], addr[1]), timeout=10) as sock, context.wrap_socket(
sock,
server_hostname=servername,
) as sslsock:
if der_cert := sslsock.getpeercert(binary_form=True):
return ssl.DER_cert_to_PEM_cert(der_cert).encode("utf=8")
return bytes()
return b""
def format_fingerprint(fingerprint: bytes | str) -> str:
"""
Print a fingerprint as a colon-separated hex string
"""Print a fingerprint as a colon-separated hex string.
Args:
fingerprint (bytes | str): fingerprint to format
Returns:
str: formatted fingerprint
"""
if isinstance(fingerprint, str):
fingerprint = bytearray.fromhex(fingerprint)
return ":".join([format(i, "02x") for i in fingerprint])
def display_error(
site: str,
error: Any = None,
) -> None:
"""
Print a generic error
"""
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))
def parseargs() -> argparse.Namespace:
"""
Parse the CLI
"""Parse the CLI.
Returns:
argparse.Namespace: parsed arguments
"""
parser = argparse.ArgumentParser()
@ -84,11 +82,11 @@ def parseargs() -> argparse.Namespace:
def main() -> int:
"""
Main entrypoint
"""Run the code.
Returns:
int: return value
"""
args = parseargs()
@ -123,10 +121,8 @@ def main() -> int:
).encode("utf-8")
cert_chain = CertificateChain()
try:
with suppress(urllib.error.URLError):
cert_chain = resolve(pem_data)
except urllib.error.URLError:
pass
except (
ConnectionRefusedError,
ConnectionResetError,
@ -146,23 +142,20 @@ def main() -> int:
sans = [
f"DNS:{dns}"
for dns in cert.extensions.get_extension_for_class(
x509.SubjectAlternativeName
).value.get_values_for_type(x509.DNSName)
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)
]
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)
]
sangroups = [sans[group : group + SAN_GROUPING] for group in range(0, len(sans), SAN_GROUPING)]
table = [
["Common name", cert.subject.rfc4514_string()],
@ -172,7 +165,8 @@ def main() -> int:
["Issuer", cert.issuer.rfc4514_string()],
[
"Fingerprint",
f"{format_fingerprint(cert.fingerprint(hashes.SHA1()))} (SHA1)",
f"{format_fingerprint(cert.fingerprint(hashes.SHA1()))} (SHA1)\n"
f"{format_fingerprint(cert.fingerprint(hashes.SHA256()))} (SHA256)\n",
],
]
@ -184,13 +178,14 @@ def main() -> int:
[
f"{cert.common_name} "
f"(Issuer: {cert.issuer})\n"
"Fingerprint: "
f"{format_fingerprint(cert.get_fingerprint(hashes.SHA1))} (SHA1)"
for cert in list(cert_chain.intermediates) + [cert_chain.root]
"Fingerprint: \n"
f"\t{format_fingerprint(cert.get_fingerprint(hashes.SHA1))} (SHA1)\n"
f"\t{format_fingerprint(cert.get_fingerprint(hashes.SHA256))} (SHA256)"
for cert in [*list(cert_chain.intermediates), cert_chain.root]
if cert
]
],
),
]
],
)
print(tabulate(table, tablefmt="plain"))