~~NOTOC~~
====== Scenario 4.4: Certificate and Key Backup ======
**Category:** [[.:start|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:
* **Disaster Recovery** - Restoration after system failure
* **Business Continuity** - Operational continuation
* **Compliance** - Audit requirements
* **Key Escrow** - Key custody
**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 |
----
===== Related Scenarios =====
^ Relationship ^ Scenario ^ Description ^
| **Next Step** | [[.:archivierung|4.3 Archival]] | Long-term retention |
| **Related** | [[en:int:pqcrypt:szenarien:schluessel:speicherung|11.2 Key Storage]] | Key storage |
| **Related** | [[en:int:pqcrypt:szenarien:importexport:pfx_export|12.2 PFX Export]] | Export format |
----
<< [[.:archivierung|← 4.3 Archival]] | [[.:start|↑ Management Overview]] | [[en:int:pqcrypt:szenarien:start|→ All Scenarios]] >>
{{tag>scenario management backup disaster-recovery pfx}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//