/// <summary>
/// Displays and verifies signatures of PDF document.
/// </summary>
/// <param name="pdfFilename">The filename of PDF document.</param>
public static void VerifyDocumentSignatures(string pdfFilename)
{
// open PDF document
using (Vintasoft.Imaging.Pdf.PdfDocument document =
new Vintasoft.Imaging.Pdf.PdfDocument(pdfFilename))
{
// if document does not have interactive form
if (document.InteractiveForm == null)
{
System.Console.WriteLine("Signature fields are not found.");
return;
}
// get an array of signature fields of document
Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField[] signatureFields =
document.InteractiveForm.GetSignatureFields();
// if document does not have signature fields
if (signatureFields.Length == 0)
{
System.Console.WriteLine("Signture fields are not found.");
return;
}
// for each signature field
for (int i = 0; i < signatureFields.Length; i++)
{
// get reference to the signature field
Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField signatureField = signatureFields[i];
// print signature field name
System.Console.WriteLine(string.Format("[{0}]Signaure field: {1}", i + 1, signatureField.FullyQualifiedName));
// get information about signature
Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfSignatureInformation signatureInfo = signatureField.SignatureInfo;
// if signature information is empty
if (signatureInfo == null)
{
System.Console.WriteLine("Empty signature field.");
}
// if signature information is NOT empty
else
{
// check is document timestamp signature
if (signatureInfo.IsTimeStamp)
System.Console.WriteLine("Signature is a document timestamp signature");
// print signature filter
System.Console.WriteLine(string.Format("Filter : {0} ({1})", signatureInfo.Filter, signatureInfo.SubFilter));
// print the signer name
if (signatureInfo.SignerName != null)
System.Console.WriteLine(string.Format("Signed by : {0}", signatureInfo.SignerName));
// print the signature reason
if (signatureInfo.Reason != null)
System.Console.WriteLine(string.Format("Reason : {0}", signatureInfo.Reason));
// print the signature location
if (signatureInfo.Location != null)
System.Console.WriteLine(string.Format("Location : {0}", signatureInfo.Location));
// print the signer contact info
if (signatureInfo.ContactInfo != null)
System.Console.WriteLine(string.Format("Contact Info: {0}", signatureInfo.ContactInfo));
// print the signing date
if (signatureInfo.SigningTime != System.DateTime.MinValue)
System.Console.WriteLine(string.Format("Signig Date : {0}", signatureInfo.SigningTime.ToString("f")));
// get PKCS signature
bool error = false;
Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature signature = null;
try
{
signature = signatureInfo.GetSignature();
}
catch (System.Exception e)
{
error = true;
System.Console.WriteLine("PKCS signature parsing error: {0}", e.Message);
}
if (error)
continue;
// print name of signature algorithm
System.Console.WriteLine(string.Format("Algorithm : {0}", signature.SignatureAlgorithmName));
// print information about signature certificate chain
System.Console.WriteLine("Sign certificate chain:");
System.Security.Cryptography.X509Certificates.X509Certificate2[] signCertChain =
signature.SigningCertificateChain;
string padding = "";
foreach (System.Security.Cryptography.X509Certificates.X509Certificate2 cert in signCertChain)
{
padding += " ";
System.Console.WriteLine("{0}Serial number: {1}", padding, cert.SerialNumber);
System.Console.WriteLine("{0}Issuer : {1}", padding, cert.GetNameInfo(
System.Security.Cryptography.X509Certificates.X509NameType.SimpleName, true));
System.Console.WriteLine("{0}Subject : {1}", padding, cert.GetNameInfo(
System.Security.Cryptography.X509Certificates.X509NameType.SimpleName, false));
}
// verify digital signature
VerifyDigitalSignature(signatureInfo, signature);
}
System.Console.WriteLine();
}
}
}
/// <summary>
/// Verifies the digital signature.
/// </summary>
/// <param name="signature">The signature.</param>
/// <param name="signatureInfo">The signature information.</param>
/// <returns><b>true</b> if signature is valid; otherwise, <b>false</b>.</returns>
public static bool VerifyDigitalSignature(
Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfSignatureInformation signatureInfo,
Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature signature)
{
System.Console.WriteLine("Verifying signature...");
bool signatureVerifyResult = false;
bool embeddedTimestampVerifyResult = false;
bool certificateVerifyResult = false;
bool embeddedTimestampCertificateVerifyResult = false;
bool signatureCoversWholeDocument = false;
System.Security.Cryptography.X509Certificates.X509Chain certificateChain = null;
System.Security.Cryptography.X509Certificates.X509Chain timestampCertificateChain = null;
// verify signature
try
{
// check that signature covers the whole document
signatureCoversWholeDocument = signatureInfo.SignatureCoversWholeDocument();
// verify PKCS signature
signatureVerifyResult = signature.VerifySignature();
// if signature has embedded timestamp
if (signature.HasEmbeddedTimeStamp)
{
// verify embedded timestamp
embeddedTimestampVerifyResult = signature.VerifyTimestamp();
}
// build and verify certificate chain
certificateChain = new System.Security.Cryptography.X509Certificates.X509Chain();
certificateVerifyResult = certificateChain.Build(signature.SigningCertificate);
// if signature has embedded timestamp
if (signature.HasEmbeddedTimeStamp)
{
// build and verify timestamp certificate chain
timestampCertificateChain = new System.Security.Cryptography.X509Certificates.X509Chain();
embeddedTimestampCertificateVerifyResult = certificateChain.Build(signature.TimestampCertificate);
}
}
catch (System.Exception verificationException)
{
System.Console.WriteLine("Verification failed: {0}", verificationException.Message);
return false;
}
bool pageContentModified = false;
string subsequentChangesMessage = "";
// if PKCS signature verification is passed AND signature does not cover the whole document
if (signatureVerifyResult && !signatureCoversWholeDocument)
{
try
{
// if signature has revision info
if (signatureInfo.SignedRevision != null)
{
// check subsequent changes
using (Vintasoft.Imaging.Pdf.PdfDocumentRevisionComparer documentChanges = signatureInfo.GetDocumentChanges())
{
// check subsequent changes in pages content
pageContentModified = documentChanges.HasModifiedPages;
// build subsequent changes message
if (documentChanges.ChangedPageContents.Count > 0)
subsequentChangesMessage += string.Format("{0} page(s) modified; ", documentChanges.ChangedPageContents.Count);
if (documentChanges.AddedPages.Count > 0)
subsequentChangesMessage += string.Format("{0} page(s) added; ", documentChanges.AddedPages.Count);
if (documentChanges.RemovedPages.Count > 0)
subsequentChangesMessage += string.Format("{0} page(s) removed; ", documentChanges.RemovedPages.Count);
if (documentChanges.RemovedAnnotations.Count > 0)
subsequentChangesMessage += string.Format("annotations(s) on {0} page(s) removed; ", documentChanges.RemovedAnnotations.Count);
if (documentChanges.RemovedAnnotations.Count > 0)
subsequentChangesMessage += string.Format("removed annotation(s) on {0} page(s); ", documentChanges.RemovedAnnotations.Count);
if (documentChanges.AddedAnnotations.Count > 0)
subsequentChangesMessage += string.Format("added annotation(s) on {0} page(s); ", documentChanges.AddedAnnotations.Count);
if (documentChanges.ChangedAnnotations.Count > 0)
subsequentChangesMessage += string.Format("changed annotation(s) on {0} page(s); ", documentChanges.ChangedAnnotations.Count);
if (documentChanges.MiscellaneousChanges.Count > 0)
subsequentChangesMessage += string.Format("miscellaneous changes: {0}; ", documentChanges.MiscellaneousChanges.Count);
}
}
}
catch (System.Exception verificationException)
{
System.Console.WriteLine("Verification failed: {0}", verificationException.Message);
return false;
}
}
// print signature verification result
// if PKCS signature verification is failed OR
// signature does not cover the whole document AND page(s) content is modified
if (!signatureVerifyResult || (!signatureCoversWholeDocument && pageContentModified))
System.Console.WriteLine("Signature is INVALID.");
// if certificate verification is failed
else if (!certificateVerifyResult || (signature.HasEmbeddedTimeStamp && (!embeddedTimestampCertificateVerifyResult || !embeddedTimestampVerifyResult)))
System.Console.WriteLine("Signature validity is UNKNOWN.");
else
System.Console.WriteLine("Signature is VALID.");
// print signature verification details
// if signature verification is successful
if (signatureVerifyResult)
{
// if signature covers the whole document
if (signatureCoversWholeDocument)
{
System.Console.WriteLine(" Signature verification: Document has not been modified since this signature was applied.");
}
// if signature does NOT cover the whole document
else
{
if (pageContentModified)
{
System.Console.WriteLine(" Signature verification: Document has been modified or corrupted since it was signed.");
System.Console.WriteLine(string.Format(" Subsequent changes: {0}.", subsequentChangesMessage));
}
else if (subsequentChangesMessage != "")
{
System.Console.WriteLine(" Signature verification: The revision of the document that was covered by this signature has not been altered; however, there have been subsequent changes to the document.");
System.Console.WriteLine(string.Format(" Subsequent changes: {0}.", subsequentChangesMessage));
}
else
{
System.Console.WriteLine(" Signature verification: Document has not been modified since this signature was applied.");
}
}
}
// if signature verification is NOT successful
else
{
System.Console.WriteLine(" Signature verification: Document has been modified or corrupted since it was signed.");
}
// if signature has embedded timestamp
if (signature.HasEmbeddedTimeStamp)
{
if (embeddedTimestampVerifyResult)
System.Console.WriteLine(" Timestamp verification: Timestamp is valid.");
else
System.Console.WriteLine(" Timestamp verification: Timestamp is valid.");
}
// print certificate verification details
// if certificate chain is present
if (certificateChain != null)
{
// if certificate verification is successful
if (certificateVerifyResult)
{
System.Console.WriteLine(" Certificate verification: Signer's certificate is valid.");
}
// if certificate verification is NOT successful
else
{
// print certificate verification status
System.Console.WriteLine(" Certificate verification: Signer's certificate is invalid:");
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in certificateChain.ChainStatus)
System.Console.Write(string.Format(" {0}: {1}", status.Status, status.StatusInformation));
}
}
// if timestamp certificate chain is present
if (timestampCertificateChain != null)
{
// if timestamp certificate verification is successful
if (embeddedTimestampCertificateVerifyResult)
{
System.Console.WriteLine(" Timestamp certificate verification: Signer's certificate is valid.");
}
// if timestamp certificate verification is NOT successful
else
{
// print certificate verification status
System.Console.WriteLine(" Timestamp certificate verification: Signer's certificate is invalid:");
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in timestampCertificateChain.ChainStatus)
System.Console.Write(string.Format(" {0}: {1}", status.Status, status.StatusInformation));
}
}
// if signature is not verified
if (!signatureVerifyResult)
return false;
// if signature does NOT cover the whole document and page content was modified
if (!signatureCoversWholeDocument && pageContentModified)
return false;
// if signature certificate is NOT verified
if (!certificateVerifyResult)
return false;
if (signature.HasEmbeddedTimeStamp)
{
// if timestamp is NOT verified
if (!embeddedTimestampVerifyResult)
return false;
// if timestamp certifiacet is NOT verified
if (!embeddedTimestampCertificateVerifyResult)
return false;
}
// sigature is VALID
return true;
}