~~NOTOC~~
====== Scenarij 8.4: Verifikacija potpisa ======
**Kategorija:** [[.:start|Digitalni potpisi]] \\
**Složenost:** ⭐⭐⭐ (Srednja) \\
**Preduvjeti:** Potpisani podaci, certifikat za potpis \\
**Procijenjeno vrijeme:** 10-15 minuta
----
===== Opis =====
Ovaj scenarij opisuje **potpunu verifikaciju digitalnih potpisa**. Ispravna verifikacija obuhvaća:
* **Provjera potpisa** - Kriptografska validacija
* **Provjera certifikata** - Lanac, Opoziv, Valjanost
* **Provjera vremenske oznake** - Ako postoji
* **Provjera politike** - Namjena uporabe
----
===== Tijek rada =====
flowchart TD
SIG[Potpis] --> CRYPTO[Kripto-provjera]
CRYPTO --> CERT[Provjera certifikata]
CERT --> CHAIN[Izgradnja lanca]
CHAIN --> REV[Provjera opoziva]
REV --> TIME[Vremenska provjera]
TIME --> TS{Vremenska oznaka?}
TS -->|Da| TS_CHECK[Provjera vremenske oznake]
TS -->|Ne| POLICY[Provjera politike]
TS_CHECK --> POLICY
POLICY --> RESULT{Sve OK?}
RESULT -->|Da| VALID[Potpis VALJAN]
RESULT -->|Ne| INVALID[Potpis NEVALJAN]
style VALID fill:#e8f5e9
style INVALID fill:#ffebee
----
===== Primjer koda: Potpuna 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. Kriptografska provjera potpisa
result.SignatureValid = ctx.VerifyData(
data: data,
signature: signature,
certificate: signerCert,
hashAlgorithm: options.HashAlgorithm,
mode: options.CryptoMode
);
if (!result.SignatureValid)
{
result.Error = "Kriptografski potpis nije valjan";
return result;
}
// 2. Validacija lanca certifikata
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 nije valjan: {string.Join(", ", result.ChainStatus)}";
return result;
}
// 3. Provjera Extended Key Usage
if (options.RequiredEku != null)
{
result.EkuValid = HasExtendedKeyUsage(signerCert, options.RequiredEku);
if (!result.EkuValid)
{
result.Error = $"Potrebna EKU ({options.RequiredEku}) nedostaje";
return result;
}
}
// 4. Provjera vremena potpisa
var signatureTime = options.SignatureTime ?? DateTimeOffset.UtcNow;
result.TimeValid = signatureTime >= signerCert.NotBefore &&
signatureTime <= signerCert.NotAfter;
if (!result.TimeValid)
{
result.Error = "Certifikat nije bio valjan u vrijeme potpisivanja";
return result;
}
result.IsValid = true;
result.SignerSubject = signerCert.Subject;
result.SignatureTime = signatureTime;
}
catch (Exception ex)
{
result.IsValid = false;
result.Error = ex.Message;
}
return result;
}
}
----
===== Primjer koda: Verifikacija CMS/PKCS#7 potpisa =====
public VerificationResult VerifyCms(byte[] signedData, byte[]? originalContent = null)
{
var result = new VerificationResult();
try
{
// Parsiranje CMS-a
var signedCms = new SignedCms();
if (originalContent != null)
{
// Detached signature
var contentInfo = new ContentInfo(originalContent);
signedCms = new SignedCms(contentInfo, true);
}
signedCms.Decode(signedData);
// Provjera svakog potpisa
foreach (var signerInfo in signedCms.SignerInfos)
{
// Kriptografska provjera
signerInfo.CheckSignature(verifySignatureOnly: false);
// Certifikat potpisnika
var cert = signerInfo.Certificate;
result.SignerSubject = cert?.Subject;
// Provjera vremenske oznake (ako postoji)
var timestampAttr = signerInfo.UnsignedAttributes
.Cast()
.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 vremenske oznake
var signatureBytes = signerInfo.GetSignature();
var signatureHash = SHA256.HashData(signatureBytes);
result.TimestampValid = tsToken.VerifySignatureForHash(
signatureHash,
HashAlgorithmName.SHA256,
out _,
extraCandidates: null
);
}
// Signing Time atribut
var signingTimeAttr = signerInfo.SignedAttributes
.Cast()
.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 ChainStatus { get; set; } = new();
public string? Error { get; set; }
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine($"Potpis valjan: {IsValid}");
sb.AppendLine($" Kripto-provjera: {SignatureValid}");
sb.AppendLine($" Certifikat: {CertificateValid}");
sb.AppendLine($" Vremenska provjera: {TimeValid}");
if (SignerSubject != null)
sb.AppendLine($" Potpisnik: {SignerSubject}");
if (SignatureTime.HasValue)
sb.AppendLine($" Vrijeme potpisa: {SignatureTime:yyyy-MM-dd HH:mm:ss}");
if (TimestampPresent)
{
sb.AppendLine($" Vremenska oznaka: {(TimestampValid ? "valjana" : "nevaljana")}");
if (TimestampTime.HasValue)
sb.AppendLine($" Vrijeme oznake: {TimestampTime:yyyy-MM-dd HH:mm:ss}");
}
if (Error != null)
sb.AppendLine($" GREŠKA: {Error}");
return sb.ToString();
}
}
----
===== Grupna verifikacija =====
public class BatchVerifier
{
public async Task> VerifyDirectory(
string directory,
X509Certificate2Collection trustedCerts)
{
var results = new Dictionary();
var verifier = new SignatureVerifier();
// Pronalazak svih .sig datoteka
var sigFiles = Directory.GetFiles(directory, "*.sig", SearchOption.AllDirectories);
foreach (var sigFile in sigFiles)
{
// Pronalazak originalne datoteke
var originalFile = sigFile.Replace(".sig", "");
if (!File.Exists(originalFile))
{
results[sigFile] = new VerificationResult
{
IsValid = false,
Error = "Originalna datoteka nije pronađena"
};
continue;
}
// Pronalazak certifikata
var certFile = sigFile.Replace(".sig", ".crt");
X509Certificate2 signerCert;
if (File.Exists(certFile))
{
signerCert = new X509Certificate2(certFile);
}
else
{
// Pretraživanje u Trusted Certs (pojednostavljeno)
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;
}
}
----
===== Kodovi grešaka i rješenja =====
^ Greška ^ Uzrok ^ Rješenje ^
| **SignatureInvalid** | Podaci ili potpis manipulirani | Provjerite originale |
| **CertificateExpired** | Certifikat istekao | Koristite vremensku oznaku |
| **CertificateRevoked** | Certifikat opozvan | Novi certifikat |
| **UntrustedRoot** | Root nije pouzdan | Provjerite Trust Store |
| **ChainIncomplete** | Nedostaje Intermediate | Dovršite lanac |
| **TimestampInvalid** | Potpis vremenske oznake nije valjan | Provjerite TSA certifikat |
----
===== Povezani scenariji =====
^ Povezanost ^ Scenarij ^ Opis ^
| **Preduvjet** | [[.:dokument_signieren|8.1 Potpisivanje dokumenata]] | Kreiranje potpisa |
| **Preduvjet** | [[.:timestamp|8.3 Vremenska oznaka]] | Dodavanje vremenske oznake |
| **Povezano** | [[hr:int:pqcrypt:szenarien:validierung:chain_validation|5.2 Validacija lanca]] | Provjera certifikata |
----
<< [[.:timestamp|← 8.3 Vremenska oznaka]] | [[.:start|↑ Pregled potpisa]] | [[hr:int:pqcrypt:szenarien:start|→ Svi scenariji]] >>
{{tag>scenarij potpis verifikacija validacija cms}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//