Spaces:
Sleeping
Sleeping
# Import necessary libraries | |
import gradio as gr | |
import ssl | |
import socket | |
import logging | |
import json | |
from cryptography import x509 | |
from cryptography.hazmat.backends import default_backend | |
from cryptography.hazmat.primitives import hashes | |
from datetime import datetime, timezone | |
def setup_logging(): | |
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") | |
file_handler = logging.FileHandler("ssl_check.log") | |
file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) | |
logging.getLogger().addHandler(file_handler) | |
setup_logging() | |
def get_fingerprints(cert): | |
return { | |
"SHA-256": cert.fingerprint(hashes.SHA256()).hex(), | |
"SHA-1": cert.fingerprint(hashes.SHA1()).hex(), | |
"MD5": cert.fingerprint(hashes.MD5()).hex(), | |
} | |
def get_san_list(cert): | |
try: | |
san_extension = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName) | |
return san_extension.value.get_values_for_type(x509.DNSName) | |
except x509.ExtensionNotFound: | |
return [] | |
def extract_certificate_details(cert): | |
""" | |
Extract key details from the certificate, including issuer, subject, fingerprints, and validity. | |
Args: | |
cert (x509.Certificate): The certificate object. | |
Returns: | |
dict: Dictionary containing certificate details. | |
""" | |
now = datetime.now(timezone.utc) | |
expiry_date = cert.not_valid_after.replace(tzinfo=timezone.utc) | |
not_before = cert.not_valid_before.replace(tzinfo=timezone.utc) | |
days_remaining = (expiry_date - now).days | |
fingerprints = get_fingerprints(cert) | |
san_list = get_san_list(cert) | |
return { | |
"expiry_date": expiry_date.isoformat(), | |
"not_before": not_before.isoformat(), | |
"days_remaining": days_remaining, | |
"fingerprints": fingerprints, | |
"issuer": {attr.oid._name: attr.value for attr in cert.issuer}, | |
"subject": {attr.oid._name: attr.value for attr in cert.subject}, | |
"san_list": san_list, | |
} | |
def establish_tls_connection(hostname, port, timeout): | |
context = ssl.create_default_context() | |
context.check_hostname = False | |
context.verify_mode = ssl.CERT_REQUIRED | |
with socket.create_connection((hostname, port), timeout=timeout) as sock: | |
with context.wrap_socket(sock, server_hostname=hostname) as tls_conn: | |
peer_cert_bin = tls_conn.getpeercert(binary_form=True) | |
if not peer_cert_bin: | |
raise ValueError("Peer certificate is missing.") | |
return peer_cert_bin, tls_conn.version() | |
def check_certificate(hostname, port, timeout): | |
try: | |
peer_cert_bin, tls_version = establish_tls_connection(hostname, port, timeout) | |
cert = x509.load_der_x509_certificate(peer_cert_bin, default_backend()) | |
cert_details = extract_certificate_details(cert) | |
cert_details["tls_version"] = tls_version | |
return json.dumps(cert_details, indent=2) | |
except Exception as e: | |
logging.error(f"Error checking certificate: {e}") | |
return f"Error: {e}" | |
def gradio_interface(hostname, port, timeout): | |
try: | |
port = int(port) | |
timeout = int(timeout) | |
return check_certificate(hostname, port, timeout) | |
except ValueError: | |
return "Port and timeout must be integers." | |
def create_interface(): | |
iface = gr.Interface( | |
fn=gradio_interface, | |
inputs=[ | |
gr.Textbox(label="Hostname", placeholder="Enter server hostname", lines=1), | |
gr.Number(label="Port", value=443), | |
gr.Number(label="Timeout (seconds)", value=10), | |
], | |
outputs=gr.Textbox(label="Certificate Details"), | |
title="SSL Certificate Checker", | |
description="Check the SSL certificate details of a server.", | |
) | |
return iface | |
if __name__ == "__main__": | |
iface = create_interface() | |
iface.launch() | |