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