officefileapi-404728-pdf-document-api-examples-document-protection-how-to-validate-a-pdf-document-signature.md
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 following code snippet creates 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());
}
}
Imports System
Imports DevExpress.Pdf
' ...
Using documentSigner As New PdfDocumentSigner("Document.pdf")
' Retrieve the list of `PdfSignatureInfo` objects in the document.
For Each 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.
Dim pkcs7 = documentSigner.GetPdfPkcs7Signature(signature.FieldName)
Console.WriteLine(" Is signature valid? : {0}", pkcs7.VerifySignature())
' Obtain the PKCS#7 signature certificate and verify the certificate info.
Dim certificate = pkcs7.GetSignatureCertificate()
Console.WriteLine(" Certificate issuer : {0}", certificate.IssuerName.Name)
Console.WriteLine(" Is certificate valid? : {0}", certificate.Verify())
Dim 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 Then
Console.WriteLine(" Timestamp : {0}", timestampDate)
Console.WriteLine(" Is timestamp valid? : {0}", pkcs7.VerifyTimeStamp())
End If
Next signature
End Using
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
View Example: Blazor: Validate Document Signatures
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();
}
}
}
}
Imports DevExpress.Pdf
Namespace ConsoleApp
Friend Class Program
Shared Sub Main(ByVal args() As String)
CheckCertificateRevocationInfo()
End Sub
Public Shared Sub CheckCertificateRevocationInfo()
Using documentSigner As New PdfDocumentSigner("Signed_file.pdf")
' Retrieve the list of `PdfSignatureInfo` objects in the document.
For Each signature In documentSigner.GetSignatureInfo()
Console.WriteLine("Signature field name : {0}", signature.FieldName)
Console.WriteLine("Signer name : {0}", signature.SignerName)
Dim pkcs7 = documentSigner.GetPdfPkcs7Signature(signature.FieldName)
Console.WriteLine("Is signature valid? : {0}", pkcs7.VerifySignature())
' Check whether CRL/OCSP responses are embedded in the signature. If not, request them online.
Console.WriteLine("Is CRL embedded?: {0}", pkcs7.CrlList IsNot Nothing)
Console.WriteLine("Is OCSP embedded?: {0}", pkcs7.OcspList IsNot Nothing)
Dim options As New PdfRevocationVerificationOptions() With {
.TryFetchCrlOnline = pkcs7.CrlList Is Nothing,
.TryFetchOcspOnline = pkcs7.OcspList Is Nothing
}
' Obtain information about signature certificate revocation.
Dim result = pkcs7.CheckCertificateRevocation(Date.UtcNow, options)
Console.WriteLine("Is certificate revoked?: {0}", result.IsCrlRevoked)
If result.IsCrlRevoked Then
Console.WriteLine("Is CRL found online?: {0}", result.IsCrlFoundOnline)
End If
Console.WriteLine("OCSP Response Status: {0}", result.OcspRevocationStatus)
If result.OcspRevocationStatus <> PdfOcspRevocationStatus.None Then
Console.WriteLine("Is OCSP found online?: {0}", result.IsOcspFoundOnline)
End If
' Check whether the signature is a TimeStamp.
Console.WriteLine("Is Document Timestamp?: {0}", pkcs7.IsDocumentTimeStamp)
Console.WriteLine()
Next signature
End Using
End Sub
End Class
End Namespace
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
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();
}
}
}
}
}
}
Imports DevExpress.Pdf
Namespace ConsoleApp
Friend Class Program
Shared Sub Main(ByVal args() As String)
VerifyLTV()
End Sub
Public Shared Sub VerifyLTV()
Using documentSigner As New PdfDocumentSigner("Signed_file.pdf")
Dim options As New PdfLtvOptions() With {
.TryFetchCrlOnline = True,
.TryFetchOcspOnline = True,
.VerifyEntireCertificateChain = True
}
Dim result = documentSigner.VerifyLtv(options)
For Each entry In result
Console.WriteLine("Signature Name: {0}", entry.SignatureFieldName)
Console.WriteLine("Certificate in chain: {0}", entry.CertificateRevocationResults.Count)
For Each revocation In entry.CertificateRevocationResults
Console.WriteLine("Certificate {0}", revocation.Key.Subject)
Console.WriteLine("Is certificate revoked?: {0}", revocation.Value.IsCrlRevoked)
If revocation.Value.IsCrlRevoked Then
Console.WriteLine("Is CRL found online?: {0}", revocation.Value.IsCrlFoundOnline)
End If
Console.WriteLine("OCSP Response Status: {0}", revocation.Value.OcspRevocationStatus)
If revocation.Value.OcspRevocationStatus <> PdfOcspRevocationStatus.None Then
Console.WriteLine("Is OCSP found online?: {0}", revocation.Value.IsOcspFoundOnline)
End If
Console.WriteLine()
Next revocation
Next entry
End Using
End Sub
End Class
End Namespace