Sign a DOCX as PDF/UA
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)
# 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 -AsPlainTextExport-PfxCertificate -Cert $cert -FilePath "certificate.pfx" -Password $password
# Export public certificate to CER file for verificationExport-Certificate -Cert $cert -FilePath "certificate.cer"
# Clean up certificate from storeRemove-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:
# Step 1: Create Root CAopenssl 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 requestopenssl 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 CAopenssl 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 requestopenssl 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 CAopenssl 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 bundlecat signing_cert.pem intermediate_ca_cert.pem root_ca_cert.pem > certificate_chain.pem
# Step 7: Create PFX with complete chainopenssl 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 verificationopenssl pkcs12 -in certificate.pfx -clcerts -nokeys -out certificate.cer \ -passin pass:"Nutrient answers all your document needs"
# Step 9: Clean up temporary filesrm *_key.pem *.csr *.srl signing_cert.pem intermediate_ca_cert.pem certificate_chain.pemCertificate 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:
- Root CA Certificate - Self-signed root authority (Nutrient Root CA)
- Intermediate CA Certificate - Signed by Root CA (Nutrient Intermediate CA)
- 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:
# Import root CA into Trusted Root Certificate Authorities storeImport-Certificate -FilePath "root_ca_cert.pem" -CertStoreLocation "Cert:\LocalMachine\Root"
# Or for current user onlyImport-Certificate -FilePath "root_ca_cert.pem" -CertStoreLocation "Cert:\CurrentUser\Root"On macOS:
# 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 keychainsecurity add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain root_ca_cert.pemOn Linux:
# Ubuntu/Debiansudo cp root_ca_cert.pem /usr/local/share/ca-certificates/nutrient-root-ca.crtsudo update-ca-certificates
# CentOS/RHEL/Fedorasudo cp root_ca_cert.pem /etc/pki/ca-trust/source/anchors/nutrient-root-ca.crtsudo update-ca-trustTrust Chain Validation
After installing the root CA certificate:
- ✅ Root CA is now a trusted anchor in the certificate store
- ✅ certificate.pfx contains the complete chain for signing
- ✅ PDF validators can trace: End-Entity → Intermediate CA → Root CA → Trusted Store
- ✅ 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:
# View certificate detailsopenssl x509 -in certificate.cer -text -noout
# Verify certificate validityopenssl verify certificate.cerKey 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.