~~NOTOC~~ ====== Szenario 4.3: Zertifikat-Archivierung ====== **Kategorie:** [[.:start|Zertifikate verwalten]] \\ **Komplexität:** ⭐⭐⭐ (Mittel) \\ **Voraussetzungen:** Abgelaufene/widerrufene Zertifikate \\ **Geschätzte Zeit:** 15-20 Minuten ---- ===== Beschreibung ===== Dieses Szenario beschreibt die **sichere Archivierung** von Zertifikaten und zugehörigen Schlüsseln. Archivierung ist notwendig für: * **Compliance-Aufbewahrungspflichten** (DSGVO, GoBD, NIS2) * **Forensische Nachverfolgbarkeit** * **Entschlüsselung historischer Daten** * **Audit-Nachweise** **Wichtig:** Verschlüsselungsschlüssel müssen archiviert werden, wenn damit verschlüsselte Daten noch existieren. Signaturschlüssel sollten NICHT archiviert werden (nur Zertifikate). ---- ===== Workflow ===== flowchart TD CERT[Zertifikat abgelaufen/widerrufen] --> CLASSIFY{Schlüsseltyp?} CLASSIFY -->|Verschlüsselung| ARCHIVE_KEY[Schlüssel archivieren] CLASSIFY -->|Signatur| DESTROY_KEY[Schlüssel vernichten] ARCHIVE_KEY --> ENCRYPT[Verschlüsselt speichern] DESTROY_KEY --> ARCHIVE_CERT[Nur Zertifikat archivieren] ENCRYPT --> STORE[Archiv-Storage] ARCHIVE_CERT --> STORE STORE --> LOG[Audit-Log] style ENCRYPT fill:#fff3e0 style STORE fill:#e8f5e9 ---- ===== Code-Beispiel (C#) ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using var ctx = PqCryptoContext.Initialize(); // Zu archivierende Zertifikate laden var expiredCert = ctx.LoadCertificate("old-server.crt.pem"); var expiredKey = ctx.LoadPrivateKey("old-server.key.pem", "OldPassword!"); // Archiv-Struktur var archive = new CertificateArchive { Certificate = expiredCert, ArchivedAt = DateTime.UtcNow, OriginalPath = "old-server.crt.pem", Reason = ArchiveReason.Expired, RetentionUntil = DateTime.UtcNow.AddYears(10), Metadata = new Dictionary { ["Subject"] = expiredCert.Subject, ["SerialNumber"] = expiredCert.SerialNumber, ["NotBefore"] = expiredCert.NotBefore.ToString("O"), ["NotAfter"] = expiredCert.NotAfter.ToString("O"), ["Thumbprint"] = expiredCert.Thumbprint, ["KeyUsage"] = GetKeyUsageString(expiredCert) } }; // Schlüssel nur bei Verschlüsselungszertifikaten archivieren if (HasKeyEncipherment(expiredCert)) { // Schlüssel verschlüsselt speichern var encryptedKey = ctx.EncryptPrivateKey( expiredKey, archivePassword: "ArchivePassword!SecureVault2024", algorithm: PbeAlgorithm.Aes256Cbc, prf: PbePrf.HmacSha256, iterations: 100000 ); archive.EncryptedPrivateKey = encryptedKey; } // Als JSON archivieren var archivePath = $"archive/{expiredCert.SerialNumber}.json"; File.WriteAllText(archivePath, JsonSerializer.Serialize(archive, new JsonSerializerOptions { WriteIndented = true })); // Audit-Log Console.WriteLine($"Archiviert: {expiredCert.Subject}"); Console.WriteLine($" Serial: {expiredCert.SerialNumber}"); Console.WriteLine($" Ablauf: {expiredCert.NotAfter:yyyy-MM-dd}"); Console.WriteLine($" Archiv: {archivePath}"); Console.WriteLine($" Aufbewahrung bis: {archive.RetentionUntil:yyyy-MM-dd}"); ---- ===== Archiv-Datenstruktur ===== public class CertificateArchive { public string Version { get; } = "1.0"; public DateTime ArchivedAt { get; set; } public X509Certificate2 Certificate { get; set; } public byte[]? EncryptedPrivateKey { get; set; } // Nur bei Encryption-Certs public string OriginalPath { get; set; } public ArchiveReason Reason { get; set; } public DateTime RetentionUntil { get; set; } public Dictionary Metadata { get; set; } public string? Notes { get; set; } } public enum ArchiveReason { Expired, Revoked, Superseded, KeyCompromise, CessationOfOperation, PolicyChange } ---- ===== Branchenspezifische Aufbewahrungsfristen ===== ^ Branche ^ Vorschrift ^ Aufbewahrungsfrist ^ Schlüssel archivieren? ^ | **Finanzsektor** | GoBD | 10 Jahre | Ja (Verschlüsselung) | | **Healthcare** | DSGVO, PatArch | 30 Jahre | Ja (Patientendaten) | | **Energie** | EnWG, IT-SiG | 10 Jahre | Ja (Mess-Daten) | | **Öffentlich** | Archivgesetze | 30+ Jahre | Je nach Datentyp | | **Standard IT** | DSGVO | 6 Jahre | Nein (nur Zertifikat) | ---- ===== Archiv-Verzeichnis anlegen ===== // Strukturiertes Archiv-Verzeichnis public class ArchiveDirectory { private readonly string _basePath; public ArchiveDirectory(string basePath) { _basePath = basePath; Directory.CreateDirectory(Path.Combine(basePath, "certificates")); Directory.CreateDirectory(Path.Combine(basePath, "keys")); Directory.CreateDirectory(Path.Combine(basePath, "metadata")); } public void Archive(CertificateArchive archive) { var serial = archive.Certificate.SerialNumber; var year = archive.Certificate.NotAfter.Year; // Zertifikat (PEM) var certPath = Path.Combine(_basePath, "certificates", $"{year}", $"{serial}.crt.pem"); Directory.CreateDirectory(Path.GetDirectoryName(certPath)!); archive.Certificate.ToPemFile(certPath); // Schlüssel (wenn vorhanden) if (archive.EncryptedPrivateKey != null) { var keyPath = Path.Combine(_basePath, "keys", $"{year}", $"{serial}.key.enc"); Directory.CreateDirectory(Path.GetDirectoryName(keyPath)!); File.WriteAllBytes(keyPath, archive.EncryptedPrivateKey); } // Metadaten var metaPath = Path.Combine(_basePath, "metadata", $"{year}", $"{serial}.json"); Directory.CreateDirectory(Path.GetDirectoryName(metaPath)!); File.WriteAllText(metaPath, JsonSerializer.Serialize(archive.Metadata)); } } ---- ===== Archiv-Suche ===== // Archivierte Zertifikate durchsuchen public IEnumerable SearchArchive( string basePath, string? subjectFilter = null, DateTime? expiredAfter = null) { var metadataFiles = Directory.GetFiles( Path.Combine(basePath, "metadata"), "*.json", SearchOption.AllDirectories ); foreach (var file in metadataFiles) { var metadata = JsonSerializer.Deserialize>( File.ReadAllText(file) ); if (subjectFilter != null && !metadata["Subject"].Contains(subjectFilter, StringComparison.OrdinalIgnoreCase)) continue; if (expiredAfter.HasValue && DateTime.Parse(metadata["NotAfter"]) < expiredAfter.Value) continue; var serial = Path.GetFileNameWithoutExtension(file); var year = Path.GetFileName(Path.GetDirectoryName(file)); yield return LoadArchive(basePath, year, serial); } } ---- ===== Verwandte Szenarien ===== ^ Beziehung ^ Szenario ^ Beschreibung ^ | **Voraussetzung** | [[.:backup|4.4 Backup]] | Vor Archivierung sichern | | **Verwandt** | [[de:int:pqcrypt:szenarien:schluessel:vernichtung|11.5 Schlüsselvernichtung]] | Signatur-Keys löschen | | **Verwandt** | [[de:int:pqcrypt:szenarien:widerruf:zertifikat_widerrufen|6.4 Widerrufen]] | Vor Archivierung | ---- << [[.:rekey|← 4.2 Rekey]] | [[.:start|↑ Verwaltung-Übersicht]] | [[.:backup|4.4 Backup →]] >> {{tag>szenario verwaltung archivierung compliance aufbewahrung}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//