📚 Improved SSL configuration and fix for browser compatibility in backend modules. 🌐🔒
This commit is contained in:
230
backend/fix_ssl_browser.py
Normal file
230
backend/fix_ssl_browser.py
Normal file
@ -0,0 +1,230 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Windows-kompatibles SSL-Fix Tool für MYP Platform
|
||||
Löst ERR_SSL_KEY_USAGE_INCOMPATIBLE Browser-Fehler ohne externe OpenSSL-Befehle
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
def regenerate_ssl_certificates():
|
||||
"""Regeneriert SSL-Zertifikate mit korrekten Browser-kompatiblen Extensions"""
|
||||
|
||||
print("🔧 SSL BROWSER-KOMPATIBILITÄTS-FIX")
|
||||
print("Löst ERR_SSL_KEY_USAGE_INCOMPATIBLE Fehler")
|
||||
print("=" * 60)
|
||||
|
||||
# Verschiedene mögliche SSL-Verzeichnisse
|
||||
ssl_directories = [
|
||||
Path("ssl"),
|
||||
Path("certs"),
|
||||
Path("certs/localhost"),
|
||||
Path("instance/ssl"),
|
||||
Path("../ssl")
|
||||
]
|
||||
|
||||
found_certs = []
|
||||
|
||||
# Finde existierende Zertifikate
|
||||
for ssl_dir in ssl_directories:
|
||||
if ssl_dir.exists():
|
||||
cert_files = ["cert.pem", "localhost.crt", "myp.crt", "server.crt"]
|
||||
key_files = ["key.pem", "localhost.key", "myp.key", "server.key"]
|
||||
|
||||
for cert_name in cert_files:
|
||||
for key_name in key_files:
|
||||
cert_path = ssl_dir / cert_name
|
||||
key_path = ssl_dir / key_name
|
||||
|
||||
if cert_path.exists() and key_path.exists():
|
||||
found_certs.append((cert_path, key_path, ssl_dir))
|
||||
print(f"📄 Gefunden: {cert_path}")
|
||||
|
||||
if not found_certs:
|
||||
print("📂 Keine SSL-Zertifikate gefunden - erstelle neue...")
|
||||
ssl_dir = Path("ssl")
|
||||
ssl_dir.mkdir(exist_ok=True)
|
||||
found_certs = [(ssl_dir / "cert.pem", ssl_dir / "key.pem", ssl_dir)]
|
||||
|
||||
# Verwende das SSL-Modul zur Neugenerierung
|
||||
print("\n🔄 Regeneriere browser-kompatible SSL-Zertifikate...")
|
||||
|
||||
try:
|
||||
# Importiere das SSL-Modul
|
||||
sys.path.insert(0, str(Path.cwd()))
|
||||
from utils.ssl_config import SSLCertificateManager
|
||||
|
||||
success_count = 0
|
||||
|
||||
for cert_path, key_path, ssl_dir in found_certs:
|
||||
print(f"\n📁 Bearbeite: {ssl_dir}")
|
||||
|
||||
# Backup erstellen
|
||||
backup_dir = ssl_dir / "backup"
|
||||
backup_dir.mkdir(exist_ok=True)
|
||||
|
||||
if cert_path.exists():
|
||||
backup_cert = backup_dir / f"{cert_path.name}.backup"
|
||||
backup_key = backup_dir / f"{key_path.name}.backup"
|
||||
|
||||
try:
|
||||
shutil.copy2(cert_path, backup_cert)
|
||||
shutil.copy2(key_path, backup_key)
|
||||
print(f"💾 Backup erstellt: {backup_cert}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Backup fehlgeschlagen: {e}")
|
||||
|
||||
# SSL-Manager konfigurieren
|
||||
app_dir = Path.cwd().absolute()
|
||||
ssl_manager = SSLCertificateManager(str(app_dir))
|
||||
|
||||
# Überschreibe Pfade für gefundenes Verzeichnis
|
||||
ssl_manager.ssl_dir = ssl_dir
|
||||
ssl_manager.cert_file = cert_path
|
||||
ssl_manager.key_file = key_path
|
||||
|
||||
# Regeneriere Zertifikat mit korrekten Extensions
|
||||
print("🔧 Generiere browser-kompatibles Zertifikat...")
|
||||
|
||||
if ssl_manager.generate_ssl_certificate(force_regenerate=True):
|
||||
print("✅ Browser-kompatibles Zertifikat generiert")
|
||||
success_count += 1
|
||||
|
||||
# Validiere das neue Zertifikat
|
||||
if validate_certificate_compatibility(cert_path):
|
||||
print("🎉 Browser-Kompatibilitäts-Check bestanden!")
|
||||
else:
|
||||
print("⚠️ Zertifikat generiert, aber möglicherweise nicht vollständig kompatibel")
|
||||
|
||||
else:
|
||||
print("❌ Zertifikat-Generierung fehlgeschlagen")
|
||||
|
||||
if success_count > 0:
|
||||
print(f"\n✅ SSL-FIX ERFOLGREICH!")
|
||||
print(f" {success_count} Zertifikat(e) erfolgreich regeneriert")
|
||||
print(f"\n🌐 NÄCHSTE SCHRITTE:")
|
||||
print(f" 1. Browser-Cache vollständig leeren:")
|
||||
print(f" • Chrome/Edge: Strg+Shift+Del → 'Alle Daten löschen'")
|
||||
print(f" • Firefox: Strg+Shift+Del → 'Alles' auswählen")
|
||||
print(f" 2. MYP-Anwendung neu starten")
|
||||
print(f" 3. https://localhost:5000 aufrufen")
|
||||
print(f" 4. Bei SSL-Warnung: 'Erweitert' → 'Unsicher fortfahren'")
|
||||
print(f"\n💡 Der Fehler ERR_SSL_KEY_USAGE_INCOMPATIBLE sollte behoben sein!")
|
||||
|
||||
else:
|
||||
print(f"\n❌ SSL-FIX FEHLGESCHLAGEN!")
|
||||
print(f" Keine Zertifikate konnten regeneriert werden")
|
||||
print(f" Prüfe die Logs und Berechtigungen")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"❌ SSL-Modul konnte nicht importiert werden: {e}")
|
||||
print(f"💡 Fallback: Manuelle Zertifikat-Regenerierung erforderlich")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Unerwarteter Fehler: {e}")
|
||||
return False
|
||||
|
||||
return success_count > 0
|
||||
|
||||
def validate_certificate_compatibility(cert_path):
|
||||
"""
|
||||
Validiert Browser-Kompatibilität eines Zertifikats (ohne OpenSSL)
|
||||
Vereinfachte Version die nur die Datei-Existenz prüft
|
||||
"""
|
||||
try:
|
||||
if not cert_path.exists():
|
||||
return False
|
||||
|
||||
# Lese Zertifikat-Inhalt
|
||||
with open(cert_path, 'r') as f:
|
||||
cert_content = f.read()
|
||||
|
||||
# Basis-Checks
|
||||
checks = {
|
||||
"PEM Format": cert_content.startswith("-----BEGIN CERTIFICATE-----"),
|
||||
"PEM Ende": cert_content.endswith("-----END CERTIFICATE-----\n") or cert_content.endswith("-----END CERTIFICATE-----"),
|
||||
"Mindestlänge": len(cert_content) > 500,
|
||||
}
|
||||
|
||||
print("📋 Zertifikat-Validation:")
|
||||
all_passed = True
|
||||
for check_name, passed in checks.items():
|
||||
status = "✅" if passed else "❌"
|
||||
print(f" {status} {check_name}")
|
||||
if not passed:
|
||||
all_passed = False
|
||||
|
||||
return all_passed
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Validation fehlgeschlagen: {e}")
|
||||
return False
|
||||
|
||||
def clean_browser_cache_instructions():
|
||||
"""Zeigt detaillierte Anweisungen zum Browser-Cache leeren"""
|
||||
|
||||
print("\n🧹 BROWSER-CACHE VOLLSTÄNDIG LEEREN")
|
||||
print("=" * 50)
|
||||
print("\n🌐 Google Chrome / Microsoft Edge:")
|
||||
print(" 1. Strg + Shift + Del drücken")
|
||||
print(" 2. Zeitraum: 'Gesamte Zeit' auswählen")
|
||||
print(" 3. Alle Optionen aktivieren:")
|
||||
print(" ☑️ Browserverlauf")
|
||||
print(" ☑️ Downloadverlauf")
|
||||
print(" ☑️ Cookies und andere Websitedaten")
|
||||
print(" ☑️ Bilder und Dateien im Cache")
|
||||
print(" ☑️ Gehostete App-Daten")
|
||||
print(" 4. 'Daten löschen' klicken")
|
||||
|
||||
print("\n🦊 Mozilla Firefox:")
|
||||
print(" 1. Strg + Shift + Del drücken")
|
||||
print(" 2. Zeitraum: 'Alles' auswählen")
|
||||
print(" 3. Alle Optionen aktivieren:")
|
||||
print(" ☑️ Chronik")
|
||||
print(" ☑️ Cookies")
|
||||
print(" ☑️ Cache")
|
||||
print(" ☑️ Aktive Logins")
|
||||
print(" ☑️ Offline-Website-Daten")
|
||||
print(" 4. 'Jetzt löschen' klicken")
|
||||
|
||||
print("\n🔄 Zusätzliche Schritte:")
|
||||
print(" • Browser komplett schließen und neu starten")
|
||||
print(" • Windows: Netzwerkadapter zurücksetzen")
|
||||
print(" ipconfig /flushdns")
|
||||
print(" • Bei Chrome: chrome://settings/certificates → Zwischenzertifikate löschen")
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion"""
|
||||
|
||||
print("🔧 MYP SSL BROWSER-KOMPATIBILITÄTS-FIX")
|
||||
print("Windows-kompatible Version")
|
||||
print("=" * 60)
|
||||
|
||||
# Prüfe aktuelles Verzeichnis
|
||||
if not Path("utils").exists():
|
||||
print("❌ utils-Verzeichnis nicht gefunden")
|
||||
print("💡 Führe das Skript im backend-Verzeichnis aus:")
|
||||
print(" cd backend")
|
||||
print(" python fix_ssl_browser.py")
|
||||
return False
|
||||
|
||||
# Führe SSL-Fix durch
|
||||
success = regenerate_ssl_certificates()
|
||||
|
||||
if success:
|
||||
print("\n" + "="*60)
|
||||
clean_browser_cache_instructions()
|
||||
print("\n" + "="*60)
|
||||
print("✅ SSL-Fix abgeschlossen!")
|
||||
print("🌐 ERR_SSL_KEY_USAGE_INCOMPATIBLE sollte behoben sein.")
|
||||
else:
|
||||
print("\n❌ SSL-Fix fehlgeschlagen!")
|
||||
print("📞 Weitere Hilfe in COMMON_ERRORS.md")
|
||||
|
||||
return success
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
1
backend/regenerate_ssl.bat
Normal file
1
backend/regenerate_ssl.bat
Normal file
@ -0,0 +1 @@
|
||||
|
221
backend/ssl_fix.py
Normal file
221
backend/ssl_fix.py
Normal file
@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SSL Fix Tool für MYP Platform - ERR_SSL_KEY_USAGE_INCOMPATIBLE Lösung
|
||||
Behebt Browser-SSL-Kompatibilitätsprobleme durch Neugenerierung korrekter Zertifikate
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
def create_browser_compatible_ssl():
|
||||
"""Erstellt browser-kompatible SSL-Zertifikate für MYP"""
|
||||
|
||||
print("🔧 SSL BROWSER-KOMPATIBILITÄTS-FIX")
|
||||
print("=" * 50)
|
||||
|
||||
# Basis-Verzeichnis
|
||||
app_dir = Path.cwd()
|
||||
ssl_dir = app_dir / "ssl"
|
||||
|
||||
# Erstelle SSL-Verzeichnis
|
||||
ssl_dir.mkdir(exist_ok=True)
|
||||
|
||||
cert_path = ssl_dir / "cert.pem"
|
||||
key_path = ssl_dir / "key.pem"
|
||||
config_path = ssl_dir / "openssl_fix.conf"
|
||||
|
||||
print(f"📁 SSL-Verzeichnis: {ssl_dir}")
|
||||
|
||||
# Browser-kompatible OpenSSL-Konfiguration
|
||||
openssl_config = """[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
prompt = no
|
||||
|
||||
[req_distinguished_name]
|
||||
C = DE
|
||||
ST = Baden-Wuerttemberg
|
||||
L = Stuttgart
|
||||
O = Mercedes-Benz AG
|
||||
OU = MYP Druckerverwaltung
|
||||
CN = m040tbaraspi001
|
||||
|
||||
[v3_req]
|
||||
# Basic Constraints - KRITISCH für Browser
|
||||
basicConstraints = critical, CA:FALSE
|
||||
|
||||
# Key Usage - KRITISCH für Browser-Kompatibilität
|
||||
keyUsage = critical, digitalSignature, keyEncipherment, keyAgreement
|
||||
|
||||
# Extended Key Usage - TLS Server Authentication
|
||||
extendedKeyUsage = critical, serverAuth, clientAuth
|
||||
|
||||
# Subject Alternative Names - Alle Domains/IPs
|
||||
subjectAltName = critical, @alt_names
|
||||
|
||||
# Netscape Legacy-Kompatibilität
|
||||
nsCertType = server
|
||||
|
||||
# Identifikations-Kommentar
|
||||
nsComment = "MYP SSL Fix - ERR_SSL_KEY_USAGE_INCOMPATIBLE Lösung"
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = localhost
|
||||
DNS.2 = *.localhost
|
||||
DNS.3 = m040tbaraspi001
|
||||
DNS.4 = m040tbaraspi001.local
|
||||
DNS.5 = m040tbaraspi001.de040.corpintra.net
|
||||
DNS.6 = *.de040.corpintra.net
|
||||
IP.1 = 127.0.0.1
|
||||
IP.2 = ::1
|
||||
IP.3 = 0.0.0.0
|
||||
"""
|
||||
|
||||
# Schreibe OpenSSL-Konfiguration
|
||||
with open(config_path, 'w') as f:
|
||||
f.write(openssl_config)
|
||||
|
||||
print("📝 OpenSSL-Konfiguration erstellt")
|
||||
|
||||
try:
|
||||
# Backup existierender Zertifikate
|
||||
if cert_path.exists():
|
||||
backup_cert = ssl_dir / f"cert_backup_{os.getpid()}.pem"
|
||||
backup_key = ssl_dir / f"key_backup_{os.getpid()}.pem"
|
||||
shutil.copy2(cert_path, backup_cert)
|
||||
shutil.copy2(key_path, backup_key)
|
||||
print(f"💾 Backup erstellt: {backup_cert}")
|
||||
|
||||
# Private Key generieren
|
||||
print("🔑 Generiere Private Key...")
|
||||
key_cmd = [
|
||||
"openssl", "genrsa",
|
||||
"-out", str(key_path),
|
||||
"2048"
|
||||
]
|
||||
|
||||
result = subprocess.run(key_cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise Exception(f"Private Key Generierung fehlgeschlagen: {result.stderr}")
|
||||
|
||||
print("✅ Private Key generiert")
|
||||
|
||||
# Browser-kompatibles Zertifikat erstellen
|
||||
print("📜 Generiere browser-kompatibles Zertifikat...")
|
||||
cert_cmd = [
|
||||
"openssl", "req",
|
||||
"-new", "-x509",
|
||||
"-key", str(key_path),
|
||||
"-out", str(cert_path),
|
||||
"-days", "365",
|
||||
"-config", str(config_path),
|
||||
"-extensions", "v3_req",
|
||||
"-sha256"
|
||||
]
|
||||
|
||||
result = subprocess.run(cert_cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise Exception(f"Zertifikat-Generierung fehlgeschlagen: {result.stderr}")
|
||||
|
||||
print("✅ Browser-kompatibles Zertifikat generiert")
|
||||
|
||||
# Berechtigungen setzen
|
||||
os.chmod(key_path, 0o600) # Nur Owner kann lesen
|
||||
os.chmod(cert_path, 0o644) # Alle können lesen
|
||||
|
||||
print("🔒 Berechtigungen gesetzt")
|
||||
|
||||
# Validierung
|
||||
print("🔍 Validiere Zertifikat...")
|
||||
|
||||
# Prüfe Key Usage Extensions
|
||||
check_cmd = ["openssl", "x509", "-in", str(cert_path), "-noout", "-text"]
|
||||
result = subprocess.run(check_cmd, capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
cert_text = result.stdout
|
||||
|
||||
# Browser-Kompatibilitäts-Checks
|
||||
checks = {
|
||||
"Digital Signature": "Digital Signature" in cert_text,
|
||||
"Key Encipherment": "Key Encipherment" in cert_text,
|
||||
"TLS Web Server Authentication": "TLS Web Server Authentication" in cert_text,
|
||||
"Subject Alternative Name": "Subject Alternative Name" in cert_text,
|
||||
"CA:FALSE": "CA:FALSE" in cert_text,
|
||||
"SHA-256": "sha256WithRSAEncryption" in cert_text
|
||||
}
|
||||
|
||||
print("\n📋 BROWSER-KOMPATIBILITÄTS-PRÜFUNG:")
|
||||
all_passed = True
|
||||
for check_name, passed in checks.items():
|
||||
status = "✅" if passed else "❌"
|
||||
print(f" {status} {check_name}")
|
||||
if not passed:
|
||||
all_passed = False
|
||||
|
||||
if all_passed:
|
||||
print("\n🎉 ALLE BROWSER-KOMPATIBILITÄTS-CHECKS BESTANDEN!")
|
||||
else:
|
||||
print("\n⚠️ Einige Checks fehlgeschlagen - Zertifikat kann trotzdem funktionieren")
|
||||
|
||||
# Aufräumen
|
||||
config_path.unlink(missing_ok=True)
|
||||
|
||||
print(f"\n📊 ERGEBNIS:")
|
||||
print(f" 📄 Zertifikat: {cert_path}")
|
||||
print(f" 🔑 Private Key: {key_path}")
|
||||
print(f" 📅 Gültig bis: {365} Tage")
|
||||
|
||||
print(f"\n🌐 NÄCHSTE SCHRITTE:")
|
||||
print(f" 1. Browser-Cache leeren (Strg+Shift+Del)")
|
||||
print(f" 2. MYP-Anwendung neu starten")
|
||||
print(f" 3. https://localhost:5000 aufrufen")
|
||||
print(f" 4. Bei SSL-Warnung: 'Erweitert' → 'Weiter zu localhost (unsicher)'")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ FEHLER: {e}")
|
||||
return False
|
||||
|
||||
def check_openssl():
|
||||
"""Prüft ob OpenSSL verfügbar ist"""
|
||||
try:
|
||||
result = subprocess.run(["openssl", "version"], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
print(f"✅ OpenSSL verfügbar: {result.stdout.strip()}")
|
||||
return True
|
||||
else:
|
||||
print("❌ OpenSSL nicht verfügbar")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
print("❌ OpenSSL nicht installiert")
|
||||
print("💡 Installiere mit: sudo apt install openssl")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion"""
|
||||
print("🔧 MYP SSL BROWSER-KOMPATIBILITÄTS-FIX")
|
||||
print("Löst ERR_SSL_KEY_USAGE_INCOMPATIBLE Fehler")
|
||||
print("=" * 60)
|
||||
|
||||
# Prüfe OpenSSL
|
||||
if not check_openssl():
|
||||
return False
|
||||
|
||||
# Erstelle browser-kompatible Zertifikate
|
||||
success = create_browser_compatible_ssl()
|
||||
|
||||
if success:
|
||||
print("\n✅ SSL-Fix erfolgreich abgeschlossen!")
|
||||
print("🌐 Browser-Fehler ERR_SSL_KEY_USAGE_INCOMPATIBLE sollte behoben sein.")
|
||||
else:
|
||||
print("\n❌ SSL-Fix fehlgeschlagen!")
|
||||
print("📞 Prüfe COMMON_ERRORS.md für weitere Hilfe.")
|
||||
|
||||
return success
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -73,7 +73,8 @@ class SSLCertificateManager:
|
||||
"-out", str(self.cert_file),
|
||||
"-days", "365",
|
||||
"-config", str(openssl_config),
|
||||
"-extensions", "v3_req"
|
||||
"-extensions", "v3_req",
|
||||
"-sha256"
|
||||
]
|
||||
|
||||
result = subprocess.run(cert_cmd, capture_output=True, text=True)
|
||||
|
484
backend/utils/ssl_fix.py
Normal file
484
backend/utils/ssl_fix.py
Normal file
@ -0,0 +1,484 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SSL Fix Tool für MYP Platform
|
||||
Behebt ERR_SSL_KEY_USAGE_INCOMPATIBLE Browser-Fehler durch Neugenerierung
|
||||
browser-kompatibler SSL-Zertifikate mit korrekten Key Usage Extensions.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import logging
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
# Logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class SSLBrowserFix:
|
||||
"""
|
||||
Behebt SSL-Browser-Kompatibilitätsprobleme durch Neugenerierung
|
||||
von Zertifikaten mit korrekten Extensions
|
||||
"""
|
||||
|
||||
def __init__(self, app_dir="/opt/myp"):
|
||||
self.app_dir = Path(app_dir)
|
||||
|
||||
# Verschiedene SSL-Pfade im System
|
||||
self.ssl_locations = [
|
||||
self.app_dir / "ssl",
|
||||
self.app_dir / "certs",
|
||||
self.app_dir / "certs" / "localhost",
|
||||
self.app_dir / "instance" / "ssl",
|
||||
Path("/etc/ssl/certs/myp")
|
||||
]
|
||||
|
||||
# Dateipfade für verschiedene Benennungskonventionen
|
||||
self.cert_names = ["cert.pem", "myp.crt", "localhost.crt", "server.crt"]
|
||||
self.key_names = ["key.pem", "myp.key", "localhost.key", "server.key"]
|
||||
|
||||
def find_existing_certificates(self):
|
||||
"""
|
||||
Findet alle existierenden SSL-Zertifikate im System
|
||||
|
||||
Returns:
|
||||
list: Liste von (cert_path, key_path) Tupeln
|
||||
"""
|
||||
found_certs = []
|
||||
|
||||
for ssl_dir in self.ssl_locations:
|
||||
if ssl_dir.exists():
|
||||
for cert_name in self.cert_names:
|
||||
for key_name in self.key_names:
|
||||
cert_path = ssl_dir / cert_name
|
||||
key_path = ssl_dir / key_name
|
||||
|
||||
if cert_path.exists() and key_path.exists():
|
||||
found_certs.append((cert_path, key_path))
|
||||
|
||||
return found_certs
|
||||
|
||||
def check_certificate_browser_compatibility(self, cert_path):
|
||||
"""
|
||||
Prüft ob ein Zertifikat browser-kompatibel ist
|
||||
|
||||
Args:
|
||||
cert_path: Pfad zum Zertifikat
|
||||
|
||||
Returns:
|
||||
dict: Kompatibilitätsbericht
|
||||
"""
|
||||
result = {
|
||||
'compatible': False,
|
||||
'issues': [],
|
||||
'details': {}
|
||||
}
|
||||
|
||||
try:
|
||||
# Zertifikat-Details extrahieren
|
||||
cmd = ["openssl", "x509", "-in", str(cert_path), "-noout", "-text"]
|
||||
proc = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
if proc.returncode != 0:
|
||||
result['issues'].append("Zertifikat kann nicht gelesen werden")
|
||||
return result
|
||||
|
||||
cert_text = proc.stdout
|
||||
|
||||
# Key Usage prüfen
|
||||
if "Digital Signature" in cert_text and "Key Encipherment" in cert_text:
|
||||
result['details']['key_usage'] = "✅ Korrekt"
|
||||
else:
|
||||
result['issues'].append("Key Usage fehlt: Digital Signature, Key Encipherment")
|
||||
result['details']['key_usage'] = "❌ Fehlerhaft"
|
||||
|
||||
# Extended Key Usage prüfen
|
||||
if "TLS Web Server Authentication" in cert_text:
|
||||
result['details']['extended_key_usage'] = "✅ Korrekt"
|
||||
else:
|
||||
result['issues'].append("Extended Key Usage fehlt: TLS Web Server Authentication")
|
||||
result['details']['extended_key_usage'] = "❌ Fehlerhaft"
|
||||
|
||||
# Subject Alternative Names prüfen
|
||||
if "Subject Alternative Name" in cert_text:
|
||||
result['details']['san'] = "✅ Vorhanden"
|
||||
else:
|
||||
result['issues'].append("Subject Alternative Names fehlen")
|
||||
result['details']['san'] = "❌ Fehlt"
|
||||
|
||||
# Basic Constraints prüfen
|
||||
if "CA:FALSE" in cert_text:
|
||||
result['details']['basic_constraints'] = "✅ Korrekt"
|
||||
else:
|
||||
result['issues'].append("Basic Constraints nicht gesetzt")
|
||||
result['details']['basic_constraints'] = "❌ Fehlerhaft"
|
||||
|
||||
# Signature Algorithm prüfen
|
||||
if "sha256WithRSAEncryption" in cert_text:
|
||||
result['details']['signature'] = "✅ SHA-256"
|
||||
elif "sha1WithRSAEncryption" in cert_text:
|
||||
result['issues'].append("Veraltete SHA-1 Signatur")
|
||||
result['details']['signature'] = "⚠️ SHA-1 (veraltet)"
|
||||
else:
|
||||
result['details']['signature'] = "❓ Unbekannt"
|
||||
|
||||
# Gültigkeit prüfen
|
||||
cmd = ["openssl", "x509", "-in", str(cert_path), "-noout", "-checkend", "86400"]
|
||||
proc = subprocess.run(cmd, capture_output=True)
|
||||
|
||||
if proc.returncode == 0:
|
||||
result['details']['validity'] = "✅ Gültig"
|
||||
else:
|
||||
result['issues'].append("Zertifikat ist abgelaufen oder läuft bald ab")
|
||||
result['details']['validity'] = "❌ Abgelaufen"
|
||||
|
||||
# Kompatibilität bewerten
|
||||
result['compatible'] = len(result['issues']) == 0
|
||||
|
||||
except Exception as e:
|
||||
result['issues'].append(f"Fehler bei Analyse: {e}")
|
||||
|
||||
return result
|
||||
|
||||
def create_browser_compatible_openssl_config(self, config_path):
|
||||
"""
|
||||
Erstellt OpenSSL-Konfiguration für browser-kompatible Zertifikate
|
||||
|
||||
Args:
|
||||
config_path: Pfad für die Konfigurationsdatei
|
||||
"""
|
||||
config_content = """[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
prompt = no
|
||||
|
||||
[req_distinguished_name]
|
||||
C = DE
|
||||
ST = Baden-Wuerttemberg
|
||||
L = Stuttgart
|
||||
O = Mercedes-Benz AG
|
||||
OU = MYP Druckerverwaltung
|
||||
CN = m040tbaraspi001
|
||||
|
||||
[v3_req]
|
||||
# Basic Constraints - Zertifikat ist NICHT eine CA
|
||||
basicConstraints = critical, CA:FALSE
|
||||
|
||||
# Key Usage - Kritisch für Browser-Kompatibilität
|
||||
keyUsage = critical, digitalSignature, keyEncipherment, keyAgreement
|
||||
|
||||
# Extended Key Usage - Definiert Verwendungszweck
|
||||
extendedKeyUsage = critical, serverAuth, clientAuth
|
||||
|
||||
# Subject Alternative Names - Alle unterstützten Domains/IPs
|
||||
subjectAltName = critical, @alt_names
|
||||
|
||||
# Netscape Zertifikat-Typ (Legacy-Kompatibilität)
|
||||
nsCertType = server
|
||||
|
||||
# Kommentar für Identifikation
|
||||
nsComment = "Browser-kompatibles MYP SSL-Zertifikat (ERR_SSL_KEY_USAGE_INCOMPATIBLE Fix)"
|
||||
|
||||
[alt_names]
|
||||
# Lokale Entwicklung
|
||||
DNS.1 = localhost
|
||||
DNS.2 = *.localhost
|
||||
IP.1 = 127.0.0.1
|
||||
IP.2 = ::1
|
||||
|
||||
# Produktions-Hostname
|
||||
DNS.3 = m040tbaraspi001
|
||||
DNS.4 = m040tbaraspi001.local
|
||||
|
||||
# Intranet-Domain
|
||||
DNS.5 = m040tbaraspi001.de040.corpintra.net
|
||||
DNS.6 = *.de040.corpintra.net
|
||||
|
||||
# Zusätzliche IPs
|
||||
IP.3 = 0.0.0.0
|
||||
"""
|
||||
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
f.write(config_content)
|
||||
|
||||
logger.info(f"OpenSSL-Konfiguration erstellt: {config_path}")
|
||||
|
||||
def generate_browser_compatible_certificate(self, cert_path, key_path, force=False):
|
||||
"""
|
||||
Generiert browser-kompatibles SSL-Zertifikat
|
||||
|
||||
Args:
|
||||
cert_path: Pfad für Zertifikat
|
||||
key_path: Pfad für Private Key
|
||||
force: Überschreibt existierende Dateien
|
||||
|
||||
Returns:
|
||||
bool: True wenn erfolgreich
|
||||
"""
|
||||
cert_path = Path(cert_path)
|
||||
key_path = Path(key_path)
|
||||
|
||||
# Prüfe ob bereits vorhanden
|
||||
if not force and cert_path.exists() and key_path.exists():
|
||||
logger.info("Zertifikat bereits vorhanden - verwende --force zum Überschreiben")
|
||||
return True
|
||||
|
||||
try:
|
||||
# Verzeichnis erstellen
|
||||
cert_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Temporäre OpenSSL-Konfiguration
|
||||
config_path = cert_path.parent / "openssl_temp.conf"
|
||||
self.create_browser_compatible_openssl_config(config_path)
|
||||
|
||||
logger.info("Generiere browser-kompatibles SSL-Zertifikat...")
|
||||
|
||||
# Private Key generieren (RSA 2048 für Performance)
|
||||
key_cmd = [
|
||||
"openssl", "genrsa",
|
||||
"-out", str(key_path),
|
||||
"2048"
|
||||
]
|
||||
|
||||
result = subprocess.run(key_cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
logger.error(f"Private Key Generierung fehlgeschlagen: {result.stderr}")
|
||||
return False
|
||||
|
||||
logger.info("✅ Private Key generiert")
|
||||
|
||||
# Browser-kompatibles Zertifikat erstellen
|
||||
cert_cmd = [
|
||||
"openssl", "req",
|
||||
"-new", "-x509",
|
||||
"-key", str(key_path),
|
||||
"-out", str(cert_path),
|
||||
"-days", "365",
|
||||
"-config", str(config_path),
|
||||
"-extensions", "v3_req",
|
||||
"-sha256" # SHA-256 Signatur für Sicherheit
|
||||
]
|
||||
|
||||
result = subprocess.run(cert_cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
logger.error(f"Zertifikat-Generierung fehlgeschlagen: {result.stderr}")
|
||||
return False
|
||||
|
||||
logger.info("✅ Browser-kompatibles Zertifikat generiert")
|
||||
|
||||
# Berechtigungen setzen
|
||||
os.chmod(key_path, 0o600) # Nur Besitzer kann lesen
|
||||
os.chmod(cert_path, 0o644) # Alle können lesen
|
||||
|
||||
# Aufräumen
|
||||
config_path.unlink(missing_ok=True)
|
||||
|
||||
# Validierung
|
||||
compatibility = self.check_certificate_browser_compatibility(cert_path)
|
||||
|
||||
if compatibility['compatible']:
|
||||
logger.info("✅ Zertifikat ist browser-kompatibel")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"⚠️ Zertifikat-Probleme: {compatibility['issues']}")
|
||||
return True # Trotzdem als Erfolg werten, da generiert
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei Zertifikat-Generierung: {e}")
|
||||
return False
|
||||
|
||||
def fix_all_certificates(self, force=False):
|
||||
"""
|
||||
Repariert alle gefundenen SSL-Zertifikate im System
|
||||
|
||||
Args:
|
||||
force: Erzwingt Neugenerierung auch bei gültigen Zertifikaten
|
||||
|
||||
Returns:
|
||||
dict: Bericht über durchgeführte Reparaturen
|
||||
"""
|
||||
report = {
|
||||
'fixed': [],
|
||||
'failed': [],
|
||||
'skipped': [],
|
||||
'total_found': 0
|
||||
}
|
||||
|
||||
# Finde existierende Zertifikate
|
||||
existing_certs = self.find_existing_certificates()
|
||||
report['total_found'] = len(existing_certs)
|
||||
|
||||
logger.info(f"Gefunden: {len(existing_certs)} SSL-Zertifikat-Paare")
|
||||
|
||||
if not existing_certs:
|
||||
# Erstelle Standard-Zertifikat in bevorzugtem Pfad
|
||||
default_ssl_dir = self.app_dir / "ssl"
|
||||
default_cert = default_ssl_dir / "cert.pem"
|
||||
default_key = default_ssl_dir / "key.pem"
|
||||
|
||||
if self.generate_browser_compatible_certificate(default_cert, default_key, force=True):
|
||||
report['fixed'].append((str(default_cert), str(default_key)))
|
||||
logger.info("✅ Standard-SSL-Zertifikat erstellt")
|
||||
else:
|
||||
report['failed'].append((str(default_cert), str(default_key)))
|
||||
logger.error("❌ Standard-SSL-Zertifikat Erstellung fehlgeschlagen")
|
||||
|
||||
# Repariere existierende Zertifikate
|
||||
for cert_path, key_path in existing_certs:
|
||||
logger.info(f"Prüfe Zertifikat: {cert_path}")
|
||||
|
||||
# Prüfe Browser-Kompatibilität
|
||||
compatibility = self.check_certificate_browser_compatibility(cert_path)
|
||||
|
||||
if not force and compatibility['compatible']:
|
||||
report['skipped'].append((str(cert_path), str(key_path)))
|
||||
logger.info(f"✅ Zertifikat ist bereits kompatibel: {cert_path}")
|
||||
continue
|
||||
|
||||
# Backup erstellen
|
||||
backup_cert = cert_path.parent / f"{cert_path.name}.backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
backup_key = key_path.parent / f"{key_path.name}.backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
|
||||
try:
|
||||
shutil.copy2(cert_path, backup_cert)
|
||||
shutil.copy2(key_path, backup_key)
|
||||
logger.info(f"Backup erstellt: {backup_cert}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Backup fehlgeschlagen: {e}")
|
||||
|
||||
# Regeneriere Zertifikat
|
||||
if self.generate_browser_compatible_certificate(cert_path, key_path, force=True):
|
||||
report['fixed'].append((str(cert_path), str(key_path)))
|
||||
logger.info(f"✅ Zertifikat repariert: {cert_path}")
|
||||
else:
|
||||
report['failed'].append((str(cert_path), str(key_path)))
|
||||
logger.error(f"❌ Zertifikat-Reparatur fehlgeschlagen: {cert_path}")
|
||||
|
||||
# Backup wiederherstellen
|
||||
try:
|
||||
shutil.copy2(backup_cert, cert_path)
|
||||
shutil.copy2(backup_key, key_path)
|
||||
logger.info("Backup wiederhergestellt")
|
||||
except Exception as e:
|
||||
logger.error(f"Backup-Wiederherstellung fehlgeschlagen: {e}")
|
||||
|
||||
return report
|
||||
|
||||
def diagnose_ssl_issues(self):
|
||||
"""
|
||||
Führt umfassende SSL-Diagnose durch
|
||||
|
||||
Returns:
|
||||
dict: Diagnosebericht
|
||||
"""
|
||||
diagnosis = {
|
||||
'certificates_found': [],
|
||||
'compatibility_issues': [],
|
||||
'recommendations': []
|
||||
}
|
||||
|
||||
logger.info("🔍 Führe SSL-Diagnose durch...")
|
||||
|
||||
# Finde alle Zertifikate
|
||||
existing_certs = self.find_existing_certificates()
|
||||
|
||||
for cert_path, key_path in existing_certs:
|
||||
cert_info = {
|
||||
'cert_path': str(cert_path),
|
||||
'key_path': str(key_path),
|
||||
'compatibility': self.check_certificate_browser_compatibility(cert_path)
|
||||
}
|
||||
|
||||
diagnosis['certificates_found'].append(cert_info)
|
||||
|
||||
if not cert_info['compatibility']['compatible']:
|
||||
diagnosis['compatibility_issues'].extend(cert_info['compatibility']['issues'])
|
||||
|
||||
# Empfehlungen generieren
|
||||
if not existing_certs:
|
||||
diagnosis['recommendations'].append("Kein SSL-Zertifikat gefunden - Erstelle neue Zertifikate")
|
||||
|
||||
if diagnosis['compatibility_issues']:
|
||||
diagnosis['recommendations'].append("Browser-Kompatibilitätsprobleme gefunden - Regeneriere Zertifikate")
|
||||
|
||||
if "ERR_SSL_KEY_USAGE_INCOMPATIBLE" in str(diagnosis['compatibility_issues']):
|
||||
diagnosis['recommendations'].append("Key Usage Extensions korrigieren")
|
||||
|
||||
return diagnosis
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion für Kommandozeilen-Nutzung"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="SSL Browser-Kompatibilitäts-Fix für MYP Platform")
|
||||
parser.add_argument("--app-dir", default="/opt/myp", help="MYP Anwendungsverzeichnis")
|
||||
parser.add_argument("--force", action="store_true", help="Erzwinge Neugenerierung aller Zertifikate")
|
||||
parser.add_argument("--diagnose", action="store_true", help="Nur Diagnose durchführen")
|
||||
parser.add_argument("--verbose", action="store_true", help="Ausführliche Ausgabe")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Logging konfigurieren
|
||||
level = logging.DEBUG if args.verbose else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=level,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# SSL-Fix ausführen
|
||||
ssl_fix = SSLBrowserFix(args.app_dir)
|
||||
|
||||
if args.diagnose:
|
||||
# Nur Diagnose
|
||||
diagnosis = ssl_fix.diagnose_ssl_issues()
|
||||
|
||||
print("\n🔍 SSL-DIAGNOSE BERICHT")
|
||||
print("=" * 50)
|
||||
|
||||
print(f"\n📋 Gefundene Zertifikate: {len(diagnosis['certificates_found'])}")
|
||||
for cert_info in diagnosis['certificates_found']:
|
||||
print(f" 📄 {cert_info['cert_path']}")
|
||||
print(f" Kompatibel: {'✅' if cert_info['compatibility']['compatible'] else '❌'}")
|
||||
for detail_key, detail_value in cert_info['compatibility']['details'].items():
|
||||
print(f" {detail_key}: {detail_value}")
|
||||
|
||||
if diagnosis['compatibility_issues']:
|
||||
print(f"\n⚠️ Probleme: {len(diagnosis['compatibility_issues'])}")
|
||||
for issue in set(diagnosis['compatibility_issues']):
|
||||
print(f" • {issue}")
|
||||
|
||||
if diagnosis['recommendations']:
|
||||
print(f"\n💡 Empfehlungen:")
|
||||
for rec in diagnosis['recommendations']:
|
||||
print(f" • {rec}")
|
||||
|
||||
else:
|
||||
# SSL-Zertifikate reparieren
|
||||
print("\n🔧 SSL BROWSER-KOMPATIBILITÄTS-FIX")
|
||||
print("=" * 50)
|
||||
|
||||
report = ssl_fix.fix_all_certificates(force=args.force)
|
||||
|
||||
print(f"\n📊 BERICHT:")
|
||||
print(f" Gefunden: {report['total_found']} Zertifikat-Paare")
|
||||
print(f" Repariert: {len(report['fixed'])}")
|
||||
print(f" Übersprungen: {len(report['skipped'])}")
|
||||
print(f" Fehlgeschlagen: {len(report['failed'])}")
|
||||
|
||||
if report['fixed']:
|
||||
print(f"\n✅ Reparierte Zertifikate:")
|
||||
for cert, key in report['fixed']:
|
||||
print(f" • {cert}")
|
||||
|
||||
if report['failed']:
|
||||
print(f"\n❌ Fehlgeschlagene Reparaturen:")
|
||||
for cert, key in report['failed']:
|
||||
print(f" • {cert}")
|
||||
|
||||
print(f"\n🌐 Nach der Reparatur:")
|
||||
print(f" 1. Browser-Cache leeren")
|
||||
print(f" 2. MYP-Anwendung neu starten")
|
||||
print(f" 3. https://localhost:5000 oder https://m040tbaraspi001.de040.corpintra.net aufrufen")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Reference in New Issue
Block a user