Добавление цифровой подписи в PDF документ с использованием C#
20 июля 2026
using System.Drawing;
using System.Security.Cryptography.X509Certificates;
using Vintasoft.Imaging.Pdf;
/// <summary>
/// Adds digital signature with text appearance to a PDF page.
/// </summary>
public class PdfPageDigitalSignatureHelper_TextAppearance
{
public static void Run()
{
// get the X509 certificate from .pfx-file
using (X509Certificate2 certificate = new X509Certificate2("TestCertificate.pfx", "test"))
{
// create a helper that alows to add digital signature to a PDF document
PdfPageDigitalSignatureHelper digitalSignatureHelper =
new PdfPageDigitalSignatureHelper(certificate, new RectangleF(20, 20, 250, 100));
// set the reason for signing
digitalSignatureHelper.SigningReason = "Approve document";
// set the signature appearance text
digitalSignatureHelper.SignatureText = string.Format("Digitally signed by\n{0}", digitalSignatureHelper.SignerName);
// add digital signature to the first PDF page, sign PDF document and save PDF document to the output file
digitalSignatureHelper.SignDocument("TestDocumentToSign.pdf", "TestDocumentToSign-signed.pdf", 0);
}
}
}
using System.Drawing;
using System.Security.Cryptography.X509Certificates;
using Vintasoft.Imaging.Pdf;
/// <summary>
/// Adds digital signature with image appearance to a PDF page.
/// </summary>
public class PdfPageDigitalSignatureHelper_ImageAppearance
{
public static void Run()
{
// get the X509 certificate from .pfx-file
using (X509Certificate2 certificate = new X509Certificate2("TestCertificate.pfx", "test"))
{
// create a helper that alows to add digital signature to a PDF document
PdfPageDigitalSignatureHelper digitalSignatureHelper =
new PdfPageDigitalSignatureHelper(certificate, new RectangleF(20, 20, 250, 100));
// set signature information
digitalSignatureHelper.SignerName = "Mr. X";
digitalSignatureHelper.SigningReason = "Approval";
digitalSignatureHelper.SigningLocation = "My Location";
digitalSignatureHelper.SignerContactInfo = "Phone: 9999-123-45-67";
// set the name of image file that defines the signature appearance
digitalSignatureHelper.SignatureImageFilename = "SignatureImage.svg";
// add digital signature to the first PDF page, sign PDF document and save PDF document to the output file
digitalSignatureHelper.SignDocument("TestDocumentToSign.pdf", "TestDocumentToSign-signed.pdf", 0);
}
}
}
using System.Drawing;
using System.Security.Cryptography.X509Certificates;
using Vintasoft.Imaging.Pdf;
using Vintasoft.Imaging.Pdf.Drawing;
using Vintasoft.Imaging.Pdf.Tree.Fonts;
/// <summary>
/// Adds visible digital signature with custom appearance to a PDF page.
/// </summary>
public class PdfPageDigitalSignatureHelper_CustomAppearance
{
public static void Run()
{
// get the X509 certificate from .pfx-file
using (X509Certificate2 certificate = new X509Certificate2("TestCertificate.pfx", "test"))
{
// create a helper that alows to add digital signature to a PDF document
MyDigitalSignatureHelper digitalSignatureHelper =
new MyDigitalSignatureHelper(certificate, new RectangleF(20, 20, 250, 100));
// set the background color for signature
digitalSignatureHelper.SignatureBackgoundColor = Color.Green;
// set the reason for signing
digitalSignatureHelper.SigningReason = "Approve document";
// set text for signature appearance
digitalSignatureHelper.SignatureText =
string.Format("Digitally signed by\n{0}", digitalSignatureHelper.SignerName);
// add digital signature to the first PDF page, sign PDF document and save PDF document to the output file
digitalSignatureHelper.SignDocument("TestDocumentToSign.pdf", "TestDocumentToSign-signed.pdf", 0);
}
}
public class MyDigitalSignatureHelper : PdfPageDigitalSignatureHelper
{
public MyDigitalSignatureHelper(X509Certificate2 certificate, RectangleF signatureRect)
: base(certificate, signatureRect)
{
}
/// <summary>
/// Draws the text on signature appearance.
/// </summary>
/// <param name="graphics">The PDF graphics.</param>
/// <param name="rect">The rectangle.</param>
/// <param name="font">The text font.</param>
/// <param name="text">The text do draw.</param>
protected override void DrawSignatureAppearanceText(PdfGraphics graphics, RectangleF rect, PdfFont font, string text)
{
// create border pen
PdfPen borderPen = new PdfPen(Color.Orange, 10);
// draw border
graphics.DrawRectangle(borderPen, rect);
// padding
rect.Inflate(-borderPen.Width * 2, -borderPen.Width * 2);
// measure font size
float fontSize = graphics.MeasureFontSize(text, font, rect.Width, rect.Height);
// draw the signature text
graphics.DrawString(text, font, fontSize, new PdfBrush(SignatureTextColor), rect, SignatureTextAlignment, false);
}
}
}
using System.Security.Cryptography.X509Certificates;
using Vintasoft.Imaging.Pdf;
/// <summary>
/// Adds invisible digital signature to a PDF page.
/// </summary>
public class PdfPageDigitalSignatureHelper_InvisibleAppearance
{
public static void Run()
{
// get the X509 certificate from .pfx-file
using (X509Certificate2 certificate = new X509Certificate2("TestCertificate.pfx", "test"))
{
// create a helper that allows to add digital signature to a PDF document
PdfPageDigitalSignatureHelper digitalSignatureHelper = new PdfPageDigitalSignatureHelper(certificate);
// set the reason for signing
digitalSignatureHelper.SigningReason = "Approve document";
// add digital signature to the first PDF page, sign PDF document and save PDF document to the output file
digitalSignatureHelper.SignDocument("TestDocumentToSign.pdf", "TestDocumentToSign-signed.pdf", 0);
}
}
}
using System.Drawing;
using System.Security.Cryptography.X509Certificates;
using Vintasoft.Imaging.Pdf;
/// <summary>
/// Adds digital signature with timestamp to a PDF page.
/// </summary>
public class PdfPageDigitalSignatureHelper_Timestamp
{
public static void Run()
{
// get the X509 certificate from .pfx-file
using (X509Certificate2 certificate = new X509Certificate2("TestCertificate.pfx", "test"))
{
// create a helper that alows to add digital signature to a PDF document
PdfPageDigitalSignatureHelper digitalSignatureHelper =
new PdfPageDigitalSignatureHelper(certificate, new RectangleF(20, 20, 250, 100));
// set the reason for signing
digitalSignatureHelper.SigningReason = "Approve document";
// set the name of image file that defines the signature appearance
digitalSignatureHelper.SignatureImageFilename = "SignatureImage.svg";
// set the URL to the timestamp server
digitalSignatureHelper.TimestampServerUrl = "http://timestamp.comodoca.com/";
// add digital signature to the first PDF page, sign PDF document and save PDF document to the output file
digitalSignatureHelper.SignDocument("TestDocumentToSign.pdf", "TestDocumentToSign-signed.pdf", 0);
}
}
}
using System.Drawing;
using System.Security.Cryptography.X509Certificates;
using Vintasoft.Imaging.Pdf;
/// <summary>
/// Adds two digital signatures with text appearance to a PDF page.
/// </summary>
public class PdfPageDigitalSignatureHelper_Multi
{
public static void Run()
{
// open PDF document
using (PdfDocument document = new PdfDocument("TestDocumentToSign.pdf"))
{
// get the X509 certificate from .pfx-file
using (X509Certificate2 certificate = new X509Certificate2("TestCertificate.pfx", "test"))
{
// create a helper that alows to add digital signature to a PDF document
PdfPageDigitalSignatureHelper digitalSignatureHelper =
new PdfPageDigitalSignatureHelper(certificate, new RectangleF(20, 20, 250, 100));
// set the reason for signing
digitalSignatureHelper.SigningReason = "Approve document";
// set the signature appearance text
digitalSignatureHelper.SignatureText = string.Format("Digitally signed by\n{0}, page 1",
digitalSignatureHelper.SignerName);
// add signature to first page
digitalSignatureHelper.AddSignature(document, 0);
// set the signature appearance text
digitalSignatureHelper.SignatureText = string.Format("Digitally signed by\n{0}, page 2",
digitalSignatureHelper.SignerName);
// add signature to second page
digitalSignatureHelper.AddSignature(document, 1);
}
// sign PDF document and save PDF document to the output file
document.SaveChanges("TestDocumentToSign-signed.pdf");
}
}
}
/// <summary>
/// Adds long term validation (LTV) information to all signatures of specified PDF document.
/// </summary>
/// <param name="inputPdfFilename">The filename of input PDF document.</param>
/// <param name="outputPdfFilename">The filename of output PDF document.</param>
public static bool AddVltInfo(string inputPdfFilename, string outputPdfFilename)
{
// open PDF document
using (Vintasoft.Imaging.Pdf.PdfDocument document =
new Vintasoft.Imaging.Pdf.PdfDocument(inputPdfFilename))
{
try
{
// add LTV info
int count = Vintasoft.Imaging.Pdf.Tree.DigitalSignatures.PdfDocumentLtv.AddLtvInfo(document);
if (count == 0)
System.Console.WriteLine("LTV information is not required for this document.");
else
System.Console.WriteLine("LTV information is added.");
}
catch (System.Exception ex)
{
System.Console.WriteLine("Error: " + ex.Message);
return false;
}
// save PDF document
if (inputPdfFilename == outputPdfFilename)
document.SaveChanges();
else
document.Save(outputPdfFilename);
return true;
}
}
using System.Drawing;
using Vintasoft.Imaging.Pdf;
/// <summary>
/// Adds an empty signature field to a PDF page.
/// </summary>
public class PdfPageDigitalSignatureHelper_EmptySignatureField
{
public static void Run()
{
// create a helper that alows to add digital signature to a PDF document
PdfPageDigitalSignatureHelper digitalSignatureHelper =
new PdfPageDigitalSignatureHelper(null, new RectangleF(20, 20, 250, 100));
// set the appearance for signature field
digitalSignatureHelper.SignatureText = "Add your signature here";
digitalSignatureHelper.SignatureBackgoundColor = Color.Yellow;
// open PDF document
using (PdfDocument document = new PdfDocument("TestDocumentToSign.pdf"))
{
// add signature field to the first PDF page
digitalSignatureHelper.AddEmptySignatureField(document.Pages[0]);
// save PDF document to the output file
document.SaveChanges("TestDocumentToSign-output.pdf");
}
}
}
/// <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;
}
using Vintasoft.Imaging.Pdf;
using Vintasoft.Imaging.Pdf.Tree.InteractiveForms;
public class PdfSignaturesHelper2
{
/// <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 (PdfDocument document = new PdfDocument(pdfFilename))
{
// if PDF document has PDF interactive form
if (document.InteractiveForm != null)
{
// for each signature field
foreach (PdfInteractiveFormField field in
document.InteractiveForm.GetSignatureFields())
{
// remove signature field
field.Remove();
}
// pack PDF document
document.Pack();
}
}
}
}