# Digitally Sign a PDF

> Sign a PDF with a PFX certificate using SaveSettings.DigitalSignature, sign signature fields, test with a self-signed certificate and verify the result.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > Getting Started > PDF Processing > Digitally Sign a PDF
- **3515 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/sign/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/sign/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/sign/llms-full.txt

---

`ServerTextControl` signs a PDF with an X.509 certificate while it saves the document. For testing, you create a self-signed certificate, then sign the whole document, sign a visible signature field and check the result. The timestamp section explains a limitation in version 34.0 SP5.

### How PDF Signing Works

A digital signature proves two things: who signed the document, and that the document has not been changed since it was signed. It is based on public key cryptography:

1. A cryptographic hash of the document is calculated.
2. The hash is encrypted with the signer's private key. The result is the digital signature.
3. The signature and the signer's certificate are embedded in the PDF.
4. A PDF reader decrypts the signature with the public key from the certificate and compares the hash with a newly calculated one. If they differ, the document has been changed and the signature is shown as invalid.

TX Text Control applies the signature when it saves a document as PDF or PDF/A. You describe the certificate with a [DigitalSignature](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/digitalsignature/llms-full.txt) object, which wraps a .NET `X509Certificate2`, and pass it through [SaveSettings](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/savesettings/llms-full.txt). Signing works on Windows and Linux.

Certificates can be loaded from PFX, DER CER or Base64 CER files, from raw data or from the local certificate store. To sign, the certificate must include its private key, which is why this tutorial uses a PFX file.

Because the signature is created while the document is saved, you usually sign the document you generate, for example from a DOCX template. To sign a PDF that was created elsewhere, you first load it into `ServerTextControl`, which rebuilds its content as described in [Load and Modify a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/load-modify/llms-full.txt).

#### Sign the Document or Signature Fields

There are two ways to sign a PDF:

|  | Sign the whole document | Sign signature fields |
|---|---|---|
| Property | [SaveSettings.DigitalSignature](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/savesettings/digitalsignature-property/llms-full.txt) | [SaveSettings.SignatureFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/savesettings/signaturefields-property/llms-full.txt) |
| Appearance | Invisible. PDF readers show the signature in their signature panel. | Visible. A signature field shows an image, such as a handwritten signature. |
| Number of signatures | One signature for the document. | One certificate per named signature field, each with its own validation status. |
| Typical use | One person or organization certifies the complete document, for example a contract or a regulatory filing. | Several parties sign different fields, or a visible signature is required. |

### Prerequisites

- A .NET console application with the `TXTextControl.TextControl.Core.SDK` package (or `TXTextControl.TextControl.ASP.SDK` on Windows) installed from the [Text Control Private NuGet Feed](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/nuget/private-feed/llms-full.txt). [Create a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/create/llms-full.txt) shows how to set it up.
- A certificate as a PFX file and its password. If you do not have one, create a self-signed certificate as described in the next step.

### Create a Self-Signed Certificate for Testing

A self-signed certificate is fine for testing and internal use. Because it is not issued by a trusted certificate authority (CA), use a certificate from a CA for documents that other people must be able to trust. [Self-Signed Certificates](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/self-signed/llms-full.txt) covers the topic in more detail.

#### On Windows

Open PowerShell as an administrator and create a certificate in the personal certificate store of the current user:

```powershell
$cert = New-SelfSignedCertificate `
  -Subject "CN=MyTXCert" `
  -CertStoreLocation "Cert:\CurrentUser\My" `
  -KeyExportPolicy Exportable `
  -KeySpec Signature `
  -FriendlyName "My PDF Signing Certificate" `
  -NotAfter (Get-Date).AddYears(5)
```

Then export the certificate together with its private key to a password-protected PFX file:

```powershell
$Password = ConvertTo-SecureString -String "123" -Force -AsPlainText

Export-PfxCertificate `
    -Cert "Cert:\CurrentUser\My\$($cert.Thumbprint)" `
    -FilePath "C:\Path\To\certificate.pfx" `
    -Password $Password
```

#### On Linux

With OpenSSL, create a private key and a certificate signing request, sign the request, and combine certificate and key into a PFX file:

```bash
openssl req -new -newkey rsa:2048 -nodes -keyout my_private.key -out my_request.csr
openssl x509 -req -days 365 -in my_request.csr -signkey my_private.key -out my_certificate.crt
openssl pkcs12 -export -out my_certificate.pfx -inkey my_private.key -in my_certificate.crt
```

The first command asks for details such as country, organization and email address. The last command asks for the password that protects the PFX file.

Add the PFX file to your project and set its **Copy to Output Directory** property to **Copy if newer**, so the application finds it at runtime. The examples below use the file name *certificate.pfx* and the password *123*.

### Sign the Whole Document

Replace the content of *Program.cs* with the following code. It loads the certificate, creates a document and saves it as a signed PDF:

```csharp
using System.Security.Cryptography.X509Certificates;
using TXTextControl;

// Load the certificate including its private key
X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile(
    "certificate.pfx",
    "123",
    X509KeyStorageFlags.Exportable);

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();
    tx.Text = "This document is digitally signed.";

    // Sign the complete document when it is saved
    SaveSettings saveSettings = new SaveSettings()
    {
        DigitalSignature = new DigitalSignature(certificate, "")
    };

    tx.Save("signed.pdf", StreamType.AdobePDF, saveSettings);
}
```

The second parameter of the `DigitalSignature` constructor is the URL of a timestamp server. This example passes an empty string to sign with the current date and time of the computer, without requesting a trusted timestamp.

`X509CertificateLoader` is available in .NET 9 and later. In a .NET 8 project, load the certificate with the constructor instead: `new X509Certificate2("certificate.pfx", "123", X509KeyStorageFlags.Exportable)`.

The same `SaveSettings` work for any document. Load a DOCX file first to sign a converted contract, or save with `StreamType.AdobePDFA` and the font setting from [Create a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/create/#create-a-pdf-a-document) to create a signed PDF/A document for archiving.

Do not keep certificate passwords in source code in production. [Certificate-Based Signatures](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/certificate-based/#load-the-certificate-from-azure-key-vault) shows how to load the certificate together with its private key from Azure Key Vault.

### Add a Trusted Timestamp

A signature on its own does not prove when the document was signed. Years later, when the certificate has expired or been revoked, a validator cannot tell whether the certificate was valid at signing time. A timestamp from an RFC 3161 timestamp server (a Time-Stamping Authority) adds this proof. Only a hash of the signature is sent to the server, never the document.

> Warning
>
> **Timestamp Servers in Version 34.0 SP5.** Requesting a server timestamp can fail during PDF export (TXT-5460), including with the error "The specified certificate is invalid or has no private key" (`1-1D0E`). Keep the timestamp-server parameter empty for this tutorial. Before enabling server timestamps, verify that your installed build resolves TXT-5460.

`new DigitalSignature(certificate, "")` signs with the computer's current date and time. It does not provide a trusted timestamp or independent proof of the signing time. See [RFC 3161 Timestamps](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/timestamps/llms-full.txt) for the timestamp concept and API.

### Sign Signature Fields

A signature field is a named area in the document that shows the signature. The following code inserts a signature field with an SVG image and associates a certificate with it by the field's name. Add an image file named *signature.svg* to the project and set it to **Copy if newer**:

```csharp
using System.Security.Cryptography.X509Certificates;
using TXTextControl;

X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile(
    "certificate.pfx",
    "123",
    X509KeyStorageFlags.Exportable);

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();

    // Create a signature field (size in twips) named "txsign" with the ID 10
    SignatureField signatureField = new SignatureField(
        new System.Drawing.Size(2000, 2000), "txsign", 10);

    // Show an image in the field (filter index 8 is SVG)
    signatureField.Image = new SignatureImage("signature.svg", 8);

    // Insert the field at the current input position
    tx.SignatureFields.Add(signatureField, -1);

    // Associate the certificate with the field by its name
    DigitalSignature digitalSignature =
        new DigitalSignature(certificate, "", "txsign");

    SaveSettings saveSettings = new SaveSettings()
    {
        SignatureFields = new DigitalSignature[] { digitalSignature }
    };

    tx.Save("signed-field.pdf", StreamType.AdobePDF, saveSettings);
}
```

A certificate can only be associated with a signature field that has a name. For a document with several signature fields, create one `DigitalSignature` object for each field and pass all of them in the `SignatureFields` array. You can also store information about the expected signer, such as name, title and reason, with the [SignatureField.SignerData](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/signaturefield/signerdata-property/llms-full.txt) property.

In a typical signing workflow, users sign the signature fields electronically in the Document Viewer. Your ASP.NET Core backend receives the signed document, loads it into `ServerTextControl` and applies the certificate to the signature fields as shown above. See [Document Viewer](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/document-viewer/llms-full.txt) in Getting Started and [Signature Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/signature-fields/llms-full.txt).

### Verify the Signed PDF

#### In a PDF Reader

Open *signed.pdf* in Adobe Acrobat Reader. The signature and the certificate details are listed in the signature panel. A document signed with `DigitalSignature` contains an invisible signature field, which the panel names *Signature1 (invisible signature)*:

![Adobe Acrobat Reader with the Signatures panel of a PDF signed by TX Text Control with the certificate MyTXCert: the bar above the page reports that all signatures are valid, and the panel says that the document hasn't been modified since the signature was applied and names the field Signature1 (invisible signature).](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-server/acrobat-signature-valid.5c2a0c2d.webp)

In *signed-field.pdf*, the signature field shows the image, and clicking it displays the validation status:

![Adobe Acrobat with a signed signature field on page 1, the Signatures panel naming the field txsign and the Signature Validation Status dialog reporting a valid signature.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-server/acrobat-signed-field-status.4f29ec85.webp)

To see the protection at work, open a copy of the signed file in a text editor, change a value in the PDF metadata, such as the text of the `/Producer` entry, save it and open it in the reader again. The reader now shows that the document has been modified and the signature is no longer valid:

![Adobe Acrobat Reader with the Signatures panel of a changed PDF: the bar above the page reports that at least one signature is invalid, and the panel says that the document has been altered or corrupted since it was signed.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-server/acrobat-signature-invalid.68b122ef.webp)

#### In Code

To check signatures automatically, for example before documents enter an archive, use the `TXTextControl.PDF.Validation` package from [nuget.org](https://www.nuget.org/packages/TXTextControl.PDF.Validation). Its main purpose is PDF/UA validation, and it also reports the integrity, the signer and the signing time of each signature; it targets .NET 10, and for encrypted PDFs the report status is `Blocked`. [Check the Signatures of a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/validation/#check-the-signatures-of-a-pdf) shows the code.

### Next Steps

- [Signing PDF Documents](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/signing/llms-full.txt): all options for signing PDF documents.
- [Signature Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/signature-fields/llms-full.txt): design documents with signature fields and signer data.
- [Signature Validation](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/validation/llms-full.txt): validate signatures and document integrity.
- [Document Viewer](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/document-viewer/llms-full.txt): let users sign documents in the browser.

---

## Nearby

- **Previous:** [Load and Modify a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/load-modify/llms-full.txt)
- **Next:** [Document Editor](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/llms-full.txt)
