Digital signatures provide authentication, integrity, and non-repudiation for PDF documents. This sample demonstrates how to apply a digital signature to a PDF document using a certificate from a P12/PFX file, with comprehensive configuration options for signature appearance and security settings.

Digital signatures are essential for document workflows requiring legal validity, compliance verification, and security assurance. They ensure that documents have not been tampered with after signing and provide proof of the signer’s identity through certificate-based authentication.

Modern PDF signatures support various levels of certification, from simple approval signatures to document certification that controls how recipients can modify the signed document. This sample covers the complete signing process with professional signature appearance and security configurations.

Prerequisites: Generating a PADES-Compliant Digital Certificate

Before running this sample, you need a digital certificate for signing. The sample uses a certificate file named certificate.pfx with the password “Nutrient answers all your document needs”. You can generate a self-signed certificate suitable for testing and development purposes.

This sample implements PADES (PDF Advanced Electronic Signatures), which is the PDF-specific variant of the ETSI Advanced Electronic Signatures standards, providing enhanced security and compliance for PDF documents.

Understanding Certificate Trust

In this sample environment, the certificate chain validates structurally but shows “not trusted” because:

  • Self-signed root CA: The root certificate is generated locally, not from a recognized Certificate Authority
  • No trust anchor: The root CA is not yet installed in the system’s trusted certificate store
  • Development environment: This is expected behavior for testing/development scenarios

For production use, you would typically obtain certificates from a recognized CA (like DigiCert, GlobalSign, etc.) that are already trusted by systems.

On Windows (using PowerShell)

Terminal window
# Create a self-signed certificate with PADES extensions
$cert = New-SelfSignedCertificate -Subject "CN=Nutrient Digital Signature, O=Nutrient, L=Toulouse, S=Occitanie, C=FR" -KeyUsage DigitalSignature,NonRepudiation -KeyExportPolicy Exportable -CertStoreLocation "Cert:\CurrentUser\My" -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256
# Export certificate to PFX file with password
$password = ConvertTo-SecureString -String "Nutrient answers all your document needs" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "certificate.pfx" -Password $password
# Export public certificate to CER file for verification
Export-Certificate -Cert $cert -FilePath "certificate.cer"
# Clean up certificate from store
Remove-Item -Path "Cert:\CurrentUser\My\$($cert.Thumbprint)"

On Linux/macOS (using OpenSSL) - Complete Certificate Chain

For production-quality signatures that will validate properly, create a complete certificate chain:

Terminal window
# Step 1: Create Root CA
openssl req -x509 -new -nodes -keyout root_ca_key.pem -sha256 -days 3650 -out root_ca_cert.pem \
-subj "/C=FR/ST=Occitanie/L=Toulouse/O=Nutrient/OU=Certificate Authority/CN=Nutrient Root CA/emailAddress=ca@nutrient.io" \
-extensions v3_ca -config <(
echo "[req]"; echo "distinguished_name=req"; echo "[v3_ca]"
echo "basicConstraints=critical,CA:TRUE"
echo "keyUsage=critical,keyCertSign,cRLSign"
echo "subjectKeyIdentifier=hash"
echo "authorityKeyIdentifier=keyid:always,issuer"
)
# Step 2: Create Intermediate CA request
openssl req -new -nodes -keyout intermediate_ca_key.pem -out intermediate_ca_csr.pem \
-subj "/C=FR/ST=Occitanie/L=Toulouse/O=Nutrient/OU=Intermediate CA/CN=Nutrient Intermediate CA/emailAddress=intermediate-ca@nutrient.io"
# Step 3: Sign Intermediate CA with Root CA
openssl x509 -req -in intermediate_ca_csr.pem -CA root_ca_cert.pem -CAkey root_ca_key.pem \
-CAcreateserial -out intermediate_ca_cert.pem -days 1825 -sha256 -extensions v3_ca -extfile <(
echo "[v3_ca]"
echo "basicConstraints=critical,CA:TRUE,pathlen:0"
echo "keyUsage=critical,keyCertSign,cRLSign"
echo "subjectKeyIdentifier=hash"
echo "authorityKeyIdentifier=keyid:always,issuer"
)
# Step 4: Create signing certificate request
openssl req -new -nodes -keyout signing_key.pem -out signing_csr.pem \
-subj "/C=FR/ST=Occitanie/L=Toulouse/O=Nutrient/OU=Document Processing/CN=Nutrient Digital Signature/emailAddress=sales@nutrient.io"
# Step 5: Sign end-entity certificate with Intermediate CA
openssl x509 -req -in signing_csr.pem -CA intermediate_ca_cert.pem -CAkey intermediate_ca_key.pem \
-CAcreateserial -out signing_cert.pem -days 365 -sha256 -extensions v3_req -extfile <(
echo "[v3_req]"
echo "keyUsage=critical,digitalSignature,nonRepudiation"
echo "extendedKeyUsage=critical,codeSigning,emailProtection"
echo "subjectKeyIdentifier=hash"
echo "authorityKeyIdentifier=keyid:always,issuer"
echo "subjectAltName=email:sales@nutrient.io"
)
# Step 6: Create certificate chain bundle
cat signing_cert.pem intermediate_ca_cert.pem root_ca_cert.pem > certificate_chain.pem
# Step 7: Create PFX with complete chain
openssl pkcs12 -export -out certificate.pfx -inkey signing_key.pem -in certificate_chain.pem \
-name "Nutrient Digital Signature Certificate with Chain" \
-passout pass:"Nutrient answers all your document needs"
# Step 8: Extract public certificate to CER file for verification
openssl pkcs12 -in certificate.pfx -clcerts -nokeys -out certificate.cer \
-passin pass:"Nutrient answers all your document needs"
# Step 9: Clean up temporary files
rm *_key.pem *.csr *.srl signing_cert.pem intermediate_ca_cert.pem certificate_chain.pem

Certificate Requirements for PADES Signatures

The generated certificate includes the following PADES-compliant features:

  • Key Usage: DigitalSignature and NonRepudiation flags for signing operations
  • Extended Key Usage: CodeSigning and EmailProtection for document signing
  • RSA 2048-bit key: Provides adequate cryptographic strength
  • SHA-256 algorithm: Modern hashing algorithm for certificate signing
  • Subject Alternative Name: Email address for enhanced identification

Certificate Chain Structure

The complete certificate chain resolves the NO_CERTIFICATE_CHAIN_FOUND validation error by providing a proper trust path:

  1. Root CA Certificate - Self-signed root authority (Nutrient Root CA)
  2. Intermediate CA Certificate - Signed by Root CA (Nutrient Intermediate CA)
  3. End-Entity Certificate - Signed by Intermediate CA (Nutrient Digital Signature)

Certificate Files Generated

After running the certificate generation commands, you will have two files:

  • certificate.pfx - Contains the complete certificate chain (root + intermediate + end-entity) plus private key
  • certificate.cer - Contains only the end-entity public certificate (used for signature verification)
  • root_ca_cert.pem - Root CA certificate (install in trusted root store for validation)

Installing the Trust Anchor

To resolve the “certificate chain is not trusted” error, install the root CA certificate as a trust anchor:

On Windows:

Terminal window
# Import root CA into Trusted Root Certificate Authorities store
Import-Certificate -FilePath "root_ca_cert.pem" -CertStoreLocation "Cert:\LocalMachine\Root"
# Or for current user only
Import-Certificate -FilePath "root_ca_cert.pem" -CertStoreLocation "Cert:\CurrentUser\Root"

On macOS:

Terminal window
# Add root CA to system keychain (requires admin password)
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain root_ca_cert.pem
# Or add to user keychain
security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain root_ca_cert.pem

On Linux:

Terminal window
# Ubuntu/Debian
sudo cp root_ca_cert.pem /usr/local/share/ca-certificates/nutrient-root-ca.crt
sudo update-ca-certificates
# CentOS/RHEL/Fedora
sudo cp root_ca_cert.pem /etc/pki/ca-trust/source/anchors/nutrient-root-ca.crt
sudo update-ca-trust

Trust Chain Validation

After installing the root CA certificate:

  1. Root CA is now a trusted anchor in the certificate store
  2. certificate.pfx contains the complete chain for signing
  3. ✅ PDF validators can trace: End-Entity → Intermediate CA → Root CA → Trusted Store
  4. ✅ Certificate validation will succeed: “The certificate chain is trusted”

Preparing the project

Before signing PDF documents, you need to initialize the licensing system and prepare the document processing components.

using GdPicture14;
using GdPicture14.Imaging;
LicenseManager license = new LicenseManager();
license.RegisterKEY("");

The license initialization ensures that all PDF signature capabilities are available for your application. The GdPicture14.Imaging namespace provides access to color types and image processing functionality.

Converting to PDF/UA format

The first step involves converting the input PDF to PDF/UA format to ensure accessibility compliance before signing.

using GdPictureDocumentConverter converter = new GdPictureDocumentConverter();
converter.LoadFromFile("input.docx");
converter.SaveAsPDF("output_pdfa.pdf", PdfConformance.PDF_UA_1);

The document converter automatically handles the PDF/UA conversion, ensuring the document meets accessibility standards before the signature is applied.

Loading the PDF document for signing

Next, load the PDF/UA document that will be digitally signed.

using GdPicturePDF pdf = new GdPicturePDF();
pdf.LoadFromFile("output_pdfa.pdf", false);
var ffId = pdf.AddSignatureFormField(400, 600, 100, 50, "sig");
pdf.SetFormFieldAlternateTitle(ffId, "Signature");
var rootid = pdf.GetTagRootID();
var newtagid = pdf.NewTag(rootid, "Form");
pdf.AttachTagToFormField(newtagid, ffId);
pdf.SetSignaturePosFromPlaceHolder("sig");

The LoadFromFile method opens the PDF/UA document in memory, making it ready for signature application. The second parameter (false) indicates that the document should not be opened in read-only mode, allowing for signature modifications.

Setting up the digital certificate

Digital signatures require a valid certificate that identifies the signer. This step configures the certificate from a P12/PFX file.

pdf.SetSignatureCertificateFromP12("certificate.pfx", "Nutrient answers all your document needs");
var frn = pdf.AddTrueTypeFontU("Arial", false, false, true);

The SetSignatureCertificateFromP12 method loads the certificate and private key from a PKCS#12 file format (commonly used for storing certificates with their private keys). The certificate contains the signer’s identity information and enables the cryptographic operations required for digital signing.

Configuring signature information

Signature information provides details about the signer and signing context that appear in the signature properties.

The SetSignatureInfo method accepts four parameters: signer name, reason for signing, location, and contact information. These details become part of the signature metadata and are displayed in PDF viewers when examining the signature properties. At least one parameter must be provided, while others can remain empty if not applicable.

Positioning the signature on the page

Visual signature placement makes the signed document more professional and clearly indicates where the signature was applied.

The SetSignaturePos method defines the signature’s bounding rectangle on the current page using four parameters: X position, Y position, width, and height (all in points). This creates a visible signature field that can contain text, images, and validation marks. If this step is omitted, the signature becomes invisible but remains cryptographically valid.

Customizing signature appearance

The signature appearance can be enhanced with custom text, images, and validation indicators.

pdf.SetSignatureText("Signature", frn, 14, GdPictureColor.Red, TextAlignment.TextAlignmentCenter, TextAlignment.TextAlignmentCenter, true);

The SetSignatureText method configures text display within the signature bounds. Parameters include two text strings (typically signer name and signing date), font size, text color, horizontal alignment, vertical alignment, and a boolean for automatic date inclusion.

Adding a custom image to the signature creates a more distinctive appearance. The AddJpegImageFromFile method loads an image into the PDF document resources, returning an image name reference that SetSignatureStampImage uses to display the image within the signature bounds.

The validation mark provides a visual indicator of the signature’s validity status, helping users quickly identify the signature’s authentication state.

Configuring signature security settings

Advanced security settings control the signature’s cryptographic strength and document modification permissions.

//pdf.SetSignatureCertificationLevel(PdfSignatureCertificationLevel.NoChanges);

The certification level determines what changes recipients can make to the signed document. NotCertified represents standard approval signatures, while other levels (CertifiedNoChangesAllowed, CertifiedFormFillingAndAnnotationsAllowed, CertifiedFormFillingAllowed) create certifying signatures that restrict subsequent modifications.

//pdf.SetSignatureHash(PdfSignatureHash.SHA512);

The hash algorithm determines the cryptographic strength of the signature. SHA512 provides stronger security than the default SHA256, offering enhanced protection against cryptographic attacks.

Applying the digital signature

The final step applies all configured settings to create the signed PDF document.

pdf.ApplySignature("signed.pdf", PdfSignatureMode.PdfSignatureModeAdobeCADES, false);

The ApplySignature method performs the actual signing operation using the configured certificate, appearance settings, and security parameters. The output file (“signed.pdf”) contains the original document with the applied digital signature. The PdfSignatureModeAdobeCADES parameter specifies Adobe’s implementation of PADES (PDF Advanced Electronic Signatures), which provides enhanced security and compliance with European digital signature standards.

Certificate Verification

The generated certificate.cer file can be used to verify signatures created with the corresponding certificate.pfx file. This is useful for:

  • Signature validation: Verifying that signatures were created with the expected certificate
  • Trust establishment: Installing the public certificate in certificate stores
  • Certificate distribution: Sharing the public certificate safely without exposing the private key

To verify a certificate, you can use:

Terminal window
# View certificate details
openssl x509 -in certificate.cer -text -noout
# Verify certificate validity
openssl verify certificate.cer

Key Features

  • PADES compliance: Implements PDF Advanced Electronic Signatures for enhanced security
  • Certificate-based authentication: Use P12/PFX certificates for secure digital signing
  • Flexible signature appearance: Customize text, images, and validation marks
  • Advanced security options: Configure hash algorithms and certification levels
  • Professional signature placement: Position signatures precisely on PDF pages
  • Comprehensive signature information: Include detailed signer metadata
  • Public certificate distribution: Separate .cer file for verification purposes

Conclusion

This sample demonstrates the complete process of creating accessible, digitally signed PDF documents by combining PDF/UA conversion with professional digital signatures. The workflow includes document accessibility conversion, certificate management, signature appearance customization, and PADES-compliant security configuration. The resulting signed PDF/UA documents provide both accessibility compliance and legal validity, making them suitable for organizations requiring both digital accessibility standards and secure document authentication.