#!/usr/bin/env python3 import os import sys import requests from html.parser import HTMLParser from urllib.parse import urljoin LETSENCRYPT_CERT_PAGE = "https://letsencrypt.org/certificates/" DEFAULT_TARGET_DIR = "./letsencrypt-ca" class PemLinkParser(HTMLParser): def __init__(self): super().__init__() self.pem_links = set() def handle_starttag(self, tag, attrs): if tag.lower() != "a": return for attr, value in attrs: if attr == "href" and value.lower().endswith(".pem"): self.pem_links.add(value) def fetch_certificate_page(): resp = requests.get(LETSENCRYPT_CERT_PAGE, timeout=15) resp.raise_for_status() return resp.text def extract_pem_links(html): parser = PemLinkParser() parser.feed(html) return sorted( urljoin(LETSENCRYPT_CERT_PAGE, link) for link in parser.pem_links ) def download_and_store(url, target_dir): base_name = os.path.basename(url) # Zielname = .crt statt .pem target_name = os.path.splitext(base_name)[0] + ".crt" target_path = os.path.join(target_dir, target_name) if os.path.exists(target_path): print(f"[=] Bereits vorhanden: {target_name}") return target_name print(f"[+] Lade herunter: {base_name}") resp = requests.get(url, timeout=15) resp.raise_for_status() if b"BEGIN CERTIFICATE" not in resp.content: print(f"[!] Ungültiges Zertifikat: {base_name}") return None # Direkt als .crt speichern (PEM-Inhalt) with open(target_path, "wb") as f: f.write(resp.content) return target_name def list_local_crt_files(target_dir): return { f for f in os.listdir(target_dir) if f.lower().endswith(".crt") } def main(): target_dir = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_TARGET_DIR os.makedirs(target_dir, exist_ok=True) print(f"[*] Zielverzeichnis: {os.path.abspath(target_dir)}") print("[*] Format: PEM-Inhalt mit .crt-Endung") html = fetch_certificate_page() pem_urls = extract_pem_links(html) # Remote-Dateinamen im .crt-Format remote_files = { os.path.splitext(os.path.basename(url))[0] + ".crt" for url in pem_urls } for url in pem_urls: download_and_store(url, target_dir) local_files = list_local_crt_files(target_dir) orphaned = sorted(local_files - remote_files) print("\n" + "=" * 60) if orphaned: print("[!] Lokal vorhanden, aber nicht mehr gelistet:") for f in orphaned: print(f" - {f}") else: print("[✓] Keine veralteten Dateien gefunden") print("=" * 60) print("[✓] Fertig.") if __name__ == "__main__": main()