270 lines
10 KiB
Python
270 lines
10 KiB
Python
#!/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!") |