Scenario 4.4: Certificate and Key Backup

Category: Certificate Management
Complexity: ⭐⭐⭐⭐ (High)
Prerequisites: Certificates and keys available
Estimated Time: 20-30 Minutes


Description

This scenario describes the secure backup of certificates, private keys, and CA infrastructure. A proper backup concept is critical for:

CRITICAL: Private keys are the most valuable asset! Backups must be:

  • Encrypted
  • Stored offline
  • Access protected
  • Regularly tested

Workflow

flowchart TD START[Initiate Backup] --> COLLECT[Collect Data] COLLECT --> ENCRYPT[Encrypt] ENCRYPT --> SIGN[Sign] SIGN --> STORE1[Primary Storage] SIGN --> STORE2[Secondary Storage] STORE1 --> VERIFY[Verify] STORE2 --> VERIFY VERIFY --> LOG[Audit Log] style ENCRYPT fill:#fff3e0 style STORE1 fill:#e8f5e9 style STORE2 fill:#e8f5e9


Code Example (C#)

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Backup configuration
var backupConfig = new BackupConfiguration
{
    EncryptionPassword = "BackupPassword!Secure2024",
    OutputPath = "backup/",
    Timestamp = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss"),
    IncludeChain = true
};
 
// Load CA certificate and key
var caCert = ctx.LoadCertificate("root-ca.crt.pem");
var caKey = ctx.LoadPrivateKey("root-ca.key.pem", "CaPassword!");
 
// Create encrypted PFX
var pfxData = ctx.ExportToPfx(
    certificate: caCert,
    privateKey: caKey,
    chain: null,  // Root has no chain
    password: backupConfig.EncryptionPassword,
    friendlyName: $"Root-CA Backup {backupConfig.Timestamp}"
);
 
// Backup file with metadata
var backupPath = Path.Combine(
    backupConfig.OutputPath,
    $"root-ca-backup-{backupConfig.Timestamp}.pfx"
);
 
Directory.CreateDirectory(backupConfig.OutputPath);
File.WriteAllBytes(backupPath, pfxData);
 
// Calculate checksum
var checksum = ctx.ComputeSha256(pfxData);
var checksumPath = backupPath + ".sha256";
File.WriteAllText(checksumPath, Convert.ToHexString(checksum));
 
// Save metadata
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 created:");
Console.WriteLine($"  File: {backupPath}");
Console.WriteLine($"  SHA256: {metadata.Checksum}");
Console.WriteLine($"  Size: {new FileInfo(backupPath).Length:N0} Bytes");

Complete CA Backup

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. All Intermediate CAs
        foreach (var intCaDir in Directory.GetDirectories(caDirectory, "intermediate-*"))
        {
            var name = Path.GetFileName(intCaDir);
            BackupCertificateAndKey(ctx, intCaDir, name, backupDir, backupPassword);
        }
 
        // 3. CRL files
        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. Configuration files
        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. Create manifest
        CreateBackupManifest(backupDir, timestamp);
 
        Console.WriteLine($"Complete CA backup created: {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);
 
        // Certificate in cleartext (PEM)
        var certBackup = Path.Combine(backupDir, "certs", $"{name}.crt.pem");
        Directory.CreateDirectory(Path.GetDirectoryName(certBackup)!);
        cert.ToPemFile(certBackup);
 
        // Key encrypted (if present)
        if (File.Exists(keyPath))
        {
            // Encrypt key with new password
            var key = ctx.LoadPrivateKey(keyPath, "OriginalPassword!");  // Adjust!
            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
        }));
    }
}

Backup Verification

public bool VerifyBackup(string backupPath, string password)
{
    using var ctx = PqCryptoContext.Initialize();
 
    // 1. Verify checksum
    var expectedChecksum = File.ReadAllText(backupPath + ".sha256");
    var actualData = File.ReadAllBytes(backupPath);
    var actualChecksum = Convert.ToHexString(ctx.ComputeSha256(actualData));
 
    if (expectedChecksum != actualChecksum)
    {
        Console.WriteLine("ERROR: Checksum mismatch!");
        return false;
    }
 
    // 2. Load PFX (tests password and integrity)
    try
    {
        var (cert, key) = ctx.ImportFromPfx(actualData, password);
        Console.WriteLine($"Backup OK: {cert.Subject}");
        Console.WriteLine($"  Valid until: {cert.NotAfter:yyyy-MM-dd}");
        Console.WriteLine($"  Key: {(key != null ? "Present" : "Missing")}");
        return true;
    }
    catch (CryptographicException ex)
    {
        Console.WriteLine($"ERROR: {ex.Message}");
        return false;
    }
}

Industry-Specific Backup Requirements

Industry Regulation Backup Frequency Retention Special Feature
Financial Sector MaRisk Daily 10 years Geo-redundancy mandatory
Healthcare GDPR Daily 30 years Air-gap storage
Energy KRITIS-VO Weekly 10 years Offline media
Automotive UNECE R155 Monthly Vehicle lifetime OTA recovery

Backup Strategy 3-2-1

3-2-1 Rule:

  • 3 copies of data
  • 2 different media types
  • 1 copy off-site
Copy Medium Location Purpose
——-——–—–——-
1 Server storage Data center Operational
2 Tape/NAS Building B Disaster recovery
3 Cloud (encrypted) Different location Geo-redundancy

Relationship Scenario Description
Next Step 4.3 Archival Long-term retention
Related 11.2 Key Storage Key storage
Related 12.2 PFX Export Export format

« ← 4.3 Archival | ↑ Management Overview | → All Scenarios »


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