Szenario 8.4: Signatur verifizieren
Kategorie: Digitale Signaturen
Komplexität: ⭐⭐⭐ (Mittel)
Voraussetzungen: Signierte Daten, Signaturzertifikat
Geschätzte Zeit: 10-15 Minuten
Beschreibung
Dieses Szenario beschreibt die vollständige Verifikation digitaler Signaturen. Eine korrekte Verifikation umfasst:
- Signaturprüfung - Kryptographische Validierung
- Zertifikatsprüfung - Chain, Revocation, Gültigkeit
- Timestamp-Prüfung - Falls vorhanden
- Policy-Prüfung - Verwendungszweck
Workflow
flowchart TD
SIG[Signatur] --> CRYPTO[Krypto-Prüfung]
CRYPTO --> CERT[Zertifikat prüfen]
CERT --> CHAIN[Chain Building]
CHAIN --> REV[Revocation Check]
REV --> TIME[Zeitprüfung]
TIME --> TS{Timestamp?}
TS -->|Ja| TS_CHECK[Timestamp prüfen]
TS -->|Nein| POLICY[Policy prüfen]
TS_CHECK --> POLICY
POLICY --> RESULT{Alles OK?}
RESULT -->|Ja| VALID[Signatur GÜLTIG]
RESULT -->|Nein| INVALID[Signatur UNGÜLTIG]
style VALID fill:#e8f5e9
style INVALID fill:#ffebee
Code-Beispiel: Vollständige Verifikation
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography; using System.Security.Cryptography.Pkcs; using var ctx = PqCryptoContext.Initialize(); public class SignatureVerifier { public VerificationResult Verify( byte[] data, byte[] signature, X509Certificate2 signerCert, VerificationOptions options) { var result = new VerificationResult(); try { // 1. Kryptographische Signaturprüfung result.SignatureValid = ctx.VerifyData( data: data, signature: signature, certificate: signerCert, hashAlgorithm: options.HashAlgorithm, mode: options.CryptoMode ); if (!result.SignatureValid) { result.Error = "Kryptographische Signatur ungültig"; return result; } // 2. Zertifikatskette validieren var chain = new X509Chain(); ConfigureChainPolicy(chain.ChainPolicy, options); result.CertificateValid = chain.Build(signerCert); result.ChainStatus = chain.ChainStatus .Select(s => s.Status.ToString()) .ToList(); if (!result.CertificateValid) { result.Error = $"Zertifikat ungültig: {string.Join(", ", result.ChainStatus)}"; return result; } // 3. Extended Key Usage prüfen if (options.RequiredEku != null) { result.EkuValid = HasExtendedKeyUsage(signerCert, options.RequiredEku); if (!result.EkuValid) { result.Error = $"Erforderliche EKU ({options.RequiredEku}) fehlt"; return result; } } // 4. Signaturzeitpunkt prüfen var signatureTime = options.SignatureTime ?? DateTimeOffset.UtcNow; result.TimeValid = signatureTime >= signerCert.NotBefore && signatureTime <= signerCert.NotAfter; if (!result.TimeValid) { result.Error = "Zertifikat war zum Signaturzeitpunkt nicht gültig"; return result; } result.IsValid = true; result.SignerSubject = signerCert.Subject; result.SignatureTime = signatureTime; } catch (Exception ex) { result.IsValid = false; result.Error = ex.Message; } return result; } }
Code-Beispiel: CMS/PKCS#7 Signatur verifizieren
public VerificationResult VerifyCms(byte[] signedData, byte[]? originalContent = null) { var result = new VerificationResult(); try { // CMS parsen var signedCms = new SignedCms(); if (originalContent != null) { // Detached signature var contentInfo = new ContentInfo(originalContent); signedCms = new SignedCms(contentInfo, true); } signedCms.Decode(signedData); // Jede Signatur prüfen foreach (var signerInfo in signedCms.SignerInfos) { // Kryptographische Prüfung signerInfo.CheckSignature(verifySignatureOnly: false); // Signer-Zertifikat var cert = signerInfo.Certificate; result.SignerSubject = cert?.Subject; // Timestamp prüfen (falls vorhanden) var timestampAttr = signerInfo.UnsignedAttributes .Cast<CryptographicAttributeObject>() .FirstOrDefault(a => a.Oid.Value == "1.2.840.113549.1.9.16.2.14"); if (timestampAttr != null) { var tsToken = Rfc3161TimestampToken.Decode( timestampAttr.Values[0].RawData, out _); result.TimestampPresent = true; result.TimestampTime = tsToken.TokenInfo.Timestamp; // Timestamp validieren var signatureBytes = signerInfo.GetSignature(); var signatureHash = SHA256.HashData(signatureBytes); result.TimestampValid = tsToken.VerifySignatureForHash( signatureHash, HashAlgorithmName.SHA256, out _, extraCandidates: null ); } // Signing Time Attribut var signingTimeAttr = signerInfo.SignedAttributes .Cast<CryptographicAttributeObject>() .FirstOrDefault(a => a.Oid.Value == "1.2.840.113549.1.9.5"); if (signingTimeAttr != null) { var pkcs9Time = new Pkcs9SigningTime(signingTimeAttr.Values[0].RawData); result.SignatureTime = pkcs9Time.SigningTime; } } result.IsValid = true; result.SignatureValid = true; result.CertificateValid = true; } catch (CryptographicException ex) { result.IsValid = false; result.Error = ex.Message; } return result; }
Verifikationsergebnis
public class VerificationResult { public bool IsValid { get; set; } public bool SignatureValid { get; set; } public bool CertificateValid { get; set; } public bool TimeValid { get; set; } public bool EkuValid { get; set; } = true; public bool TimestampPresent { get; set; } public bool TimestampValid { get; set; } public string? SignerSubject { get; set; } public DateTimeOffset? SignatureTime { get; set; } public DateTimeOffset? TimestampTime { get; set; } public List<string> ChainStatus { get; set; } = new(); public string? Error { get; set; } public override string ToString() { var sb = new StringBuilder(); sb.AppendLine($"Signatur gültig: {IsValid}"); sb.AppendLine($" Krypto-Prüfung: {SignatureValid}"); sb.AppendLine($" Zertifikat: {CertificateValid}"); sb.AppendLine($" Zeitprüfung: {TimeValid}"); if (SignerSubject != null) sb.AppendLine($" Signer: {SignerSubject}"); if (SignatureTime.HasValue) sb.AppendLine($" Signaturzeit: {SignatureTime:yyyy-MM-dd HH:mm:ss}"); if (TimestampPresent) { sb.AppendLine($" Timestamp: {(TimestampValid ? "gültig" : "ungültig")}"); if (TimestampTime.HasValue) sb.AppendLine($" Timestamp-Zeit: {TimestampTime:yyyy-MM-dd HH:mm:ss}"); } if (Error != null) sb.AppendLine($" FEHLER: {Error}"); return sb.ToString(); } }
Batch-Verifikation
public class BatchVerifier { public async Task<Dictionary<string, VerificationResult>> VerifyDirectory( string directory, X509Certificate2Collection trustedCerts) { var results = new Dictionary<string, VerificationResult>(); var verifier = new SignatureVerifier(); // Alle .sig Dateien finden var sigFiles = Directory.GetFiles(directory, "*.sig", SearchOption.AllDirectories); foreach (var sigFile in sigFiles) { // Originaldatei finden var originalFile = sigFile.Replace(".sig", ""); if (!File.Exists(originalFile)) { results[sigFile] = new VerificationResult { IsValid = false, Error = "Originaldatei nicht gefunden" }; continue; } // Zertifikat finden var certFile = sigFile.Replace(".sig", ".crt"); X509Certificate2 signerCert; if (File.Exists(certFile)) { signerCert = new X509Certificate2(certFile); } else { // Aus Trusted Certs suchen (vereinfacht) signerCert = trustedCerts[0]; } // Verifizieren var data = await File.ReadAllBytesAsync(originalFile); var signature = await File.ReadAllBytesAsync(sigFile); results[sigFile] = verifier.Verify( data, signature, signerCert, new VerificationOptions { HashAlgorithm = HashAlgorithmName.SHA256, CryptoMode = CryptoMode.Hybrid } ); } return results; } }
Fehlercodes und Behebung
| Fehler | Ursache | Lösung |
|---|---|---|
| SignatureInvalid | Daten oder Signatur manipuliert | Originale prüfen |
| CertificateExpired | Zertifikat abgelaufen | Timestamp nutzen |
| CertificateRevoked | Zertifikat widerrufen | Neues Zertifikat |
| UntrustedRoot | Root nicht vertrauenswürdig | Trust Store prüfen |
| ChainIncomplete | Intermediate fehlt | Chain vervollständigen |
| TimestampInvalid | Timestamp-Signatur ungültig | TSA-Zertifikat prüfen |
Verwandte Szenarien
| Beziehung | Szenario | Beschreibung |
|---|---|---|
| Voraussetzung | 8.1 Dokument signieren | Signatur erstellen |
| Voraussetzung | 8.3 Zeitstempel | Timestamp hinzufügen |
| Verwandt | 5.2 Chain Validation | Zertifikatsprüfung |
« ← 8.3 Zeitstempel | ↑ Signaturen-Übersicht | → Alle Szenarien »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional
Zuletzt geändert: den 29.01.2026 um 15:13