๐Ÿ–Š๏ธ Digital Signatures

Digitally sign PDFs with X.509 certificates using PKCS#7/CMS detached signatures (ISO 32000 ยง12.8).

Digitally Signed PDF
using System.Security.Cryptography.X509Certificates;
using ObviousPDF;

// Load a certificate with private key (.pfx / .p12)
var cert = new X509Certificate2("certificate.pfx", "password",
    X509KeyStorageFlags.Exportable);

var sig = new PdfDigitalSignature(cert)
{
    Reason = "I approve this document",
    Location = "New York, NY",
    ContactInfo = "alice@example.com",
    SignerName = "Alice Signer",
    PageIndex = 0,       // Sign the first page
    X = 72, Y = 50,     // Signature field position
    Width = 250, Height = 60
};

var doc = new PdfDocument();
doc.Info.Title = "Digitally Signed Document";
var page = doc.AddPage();
page.AddText("This document is digitally signed.", 72, 720);

// Sign() writes the PDF with a PKCS#7 detached signature
doc.Sign("signed_document.pdf", sig);
Imports System.Security.Cryptography.X509Certificates
Imports ObviousPDF

' Load a certificate with private key (.pfx / .p12)
Dim cert As New X509Certificate2("certificate.pfx", "password",
    X509KeyStorageFlags.Exportable)

Dim sig As New PdfDigitalSignature(cert) With {
    .Reason = "I approve this document",
    .Location = "New York, NY",
    .ContactInfo = "alice@example.com",
    .SignerName = "Alice Signer",
    .PageIndex = 0,
    .X = 72, .Y = 50,
    .Width = 250, .Height = 60
}

Dim doc As New PdfDocument()
doc.Info.Title = "Digitally Signed Document"
Dim page = doc.AddPage()
page.AddText("This document is digitally signed.", 72, 720)

doc.Sign("signed_document.pdf", sig)
open System.Security.Cryptography.X509Certificates
open ObviousPDF

// Load a certificate with private key (.pfx / .p12)
let cert = new X509Certificate2("certificate.pfx", "password",
    X509KeyStorageFlags.Exportable)

let sig = PdfDigitalSignature(cert,
    Reason = "I approve this document",
    Location = "New York, NY",
    ContactInfo = "alice@example.com",
    SignerName = "Alice Signer",
    PageIndex = 0,
    X = 72.0, Y = 50.0,
    Width = 250.0, Height = 60.0)

let doc = PdfDocument()
doc.Info.Title <- "Digitally Signed Document"
let page = doc.AddPage()
page.AddText("This document is digitally signed.", 72.0, 720.0)

doc.Sign("signed_document.pdf", sig)
Add-Type -Path "ObviousPDF.dll"
Add-Type -AssemblyName "System.Security.Cryptography.X509Certificates"

$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
    "certificate.pfx", "password",
    [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

$sig = [ObviousPDF.PdfDigitalSignature]::new($cert)
$sig.Reason      = "I approve this document"
$sig.Location    = "New York, NY"
$sig.ContactInfo = "alice@example.com"
$sig.SignerName  = "Alice Signer"
$sig.X = 72; $sig.Y = 50
$sig.Width = 250; $sig.Height = 60

$doc = [ObviousPDF.PdfDocument]::new()
$doc.Info.Title = "Digitally Signed Document"
$page = $doc.AddPage()
$page.AddText("This document is digitally signed.", 72, 720)

$doc.Sign("c:\temp\signed_document.pdf", $sig)

What you should see: When opened in Adobe Acrobat Reader, the document displays a "Signed and all signatures are valid" or "At least one signature has problems" banner at the top with a Signatures panel on the right. The banner message depends on whether the signing certificate is trusted (see Certificate Setup below).

Certificate Setup Guide

ObviousPDF produces standard PKCS#7 detached signatures (/SubFilter /adbe.pkcs7.detached). Adobe Acrobat Reader will always detect the signature, but its validity depends on whether the signing certificate is trusted by the viewer.

Certificate Trust Levels

Certificate TypeAdobe Reader StatusUse Case
Self-signed (test/development) โš ๏ธ "Signature validity is unknown" Internal testing, development
Organisation CA โš ๏ธ "Signer’s identity is unknown" (unless CA is installed) Internal documents within an organisation
Trusted CA (e.g. GlobalSign, DigiCert, Sectigo) โœ… "Signed and all signatures are valid" Public-facing documents, contracts, invoices
AATL Certificate (Adobe Approved Trust List) โœ… Fully trusted with blue ribbon icon Legal documents, government, regulated industries

Option 1: Self-Signed Certificate (Development & Testing)

Create a self-signed certificate using .NET or openssl. The signature will be detected by Adobe Reader but shown as "validity unknown" until you manually trust it.

Create Self-Signed Certificate (.NET)
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

using var rsa = RSA.Create(2048);
var req = new CertificateRequest(
    "CN=My Signer, O=My Company",
    rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

req.CertificateExtensions.Add(
    new X509KeyUsageExtension(
        X509KeyUsageFlags.DigitalSignature, critical: true));

var cert = req.CreateSelfSigned(
    DateTimeOffset.UtcNow.AddDays(-1),
    DateTimeOffset.UtcNow.AddYears(3));

// Export as .pfx for later use
byte[] pfxBytes = cert.Export(X509ContentType.Pfx, "mypassword");
File.WriteAllBytes("my_signing_cert.pfx", pfxBytes);
Create Self-Signed Certificate (OpenSSL CLI)
# Generate private key and certificate in one step
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
    -days 1095 -nodes -subj "/CN=My Signer/O=My Company"

# Convert to .pfx (PKCS#12) for use with .NET
openssl pkcs12 -export -out my_signing_cert.pfx \
    -inkey key.pem -in cert.pem -passout pass:mypassword

Option 2: Trusting a Self-Signed Certificate in Adobe Reader

To make Adobe Reader trust your self-signed certificate:

  1. Open the signed PDF in Adobe Acrobat Reader.
  2. Click the "Signature Panel" button in the warning banner.
  3. Expand the signature and click "Certificate Details".
  4. In the Certificate Viewer, go to the "Trust" tab.
  5. Click "Add to Trusted Certificates..." and confirm.
  6. Check "Use this certificate as a trusted root".
  7. Click OK and re-validate โ€” the signature should now show as valid.

Option 3: Purchasing a Trusted Certificate (Production)

For production use, purchase a document signing certificate from a Certificate Authority (CA) trusted by Adobe. Certificates on the Adobe Approved Trust List (AATL) are automatically trusted by all Adobe Reader installations worldwide.

Popular providers of document signing certificates:

ProviderNotes
GlobalSignAATL member, individual and organisation certificates
DigiCertAATL member, hardware token options
Sectigo (Comodo)AATL member, affordable options
EntrustAATL member, enterprise-focused

Most vendors deliver the certificate as a .pfx / .p12 file or on a hardware token (USB). Load it in your .NET code with:

Load a Purchased Certificate
// From a .pfx file
var cert = new X509Certificate2("purchased_cert.pfx", "password",
    X509KeyStorageFlags.Exportable);

// From the Windows certificate store
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates
    .Find(X509FindType.FindBySubjectName, "My Signer", validOnly: true)
    .OfType<X509Certificate2>()
    .FirstOrDefault(c => c.HasPrivateKey)
    ?? throw new InvalidOperationException("Certificate not found");

Signature Properties

PropertyTypeDefaultDescription
CertificateX509Certificate2(required)Signing certificate โ€” must include a private key.
Reasonstring?nullReason for signing (e.g. "I approve this document").
Locationstring?nullPhysical or logical location of signing.
ContactInfostring?nullContact information for the signer.
SignerNamestring?nullSigner name. Defaults to the certificate’s CN.
PageIndexint0Zero-based page index for the signature field.
X, Ydouble0Bottom-left corner of the signature field (points).
Widthdouble200Signature field width in points.
Heightdouble50Signature field height in points.
FieldNamestring"Signature1"Unique form field name for the signature.

Technical Details

AspectValue
StandardISO 32000-2 ยง12.8 (PDF 2.0)
Filter/Adobe.PPKLite
SubFilter/adbe.pkcs7.detached
Signature FormatPKCS#7 / CMS (RFC 5652), detached
Digest AlgorithmSHA-256
Byte RangeCovers the entire file except the /Contents hex value
Certificate InclusionWhole chain (X509IncludeOption.WholeChain)

Troubleshooting

IssueCauseSolution
"Signature validity is unknown" Certificate is not in Adobe’s trust store Add the certificate to Trusted Certificates in Adobe Reader (see above), or use a CA-issued certificate.
"Document has been altered" File was modified after signing Do not edit or re-save the PDF after calling Sign().
ArgumentException: "Certificate must contain a private key" Certificate loaded without private key Load from a .pfx/.p12 file (not .cer/.crt). Include X509KeyStorageFlags.Exportable.
Signature not visible on the page Signature field is outside the visible page area Adjust X, Y, Width, Height to fit within the page’s MediaBox (default: 612 ร— 792 points).