Scenario 11.3: Key Rotation

Category: Key Management
Complexity: ⭐⭐⭐⭐ (High)
Prerequisites: Existing keys, backup strategy
Estimated Time: 30-45 Minutes


Description

This scenario describes the regular rotation of cryptographic keys. Key rotation is a critical security measure that limits the risk of compromise.

Rotation Reasons:


Workflow

flowchart TD TRIGGER[Rotation Trigger] --> CHECK{Rotation needed?} CHECK -->|No| WAIT[Wait] CHECK -->|Yes| BACKUP[Backup old key] BACKUP --> GEN[Generate new key] GEN --> MIGRATE[Migrate systems] MIGRATE --> TEST[Function test] TEST --> OVERLAP{Overlap OK?} OVERLAP -->|Yes| RETIRE[Deactivate old key] OVERLAP -->|No| ROLLBACK[Rollback] RETIRE --> ARCHIVE[Archive/Delete] style GEN fill:#e8f5e9 style BACKUP fill:#fff3e0


Code Example: Automatic Rotation

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
public class KeyRotationService
{
    private readonly IKeyStore _keyStore;
    private readonly TimeSpan _maxKeyAge = TimeSpan.FromDays(365);
    private readonly long _maxOperations = 1_000_000;
 
    public KeyRotationService(IKeyStore keyStore)
    {
        _keyStore = keyStore;
    }
 
    public async Task<RotationResult> CheckAndRotateAsync(string keyId)
    {
        var metadata = await _keyStore.GetMetadataAsync(keyId);
 
        // Check rotation conditions
        var needsRotation = ShouldRotate(metadata);
 
        if (!needsRotation.Required)
        {
            return new RotationResult
            {
                KeyId = keyId,
                Rotated = false,
                Reason = "No rotation required"
            };
        }
 
        return await PerformRotationAsync(keyId, metadata, needsRotation.Reason);
    }
 
    private RotationCheck ShouldRotate(KeyMetadata metadata)
    {
        // 1. Time-based rotation
        if (DateTime.UtcNow - metadata.CreatedAt > _maxKeyAge)
        {
            return new RotationCheck(true, "Maximum age reached");
        }
 
        // 2. Usage-based rotation
        if (metadata.OperationCount > _maxOperations)
        {
            return new RotationCheck(true, "Maximum operations reached");
        }
 
        // 3. Algorithm upgrade (RSA → ML-DSA)
        if (metadata.Algorithm.StartsWith("RSA") && !metadata.Algorithm.Contains("ML-DSA"))
        {
            return new RotationCheck(true, "PQ migration required");
        }
 
        return new RotationCheck(false, null);
    }
 
    private async Task<RotationResult> PerformRotationAsync(
        string keyId,
        KeyMetadata oldMetadata,
        string reason)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // 1. Backup old key
        await _keyStore.BackupAsync(keyId);
 
        // 2. Generate new key
        var newKeyId = $"{keyId}-{DateTime.UtcNow:yyyyMMdd}";
        using var newKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
        // 3. Store new key
        await _keyStore.StoreAsync(newKeyId, newKey, new KeyMetadata
        {
            Algorithm = "ML-DSA-65",
            CreatedAt = DateTime.UtcNow,
            PreviousKeyId = keyId,
            RotationReason = reason
        });
 
        // 4. Mark old key as "rotating"
        await _keyStore.SetStatusAsync(keyId, KeyStatus.Rotating);
 
        return new RotationResult
        {
            KeyId = keyId,
            NewKeyId = newKeyId,
            Rotated = true,
            Reason = reason
        };
    }
}

Code Example: Overlap Phase

public class OverlappingKeyManager
{
    public async Task<byte[]> SignWithOverlap(
        byte[] data,
        string keyId,
        IKeyStore keyStore)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Load current key
        var currentKey = await keyStore.GetCurrentKeyAsync(keyId);
 
        // Sign with current key
        var signature = ctx.SignData(
            data,
            currentKey,
            HashAlgorithmName.SHA256
        );
 
        return signature;
    }
 
    public async Task<bool> VerifyWithOverlap(
        byte[] data,
        byte[] signature,
        string keyId,
        IKeyStore keyStore)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Get all valid key versions
        var validKeys = await keyStore.GetValidKeysAsync(keyId);
 
        foreach (var key in validKeys)
        {
            try
            {
                if (ctx.VerifyData(data, signature, key.PublicKey, HashAlgorithmName.SHA256))
                {
                    return true;
                }
            }
            catch (CryptographicException)
            {
                // Wrong key, try next
                continue;
            }
        }
 
        return false;
    }
}

Rotation Policies

Key Type Maximum Age Maximum Operations Overlap
Root CA Key 10-20 years N/A 1 year
Intermediate CA Key 3-5 years N/A 90 days
TLS Server Key 1 year 10M handshakes 7 days
Code Signing Key 2 years 100K signatures 30 days
Encryption Key 1 year 100TB data 30 days

Industry-Specific Rotation Requirements

Industry Rotation Cycle Requirement Specifics
Financial Sector 1 year PCI-DSS 3.6.4 Audit trail mandatory
Healthcare 2 years HIPAA Key escrow
Energy/KRITIS 3 years BSI KRITIS-VO Maintenance window
Government 2 years BSI TR-03116 HSM mandatory

Relationship Scenario Description
Prerequisite 11.2 Key Storage Secure storage
Prerequisite 11.4 Key Backup Backup before rotation
Next Step 11.5 Key Destruction Delete old keys
Related 4.2 Rekey Certificate with new key

« ← 11.2 Key Storage | ↑ Key Overview | 11.4 Key Backup → »


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