Security / Signing: CMS, RFC 3161 timestamp, LTV, trust
At a glance
Section titled “At a glance”This page describes the signature surface in NextPDF Core: producing a Content Management Syntax (CMS) signature, applying a Request for Comments (RFC) 3161 timestamp, validating a certificate chain against RFC 5280, and checking revocation through the Online Certificate Status Protocol (OCSP) and a certificate revocation list (CRL). It stays at the behavior level. Core implementation classes are internal: production code consumes the SignerInterface contract, not the concrete NextPDF\Security\Signature types. The verifier and its configured trust anchors decide whether a produced signature verifies. That outcome is outside the producer’s control, and this page says so wherever it matters.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”Core builds a CMS SignedData structure from the byte range, then stores it as Distinguished Encoding Rules (DER)-encoded data in the signature dictionary Contents entry — ISO 32000-2 §12.8.1. The structure carries SignerInfo signed attributes, including content-type and message-digest — RFC 5652 §5.3. A verifier recomputes the content digest and compares it with the message-digest attribute. The comparison must match for the signature to be valid — RFC 5652 §5.4. SignerInfo also carries the digest-algorithm identifier and the signed-attributes block — RFC 5652 §5. Core uses phpseclib3 for the software signing paths it ships: RSA, RSASSA-PSS, ECDSA, and Ed25519.
An RFC 3161 timestamp is a request-and-response exchange with a Time-Stamping Authority (TSA) that returns a TSTInfo structure — RFC 3161 §2.4.1. Each token carries a serialNumber unique to the issuing TSA — RFC 3161 §2.4.2 — and a genTime expressed as Coordinated Universal Time (UTC), the instant the token was created — RFC 3161 §2.4.2.
Trust validation has two checks. Path validation walks from the signer certificate to a trust anchor, checking basic constraints and the path-construction inputs — RFC 5280 §6.1. Revocation checking asks an OCSP responder or reads a CRL: an OCSP response reports good, revoked, or unknown — RFC 6960 §2.2 — and the response’s thisUpdate and nextUpdate bound how fresh that status is — RFC 6960 §4.2. The caller supplies the trust anchors and the revocation freshness policy. The engine validates against those inputs and does not ship a built-in trust list.
API surface
Section titled “API surface”| Type | Kind | Role | Stability | Since |
|---|---|---|---|---|
SignerInterface | interface (NextPDF\Contracts) | The signing contract callers depend on | stable | 1.0.0 |
SignatureLevel | enum | PDF Advanced Electronic Signatures (PAdES) level selector and availability probe | stable | 1.0.0 |
Rfc5280PathValidator | interface | Certification-path validation entry point (validate(...)) | stable (frozen 3.1.0) | 3.1.0 |
RevocationStatus | enum | OCSP / CRL outcome: good, revoked, unknown | stable | 3.1.0 |
CaTrustAnchorBundle | type | Caller-supplied set of trust anchors | stable | 3.1.0 |
TstInfo | type | Parsed RFC 3161 timestamp fields | stable | 3.2.0 |
SignerInterface::sign() returns a SignatureResult. Its toHex() method yields the /Contents hex string, and its cmsSignedData property holds the raw DER bytes. The concrete NextPDF\Security\Signature classes that implement this behavior are internal (stability: internal in the module manifest). They are not part of the public API and may change without a major-version bump. Depend on the contracts and enums above.
Code sample — Quick start
Section titled “Code sample — Quick start”<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/** * Produce the CMS SignedData hex for a PDF /Contents field. * * @param SignerInterface $signer A Core or Premium signer. * @param string $byteRange The PDF byte range to sign. * * @return string Hex-encoded CMS SignedData. */function sign(SignerInterface $signer, string $byteRange): string{ return $signer->sign($byteRange)->toHex();}The caller depends on the contract. A Core software signer and a Premium Hardware Security Module (HSM) signer both satisfy SignerInterface, so this code does not change across editions.
Code sample — Production
Section titled “Code sample — Production”<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;use NextPDF\Contracts\TimestampProviderInterface;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final readonly class TimestampedSigner{ public function __construct( private SignerInterface $signer, private TimestampProviderInterface $timestamps, private LoggerInterface $logger, ) {}
/** * Sign a byte range, then timestamp the CMS structure. * * The timestamp's trust still depends on the verifier accepting the * Time-Stamping Authority; this method only produces the structure. * * @param string $byteRange The PDF byte range to sign. * * @return array{cms: string, tst: string} */ public function sign(string $byteRange): array { try { $signature = $this->signer->sign($byteRange); $token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return ['cms' => $signature->toHex(), 'tst' => $token]; } catch (NextPdfException $e) { $this->logger->error('Signing failed', ['error' => $e->getMessage()]);
throw $e; } }}The timestamp provider is injected so a deployment can pin its own Time-Stamping Authority. The catch block logs and rethrows. It never swallows the failure, so the signing path stays fail-closed.
Edge cases & gotchas
Section titled “Edge cases & gotchas”- A produced signature is not a verified signature. Path validation and revocation run at the verifier, using that verifier’s trust anchors. The producer cannot assert the result.
- The byte-range digest excludes the signature value. A digest that covers the
Contentsoctets cannot verify — ISO 32000-2 §12.8.1. - Revocation status has a freshness window. An OCSP response is current only for its
thisUpdate/nextUpdateinterval — RFC 6960 §4.2. A stale response is not a substitute for a fresh check at validation time. - The engine ships no built-in trust list.
CaTrustAnchorBundleis caller-supplied; an empty bundle means no chain validates, by design. - OCSP
unknownis notgood. Treatunknownas a non-determination, not an implicit pass — RFC 6960 §2.2. - HSM key custody, deferred and cloud signing, and the PAdES B-LT / B-LTA producer are not in Core. Selecting those paths in the Core distribution fails closed with a message that names the missing Enterprise component.
Performance
Section titled “Performance”A software signature takes single-digit milliseconds. A timestamp adds one network round trip to the TSA. Path validation is local once the certificates are in memory; revocation adds one OCSP or CRL fetch per certificate in the chain. The 1500 ms wall budget covers one timestamped signature with a remote TSA on a warm connection. Revocation against a slow endpoint exceeds that budget and belongs outside the request path. The reproducibility profile is structural: a timestamp embeds the signing instant, so two runs differ in the timestamp bytes while the document structure is identical.
Security notes
Section titled “Security notes”This is the engine’s primary cryptographic boundary, so the threat model is explicit. The engine computes the byte range and never accepts it from the caller. The signing path is fail-closed: a primitive failure or a capability gap raises a typed exception and never silently downgrades to a weaker algorithm. At a timestamp-required level (B-T, B-LT, B-LTA), a Time-Stamping Authority that returns an empty token is a terminal fault: the signature is refused, not emitted at a silently unstamped, down-levelled state, unless a fault handler is wired to authorise a documented degradation. Trust is caller-controlled by design: anchors and revocation policy are inputs, not engine defaults, because a producer that asserted its own trust would assert a fact only the verifier can establish. Timestamp trust reduces to trust in the Time-Stamping Authority, which is injectable so a deployment can pin its own. This page is marked export_control_class: legal-review-required because it concerns cryptographic signing; every normative source is paraphrased and none is reproduced, per citation hygiene.
Conformance
Section titled “Conformance”| Claim | Standard | Clause | Evidence |
|---|---|---|---|
The CMS signature is stored DER-encoded in the signature dictionary Contents entry. | ISO 32000-2 | §12.8.1 | |
| SignerInfo carries content-type and message-digest signed attributes. | RFC 5652 | §5.3 | |
| The verifier recomputes the content digest and compares it with the message-digest attribute. | RFC 5652 | §5.4 | |
| A timestamp token is produced by an RFC 3161 TSA and carries a unique serialNumber and a UTC genTime. | RFC 3161 | §2.4.1, §2.4.2 | ,, |
| Certification path validation checks basic constraints and the path inputs from the signer to a trust anchor. | RFC 5280 | §6.1 | , |
| OCSP reports certStatus as good, revoked, or unknown, bounded by thisUpdate / nextUpdate. | RFC 6960 | §2.2, §4.2 | , |
All clauses are paraphrased. NextPDF does not reproduce normative text. Consult the published standards for the authoritative wording.
Commercial context
Section titled “Commercial context”Core ships the software CMS signer (RSA, RSASSA-PSS, ECDSA, Ed25519), RFC 3161 timestamp consumption, RFC 5280 path validation, and OCSP / CRL revocation checking. HSM and Public-Key Cryptography Standards #11 (PKCS#11) key custody, deferred and cloud signing, the PAdES B-LT and B-LTA producer, and the Federal Information Processing Standards (FIPS) 140-3 crypto-policy profile ship in the Pro and Enterprise editions. Core resolves these at runtime against the contract, so the open-source engine carries no commercial dependency, and the API does not change on upgrade.
See also
Section titled “See also”- PAdES baseline mapping — Core versus Premium across B-B, B-T, B-LT, B-LTA.
- Contracts / Signing — the
SignerInterfaceservice provider interface (SPI) and stability tiers. - Security — encryption and the wider signature surface.
- Conformance — profile enforcement that pairs with signed archival.
- CMS · RFC 3161 timestamp · Long-Term Validation (LTV) · Document Security Store (DSS) · Validation-Related Information (VRI) · Hardware Security Module (HSM) — glossary terms.