PDF: Использование цифровых подписей в PDF документах
В этом разделе
Цифровая подпись используется для подтверждения подлинности личности пользователя и достоверности содержимого документа.
SDK позволяет:
- Подписать PDF документ с помощью технологии "byte range", которая вычисляет контрольную сумму для двоичных данных всего документа. Цифровая подпись и контрольная сумма хранятся в поле подписи интерактивной формы PDF документа.
- Проверить достоверность подписи PDF документа.
- Восстановить PDF документ до состояния на момент подписания документа (PdfSignatureInformation.SignedRevision).
Добавление цифровой подписи в PDF документ
Чтобы подписать PDF документ с помощью цифровой подписи, необходимо сделать следующее:
- Создать поле, в котором будет храниться подпись
- Получить информацию о цифровом сертификате
- Добавить цифровой сертификат в поле
- Определить внешний вид поля
- Добавить поле в интерактивную форму PDF документа
- Добавить аннотацию, представляющую поле, в список аннотаций к PDF странице, на которой должна быть расположена подпись
- Сохранить PDF документ - подписание PDF документа происходит во время сохранения
Вот C#/VB.NET код, который демонстрирует, как подписать PDF документ с помощью цифровой подписи:
/// <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
Проверка цифровой подписи
Для проверки цифровой подписи PDF документа необходимо сделать следующее:
- Получить подпись из поля подписи
- Убедиться, что подпись охватывает весь PDF документ.
- Убедиться, что подпись подлинная
- Убедиться, что цепочка сертификатов подписи действительна
Вот C#/VB.NET код, который демонстрирует, как проверить, является ли подпись 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.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
ВАЖНО!
Проверка сертификата будет выполнена успешно только в том случае, если сертификат добавлен в список доверенных корневых сертификатов текущего пользователя Windows. Подробнее о том, как управлять доверенными корневыми сертификатами, вы можете прочитать здесь:
https://technet.microsoft.com/en-us/library/cc754841.aspx
.
Удаление цифровой подписи из PDF документа
Чтобы удалить подпись из PDF документа, необходимо выполнить следующие действия:
- Найти поле, в котором хранится цифровая подпись
- Удалить поле из интерактивной формы PDF документа
- Сохранить PDF документ
Вот C#/VB.NET код, который демонстрирует, как удалить подпись из PDF документа:
/// <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