~~NOTOC~~
====== Scenario 8.4: Verificare firma ======
**Categoria:** [[.:start|Firme digitali]] \\
**Complessità:** Media \\
**Prerequisiti:** Dati firmati, certificato firmatario \\
**Tempo stimato:** 10-15 minuti
----
===== Descrizione =====
Questo scenario descrive la **verifica completa delle firme digitali**. Una verifica corretta comprende:
* **Verifica firma** - Validazione crittografica
* **Verifica certificato** - Chain, revoca, validità
* **Verifica timestamp** - Se presente
* **Verifica policy** - Scopo d'uso
----
===== Workflow =====
flowchart TD
SIG[Firma] --> CRYPTO[Verifica crittografica]
CRYPTO --> CERT[Verificare certificato]
CERT --> CHAIN[Chain Building]
CHAIN --> REV[Controllo revoca]
REV --> TIME[Verifica temporale]
TIME --> TS{Timestamp?}
TS -->|Si| TS_CHECK[Verificare timestamp]
TS -->|No| POLICY[Verificare policy]
TS_CHECK --> POLICY
POLICY --> RESULT{Tutto OK?}
RESULT -->|Si| VALID[Firma VALIDA]
RESULT -->|No| INVALID[Firma NON VALIDA]
style VALID fill:#e8f5e9
style INVALID fill:#ffebee
----
===== Esempio codice: Verifica completa =====
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. Verifica crittografica della firma
result.SignatureValid = ctx.VerifyData(
data: data,
signature: signature,
certificate: signerCert,
hashAlgorithm: options.HashAlgorithm,
mode: options.CryptoMode
);
if (!result.SignatureValid)
{
result.Error = "Firma crittografica non valida";
return result;
}
// 2. Validare catena certificati
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 = $"Certificato non valido: {string.Join(", ", result.ChainStatus)}";
return result;
}
// 3. Verificare Extended Key Usage
if (options.RequiredEku != null)
{
result.EkuValid = HasExtendedKeyUsage(signerCert, options.RequiredEku);
if (!result.EkuValid)
{
result.Error = $"EKU richiesto ({options.RequiredEku}) mancante";
return result;
}
}
// 4. Verificare momento della firma
var signatureTime = options.SignatureTime ?? DateTimeOffset.UtcNow;
result.TimeValid = signatureTime >= signerCert.NotBefore &&
signatureTime <= signerCert.NotAfter;
if (!result.TimeValid)
{
result.Error = "Certificato non valido al momento della firma";
return result;
}
result.IsValid = true;
result.SignerSubject = signerCert.Subject;
result.SignatureTime = signatureTime;
}
catch (Exception ex)
{
result.IsValid = false;
result.Error = ex.Message;
}
return result;
}
}
----
===== Esempio codice: Verificare firma CMS/PKCS#7 =====
public VerificationResult VerifyCms(byte[] signedData, byte[]? originalContent = null)
{
var result = new VerificationResult();
try
{
// Analizzare CMS
var signedCms = new SignedCms();
if (originalContent != null)
{
// Firma detached
var contentInfo = new ContentInfo(originalContent);
signedCms = new SignedCms(contentInfo, true);
}
signedCms.Decode(signedData);
// Verificare ogni firma
foreach (var signerInfo in signedCms.SignerInfos)
{
// Verifica crittografica
signerInfo.CheckSignature(verifySignatureOnly: false);
// Certificato firmatario
var cert = signerInfo.Certificate;
result.SignerSubject = cert?.Subject;
// Verificare timestamp (se presente)
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;
// Validare timestamp
var signatureBytes = signerInfo.GetSignature();
var signatureHash = SHA256.HashData(signatureBytes);
result.TimestampValid = tsToken.VerifySignatureForHash(
signatureHash,
HashAlgorithmName.SHA256,
out _,
extraCandidates: null
);
}
// Attributo Signing Time
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;
}
----
===== Risultato verifica =====
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($"Firma valida: {IsValid}");
sb.AppendLine($" Verifica crittografica: {SignatureValid}");
sb.AppendLine($" Certificato: {CertificateValid}");
sb.AppendLine($" Verifica temporale: {TimeValid}");
if (SignerSubject != null)
sb.AppendLine($" Firmatario: {SignerSubject}");
if (SignatureTime.HasValue)
sb.AppendLine($" Ora firma: {SignatureTime:yyyy-MM-dd HH:mm:ss}");
if (TimestampPresent)
{
sb.AppendLine($" Timestamp: {(TimestampValid ? "valido" : "non valido")}");
if (TimestampTime.HasValue)
sb.AppendLine($" Ora timestamp: {TimestampTime:yyyy-MM-dd HH:mm:ss}");
}
if (Error != null)
sb.AppendLine($" ERRORE: {Error}");
return sb.ToString();
}
}
----
===== Verifica batch =====
public class BatchVerifier
{
public async Task> VerifyDirectory(
string directory,
X509Certificate2Collection trustedCerts)
{
var results = new Dictionary();
var verifier = new SignatureVerifier();
// Trovare tutti i file .sig
var sigFiles = Directory.GetFiles(directory, "*.sig", SearchOption.AllDirectories);
foreach (var sigFile in sigFiles)
{
// Trovare file originale
var originalFile = sigFile.Replace(".sig", "");
if (!File.Exists(originalFile))
{
results[sigFile] = new VerificationResult
{
IsValid = false,
Error = "File originale non trovato"
};
continue;
}
// Trovare certificato
var certFile = sigFile.Replace(".sig", ".crt");
X509Certificate2 signerCert;
if (File.Exists(certFile))
{
signerCert = new X509Certificate2(certFile);
}
else
{
// Cercare nei certificati trusted (semplificato)
signerCert = trustedCerts[0];
}
// Verificare
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;
}
}
----
===== Codici di errore e soluzioni =====
^ Errore ^ Causa ^ Soluzione ^
| **SignatureInvalid** | Dati o firma manipolati | Verificare originali |
| **CertificateExpired** | Certificato scaduto | Usare timestamp |
| **CertificateRevoked** | Certificato revocato | Nuovo certificato |
| **UntrustedRoot** | Root non affidabile | Verificare Trust Store |
| **ChainIncomplete** | Intermediate mancante | Completare chain |
| **TimestampInvalid** | Firma timestamp non valida | Verificare certificato TSA |
----
===== Scenari correlati =====
^ Relazione ^ Scenario ^ Descrizione ^
| **Prerequisito** | [[.:dokument_signieren|8.1 Firmare documento]] | Creare firma |
| **Prerequisito** | [[.:timestamp|8.3 Timestamp]] | Aggiungere timestamp |
| **Correlato** | [[it:int:pqcrypt:szenarien:validierung:chain_validation|5.2 Validazione Chain]] | Verifica certificati |
----
<< [[.:timestamp|← 8.3 Timestamp]] | [[.:start|↑ Panoramica firme]] | [[it:int:pqcrypt:szenarien:start|→ Tutti gli scenari]] >>
{{tag>scenario firma verifica validazione cms}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//