Scenarij 8.4: Verifikacija podpisa

Kategorija: Digitalni podpisi
Kompleksnost: ⭐⭐⭐ (Srednja)
Predpogoji: Podpisani podatki, certifikat podpisnika
Predviden čas: 10-15 minut


Opis

Ta scenarij opisuje popolno verifikacijo digitalnih podpisov. Pravilna verifikacija vključuje:

  • Preverjanje podpisa - Kriptografska validacija
  • Preverjanje certifikata - Veriga, preklic, veljavnost
  • Preverjanje časovnega žiga - Če je prisoten
  • Preverjanje politike - Namen uporabe

Potek dela

flowchart TD SIG[Podpis] --> CRYPTO[Kriptografsko preverjanje] CRYPTO --> CERT[Preverjanje certifikata] CERT --> CHAIN[Gradnja verige] CHAIN --> REV[Preverjanje preklica] REV --> TIME[Časovno preverjanje] TIME --> TS{Časovni žig?} TS -->|Da| TS_CHECK[Preverjanje časovnega žiga] TS -->|Ne| POLICY[Preverjanje politike] TS_CHECK --> POLICY POLICY --> RESULT{Vse v redu?} RESULT -->|Da| VALID[Podpis VELJAVEN] RESULT -->|Ne| INVALID[Podpis NEVELJAVEN] style VALID fill:#e8f5e9 style INVALID fill:#ffebee


Primer kode: Popolna verifikacija

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. Kriptografsko preverjanje podpisa
            result.SignatureValid = ctx.VerifyData(
                data: data,
                signature: signature,
                certificate: signerCert,
                hashAlgorithm: options.HashAlgorithm,
                mode: options.CryptoMode
            );
 
            if (!result.SignatureValid)
            {
                result.Error = "Kriptografski podpis neveljaven";
                return result;
            }
 
            // 2. Validacija verige certifikatov
            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 = $"Certifikat neveljaven: {string.Join(", ", result.ChainStatus)}";
                return result;
            }
 
            // 3. Preverjanje razširjene uporabe ključa
            if (options.RequiredEku != null)
            {
                result.EkuValid = HasExtendedKeyUsage(signerCert, options.RequiredEku);
                if (!result.EkuValid)
                {
                    result.Error = $"Zahtevana EKU ({options.RequiredEku}) manjka";
                    return result;
                }
            }
 
            // 4. Preverjanje časa podpisa
            var signatureTime = options.SignatureTime ?? DateTimeOffset.UtcNow;
            result.TimeValid = signatureTime >= signerCert.NotBefore &&
                               signatureTime <= signerCert.NotAfter;
 
            if (!result.TimeValid)
            {
                result.Error = "Certifikat ob času podpisa ni bil veljaven";
                return result;
            }
 
            result.IsValid = true;
            result.SignerSubject = signerCert.Subject;
            result.SignatureTime = signatureTime;
        }
        catch (Exception ex)
        {
            result.IsValid = false;
            result.Error = ex.Message;
        }
 
        return result;
    }
}

Primer kode: Verifikacija CMS/PKCS#7 podpisa

public VerificationResult VerifyCms(byte[] signedData, byte[]? originalContent = null)
{
    var result = new VerificationResult();
 
    try
    {
        // Razčlenjevanje CMS
        var signedCms = new SignedCms();
 
        if (originalContent != null)
        {
            // Ločen podpis
            var contentInfo = new ContentInfo(originalContent);
            signedCms = new SignedCms(contentInfo, true);
        }
 
        signedCms.Decode(signedData);
 
        // Preverjanje vsakega podpisa
        foreach (var signerInfo in signedCms.SignerInfos)
        {
            // Kriptografsko preverjanje
            signerInfo.CheckSignature(verifySignatureOnly: false);
 
            // Certifikat podpisnika
            var cert = signerInfo.Certificate;
            result.SignerSubject = cert?.Subject;
 
            // Preverjanje časovnega žiga (če obstaja)
            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;
 
                // Validacija časovnega žiga
                var signatureBytes = signerInfo.GetSignature();
                var signatureHash = SHA256.HashData(signatureBytes);
 
                result.TimestampValid = tsToken.VerifySignatureForHash(
                    signatureHash,
                    HashAlgorithmName.SHA256,
                    out _,
                    extraCandidates: null
                );
            }
 
            // Atribut časa podpisa
            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;
}

Rezultat verifikacije

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($"Podpis veljaven: {IsValid}");
        sb.AppendLine($"  Kriptografsko preverjanje: {SignatureValid}");
        sb.AppendLine($"  Certifikat: {CertificateValid}");
        sb.AppendLine($"  Časovno preverjanje: {TimeValid}");
 
        if (SignerSubject != null)
            sb.AppendLine($"  Podpisnik: {SignerSubject}");
 
        if (SignatureTime.HasValue)
            sb.AppendLine($"  Čas podpisa: {SignatureTime:yyyy-MM-dd HH:mm:ss}");
 
        if (TimestampPresent)
        {
            sb.AppendLine($"  Časovni žig: {(TimestampValid ? "veljaven" : "neveljaven")}");
            if (TimestampTime.HasValue)
                sb.AppendLine($"  Čas časovnega žiga: {TimestampTime:yyyy-MM-dd HH:mm:ss}");
        }
 
        if (Error != null)
            sb.AppendLine($"  NAPAKA: {Error}");
 
        return sb.ToString();
    }
}

Paketna verifikacija

public class BatchVerifier
{
    public async Task<Dictionary<string, VerificationResult>> VerifyDirectory(
        string directory,
        X509Certificate2Collection trustedCerts)
    {
        var results = new Dictionary<string, VerificationResult>();
        var verifier = new SignatureVerifier();
 
        // Iskanje vseh .sig datotek
        var sigFiles = Directory.GetFiles(directory, "*.sig", SearchOption.AllDirectories);
 
        foreach (var sigFile in sigFiles)
        {
            // Iskanje izvorne datoteke
            var originalFile = sigFile.Replace(".sig", "");
            if (!File.Exists(originalFile))
            {
                results[sigFile] = new VerificationResult
                {
                    IsValid = false,
                    Error = "Izvorna datoteka ni najdena"
                };
                continue;
            }
 
            // Iskanje certifikata
            var certFile = sigFile.Replace(".sig", ".crt");
            X509Certificate2 signerCert;
 
            if (File.Exists(certFile))
            {
                signerCert = new X509Certificate2(certFile);
            }
            else
            {
                // Iskanje med zaupanja vrednimi certifikati (poenostavljeno)
                signerCert = trustedCerts[0];
            }
 
            // Verifikacija
            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;
    }
}

Kode napak in odprava

Napaka Vzrok Rešitev
SignatureInvalid Podatki ali podpis spremenjen Preverjanje izvirnikov
CertificateExpired Certifikat potekel Uporaba časovnega žiga
CertificateRevoked Certifikat preklican Nov certifikat
UntrustedRoot Korenski certifikat ni zaupanja vreden Preverjanje shrambe zaupanja
ChainIncomplete Vmesni certifikat manjka Dopolnitev verige
TimestampInvalid Podpis časovnega žiga neveljaven Preverjanje TSA certifikata

Povezani scenariji

Povezava Scenarij Opis
Predpogoj 8.1 Podpisovanje dokumentov Ustvarjanje podpisa
Predpogoj 8.3 Časovni žig Dodajanje časovnega žiga
Povezano 5.2 Validacija verige Preverjanje certifikatov

« ← 8.3 Časovni žig | ↑ Pregled podpisov | → Vsi scenariji »


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

Zuletzt geändert: dne 30.01.2026 ob 06:42