Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Digital Signatures

Commercial License Required - This feature requires a commercial license. See printwell.dev/pricing.

Sign PDF documents with PAdES-compliant digital signatures.

Signature Levels

LevelDescription
PadesBBasic signature
PadesTWith trusted timestamp
PadesLTLong-term validation data
PadesLTALong-term archival

Invisible Signatures

#![allow(unused)]
fn main() {
use printwell::signing::{sign_pdf, SigningOptions};

let cert_data = std::fs::read("certificate.p12")?;

let options = SigningOptions {
    reason: Some("Document approved".into()),
    location: Some("New York, NY".into()),
    contact_info: Some("signer@example.com".into()),
    signature_level: SignatureLevel::PadesB,
    ..Default::default()
};

let signed = sign_pdf(&pdf_data, &cert_data, "cert_password", options)?;
}

Visible Signatures

#![allow(unused)]
fn main() {
use printwell::signing::{sign_pdf_visible, SignatureAppearance};

let appearance = SignatureAppearance {
    page: 1,
    x: 400.0,
    y: 50.0,
    width: 200.0,
    height: 75.0,
    show_name: true,
    show_date: true,
    show_reason: true,
    background_image: None, // Optional logo
};

let signed = sign_pdf_visible(
    &pdf_data,
    &cert_data,
    "password",
    SigningOptions::default(),
    appearance
)?;
}

Verifying Signatures

#![allow(unused)]
fn main() {
use printwell::signing::verify_signatures;

let results = verify_signatures(&signed_pdf)?;

for result in &results {
    println!("Signer: {}", result.signer_name);
    println!("Valid: {}", result.is_valid);
    println!("Covers whole doc: {}", result.covers_whole_document);
    println!("Time: {:?}", result.signing_time);

    if !result.cert_warnings.is_empty() {
        println!("Warnings: {:?}", result.cert_warnings);
    }
}
}

Extracting Signature Info

#![allow(unused)]
fn main() {
use printwell::signing::extract_signatures;

let signatures = extract_signatures(&pdf_data)?;

for sig in &signatures {
    println!("Signer: {:?}", sig.signer_name);
    println!("Reason: {:?}", sig.reason);
    println!("Location: {:?}", sig.location);
    println!("Time: {:?}", sig.signing_time);
}
}

Certificate Requirements

Certificates must be in PKCS#12 format (.p12 or .pfx):

  • Must contain private key
  • Should include certificate chain
  • Supported algorithms: RSA, ECDSA (P-256, P-384)

Creating Test Certificates

# Generate self-signed certificate (for testing only)
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
openssl pkcs12 -export -out certificate.p12 -inkey key.pem -in cert.pem

Node.js Example

import { signPdf, signPdfVisible, verifySignatures } from 'printwell';

const signed = signPdf(pdfData, certData, 'password', {
    reason: 'Approved',
    location: 'New York',
    signatureLevel: 'PadesB'
});

const signedVisible = signPdfVisible(pdfData, certData, 'password',
    { reason: 'Approved' },
    { page: 1, x: 400, y: 50, width: 200, height: 75 }
);

const results = verifySignatures(signedData);

Python Example

from printwell import sign_pdf, sign_pdf_visible, verify_signatures

signed = sign_pdf(pdf_data, cert_data, "password",
    SigningOptions(reason="Approved", location="New York"))

results = verify_signatures(signed)
for r in results:
    print(f"{r.signer_name}: {'Valid' if r.is_valid else 'Invalid'}")