Available for: UI for ASP.NET MVC | UI for ASP.NET AJAX | UI for Blazor | UI for WPF | UI for WinForms | UI for Silverlight | UI for Xamarin | UI for WinUI | UI for ASP.NET Core | UI for .NET MAUI

New to Telerik Document Processing? Download free 30-day trial

Digital Signature

This article covers the following topics:

What is Digital Signature?

The digital signature feature enables you to sign and validate a PDF document. A signature confirms that the document's content originated from the signer and has not been modified in any way. A signed document is considered valid when it has not been changed after the signing, and all of its certificates have a valid trusted root certificate.

To use the signing functionality in PdfProcessing for .NET Standard/.NET Core, you must add a reference to the System.Security.Cryptography.Pkcs NuGet package, version 6 or newer (This functionality is available since R1 2022 SP1).

Signing a Document

The signing is done through the Signature object. The constructor of the Signature class takes a X509Certificate2 object as a parameter. This is the certificate that will be used to sign the PDF document.

Example 1: Create a Signature object

System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificateFilePath, password); 
Signature signature = new Signature(certificate); 
When instantiated, the signature should be added to the document's content using the SignatureField.

Example 2: Add signature to a signature field

SignatureField signatureField = new SignatureField("Signature Name"); 
signatureField.Signature = signature; 
In addition, to create a signature, which has a visual representation, you must use the Widget constructor - you need to associate a Widget annotation with the signed SignatureField. The widget also needs a FormSource object applied to its Content.NormalContentSource property. A FormSource could be filled with data using the FixedContentEditor.

When exporting a digitally signed document a stream that allows both reading and writing should be passed otherwise an exception is thrown: NotSupportedException: 'Stream does not support reading.'

Example 3 shows the full code for a simple signing of a document.

Example 3: Sign a document

// Define the certificate which will be used for the signing. 
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificateFilePath, certificateFilePassword); 
 
// The name of the signature must be unique. 
string signatureName = "SampleSignature"; 
 
// This is the Form XObject element that represents the contents of the signature field.  
Form form = new Form(); 
form.FormSource = new FormSource(); 
form.FormSource.Size = new Size(220, 220); 
 
// We will use the editor to fill the Form XObject.  
FixedContentEditor formEditor = new FixedContentEditor(form.FormSource); 
form.Position.Translate(10, 10); 
formEditor.DrawCircle(new Point(50, 50), 20); 
formEditor.DrawText(signatureName); 
 
// The Signature object is added to a signature field, so we can add a visualization to it.  
SignatureField signatureField = new SignatureField(signatureName); 
signatureField.Signature = new Signature(certificate); 
 
// The widget contains the Form XObject and defines the appearance of the signature field.  
SignatureWidget widget = signatureField.Widgets.AddWidget(); 
widget.Rect = new Rect(new Point(200, 600), new Size(100, 100)); 
widget.Border = new AnnotationBorder(10, AnnotationBorderStyle.Solid, null); 
widget.Content.NormalContentSource = form.FormSource; 
widget.RecalculateContent(); 
 
// The Widget class inherits from Annotation. And, as with any other annotation, must be added to the respective collection of the page.  
 
RadFixedDocument document = new RadFixedDocument(); 
RadFixedPage page = document.Pages.AddPage(); 
page.Annotations.Add(widget); 
 
var editor = new FixedContentEditor(page); 
editor.Position.Translate(200, 400); 
editor.DrawForm(form.FormSource); 
document.AcroForm.FormFields.Add(signatureField); 
widget.RecalculateContent(); 
widget.AppearanceCharacteristics.Background = new Telerik.Windows.Documents.Fixed.Model.ColorSpaces.RgbColor(255, 0, 0); 
 
using (Stream output = new FileStream("signed.pdf", FileMode.OpenOrCreate, FileAccess.ReadWrite)) 
{ 
    new PdfFormatProvider().Export(document, output); 
} 

When signing an existing document (after the import) we must be sure the AcroForm's ViewersShouldRecalculateWidgetAppearances property is set to false, otherwise, the exported and signed PDF document could not be shown as a signed.

Signature Encodings

RadPdfProcessing enables you to sign and validate signature fields using standard signature encodings:

  • adbe.x509.rsa_sha1 (PKCS #1)

  • adbe.pkcs7.sha1 (PKCS #7)

  • adbe.pkcs7.detached (PKCS #7 Detached)

Signature Flags

The signature flags were introduced in R2022 SP1. You can set the flags with the following code:

Example 4: Set signature flags

pdfDocument.AcroForm.SignatureFlags = SignatureFlags.None; 
The possible values are:
  • None
  • SignaturesExist: If set, the document contains at least one signature field.
  • AppendOnly: The document contains signatures that may be invalidated if the file is saved in a way that alters its previous contents.

Validating a Signature

The validation is performed for the current field and, since it strongly depends on the file bytes of the document, against the state of the document at the moment of importing.

The Signature class exposes two methods that allow you to validate a signature:

  • Validate(): The method accepts a parameter of type SignatureValidationProperties. The method uses these properties while validating the signature. The SignatureValidationProperties class exposes the following properties:

    • Chain: Gets or sets the chain used to validate the certificate that signed the digital signature. It is of type X509Chain.
    • ChainStatusFlags: Gets or sets the chain status flags that describe the used signature certificate as invalid. It is of type X509ChainStatusFlags.

    Validate() returns an object of type SignatureValidationResult.

  • TryValidate(): This method returns a boolean value indicating whether the validation succeeded or not. There are two overloads of this method. The first one accepts an out parameter containing a SignatureValidationResult object and second one allows you to also pass SignatureValidationProperties.

The validation requires that the stream, from which the document is imported, to be opened. The validation is performed for the current field and against the state of the document at the moment of importing.

Example 5 shows how the validation can be used.

Example 5: Validate a field

RadFixedDocument document = new PdfFormatProvider().Import(stream); // The stream containing the document 
 
string validationStatus; 
 
// For simplicity, the example handles only the first signature. 
SignatureField firstSignatureField = document.AcroForm.FormFields.FirstOrDefault(field => field.FieldType == FormFieldType.Signature) as SignatureField; 
if (firstSignatureField != null && firstSignatureField.Signature != null) 
{ 
    SignatureValidationProperties properties = new SignatureValidationProperties(); 
    System.Security.Cryptography.X509Certificates.X509VerificationFlags verificationFlags = System.Security.Cryptography.X509Certificates.X509VerificationFlags.IgnoreInvalidName; 
    properties.Chain.ChainPolicy.VerificationFlags = verificationFlags; 
 
    SignatureValidationResult validationResult; 
    if (firstSignatureField.Signature.TryValidate(properties, out validationResult)) 
    { 
        if (!validationResult.IsDocumentModified) 
        { 
            if (validationResult.IsCertificateValid) 
            { 
                validationStatus = "Valid"; 
            } 
            else 
            { 
                validationStatus = "Unknown"; 
            } 
        } 
        else 
        { 
            validationStatus = "Invalid"; 
        } 
    } 
    else 
    { 
        validationStatus = "Invalid"; 
    } 
} 
else 
{ 
    validationStatus = "None"; 
} 

To evaluate a certificate as trusted, it must be added to the trusted certificates on your machine.

Limitations

There are a few limitations related to the usage of digital signatures in RadPdfProcessing.

  • Exporting a document that is signed must be done using a stream that supports reading.

  • The validation of a signature depends on the bytes representing the document. Thus, to validate a signature, the stream used to import the document must be still open.

  • The validation is always performed for the current field, against the state of the document at the moment of importing.

  • At this point, RadPdfProcessing supports only the signing of a document that does not contain a signed signature field. Signing a document containing a signed signature field will result in invalidation and corruption of the existing signature.

  • RadPdfProcessing currently supports only the signing of a single signature field. Signing more than one signature field will result in the invalidation of all signatures except the last one.

See Also

In this article