#!/usr/bin/env python # -*- coding: utf-8 -*- """ SSL-Manager für die MYP-Plattform Generiert und verwaltet SSL-Zertifikate für Mercedes-Benz Yard Printing """ import os import socket from datetime import datetime, timedelta from cryptography import x509 from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa import ipaddress class SSLManager: """SSL-Zertifikat-Manager für die MYP-Plattform""" def __init__(self, cert_path: str = None, key_path: str = None): """ Initialisiert den SSL-Manager Args: cert_path: Pfad zum SSL-Zertifikat key_path: Pfad zum SSL-Schlüssel """ from config.settings import SSL_CERT_PATH, SSL_KEY_PATH self.cert_path = cert_path or SSL_CERT_PATH self.key_path = key_path or SSL_KEY_PATH # Stelle sicher, dass das Verzeichnis existiert cert_dir = os.path.dirname(self.cert_path) if not os.path.exists(cert_dir): os.makedirs(cert_dir, exist_ok=True) def generate_mercedes_certificate(self, hostname: str = "localhost", validity_days: int = 365) -> bool: """ Generiert ein Mercedes-Benz SSL-Zertifikat Args: hostname: Hostname für das Zertifikat validity_days: Gültigkeitsdauer in Tagen Returns: bool: True wenn erfolgreich, False bei Fehler """ try: print(f"Generiere Mercedes-Benz SSL-Zertifikat für {hostname}...") # Privaten Schlüssel generieren (4096-bit für höhere Sicherheit) private_key = rsa.generate_private_key( public_exponent=65537, key_size=4096, ) # Subject und Issuer für Mercedes-Benz subject = issuer = x509.Name([ x509.NameAttribute(NameOID.COUNTRY_NAME, "DE"), x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Baden-Württemberg"), x509.NameAttribute(NameOID.LOCALITY_NAME, "Stuttgart"), x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Mercedes-Benz Group AG"), x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "IT Infrastructure"), x509.NameAttribute(NameOID.COMMON_NAME, hostname), x509.NameAttribute(NameOID.EMAIL_ADDRESS, "admin@mercedes-benz.com"), ]) # Zertifikat erstellen cert = x509.CertificateBuilder().subject_name( subject ).issuer_name( issuer ).public_key( private_key.public_key() ).serial_number( x509.random_serial_number() ).not_valid_before( datetime.utcnow() ).not_valid_after( datetime.utcnow() + timedelta(days=validity_days) ) # Subject Alternative Names hinzufügen san_list = [ x509.DNSName(hostname), x509.DNSName("localhost"), x509.DNSName("*.localhost"), x509.DNSName("raspberrypi"), x509.DNSName("*.raspberrypi"), x509.DNSName("myp.mercedes-benz.local"), x509.DNSName("*.myp.mercedes-benz.local"), x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")), x509.IPAddress(ipaddress.IPv4Address("0.0.0.0")), ] # Lokale IP-Adresse hinzufügen try: local_ip = socket.gethostbyname(socket.gethostname()) if local_ip and local_ip != "127.0.0.1": san_list.append(x509.IPAddress(ipaddress.IPv4Address(local_ip))) except: pass cert = cert.add_extension( x509.SubjectAlternativeName(san_list), critical=False, ) # Key Usage Extension cert = cert.add_extension( x509.KeyUsage( digital_signature=True, key_encipherment=True, key_agreement=False, key_cert_sign=False, crl_sign=False, content_commitment=False, data_encipherment=False, encipher_only=False, decipher_only=False, ), critical=True, ) # Extended Key Usage cert = cert.add_extension( x509.ExtendedKeyUsage([ ExtendedKeyUsageOID.SERVER_AUTH, ExtendedKeyUsageOID.CLIENT_AUTH, ]), critical=True, ) # Basic Constraints cert = cert.add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True, ) # Zertifikat signieren cert = cert.sign(private_key, hashes.SHA256()) # Zertifikat in Datei schreiben with open(self.cert_path, "wb") as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) # Privaten Schlüssel in Datei schreiben with open(self.key_path, "wb") as f: f.write(private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() )) print(f"✓ SSL-Zertifikat erfolgreich erstellt: {self.cert_path}") print(f"✓ SSL-Schlüssel erfolgreich erstellt: {self.key_path}") # Zertifikatsinformationen anzeigen self._print_certificate_info(cert) return True except Exception as e: print(f"✗ Fehler beim Erstellen des SSL-Zertifikats: {e}") return False def _print_certificate_info(self, cert): """Zeigt Informationen über das erstellte Zertifikat an""" try: print("\n=== Zertifikatsinformationen ===") print(f"Subject: {cert.subject.rfc4514_string()}") print(f"Gültig von: {cert.not_valid_before}") print(f"Gültig bis: {cert.not_valid_after}") print(f"Seriennummer: {cert.serial_number}") # SAN anzeigen try: san_ext = cert.extensions.get_extension_for_oid(x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME) print("Subject Alternative Names:") for name in san_ext.value: print(f" - {name}") except: pass print("================================\n") except Exception as e: print(f"Fehler beim Anzeigen der Zertifikatsinformationen: {e}") def certificate_exists(self) -> bool: """ Prüft, ob SSL-Zertifikat und Schlüssel existieren Returns: bool: True wenn beide Dateien existieren """ return os.path.exists(self.cert_path) and os.path.exists(self.key_path) def get_certificate_info(self) -> dict: """ Gibt Informationen über das vorhandene Zertifikat zurück Returns: dict: Zertifikatsinformationen oder None bei Fehler """ if not self.certificate_exists(): return None try: with open(self.cert_path, "rb") as f: cert_data = f.read() cert = x509.load_pem_x509_certificate(cert_data) return { "subject": cert.subject.rfc4514_string(), "issuer": cert.issuer.rfc4514_string(), "not_valid_before": cert.not_valid_before, "not_valid_after": cert.not_valid_after, "serial_number": cert.serial_number, "is_expired": datetime.utcnow() > cert.not_valid_after, "days_until_expiry": (cert.not_valid_after - datetime.utcnow()).days } except Exception as e: print(f"Fehler beim Lesen der Zertifikatsinformationen: {e}") return None # Globale SSL-Manager-Instanz ssl_manager = SSLManager() def ensure_ssl_certificates() -> bool: """ Stellt sicher, dass SSL-Zertifikate vorhanden sind Returns: bool: True wenn Zertifikate verfügbar sind """ if ssl_manager.certificate_exists(): cert_info = ssl_manager.get_certificate_info() if cert_info and not cert_info["is_expired"]: print(f"✓ Gültiges SSL-Zertifikat gefunden (läuft ab in {cert_info['days_until_expiry']} Tagen)") return True else: print("⚠ SSL-Zertifikat ist abgelaufen, erstelle neues...") print("SSL-Zertifikate nicht gefunden, erstelle neue...") return ssl_manager.generate_mercedes_certificate() if __name__ == "__main__": # Direkte Ausführung für Tests print("Mercedes-Benz SSL-Zertifikat-Generator") print("=====================================") if ssl_manager.certificate_exists(): print("Vorhandene Zertifikate gefunden:") info = ssl_manager.get_certificate_info() if info: print(f" Subject: {info['subject']}") print(f" Gültig bis: {info['not_valid_after']}") print(f" Status: {'Abgelaufen' if info['is_expired'] else 'Gültig'}") success = ssl_manager.generate_mercedes_certificate() if success: print("✓ SSL-Zertifikat erfolgreich generiert!") else: print("✗ Fehler beim Generieren des SSL-Zertifikats!")