Files @ bb749f282c4e
Branch filter:

Location: C3L-NOC/tls-expiry-tracker/backend/check_domains.py - annotation

x
feat: add initial backend

current backend only prints out the state of the certificates in stdout.
it takes input domains from input.json, and checks only web ones.
various fail states are recogzied.
#!/usr/bin/env python3
import json
import ssl
import socket
from rich.console import Console
from cryptography import x509
import datetime
import math

def get_expiry_days(expiry_timestamp: int, now_timestamp: int = datetime.datetime.now().timestamp()) -> int:
    expiry_seconds = now_timestamp - expiry_timestamp
    expiry_days = math.floor(expiry_seconds / 86400)
    return expiry_days

def web_noconn_expiry_days(web_domain: str) -> int | None:
    try:
        pem_cert = ssl.get_server_certificate((web_domain, 443), timeout=5)
        cert = x509.load_pem_x509_certificate(pem_cert.encode())
    except Exception as e:
        console = Console()
        console.log("Could not grab server cert for", "[orange bold underline]"+web_domain, ":", e, style="orange")
        return None
    
    not_after = cert.not_valid_after.timestamp()
    return get_expiry_days(not_after)


console = Console()

# Parse the input file
with open('input.json') as raw_data:
    input = json.load(raw_data)

console.log("[white]Checking web domains...")

context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)

for web_domain in input["domains"]["web"]:
    # Initiate TLS connection
    with context.wrap_socket(socket.socket(), server_hostname=web_domain) as s:
        try:
            s.connect((web_domain, 443))
            cert = s.getpeercert()
        except ssl.SSLCertVerificationError as e:
            saved = e
            if e.verify_code == 10:
                expiry = web_noconn_expiry_days(web_domain)
                if(expiry != None):
                    # TODO: add the TLS expiry stuff here
                    # possibly a list of domains that have expired
                    # if its already in here, dont add it again
                    console.log("[red bold underline]" + web_domain, "expired", expiry, "days ago.", style="red")
            elif e.verify_code == 23:
                console.log("[red bold underline]" + web_domain, "was revoked.", style="red")
            elif e.verify_code == 18:
                console.log("[red bold underline]" + web_domain, "is self-signed.", style="red")
            elif e.verify_code == 19:
                console.log("[red bold underline]" + web_domain, "invalid: root not trusted.", style="red")
            else:
                console.log("[red bold underline]" + web_domain, "failed verification:", e.verify_message + ".", style="red")
            continue
        except ssl.SSLError as e:
            console.log("[orange bold underline]" + web_domain, "could not establish a secure connection:", e.reason, style="orange")
            continue
        except Exception as e:
            print(e)
            continue

    # Get expiry date
    expiry = cert['notAfter']
    expiry = datetime.datetime.strptime(expiry, '%b %d %H:%M:%S %Y %Z')

    # datetime to UNIX time
    expiry = expiry.timestamp()
    validity = abs(get_expiry_days(expiry))

    # Print expiry date
    console.log("[green bold underline]" + web_domain, "expires in", validity, "days", style="green")
    # TODO: remove known expired certs
    # If the cert was expired before, we know that it is now valid
    # -> remove it from the list of expired certs