PDF: Usage of digital signatures in PDF document
In This Topic
Digital signature is used for authenticating the identity of a user and the validity of the document contents.
The SDK allows to:
- Sign a PDF document using "byte range" technology, which calculates the check sum for binary data of the entire document. Digital signature and check sum is stored in the signature field of the PDF document interactive form.
- Check the validity of the PDF document signature.
- Restore a PDF document to the state at the moment of document signing (PdfSignatureInformation.SignedRevision).
Add digital signature to PDF document
To sign a PDF document using digital signature is necessary to do the following:
- Create a field that will store the signature
- Determine the information about digital certificate
- Add the digital certificate to the field
- Define the visual appearance of the field
- Add the field to the interactive form of PDF document
- Add annotation, that represents the field, to a list annotation of the PDF page where the signature must be located
- Save the PDF document - signing of PDF document takes place while saving
Here is C#/VB.NET code, that demonstrates how to sign a PDF document via digital signature:
/// <summary>
/// Signs a PDF or PDF/A document using specified certificate.
/// </summary>
/// <param name="inputFilename">The filename of input PDF document.</param>
/// <param name="outputFilename">The filename of output PDF document.</param>
/// <param name="certificate">The certificate that should be used
/// for signing the input PDF document.</param>
/// <param name="conformance">The conformance of PDF document.</param>
public static void SignDocument(
string inputFilename,
string outputFilename,
Vintasoft.Imaging.Pdf.PdfDocumentConformance conformance,
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
{
SignDocument(inputFilename, outputFilename, conformance, certificate, false, null);
}
/// <summary>
/// Signs with timestamp a PDF or PDF/A document using specified certificate.
/// </summary>
/// <param name="inputFilename">The filename of input PDF document.</param>
/// <param name="outputFilename">The filename of output PDF document.</param>
/// <param name="certificate">The certificate that should be used
/// for signing the input PDF document.</param>
/// <param name="addCertificateChain">A value indicating whether signing certificate chain must be added to signature.</param>
/// <param name="conformance">The conformance of PDF document.</param>
/// <param name="timestampServerUrl">Timestamp server URL.</param>
public static void SignDocument(
string inputFilename,
string outputFilename,
Vintasoft.Imaging.Pdf.PdfDocumentConformance conformance,
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate,
bool addCertificateChain,
string timestampServerUrl)
{
Vintasoft.Imaging.Pdf.Processing.PdfDocumentConverter converter = null;
// if PDF document conformance is specified
if (conformance != Vintasoft.Imaging.Pdf.PdfDocumentConformance.Undefined)
{
// create PDF document converter
converter = Vintasoft.Imaging.Pdf.Processing.PdfDocumentConverter.Create(conformance);
// if is PDF/A converter
Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter pdfAConverter = converter as Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter;
if (pdfAConverter != null)
{
// set ICC profiles
//pdfAConverter.DefaultCmykIccProfileFilename = "DefaultCMYK.icc";
//pdfAConverter.DefaultRgbIccProfileFilename = "DefaultRGB.icc";
}
// if PDF document converter is not found
if (converter == null)
{
string message = string.Format("Unsupported {0} conformance.", conformance);
throw new System.ArgumentOutOfRangeException(message);
}
}
// open PDF document
using (Vintasoft.Imaging.Pdf.PdfDocument document = new Vintasoft.Imaging.Pdf.PdfDocument(inputFilename))
{
// add signature
AddSignature(document, certificate, addCertificateChain, timestampServerUrl, 1);
// if PDF document cannot be converted
if (converter == null)
{
if (inputFilename == outputFilename)
{
// sign PDF document and save changes in PDF document
document.SaveChanges();
}
else
{
// sign PDF document and save PDF document to the output file
document.SaveChanges(outputFilename);
}
}
else
{
if (inputFilename != outputFilename)
{
Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter pdfAConverter =
(Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter)converter;
pdfAConverter.OutputFilename = outputFilename;
}
// sign and convert PDF document
Vintasoft.Imaging.Processing.ConversionProfileResult conversionResult =
converter.Convert(document, new Vintasoft.Imaging.Processing.ProcessingState());
// if conversion falied
if (!conversionResult.IsSuccessful)
{
// throw conversion exception
throw conversionResult.CreateConversionException();
}
}
}
}
/// <summary>
/// Adds a digital signature to specified PDF document.
/// </summary>
/// <param name="document">The PDF document.</param>
/// <param name="certificate">The certificate that should be added.</param>
/// <param name="timestampServerUrl">Timestamp server URL.</param>
/// <param name="addCertificateChain">A value indicating whether signing certificate chain must be added to signature.</param>
/// <param name="sigNumber">The number of signature field.</param>
private static void AddSignature(
Vintasoft.Imaging.Pdf.PdfDocument document,
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate,
bool addCertificateChain,
string timestampServerUrl,
int sigNumber)
{
// if PDF document does not have interactive form
if (document.InteractiveForm == null)
{
// create the interactive form in document
document.InteractiveForm = new Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentInteractiveForm(document);
}
// specify that document contains signatures
document.InteractiveForm.SignatureFlags =
Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentSignatureFlags.SignaturesExist |
Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentSignatureFlags.AppendOnly;
// specify that the viewer application must NOT construct appearance streams and
// appearance properties for widget annotations in the document
document.InteractiveForm.NeedAppearances = false;
// get PDF page on which signature will be placed
Vintasoft.Imaging.Pdf.Tree.PdfPage page = document.Pages[0];
// calculate the signature field rectangle (field will be placed in the bottom-center of page)
System.Drawing.RectangleF signatureRect = new System.Drawing.RectangleF();
signatureRect.Width = page.MediaBox.Width / 5;
signatureRect.Height = signatureRect.Width / 3;
signatureRect.X = page.MediaBox.X + (page.MediaBox.Width - signatureRect.Width) / 2;
signatureRect.Y = page.MediaBox.Y + signatureRect.Height * sigNumber;
// create parameters for creation of PKCS#7 signature
Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignatureCreationParams creationParams =
new Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignatureCreationParams(certificate, addCertificateChain);
// if timestamp server is specified
if (!string.IsNullOrEmpty(timestampServerUrl))
{
// specify the timestamp authority client
creationParams.TimestampAuthorityClient = new Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.TimestampAuthorityWebClient(timestampServerUrl);
}
// create PKCS#7 signature
Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature signature = Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature.CreatePkcs7Signature(
document.Format, creationParams);
// create signature info
Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfSignatureInformation signatureInfo =
new Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfSignatureInformation(document, signature);
signatureInfo.SignerName = certificate.GetNameInfo(
System.Security.Cryptography.X509Certificates.X509NameType.SimpleName, false);
signatureInfo.Reason = "Test signing";
signatureInfo.Location = System.Globalization.CultureInfo.CurrentCulture.EnglishName;
signatureInfo.SigningTime = System.DateTime.Now;
// create the signature field
Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField signatureField =
new Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField(document, string.Format("MySignature{0}", sigNumber), signatureRect);
// set the signature information
signatureField.SignatureInfo = signatureInfo;
// create the signature appearance
using (Vintasoft.Imaging.Pdf.Drawing.PdfGraphics g = signatureField.CreateAppearanceGraphics())
{
// signature text
string signatureText = string.Format("Digitally signed by\n{0}",
signatureInfo.SignerName);
// signature appearance rect
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(
System.Drawing.PointF.Empty,
signatureField.Annotation.Rectangle.Size);
// draw background
g.FillRectangle(new Vintasoft.Imaging.Pdf.Drawing.PdfBrush(
System.Drawing.Color.FromArgb(255, System.Drawing.Color.Lime)), rect);
// padding
rect.Inflate(-rect.Height / 10, -rect.Height / 10);
// create TimesRoman font
Vintasoft.Imaging.Pdf.Tree.Fonts.PdfFont font = document.FontManager.GetStandardFont(
Vintasoft.Imaging.Pdf.Tree.Fonts.PdfStandardFontType.TimesRoman);
// measure font size
float fontSize = g.MeasureFontSize(signatureText, font, rect.Width, rect.Height);
// draw signture text
g.DrawString(
signatureText,
font, fontSize, new Vintasoft.Imaging.Pdf.Drawing.PdfBrush(System.Drawing.Color.Black),
rect, Vintasoft.Imaging.Pdf.Drawing.PdfContentAlignment.Center, false);
}
// add signature field to the interactive form of document
document.InteractiveForm.Fields.Add(signatureField);
// if PDF page does not have annotations
if (page.Annotations == null)
// create an empty annotation collection for page
page.Annotations = new Vintasoft.Imaging.Pdf.Tree.Annotations.PdfAnnotationList(document);
// add widget annotation of signature field to the annotation collection of page
page.Annotations.Add(signatureField.Annotation);
}
''' <summary>
''' Signs a PDF or PDF/A document using specified certificate.
''' </summary>
''' <param name="inputFilename">The filename of input PDF document.</param>
''' <param name="outputFilename">The filename of output PDF document.</param>
''' <param name="certificate">The certificate that should be used
''' for signing the input PDF document.</param>
''' <param name="conformance">The conformance of PDF document.</param>
Public Shared Sub SignDocument(inputFilename As String, outputFilename As String, conformance As Vintasoft.Imaging.Pdf.PdfDocumentConformance, certificate As System.Security.Cryptography.X509Certificates.X509Certificate2)
SignDocument(inputFilename, outputFilename, conformance, certificate, False, Nothing)
End Sub
''' <summary>
''' Signs with timestamp a PDF or PDF/A document using specified certificate.
''' </summary>
''' <param name="inputFilename">The filename of input PDF document.</param>
''' <param name="outputFilename">The filename of output PDF document.</param>
''' <param name="certificate">The certificate that should be used
''' for signing the input PDF document.</param>
''' <param name="addCertificateChain">A value indicating whether signing certificate chain must be added to signature.</param>
''' <param name="conformance">The conformance of PDF document.</param>
''' <param name="timestampServerUrl">Timestamp server URL.</param>
Public Shared Sub SignDocument(inputFilename As String, outputFilename As String, conformance As Vintasoft.Imaging.Pdf.PdfDocumentConformance, certificate As System.Security.Cryptography.X509Certificates.X509Certificate2, addCertificateChain As Boolean, timestampServerUrl As String)
Dim converter As Vintasoft.Imaging.Pdf.Processing.PdfDocumentConverter = Nothing
' if PDF document conformance is specified
If conformance <> Vintasoft.Imaging.Pdf.PdfDocumentConformance.Undefined Then
' create PDF document converter
converter = Vintasoft.Imaging.Pdf.Processing.PdfDocumentConverter.Create(conformance)
' if is PDF/A converter
Dim pdfAConverter As Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter = TryCast(converter, Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter)
' set ICC profiles
'pdfAConverter.DefaultCmykIccProfileFilename = "DefaultCMYK.icc";
'pdfAConverter.DefaultRgbIccProfileFilename = "DefaultRGB.icc";
If pdfAConverter IsNot Nothing Then
End If
' if PDF document converter is not found
If converter Is Nothing Then
Dim message As String = String.Format("Unsupported {0} conformance.", conformance)
Throw New System.ArgumentOutOfRangeException(message)
End If
End If
' open PDF document
Using document As New Vintasoft.Imaging.Pdf.PdfDocument(inputFilename)
' add signature
AddSignature(document, certificate, addCertificateChain, timestampServerUrl, 1)
' if PDF document cannot be converted
If converter Is Nothing Then
If inputFilename = outputFilename Then
' sign PDF document and save changes in PDF document
document.SaveChanges()
Else
' sign PDF document and save PDF document to the output file
document.SaveChanges(outputFilename)
End If
Else
If inputFilename <> outputFilename Then
Dim pdfAConverter As Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter = DirectCast(converter, Vintasoft.Imaging.Pdf.Processing.PdfA.PdfAConverter)
pdfAConverter.OutputFilename = outputFilename
End If
' sign and convert PDF document
Dim conversionResult As Vintasoft.Imaging.Processing.ConversionProfileResult = converter.Convert(document, New Vintasoft.Imaging.Processing.ProcessingState())
' if conversion falied
If Not conversionResult.IsSuccessful Then
' throw conversion exception
Throw conversionResult.CreateConversionException()
End If
End If
End Using
End Sub
''' <summary>
''' Adds a digital signature to specified PDF document.
''' </summary>
''' <param name="document">The PDF document.</param>
''' <param name="certificate">The certificate that should be added.</param>
''' <param name="timestampServerUrl">Timestamp server URL.</param>
''' <param name="addCertificateChain">A value indicating whether signing certificate chain must be added to signature.</param>
''' <param name="sigNumber">The number of signature field.</param>
Private Shared Sub AddSignature(document As Vintasoft.Imaging.Pdf.PdfDocument, certificate As System.Security.Cryptography.X509Certificates.X509Certificate2, addCertificateChain As Boolean, timestampServerUrl As String, sigNumber As Integer)
' if PDF document does not have interactive form
If document.InteractiveForm Is Nothing Then
' create the interactive form in document
document.InteractiveForm = New Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentInteractiveForm(document)
End If
' specify that document contains signatures
document.InteractiveForm.SignatureFlags = Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentSignatureFlags.SignaturesExist Or Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentSignatureFlags.AppendOnly
' specify that the viewer application must NOT construct appearance streams and
' appearance properties for widget annotations in the document
document.InteractiveForm.NeedAppearances = False
' get PDF page on which signature will be placed
Dim page As Vintasoft.Imaging.Pdf.Tree.PdfPage = document.Pages(0)
' calculate the signature field rectangle (field will be placed in the bottom-center of page)
Dim signatureRect As New System.Drawing.RectangleF()
signatureRect.Width = page.MediaBox.Width / 5
signatureRect.Height = signatureRect.Width / 3
signatureRect.X = page.MediaBox.X + (page.MediaBox.Width - signatureRect.Width) / 2
signatureRect.Y = page.MediaBox.Y + signatureRect.Height * sigNumber
' create parameters for creation of PKCS#7 signature
Dim creationParams As New Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignatureCreationParams(certificate, addCertificateChain)
' if timestamp server is specified
If Not String.IsNullOrEmpty(timestampServerUrl) Then
' specify the timestamp authority client
creationParams.TimestampAuthorityClient = New Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.TimestampAuthorityWebClient(timestampServerUrl)
End If
' create PKCS#7 signature
Dim signature As Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature = Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature.CreatePkcs7Signature(document.Format, creationParams)
' create signature info
Dim signatureInfo As New Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfSignatureInformation(document, signature)
signatureInfo.SignerName = certificate.GetNameInfo(System.Security.Cryptography.X509Certificates.X509NameType.SimpleName, False)
signatureInfo.Reason = "Test signing"
signatureInfo.Location = System.Globalization.CultureInfo.CurrentCulture.EnglishName
signatureInfo.SigningTime = System.DateTime.Now
' create the signature field
Dim signatureField As New Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField(document, String.Format("MySignature{0}", sigNumber), signatureRect)
' set the signature information
signatureField.SignatureInfo = signatureInfo
' create the signature appearance
Using g As Vintasoft.Imaging.Pdf.Drawing.PdfGraphics = signatureField.CreateAppearanceGraphics()
' signature text
Dim signatureText As String = String.Format("Digitally signed by" & vbLf & "{0}", signatureInfo.SignerName)
' signature appearance rect
Dim rect As New System.Drawing.RectangleF(System.Drawing.PointF.Empty, signatureField.Annotation.Rectangle.Size)
' draw background
g.FillRectangle(New Vintasoft.Imaging.Pdf.Drawing.PdfBrush(System.Drawing.Color.FromArgb(255, System.Drawing.Color.Lime)), rect)
' padding
rect.Inflate(-rect.Height / 10, -rect.Height / 10)
' create TimesRoman font
Dim font As Vintasoft.Imaging.Pdf.Tree.Fonts.PdfFont = document.FontManager.GetStandardFont(Vintasoft.Imaging.Pdf.Tree.Fonts.PdfStandardFontType.TimesRoman)
' measure font size
Dim fontSize As Single = g.MeasureFontSize(signatureText, font, rect.Width, rect.Height)
' draw signture text
g.DrawString(signatureText, font, fontSize, New Vintasoft.Imaging.Pdf.Drawing.PdfBrush(System.Drawing.Color.Black), rect, Vintasoft.Imaging.Pdf.Drawing.PdfContentAlignment.Center, _
False)
End Using
' add signature field to the interactive form of document
document.InteractiveForm.Fields.Add(signatureField)
' if PDF page does not have annotations
If page.Annotations Is Nothing Then
' create an empty annotation collection for page
page.Annotations = New Vintasoft.Imaging.Pdf.Tree.Annotations.PdfAnnotationList(document)
End If
' add widget annotation of signature field to the annotation collection of page
page.Annotations.Add(signatureField.Annotation)
End Sub
Verify digital signature
To verify the signature of PDF document is necessary to do the following:
- Obtain the signature from the signature field
- Make sure that the signature covers the entire PDF document
- Make sure that the signature is authentic
- Make sure that the certificate chain of the signature is valid
Here is C#/VB.NET code, that demonstrates how to check whether signature of PDF document is authentic:
/// <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.SignerName));
// 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;
}
''' <summary>
''' Displays and verifies signatures of PDF document.
''' </summary>
''' <param name="pdfFilename">The filename of PDF document.</param>
Public Shared Sub VerifyDocumentSignatures(pdfFilename As String)
' open PDF document
Using document As New Vintasoft.Imaging.Pdf.PdfDocument(pdfFilename)
' if document does not have interactive form
If document.InteractiveForm Is Nothing Then
System.Console.WriteLine("Signature fields are not found.")
Return
End If
' get an array of signature fields of document
Dim signatureFields As Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField() = document.InteractiveForm.GetSignatureFields()
' if document does not have signature fields
If signatureFields.Length = 0 Then
System.Console.WriteLine("Signture fields are not found.")
Return
End If
' for each signature field
For i As Integer = 0 To signatureFields.Length - 1
' get reference to the signature field
Dim signatureField As Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField = signatureFields(i)
' print signature field name
System.Console.WriteLine(String.Format("[{0}]Signaure field: {1}", i + 1, signatureField.FullyQualifiedName))
' get information about signature
Dim signatureInfo As Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfSignatureInformation = signatureField.SignatureInfo
' if signature information is empty
If signatureInfo Is Nothing Then
System.Console.WriteLine("Empty signature field.")
Else
' if signature information is NOT empty
' check is document timestamp signature
If signatureInfo.IsTimeStamp Then
System.Console.WriteLine("Signature is a document timestamp signature")
End If
' print signature filter
System.Console.WriteLine(String.Format("Filter : {0} ({1})", signatureInfo.Filter, signatureInfo.SubFilter))
' print the signer name
If signatureInfo.SignerName IsNot Nothing Then
System.Console.WriteLine(String.Format("Signed by : {0}", signatureInfo.SignerName))
End If
' print the signature reason
If signatureInfo.Reason IsNot Nothing Then
System.Console.WriteLine(String.Format("Reason : {0}", signatureInfo.Reason))
End If
' print the signature location
If signatureInfo.Location IsNot Nothing Then
System.Console.WriteLine(String.Format("Location : {0}", signatureInfo.Location))
End If
' print the signer contact info
If signatureInfo.ContactInfo IsNot Nothing Then
System.Console.WriteLine(String.Format("Contact Info: {0}", signatureInfo.SignerName))
End If
' print the signing date
If signatureInfo.SigningTime <> System.DateTime.MinValue Then
System.Console.WriteLine(String.Format("Signig Date : {0}", signatureInfo.SigningTime.ToString("f")))
End If
' get PKCS signature
Dim [error] As Boolean = False
Dim signature As Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature = Nothing
Try
signature = signatureInfo.GetSignature()
Catch e As System.Exception
[error] = True
System.Console.WriteLine("PKCS signature parsing error: {0}", e.Message)
End Try
If [error] Then
Continue For
End If
' 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:")
Dim signCertChain As System.Security.Cryptography.X509Certificates.X509Certificate2() = signature.SigningCertificateChain
Dim padding As String = ""
For Each cert As System.Security.Cryptography.X509Certificates.X509Certificate2 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))
Next
' verify digital signature
VerifyDigitalSignature(signatureInfo, signature)
End If
System.Console.WriteLine()
Next
End Using
End Sub
''' <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 Shared Function VerifyDigitalSignature(signatureInfo As Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfSignatureInformation, signature As Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfPkcsSignature) As Boolean
System.Console.WriteLine("Verifying signature...")
Dim signatureVerifyResult As Boolean = False
Dim embeddedTimestampVerifyResult As Boolean = False
Dim certificateVerifyResult As Boolean = False
Dim embeddedTimestampCertificateVerifyResult As Boolean = False
Dim signatureCoversWholeDocument As Boolean = False
Dim certificateChain As System.Security.Cryptography.X509Certificates.X509Chain = Nothing
Dim timestampCertificateChain As System.Security.Cryptography.X509Certificates.X509Chain = Nothing
' 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 Then
' verify embedded timestamp
embeddedTimestampVerifyResult = signature.VerifyTimestamp()
End If
' 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 Then
' build and verify timestamp certificate chain
timestampCertificateChain = New System.Security.Cryptography.X509Certificates.X509Chain()
embeddedTimestampCertificateVerifyResult = certificateChain.Build(signature.TimestampCertificate)
End If
Catch verificationException As System.Exception
System.Console.WriteLine("Verification failed: {0}", verificationException.Message)
Return False
End Try
Dim pageContentModified As Boolean = False
Dim subsequentChangesMessage As String = ""
' if PKCS signature verification is passed AND signature does not cover the whole document
If signatureVerifyResult AndAlso Not signatureCoversWholeDocument Then
Try
' if signature has revision info
If signatureInfo.SignedRevision IsNot Nothing Then
' check subsequent changes
Using documentChanges As Vintasoft.Imaging.Pdf.PdfDocumentRevisionComparer = signatureInfo.GetDocumentChanges()
' check subsequent changes in pages content
pageContentModified = documentChanges.HasModifiedPages
' build subsequent changes message
If documentChanges.ChangedPageContents.Count > 0 Then
subsequentChangesMessage += String.Format("{0} page(s) modified; ", documentChanges.ChangedPageContents.Count)
End If
If documentChanges.AddedPages.Count > 0 Then
subsequentChangesMessage += String.Format("{0} page(s) added; ", documentChanges.AddedPages.Count)
End If
If documentChanges.RemovedPages.Count > 0 Then
subsequentChangesMessage += String.Format("{0} page(s) removed; ", documentChanges.RemovedPages.Count)
End If
If documentChanges.RemovedAnnotations.Count > 0 Then
subsequentChangesMessage += String.Format("annotations(s) on {0} page(s) removed; ", documentChanges.RemovedAnnotations.Count)
End If
If documentChanges.RemovedAnnotations.Count > 0 Then
subsequentChangesMessage += String.Format("removed annotation(s) on {0} page(s); ", documentChanges.RemovedAnnotations.Count)
End If
If documentChanges.AddedAnnotations.Count > 0 Then
subsequentChangesMessage += String.Format("added annotation(s) on {0} page(s); ", documentChanges.AddedAnnotations.Count)
End If
If documentChanges.ChangedAnnotations.Count > 0 Then
subsequentChangesMessage += String.Format("changed annotation(s) on {0} page(s); ", documentChanges.ChangedAnnotations.Count)
End If
If documentChanges.MiscellaneousChanges.Count > 0 Then
subsequentChangesMessage += String.Format("miscellaneous changes: {0}; ", documentChanges.MiscellaneousChanges.Count)
End If
End Using
End If
Catch verificationException As System.Exception
System.Console.WriteLine("Verification failed: {0}", verificationException.Message)
Return False
End Try
End If
' 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 Not signatureVerifyResult OrElse (Not signatureCoversWholeDocument AndAlso pageContentModified) Then
System.Console.WriteLine("Signature is INVALID.")
' if certificate verification is failed
ElseIf Not certificateVerifyResult OrElse (signature.HasEmbeddedTimeStamp AndAlso (Not embeddedTimestampCertificateVerifyResult OrElse Not embeddedTimestampVerifyResult)) Then
System.Console.WriteLine("Signature validity is UNKNOWN.")
Else
System.Console.WriteLine("Signature is VALID.")
End If
' print signature verification details
' if signature verification is successful
If signatureVerifyResult Then
' if signature covers the whole document
If signatureCoversWholeDocument Then
System.Console.WriteLine(" Signature verification: Document has not been modified since this signature was applied.")
Else
' if signature does NOT cover the whole document
If pageContentModified Then
System.Console.WriteLine(" Signature verification: Document has been modified or corrupted since it was signed.")
System.Console.WriteLine(String.Format(" Subsequent changes: {0}.", subsequentChangesMessage))
ElseIf subsequentChangesMessage <> "" Then
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.")
End If
End If
Else
' if signature verification is NOT successful
System.Console.WriteLine(" Signature verification: Document has been modified or corrupted since it was signed.")
End If
' if signature has embedded timestamp
If signature.HasEmbeddedTimeStamp Then
If embeddedTimestampVerifyResult Then
System.Console.WriteLine(" Timestamp verification: Timestamp is valid.")
Else
System.Console.WriteLine(" Timestamp verification: Timestamp is valid.")
End If
End If
' print certificate verification details
' if certificate chain is present
If certificateChain IsNot Nothing Then
' if certificate verification is successful
If certificateVerifyResult Then
System.Console.WriteLine(" Certificate verification: Signer's certificate is valid.")
Else
' if certificate verification is NOT successful
' print certificate verification status
System.Console.WriteLine(" Certificate verification: Signer's certificate is invalid:")
For Each status As System.Security.Cryptography.X509Certificates.X509ChainStatus In certificateChain.ChainStatus
System.Console.Write(String.Format(" {0}: {1}", status.Status, status.StatusInformation))
Next
End If
End If
' if timestamp certificate chain is present
If timestampCertificateChain IsNot Nothing Then
' if timestamp certificate verification is successful
If embeddedTimestampCertificateVerifyResult Then
System.Console.WriteLine(" Timestamp certificate verification: Signer's certificate is valid.")
Else
' if timestamp certificate verification is NOT successful
' print certificate verification status
System.Console.WriteLine(" Timestamp certificate verification: Signer's certificate is invalid:")
For Each status As System.Security.Cryptography.X509Certificates.X509ChainStatus In timestampCertificateChain.ChainStatus
System.Console.Write(String.Format(" {0}: {1}", status.Status, status.StatusInformation))
Next
End If
End If
' if signature is not verified
If Not signatureVerifyResult Then
Return False
End If
' if signature does NOT cover the whole document and page content was modified
If Not signatureCoversWholeDocument AndAlso pageContentModified Then
Return False
End If
' if signature certificate is NOT verified
If Not certificateVerifyResult Then
Return False
End If
If signature.HasEmbeddedTimeStamp Then
' if timestamp is NOT verified
If Not embeddedTimestampVerifyResult Then
Return False
End If
' if timestamp certifiacet is NOT verified
If Not embeddedTimestampCertificateVerifyResult Then
Return False
End If
End If
' sigature is VALID
Return True
End Function
IMPORTANT! Certificate verification will be performed successfully only if certificate is added to the list oftrusted root certificates of current Windows user. You can read more on how to manage trusted root certificates here:
https://technet.microsoft.com/en-us/library/cc754841.aspx.
Remove digital signature from PDF document
To remove the signature from PDF document is necessary to do the following:
- Find the field that stores the digital signature
- Remove the field from interactive form of PDF document
- Save the PDF document
Here is C#/VB.NET code, that demonstrates how to remove a signature from PDF document:
/// <summary>
/// Removes all digital signatures from PDF document.
/// </summary>
/// <param name="pdfFilename">The filename of PDF document.</param>
public static void RemoveDigitalSignaturesFromPdfDocument(string pdfFilename)
{
// open PDF document
using (Vintasoft.Imaging.Pdf.PdfDocument document =
new Vintasoft.Imaging.Pdf.PdfDocument(pdfFilename))
{
// if PDF document has PDF interactive form
if (document.InteractiveForm != null)
{
// get reference to the interactive form of PDF document
Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentInteractiveForm form =
document.InteractiveForm;
// get all signature fields of PDF document
Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField[] signatureFields =
form.GetSignatureFields();
// for each signature fields
foreach (Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormField field in signatureFields)
{
// remove signature field
field.Remove();
}
// pack PDF document
document.Pack();
}
}
}
''' <summary>
''' Removes all digital signatures from PDF document.
''' </summary>
''' <param name="pdfFilename">The filename of PDF document.</param>
Public Shared Sub RemoveDigitalSignaturesFromPdfDocument(pdfFilename As String)
' open PDF document
Using document As New Vintasoft.Imaging.Pdf.PdfDocument(pdfFilename)
' if PDF document has PDF interactive form
If document.InteractiveForm IsNot Nothing Then
' get reference to the interactive form of PDF document
Dim form As Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfDocumentInteractiveForm = document.InteractiveForm
' get all signature fields of PDF document
Dim signatureFields As Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormSignatureField() = form.GetSignatureFields()
' for each signature fields
For Each field As Vintasoft.Imaging.Pdf.Tree.InteractiveForms.PdfInteractiveFormField In signatureFields
' remove signature field
field.Remove()
Next
' pack PDF document
document.Pack()
End If
End Using
End Sub