Apply a PAdES digital signature over NextPDF Connect (Pro)
At a glance
Section titled “At a glance”Apply a PDF Advanced Electronic Signatures (PAdES) baseline digital signature
to a PDF over NextPDF Connect. Use sign_pdf, which has been re-verified
against the Pro tool provider: that provider registers new SignPdfTool(),
whose protocol name is sign_pdf. sign_pdf is a Pro-tier tool. At boot,
the server probes it with class_exists() and registers it only when the Pro
package is installed.
By default, the tool produces PAdES B-B. It can produce PAdES B-T (B-B plus one RFC 3161 signature-time-stamp) only when the host has wired a timestamp provider into the tool; the request cannot point at a Time Stamp Authority (TSA). Long-term levels (B-LT, B-LTA) and their validation material (DSS, VRI, LTV) are not part of this tool and are out of scope here.
U-1 caveat. NextPDF does not assert any independent ETSI EN 319 142-1 certification for PAdES B-T. EN 319 142-1 is not in the verification corpus. The B-T
signature-time-stamprequirement was verified against ETSI EN 319 122-1 §5.3 (the CAdES basis that EN 319 142-1/-2 import by reference), together with RFC 3161, RFC 5652, RFC 5816, and ISO 32000-2 §12.8. Support for the B-T profile is not a conformance or legal-validity certification; an independent validator makes that determination.
Install
Section titled “Install”composer require nextpdf/servercomposer require nextpdf/proBind a transport, then confirm that sign_pdf exists with
diagnostic.capabilities. For B-T, the host must construct the tool with a
timestamp provider. Without one, a pades_b_t: true request fails with a
typed error instead of silently downgrading.
Conceptual overview
Section titled “Conceptual overview”sign_pdf computes a byte-range digest over the file, excluding the
signature value placeholder (ISO 32000-2 §12.8.1). It then writes
Distinguished Encoding Rules (DER)-encoded Cryptographic Message Syntax (CMS)
SignedData into the signature dictionary Contents (ISO 32000-2 §12.8.1).
Supported algorithms are RSA-SHA256 (default), RSA + SHA-3 (256/384/512), and
Ed25519. For transports that are not end-to-end confidential, you can wrap
the inbound private_key payload in an optional AES-GCM envelope.
B-T upgrade. With pades_b_t: true and a host-wired timestamp
provider, the signature is upgraded to PAdES B-T: the byte-range hash is
sent to a TSA and a TimeStampToken is embedded (ISO 32000-2 §12.8.5).
B-T is exactly B-B plus one RFC 3161 signature-time-stamp carried as an
unsigned attribute on the CMS SignerInfo (RFC 5652 §5.3).
Unsigned attributes are not covered by the signature, so the B-B signed
digest and its validity are unchanged (RFC 5652 §5.3).
The attribute value is a SignatureTimeStampToken (ETSI EN 319 122-1 §5.3).
B-T adds no Document Security Store (DSS) dictionary, no Validation Related
Information (VRI), no validation material, and no archive-timestamp loop.
Those are the B-LT/B-LTA Enterprise delta and are out of this tool’s scope.
U-1 caveat (repeated at the B-T claim). B-T support here is not an EN 319 142-1 conformance or legal-validity certification; an independent validator decides. EN 319 142-1 is not in the verification corpus. B-T is based on ETSI EN 319 122-1 §5.3, RFC 3161, RFC 5652, RFC 5816, and ISO 32000-2 §12.8.
The flow below shows the host-gated TSA path (the request cannot point at a TSA) and the fail-closed B-T branch (never a silent downgrade).
API surface
Section titled “API surface”| Tool | Tier | Role | Risk tier |
|---|---|---|---|
create_pdf, add_text | Core | Build content | Safe / Caution |
sign_pdf | Pro | Apply PAdES B-B (or host-gated B-T) | Approval Required |
output_pdf | Core | Render and return the PDF | Approval Required / Review (base64) |
Tool names are registry protocol names. The tool catalog is the catalog of record. Available tools depend on the installed tier, and long-term-level tools are not present in Pro.
Code sample — Quick start
Section titled “Code sample — Quick start”create_pdf→ build content withadd_text.sign_pdfwithcertificate(PEM),private_key(PKCS#8 PEM), optionalsigner_name,reason, andalgorithm. Omitpades_b_t(or set itfalse) for B-B.output_pdf.
The tool returns this result envelope:
{ "pdf": "<base64 of the signed PDF>", "signature_count": 1, "is_complete": true, "algorithm": "RSA_SHA256", "oid": "<algorithm OID>", "digest": "<digest algorithm>", "level": "PAdES-B-B", "timestamped": false}For a host-gated B-T signature, send pades_b_t: true; level becomes
"PAdES-B-T", and timestamped becomes true.
Code sample — Production
Section titled “Code sample — Production”Sign as the last content operation. Any add_text/add_image after
sign_pdf invalidates the signature. On a non-confidential transport,
wrap private_key in the AES-GCM transport_encryption envelope (12-byte
nonce; 16/24/32-byte key). Verify that the result level matches your
request. A pades_b_t: true request against a tool with no provider
fails explicitly. Handle that error, and do not retry as B-B silently.
Edge cases & gotchas
Section titled “Edge cases & gotchas”- Cert/key mismatch. The tool rejects the request with a clear error; the private key must match the certificate’s public key.
- Malformed PEM / expired certificate. The tool rejects the request; it does not sign with an unparseable or expired certificate by default.
- Content after signing. The tool rejects the request — sign last.
- B-T requested, no provider. The tool returns a typed error: the signature is not produced and is not silently downgraded to B-B.
- Self-signed certificate. The signature applies, but readers show unknown trust. That is expected, not a tool defect.
- Pro absent. With Core only, the server does not register
sign_pdf.
Performance
Section titled “Performance”Signing adds the CMS build and, for B-T, one TSA round-trip; the budget
covers both. The profile is semantic: an RFC 3161 token is inherently
non-reproducible, and the §12.8.1 byte-range digest excludes the signature
value. Use only an AST + signature-metadata comparison.
Security notes
Section titled “Security notes”A signature provides integrity and authentication relative to the signing key. By itself, it does not make a document “secure” or “legally valid”, or guarantee non-repudiation. Those outcomes depend on the certificate, its trust anchor, key custody, and the verifier’s policy, all outside this tool. Encrypting the key payload with the AES-GCM envelope protects confidentiality in transit, not integrity. Treat the private key as a secret, and prefer the transport-encryption envelope on any non-confidential channel.
Conformance
Section titled “Conformance”| Statement | Spec | Clause | reference_id |
|---|---|---|---|
| The byte-range digest covers the file and excludes the signature value. | ISO 32000-2 | §12.8.1 | |
Contents holds the DER-encoded CMS SignedData. | ISO 32000-2 | §12.8.1 | |
For a timestamp, the byte-range hash goes to a TSA and the token is placed in Contents. | ISO 32000-2 | §12.8.5 | |
| The B-T time-stamp is an unsigned attribute on SignerInfo. | RFC 5652 | §5.3 | |
| Unsigned attributes do not change the B-B signed digest/validity. | RFC 5652 | §5.3 | |
| The signature-time-stamp value is a SignatureTimeStampToken. | ETSI EN 319 122-1 | §5.3 |
NextPDF produces the signature structure. It does not assert that any resulting signature is conformant or legally valid; an independent validator decides. This tool does not produce B-LT/B-LTA.
Commercial context
Section titled “Commercial context”sign_pdf is a Pro-tier tool. The server registers it only when the Pro
package resolves at server boot. PAdES long-term levels (B-LT, B-LTA) and
their validation material (DSS, VRI, LTV) are Enterprise-only and are not
exposed by this tool or this recipe.
Data residency & PII mitigations
Section titled “Data residency & PII mitigations”The certificate and private key transit the request. Use the AES-GCM
transport_encryption envelope on any channel that is not end-to-end
confidential. The signed PDF and signer identity (signer_name, reason)
are document content, so keep them within your data-residency boundary.
The integrator is responsible for deployment-level residency.
Safe telemetry & log scrubbing
Section titled “Safe telemetry & log scrubbing”Never log the private_key payload, the AES-GCM key/nonce, or the
confirmation token. Log the algorithm, the resulting level, and
signature_count, not key material. The tool does not emit key bytes in
its result.
Threat model
Section titled “Threat model”Threats considered: key disclosure in transit (mitigated by the AES-GCM envelope and the host-injected, request-unconfigurable TSA provider); an MCP caller pointing the timestamp at an arbitrary endpoint (prevented because the provider is host-injected, not request-configurable); and post-sign tampering (the byte-range digest detects modification). A threat model documents considered threats and mitigations; it does not assert the absence of vulnerabilities.
FIPS-mode behavior
Section titled “FIPS-mode behavior”Algorithm selection (RSA-SHA256, RSA + SHA-3, Ed25519) is request-driven. The host’s OpenSSL provides the cryptographic primitives. In a FIPS-constrained deployment, restrict the algorithm at the policy layer and rely on the host’s validated module. This tool does not itself assert Federal Information Processing Standards (FIPS) validation.
Transport availability
Section titled “Transport availability”| Transport | Available | Notes |
|---|---|---|
| MCP (stdio) | Yes (Pro) | Use the AES-GCM key envelope on stdio. |
| REST | Yes (Pro) | Prefer TLS plus the key envelope. |
| gRPC | Yes (Pro) | Prefer TLS plus the key envelope. |
HITL risk tier
Section titled “HITL risk tier”sign_pdf is Approval Required because it is a destructive, irreversible
operation; the tool advertises a destructive hint. The confirmation gate
applies as it does for any Approval Required tool. output_pdf to a file is
also Approval Required; base64 mode is Review
(HITL risk tiers).
Confirmation gate JSON envelope
Section titled “Confirmation gate JSON envelope”sign_pdf without a valid token returns the challenge envelope:
{ "allowed": false, "challenge": "⚠️ CONFIRMATION REQUIRED\n\nOperation: sign_pdf\nDescription: <tool description>\n\nTo proceed, call sign_pdf again with parameter _confirmation_token: \"confirm_<single-use-hex>\"\nExpires in 300 seconds.", "token": "confirm_<single-use-hex>"}Call again with _confirmation_token set to the token → { "allowed": true }.
Full flow: output-approval.