How to: Validate a PDF Document Signature
- 6 minutes to read
Important
You need a license for the DevExpress Office File API Subscription or DevExpress Universal Subscription to use these examples in production code.
The PDF Document API allows you to validate PKCS #7 signatures in a PDF document. Use the PdfPkcs7Signature class methods to obtain information about the PKCS#7 signature and verify it.
The example below shows how to create a console app that obtains the PKCS#7 signatures from a PDF document (Document.pdf in this example). Once the signature is obtained, the code checks attributes such as the time of signing, the signer’s identity, and authenticity of the signature. The result is shown in a console.
using DevExpress.Pdf;
// ...
// Get the Document.pdf file.
using (PdfDocumentSigner documentSigner = new PdfDocumentSigner("Document.pdf"))
// Retrieve the list of `PdfSignatureInfo` objects in the document.
foreach (var signature in documentSigner.GetSignatureInfo()) {
Console.WriteLine("Signature field name : {0}", signature.FieldName);
Console.WriteLine(" Signer name : {0}", signature.SignerName);
// Obtain the PKCS#7 signature from the list of `PdfSignatureInfo` objects and verify it.
var pkcs7 = documentSigner.GetPdfPkcs7Signature(signature.FieldName);
Console.WriteLine(" Is signature valid? : {0}", pkcs7.VerifySignature());
// Obtain the PKCS#7 signature certificate and verify the certificate info.
var certificate = pkcs7.GetSignatureCertificate();
Console.WriteLine(" Certificate issuer : {0}", certificate.IssuerName.Name);
Console.WriteLine(" Is certificate valid? : {0}", certificate.Verify());
var timestampDate = pkcs7.GetTimeStampDate();
// Get a timestamp and verify the time of signing.
Console.WriteLine(" Does signature include a timestamp? : {0}", timestampDate.HasValue);
if(timestampDate.HasValue) {
Console.WriteLine(" Timestamp : {0}", timestampDate);
Console.WriteLine(" Is timestamp valid? : {0}", pkcs7.VerifyTimeStamp());
}
}
The result is shown below:
Signature field name : Signature1
Signer name : DevExpress Demo
Is signature valid? : True
Certificate issuer : CN=DevExpress Demo
Is certificate valid? : False
Does signature include a timestamp? : False
Signature field name : 9a1677be-7fa2-4429-8cb3-bea0c737ebf4
Signer name : DevExpress Demo
Is signature valid? : True
Certificate issuer : CN=DevExpress Demo
Is certificate valid? : False
Does signature include a timestamp? : True
Timestamp : 11/14/2023 8:02:57 AM
Is timestamp valid? : True
Check Certificate Revocation Based on CRL and OCSP Responses
Call the PdfPkcs7Signature.CheckCertificateRevocation method to obtain information about signature certificate revocation based on Online Certificate Status Protocol (OCSP) and Certificate Revocation List (CRL) responses.
The following code snippet checks the status of signature certificates in the “Signed_file.pdf” file:
using DevExpress.Pdf;
namespace ConsoleApp {
internal class Program {
static void Main(string[] args) {
CheckCertificateRevocationInfo();
}
public static void CheckCertificateRevocationInfo() {
using (PdfDocumentSigner documentSigner = new PdfDocumentSigner("Signed_file.pdf"))
// Retrieve the list of `PdfSignatureInfo` objects in the document.
foreach (var signature in documentSigner.GetSignatureInfo()){
Console.WriteLine("Signature field name : {0}", signature.FieldName);
Console.WriteLine("Signer name : {0}", signature.SignerName);
var pkcs7 = documentSigner.GetPdfPkcs7Signature(signature.FieldName);
Console.WriteLine("Is signature valid? : {0}", pkcs7.VerifySignature());
// Check wheter CRL/OCSP responses are embedded in the signature. If not, request them online.
Console.WriteLine("Is CRL embedded?: {0}", pkcs7.CrlList != null);
Console.WriteLine("Is OCSP embedded?: {0}", pkcs7.OcspList != null);
PdfRevocationVerificationOptions options = new PdfRevocationVerificationOptions(){
TryFetchCrlOnline = pkcs7.CrlList == null,
TryFetchOcspOnline = pkcs7.OcspList == null,
};
// Obtain information about signature certificate revocation.
var result = pkcs7.CheckCertificateRevocation(DateTime.UtcNow, options);
Console.WriteLine("Is certificate revoked?: {0}", result.IsCrlRevoked);
if (result.IsCrlRevoked)
Console.WriteLine("Is CRL found online?: {0}", result.IsCrlFoundOnline);
Console.WriteLine("OCSP Response Status: {0}", result.OcspRevocationStatus);
if (result.OcspRevocationStatus != PdfOcspRevocationStatus.None)
Console.WriteLine("Is OCSP found online?: {0}", result.IsOcspFoundOnline);
// Check whether the signature is a TimeStamp.
Console.WriteLine("Is Document Timestamp?: {0}", pkcs7.IsDocumentTimeStamp);
Console.WriteLine();
}
}
}
}
The result is shown below:
Signature field name : Signature1
Signer name : DevExpress Demo
Is signature valid? : True
Is CRL embedded?: False
Is OCSP embedded?: False
Is certificate revoked?: False
OCSP Response Status: Good
Is OCSP found online: True
Is Document Timestamp: False
Signature field name : Signature1
Signer name : DevExpress Demo
Is signature valid? : True
Is CRL embedded?: False
Is OCSP embedded?: False
Is certificate revoked?: False
OCSP Response Status: Unknown
Is OCSP found online: True
Is Document Timestamp: True
Validate Long Term Validation (LTV) Signatures
Call the PdfDocumentSigner.VerifyLtv method to obtain Long Term Validation (LTV) records about the state of the signature certificate.
The following example executes an LTV check for a signature from the “Signed_file.pdf” file:
using DevExpress.Office.DigitalSignatures;
namespace ConsoleApp {
internal class Program {
static void Main(string[] args) {
VerifyLTV();
}
public static void VerifyLTV(){
using (PdfDocumentSigner documentSigner = new PdfDocumentSigner("Signed_file.pdf")){
PdfLtvOptions options = new PdfLtvOptions(){
TryFetchCrlOnline = true,
TryFetchOcspOnline = true,
VerifyEntireCertificateChain = true,
};
var result = documentSigner.VerifyLtv(options);
foreach (var entry in result){
Console.WriteLine("Signature Name: {0}", entry.SignatureFieldName);
Console.WriteLine("Certificate in chain: {0}", entry.CertificateRevocationResults.Count);
foreach(var revocation in entry.CertificateRevocationResults){
Console.WriteLine("Certificate {0}", revocation.Key.Subject);
Console.WriteLine("Is certificate revoked?: {0}", revocation.Value.IsCrlRevoked);
if (revocation.Value.IsCrlRevoked)
Console.WriteLine("Is CRL found online?: {0}", revocation.Value.IsCrlFoundOnline);
Console.WriteLine("OCSP Response Status: {0}", revocation.Value.OcspRevocationStatus);
if (revocation.Value.OcspRevocationStatus != PdfOcspRevocationStatus.None)
Console.WriteLine("Is OCSP found online?: {0}", revocation.Value.IsOcspFoundOnline);
Console.WriteLine();
}
}
}
}
}
}