Compare commits
2 commits
ad4bcc66cf
...
d207312a2e
Author | SHA1 | Date | |
---|---|---|---|
|
d207312a2e | ||
|
ec2f5ce902 |
|
@ -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"))
|
||||
|
|
Loading…
Reference in a new issue