Scenario 4.4: Backup certificati e chiavi

Categoria: Gestire certificati
Complessità: Alta
Prerequisiti: Certificati e chiavi esistenti
Tempo stimato: 20-30 minuti


Descrizione

Questo scenario descrive il backup sicuro di certificati, chiavi private e infrastruttura CA. Un concetto di backup corretto è critico per:

CRITICO: Le chiavi private sono il bene più prezioso! I backup devono:

  • Essere cifrati
  • Essere conservati offline
  • Essere protetti da accesso
  • Essere testati regolarmente

Workflow

flowchart TD START[Avviare backup] --> COLLECT[Raccogliere dati] COLLECT --> ENCRYPT[Cifrare] ENCRYPT --> SIGN[Firmare] SIGN --> STORE1[Storage primario] SIGN --> STORE2[Storage secondario] STORE1 --> VERIFY[Verificare] STORE2 --> VERIFY VERIFY --> LOG[Log audit] style ENCRYPT fill:#fff3e0 style STORE1 fill:#e8f5e9 style STORE2 fill:#e8f5e9


Esempio codice (C#)

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Configurazione backup
var backupConfig = new BackupConfiguration
{
    EncryptionPassword = "BackupPassword!Secure2024",
    OutputPath = "backup/",
    Timestamp = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss"),
    IncludeChain = true
};
 
// Caricare certificato e chiave CA
var caCert = ctx.LoadCertificate("root-ca.crt.pem");
var caKey = ctx.LoadPrivateKey("root-ca.key.pem", "CaPassword!");
 
// Creare PFX cifrato
var pfxData = ctx.ExportToPfx(
    certificate: caCert,
    privateKey: caKey,
    chain: null,  // Root non ha chain
    password: backupConfig.EncryptionPassword,
    friendlyName: $"Root-CA Backup {backupConfig.Timestamp}"
);
 
// File backup con metadati
var backupPath = Path.Combine(
    backupConfig.OutputPath,
    $"root-ca-backup-{backupConfig.Timestamp}.pfx"
);
 
Directory.CreateDirectory(backupConfig.OutputPath);
File.WriteAllBytes(backupPath, pfxData);
 
// Calcolare checksum
var checksum = ctx.ComputeSha256(pfxData);
var checksumPath = backupPath + ".sha256";
File.WriteAllText(checksumPath, Convert.ToHexString(checksum));
 
// Salvare metadati
var metadata = new BackupMetadata
{
    BackupDate = DateTime.UtcNow,
    Subject = caCert.Subject,
    SerialNumber = caCert.SerialNumber,
    NotAfter = caCert.NotAfter,
    Checksum = Convert.ToHexString(checksum),
    Algorithm = caCert.PublicKey.Oid.FriendlyName
};
 
var metadataPath = backupPath + ".meta.json";
File.WriteAllText(metadataPath, JsonSerializer.Serialize(metadata, new JsonSerializerOptions
{
    WriteIndented = true
}));
 
Console.WriteLine("Backup creato:");
Console.WriteLine($"  File: {backupPath}");
Console.WriteLine($"  SHA256: {metadata.Checksum}");
Console.WriteLine($"  Dimensione: {new FileInfo(backupPath).Length:N0} Bytes");

Backup completo CA

public class CaBackupManager
{
    public void CreateFullBackup(string caDirectory, string backupPassword, string outputPath)
    {
        var timestamp = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss");
        var backupDir = Path.Combine(outputPath, $"ca-backup-{timestamp}");
        Directory.CreateDirectory(backupDir);
 
        using var ctx = PqCryptoContext.Initialize();
 
        // 1. Root-CA
        BackupCertificateAndKey(ctx, caDirectory, "root-ca", backupDir, backupPassword);
 
        // 2. Tutte le Intermediate-CA
        foreach (var intCaDir in Directory.GetDirectories(caDirectory, "intermediate-*"))
        {
            var name = Path.GetFileName(intCaDir);
            BackupCertificateAndKey(ctx, intCaDir, name, backupDir, backupPassword);
        }
 
        // 3. File CRL
        var crlDir = Path.Combine(backupDir, "crls");
        Directory.CreateDirectory(crlDir);
        foreach (var crl in Directory.GetFiles(caDirectory, "*.crl", SearchOption.AllDirectories))
        {
            File.Copy(crl, Path.Combine(crlDir, Path.GetFileName(crl)));
        }
 
        // 4. File di configurazione
        var configDir = Path.Combine(backupDir, "config");
        Directory.CreateDirectory(configDir);
        foreach (var config in Directory.GetFiles(caDirectory, "*.json"))
        {
            File.Copy(config, Path.Combine(configDir, Path.GetFileName(config)));
        }
 
        // 5. Creare manifest
        CreateBackupManifest(backupDir, timestamp);
 
        Console.WriteLine($"Backup completo CA creato: {backupDir}");
    }
 
    private void BackupCertificateAndKey(
        PqCryptoContext ctx,
        string sourceDir,
        string name,
        string backupDir,
        string password)
    {
        var certPath = Path.Combine(sourceDir, $"{name}.crt.pem");
        var keyPath = Path.Combine(sourceDir, $"{name}.key.pem");
 
        if (!File.Exists(certPath)) return;
 
        var cert = ctx.LoadCertificate(certPath);
 
        // Certificato in chiaro (PEM)
        var certBackup = Path.Combine(backupDir, "certs", $"{name}.crt.pem");
        Directory.CreateDirectory(Path.GetDirectoryName(certBackup)!);
        cert.ToPemFile(certBackup);
 
        // Chiave cifrata (se presente)
        if (File.Exists(keyPath))
        {
            // Cifrare chiave con nuova password
            var key = ctx.LoadPrivateKey(keyPath, "OriginalPassword!");  // Adattare!
            var keyBackup = Path.Combine(backupDir, "keys", $"{name}.key.pem.enc");
            Directory.CreateDirectory(Path.GetDirectoryName(keyBackup)!);
            key.ToEncryptedPemFile(keyBackup, password);
        }
    }
 
    private void CreateBackupManifest(string backupDir, string timestamp)
    {
        var manifest = new
        {
            Version = "1.0",
            Timestamp = timestamp,
            CreatedAt = DateTime.UtcNow,
            Contents = new
            {
                Certificates = Directory.GetFiles(Path.Combine(backupDir, "certs"), "*.pem").Length,
                Keys = Directory.GetFiles(Path.Combine(backupDir, "keys"), "*.enc").Length,
                CRLs = Directory.GetFiles(Path.Combine(backupDir, "crls"), "*.crl").Length,
                Configs = Directory.GetFiles(Path.Combine(backupDir, "config"), "*.json").Length
            }
        };
 
        var manifestPath = Path.Combine(backupDir, "MANIFEST.json");
        File.WriteAllText(manifestPath, JsonSerializer.Serialize(manifest, new JsonSerializerOptions
        {
            WriteIndented = true
        }));
    }
}

Verifica backup

public bool VerifyBackup(string backupPath, string password)
{
    using var ctx = PqCryptoContext.Initialize();
 
    // 1. Verificare checksum
    var expectedChecksum = File.ReadAllText(backupPath + ".sha256");
    var actualData = File.ReadAllBytes(backupPath);
    var actualChecksum = Convert.ToHexString(ctx.ComputeSha256(actualData));
 
    if (expectedChecksum != actualChecksum)
    {
        Console.WriteLine("ERRORE: Checksum non corrispondente!");
        return false;
    }
 
    // 2. Caricare PFX (testa password e integrità)
    try
    {
        var (cert, key) = ctx.ImportFromPfx(actualData, password);
        Console.WriteLine($"Backup OK: {cert.Subject}");
        Console.WriteLine($"  Valido fino a: {cert.NotAfter:yyyy-MM-dd}");
        Console.WriteLine($"  Chiave: {(key != null ? "Presente" : "Mancante")}");
        return true;
    }
    catch (CryptographicException ex)
    {
        Console.WriteLine($"ERRORE: {ex.Message}");
        return false;
    }
}

Requisiti backup specifici per settore

Settore Normativa Frequenza backup Conservazione Particolarità
Settore finanziario MaRisk Giornaliera 10 anni Georidondanza obbligatoria
Sanità GDPR Giornaliera 30 anni Storage air-gap
Energia KRITIS-VO Settimanale 10 anni Supporti offline
Automotive UNECE R155 Mensile Vita veicolo Recovery OTA

Strategia backup 3-2-1

Regola 3-2-1:

  • 3 copie dei dati
  • 2 tipi di supporti diversi
  • 1 copia off-site
Copia Supporto Luogo Scopo
——-———-——-——-
1 Server-Storage Data center Operativo
2 Tape/NAS Edificio B Disaster Recovery
3 Cloud (cifrato) Altra sede Georidondanza

Scenari correlati

Relazione Scenario Descrizione
Passo successivo 4.3 Archiviazione Conservazione a lungo termine
Correlato 11.2 Storage chiavi Key Storage
Correlato 12.2 Export PFX Formato export

« ← 4.3 Archiviazione | ↑ Panoramica gestione | → Tutti gli scenari »


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