Scenarij 4.3: Arhiviranje certifikatov

Kategorija: Upravljanje certifikatov
Kompleksnost: Srednja
Predpogoji: Potekli/preklicani certifikati
Ocenjeni čas: 15-20 minut


Opis

Ta scenarij opisuje varno arhiviranje certifikatov in pripadajočih ključev. Arhiviranje je potrebno za:

Pomembno: Šifrirni ključi morajo biti arhivirani, če še obstajajo podatki, šifrirani z njimi. Podpisni ključi NE smejo biti arhivirani (samo certifikati).


Potek dela

flowchart TD CERT[Certifikat potekel/preklican] --> CLASSIFY{Tip ključa?} CLASSIFY -->|Šifriranje| ARCHIVE_KEY[Arhiviranje ključa] CLASSIFY -->|Podpis| DESTROY_KEY[Uničenje ključa] ARCHIVE_KEY --> ENCRYPT[Šifrirano shranjevanje] DESTROY_KEY --> ARCHIVE_CERT[Samo arhiviranje certifikata] ENCRYPT --> STORE[Arhivska shramba] ARCHIVE_CERT --> STORE STORE --> LOG[Revizijski dnevnik] style ENCRYPT fill:#fff3e0 style STORE fill:#e8f5e9


Primer kode (C#)

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Nalaganje certifikatov za arhiviranje
var expiredCert = ctx.LoadCertificate("old-server.crt.pem");
var expiredKey = ctx.LoadPrivateKey("old-server.key.pem", "OldPassword!");
 
// Struktura arhiva
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<string, string>
    {
        ["Subject"] = expiredCert.Subject,
        ["SerialNumber"] = expiredCert.SerialNumber,
        ["NotBefore"] = expiredCert.NotBefore.ToString("O"),
        ["NotAfter"] = expiredCert.NotAfter.ToString("O"),
        ["Thumbprint"] = expiredCert.Thumbprint,
        ["KeyUsage"] = GetKeyUsageString(expiredCert)
    }
};
 
// Ključ arhiviraj samo pri šifrirnih certifikatih
if (HasKeyEncipherment(expiredCert))
{
    // Šifrirano shranjevanje ključa
    var encryptedKey = ctx.EncryptPrivateKey(
        expiredKey,
        archivePassword: "ArchivePassword!SecureVault2024",
        algorithm: PbeAlgorithm.Aes256Cbc,
        prf: PbePrf.HmacSha256,
        iterations: 100000
    );
    archive.EncryptedPrivateKey = encryptedKey;
}
 
// Arhiviranje kot JSON
var archivePath = $"archive/{expiredCert.SerialNumber}.json";
File.WriteAllText(archivePath, JsonSerializer.Serialize(archive, new JsonSerializerOptions
{
    WriteIndented = true
}));
 
// Revizijski dnevnik
Console.WriteLine($"Arhivirano: {expiredCert.Subject}");
Console.WriteLine($"  Serijska: {expiredCert.SerialNumber}");
Console.WriteLine($"  Iztek: {expiredCert.NotAfter:yyyy-MM-dd}");
Console.WriteLine($"  Arhiv: {archivePath}");
Console.WriteLine($"  Hramba do: {archive.RetentionUntil:yyyy-MM-dd}");

Podatkovna struktura arhiva

public class CertificateArchive
{
    public string Version { get; } = "1.0";
    public DateTime ArchivedAt { get; set; }
    public X509Certificate2 Certificate { get; set; }
    public byte[]? EncryptedPrivateKey { get; set; }  // Samo pri šifrirnih certifikatih
    public string OriginalPath { get; set; }
    public ArchiveReason Reason { get; set; }
    public DateTime RetentionUntil { get; set; }
    public Dictionary<string, string> Metadata { get; set; }
    public string? Notes { get; set; }
}
 
public enum ArchiveReason
{
    Expired,
    Revoked,
    Superseded,
    KeyCompromise,
    CessationOfOperation,
    PolicyChange
}

Panožne dobe hrambe

Panoga Predpis Doba hrambe Arhivirati ključ?
Finančni sektor GoBD 10 let Da (šifriranje)
Zdravstvo GDPR, PatArch 30 let Da (podatki pacientov)
Energetika EnWG, IT-SiG 10 let Da (merilni podatki)
Javni sektor Arhivski zakoni 30+ let Odvisno od vrste podatkov
Standardni IT GDPR 6 let Ne (samo certifikat)

Ustvarjanje arhivskega imenika

// Strukturiran arhivski imenik
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;
 
        // Certifikat (PEM)
        var certPath = Path.Combine(_basePath, "certificates", $"{year}", $"{serial}.crt.pem");
        Directory.CreateDirectory(Path.GetDirectoryName(certPath)!);
        archive.Certificate.ToPemFile(certPath);
 
        // Ključ (če obstaja)
        if (archive.EncryptedPrivateKey != null)
        {
            var keyPath = Path.Combine(_basePath, "keys", $"{year}", $"{serial}.key.enc");
            Directory.CreateDirectory(Path.GetDirectoryName(keyPath)!);
            File.WriteAllBytes(keyPath, archive.EncryptedPrivateKey);
        }
 
        // Metapodatki
        var metaPath = Path.Combine(_basePath, "metadata", $"{year}", $"{serial}.json");
        Directory.CreateDirectory(Path.GetDirectoryName(metaPath)!);
        File.WriteAllText(metaPath, JsonSerializer.Serialize(archive.Metadata));
    }
}

Iskanje po arhivu

// Iskanje arhiviranih certifikatov
public IEnumerable<CertificateArchive> 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<Dictionary<string, string>>(
            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);
    }
}

Povezani scenariji

Povezava Scenarij Opis
Predpogoj 4.4 Varnostna kopija Varnostna kopija pred arhiviranjem
Povezano 11.5 Uničenje ključev Brisanje podpisnih ključev
Povezano 6.4 Preklic Pred arhiviranjem

« ← 4.2 Ponovna izdaja | ↑ Pregled upravljanja | 4.4 Varnostna kopija → »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional