~~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//